]> granicus.if.org Git - sysstat/blob - mpstat.c
mpstat: Add new switch to display system topology
[sysstat] / mpstat.c
1 /*
2  * mpstat: per-processor statistics
3  * (C) 2000-2019 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
5  ***************************************************************************
6  * This program is free software; you can redistribute it and/or modify it *
7  * under the terms of the GNU General Public License as published  by  the *
8  * Free Software Foundation; either version 2 of the License, or (at  your *
9  * option) any later version.                                              *
10  *                                                                         *
11  * This program is distributed in the hope that it  will  be  useful,  but *
12  * WITHOUT ANY WARRANTY; without the implied warranty  of  MERCHANTABILITY *
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
14  * for more details.                                                       *
15  *                                                                         *
16  * You should have received a copy of the GNU General Public License along *
17  * with this program; if not, write to the Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA              *
19  ***************************************************************************
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <dirent.h>
29 #include <ctype.h>
30 #include <sys/utsname.h>
31
32 #include "version.h"
33 #include "mpstat.h"
34 #include "rd_stats.h"
35 #include "count.h"
36
37 #include <locale.h>     /* For setlocale() */
38 #ifdef USE_NLS
39 #include <libintl.h>
40 #define _(string) gettext(string)
41 #else
42 #define _(string) (string)
43 #endif
44
45 #ifdef USE_SCCSID
46 #define SCCSID "@(#)sysstat-" VERSION ": "  __FILE__ " compiled " __DATE__ " " __TIME__
47 char *sccsid(void) { return (SCCSID); }
48 #endif
49
50 unsigned long long uptime_cs[3] = {0, 0, 0};
51
52 /* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
53 unsigned char *cpu_bitmap;      /* Bit 0: Global; Bit 1: 1st proc; etc. */
54 unsigned char *node_bitmap;     /* Bit 0: Global; Bit 1: 1st NUMA node; etc. */
55
56 /* Structures used to save CPU and NUMA nodes CPU stats */
57 struct stats_cpu *st_cpu[3];
58 struct stats_cpu *st_node[3];
59
60 /*
61  * Structure used to save total number of interrupts received
62  * among all CPU and for each CPU.
63  */
64 struct stats_irq *st_irq[3];
65
66 /*
67  * Structures used to save, for each interrupt, the number
68  * received by each CPU.
69  */
70 struct stats_irqcpu *st_irqcpu[3];
71 struct stats_irqcpu *st_softirqcpu[3];
72
73 /*
74  * Number of CPU per node, e.g.:
75  * cpu_per_node[0]: total nr of CPU (this is node "all")
76  * cpu_per_node[1]: nr of CPU for node 0
77  * etc.
78  */
79 int *cpu_per_node;
80
81 /*
82  * Node number the CPU belongs to, e.g.:
83  * cpu2node[0]: node nr for CPU 0
84  */
85 int *cpu2node;
86
87 /* CPU topology */
88 struct cpu_topology *st_cpu_topology;
89
90 struct tm mp_tstamp[3];
91
92 /* Activity flag */
93 unsigned int actflags = 0;
94
95 unsigned int flags = 0;
96
97 /* Interval and count parameters */
98 long interval = -1, count = 0;
99 /* Number of decimal places */
100 int dplaces_nr = -1;
101
102 /*
103  * Nb of processors on the machine.
104  * A value of 2 means there are 2 processors (0 and 1).
105  */
106 int cpu_nr = 0;
107
108 /*
109  * Highest NUMA node number found on the machine.
110  * A value of 0 means node 0 (one node).
111  * A value of -1 means no nodes found.
112  * We have: node_nr < cpu_nr (see get_node_placement() function).
113  */
114 int node_nr = -1;
115
116 /* Nb of interrupts per processor */
117 int irqcpu_nr = 0;
118 /* Nb of soft interrupts per processor */
119 int softirqcpu_nr = 0;
120
121 struct sigaction alrm_act, int_act;
122 int sigint_caught = 0;
123
124 /*
125  ***************************************************************************
126  * Print usage and exit
127  *
128  * IN:
129  * @progname    Name of sysstat command
130  ***************************************************************************
131  */
132 void usage(char *progname)
133 {
134         fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
135                 progname);
136
137         fprintf(stderr, _("Options are:\n"
138                           "[ -A ] [ -n ] [ -u ] [ -V ]\n"
139                           "[ -I { SUM | CPU | SCPU | ALL } ] [ -N { <node_list> | ALL } ]\n"
140                           "[ --dec={ 0 | 1 | 2 } ] [ -o JSON ] [ -P { <cpu_list> | ALL } ]\n"));
141         exit(1);
142 }
143
144 /*
145  ***************************************************************************
146  * SIGALRM signal handler. No need to reset the handler here.
147  *
148  * IN:
149  * @sig Signal number.
150  ***************************************************************************
151  */
152 void alarm_handler(int sig)
153 {
154         alarm(interval);
155 }
156
157 /*
158  ***************************************************************************
159  * SIGINT signal handler.
160  *
161  * IN:
162  * @sig Signal number.
163  **************************************************************************
164  */
165 void int_handler(int sig)
166 {
167         sigint_caught = 1;
168 }
169
170 /*
171  ***************************************************************************
172  * Allocate stats structures and cpu bitmap. Also do it for NUMA nodes
173  * (although the machine may not be a NUMA one). Assume that the number of
174  * nodes is lower or equal than that of CPU.
175  *
176  * IN:
177  * @nr_cpus     Number of CPUs. This is the real number of available CPUs + 1
178  *              because we also have to allocate a structure for CPU 'all'.
179  ***************************************************************************
180  */
181 void salloc_mp_struct(int nr_cpus)
182 {
183         int i;
184
185         for (i = 0; i < 3; i++) {
186
187                 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
188                     == NULL) {
189                         perror("malloc");
190                         exit(4);
191                 }
192                 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
193
194                 if ((st_node[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
195                     == NULL) {
196                         perror("malloc");
197                         exit(4);
198                 }
199                 memset(st_node[i], 0, STATS_CPU_SIZE * nr_cpus);
200
201                 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
202                     == NULL) {
203                         perror("malloc");
204                         exit(4);
205                 }
206                 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
207
208                 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
209                     == NULL) {
210                         perror("malloc");
211                         exit(4);
212                 }
213                 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
214
215                 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
216                      == NULL) {
217                         perror("malloc");
218                         exit(4);
219                 }
220                 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
221         }
222
223         if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
224                 perror("malloc");
225                 exit(4);
226         }
227         memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
228
229         if ((node_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
230                 perror("malloc");
231                 exit(4);
232         }
233         memset(node_bitmap, 0, (nr_cpus >> 3) + 1);
234
235         if ((cpu_per_node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
236                 perror("malloc");
237                 exit(4);
238         }
239
240         if ((cpu2node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
241                 perror("malloc");
242                 exit(4);
243         }
244
245         if ((st_cpu_topology = (struct cpu_topology *) malloc(sizeof(struct cpu_topology) * nr_cpus)) == NULL) {
246                 perror("malloc");
247                 exit(4);
248         }
249 }
250
251 /*
252  ***************************************************************************
253  * Free structures and bitmap.
254  ***************************************************************************
255  */
256 void sfree_mp_struct(void)
257 {
258         int i;
259
260         for (i = 0; i < 3; i++) {
261                 free(st_cpu[i]);
262                 free(st_node[i]);
263                 free(st_irq[i]);
264                 free(st_irqcpu[i]);
265                 free(st_softirqcpu[i]);
266         }
267
268         free(cpu_bitmap);
269         free(node_bitmap);
270         free(cpu_per_node);
271         free(cpu2node);
272 }
273
274 /*
275  ***************************************************************************
276  * Get node placement (which node each CPU belongs to, and total number of
277  * CPU that each node has).
278  *
279  * IN:
280  * @nr_cpus             Number of CPU on this machine.
281  *
282  * OUT:
283  * @cpu_per_node        Number of CPU per node.
284  * @cpu2node            The node the CPU belongs to.
285  *
286  * RETURNS:
287  * Highest node number found (e.g., 0 means node 0).
288  * A value of -1 means no nodes have been found.
289  ***************************************************************************
290  */
291 int get_node_placement(int nr_cpus, int cpu_per_node[], int cpu2node[])
292
293 {
294         DIR *dir;
295         struct dirent *drd;
296         char line[MAX_PF_NAME];
297         int cpu, node, hi_node_nr = -1;
298
299         /* Init number of CPU per node */
300         memset(cpu_per_node, 0, sizeof(int) * (nr_cpus + 1));
301         /* CPU belongs to no node by default */
302         memset(cpu2node, -1, sizeof(int) * nr_cpus);
303
304         /* This is node "all" */
305         cpu_per_node[0] = nr_cpus;
306
307         for (cpu = 0; cpu < nr_cpus; cpu++) {
308                 snprintf(line, MAX_PF_NAME, "%s/cpu%d", SYSFS_DEVCPU, cpu);
309                 line[MAX_PF_NAME - 1] = '\0';
310
311                 /* Open relevant /sys directory */
312                 if ((dir = opendir(line)) == NULL)
313                         return -1;
314
315                 /* Get current file entry */
316                 while ((drd = readdir(dir)) != NULL) {
317
318                         if (!strncmp(drd->d_name, "node", 4) && isdigit(drd->d_name[4])) {
319                                 node = atoi(drd->d_name + 4);
320                                 if ((node >= nr_cpus) || (node < 0)) {
321                                         /* Assume we cannot have more nodes than CPU */
322                                         closedir(dir);
323                                         return -1;
324                                 }
325                                 cpu_per_node[node + 1]++;
326                                 cpu2node[cpu] = node;
327                                 if (node > hi_node_nr) {
328                                         hi_node_nr = node;
329                                 }
330                                 /* Node placement found for current CPU: Go to next CPU directory */
331                                 break;
332                         }
333                 }
334
335                 /* Close directory */
336                 closedir(dir);
337         }
338
339         return hi_node_nr;
340 }
341
342 /*
343  ***************************************************************************
344  * Read system logical topology: Socket number for each logical core is read
345  * from the /sys/devices/system/cpu/cpu{N}/topology/physical_package_id file,
346  * and the logical core id number is the first number read from the
347  * /sys/devices/system/cpu/cpu{N}/topology/thread_siblings_list file.
348  * Don't use /sys/devices/system/cpu/cpu{N}/topology/core_id as this is the
349  * physical core id (seems to be different from the number displayed by lscpu).
350  *
351  * IN:
352  * @nr_cpus     Number of CPU on this machine.
353  * @cpu_topo    Structures where socket and core id numbers will be saved.
354  *
355  * OUT:
356  * @cpu_topo    Structures where socket and core id numbers have been saved.
357  ***************************************************************************
358  */
359 void read_topology(int nr_cpus, struct cpu_topology *cpu_topo)
360 {
361         struct cpu_topology *cpu_topo_i;
362         FILE *fp;
363         char filename[MAX_PF_NAME];
364         int cpu;
365
366         /* Init system topology */
367         memset(st_cpu_topology, 0, sizeof(struct cpu_topology) * nr_cpus);
368
369         for (cpu = 0; cpu < nr_cpus; cpu++) {
370
371                 cpu_topo_i = cpu_topo + cpu;
372
373                 /* Read current CPU's socket number */
374                 snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, PHYS_PACK_ID);
375                 filename[MAX_PF_NAME - 1] = '\0';
376
377                 if ((fp = fopen(filename, "r")) != NULL) {
378                         fscanf(fp, "%d", &cpu_topo_i->phys_package_id);
379                         fclose(fp);
380                 }
381
382                 /* Read current CPU's logical core id number */
383                 snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, THREAD_SBL_LST);
384                 filename[MAX_PF_NAME - 1] = '\0';
385
386                 if ((fp = fopen(filename, "r")) != NULL) {
387                         fscanf(fp, "%d", &cpu_topo_i->logical_core_id);
388                         fclose(fp);
389                 }
390         }
391 }
392
393 /*
394  ***************************************************************************
395  * Compute node statistics: Split CPU statistics among nodes.
396  *
397  * IN:
398  * @src         Structure containing CPU stats to add.
399  *
400  * OUT:
401  * @dest        Structure containing global CPU stats.
402  ***************************************************************************
403  */
404 void add_cpu_stats(struct stats_cpu *dest, struct stats_cpu *src)
405 {
406         dest->cpu_user       += src->cpu_user;
407         dest->cpu_nice       += src->cpu_nice;
408         dest->cpu_sys        += src->cpu_sys;
409         dest->cpu_idle       += src->cpu_idle;
410         dest->cpu_iowait     += src->cpu_iowait;
411         dest->cpu_hardirq    += src->cpu_hardirq;
412         dest->cpu_softirq    += src->cpu_softirq;
413         dest->cpu_steal      += src->cpu_steal;
414         dest->cpu_guest      += src->cpu_guest;
415         dest->cpu_guest_nice += src->cpu_guest_nice;
416 }
417
418 /*
419  ***************************************************************************
420  * Compute node statistics: Split CPU statistics among nodes.
421  *
422  * IN:
423  * @prev        Index in array where stats used as reference are.
424  * @curr        Index in array for current sample statistics.
425  *
426  * OUT:
427  * @st_node     Array where CPU stats for each node have been saved.
428  ***************************************************************************
429  */
430 void set_node_cpu_stats(int prev, int curr)
431 {
432         int cpu;
433         unsigned long long tot_jiffies_p;
434         struct stats_cpu *scp, *scc, *snp, *snc;
435         struct stats_cpu *scc_all = st_cpu[curr];
436         struct stats_cpu *scp_all = st_cpu[prev];
437         struct stats_cpu *snc_all = st_node[curr];
438         struct stats_cpu *snp_all = st_node[prev];
439
440         /* Reset structures */
441         memset(st_node[prev], 0, STATS_CPU_SIZE * (cpu_nr + 1));
442         memset(st_node[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
443
444         /* Node 'all' is the same as CPU 'all' */
445         *snp_all = *scp_all;
446         *snc_all = *scc_all;
447
448         /* Individual nodes */
449         for (cpu = 0; cpu < cpu_nr; cpu++) {
450                 scc = st_cpu[curr] + cpu + 1;
451                 scp = st_cpu[prev] + cpu + 1;
452                 snp = st_node[prev] + cpu2node[cpu] + 1;
453                 snc = st_node[curr] + cpu2node[cpu] + 1;
454
455
456                 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
457                                 scp->cpu_sys + scp->cpu_idle +
458                                 scp->cpu_iowait + scp->cpu_hardirq +
459                                 scp->cpu_steal + scp->cpu_softirq;
460                 if ((tot_jiffies_p == 0) && (interval != 0))
461                         /*
462                          * CPU has just come back online with no ref from
463                          * previous iteration: Skip it.
464                          */
465                         continue;
466
467                 add_cpu_stats(snp, scp);
468                 add_cpu_stats(snc, scc);
469         }
470 }
471
472 /*
473  ***************************************************************************
474  * Compute global CPU statistics as the sum of individual CPU ones, and
475  * calculate interval for global CPU.
476  * Also identify offline CPU.
477  *
478  * IN:
479  * @prev        Index in array where stats used as reference are.
480  * @curr        Index in array for current sample statistics.
481  * @offline_cpu_bitmap
482  *              CPU bitmap for offline CPU.
483  *
484  * OUT:
485  * @offline_cpu_bitmap
486  *              CPU bitmap with offline CPU.
487  *
488  * RETURNS:
489  * Interval for global CPU.
490  ***************************************************************************
491  */
492 unsigned long long get_global_cpu_mpstats(int prev, int curr,
493                                           unsigned char offline_cpu_bitmap[])
494 {
495         int i;
496         unsigned long long tot_jiffies_c, tot_jiffies_p;
497         unsigned long long deltot_jiffies = 0;
498         struct stats_cpu *scc, *scp;
499         struct stats_cpu *scc_all = st_cpu[curr];
500         struct stats_cpu *scp_all = st_cpu[prev];
501
502         /*
503          * For UP machines we keep the values read from global CPU line in /proc/stat.
504          * Also look for offline CPU: They won't be displayed, and some of their values may
505          * have to be modified.
506          */
507         if (cpu_nr > 1) {
508                 memset(scc_all, 0, sizeof(struct stats_cpu));
509                 memset(scp_all, 0, sizeof(struct stats_cpu));
510         }
511         else {
512                 /* This is a UP machine */
513                 return get_per_cpu_interval(st_cpu[curr], st_cpu[prev]);
514         }
515
516         for (i = 1; i <= cpu_nr; i++) {
517
518                 scc = st_cpu[curr] + i;
519                 scp = st_cpu[prev] + i;
520
521                 /*
522                  * Compute the total number of jiffies spent by current processor.
523                  * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
524                  * already include them.
525                  */
526                 tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
527                                 scc->cpu_sys + scc->cpu_idle +
528                                 scc->cpu_iowait + scc->cpu_hardirq +
529                                 scc->cpu_steal + scc->cpu_softirq;
530                 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
531                                 scp->cpu_sys + scp->cpu_idle +
532                                 scp->cpu_iowait + scp->cpu_hardirq +
533                                 scp->cpu_steal + scp->cpu_softirq;
534
535                 /*
536                  * If the CPU is offline then it is omited from /proc/stat:
537                  * All the fields couldn't have been read and the sum of them is zero.
538                  */
539                 if (tot_jiffies_c == 0) {
540                         /*
541                          * CPU is currently offline.
542                          * Set current struct fields (which have been set to zero)
543                          * to values from previous iteration. Hence their values won't
544                          * jump from zero when the CPU comes back online.
545                          * Note that this workaround no longer fully applies with recent kernels,
546                          * as I have noticed that when a CPU comes back online, some fields
547                          * restart from their previous value (e.g. user, nice, system)
548                          * whereas others restart from zero (idle, iowait)! To deal with this,
549                          * the get_per_cpu_interval() function will set these previous values
550                          * to zero if necessary.
551                          */
552                         *scc = *scp;
553
554                         /*
555                          * Mark CPU as offline to not display it
556                          * (and thus it will not be confused with a tickless CPU).
557                          */
558                         offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
559                 }
560
561                 if ((tot_jiffies_p == 0) && (interval != 0)) {
562                         /*
563                          * CPU has just come back online.
564                          * Unfortunately, no reference values are available
565                          * from a previous iteration, probably because it was
566                          * already offline when the first sample has been taken.
567                          * So don't display that CPU to prevent "jump-from-zero"
568                          * output syndrome, and don't take it into account for CPU "all".
569                          * NB: Test for interval != 0 to make sure we don't want stats
570                          * since boot time.
571                          */
572                         offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
573                         continue;
574                 }
575
576                 /*
577                  * Get interval for current CPU and add it to global CPU.
578                  * Note: Previous idle and iowait values (saved in scp) may be modified here.
579                  */
580                 deltot_jiffies += get_per_cpu_interval(scc, scp);
581
582                 add_cpu_stats(scc_all, scc);
583                 add_cpu_stats(scp_all, scp);
584         }
585
586         return deltot_jiffies;
587 }
588
589 /*
590  ***************************************************************************
591  * Display CPU statistics in plain format.
592  *
593  * IN:
594  * @dis         TRUE if a header line must be printed.
595  * @deltot_jiffies
596  *              Number of jiffies spent on the interval by all processors.
597  * @prev        Position in array where statistics used as reference are.
598  *              Stats used as reference may be the previous ones read, or
599  *              the very first ones when calculating the average.
600  * @curr        Position in array where current statistics will be saved.
601  * @prev_string String displayed at the beginning of a header line. This is
602  *              the timestamp of the previous sample, or "Average" when
603  *              displaying average stats.
604  * @curr_string String displayed at the beginning of current sample stats.
605  *              This is the timestamp of the current sample, or "Average"
606  *              when displaying average stats.
607  * @offline_cpu_bitmap
608  *              CPU bitmap for offline CPU.
609  ***************************************************************************
610  */
611 void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
612                            char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
613 {
614         int i;
615         struct stats_cpu *scc, *scp;
616         struct cpu_topology *cpu_topo_i;
617
618         if (dis) {
619                 printf("\n%-11s  CPU", prev_string);
620                 if (DISPLAY_TOPOLOGY(flags)) {
621                         printf(" CORE SOCK NODE");
622                 }
623                 printf("    %%usr   %%nice    %%sys %%iowait    %%irq   "
624                        "%%soft  %%steal  %%guest  %%gnice   %%idle\n");
625         }
626
627         /*
628          * Now display CPU statistics (including CPU "all"),
629          * except for offline CPU or CPU that the user doesn't want to see.
630          */
631         for (i = 0; i <= cpu_nr; i++) {
632
633                 /* Check if we want stats about this proc */
634                 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
635                     offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
636                         continue;
637
638                 scc = st_cpu[curr] + i;
639                 scp = st_cpu[prev] + i;
640
641                 printf("%-11s", curr_string);
642
643                 if (i == 0) {
644                         /* This is CPU "all" */
645                         cprintf_in(IS_STR, " %s", " all", 0);
646
647                         if (DISPLAY_TOPOLOGY(flags)) {
648                                 printf("               ");
649                         }
650                 }
651                 else {
652                         cprintf_in(IS_INT, " %4d", "", i - 1);
653
654                         if (DISPLAY_TOPOLOGY(flags)) {
655                                 cpu_topo_i = st_cpu_topology + i - 1;
656                                 cprintf_in(IS_INT, " %4d", "", cpu_topo_i->logical_core_id);
657                                 cprintf_in(IS_INT, " %4d", "", cpu_topo_i->phys_package_id);
658                                 cprintf_in(IS_INT, " %4d", "", cpu2node[i - 1]);
659                         }
660
661                         /* Recalculate itv for current proc */
662                         deltot_jiffies = get_per_cpu_interval(scc, scp);
663
664                         if (!deltot_jiffies) {
665                                 /*
666                                  * If the CPU is tickless then there is no change in CPU values
667                                  * but the sum of values is not zero.
668                                  */
669                                 cprintf_pc(NO_UNIT, 10, 7, 2,
670                                            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
671                                 printf("\n");
672
673                                 continue;
674                         }
675                 }
676
677                 cprintf_pc(NO_UNIT, 10, 7, 2,
678                            (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
679                            0.0 :
680                            ll_sp_value(scp->cpu_user - scp->cpu_guest,
681                                        scc->cpu_user - scc->cpu_guest, deltot_jiffies),
682                            (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
683                            0.0 :
684                            ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
685                                        scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
686                            ll_sp_value(scp->cpu_sys,
687                                        scc->cpu_sys, deltot_jiffies),
688                            ll_sp_value(scp->cpu_iowait,
689                                        scc->cpu_iowait, deltot_jiffies),
690                            ll_sp_value(scp->cpu_hardirq,
691                                        scc->cpu_hardirq, deltot_jiffies),
692                            ll_sp_value(scp->cpu_softirq,
693                                        scc->cpu_softirq, deltot_jiffies),
694                            ll_sp_value(scp->cpu_steal,
695                                        scc->cpu_steal, deltot_jiffies),
696                            ll_sp_value(scp->cpu_guest,
697                                        scc->cpu_guest, deltot_jiffies),
698                            ll_sp_value(scp->cpu_guest_nice,
699                                        scc->cpu_guest_nice, deltot_jiffies),
700                            (scc->cpu_idle < scp->cpu_idle) ?
701                            0.0 :
702                            ll_sp_value(scp->cpu_idle,
703                                        scc->cpu_idle, deltot_jiffies));
704                 printf("\n");
705         }
706 }
707
708 /*
709  ***************************************************************************
710  * Display CPU statistics in JSON format.
711  *
712  * IN:
713  * @tab         Number of tabs to print.
714  * @deltot_jiffies
715  *              Number of jiffies spent on the interval by all processors.
716  * @prev        Position in array where statistics used as reference are.
717  *              Stats used as reference may be the previous ones read, or
718  *              the very first ones when calculating the average.
719  * @curr        Position in array where current statistics will be saved.
720  * @offline_cpu_bitmap
721  *              CPU bitmap for offline CPU.
722  ***************************************************************************
723  */
724 void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev, int curr,
725                           unsigned char offline_cpu_bitmap[])
726 {
727         int i, next = FALSE;
728         char cpu_name[16], topology[1024] = "";
729         struct stats_cpu *scc, *scp;
730         struct cpu_topology *cpu_topo_i;
731
732         xprintf(tab++, "\"cpu-load\": [");
733
734         /*
735          * Now display CPU statistics (including CPU "all"),
736          * except for offline CPU or CPU that the user doesn't want to see.
737          */
738         for (i = 0; i <= cpu_nr; i++) {
739
740                 /* Check if we want stats about this proc */
741                 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
742                     offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
743                         continue;
744
745                 scc = st_cpu[curr] + i;
746                 scp = st_cpu[prev] + i;
747
748                 if (next) {
749                         printf(",\n");
750                 }
751                 next = TRUE;
752
753                 if (i == 0) {
754                         /* This is CPU "all" */
755                         strcpy(cpu_name, "all");
756
757                         if (DISPLAY_TOPOLOGY(flags)) {
758                                 snprintf(topology, 1024,
759                                          ", \"core\": \"\", \"socket\": \"\", \"node\": \"\"");
760                         }
761
762                 }
763                 else {
764                         snprintf(cpu_name, 16, "%d", i - 1);
765                         cpu_name[15] = '\0';
766
767                         if (DISPLAY_TOPOLOGY(flags)) {
768                                 cpu_topo_i = st_cpu_topology + i - 1;
769                                 snprintf(topology, 1024,
770                                          ", \"core\": \"%d\", \"socket\": \"%d\", \"node\": \"%d\"",
771                                          cpu_topo_i->logical_core_id, cpu_topo_i->phys_package_id, cpu2node[i - 1]);
772                         }
773
774                         /* Recalculate itv for current proc */
775                         deltot_jiffies = get_per_cpu_interval(scc, scp);
776
777                         if (!deltot_jiffies) {
778                                 /*
779                                  * If the CPU is tickless then there is no change in CPU values
780                                  * but the sum of values is not zero.
781                                  */
782                                 xprintf0(tab, "{\"cpu\": \"%d\"%s, \"usr\": 0.00, \"nice\": 0.00, "
783                                          "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
784                                          "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
785                                          "\"gnice\": 0.00, \"idle\": 100.00}", i - 1, topology);
786                                 printf("\n");
787
788                                 continue;
789                         }
790                 }
791
792                 xprintf0(tab, "{\"cpu\": \"%s\"%s, \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
793                          "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
794                          "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
795                          cpu_name, topology,
796                          (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
797                          0.0 :
798                          ll_sp_value(scp->cpu_user - scp->cpu_guest,
799                                      scc->cpu_user - scc->cpu_guest, deltot_jiffies),
800                          (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
801                          0.0 :
802                          ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
803                                      scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
804                          ll_sp_value(scp->cpu_sys,
805                                      scc->cpu_sys, deltot_jiffies),
806                          ll_sp_value(scp->cpu_iowait,
807                                      scc->cpu_iowait, deltot_jiffies),
808                          ll_sp_value(scp->cpu_hardirq,
809                                      scc->cpu_hardirq, deltot_jiffies),
810                          ll_sp_value(scp->cpu_softirq,
811                                      scc->cpu_softirq, deltot_jiffies),
812                          ll_sp_value(scp->cpu_steal,
813                                      scc->cpu_steal, deltot_jiffies),
814                          ll_sp_value(scp->cpu_guest,
815                                      scc->cpu_guest, deltot_jiffies),
816                          ll_sp_value(scp->cpu_guest_nice,
817                                      scc->cpu_guest_nice, deltot_jiffies),
818                          (scc->cpu_idle < scp->cpu_idle) ?
819                          0.0 :
820                          ll_sp_value(scp->cpu_idle,
821                                      scc->cpu_idle, deltot_jiffies));
822         }
823
824         printf("\n");
825         xprintf0(--tab, "]");
826 }
827
828 /*
829  ***************************************************************************
830  * Display CPU statistics in plain or JSON format.
831  *
832  * IN:
833  * @dis         TRUE if a header line must be printed.
834  * @deltot_jiffies
835  *              Number of jiffies spent on the interval by all processors.
836  * @prev        Position in array where statistics used as reference are.
837  *              Stats used as reference may be the previous ones read, or
838  *              the very first ones when calculating the average.
839  * @curr        Position in array where current statistics will be saved.
840  * @prev_string String displayed at the beginning of a header line. This is
841  *              the timestamp of the previous sample, or "Average" when
842  *              displaying average stats.
843  * @curr_string String displayed at the beginning of current sample stats.
844  *              This is the timestamp of the current sample, or "Average"
845  *              when displaying average stats.
846  * @tab         Number of tabs to print (JSON format only).
847  * @next        TRUE is a previous activity has been displayed (JSON format
848  *              only).
849  * @offline_cpu_bitmap
850  *              CPU bitmap for offline CPU.
851  ***************************************************************************
852  */
853 void write_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
854                      char *prev_string, char *curr_string, int tab, int *next,
855                      unsigned char offline_cpu_bitmap[])
856 {
857         if (!deltot_jiffies) {
858                 /* CPU "all" cannot be tickless */
859                 deltot_jiffies = 1;
860         }
861
862         if (DISPLAY_JSON_OUTPUT(flags)) {
863                 if (*next) {
864                         printf(",\n");
865                 }
866                 *next = TRUE;
867                 write_json_cpu_stats(tab, deltot_jiffies, prev, curr,
868                                      offline_cpu_bitmap);
869         }
870         else {
871                 write_plain_cpu_stats(dis, deltot_jiffies, prev, curr,
872                                       prev_string, curr_string, offline_cpu_bitmap);
873         }
874 }
875
876 /*
877  ***************************************************************************
878  * Display CPU statistics for NUMA nodes in plain format.
879  *
880  * IN:
881  * @dis         TRUE if a header line must be printed.
882  * @deltot_jiffies
883  *              Number of jiffies spent on the interval by all processors.
884  * @prev        Position in array where statistics used as reference are.
885  *              Stats used as reference may be the previous ones read, or
886  *              the very first ones when calculating the average.
887  * @curr        Position in array where current statistics will be saved.
888  * @prev_string String displayed at the beginning of a header line. This is
889  *              the timestamp of the previous sample, or "Average" when
890  *              displaying average stats.
891  * @curr_string String displayed at the beginning of current sample stats.
892  *              This is the timestamp of the current sample, or "Average"
893  *              when displaying average stats.
894  ***************************************************************************
895  */
896 void write_plain_node_stats(int dis, unsigned long long deltot_jiffies,
897                             int prev, int curr, char *prev_string, char *curr_string)
898 {
899         struct stats_cpu *snc, *snp, *scc, *scp;
900         int cpu, node;
901
902         if (dis) {
903                 printf("\n%-11s NODE    %%usr   %%nice    %%sys %%iowait    %%irq   "
904                        "%%soft  %%steal  %%guest  %%gnice   %%idle\n",
905                        prev_string);
906         }
907
908         for (node = 0; node <= node_nr + 1; node++) {
909
910                 snc = st_node[curr] + node;
911                 snp = st_node[prev] + node;
912
913                 /* Check if we want stats about this node */
914                 if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
915                         continue;
916
917                 if (!cpu_per_node[node])
918                         /* No CPU in this node */
919                         continue;
920
921                 printf("%-11s", curr_string);
922                 if (node == 0) {
923                         /* This is node "all", i.e. CPU "all" */
924                         cprintf_in(IS_STR, " %s", " all", 0);
925                 }
926                 else {
927                         cprintf_in(IS_INT, " %4d", "", node - 1);
928
929                         /* Recalculate interval for current node */
930                         deltot_jiffies = 0;
931                         for (cpu = 1; cpu <= cpu_nr; cpu++) {
932                                 scc = st_cpu[curr] + cpu;
933                                 scp = st_cpu[prev] + cpu;
934
935                                 if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
936                                      scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
937                                      scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
938                                         continue;
939
940                                 if (cpu2node[cpu - 1] == node - 1) {
941                                         deltot_jiffies += get_per_cpu_interval(scc, scp);
942                                 }
943                         }
944
945                         if (!deltot_jiffies) {
946                                 /* All CPU in node are tickless and/or offline */
947                                 cprintf_pc(NO_UNIT, 10, 7, 2,
948                                            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
949                                 printf("\n");
950
951                                 continue;
952                         }
953                 }
954
955                 cprintf_pc(NO_UNIT, 10, 7, 2,
956                            (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
957                            0.0 :
958                            ll_sp_value(snp->cpu_user - snp->cpu_guest,
959                                        snc->cpu_user - snc->cpu_guest, deltot_jiffies),
960                            (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
961                            0.0 :
962                            ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
963                                        snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
964                            ll_sp_value(snp->cpu_sys,
965                                        snc->cpu_sys, deltot_jiffies),
966                            ll_sp_value(snp->cpu_iowait,
967                                        snc->cpu_iowait, deltot_jiffies),
968                            ll_sp_value(snp->cpu_hardirq,
969                                        snc->cpu_hardirq, deltot_jiffies),
970                            ll_sp_value(snp->cpu_softirq,
971                                        snc->cpu_softirq, deltot_jiffies),
972                            ll_sp_value(snp->cpu_steal,
973                                        snc->cpu_steal, deltot_jiffies),
974                            ll_sp_value(snp->cpu_guest,
975                                        snc->cpu_guest, deltot_jiffies),
976                            ll_sp_value(snp->cpu_guest_nice,
977                                        snc->cpu_guest_nice, deltot_jiffies),
978                            (snc->cpu_idle < snp->cpu_idle) ?
979                            0.0 :
980                            ll_sp_value(snp->cpu_idle,
981                                        snc->cpu_idle, deltot_jiffies));
982                 printf("\n");
983         }
984 }
985
986 /*
987  ***************************************************************************
988  * Display CPU statistics for NUMA nodes in JSON format.
989  *
990  * IN:
991  * @tab         Number of tabs to print.
992  * @deltot_jiffies
993  *              Number of jiffies spent on the interval by all processors.
994  * @prev        Position in array where statistics used as reference are.
995  *              Stats used as reference may be the previous ones read, or
996  *              the very first ones when calculating the average.
997  * @curr        Position in array where current statistics will be saved.
998  ***************************************************************************
999  */
1000 void write_json_node_stats(int tab, unsigned long long deltot_jiffies,
1001                            int prev, int curr)
1002 {
1003         struct stats_cpu *snc, *snp, *scc, *scp;
1004         int cpu, node, next = FALSE;
1005         char node_name[16];
1006
1007         xprintf(tab++, "\"node-load\": [");
1008
1009         for (node = 0; node <= node_nr + 1; node++) {
1010
1011                 snc = st_node[curr] + node;
1012                 snp = st_node[prev] + node;
1013
1014                 /* Check if we want stats about this node */
1015                 if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
1016                         continue;
1017
1018                 if (!cpu_per_node[node])
1019                         /* No CPU in this node */
1020                         continue;
1021
1022                 if (next) {
1023                         printf(",\n");
1024                 }
1025                 next = TRUE;
1026
1027                 if (node == 0) {
1028                         /* This is node "all", i.e. CPU "all" */
1029                         strcpy(node_name, "all");
1030                 }
1031                 else {
1032                         snprintf(node_name, 16, "%d", node - 1);
1033                         node_name[15] = '\0';
1034
1035                         /* Recalculate interval for current node */
1036                         deltot_jiffies = 0;
1037                         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1038                                 scc = st_cpu[curr] + cpu;
1039                                 scp = st_cpu[prev] + cpu;
1040
1041                                 if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
1042                                      scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
1043                                      scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
1044                                         continue;
1045
1046                                 if (cpu2node[cpu - 1] == node - 1) {
1047                                         deltot_jiffies += get_per_cpu_interval(scc, scp);
1048                                 }
1049                         }
1050
1051                         if (!deltot_jiffies) {
1052                                 /* All CPU in node are tickless and/or offline */
1053                                 xprintf0(tab, "{\"node\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, \"sys\": 0.00, "
1054                               "\"iowait\": 0.00, \"irq\": 0.00, \"soft\": 0.00, \"steal\": 0.00, "
1055                               "\"guest\": 0.00, \"gnice\": 0.00, \"idle\": 100.00}", node - 1);
1056
1057                                 continue;
1058                         }
1059                 }
1060
1061                 xprintf0(tab, "{\"node\": \"%s\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
1062                               "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
1063                               "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node_name,
1064                          (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
1065                          0.0 :
1066                          ll_sp_value(snp->cpu_user - snp->cpu_guest,
1067                                      snc->cpu_user - snc->cpu_guest, deltot_jiffies),
1068                          (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
1069                          0.0 :
1070                          ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
1071                                      snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
1072                          ll_sp_value(snp->cpu_sys,
1073                                      snc->cpu_sys, deltot_jiffies),
1074                          ll_sp_value(snp->cpu_iowait,
1075                                      snc->cpu_iowait, deltot_jiffies),
1076                          ll_sp_value(snp->cpu_hardirq,
1077                                      snc->cpu_hardirq, deltot_jiffies),
1078                          ll_sp_value(snp->cpu_softirq,
1079                                      snc->cpu_softirq, deltot_jiffies),
1080                          ll_sp_value(snp->cpu_steal,
1081                                      snc->cpu_steal, deltot_jiffies),
1082                          ll_sp_value(snp->cpu_guest,
1083                                      snc->cpu_guest, deltot_jiffies),
1084                          ll_sp_value(snp->cpu_guest_nice,
1085                                      snc->cpu_guest_nice, deltot_jiffies),
1086                          (snc->cpu_idle < snp->cpu_idle) ?
1087                          0.0 :
1088                          ll_sp_value(snp->cpu_idle,
1089                                      snc->cpu_idle, deltot_jiffies));
1090         }
1091         printf("\n");
1092         xprintf0(--tab, "]");
1093 }
1094
1095 /*
1096  ***************************************************************************
1097  * Display nodes statistics in plain or JSON format.
1098  *
1099  * IN:
1100  * @dis         TRUE if a header line must be printed.
1101  * @deltot_jiffies
1102  *              Number of jiffies spent on the interval by all processors.
1103  * @prev        Position in array where statistics used as reference are.
1104  *              Stats used as reference may be the previous ones read, or
1105  *              the very first ones when calculating the average.
1106  * @curr        Position in array where current statistics will be saved.
1107  * @prev_string String displayed at the beginning of a header line. This is
1108  *              the timestamp of the previous sample, or "Average" when
1109  *              displaying average stats.
1110  * @curr_string String displayed at the beginning of current sample stats.
1111  *              This is the timestamp of the current sample, or "Average"
1112  *              when displaying average stats.
1113  * @tab         Number of tabs to print (JSON format only).
1114  * @next        TRUE is a previous activity has been displayed (JSON format
1115  *              only).
1116  ***************************************************************************
1117  */
1118 void write_node_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
1119                       char *prev_string, char *curr_string, int tab, int *next)
1120 {
1121         if (!deltot_jiffies) {
1122                 /* CPU "all" cannot be tickless */
1123                 deltot_jiffies = 1;
1124         }
1125
1126         if (DISPLAY_JSON_OUTPUT(flags)) {
1127                 if (*next) {
1128                         printf(",\n");
1129                 }
1130                 *next = TRUE;
1131                 write_json_node_stats(tab, deltot_jiffies, prev, curr);
1132         }
1133         else {
1134                 write_plain_node_stats(dis, deltot_jiffies, prev, curr,
1135                                        prev_string, curr_string);
1136         }
1137 }
1138
1139 /*
1140  ***************************************************************************
1141  * Display total number of interrupts per CPU in plain format.
1142  *
1143  * IN:
1144  * @dis         TRUE if a header line must be printed.
1145  * @itv         Interval value.
1146  * @prev        Position in array where statistics used as reference are.
1147  *              Stats used as reference may be the previous ones read, or
1148  *              the very first ones when calculating the average.
1149  * @curr        Position in array where current statistics will be saved.
1150  * @prev_string String displayed at the beginning of a header line. This is
1151  *              the timestamp of the previous sample, or "Average" when
1152  *              displaying average stats.
1153  * @curr_string String displayed at the beginning of current sample stats.
1154  *              This is the timestamp of the current sample, or "Average"
1155  *              when displaying average stats.
1156  ***************************************************************************
1157  */
1158 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1159                                char *prev_string, char *curr_string)
1160 {
1161         struct stats_cpu *scc, *scp;
1162         struct stats_irq *sic, *sip;
1163         unsigned long long pc_itv;
1164         int cpu;
1165
1166         if (dis) {
1167                 printf("\n%-11s  CPU    intr/s\n", prev_string);
1168                 }
1169
1170         if (*cpu_bitmap & 1) {
1171                 printf("%-11s", curr_string);
1172                 cprintf_in(IS_STR, " %s", " all", 0);
1173                 /* Print total number of interrupts among all cpu */
1174                 cprintf_f(NO_UNIT, 1, 9, 2,
1175                           S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1176                 printf("\n");
1177         }
1178
1179         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1180
1181                 sic = st_irq[curr] + cpu;
1182                 sip = st_irq[prev] + cpu;
1183
1184                 scc = st_cpu[curr] + cpu;
1185                 scp = st_cpu[prev] + cpu;
1186
1187                 /* Check if we want stats about this CPU */
1188                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1189                         continue;
1190
1191                 if ((scc->cpu_user    + scc->cpu_nice + scc->cpu_sys   +
1192                      scc->cpu_iowait  + scc->cpu_idle + scc->cpu_steal +
1193                      scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1194
1195                         /* This is an offline CPU */
1196                         continue;
1197                 }
1198
1199                 printf("%-11s", curr_string);
1200                 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1201
1202                 /* Recalculate itv for current proc */
1203                 pc_itv = get_per_cpu_interval(scc, scp);
1204
1205                 if (!pc_itv) {
1206                         /* This is a tickless CPU: Value displayed is 0.00 */
1207                         cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1208                         printf("\n");
1209                 }
1210                 else {
1211                         /* Display total number of interrupts for current CPU */
1212                         cprintf_f(NO_UNIT, 1, 9, 2,
1213                                   S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1214                         printf("\n");
1215                 }
1216         }
1217 }
1218
1219 /*
1220  ***************************************************************************
1221  * Display total number of interrupts per CPU in JSON format.
1222  *
1223  * IN:
1224  * @tab         Number of tabs to print.
1225  * @itv         Interval value.
1226  * @prev        Position in array where statistics used as reference are.
1227  *              Stats used as reference may be the previous ones read, or
1228  *              the very first ones when calculating the average.
1229  * @curr        Position in array where current statistics will be saved.
1230  ***************************************************************************
1231  */
1232 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr)
1233 {
1234         struct stats_cpu *scc, *scp;
1235         struct stats_irq *sic, *sip;
1236         unsigned long long pc_itv;
1237         int cpu, next = FALSE;
1238
1239         xprintf(tab++, "\"sum-interrupts\": [");
1240
1241         if (*cpu_bitmap & 1) {
1242
1243                 next = TRUE;
1244                 /* Print total number of interrupts among all cpu */
1245                 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
1246                          S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1247         }
1248
1249         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1250
1251                 sic = st_irq[curr] + cpu;
1252                 sip = st_irq[prev] + cpu;
1253
1254                 scc = st_cpu[curr] + cpu;
1255                 scp = st_cpu[prev] + cpu;
1256
1257                 /* Check if we want stats about this CPU */
1258                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1259                         continue;
1260
1261                 if (next) {
1262                         printf(",\n");
1263                 }
1264                 next = TRUE;
1265
1266                 if ((scc->cpu_user    + scc->cpu_nice + scc->cpu_sys   +
1267                      scc->cpu_iowait  + scc->cpu_idle + scc->cpu_steal +
1268                      scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1269
1270                         /* This is an offline CPU */
1271                         continue;
1272                 }
1273
1274                 /* Recalculate itv for current proc */
1275                 pc_itv = get_per_cpu_interval(scc, scp);
1276
1277                 if (!pc_itv) {
1278                         /* This is a tickless CPU: Value displayed is 0.00 */
1279                         xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1280                                  cpu - 1);
1281                 }
1282                 else {
1283                         /* Display total number of interrupts for current CPU */
1284                         xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
1285                                  cpu - 1,
1286                                  S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1287                 }
1288         }
1289         printf("\n");
1290         xprintf0(--tab, "]");
1291 }
1292
1293 /*
1294  ***************************************************************************
1295  * Display total number of interrupts per CPU in plain or JSON format.
1296  *
1297  * IN:
1298  * @dis         TRUE if a header line must be printed.
1299  * @itv         Interval value.
1300  * @prev        Position in array where statistics used as reference are.
1301  *              Stats used as reference may be the previous ones read, or
1302  *              the very first ones when calculating the average.
1303  * @curr        Position in array where current statistics will be saved.
1304  * @prev_string String displayed at the beginning of a header line. This is
1305  *              the timestamp of the previous sample, or "Average" when
1306  *              displaying average stats.
1307  * @curr_string String displayed at the beginning of current sample stats.
1308  *              This is the timestamp of the current sample, or "Average"
1309  *              when displaying average stats.
1310  * @tab         Number of tabs to print (JSON format only).
1311  * @next        TRUE is a previous activity has been displayed (JSON format
1312  *              only).
1313  ***************************************************************************
1314  */
1315 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1316                      char *prev_string, char *curr_string, int tab, int *next)
1317 {
1318         if (DISPLAY_JSON_OUTPUT(flags)) {
1319                 if (*next) {
1320                         printf(",\n");
1321                 }
1322                 *next = TRUE;
1323                 write_json_isumcpu_stats(tab, itv, prev, curr);
1324         }
1325         else {
1326                 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
1327         }
1328 }
1329
1330 /*
1331  ***************************************************************************
1332  * Display interrupts statistics for each CPU in plain format.
1333  *
1334  * IN:
1335  * @st_ic       Array for per-CPU statistics.
1336  * @ic_nr       Number of interrupts (hard or soft) per CPU.
1337  * @dis         TRUE if a header line must be printed.
1338  * @itv         Interval value.
1339  * @prev        Position in array where statistics used as reference are.
1340  *              Stats used as reference may be the previous ones read, or
1341  *              the very first ones when calculating the average.
1342  * @curr        Position in array where current statistics will be saved.
1343  * @prev_string String displayed at the beginning of a header line. This is
1344  *              the timestamp of the previous sample, or "Average" when
1345  *              displaying average stats.
1346  * @curr_string String displayed at the beginning of current sample stats.
1347  *              This is the timestamp of the current sample, or "Average"
1348  *              when displaying average stats.
1349  ***************************************************************************
1350  */
1351 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1352                               unsigned long long itv, int prev, int curr,
1353                               char *prev_string, char *curr_string)
1354 {
1355         struct stats_cpu *scc;
1356         int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
1357         struct stats_irqcpu *p, *q, *p0, *q0;
1358
1359         /*
1360          * Check if number of interrupts has changed.
1361          * If this is the case, the header line will be printed again.
1362          * NB: A zero interval value indicates that we are
1363          * displaying statistics since system startup.
1364          */
1365         if (!dis && interval) {
1366                 for (j = 0; j < ic_nr; j++) {
1367                         p0 = st_ic[curr] + j;
1368                         q0 = st_ic[prev] + j;
1369                         if (strcmp(p0->irq_name, q0->irq_name))
1370                                 /*
1371                                  * These are two different interrupts: The header must be displayed
1372                                  * (maybe an interrupt has disappeared, or a new one has just been registered).
1373                                  * Note that we compare even empty strings for the case where
1374                                  * a disappearing interrupt would be the last one in the list.
1375                                  */
1376                                 break;
1377                 }
1378         }
1379
1380         if (dis || (j < ic_nr)) {
1381                 /* Print header */
1382                 printf("\n%-11s  CPU", prev_string);
1383                 for (j = 0; j < ic_nr; j++) {
1384                         p0 = st_ic[curr] + j;
1385                         if (p0->irq_name[0] == '\0')
1386                                 /* End of the list of interrupts */
1387                                 break;
1388                         printf(" %8s/s", p0->irq_name);
1389                 }
1390                 printf("\n");
1391         }
1392
1393         /* Calculate column widths */
1394         for (j = 0; j < ic_nr; j++) {
1395                 p0 = st_ic[curr] + j;
1396                 /*
1397                  * Width is IRQ name + 2 for the trailing "/s".
1398                  * Width is calculated even for "undefined" interrupts (with
1399                  * an empty irq_name string) to quiet code analysis tools.
1400                  */
1401                 colwidth[j] = strlen(p0->irq_name) + 2;
1402                 /*
1403                  * Normal space for printing a number is 11 chars
1404                  * (space + 10 digits including the period).
1405                  */
1406                 if (colwidth[j] < 10) {
1407                         colwidth[j] = 10;
1408                 }
1409         }
1410
1411         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1412
1413                 scc = st_cpu[curr] + cpu;
1414
1415                 /*
1416                  * Check if we want stats about this CPU.
1417                  * CPU must have been explicitly selected using option -P,
1418                  * else we display every CPU.
1419                  */
1420                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags))
1421                         continue;
1422
1423                 if ((scc->cpu_user    + scc->cpu_nice + scc->cpu_sys   +
1424                      scc->cpu_iowait  + scc->cpu_idle + scc->cpu_steal +
1425                      scc->cpu_hardirq + scc->cpu_softirq) == 0)
1426                         /* Offline CPU found */
1427                         continue;
1428
1429                 printf("%-11s", curr_string);
1430                 cprintf_in(IS_INT, "  %3d", "", cpu - 1);
1431
1432                 for (j = 0; j < ic_nr; j++) {
1433                         p0 = st_ic[curr] + j;   /* irq_name set only for CPU#0 */
1434                         /*
1435                          * An empty string for irq_name means it is a remaining interrupt
1436                          * which is no longer used, for example because the
1437                          * number of interrupts has decreased in /proc/interrupts.
1438                          */
1439                         if (p0->irq_name[0] == '\0')
1440                                 /* End of the list of interrupts */
1441                                 break;
1442                         q0 = st_ic[prev] + j;
1443                         offset = j;
1444
1445                         /*
1446                          * If we want stats for the time since system startup,
1447                          * we have p0->irq_name != q0->irq_name, since q0 structure
1448                          * is completely set to zero.
1449                          */
1450                         if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1451                                 /* Check if interrupt exists elsewhere in list */
1452                                 for (offset = 0; offset < ic_nr; offset++) {
1453                                         q0 = st_ic[prev] + offset;
1454                                         if (!strcmp(p0->irq_name, q0->irq_name))
1455                                                 /* Interrupt found at another position */
1456                                                 break;
1457                                 }
1458                         }
1459
1460                         p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1461
1462                         if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1463                                 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1464                                 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1465                                           S_VALUE(q->interrupt, p->interrupt, itv));
1466                         }
1467                         else {
1468                                 /*
1469                                  * Instead of printing "N/A", assume that previous value
1470                                  * for this new interrupt was zero.
1471                                  */
1472                                 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1473                                           S_VALUE(0, p->interrupt, itv));
1474                         }
1475                 }
1476                 printf("\n");
1477         }
1478 }
1479
1480 /*
1481  ***************************************************************************
1482  * Display interrupts statistics for each CPU in JSON format.
1483  *
1484  * IN:
1485  * @tab         Number of tabs to print.
1486  * @st_ic       Array for per-CPU statistics.
1487  * @ic_nr       Number of interrupts (hard or soft) per CPU.
1488  * @itv         Interval value.
1489  * @prev        Position in array where statistics used as reference are.
1490  *              Stats used as reference may be the previous ones read, or
1491  *              the very first ones when calculating the average.
1492  * @curr        Position in array where current statistics will be saved.
1493  * @type        Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1494  ***************************************************************************
1495  */
1496 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
1497                              unsigned long long itv, int prev, int curr, int type)
1498 {
1499         struct stats_cpu *scc;
1500         int j = ic_nr, offset, cpu;
1501         struct stats_irqcpu *p, *q, *p0, *q0;
1502         int nextcpu = FALSE, nextirq;
1503
1504         if (type == M_D_IRQ_CPU) {
1505                 xprintf(tab++, "\"individual-interrupts\": [");
1506         }
1507         else {
1508                 xprintf(tab++, "\"soft-interrupts\": [");
1509         }
1510
1511         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1512
1513                 scc = st_cpu[curr] + cpu;
1514
1515                 /*
1516                  * Check if we want stats about this CPU.
1517                  * CPU must have been explicitly selected using option -P,
1518                  * else we display every CPU.
1519                  */
1520                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags))
1521                         continue;
1522
1523                 if ((scc->cpu_user    + scc->cpu_nice + scc->cpu_sys   +
1524                      scc->cpu_iowait  + scc->cpu_idle + scc->cpu_steal +
1525                      scc->cpu_hardirq + scc->cpu_softirq) == 0)
1526                         /* Offline CPU found */
1527                         continue;
1528
1529                 if (nextcpu) {
1530                         printf(",\n");
1531                 }
1532                 nextcpu = TRUE;
1533                 nextirq = FALSE;
1534                 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1535
1536                 for (j = 0; j < ic_nr; j++) {
1537
1538                         p0 = st_ic[curr] + j;   /* irq_name set only for CPU#0 */
1539                         /*
1540                          * An empty string for irq_name means it is a remaining interrupt
1541                          * which is no longer used, for example because the
1542                          * number of interrupts has decreased in /proc/interrupts.
1543                          */
1544                         if (p0->irq_name[0] == '\0')
1545                                 /* End of the list of interrupts */
1546                                 break;
1547                         q0 = st_ic[prev] + j;
1548                         offset = j;
1549
1550                         if (nextirq) {
1551                                 printf(",\n");
1552                         }
1553                         nextirq = TRUE;
1554
1555                         /*
1556                          * If we want stats for the time since system startup,
1557                          * we have p0->irq_name != q0->irq_name, since q0 structure
1558                          * is completely set to zero.
1559                          */
1560                         if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1561                                 /* Check if interrupt exists elsewhere in list */
1562                                 for (offset = 0; offset < ic_nr; offset++) {
1563                                         q0 = st_ic[prev] + offset;
1564                                         if (!strcmp(p0->irq_name, q0->irq_name))
1565                                                 /* Interrupt found at another position */
1566                                                 break;
1567                                 }
1568                         }
1569
1570                         p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1571
1572                         if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1573                                 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1574                                 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1575                                          p0->irq_name,
1576                                          S_VALUE(q->interrupt, p->interrupt, itv));
1577                         }
1578                         else {
1579                                 /*
1580                                  * Instead of printing "N/A", assume that previous value
1581                                  * for this new interrupt was zero.
1582                                  */
1583                                 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1584                                          p0->irq_name,
1585                                          S_VALUE(0, p->interrupt, itv));
1586                         }
1587                 }
1588                 printf("\n");
1589                 xprintf0(--tab, "] }");
1590         }
1591         printf("\n");
1592         xprintf0(--tab, "]");
1593 }
1594
1595 /*
1596  ***************************************************************************
1597  * Display interrupts statistics for each CPU in plain or JSON format.
1598  *
1599  * IN:
1600  * @st_ic       Array for per-CPU statistics.
1601  * @ic_nr       Number of interrupts (hard or soft) per CPU.
1602  * @dis         TRUE if a header line must be printed.
1603  * @itv         Interval value.
1604  * @prev        Position in array where statistics used as reference are.
1605  *              Stats used as reference may be the previous ones read, or
1606  *              the very first ones when calculating the average.
1607  * @curr        Position in array where current statistics will be saved.
1608  * @prev_string String displayed at the beginning of a header line. This is
1609  *              the timestamp of the previous sample, or "Average" when
1610  *              displaying average stats.
1611  * @curr_string String displayed at the beginning of current sample stats.
1612  *              This is the timestamp of the current sample, or "Average"
1613  *              when displaying average stats.
1614  * @tab         Number of tabs to print (JSON format only).
1615  * @next        TRUE is a previous activity has been displayed (JSON format
1616  *              only).
1617  * @type        Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1618  ***************************************************************************
1619  */
1620 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1621                         unsigned long long itv, int prev, int curr,
1622                         char *prev_string, char *curr_string, int tab,
1623                         int *next, int type)
1624 {
1625         if (DISPLAY_JSON_OUTPUT(flags)) {
1626                 if (*next) {
1627                         printf(",\n");
1628                 }
1629                 *next = TRUE;
1630                 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type);
1631         }
1632         else {
1633                 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1634                                          prev_string, curr_string);
1635         }
1636 }
1637
1638 /*
1639  ***************************************************************************
1640  * Core function used to display statistics.
1641  *
1642  * IN:
1643  * @prev        Position in array where statistics used as reference are.
1644  *              Stats used as reference may be the previous ones read, or
1645  *              the very first ones when calculating the average.
1646  * @curr        Position in array where statistics for current sample are.
1647  * @dis         TRUE if a header line must be printed.
1648  * @prev_string String displayed at the beginning of a header line. This is
1649  *              the timestamp of the previous sample, or "Average" when
1650  *              displaying average stats.
1651  * @curr_string String displayed at the beginning of current sample stats.
1652  *              This is the timestamp of the current sample, or "Average"
1653  *              when displaying average stats.
1654  ***************************************************************************
1655  */
1656 void write_stats_core(int prev, int curr, int dis,
1657                       char *prev_string, char *curr_string)
1658 {
1659         unsigned long long itv, deltot_jiffies = 1;
1660         int tab = 4, next = FALSE;
1661         unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
1662
1663         /* Test stdout */
1664         TEST_STDOUT(STDOUT_FILENO);
1665
1666         /*
1667          * Compute CPU "all" as sum of all individual CPU (on SMP machines)
1668          * and look for offline CPU.
1669          */
1670         deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
1671
1672         if (DISPLAY_JSON_OUTPUT(flags)) {
1673                 xprintf(tab++, "{");
1674                 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1675         }
1676
1677         /* Get time interval */
1678         itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
1679
1680         /* Print CPU stats */
1681         if (DISPLAY_CPU(actflags)) {
1682                 write_cpu_stats(dis, deltot_jiffies, prev, curr,
1683                                 prev_string, curr_string, tab, &next, offline_cpu_bitmap);
1684         }
1685
1686         /* Print node CPU stats */
1687         if (DISPLAY_NODE(actflags)) {
1688                 set_node_cpu_stats(prev, curr);
1689                 write_node_stats(dis, deltot_jiffies, prev, curr, prev_string,
1690                                  curr_string, tab, &next);
1691         }
1692
1693         /* Print total number of interrupts per processor */
1694         if (DISPLAY_IRQ_SUM(actflags)) {
1695                 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1696                                     tab, &next);
1697         }
1698
1699         /* Display each interrupt value for each CPU */
1700         if (DISPLAY_IRQ_CPU(actflags)) {
1701                 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1702                                    prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
1703         }
1704         if (DISPLAY_SOFTIRQS(actflags)) {
1705                 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1706                                    prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
1707         }
1708
1709         if (DISPLAY_JSON_OUTPUT(flags)) {
1710                 printf("\n");
1711                 xprintf0(--tab, "}");
1712         }
1713 }
1714
1715 /*
1716  ***************************************************************************
1717  * Print statistics average.
1718  *
1719  * IN:
1720  * @curr        Position in array where statistics for current sample are.
1721  * @dis         TRUE if a header line must be printed.
1722  ***************************************************************************
1723  */
1724 void write_stats_avg(int curr, int dis)
1725 {
1726         char string[16];
1727
1728         strncpy(string, _("Average:"), 16);
1729         string[15] = '\0';
1730         write_stats_core(2, curr, dis, string, string);
1731 }
1732
1733 /*
1734  ***************************************************************************
1735  * Print statistics.
1736  *
1737  * IN:
1738  * @curr        Position in array where statistics for current sample are.
1739  * @dis         TRUE if a header line must be printed.
1740  ***************************************************************************
1741  */
1742 void write_stats(int curr, int dis)
1743 {
1744         char cur_time[2][TIMESTAMP_LEN];
1745
1746         /* Get previous timestamp */
1747         if (is_iso_time_fmt()) {
1748                 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1749         }
1750         else {
1751                 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1752         }
1753
1754         /* Get current timestamp */
1755         if (is_iso_time_fmt()) {
1756                 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &mp_tstamp[curr]);
1757         }
1758         else {
1759                 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1760         }
1761
1762         write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1763 }
1764
1765 /*
1766  ***************************************************************************
1767  * Read stats from /proc/interrupts or /proc/softirqs.
1768  *
1769  * IN:
1770  * @file        /proc file to read (interrupts or softirqs).
1771  * @ic_nr       Number of interrupts (hard or soft) per CPU.
1772  * @curr        Position in array where current statistics will be saved.
1773  *
1774  * OUT:
1775  * @st_ic       Array for per-CPU interrupts statistics.
1776  ***************************************************************************
1777  */
1778 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1779 {
1780         FILE *fp;
1781         struct stats_irq *st_irq_i;
1782         struct stats_irqcpu *p;
1783         char *line = NULL, *li;
1784         unsigned long irq = 0;
1785         unsigned int cpu;
1786         int cpu_index[cpu_nr], index = 0, len;
1787         char *cp, *next;
1788
1789         /* Reset total number of interrupts received by each CPU */
1790         for (cpu = 0; cpu < cpu_nr; cpu++) {
1791                 st_irq_i = st_irq[curr] + cpu + 1;
1792                 st_irq_i->irq_nr = 0;
1793         }
1794
1795         if ((fp = fopen(file, "r")) != NULL) {
1796
1797                 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1798
1799                 /*
1800                  * Parse header line to see which CPUs are online
1801                  */
1802                 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1803                         next = line;
1804                         while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1805                                 cpu = strtol(cp + 3, &next, 10);
1806                                 cpu_index[index++] = cpu;
1807                         }
1808                         if (index)
1809                                 /* Header line found */
1810                                 break;
1811                 }
1812
1813                 /* Parse each line of interrupts statistics data */
1814                 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1815                        (irq < ic_nr)) {
1816
1817                         /* Skip over "<irq>:" */
1818                         if ((cp = strchr(line, ':')) == NULL)
1819                                 /* Chr ':' not found */
1820                                 continue;
1821                         cp++;
1822
1823                         p = st_ic[curr] + irq;
1824
1825                         /* Remove possible heading spaces in interrupt's name... */
1826                         li = line;
1827                         while (*li == ' ')
1828                                 li++;
1829
1830                         len = strcspn(li, ":");
1831                         if (len >= MAX_IRQ_LEN) {
1832                                 len = MAX_IRQ_LEN - 1;
1833                         }
1834                         /* ...then save its name */
1835                         strncpy(p->irq_name, li, len);
1836                         p->irq_name[len] = '\0';
1837
1838                         /* For each interrupt: Get number received by each CPU */
1839                         for (cpu = 0; cpu < index; cpu++) {
1840                                 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1841                                 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1842                                 /*
1843                                  * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1844                                  * This is the same as st_irqcpu->irq_name.
1845                                  * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1846                                  * and total number of interrupts received by current CPU (in stats_irq structure).
1847                                  */
1848                                 p->interrupt = strtoul(cp, &next, 10);
1849                                 st_irq_i->irq_nr += p->interrupt;
1850                                 cp = next;
1851                         }
1852                         irq++;
1853                 }
1854
1855                 fclose(fp);
1856
1857                 free(line);
1858         }
1859
1860         while (irq < ic_nr) {
1861                 /* Nb of interrupts per processor has changed */
1862                 p = st_ic[curr] + irq;
1863                 p->irq_name[0] = '\0';  /* This value means this is a dummy interrupt */
1864                 irq++;
1865         }
1866 }
1867
1868 /*
1869  ***************************************************************************
1870  * Main loop: Read stats from the relevant sources, and display them.
1871  *
1872  * IN:
1873  * @dis_hdr     Set to TRUE if the header line must always be printed.
1874  * @rows        Number of rows of screen.
1875  ***************************************************************************
1876  */
1877 void rw_mpstat_loop(int dis_hdr, int rows)
1878 {
1879         struct stats_cpu *scc;
1880         int i;
1881         int curr = 1, dis = 1;
1882         unsigned long lines = rows;
1883
1884         /* Dont buffer data if redirected to a pipe */
1885         setbuf(stdout, NULL);
1886
1887         /* Read system uptime and CPU stats */
1888         read_uptime(&(uptime_cs[0]));
1889         read_stat_cpu(st_cpu[0], cpu_nr + 1);
1890
1891         /*
1892          * Calculate global CPU stats as the sum of individual ones.
1893          * Done only on SMP machines. On UP machines, we keep the values
1894          * read from /proc/stat for global CPU stats.
1895          */
1896         if (cpu_nr > 1) {
1897                 memset(st_cpu[0], 0, STATS_CPU_SIZE);
1898
1899                 for (i = 1; i <= cpu_nr; i++) {
1900                         scc = st_cpu[0] + i;
1901
1902                         st_cpu[0]->cpu_user += scc->cpu_user;
1903                         st_cpu[0]->cpu_nice += scc->cpu_nice;
1904                         st_cpu[0]->cpu_sys += scc->cpu_sys;
1905                         st_cpu[0]->cpu_idle += scc->cpu_idle;
1906                         st_cpu[0]->cpu_iowait += scc->cpu_iowait;
1907                         st_cpu[0]->cpu_hardirq += scc->cpu_hardirq;
1908                         st_cpu[0]->cpu_steal += scc->cpu_steal;
1909                         st_cpu[0]->cpu_softirq += scc->cpu_softirq;
1910                         st_cpu[0]->cpu_guest += scc->cpu_guest;
1911                         st_cpu[0]->cpu_guest_nice += scc->cpu_guest_nice;
1912                 }
1913         }
1914
1915         /* Read system topology */
1916         if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
1917                 read_topology(cpu_nr, st_cpu_topology);
1918         }
1919
1920         /*
1921          * Read total number of interrupts received among all CPU.
1922          * (this is the first value on the line "intr:" in the /proc/stat file).
1923          */
1924         if (DISPLAY_IRQ_SUM(actflags)) {
1925                 read_stat_irq(st_irq[0], 1);
1926         }
1927
1928         /*
1929          * Read number of interrupts received by each CPU, for each interrupt,
1930          * and compute the total number of interrupts received by each CPU.
1931          */
1932         if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1933                 /* Read this file to display int per CPU or total nr of int per CPU */
1934                 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1935         }
1936         if (DISPLAY_SOFTIRQS(actflags)) {
1937                 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1938         }
1939
1940         if (!interval) {
1941                 /* Display since boot time */
1942                 mp_tstamp[1] = mp_tstamp[0];
1943                 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1944                 memset(st_node[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1945                 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1946                 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1947                 if (DISPLAY_SOFTIRQS(actflags)) {
1948                         memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1949                 }
1950                 write_stats(0, DISP_HDR);
1951                 if (DISPLAY_JSON_OUTPUT(flags)) {
1952                         printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1953                 }
1954                 exit(0);
1955         }
1956
1957         /* Set a handler for SIGALRM */
1958         memset(&alrm_act, 0, sizeof(alrm_act));
1959         alrm_act.sa_handler = alarm_handler;
1960         sigaction(SIGALRM, &alrm_act, NULL);
1961         alarm(interval);
1962
1963         /* Save the first stats collected. Will be used to compute the average */
1964         mp_tstamp[2] = mp_tstamp[0];
1965         uptime_cs[2] = uptime_cs[0];
1966         memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1967         memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
1968         memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1969         memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1970         if (DISPLAY_SOFTIRQS(actflags)) {
1971                 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1972                        STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1973         }
1974
1975         /* Set a handler for SIGINT */
1976         memset(&int_act, 0, sizeof(int_act));
1977         int_act.sa_handler = int_handler;
1978         sigaction(SIGINT, &int_act, NULL);
1979
1980         __pause();
1981
1982         if (sigint_caught)
1983                 /* SIGINT signal caught during first interval: Exit immediately */
1984                 return;
1985
1986         do {
1987                 /*
1988                  * Resetting the structure not needed since every fields will be set.
1989                  * Exceptions are per-CPU structures: Some of them may not be filled
1990                  * if corresponding processor is disabled (offline). We set them to zero
1991                  * to be able to distinguish between offline and tickless CPUs.
1992                  */
1993                 memset(st_cpu[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1994
1995                 /* Get time */
1996                 get_localtime(&(mp_tstamp[curr]), 0);
1997
1998                 /* Read uptime and CPU stats */
1999                 read_uptime(&(uptime_cs[curr]));
2000                 read_stat_cpu(st_cpu[curr], cpu_nr + 1);
2001
2002                 /* Read system topology */
2003                 if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
2004                         read_topology(cpu_nr, st_cpu_topology);
2005                 }
2006
2007                 /* Read total number of interrupts received among all CPU */
2008                 if (DISPLAY_IRQ_SUM(actflags)) {
2009                         read_stat_irq(st_irq[curr], 1);
2010                 }
2011
2012                 /*
2013                  * Read number of interrupts received by each CPU, for each interrupt,
2014                  * and compute the total number of interrupts received by each CPU.
2015                  */
2016                 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
2017                         read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
2018                 }
2019                 if (DISPLAY_SOFTIRQS(actflags)) {
2020                         read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
2021                 }
2022
2023                 /* Write stats */
2024                 if (!dis_hdr) {
2025                         dis = lines / rows;
2026                         if (dis) {
2027                                 lines %= rows;
2028                         }
2029                         lines++;
2030                 }
2031                 write_stats(curr, dis);
2032
2033                 if (count > 0) {
2034                         count--;
2035                 }
2036
2037                 if (count) {
2038
2039                         __pause();
2040
2041                         if (sigint_caught) {
2042                                 /* SIGINT signal caught => Display average stats */
2043                                 count = 0;
2044                         }
2045                         else {
2046                                 if (DISPLAY_JSON_OUTPUT(flags)) {
2047                                         printf(",\n");
2048                                 }
2049                                 curr ^= 1;
2050                         }
2051                 }
2052         }
2053         while (count);
2054
2055         /* Write stats average */
2056         if (DISPLAY_JSON_OUTPUT(flags)) {
2057                 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
2058         }
2059         else {
2060                 write_stats_avg(curr, dis_hdr);
2061         }
2062 }
2063
2064 /*
2065  ***************************************************************************
2066  * Main entry to the program
2067  ***************************************************************************
2068  */
2069 int main(int argc, char **argv)
2070 {
2071         int opt = 0, i, actset = FALSE;
2072         struct utsname header;
2073         int dis_hdr = -1;
2074         int rows = 23;
2075         char *t;
2076
2077 #ifdef USE_NLS
2078         /* Init National Language Support */
2079         init_nls();
2080 #endif
2081
2082         /* Init color strings */
2083         init_colors();
2084
2085         /* Get HZ */
2086         get_HZ();
2087
2088         /* What is the highest processor number on this machine? */
2089         cpu_nr = get_cpu_nr(~0, TRUE);
2090
2091         /* Calculate number of interrupts per processor */
2092         irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
2093                     NR_IRQCPU_PREALLOC;
2094         /* Calculate number of soft interrupts per processor */
2095         softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
2096                         NR_IRQCPU_PREALLOC;
2097
2098         /*
2099          * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
2100          * In this case, we have to allocate 3 structures: global, proc0 and proc1.
2101          */
2102         salloc_mp_struct(cpu_nr + 1);
2103
2104         /* Get NUMA node placement */
2105         node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
2106
2107         while (++opt < argc) {
2108
2109                 if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2110                         /* Get number of decimal places */
2111                         dplaces_nr = atoi(argv[opt] + 6);
2112                         if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2113                                 usage(argv[0]);
2114                         }
2115                 }
2116
2117                 else if (!strcmp(argv[opt], "-I")) {
2118                         if (!argv[++opt]) {
2119                                 usage(argv[0]);
2120                         }
2121                         actset = TRUE;
2122
2123                         for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2124                                 if (!strcmp(t, K_SUM)) {
2125                                         /* Display total number of interrupts per CPU */
2126                                         actflags |= M_D_IRQ_SUM;
2127                                 }
2128                                 else if (!strcmp(t, K_CPU)) {
2129                                         /* Display interrupts per CPU */
2130                                         actflags |= M_D_IRQ_CPU;
2131                                 }
2132                                 else if (!strcmp(t, K_SCPU)) {
2133                                         /* Display soft interrupts per CPU */
2134                                         actflags |= M_D_SOFTIRQS;
2135                                 }
2136                                 else if (!strcmp(t, K_ALL)) {
2137                                         actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2138                                 }
2139                                 else {
2140                                         usage(argv[0]);
2141                                 }
2142                         }
2143                 }
2144
2145                 else if (!strcmp(argv[opt], "-o")) {
2146                         /* Select output format */
2147                         if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2148                                 flags |= F_JSON_OUTPUT;
2149                         }
2150                         else {
2151                                 usage(argv[0]);
2152                         }
2153                 }
2154
2155                 else if (!strcmp(argv[opt], "-N")) {
2156                         if (!argv[++opt]) {
2157                                 usage(argv[0]);
2158                         }
2159                         if (node_nr >= 0) {
2160                                 flags |= F_OPTION_N;
2161                                 actflags |= M_D_NODE;
2162                                 actset = TRUE;
2163                                 dis_hdr = 9;
2164                                 if (parse_values(argv[opt], node_bitmap, node_nr + 1, K_LOWERALL)) {
2165                                         usage(argv[0]);
2166                                 }
2167                         }
2168                 }
2169
2170                 else if (!strcmp(argv[opt], "-P")) {
2171                         /* '-P ALL' can be used on UP machines */
2172                         if (!argv[++opt]) {
2173                                 usage(argv[0]);
2174                         }
2175                         flags |= F_OPTION_P;
2176                         dis_hdr = 9;
2177
2178                         if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
2179                                 usage(argv[0]);
2180                         }
2181                 }
2182
2183                 else if (!strncmp(argv[opt], "-", 1)) {
2184                         for (i = 1; *(argv[opt] + i); i++) {
2185
2186                                 switch (*(argv[opt] + i)) {
2187
2188                                 case 'A':
2189                                         flags |= F_OPTION_A;
2190                                         actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2191                                         if (node_nr >= 0) {
2192                                                 actflags |= M_D_NODE;
2193                                         }
2194                                         actset = TRUE;
2195                                         break;
2196
2197                                 case 'n':
2198                                         /* Display CPU stats based on NUMA node placement */
2199                                         if (node_nr >= 0) {
2200                                                 actflags |= M_D_NODE;
2201                                                 actset = TRUE;
2202                                         }
2203                                         break;
2204
2205                                 case 'T':
2206                                         /* Display logical topology */
2207                                         flags |= F_TOPOLOGY;
2208                                         break;
2209
2210                                 case 'u':
2211                                         /* Display CPU */
2212                                         actflags |= M_D_CPU;
2213                                         break;
2214
2215                                 case 'V':
2216                                         /* Print version number */
2217                                         print_version();
2218                                         break;
2219
2220                                 default:
2221                                         usage(argv[0]);
2222                                 }
2223                         }
2224                 }
2225
2226                 else if (interval < 0) {
2227                         /* Get interval */
2228                         if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2229                                 usage(argv[0]);
2230                         }
2231                         interval = atol(argv[opt]);
2232                         if (interval < 0) {
2233                                 usage(argv[0]);
2234                         }
2235                         count = -1;
2236                 }
2237
2238                 else if (count <= 0) {
2239                         /* Get count value */
2240                         if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2241                             !interval) {
2242                                 usage(argv[0]);
2243                         }
2244                         count = atol(argv[opt]);
2245                         if (count < 1) {
2246                                 usage(argv[0]);
2247                         }
2248                 }
2249
2250                 else {
2251                         usage(argv[0]);
2252                 }
2253         }
2254
2255         /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
2256         if (!actset ||
2257             (USE_OPTION_P(flags) && !(actflags & ~M_D_NODE))) {
2258                 actflags |= M_D_CPU;
2259         }
2260
2261         if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
2262                 dis_hdr = 9;
2263         }
2264
2265         if (USE_OPTION_A(flags)) {
2266                 /*
2267                  * Set -P ALL -N ALL only if individual CPU and/or nodes
2268                  * have not been selected.
2269                  */
2270                 if ((node_nr >= 0) && !USE_OPTION_N(flags)) {
2271                         memset(node_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
2272                         flags += F_OPTION_N;
2273                 }
2274                 if (!USE_OPTION_P(flags)) {
2275                         memset(cpu_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
2276                         flags += F_OPTION_P;
2277                 }
2278         }
2279
2280         if (!USE_OPTION_P(flags)) {
2281                 /* Option -P not used: Set bit 0 (global stats among all proc) */
2282                 *cpu_bitmap = 1;
2283         }
2284         if (!USE_OPTION_N(flags)) {
2285                 /* Option -N not used: Set bit 0 (global stats among all nodes) */
2286                 *node_bitmap = 1;
2287         }
2288         if (dis_hdr < 0) {
2289                 dis_hdr = 0;
2290         }
2291         if (!dis_hdr) {
2292                 /* Get window size */
2293                 rows = get_win_height();
2294         }
2295         if (interval < 0) {
2296                 /* Interval not set => display stats since boot time */
2297                 interval = 0;
2298         }
2299
2300         if (DISPLAY_JSON_OUTPUT(flags)) {
2301                 /* Use a decimal point to make JSON code compliant with RFC7159 */
2302                 setlocale(LC_NUMERIC, "C");
2303         }
2304
2305         /* Get time */
2306         get_localtime(&(mp_tstamp[0]), 0);
2307
2308         /* Get system name, release number and hostname */
2309         __uname(&header);
2310         print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
2311                          header.nodename, header.machine, get_cpu_nr(~0, FALSE),
2312                          DISPLAY_JSON_OUTPUT(flags));
2313
2314         /* Main loop */
2315         rw_mpstat_loop(dis_hdr, rows);
2316
2317         /* Free structures */
2318         sfree_mp_struct();
2319
2320         return 0;
2321 }