]> granicus.if.org Git - sysstat/commitdiff
A_IRQ: Read interrupts stats from /proc/interrupts
authorSebastien GODARD <sysstat@users.noreply.github.com>
Sat, 29 Jan 2022 08:20:59 +0000 (09:20 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Sat, 29 Jan 2022 08:20:59 +0000 (09:20 +0100)
Update function used to read interrupts statistics.
They are no longer read from /proc/stat but from /proc/interrupts.

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
rd_stats.c
rd_stats.h
sa_wrap.c

index 2f98cd66f9dc834cd159953e84b37098536f6e25..0a398cae6b1159db99a26f64c307ba27dad48157 100644 (file)
@@ -164,68 +164,125 @@ __nr_t read_stat_cpu(struct stats_cpu *st_cpu, __nr_t nr_alloc)
 
 /*
  ***************************************************************************
- * Read interrupts statistics from /proc/stat.
- * Remember that this function is used by several sysstat commands!
+ * Read interrupts statistics from /proc/interrupts.
  *
  * IN:
  * @st_irq     Structure where stats will be saved.
- * @nr_alloc   Number of structures allocated. Value is >= 1.
+ * @nr_alloc   Number of CPU structures allocated. Value is >= 1.
+ * @nr_int     Number of interrupts, including sum. value is >= 1.
  *
  * OUT:
  * @st_irq     Structure with statistics.
  *
  * RETURNS:
- * Number of interrupts read, or -1 if the buffer was too small and
- * needs to be reallocated.
+ * Highest CPU number for which stats have been successfully read (2 for CPU0,
+ * 3 for CPU 1, etc.) Same logic than for softnet statistics. This number will
+ * be saved in a->_nr0. See wrap_read_stat_irq().
+ * Returns 0 if no statistics have been read.
+ * Returns -1 if the buffer was too small and needs to be reallocated (we
+ * mean here, too small for all the CPU, not for the interrupts whose number
+ * is considered to be a constant. Remember that only the number of items is
+ * saved in file preceding each sample, not the number of sub-items).
  ***************************************************************************
  */
-__nr_t read_stat_irq(struct stats_irq *st_irq, __nr_t nr_alloc)
+__nr_t read_stat_irq(struct stats_irq *st_irq, __nr_t nr_alloc, __nr_t nr_int)
 {
        FILE *fp;
-       struct stats_irq *st_irq_i;
-       char line[8192];
-       int i, pos;
-       unsigned long long irq_nr;
-       __nr_t irq_read = 0;
-
-       if ((fp = fopen(STAT, "r")) == NULL)
-               return 0;
+       struct stats_irq *st_cpuall_sum, *st_cpu_irq, *st_cpu_sum, *st_cpuall_irq;
+       char *line = NULL, *li;
+       int rc = 0, irq_read = 0;
+       int cpu, len;
+       int cpu_nr = nr_alloc - 1;
+       int *cpu_index = NULL, index = 0;
+       char *cp, *next;
+
+       if (!cpu_nr) {
+               /* We have only one proc and a non SMP kernel */
+               cpu_nr = 1;
+       }
+       SREALLOC(cpu_index, int, sizeof(int) * cpu_nr);
 
-       while (fgets(line, sizeof(line), fp) != NULL) {
+       if ((fp = fopen(INTERRUPTS, "r")) != NULL) {
 
-               if (!strncmp(line, "intr ", 5)) {
-                       /* Read total number of interrupts received since system boot */
-                       sscanf(line + 5, "%llu", &st_irq->irq_nr);
-                       pos = strcspn(line + 5, " ") + 5;
+               SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
 
-                       irq_read++;
-                       if (nr_alloc == 1)
-                               /* We just want to read the total number of interrupts */
+               /*
+                * Parse header line to see which CPUs are online
+                */
+               while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
+                       next = line;
+                       while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
+                               cpu = strtol(cp + 3, &next, 10);
+                               if (cpu + 2 > nr_alloc) {
+                                       rc = -1;
+                                       goto out;
+                               }
+                               cpu_index[index++] = cpu;
+                       }
+                       if (index)
+                               /* Header line found */
                                break;
+               }
 
-                       do {
-                               i = sscanf(line + pos, " %llu", &irq_nr);
-                               if (i < 1)
-                                       break;
+               st_cpuall_sum = st_irq;
+               /* Save name "sum" for total number of interrupts */
+               strcpy(st_cpuall_sum->irq_name, K_LOWERSUM);
 
-                               if (irq_read + 1 > nr_alloc) {
-                                       irq_read = -1;
-                                       break;
-                               }
-                               st_irq_i = st_irq + irq_read++;
-                               st_irq_i->irq_nr = irq_nr;
+               /* Parse each line of interrupts statistics data */
+               while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
+                      (irq_read < nr_int - 1)) {
 
-                               i = strcspn(line + pos + 1, " ");
-                               pos += i + 1;
-                       }
-                       while ((i > 0) && (pos < (sizeof(line) - 1)));
+                       /* Skip over "<irq>:" */
+                       if ((cp = strchr(line, ':')) == NULL)
+                               /* Chr ':' not found */
+                               continue;
+                       cp++;
 
-                       break;
+                       irq_read++;
+                       st_cpuall_irq = st_irq + irq_read;
+
+                       /* Remove possible heading spaces in interrupt's name... */
+                       li = line;
+                       while (*li == ' ')
+                               li++;
+
+                       len = strcspn(li, ":");
+                       if (len >= MAX_SA_IRQ_LEN) {
+                               len = MAX_SA_IRQ_LEN - 1;
+                       }
+                       /* ...then save its name */
+                       strncpy(st_cpuall_irq->irq_name, li, len);
+                       st_cpuall_irq->irq_name[len] = '\0';
+
+                       /* For each interrupt: Get number received by each CPU */
+                       for (cpu = 0; cpu < index; cpu++) {
+                               st_cpu_sum = st_irq + (cpu_index[cpu] + 1) * nr_int;
+                               st_cpu_irq = st_irq + (cpu_index[cpu] + 1) * nr_int + irq_read;
+                               /*
+                                * Interrupt name is saved only for CPU "all".
+                                * Now save current interrupt value for current CPU
+                                * and total number of interrupts received by current CPU
+                                * and number of current interrupt received by all CPU.
+                                */
+                               st_cpu_irq->irq_nr = strtoul(cp, &next, 10);
+                               st_cpuall_irq->irq_nr += st_cpu_irq->irq_nr;
+                               st_cpu_sum->irq_nr += st_cpu_irq->irq_nr;
+                               cp = next;
+                       }
+                       st_cpuall_sum->irq_nr += st_cpuall_irq->irq_nr;
                }
+out:
+               free(line);
+               fclose(fp);
        }
 
-       fclose(fp);
-       return irq_read;
+       if (index && !rc) {
+               rc = cpu_index[index - 1] + 2;
+       }
+
+       free(cpu_index);
+
+       return rc;
 }
 
 /*
index f2abafc942c5d09372f14ad30af4048ef1292135..e746393734c49f2da53a528d585c9adc74d9af9e 100644 (file)
@@ -779,7 +779,7 @@ unsigned long long get_per_cpu_interval
 __nr_t read_stat_cpu
        (struct stats_cpu *, __nr_t);
 __nr_t read_stat_irq
-       (struct stats_irq *, __nr_t);
+       (struct stats_irq *, __nr_t, __nr_t);
 __nr_t read_meminfo
        (struct stats_memory *);
 void read_uptime
index 67615426b514ce6b8d219f7735e709cba36e60b0..cd2971f405496347cd3b5d0047a09553d99ff839 100644 (file)
--- a/sa_wrap.c
+++ b/sa_wrap.c
@@ -127,10 +127,10 @@ __read_funct_t wrap_read_stat_irq(struct activity *a)
 
        /* Read interrupts stats */
        do {
-               nr_read = read_stat_irq(st_irq, a->nr_allocated);
+               nr_read = read_stat_irq(st_irq, a->nr_allocated, a->nr2);
 
                if (nr_read < 0) {
-                       /* Buffer needs to be reallocated */
+                       /* Buffer needs to be reallocated (for CPU, not interrupts) */
                        st_irq = (struct stats_irq *) reallocate_buffer(a);
                }
        }