2 * mpstat: per-processor statistics
3 * (C) 2000-2017 by Sebastien GODARD (sysstat <at> orange.fr)
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. *
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 *
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 ***************************************************************************
30 #include <sys/utsname.h>
38 #include <locale.h> /* For setlocale() */
41 #define _(string) gettext(string)
43 #define _(string) (string)
47 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
48 char *sccsid(void) { return (SCCSID); }
51 unsigned long long uptime[3] = {0, 0, 0};
52 unsigned long long uptime0[3] = {0, 0, 0};
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. */
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];
63 * Structure used to save total number of interrupts received
64 * among all CPU and for each CPU.
66 struct stats_irq *st_irq[3];
69 * Structures used to save, for each interrupt, the number
70 * received by each CPU.
72 struct stats_irqcpu *st_irqcpu[3];
73 struct stats_irqcpu *st_softirqcpu[3];
76 * Number of CPU per node, e.g.:
77 * cpu_per_node[0]: nr of CPU for node 0..
82 * Node number the CPU belongs to, e.g.:
83 * cpu2node[0]: node nr for CPU 0
87 struct tm mp_tstamp[3];
90 unsigned int actflags = 0;
92 unsigned int flags = 0;
94 /* Interval and count parameters */
95 long interval = -1, count = 0;
98 * Nb of processors on the machine.
99 * A value of 2 means there are 2 processors (0 and 1).
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.
110 /* Nb of interrupts per processor */
112 /* Nb of soft interrupts per processor */
113 int softirqcpu_nr = 0;
115 struct sigaction alrm_act, int_act;
116 int sigint_caught = 0;
119 ***************************************************************************
120 * Print usage and exit
123 * @progname Name of sysstat command
124 ***************************************************************************
126 void usage(char *progname)
128 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
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"));
138 ***************************************************************************
139 * SIGALRM signal handler. No need to reset the handler here.
142 * @sig Signal number.
143 ***************************************************************************
145 void alarm_handler(int sig)
151 ***************************************************************************
152 * SIGINT signal handler.
155 * @sig Signal number.
156 **************************************************************************
158 void int_handler(int sig)
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.
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 ***************************************************************************
174 void salloc_mp_struct(int nr_cpus)
178 for (i = 0; i < 3; i++) {
180 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
185 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
187 if ((st_node[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
192 memset(st_node[i], 0, STATS_CPU_SIZE * nr_cpus);
194 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
199 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
201 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
206 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
208 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
213 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
216 if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
220 memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
222 if ((node_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
226 memset(node_bitmap, 0, (nr_cpus >> 3) + 1);
228 if ((cpu_per_node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
233 if ((cpu2node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
240 ***************************************************************************
241 * Free structures and bitmap.
242 ***************************************************************************
244 void sfree_mp_struct(void)
248 for (i = 0; i < 3; i++) {
253 free(st_softirqcpu[i]);
263 ***************************************************************************
264 * Get node placement (which node each CPU belongs to, and total number of
265 * CPU that each node has).
268 * @cpu_nr Number of CPU on this machine.
271 * @cpu_per_node Number of CPU per node.
272 * @cpu2node The node the CPU belongs to.
275 * Highest node number found (e.g., 0 means node 0).
276 * A value of -1 means no nodes have been found.
277 ***************************************************************************
279 int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
284 char line[MAX_PF_NAME];
285 int cpu, node, node_nr = -1;
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);
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';
296 /* Open relevant /sys directory */
297 if ((dir = opendir(line)) == NULL)
300 /* Get current file entry */
301 while ((drd = readdir(dir)) != NULL) {
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 */
310 cpu_per_node[node]++;
311 cpu2node[cpu] = node;
312 if (node > node_nr) {
315 /* Node placement found for current CPU: Go to next CPU directory */
320 /* Close directory */
328 ***************************************************************************
329 * Compute node statistics: Split CPU statistics among nodes.
332 * @st_cpu Array where current CPU stats have been read.
335 * @st_node Array where CPU stats for each node have been saved.
336 ***************************************************************************
338 void set_node_cpu_stats(struct stats_cpu *st_node, struct stats_cpu *st_cpu)
341 struct stats_cpu *st_cpu_i, *st_node_i;
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;
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;
362 ***************************************************************************
363 * Display CPU statistics in plain format.
366 * @dis TRUE if a header line must be printed.
367 * @g_itv Interval value in jiffies multiplied by the number of CPU.
368 * @prev Position in array where statistics used as reference are.
369 * Stats used as reference may be the previous ones read, or
370 * the very first ones when calculating the average.
371 * @curr Position in array where current statistics will be saved.
372 * @prev_string String displayed at the beginning of a header line. This is
373 * the timestamp of the previous sample, or "Average" when
374 * displaying average stats.
375 * @curr_string String displayed at the beginning of current sample stats.
376 * This is the timestamp of the current sample, or "Average"
377 * when displaying average stats.
378 ***************************************************************************
380 void write_plain_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,
381 char *prev_string, char *curr_string)
383 struct stats_cpu *scc, *scp;
384 unsigned long long pc_itv;
388 printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq "
389 "%%soft %%steal %%guest %%gnice %%idle\n",
393 /* Check if we want global stats among all proc */
394 if (*cpu_bitmap & 1) {
396 printf("%-11s", curr_string);
397 cprintf_in(IS_STR, " %s", " all", 0);
399 cprintf_pc(NO_UNIT, 10, 7, 2,
400 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
401 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
403 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
404 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
406 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
407 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
409 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
410 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
412 ll_sp_value(st_cpu[prev]->cpu_sys,
413 st_cpu[curr]->cpu_sys,
415 ll_sp_value(st_cpu[prev]->cpu_iowait,
416 st_cpu[curr]->cpu_iowait,
418 ll_sp_value(st_cpu[prev]->cpu_hardirq,
419 st_cpu[curr]->cpu_hardirq,
421 ll_sp_value(st_cpu[prev]->cpu_softirq,
422 st_cpu[curr]->cpu_softirq,
424 ll_sp_value(st_cpu[prev]->cpu_steal,
425 st_cpu[curr]->cpu_steal,
427 ll_sp_value(st_cpu[prev]->cpu_guest,
428 st_cpu[curr]->cpu_guest,
430 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
431 st_cpu[curr]->cpu_guest_nice,
433 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
435 ll_sp_value(st_cpu[prev]->cpu_idle,
436 st_cpu[curr]->cpu_idle,
441 for (cpu = 1; cpu <= cpu_nr; cpu++) {
443 scc = st_cpu[curr] + cpu;
444 scp = st_cpu[prev] + cpu;
446 /* Check if we want stats about this proc */
447 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
451 * If the CPU is offline then it is omited from /proc/stat
452 * and the sum of all values is zero.
453 * (Remember that guest/guest_nice times are already included in
456 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
457 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
458 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
460 if (!DISPLAY_ONLINE_CPU(flags)) {
461 printf("%-11s", curr_string);
462 cprintf_in(IS_INT, " %4d", "", cpu - 1);
463 cprintf_pc(NO_UNIT, 10, 7, 2,
464 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
470 printf("%-11s", curr_string);
471 cprintf_in(IS_INT, " %4d", "", cpu - 1);
473 /* Recalculate itv for current proc */
474 pc_itv = get_per_cpu_interval(scc, scp);
478 * If the CPU is tickless then there is no change in CPU values
479 * but the sum of values is not zero.
481 cprintf_pc(NO_UNIT, 10, 7, 2,
482 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
487 cprintf_pc(NO_UNIT, 10, 7, 2,
488 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
490 ll_sp_value(scp->cpu_user - scp->cpu_guest,
491 scc->cpu_user - scc->cpu_guest,
493 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
495 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
496 scc->cpu_nice - scc->cpu_guest_nice,
498 ll_sp_value(scp->cpu_sys,
501 ll_sp_value(scp->cpu_iowait,
504 ll_sp_value(scp->cpu_hardirq,
507 ll_sp_value(scp->cpu_softirq,
510 ll_sp_value(scp->cpu_steal,
513 ll_sp_value(scp->cpu_guest,
516 ll_sp_value(scp->cpu_guest_nice,
519 (scc->cpu_idle < scp->cpu_idle) ?
521 ll_sp_value(scp->cpu_idle,
530 ***************************************************************************
531 * Display CPU statistics in JSON format.
534 * @tab Number of tabs to print.
535 * @g_itv Interval value in jiffies multiplied by the number of CPU.
536 * @prev Position in array where statistics used as reference are.
537 * Stats used as reference may be the previous ones read, or
538 * the very first ones when calculating the average.
539 * @curr Position in array where current statistics will be saved.
540 ***************************************************************************
542 void write_json_cpu_stats(int tab, unsigned long long g_itv, int prev, int curr)
544 struct stats_cpu *scc, *scp;
545 unsigned long long pc_itv;
546 int cpu, next = FALSE;
548 xprintf(tab++, "\"cpu-load\": [");
550 /* Check if we want global stats among all proc */
551 if (*cpu_bitmap & 1) {
554 xprintf0(tab, "{\"cpu\": \"all\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
555 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
556 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
557 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
558 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
560 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
561 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
563 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
564 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
566 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
567 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
569 ll_sp_value(st_cpu[prev]->cpu_sys,
570 st_cpu[curr]->cpu_sys,
572 ll_sp_value(st_cpu[prev]->cpu_iowait,
573 st_cpu[curr]->cpu_iowait,
575 ll_sp_value(st_cpu[prev]->cpu_hardirq,
576 st_cpu[curr]->cpu_hardirq,
578 ll_sp_value(st_cpu[prev]->cpu_softirq,
579 st_cpu[curr]->cpu_softirq,
581 ll_sp_value(st_cpu[prev]->cpu_steal,
582 st_cpu[curr]->cpu_steal,
584 ll_sp_value(st_cpu[prev]->cpu_guest,
585 st_cpu[curr]->cpu_guest,
587 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
588 st_cpu[curr]->cpu_guest_nice,
590 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
592 ll_sp_value(st_cpu[prev]->cpu_idle,
593 st_cpu[curr]->cpu_idle,
597 for (cpu = 1; cpu <= cpu_nr; cpu++) {
599 scc = st_cpu[curr] + cpu;
600 scp = st_cpu[prev] + cpu;
602 /* Check if we want stats about this proc */
603 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
612 * If the CPU is offline then it is omited from /proc/stat
613 * and the sum of all values is zero.
614 * (Remember that guest/guest_nice times are already included in
617 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
618 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
619 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
621 if (!DISPLAY_ONLINE_CPU(flags)) {
622 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
623 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
624 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
625 "\"gnice\": 0.00, \"idle\": 0.00}", cpu - 1);
630 /* Recalculate itv for current proc */
631 pc_itv = get_per_cpu_interval(scc, scp);
635 * If the CPU is tickless then there is no change in CPU values
636 * but the sum of values is not zero.
638 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
639 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
640 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
641 "\"gnice\": 0.00, \"idle\": 100.00}", cpu - 1);
645 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
646 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
647 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", cpu - 1,
648 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
650 ll_sp_value(scp->cpu_user - scp->cpu_guest,
651 scc->cpu_user - scc->cpu_guest,
653 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
655 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
656 scc->cpu_nice - scc->cpu_guest_nice,
658 ll_sp_value(scp->cpu_sys,
661 ll_sp_value(scp->cpu_iowait,
664 ll_sp_value(scp->cpu_hardirq,
667 ll_sp_value(scp->cpu_softirq,
670 ll_sp_value(scp->cpu_steal,
673 ll_sp_value(scp->cpu_guest,
676 ll_sp_value(scp->cpu_guest_nice,
679 (scc->cpu_idle < scp->cpu_idle) ?
681 ll_sp_value(scp->cpu_idle,
687 xprintf0(--tab, "]");
691 ***************************************************************************
692 * Display CPU statistics in plain or JSON format.
695 * @dis TRUE if a header line must be printed.
696 * @g_itv Interval value in jiffies multiplied by the number of CPU.
697 * @prev Position in array where statistics used as reference are.
698 * Stats used as reference may be the previous ones read, or
699 * the very first ones when calculating the average.
700 * @curr Position in array where current statistics will be saved.
701 * @prev_string String displayed at the beginning of a header line. This is
702 * the timestamp of the previous sample, or "Average" when
703 * displaying average stats.
704 * @curr_string String displayed at the beginning of current sample stats.
705 * This is the timestamp of the current sample, or "Average"
706 * when displaying average stats.
707 * @tab Number of tabs to print (JSON format only).
708 * @next TRUE is a previous activity has been displayed (JSON format
710 ***************************************************************************
712 void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,
713 char *prev_string, char *curr_string, int tab, int *next)
715 if (DISPLAY_JSON_OUTPUT(flags)) {
720 write_json_cpu_stats(tab, g_itv, prev, curr);
723 write_plain_cpu_stats(dis, g_itv, prev, curr, prev_string, curr_string);
728 ***************************************************************************
729 * Display CPU statistics for NUMA nodes in plain format.
732 * @dis TRUE if a header line must be printed.
733 * @g_itv Interval value in jiffies multiplied by the number of CPU.
734 * @itv Interval value.
735 * @prev Position in array where statistics used as reference are.
736 * Stats used as reference may be the previous ones read, or
737 * the very first ones when calculating the average.
738 * @curr Position in array where current statistics will be saved.
739 * @prev_string String displayed at the beginning of a header line. This is
740 * the timestamp of the previous sample, or "Average" when
741 * displaying average stats.
742 * @curr_string String displayed at the beginning of current sample stats.
743 * This is the timestamp of the current sample, or "Average"
744 * when displaying average stats.
745 ***************************************************************************
747 void write_plain_node_stats(int dis, unsigned long long g_itv, unsigned long long itv,
748 int prev, int curr, char *prev_string, char *curr_string)
750 struct stats_cpu *snc, *snp;
754 printf("\n%-11s NODE %%usr %%nice %%sys %%iowait %%irq "
755 "%%soft %%steal %%guest %%gnice %%idle\n",
760 * Check if we want global stats among all nodes.
761 * Stats are the same as global CPU stats among all processors.
763 if (*node_bitmap & 1) {
765 printf("%-11s", curr_string);
766 cprintf_in(IS_STR, " %s", " all", 0);
768 cprintf_pc(NO_UNIT, 10, 7, 2,
769 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
770 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
772 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
773 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
775 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
776 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
778 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
779 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
781 ll_sp_value(st_cpu[prev]->cpu_sys,
782 st_cpu[curr]->cpu_sys,
784 ll_sp_value(st_cpu[prev]->cpu_iowait,
785 st_cpu[curr]->cpu_iowait,
787 ll_sp_value(st_cpu[prev]->cpu_hardirq,
788 st_cpu[curr]->cpu_hardirq,
790 ll_sp_value(st_cpu[prev]->cpu_softirq,
791 st_cpu[curr]->cpu_softirq,
793 ll_sp_value(st_cpu[prev]->cpu_steal,
794 st_cpu[curr]->cpu_steal,
796 ll_sp_value(st_cpu[prev]->cpu_guest,
797 st_cpu[curr]->cpu_guest,
799 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
800 st_cpu[curr]->cpu_guest_nice,
802 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
804 ll_sp_value(st_cpu[prev]->cpu_idle,
805 st_cpu[curr]->cpu_idle,
810 for (node = 0; node <= node_nr; node++) {
812 snc = st_node[curr] + node + 1;
813 snp = st_node[prev] + node + 1;
815 /* Check if we want stats about this node */
816 if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
819 if (!cpu_per_node[node])
820 /* No CPU in this node */
823 printf("%-11s", curr_string);
824 cprintf_in(IS_INT, " %4d", "", node);
826 cprintf_pc(NO_UNIT, 10, 7, 2,
827 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
829 ll_sp_value(snp->cpu_user - snp->cpu_guest,
830 snc->cpu_user - snc->cpu_guest,
831 itv * cpu_per_node[node]),
832 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
834 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
835 snc->cpu_nice - snc->cpu_guest_nice,
836 itv * cpu_per_node[node]),
837 ll_sp_value(snp->cpu_sys,
839 itv * cpu_per_node[node]),
840 ll_sp_value(snp->cpu_iowait,
842 itv * cpu_per_node[node]),
843 ll_sp_value(snp->cpu_hardirq,
845 itv * cpu_per_node[node]),
846 ll_sp_value(snp->cpu_softirq,
848 itv * cpu_per_node[node]),
849 ll_sp_value(snp->cpu_steal,
851 itv * cpu_per_node[node]),
852 ll_sp_value(snp->cpu_guest,
854 itv * cpu_per_node[node]),
855 ll_sp_value(snp->cpu_guest_nice,
857 itv * cpu_per_node[node]),
858 (snc->cpu_idle < snp->cpu_idle) ?
860 ll_sp_value(snp->cpu_idle,
862 itv * cpu_per_node[node]));
868 ***************************************************************************
869 * Display CPU statistics for NUMA nodes in JSON format.
872 * @tab Number of tabs to print.
873 * @g_itv Interval value in jiffies multiplied by the number of CPU.
874 * @itv Interval value.
875 * @prev Position in array where statistics used as reference are.
876 * Stats used as reference may be the previous ones read, or
877 * the very first ones when calculating the average.
878 * @curr Position in array where current statistics will be saved.
879 ***************************************************************************
881 void write_json_node_stats(int tab, unsigned long long g_itv, unsigned long long itv,
884 struct stats_cpu *snc, *snp;
885 int node, next = FALSE;
887 xprintf(tab++, "\"node-load\": [");
889 /* Check if we want global stats among all nodes */
890 if (*node_bitmap & 1) {
893 xprintf0(tab, "{\"node\": \"all\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
894 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
895 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
896 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
897 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
899 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
900 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
902 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
903 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
905 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
906 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
908 ll_sp_value(st_cpu[prev]->cpu_sys,
909 st_cpu[curr]->cpu_sys,
911 ll_sp_value(st_cpu[prev]->cpu_iowait,
912 st_cpu[curr]->cpu_iowait,
914 ll_sp_value(st_cpu[prev]->cpu_hardirq,
915 st_cpu[curr]->cpu_hardirq,
917 ll_sp_value(st_cpu[prev]->cpu_softirq,
918 st_cpu[curr]->cpu_softirq,
920 ll_sp_value(st_cpu[prev]->cpu_steal,
921 st_cpu[curr]->cpu_steal,
923 ll_sp_value(st_cpu[prev]->cpu_guest,
924 st_cpu[curr]->cpu_guest,
926 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
927 st_cpu[curr]->cpu_guest_nice,
929 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
931 ll_sp_value(st_cpu[prev]->cpu_idle,
932 st_cpu[curr]->cpu_idle,
936 for (node = 0; node <= node_nr; node++) {
938 snc = st_node[curr] + node + 1;
939 snp = st_node[prev] + node + 1;
941 /* Check if we want stats about this node */
942 if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
945 if (!cpu_per_node[node])
946 /* No CPU in this node */
954 xprintf0(tab, "{\"node\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
955 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
956 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node,
957 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
959 ll_sp_value(snp->cpu_user - snp->cpu_guest,
960 snc->cpu_user - snc->cpu_guest,
961 itv * cpu_per_node[node]),
962 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
964 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
965 snc->cpu_nice - snc->cpu_guest_nice,
966 itv * cpu_per_node[node]),
967 ll_sp_value(snp->cpu_sys,
969 itv * cpu_per_node[node]),
970 ll_sp_value(snp->cpu_iowait,
972 itv * cpu_per_node[node]),
973 ll_sp_value(snp->cpu_hardirq,
975 itv * cpu_per_node[node]),
976 ll_sp_value(snp->cpu_softirq,
978 itv * cpu_per_node[node]),
979 ll_sp_value(snp->cpu_steal,
981 itv * cpu_per_node[node]),
982 ll_sp_value(snp->cpu_guest,
984 itv * cpu_per_node[node]),
985 ll_sp_value(snp->cpu_guest_nice,
987 itv * cpu_per_node[node]),
988 (snc->cpu_idle < snp->cpu_idle) ?
990 ll_sp_value(snp->cpu_idle,
992 itv * cpu_per_node[node]));
995 xprintf0(--tab, "]");
999 ***************************************************************************
1000 * Display nodes statistics in plain or JSON format.
1003 * @dis TRUE if a header line must be printed.
1004 * @g_itv Interval value in jiffies multiplied by the number of CPU.
1005 * @itv Interval value.
1006 * @prev Position in array where statistics used as reference are.
1007 * Stats used as reference may be the previous ones read, or
1008 * the very first ones when calculating the average.
1009 * @curr Position in array where current statistics will be saved.
1010 * @prev_string String displayed at the beginning of a header line. This is
1011 * the timestamp of the previous sample, or "Average" when
1012 * displaying average stats.
1013 * @curr_string String displayed at the beginning of current sample stats.
1014 * This is the timestamp of the current sample, or "Average"
1015 * when displaying average stats.
1016 * @tab Number of tabs to print (JSON format only).
1017 * @next TRUE is a previous activity has been displayed (JSON format
1019 ***************************************************************************
1021 void write_node_stats(int dis, unsigned long long g_itv, unsigned long long itv,
1022 int prev, int curr, char *prev_string, char *curr_string,
1025 if (DISPLAY_JSON_OUTPUT(flags)) {
1030 write_json_node_stats(tab, g_itv, itv, prev, curr);
1033 write_plain_node_stats(dis, g_itv, itv, prev, curr, prev_string, curr_string);
1038 ***************************************************************************
1039 * Display total number of interrupts per CPU in plain format.
1042 * @dis TRUE if a header line must be printed.
1043 * @itv Interval value.
1044 * @prev Position in array where statistics used as reference are.
1045 * Stats used as reference may be the previous ones read, or
1046 * the very first ones when calculating the average.
1047 * @curr Position in array where current statistics will be saved.
1048 * @prev_string String displayed at the beginning of a header line. This is
1049 * the timestamp of the previous sample, or "Average" when
1050 * displaying average stats.
1051 * @curr_string String displayed at the beginning of current sample stats.
1052 * This is the timestamp of the current sample, or "Average"
1053 * when displaying average stats.
1054 ***************************************************************************
1056 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1057 char *prev_string, char *curr_string)
1059 struct stats_cpu *scc, *scp;
1060 struct stats_irq *sic, *sip;
1061 unsigned long long pc_itv;
1065 printf("\n%-11s CPU intr/s\n", prev_string);
1068 if (*cpu_bitmap & 1) {
1069 printf("%-11s", curr_string);
1070 cprintf_in(IS_STR, " %s", " all", 0);
1071 /* Print total number of interrupts among all cpu */
1072 cprintf_f(NO_UNIT, 1, 9, 2,
1073 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1077 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1079 sic = st_irq[curr] + cpu;
1080 sip = st_irq[prev] + cpu;
1082 scc = st_cpu[curr] + cpu;
1083 scp = st_cpu[prev] + cpu;
1085 /* Check if we want stats about this CPU */
1086 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1089 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1090 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1091 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1093 /* This is an offline CPU */
1095 if (!DISPLAY_ONLINE_CPU(flags)) {
1097 * Display offline CPU if requested by the user.
1098 * Value displayed is 0.00.
1100 printf("%-11s", curr_string);
1101 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1102 cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1108 printf("%-11s", curr_string);
1109 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1111 /* Recalculate itv for current proc */
1112 pc_itv = get_per_cpu_interval(scc, scp);
1115 /* This is a tickless CPU: Value displayed is 0.00 */
1116 cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1120 /* Display total number of interrupts for current CPU */
1121 cprintf_f(NO_UNIT, 1, 9, 2,
1122 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1129 ***************************************************************************
1130 * Display total number of interrupts per CPU in JSON format.
1133 * @tab Number of tabs to print.
1134 * @itv Interval value.
1135 * @prev Position in array where statistics used as reference are.
1136 * Stats used as reference may be the previous ones read, or
1137 * the very first ones when calculating the average.
1138 * @curr Position in array where current statistics will be saved.
1139 ***************************************************************************
1141 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr)
1143 struct stats_cpu *scc, *scp;
1144 struct stats_irq *sic, *sip;
1145 unsigned long long pc_itv;
1146 int cpu, next = FALSE;
1148 xprintf(tab++, "\"sum-interrupts\": [");
1150 if (*cpu_bitmap & 1) {
1153 /* Print total number of interrupts among all cpu */
1154 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
1155 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1158 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1160 sic = st_irq[curr] + cpu;
1161 sip = st_irq[prev] + cpu;
1163 scc = st_cpu[curr] + cpu;
1164 scp = st_cpu[prev] + cpu;
1166 /* Check if we want stats about this CPU */
1167 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1175 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1176 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1177 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1179 /* This is an offline CPU */
1181 if (!DISPLAY_ONLINE_CPU(flags)) {
1183 * Display offline CPU if requested by the user.
1184 * Value displayed is 0.00.
1186 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1192 /* Recalculate itv for current proc */
1193 pc_itv = get_per_cpu_interval(scc, scp);
1196 /* This is a tickless CPU: Value displayed is 0.00 */
1197 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1201 /* Display total number of interrupts for current CPU */
1202 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
1204 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1208 xprintf0(--tab, "]");
1212 ***************************************************************************
1213 * Display total number of interrupts per CPU in plain or JSON format.
1216 * @dis TRUE if a header line must be printed.
1217 * @itv Interval value.
1218 * @prev Position in array where statistics used as reference are.
1219 * Stats used as reference may be the previous ones read, or
1220 * the very first ones when calculating the average.
1221 * @curr Position in array where current statistics will be saved.
1222 * @prev_string String displayed at the beginning of a header line. This is
1223 * the timestamp of the previous sample, or "Average" when
1224 * displaying average stats.
1225 * @curr_string String displayed at the beginning of current sample stats.
1226 * This is the timestamp of the current sample, or "Average"
1227 * when displaying average stats.
1228 * @tab Number of tabs to print (JSON format only).
1229 * @next TRUE is a previous activity has been displayed (JSON format
1231 ***************************************************************************
1233 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1234 char *prev_string, char *curr_string, int tab, int *next)
1236 if (DISPLAY_JSON_OUTPUT(flags)) {
1241 write_json_isumcpu_stats(tab, itv, prev, curr);
1244 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
1249 ***************************************************************************
1250 * Display interrupts statistics for each CPU in plain format.
1253 * @st_ic Array for per-CPU statistics.
1254 * @ic_nr Number of interrupts (hard or soft) per CPU.
1255 * @dis TRUE if a header line must be printed.
1256 * @itv Interval value.
1257 * @prev Position in array where statistics used as reference are.
1258 * Stats used as reference may be the previous ones read, or
1259 * the very first ones when calculating the average.
1260 * @curr Position in array where current statistics will be saved.
1261 * @prev_string String displayed at the beginning of a header line. This is
1262 * the timestamp of the previous sample, or "Average" when
1263 * displaying average stats.
1264 * @curr_string String displayed at the beginning of current sample stats.
1265 * This is the timestamp of the current sample, or "Average"
1266 * when displaying average stats.
1267 ***************************************************************************
1269 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1270 unsigned long long itv, int prev, int curr,
1271 char *prev_string, char *curr_string)
1273 struct stats_cpu *scc;
1274 int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
1275 struct stats_irqcpu *p, *q, *p0, *q0;
1278 * Check if number of interrupts has changed.
1279 * If this is the case, the header line will be printed again.
1280 * NB: A zero interval value indicates that we are
1281 * displaying statistics since system startup.
1283 if (!dis && interval) {
1284 for (j = 0; j < ic_nr; j++) {
1285 p0 = st_ic[curr] + j;
1286 q0 = st_ic[prev] + j;
1287 if (strcmp(p0->irq_name, q0->irq_name))
1289 * These are two different interrupts: The header must be displayed
1290 * (maybe an interrupt has disappeared, or a new one has just been registered).
1291 * Note that we compare even empty strings for the case where
1292 * a disappearing interrupt would be the last one in the list.
1298 if (dis || (j < ic_nr)) {
1300 printf("\n%-11s CPU", prev_string);
1301 for (j = 0; j < ic_nr; j++) {
1302 p0 = st_ic[curr] + j;
1303 if (p0->irq_name[0] == '\0')
1304 /* End of the list of interrupts */
1306 printf(" %8s/s", p0->irq_name);
1311 /* Calculate column widths */
1312 for (j = 0; j < ic_nr; j++) {
1313 p0 = st_ic[curr] + j;
1315 * Width is IRQ name + 2 for the trailing "/s".
1316 * Width is calculated even for "undefined" interrupts (with
1317 * an empty irq_name string) to quiet code analysis tools.
1319 colwidth[j] = strlen(p0->irq_name) + 2;
1321 * Normal space for printing a number is 11 chars
1322 * (space + 10 digits including the period).
1324 if (colwidth[j] < 10) {
1329 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1331 scc = st_cpu[curr] + cpu;
1334 * Check if we want stats about this CPU.
1335 * CPU must have been explicitly selected using option -P,
1336 * else we display every CPU.
1338 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
1341 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1342 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1343 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1345 /* Offline CPU found */
1347 if (DISPLAY_ONLINE_CPU(flags))
1351 printf("%-11s", curr_string);
1352 cprintf_in(IS_INT, " %3d", "", cpu - 1);
1354 for (j = 0; j < ic_nr; j++) {
1355 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1357 * An empty string for irq_name means it is a remaining interrupt
1358 * which is no longer used, for example because the
1359 * number of interrupts has decreased in /proc/interrupts.
1361 if (p0->irq_name[0] == '\0')
1362 /* End of the list of interrupts */
1364 q0 = st_ic[prev] + j;
1368 * If we want stats for the time since system startup,
1369 * we have p0->irq_name != q0->irq_name, since q0 structure
1370 * is completely set to zero.
1372 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1373 /* Check if interrupt exists elsewhere in list */
1374 for (offset = 0; offset < ic_nr; offset++) {
1375 q0 = st_ic[prev] + offset;
1376 if (!strcmp(p0->irq_name, q0->irq_name))
1377 /* Interrupt found at another position */
1382 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1384 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1385 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1386 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1387 S_VALUE(q->interrupt, p->interrupt, itv));
1391 * Instead of printing "N/A", assume that previous value
1392 * for this new interrupt was zero.
1394 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1395 S_VALUE(0, p->interrupt, itv));
1403 ***************************************************************************
1404 * Display interrupts statistics for each CPU in JSON format.
1407 * @tab Number of tabs to print.
1408 * @st_ic Array for per-CPU statistics.
1409 * @ic_nr Number of interrupts (hard or soft) per CPU.
1410 * @itv Interval value.
1411 * @prev Position in array where statistics used as reference are.
1412 * Stats used as reference may be the previous ones read, or
1413 * the very first ones when calculating the average.
1414 * @curr Position in array where current statistics will be saved.
1415 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1416 ***************************************************************************
1418 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
1419 unsigned long long itv, int prev, int curr, int type)
1421 struct stats_cpu *scc;
1422 int j = ic_nr, offset, cpu;
1423 struct stats_irqcpu *p, *q, *p0, *q0;
1424 int nextcpu = FALSE, nextirq;
1426 if (type == M_D_IRQ_CPU) {
1427 xprintf(tab++, "\"individual-interrupts\": [");
1430 xprintf(tab++, "\"soft-interrupts\": [");
1433 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1435 scc = st_cpu[curr] + cpu;
1438 * Check if we want stats about this CPU.
1439 * CPU must have been explicitly selected using option -P,
1440 * else we display every CPU.
1442 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
1445 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1446 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1447 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1449 /* Offline CPU found */
1451 if (DISPLAY_ONLINE_CPU(flags))
1460 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1462 for (j = 0; j < ic_nr; j++) {
1464 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1466 * An empty string for irq_name means it is a remaining interrupt
1467 * which is no longer used, for example because the
1468 * number of interrupts has decreased in /proc/interrupts.
1470 if (p0->irq_name[0] == '\0')
1471 /* End of the list of interrupts */
1473 q0 = st_ic[prev] + j;
1482 * If we want stats for the time since system startup,
1483 * we have p0->irq_name != q0->irq_name, since q0 structure
1484 * is completely set to zero.
1486 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1487 /* Check if interrupt exists elsewhere in list */
1488 for (offset = 0; offset < ic_nr; offset++) {
1489 q0 = st_ic[prev] + offset;
1490 if (!strcmp(p0->irq_name, q0->irq_name))
1491 /* Interrupt found at another position */
1496 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1498 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1499 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1500 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1502 S_VALUE(q->interrupt, p->interrupt, itv));
1506 * Instead of printing "N/A", assume that previous value
1507 * for this new interrupt was zero.
1509 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1511 S_VALUE(0, p->interrupt, itv));
1515 xprintf0(--tab, "] }");
1518 xprintf0(--tab, "]");
1522 ***************************************************************************
1523 * Display interrupts statistics for each CPU in plain or JSON format.
1526 * @st_ic Array for per-CPU statistics.
1527 * @ic_nr Number of interrupts (hard or soft) per CPU.
1528 * @dis TRUE if a header line must be printed.
1529 * @itv Interval value.
1530 * @prev Position in array where statistics used as reference are.
1531 * Stats used as reference may be the previous ones read, or
1532 * the very first ones when calculating the average.
1533 * @curr Position in array where current statistics will be saved.
1534 * @prev_string String displayed at the beginning of a header line. This is
1535 * the timestamp of the previous sample, or "Average" when
1536 * displaying average stats.
1537 * @curr_string String displayed at the beginning of current sample stats.
1538 * This is the timestamp of the current sample, or "Average"
1539 * when displaying average stats.
1540 * @tab Number of tabs to print (JSON format only).
1541 * @next TRUE is a previous activity has been displayed (JSON format
1543 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1544 ***************************************************************************
1546 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1547 unsigned long long itv, int prev, int curr,
1548 char *prev_string, char *curr_string, int tab,
1549 int *next, int type)
1551 if (DISPLAY_JSON_OUTPUT(flags)) {
1556 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type);
1559 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1560 prev_string, curr_string);
1565 ***************************************************************************
1566 * Core function used to display statistics.
1569 * @prev Position in array where statistics used as reference are.
1570 * Stats used as reference may be the previous ones read, or
1571 * the very first ones when calculating the average.
1572 * @curr Position in array where statistics for current sample are.
1573 * @dis TRUE if a header line must be printed.
1574 * @prev_string String displayed at the beginning of a header line. This is
1575 * the timestamp of the previous sample, or "Average" when
1576 * displaying average stats.
1577 * @curr_string String displayed at the beginning of current sample stats.
1578 * This is the timestamp of the current sample, or "Average"
1579 * when displaying average stats.
1580 ***************************************************************************
1582 void write_stats_core(int prev, int curr, int dis,
1583 char *prev_string, char *curr_string)
1585 struct stats_cpu *scc, *scp;
1586 unsigned long long itv, g_itv;
1587 int cpu, tab = 4, next = FALSE;
1590 TEST_STDOUT(STDOUT_FILENO);
1592 if (DISPLAY_JSON_OUTPUT(flags)) {
1593 xprintf(tab++, "{");
1594 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1597 /* Compute time interval */
1598 g_itv = get_interval(uptime[prev], uptime[curr]);
1600 /* Reduce interval value to one processor */
1602 itv = get_interval(uptime0[prev], uptime0[curr]);
1608 /* Print CPU stats */
1609 if (DISPLAY_CPU(actflags)) {
1610 write_cpu_stats(dis, g_itv, prev, curr, prev_string, curr_string,
1614 /* Print node CPU stats */
1615 if (DISPLAY_NODE(actflags)) {
1616 write_node_stats(dis, g_itv, itv, prev, curr, prev_string, curr_string,
1620 /* Print total number of interrupts per processor */
1621 if (DISPLAY_IRQ_SUM(actflags)) {
1622 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1626 /* Display each interrupt value for each CPU */
1627 if (DISPLAY_IRQ_CPU(actflags)) {
1628 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1629 prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
1631 if (DISPLAY_SOFTIRQS(actflags)) {
1632 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1633 prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
1636 if (DISPLAY_JSON_OUTPUT(flags)) {
1638 xprintf0(--tab, "}");
1641 /* Fix CPU counter values for every offline CPU */
1642 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1644 scc = st_cpu[curr] + cpu;
1645 scp = st_cpu[prev] + cpu;
1647 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1648 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1649 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1651 * Offline CPU found.
1652 * Set current struct fields (which have been set to zero)
1653 * to values from previous iteration. Hence their values won't
1654 * jump from zero when the CPU comes back online.
1662 ***************************************************************************
1663 * Print statistics average.
1666 * @curr Position in array where statistics for current sample are.
1667 * @dis TRUE if a header line must be printed.
1668 ***************************************************************************
1670 void write_stats_avg(int curr, int dis)
1674 strncpy(string, _("Average:"), 16);
1676 write_stats_core(2, curr, dis, string, string);
1680 ***************************************************************************
1684 * @curr Position in array where statistics for current sample are.
1685 * @dis TRUE if a header line must be printed.
1686 ***************************************************************************
1688 void write_stats(int curr, int dis)
1690 char cur_time[2][TIMESTAMP_LEN];
1692 /* Get previous timestamp */
1693 if (is_iso_time_fmt()) {
1694 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1697 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1700 /* Get current timestamp */
1701 if (is_iso_time_fmt()) {
1702 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &mp_tstamp[curr]);
1705 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1708 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1712 ***************************************************************************
1713 * Read stats from /proc/interrupts or /proc/softirqs.
1716 * @file /proc file to read (interrupts or softirqs).
1717 * @ic_nr Number of interrupts (hard or soft) per CPU.
1718 * @curr Position in array where current statistics will be saved.
1721 * @st_ic Array for per-CPU interrupts statistics.
1722 ***************************************************************************
1724 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1727 struct stats_irq *st_irq_i;
1728 struct stats_irqcpu *p;
1729 char *line = NULL, *li;
1730 unsigned long irq = 0;
1732 int cpu_index[cpu_nr], index = 0, len;
1735 /* Reset total number of interrupts received by each CPU */
1736 for (cpu = 0; cpu < cpu_nr; cpu++) {
1737 st_irq_i = st_irq[curr] + cpu + 1;
1738 st_irq_i->irq_nr = 0;
1741 if ((fp = fopen(file, "r")) != NULL) {
1743 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1746 * Parse header line to see which CPUs are online
1748 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1750 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1751 cpu = strtol(cp + 3, &next, 10);
1752 cpu_index[index++] = cpu;
1755 /* Header line found */
1759 /* Parse each line of interrupts statistics data */
1760 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1763 /* Skip over "<irq>:" */
1764 if ((cp = strchr(line, ':')) == NULL)
1765 /* Chr ':' not found */
1769 p = st_ic[curr] + irq;
1771 /* Remove possible heading spaces in interrupt's name... */
1776 len = strcspn(li, ":");
1777 if (len >= MAX_IRQ_LEN) {
1778 len = MAX_IRQ_LEN - 1;
1780 /* ...then save its name */
1781 strncpy(p->irq_name, li, len);
1782 p->irq_name[len] = '\0';
1784 /* For each interrupt: Get number received by each CPU */
1785 for (cpu = 0; cpu < index; cpu++) {
1786 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1787 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1789 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1790 * This is the same as st_irqcpu->irq_name.
1791 * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1792 * and total number of interrupts received by current CPU (in stats_irq structure).
1794 p->interrupt = strtoul(cp, &next, 10);
1795 st_irq_i->irq_nr += p->interrupt;
1806 while (irq < ic_nr) {
1807 /* Nb of interrupts per processor has changed */
1808 p = st_ic[curr] + irq;
1809 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
1815 ***************************************************************************
1816 * Main loop: Read stats from the relevant sources, and display them.
1819 * @dis_hdr Set to TRUE if the header line must always be printed.
1820 * @rows Number of rows of screen.
1821 ***************************************************************************
1823 void rw_mpstat_loop(int dis_hdr, int rows)
1825 struct stats_cpu *scc;
1827 int curr = 1, dis = 1;
1828 unsigned long lines = rows;
1830 /* Dont buffer data if redirected to a pipe */
1831 setbuf(stdout, NULL);
1833 /* Read uptime and CPU stats */
1836 * Init uptime0. So if /proc/uptime cannot fill it,
1837 * this will be done by /proc/stat.
1840 read_uptime(&(uptime0[0]));
1842 read_stat_cpu(st_cpu[0], cpu_nr + 1, &(uptime[0]), &(uptime0[0]));
1843 if (DISPLAY_NODE(actflags)) {
1844 set_node_cpu_stats(st_node[0], st_cpu[0]);
1848 * Read total number of interrupts received among all CPU.
1849 * (this is the first value on the line "intr:" in the /proc/stat file).
1851 if (DISPLAY_IRQ_SUM(actflags)) {
1852 read_stat_irq(st_irq[0], 1);
1856 * Read number of interrupts received by each CPU, for each interrupt,
1857 * and compute the total number of interrupts received by each CPU.
1859 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1860 /* Read this file to display int per CPU or total nr of int per CPU */
1861 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1863 if (DISPLAY_SOFTIRQS(actflags)) {
1864 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1868 /* Display since boot time */
1869 mp_tstamp[1] = mp_tstamp[0];
1870 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1871 memset(st_node[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1872 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1873 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1874 if (DISPLAY_SOFTIRQS(actflags)) {
1875 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1877 write_stats(0, DISP_HDR);
1878 if (DISPLAY_JSON_OUTPUT(flags)) {
1879 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1884 /* Set a handler for SIGALRM */
1885 memset(&alrm_act, 0, sizeof(alrm_act));
1886 alrm_act.sa_handler = alarm_handler;
1887 sigaction(SIGALRM, &alrm_act, NULL);
1890 /* Save the first stats collected. Will be used to compute the average */
1891 mp_tstamp[2] = mp_tstamp[0];
1892 uptime[2] = uptime[0];
1893 uptime0[2] = uptime0[0];
1894 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1895 memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
1896 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1897 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1898 if (DISPLAY_SOFTIRQS(actflags)) {
1899 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1900 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1903 if (!DISPLAY_JSON_OUTPUT(flags)) {
1904 /* Set a handler for SIGINT */
1905 memset(&int_act, 0, sizeof(int_act));
1906 int_act.sa_handler = int_handler;
1907 sigaction(SIGINT, &int_act, NULL);
1913 /* SIGINT signal caught during first interval: Exit immediately */
1918 * Resetting the structure not needed since every fields will be set.
1919 * Exceptions are per-CPU structures: Some of them may not be filled
1920 * if corresponding processor is disabled (offline). We set them to zero
1921 * to be able to distinguish between offline and tickless CPUs.
1923 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1924 scc = st_cpu[curr] + cpu;
1925 memset(scc, 0, STATS_CPU_SIZE);
1926 scc = st_node[curr] + cpu;
1927 memset(scc, 0, STATS_CPU_SIZE);
1931 get_localtime(&(mp_tstamp[curr]), 0);
1933 /* Read uptime and CPU stats */
1936 read_uptime(&(uptime0[curr]));
1938 read_stat_cpu(st_cpu[curr], cpu_nr + 1, &(uptime[curr]), &(uptime0[curr]));
1939 if (DISPLAY_NODE(actflags)) {
1940 set_node_cpu_stats(st_node[curr], st_cpu[curr]);
1943 /* Read total number of interrupts received among all CPU */
1944 if (DISPLAY_IRQ_SUM(actflags)) {
1945 read_stat_irq(st_irq[curr], 1);
1949 * Read number of interrupts received by each CPU, for each interrupt,
1950 * and compute the total number of interrupts received by each CPU.
1952 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1953 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
1955 if (DISPLAY_SOFTIRQS(actflags)) {
1956 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
1967 write_stats(curr, dis);
1975 if (DISPLAY_JSON_OUTPUT(flags)) {
1980 if (sigint_caught) {
1981 /* SIGINT signal caught => Display average stats */
1983 printf("\n"); /* Skip "^C" displayed on screen */
1992 /* Write stats average */
1993 if (DISPLAY_JSON_OUTPUT(flags)) {
1994 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1997 write_stats_avg(curr, dis_hdr);
2002 ***************************************************************************
2003 * Main entry to the program
2004 ***************************************************************************
2006 int main(int argc, char **argv)
2008 int opt = 0, i, actset = FALSE;
2009 struct utsname header;
2015 /* Init National Language Support */
2019 /* Init color strings */
2025 /* What is the highest processor number on this machine? */
2026 cpu_nr = get_cpu_nr(~0, TRUE);
2028 /* Calculate number of interrupts per processor */
2029 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
2031 /* Calculate number of soft interrupts per processor */
2032 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
2036 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
2037 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
2039 salloc_mp_struct(cpu_nr + 1);
2041 /* Get NUMA node placement */
2042 node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
2044 while (++opt < argc) {
2046 if (!strcmp(argv[opt], "-I")) {
2052 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2053 if (!strcmp(t, K_SUM)) {
2054 /* Display total number of interrupts per CPU */
2055 actflags |= M_D_IRQ_SUM;
2057 else if (!strcmp(t, K_CPU)) {
2058 /* Display interrupts per CPU */
2059 actflags |= M_D_IRQ_CPU;
2061 else if (!strcmp(t, K_SCPU)) {
2062 /* Display soft interrupts per CPU */
2063 actflags |= M_D_SOFTIRQS;
2065 else if (!strcmp(t, K_ALL)) {
2066 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2074 else if (!strcmp(argv[opt], "-o")) {
2075 /* Select output format */
2076 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2077 flags |= F_JSON_OUTPUT;
2084 else if (!strcmp(argv[opt], "-N")) {
2089 flags |= F_N_OPTION;
2090 actflags |= M_D_NODE;
2093 if (parse_values(argv[opt], node_bitmap, node_nr + 1, K_LOWERALL)) {
2099 else if (!strcmp(argv[opt], "-P")) {
2100 /* '-P ALL' can be used on UP machines */
2104 flags |= F_P_OPTION;
2107 if (!strcmp(argv[opt], K_ON)) {
2108 /* Display stats for all online CPU */
2110 memset(cpu_bitmap, ~0, BITMAP_SIZE(cpu_nr));
2112 else if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
2117 else if (!strncmp(argv[opt], "-", 1)) {
2118 for (i = 1; *(argv[opt] + i); i++) {
2120 switch (*(argv[opt] + i)) {
2123 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2125 actflags |= M_D_NODE;
2126 flags |= F_N_OPTION;
2127 memset(node_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
2130 /* Select all processors */
2131 flags |= F_P_OPTION;
2132 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
2136 /* Display CPU stats based on NUMA node placement */
2138 actflags |= M_D_NODE;
2145 actflags |= M_D_CPU;
2149 /* Print version number */
2159 else if (interval < 0) {
2161 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2164 interval = atol(argv[opt]);
2171 else if (count <= 0) {
2172 /* Get count value */
2173 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2177 count = atol(argv[opt]);
2188 /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
2190 (USE_P_OPTION(flags) && !(actflags & ~M_D_NODE))) {
2191 actflags |= M_D_CPU;
2194 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
2198 if (!USE_P_OPTION(flags)) {
2199 /* Option -P not used: Set bit 0 (global stats among all proc) */
2202 if (!USE_N_OPTION(flags)) {
2203 /* Option -N not used: Set bit 0 (global stats among all nodes) */
2210 /* Get window size */
2211 rows = get_win_height();
2214 /* Interval not set => display stats since boot time */
2218 if (DISPLAY_JSON_OUTPUT(flags)) {
2219 /* Use a decimal point to make JSON code compliant with RFC7159 */
2220 setlocale(LC_NUMERIC, "C");
2224 get_localtime(&(mp_tstamp[0]), 0);
2226 /* Get system name, release number and hostname */
2228 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
2229 header.nodename, header.machine, get_cpu_nr(~0, FALSE),
2230 DISPLAY_JSON_OUTPUT(flags));
2233 rw_mpstat_loop(dis_hdr, rows);
2235 /* Free structures */