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