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