]> granicus.if.org Git - sysstat/blob - mpstat.c
Merge branch 'scop-spelling'
[sysstat] / mpstat.c
1 /*
2  * mpstat: per-processor statistics
3  * (C) 2000-2021 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 omitted 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  * @offline_cpu_bitmap
1165  *              CPU bitmap for offline CPU.
1166  ***************************************************************************
1167  */
1168 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1169                                char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
1170 {
1171         struct stats_cpu *scc, *scp;
1172         struct stats_irq *sic, *sip;
1173         unsigned long long pc_itv;
1174         int cpu;
1175
1176         if (dis) {
1177                 printf("\n%-11s  CPU    intr/s\n", prev_string);
1178                 }
1179
1180         if (*cpu_bitmap & 1) {
1181                 printf("%-11s", curr_string);
1182                 cprintf_in(IS_STR, " %s", " all", 0);
1183                 /* Print total number of interrupts among all cpu */
1184                 cprintf_f(NO_UNIT, 1, 9, 2,
1185                           S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1186                 printf("\n");
1187         }
1188
1189         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1190
1191                 sic = st_irq[curr] + cpu;
1192                 sip = st_irq[prev] + cpu;
1193
1194                 scc = st_cpu[curr] + cpu;
1195                 scp = st_cpu[prev] + cpu;
1196
1197                 /* Check if we want stats about this CPU */
1198                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) ||
1199                     offline_cpu_bitmap[cpu >> 3] & (1 << (cpu & 0x07)))
1200                         continue;
1201
1202                 printf("%-11s", curr_string);
1203                 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1204
1205                 /* Recalculate itv for current proc */
1206                 pc_itv = get_per_cpu_interval(scc, scp);
1207
1208                 if (!pc_itv) {
1209                         /* This is a tickless CPU: Value displayed is 0.00 */
1210                         cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1211                         printf("\n");
1212                 }
1213                 else {
1214                         /* Display total number of interrupts for current CPU */
1215                         cprintf_f(NO_UNIT, 1, 9, 2,
1216                                   S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1217                         printf("\n");
1218                 }
1219         }
1220 }
1221
1222 /*
1223  ***************************************************************************
1224  * Display total number of interrupts per CPU in JSON format.
1225  *
1226  * IN:
1227  * @tab         Number of tabs to print.
1228  * @itv         Interval value.
1229  * @prev        Position in array where statistics used as reference are.
1230  *              Stats used as reference may be the previous ones read, or
1231  *              the very first ones when calculating the average.
1232  * @curr        Position in array where current statistics will be saved.
1233  * @offline_cpu_bitmap
1234  *              CPU bitmap for offline CPU.
1235  ***************************************************************************
1236  */
1237 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr,
1238                               unsigned char offline_cpu_bitmap[])
1239 {
1240         struct stats_cpu *scc, *scp;
1241         struct stats_irq *sic, *sip;
1242         unsigned long long pc_itv;
1243         int cpu, next = FALSE;
1244
1245         xprintf(tab++, "\"sum-interrupts\": [");
1246
1247         if (*cpu_bitmap & 1) {
1248
1249                 next = TRUE;
1250                 /* Print total number of interrupts among all cpu */
1251                 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
1252                          S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1253         }
1254
1255         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1256
1257                 sic = st_irq[curr] + cpu;
1258                 sip = st_irq[prev] + cpu;
1259
1260                 scc = st_cpu[curr] + cpu;
1261                 scp = st_cpu[prev] + cpu;
1262
1263                 /* Check if we want stats about this CPU */
1264                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) ||
1265                     offline_cpu_bitmap[cpu >> 3] & (1 << (cpu & 0x07)))
1266                         continue;
1267
1268                 if (next) {
1269                         printf(",\n");
1270                 }
1271                 next = TRUE;
1272
1273                 /* Recalculate itv for current proc */
1274                 pc_itv = get_per_cpu_interval(scc, scp);
1275
1276                 if (!pc_itv) {
1277                         /* This is a tickless CPU: Value displayed is 0.00 */
1278                         xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1279                                  cpu - 1);
1280                 }
1281                 else {
1282                         /* Display total number of interrupts for current CPU */
1283                         xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
1284                                  cpu - 1,
1285                                  S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1286                 }
1287         }
1288         printf("\n");
1289         xprintf0(--tab, "]");
1290 }
1291
1292 /*
1293  ***************************************************************************
1294  * Display total number of interrupts per CPU in plain or JSON format.
1295  *
1296  * IN:
1297  * @dis         TRUE if a header line must be printed.
1298  * @itv         Interval value.
1299  * @prev        Position in array where statistics used as reference are.
1300  *              Stats used as reference may be the previous ones read, or
1301  *              the very first ones when calculating the average.
1302  * @curr        Position in array where current statistics will be saved.
1303  * @prev_string String displayed at the beginning of a header line. This is
1304  *              the timestamp of the previous sample, or "Average" when
1305  *              displaying average stats.
1306  * @curr_string String displayed at the beginning of current sample stats.
1307  *              This is the timestamp of the current sample, or "Average"
1308  *              when displaying average stats.
1309  * @tab         Number of tabs to print (JSON format only).
1310  * @next        TRUE is a previous activity has been displayed (JSON format
1311  *              only).
1312  * @offline_cpu_bitmap
1313  *              CPU bitmap for offline CPU.
1314  ***************************************************************************
1315  */
1316 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1317                          char *prev_string, char *curr_string, int tab, int *next,
1318                          unsigned char offline_cpu_bitmap[])
1319 {
1320         if (DISPLAY_JSON_OUTPUT(flags)) {
1321                 if (*next) {
1322                         printf(",\n");
1323                 }
1324                 *next = TRUE;
1325                 write_json_isumcpu_stats(tab, itv, prev, curr, offline_cpu_bitmap);
1326         }
1327         else {
1328                 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1329                                           offline_cpu_bitmap);
1330         }
1331 }
1332
1333 /*
1334  ***************************************************************************
1335  * Display interrupts statistics for each CPU in plain format.
1336  *
1337  * IN:
1338  * @st_ic       Array for per-CPU statistics.
1339  * @ic_nr       Number of interrupts (hard or soft) per CPU.
1340  * @dis         TRUE if a header line must be printed.
1341  * @itv         Interval value.
1342  * @prev        Position in array where statistics used as reference are.
1343  *              Stats used as reference may be the previous ones read, or
1344  *              the very first ones when calculating the average.
1345  * @curr        Position in array where current statistics will be saved.
1346  * @prev_string String displayed at the beginning of a header line. This is
1347  *              the timestamp of the previous sample, or "Average" when
1348  *              displaying average stats.
1349  * @curr_string String displayed at the beginning of current sample stats.
1350  *              This is the timestamp of the current sample, or "Average"
1351  *              when displaying average stats.
1352  * @offline_cpu_bitmap
1353  *              CPU bitmap for offline CPU.
1354  ***************************************************************************
1355  */
1356 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1357                               unsigned long long itv, int prev, int curr,
1358                               char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
1359 {
1360         int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
1361         struct stats_irqcpu *p, *q, *p0, *q0;
1362
1363         /*
1364          * Check if number of interrupts has changed.
1365          * If this is the case, the header line will be printed again.
1366          * NB: A zero interval value indicates that we are
1367          * displaying statistics since system startup.
1368          */
1369         if (!dis && interval) {
1370                 for (j = 0; j < ic_nr; j++) {
1371                         p0 = st_ic[curr] + j;
1372                         q0 = st_ic[prev] + j;
1373                         if (strcmp(p0->irq_name, q0->irq_name))
1374                                 /*
1375                                  * These are two different interrupts: The header must be displayed
1376                                  * (maybe an interrupt has disappeared, or a new one has just been registered).
1377                                  * Note that we compare even empty strings for the case where
1378                                  * a disappearing interrupt would be the last one in the list.
1379                                  */
1380                                 break;
1381                 }
1382         }
1383
1384         if (dis || (j < ic_nr)) {
1385                 /* Print header */
1386                 printf("\n%-11s  CPU", prev_string);
1387                 for (j = 0; j < ic_nr; j++) {
1388                         p0 = st_ic[curr] + j;
1389                         if (p0->irq_name[0] == '\0')
1390                                 /* End of the list of interrupts */
1391                                 break;
1392                         printf(" %8s/s", p0->irq_name);
1393                 }
1394                 printf("\n");
1395         }
1396
1397         /* Calculate column widths */
1398         for (j = 0; j < ic_nr; j++) {
1399                 p0 = st_ic[curr] + j;
1400                 /*
1401                  * Width is IRQ name + 2 for the trailing "/s".
1402                  * Width is calculated even for "undefined" interrupts (with
1403                  * an empty irq_name string) to quiet code analysis tools.
1404                  */
1405                 colwidth[j] = strlen(p0->irq_name) + 2;
1406                 /*
1407                  * Normal space for printing a number is 11 chars
1408                  * (space + 10 digits including the period).
1409                  */
1410                 if (colwidth[j] < 10) {
1411                         colwidth[j] = 10;
1412                 }
1413         }
1414
1415         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1416
1417                 /*
1418                  * Check if we want stats about this CPU.
1419                  * CPU must have been explicitly selected using option -P,
1420                  * else we display every CPU (unless it's offline).
1421                  */
1422                 if ((!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags)) ||
1423                     offline_cpu_bitmap[cpu >> 3] & (1 << (cpu & 0x07)))
1424                         continue;
1425
1426                 printf("%-11s", curr_string);
1427                 cprintf_in(IS_INT, "  %3d", "", cpu - 1);
1428
1429                 for (j = 0; j < ic_nr; j++) {
1430                         p0 = st_ic[curr] + j;   /* irq_name set only for CPU#0 */
1431                         /*
1432                          * An empty string for irq_name means it is a remaining interrupt
1433                          * which is no longer used, for example because the
1434                          * number of interrupts has decreased in /proc/interrupts.
1435                          */
1436                         if (p0->irq_name[0] == '\0')
1437                                 /* End of the list of interrupts */
1438                                 break;
1439                         q0 = st_ic[prev] + j;
1440                         offset = j;
1441
1442                         /*
1443                          * If we want stats for the time since system startup,
1444                          * we have p0->irq_name != q0->irq_name, since q0 structure
1445                          * is completely set to zero.
1446                          */
1447                         if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1448                                 /* Check if interrupt exists elsewhere in list */
1449                                 for (offset = 0; offset < ic_nr; offset++) {
1450                                         q0 = st_ic[prev] + offset;
1451                                         if (!strcmp(p0->irq_name, q0->irq_name))
1452                                                 /* Interrupt found at another position */
1453                                                 break;
1454                                 }
1455                         }
1456
1457                         p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1458
1459                         if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1460                                 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1461                                 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1462                                           S_VALUE(q->interrupt, p->interrupt, itv));
1463                         }
1464                         else {
1465                                 /*
1466                                  * Instead of printing "N/A", assume that previous value
1467                                  * for this new interrupt was zero.
1468                                  */
1469                                 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1470                                           S_VALUE(0, p->interrupt, itv));
1471                         }
1472                 }
1473                 printf("\n");
1474         }
1475 }
1476
1477 /*
1478  ***************************************************************************
1479  * Display interrupts statistics for each CPU in JSON format.
1480  *
1481  * IN:
1482  * @tab         Number of tabs to print.
1483  * @st_ic       Array for per-CPU statistics.
1484  * @ic_nr       Number of interrupts (hard or soft) per CPU.
1485  * @itv         Interval value.
1486  * @prev        Position in array where statistics used as reference are.
1487  *              Stats used as reference may be the previous ones read, or
1488  *              the very first ones when calculating the average.
1489  * @curr        Position in array where current statistics will be saved.
1490  * @type        Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1491  * @offline_cpu_bitmap
1492  *              CPU bitmap for offline CPU.
1493  ***************************************************************************
1494  */
1495 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
1496                              unsigned long long itv, int prev, int curr, int type,
1497                              unsigned char offline_cpu_bitmap[])
1498 {
1499         int j = ic_nr, offset, cpu;
1500         struct stats_irqcpu *p, *q, *p0, *q0;
1501         int nextcpu = FALSE, nextirq;
1502
1503         if (type == M_D_IRQ_CPU) {
1504                 xprintf(tab++, "\"individual-interrupts\": [");
1505         }
1506         else {
1507                 xprintf(tab++, "\"soft-interrupts\": [");
1508         }
1509
1510         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1511
1512                 /*
1513                  * Check if we want stats about this CPU.
1514                  * CPU must have been explicitly selected using option -P,
1515                  * else we display every CPU (unless it's offline).
1516                  */
1517                 if ((!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags)) ||
1518                     offline_cpu_bitmap[cpu >> 3] & (1 << (cpu & 0x07)))
1519                         continue;
1520
1521                 if (nextcpu) {
1522                         printf(",\n");
1523                 }
1524                 nextcpu = TRUE;
1525                 nextirq = FALSE;
1526                 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1527
1528                 for (j = 0; j < ic_nr; j++) {
1529
1530                         p0 = st_ic[curr] + j;   /* irq_name set only for CPU#0 */
1531                         /*
1532                          * An empty string for irq_name means it is a remaining interrupt
1533                          * which is no longer used, for example because the
1534                          * number of interrupts has decreased in /proc/interrupts.
1535                          */
1536                         if (p0->irq_name[0] == '\0')
1537                                 /* End of the list of interrupts */
1538                                 break;
1539                         q0 = st_ic[prev] + j;
1540                         offset = j;
1541
1542                         if (nextirq) {
1543                                 printf(",\n");
1544                         }
1545                         nextirq = TRUE;
1546
1547                         /*
1548                          * If we want stats for the time since system startup,
1549                          * we have p0->irq_name != q0->irq_name, since q0 structure
1550                          * is completely set to zero.
1551                          */
1552                         if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1553                                 /* Check if interrupt exists elsewhere in list */
1554                                 for (offset = 0; offset < ic_nr; offset++) {
1555                                         q0 = st_ic[prev] + offset;
1556                                         if (!strcmp(p0->irq_name, q0->irq_name))
1557                                                 /* Interrupt found at another position */
1558                                                 break;
1559                                 }
1560                         }
1561
1562                         p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1563
1564                         if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1565                                 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1566                                 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1567                                          p0->irq_name,
1568                                          S_VALUE(q->interrupt, p->interrupt, itv));
1569                         }
1570                         else {
1571                                 /*
1572                                  * Instead of printing "N/A", assume that previous value
1573                                  * for this new interrupt was zero.
1574                                  */
1575                                 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1576                                          p0->irq_name,
1577                                          S_VALUE(0, p->interrupt, itv));
1578                         }
1579                 }
1580                 printf("\n");
1581                 xprintf0(--tab, "] }");
1582         }
1583         printf("\n");
1584         xprintf0(--tab, "]");
1585 }
1586
1587 /*
1588  ***************************************************************************
1589  * Display interrupts statistics for each CPU in plain or JSON format.
1590  *
1591  * IN:
1592  * @st_ic       Array for per-CPU statistics.
1593  * @ic_nr       Number of interrupts (hard or soft) per CPU.
1594  * @dis         TRUE if a header line must be printed.
1595  * @itv         Interval value.
1596  * @prev        Position in array where statistics used as reference are.
1597  *              Stats used as reference may be the previous ones read, or
1598  *              the very first ones when calculating the average.
1599  * @curr        Position in array where current statistics will be saved.
1600  * @prev_string String displayed at the beginning of a header line. This is
1601  *              the timestamp of the previous sample, or "Average" when
1602  *              displaying average stats.
1603  * @curr_string String displayed at the beginning of current sample stats.
1604  *              This is the timestamp of the current sample, or "Average"
1605  *              when displaying average stats.
1606  * @tab         Number of tabs to print (JSON format only).
1607  * @next        TRUE is a previous activity has been displayed (JSON format
1608  *              only).
1609  * @type        Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1610  * @offline_cpu_bitmap
1611  *              CPU bitmap for offline CPU.
1612  ***************************************************************************
1613  */
1614 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1615                         unsigned long long itv, int prev, int curr,
1616                         char *prev_string, char *curr_string, int tab,
1617                         int *next, int type, unsigned char offline_cpu_bitmap[])
1618 {
1619         if (DISPLAY_JSON_OUTPUT(flags)) {
1620                 if (*next) {
1621                         printf(",\n");
1622                 }
1623                 *next = TRUE;
1624                 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type,
1625                                         offline_cpu_bitmap);
1626         }
1627         else {
1628                 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1629                                          prev_string, curr_string, offline_cpu_bitmap);
1630         }
1631 }
1632
1633 /*
1634  ***************************************************************************
1635  * Core function used to display statistics.
1636  *
1637  * IN:
1638  * @prev        Position in array where statistics used as reference are.
1639  *              Stats used as reference may be the previous ones read, or
1640  *              the very first ones when calculating the average.
1641  * @curr        Position in array where statistics for current sample are.
1642  * @dis         TRUE if a header line must be printed.
1643  * @prev_string String displayed at the beginning of a header line. This is
1644  *              the timestamp of the previous sample, or "Average" when
1645  *              displaying average stats.
1646  * @curr_string String displayed at the beginning of current sample stats.
1647  *              This is the timestamp of the current sample, or "Average"
1648  *              when displaying average stats.
1649  ***************************************************************************
1650  */
1651 void write_stats_core(int prev, int curr, int dis,
1652                       char *prev_string, char *curr_string)
1653 {
1654         unsigned long long itv, deltot_jiffies = 1;
1655         int tab = 4, next = FALSE;
1656         unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
1657
1658         /* Test stdout */
1659         TEST_STDOUT(STDOUT_FILENO);
1660
1661         /*
1662          * Compute CPU "all" as sum of all individual CPU (on SMP machines)
1663          * and look for offline CPU.
1664          */
1665         deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
1666
1667         if (DISPLAY_JSON_OUTPUT(flags)) {
1668                 xprintf(tab++, "{");
1669                 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1670         }
1671
1672         /* Get time interval */
1673         itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
1674
1675         /* Print CPU stats */
1676         if (DISPLAY_CPU(actflags)) {
1677                 write_cpu_stats(dis, deltot_jiffies, prev, curr,
1678                                 prev_string, curr_string, tab, &next, offline_cpu_bitmap);
1679         }
1680
1681         /* Print node CPU stats */
1682         if (DISPLAY_NODE(actflags)) {
1683                 set_node_cpu_stats(prev, curr);
1684                 write_node_stats(dis, deltot_jiffies, prev, curr, prev_string,
1685                                  curr_string, tab, &next);
1686         }
1687
1688         /* Print total number of interrupts per processor */
1689         if (DISPLAY_IRQ_SUM(actflags)) {
1690                 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1691                                     tab, &next, offline_cpu_bitmap);
1692         }
1693
1694         /* Display each interrupt value for each CPU */
1695         if (DISPLAY_IRQ_CPU(actflags)) {
1696                 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1697                                    prev_string, curr_string, tab, &next, M_D_IRQ_CPU,
1698                                    offline_cpu_bitmap);
1699         }
1700         if (DISPLAY_SOFTIRQS(actflags)) {
1701                 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1702                                    prev_string, curr_string, tab, &next, M_D_SOFTIRQS,
1703                                    offline_cpu_bitmap);
1704         }
1705
1706         if (DISPLAY_JSON_OUTPUT(flags)) {
1707                 printf("\n");
1708                 xprintf0(--tab, "}");
1709         }
1710 }
1711
1712 /*
1713  ***************************************************************************
1714  * Print statistics average.
1715  *
1716  * IN:
1717  * @curr        Position in array where statistics for current sample are.
1718  * @dis         TRUE if a header line must be printed.
1719  ***************************************************************************
1720  */
1721 void write_stats_avg(int curr, int dis)
1722 {
1723         char string[16];
1724
1725         strncpy(string, _("Average:"), 16);
1726         string[15] = '\0';
1727         write_stats_core(2, curr, dis, string, string);
1728 }
1729
1730 /*
1731  ***************************************************************************
1732  * Print statistics.
1733  *
1734  * IN:
1735  * @curr        Position in array where statistics for current sample are.
1736  * @dis         TRUE if a header line must be printed.
1737  ***************************************************************************
1738  */
1739 void write_stats(int curr, int dis)
1740 {
1741         char cur_time[2][TIMESTAMP_LEN];
1742
1743         /* Get previous timestamp */
1744         if (is_iso_time_fmt()) {
1745                 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1746         }
1747         else {
1748                 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1749         }
1750
1751         /* Get current timestamp */
1752         if (is_iso_time_fmt()) {
1753                 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &mp_tstamp[curr]);
1754         }
1755         else {
1756                 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1757         }
1758
1759         write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1760 }
1761
1762 /*
1763  ***************************************************************************
1764  * Read stats from /proc/interrupts or /proc/softirqs.
1765  *
1766  * IN:
1767  * @file        /proc file to read (interrupts or softirqs).
1768  * @ic_nr       Number of interrupts (hard or soft) per CPU.
1769  * @curr        Position in array where current statistics will be saved.
1770  *
1771  * OUT:
1772  * @st_ic       Array for per-CPU interrupts statistics.
1773  ***************************************************************************
1774  */
1775 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1776 {
1777         FILE *fp;
1778         struct stats_irq *st_irq_i;
1779         struct stats_irqcpu *p;
1780         char *line = NULL, *li;
1781         unsigned long irq = 0;
1782         unsigned int cpu;
1783         int cpu_index[cpu_nr], index = 0, len;
1784         char *cp, *next;
1785
1786         /* Reset total number of interrupts received by each CPU */
1787         for (cpu = 0; cpu < cpu_nr; cpu++) {
1788                 st_irq_i = st_irq[curr] + cpu + 1;
1789                 st_irq_i->irq_nr = 0;
1790         }
1791
1792         if ((fp = fopen(file, "r")) != NULL) {
1793
1794                 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1795
1796                 /*
1797                  * Parse header line to see which CPUs are online
1798                  */
1799                 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1800                         next = line;
1801                         while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1802                                 cpu = strtol(cp + 3, &next, 10);
1803                                 cpu_index[index++] = cpu;
1804                         }
1805                         if (index)
1806                                 /* Header line found */
1807                                 break;
1808                 }
1809
1810                 /* Parse each line of interrupts statistics data */
1811                 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1812                        (irq < ic_nr)) {
1813
1814                         /* Skip over "<irq>:" */
1815                         if ((cp = strchr(line, ':')) == NULL)
1816                                 /* Chr ':' not found */
1817                                 continue;
1818                         cp++;
1819
1820                         p = st_ic[curr] + irq;
1821
1822                         /* Remove possible heading spaces in interrupt's name... */
1823                         li = line;
1824                         while (*li == ' ')
1825                                 li++;
1826
1827                         len = strcspn(li, ":");
1828                         if (len >= MAX_IRQ_LEN) {
1829                                 len = MAX_IRQ_LEN - 1;
1830                         }
1831                         /* ...then save its name */
1832                         strncpy(p->irq_name, li, len);
1833                         p->irq_name[len] = '\0';
1834
1835                         /* For each interrupt: Get number received by each CPU */
1836                         for (cpu = 0; cpu < index; cpu++) {
1837                                 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1838                                 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1839                                 /*
1840                                  * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1841                                  * This is the same as st_irqcpu->irq_name.
1842                                  * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1843                                  * and total number of interrupts received by current CPU (in stats_irq structure).
1844                                  */
1845                                 p->interrupt = strtoul(cp, &next, 10);
1846                                 st_irq_i->irq_nr += p->interrupt;
1847                                 cp = next;
1848                         }
1849                         irq++;
1850                 }
1851
1852                 fclose(fp);
1853
1854                 free(line);
1855         }
1856
1857         while (irq < ic_nr) {
1858                 /* Nb of interrupts per processor has changed */
1859                 p = st_ic[curr] + irq;
1860                 p->irq_name[0] = '\0';  /* This value means this is a dummy interrupt */
1861                 irq++;
1862         }
1863 }
1864
1865 /*
1866  ***************************************************************************
1867  * Main loop: Read stats from the relevant sources, and display them.
1868  *
1869  * IN:
1870  * @dis_hdr     Set to TRUE if the header line must always be printed.
1871  * @rows        Number of rows of screen.
1872  ***************************************************************************
1873  */
1874 void rw_mpstat_loop(int dis_hdr, int rows)
1875 {
1876         struct stats_cpu *scc;
1877         int i;
1878         int curr = 1, dis = 1;
1879         unsigned long lines = rows;
1880
1881         /* Read system uptime and CPU stats */
1882         read_uptime(&(uptime_cs[0]));
1883         read_stat_cpu(st_cpu[0], cpu_nr + 1);
1884
1885         /*
1886          * Calculate global CPU stats as the sum of individual ones.
1887          * Done only on SMP machines. On UP machines, we keep the values
1888          * read from /proc/stat for global CPU stats.
1889          */
1890         if (cpu_nr > 1) {
1891                 memset(st_cpu[0], 0, STATS_CPU_SIZE);
1892
1893                 for (i = 1; i <= cpu_nr; i++) {
1894                         scc = st_cpu[0] + i;
1895
1896                         st_cpu[0]->cpu_user += scc->cpu_user;
1897                         st_cpu[0]->cpu_nice += scc->cpu_nice;
1898                         st_cpu[0]->cpu_sys += scc->cpu_sys;
1899                         st_cpu[0]->cpu_idle += scc->cpu_idle;
1900                         st_cpu[0]->cpu_iowait += scc->cpu_iowait;
1901                         st_cpu[0]->cpu_hardirq += scc->cpu_hardirq;
1902                         st_cpu[0]->cpu_steal += scc->cpu_steal;
1903                         st_cpu[0]->cpu_softirq += scc->cpu_softirq;
1904                         st_cpu[0]->cpu_guest += scc->cpu_guest;
1905                         st_cpu[0]->cpu_guest_nice += scc->cpu_guest_nice;
1906                 }
1907         }
1908
1909         /* Read system topology */
1910         if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
1911                 read_topology(cpu_nr, st_cpu_topology);
1912         }
1913
1914         /*
1915          * Read total number of interrupts received among all CPU.
1916          * (this is the first value on the line "intr:" in the /proc/stat file).
1917          */
1918         if (DISPLAY_IRQ_SUM(actflags)) {
1919                 read_stat_irq(st_irq[0], 1);
1920         }
1921
1922         /*
1923          * Read number of interrupts received by each CPU, for each interrupt,
1924          * and compute the total number of interrupts received by each CPU.
1925          */
1926         if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1927                 /* Read this file to display int per CPU or total nr of int per CPU */
1928                 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1929         }
1930         if (DISPLAY_SOFTIRQS(actflags)) {
1931                 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1932         }
1933
1934         if (!interval) {
1935                 /* Display since boot time */
1936                 mp_tstamp[1] = mp_tstamp[0];
1937                 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1938                 memset(st_node[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1939                 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1940                 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1941                 if (DISPLAY_SOFTIRQS(actflags)) {
1942                         memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1943                 }
1944                 write_stats(0, DISP_HDR);
1945                 if (DISPLAY_JSON_OUTPUT(flags)) {
1946                         printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1947                 }
1948                 exit(0);
1949         }
1950
1951         /* Set a handler for SIGALRM */
1952         memset(&alrm_act, 0, sizeof(alrm_act));
1953         alrm_act.sa_handler = alarm_handler;
1954         sigaction(SIGALRM, &alrm_act, NULL);
1955         alarm(interval);
1956
1957         /* Save the first stats collected. Will be used to compute the average */
1958         mp_tstamp[2] = mp_tstamp[0];
1959         uptime_cs[2] = uptime_cs[0];
1960         memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1961         memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
1962         memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1963         memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1964         if (DISPLAY_SOFTIRQS(actflags)) {
1965                 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1966                        STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1967         }
1968
1969         /* Set a handler for SIGINT */
1970         memset(&int_act, 0, sizeof(int_act));
1971         int_act.sa_handler = int_handler;
1972         sigaction(SIGINT, &int_act, NULL);
1973
1974         __pause();
1975
1976         if (sigint_caught)
1977                 /* SIGINT signal caught during first interval: Exit immediately */
1978                 return;
1979
1980         do {
1981                 /*
1982                  * Resetting the structure not needed since every fields will be set.
1983                  * Exceptions are per-CPU structures: Some of them may not be filled
1984                  * if corresponding processor is disabled (offline). We set them to zero
1985                  * to be able to distinguish between offline and tickless CPUs.
1986                  */
1987                 memset(st_cpu[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1988
1989                 /* Get time */
1990                 get_localtime(&(mp_tstamp[curr]), 0);
1991
1992                 /* Read uptime and CPU stats */
1993                 read_uptime(&(uptime_cs[curr]));
1994                 read_stat_cpu(st_cpu[curr], cpu_nr + 1);
1995
1996                 /* Read system topology */
1997                 if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
1998                         read_topology(cpu_nr, st_cpu_topology);
1999                 }
2000
2001                 /* Read total number of interrupts received among all CPU */
2002                 if (DISPLAY_IRQ_SUM(actflags)) {
2003                         read_stat_irq(st_irq[curr], 1);
2004                 }
2005
2006                 /*
2007                  * Read number of interrupts received by each CPU, for each interrupt,
2008                  * and compute the total number of interrupts received by each CPU.
2009                  */
2010                 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
2011                         read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
2012                 }
2013                 if (DISPLAY_SOFTIRQS(actflags)) {
2014                         read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
2015                 }
2016
2017                 /* Write stats */
2018                 if (!dis_hdr) {
2019                         dis = lines / rows;
2020                         if (dis) {
2021                                 lines %= rows;
2022                         }
2023                         lines++;
2024                 }
2025                 write_stats(curr, dis);
2026
2027                 if (count > 0) {
2028                         count--;
2029                 }
2030
2031                 if (count) {
2032
2033                         __pause();
2034
2035                         if (sigint_caught) {
2036                                 /* SIGINT signal caught => Display average stats */
2037                                 count = 0;
2038                         }
2039                         else {
2040                                 if (DISPLAY_JSON_OUTPUT(flags)) {
2041                                         printf(",\n");
2042                                 }
2043                                 curr ^= 1;
2044                         }
2045                 }
2046         }
2047         while (count);
2048
2049         /* Write stats average */
2050         if (DISPLAY_JSON_OUTPUT(flags)) {
2051                 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
2052         }
2053         else {
2054                 write_stats_avg(curr, dis_hdr);
2055         }
2056 }
2057
2058 /*
2059  ***************************************************************************
2060  * Main entry to the program
2061  ***************************************************************************
2062  */
2063 int main(int argc, char **argv)
2064 {
2065         int opt = 0, i, actset = FALSE;
2066         struct utsname header;
2067         int dis_hdr = -1;
2068         int rows = 23;
2069         char *t;
2070
2071 #ifdef USE_NLS
2072         /* Init National Language Support */
2073         init_nls();
2074 #endif
2075
2076         /* Init color strings */
2077         init_colors();
2078
2079         /* Get HZ */
2080         get_HZ();
2081
2082         /* What is the highest processor number on this machine? */
2083         cpu_nr = get_cpu_nr(~0, TRUE);
2084
2085         /* Calculate number of interrupts per processor */
2086         irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
2087                     NR_IRQCPU_PREALLOC;
2088         /* Calculate number of soft interrupts per processor */
2089         softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
2090                         NR_IRQCPU_PREALLOC;
2091
2092         /*
2093          * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
2094          * In this case, we have to allocate 3 structures: global, proc0 and proc1.
2095          */
2096         salloc_mp_struct(cpu_nr + 1);
2097
2098         /* Get NUMA node placement */
2099         node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
2100
2101         while (++opt < argc) {
2102
2103                 if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2104                         /* Get number of decimal places */
2105                         dplaces_nr = atoi(argv[opt] + 6);
2106                         if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2107                                 usage(argv[0]);
2108                         }
2109                 }
2110
2111                 else if (!strcmp(argv[opt], "-I")) {
2112                         if (!argv[++opt]) {
2113                                 usage(argv[0]);
2114                         }
2115                         actset = TRUE;
2116
2117                         for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2118                                 if (!strcmp(t, K_SUM)) {
2119                                         /* Display total number of interrupts per CPU */
2120                                         actflags |= M_D_IRQ_SUM;
2121                                 }
2122                                 else if (!strcmp(t, K_CPU)) {
2123                                         /* Display interrupts per CPU */
2124                                         actflags |= M_D_IRQ_CPU;
2125                                 }
2126                                 else if (!strcmp(t, K_SCPU)) {
2127                                         /* Display soft interrupts per CPU */
2128                                         actflags |= M_D_SOFTIRQS;
2129                                 }
2130                                 else if (!strcmp(t, K_ALL)) {
2131                                         actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2132                                 }
2133                                 else {
2134                                         usage(argv[0]);
2135                                 }
2136                         }
2137                 }
2138
2139                 else if (!strcmp(argv[opt], "-o")) {
2140                         /* Select output format */
2141                         if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2142                                 flags |= F_JSON_OUTPUT;
2143                         }
2144                         else {
2145                                 usage(argv[0]);
2146                         }
2147                 }
2148
2149                 else if (!strcmp(argv[opt], "-N")) {
2150                         if (!argv[++opt]) {
2151                                 usage(argv[0]);
2152                         }
2153                         if (node_nr >= 0) {
2154                                 flags |= F_OPTION_N;
2155                                 actflags |= M_D_NODE;
2156                                 actset = TRUE;
2157                                 dis_hdr = 9;
2158                                 if (parse_values(argv[opt], node_bitmap, node_nr + 1, K_LOWERALL)) {
2159                                         usage(argv[0]);
2160                                 }
2161                         }
2162                 }
2163
2164                 else if (!strcmp(argv[opt], "-P")) {
2165                         /* '-P ALL' can be used on UP machines */
2166                         if (!argv[++opt]) {
2167                                 usage(argv[0]);
2168                         }
2169                         flags |= F_OPTION_P;
2170                         dis_hdr = 9;
2171
2172                         if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
2173                                 usage(argv[0]);
2174                         }
2175                 }
2176
2177                 else if (!strncmp(argv[opt], "-", 1)) {
2178                         for (i = 1; *(argv[opt] + i); i++) {
2179
2180                                 switch (*(argv[opt] + i)) {
2181
2182                                 case 'A':
2183                                         flags |= F_OPTION_A;
2184                                         actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2185                                         if (node_nr >= 0) {
2186                                                 actflags |= M_D_NODE;
2187                                         }
2188                                         actset = TRUE;
2189                                         break;
2190
2191                                 case 'n':
2192                                         /* Display CPU stats based on NUMA node placement */
2193                                         if (node_nr >= 0) {
2194                                                 actflags |= M_D_NODE;
2195                                                 actset = TRUE;
2196                                         }
2197                                         break;
2198
2199                                 case 'T':
2200                                         /* Display logical topology */
2201                                         flags |= F_TOPOLOGY;
2202                                         break;
2203
2204                                 case 'u':
2205                                         /* Display CPU */
2206                                         actflags |= M_D_CPU;
2207                                         break;
2208
2209                                 case 'V':
2210                                         /* Print version number */
2211                                         print_version();
2212                                         break;
2213
2214                                 default:
2215                                         usage(argv[0]);
2216                                 }
2217                         }
2218                 }
2219
2220                 else if (interval < 0) {
2221                         /* Get interval */
2222                         if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2223                                 usage(argv[0]);
2224                         }
2225                         interval = atol(argv[opt]);
2226                         if (interval < 0) {
2227                                 usage(argv[0]);
2228                         }
2229                         count = -1;
2230                 }
2231
2232                 else if (count <= 0) {
2233                         /* Get count value */
2234                         if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2235                             !interval) {
2236                                 usage(argv[0]);
2237                         }
2238                         count = atol(argv[opt]);
2239                         if (count < 1) {
2240                                 usage(argv[0]);
2241                         }
2242                 }
2243
2244                 else {
2245                         usage(argv[0]);
2246                 }
2247         }
2248
2249         /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
2250         if (!actset ||
2251             (USE_OPTION_P(flags) && !(actflags & ~M_D_NODE))) {
2252                 actflags |= M_D_CPU;
2253         }
2254
2255         if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
2256                 dis_hdr = 9;
2257         }
2258
2259         if (USE_OPTION_A(flags)) {
2260                 /*
2261                  * Set -P ALL -N ALL only if individual CPU and/or nodes
2262                  * have not been selected.
2263                  */
2264                 if ((node_nr >= 0) && !USE_OPTION_N(flags)) {
2265                         memset(node_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
2266                         flags += F_OPTION_N;
2267                 }
2268                 if (!USE_OPTION_P(flags)) {
2269                         memset(cpu_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
2270                         flags += F_OPTION_P;
2271                 }
2272         }
2273
2274         if (!USE_OPTION_P(flags)) {
2275                 /* Option -P not used: Set bit 0 (global stats among all proc) */
2276                 *cpu_bitmap = 1;
2277         }
2278         if (!USE_OPTION_N(flags)) {
2279                 /* Option -N not used: Set bit 0 (global stats among all nodes) */
2280                 *node_bitmap = 1;
2281         }
2282         if (dis_hdr < 0) {
2283                 dis_hdr = 0;
2284         }
2285         if (!dis_hdr) {
2286                 /* Get window size */
2287                 rows = get_win_height();
2288         }
2289         if (interval < 0) {
2290                 /* Interval not set => display stats since boot time */
2291                 interval = 0;
2292         }
2293
2294         if (DISPLAY_JSON_OUTPUT(flags)) {
2295                 /* Use a decimal point to make JSON code compliant with RFC7159 */
2296                 setlocale(LC_NUMERIC, "C");
2297         }
2298
2299         /* Get time */
2300         get_localtime(&(mp_tstamp[0]), 0);
2301
2302         /*
2303          * Don't buffer data if redirected to a pipe.
2304          * Note: With musl-c, the behavior of this function is undefined except
2305          * when it is the first operation on the stream.
2306          */
2307         setbuf(stdout, NULL);
2308
2309         /* Get system name, release number and hostname */
2310         __uname(&header);
2311         print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
2312                          header.nodename, header.machine, get_cpu_nr(~0, FALSE),
2313                          DISPLAY_JSON_OUTPUT(flags));
2314
2315         /* Main loop */
2316         rw_mpstat_loop(dis_hdr, rows);
2317
2318         /* Free structures */
2319         sfree_mp_struct();
2320
2321         return 0;
2322 }