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