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