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