From 7c209484b4a14bbebc83ba5c97c5ae17b7b6c04c Mon Sep 17 00:00:00 2001 From: Sebastien GODARD Date: Sat, 29 Jan 2022 09:20:59 +0100 Subject: [PATCH] A_IRQ: Read interrupts stats from /proc/interrupts Update function used to read interrupts statistics. They are no longer read from /proc/stat but from /proc/interrupts. Signed-off-by: Sebastien GODARD --- rd_stats.c | 135 +++++++++++++++++++++++++++++++++++++---------------- rd_stats.h | 2 +- sa_wrap.c | 4 +- 3 files changed, 99 insertions(+), 42 deletions(-) diff --git a/rd_stats.c b/rd_stats.c index 2f98cd6..0a398ca 100644 --- a/rd_stats.c +++ b/rd_stats.c @@ -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 ":" */ + 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; } /* diff --git a/rd_stats.h b/rd_stats.h index f2abafc..e746393 100644 --- a/rd_stats.h +++ b/rd_stats.h @@ -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 diff --git a/sa_wrap.c b/sa_wrap.c index 6761542..cd2971f 100644 --- 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); } } -- 2.50.1