2 * mpstat: per-processor statistics
3 * (C) 2000-2019 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_cs[3] = {0, 0, 0};
53 /* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
54 unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */
55 unsigned char *node_bitmap; /* Bit 0: Global; Bit 1: 1st NUMA node; etc. */
57 /* Structures used to save CPU and NUMA nodes CPU stats */
58 struct stats_cpu *st_cpu[3];
59 struct stats_cpu *st_node[3];
62 * Structure used to save total number of interrupts received
63 * among all CPU and for each CPU.
65 struct stats_irq *st_irq[3];
68 * Structures used to save, for each interrupt, the number
69 * received by each CPU.
71 struct stats_irqcpu *st_irqcpu[3];
72 struct stats_irqcpu *st_softirqcpu[3];
75 * Number of CPU per node, e.g.:
76 * cpu_per_node[0]: total nr of CPU (this is node "all")
77 * cpu_per_node[1]: nr of CPU for node 0
83 * Node number the CPU belongs to, e.g.:
84 * cpu2node[0]: node nr for CPU 0
88 struct tm mp_tstamp[3];
91 unsigned int actflags = 0;
93 unsigned int flags = 0;
95 /* Interval and count parameters */
96 long interval = -1, count = 0;
97 /* Number of decimal places */
101 * Nb of processors on the machine.
102 * A value of 2 means there are 2 processors (0 and 1).
107 * Highest NUMA node number found on the machine.
108 * A value of 0 means node 0 (one node).
109 * A value of -1 means no nodes found.
110 * We have: node_nr < cpu_nr (see get_node_placement() function).
114 /* Nb of interrupts per processor */
116 /* Nb of soft interrupts per processor */
117 int softirqcpu_nr = 0;
119 struct sigaction alrm_act, int_act;
120 int sigint_caught = 0;
123 ***************************************************************************
124 * Print usage and exit
127 * @progname Name of sysstat command
128 ***************************************************************************
130 void usage(char *progname)
132 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
135 fprintf(stderr, _("Options are:\n"
136 "[ -A ] [ -n ] [ -u ] [ -V ]\n"
137 "[ -I { SUM | CPU | SCPU | ALL } ] [ -N { <node_list> | ALL } ]\n"
138 "[ --dec={ 0 | 1 | 2 } ] [ -o JSON ] [ -P { <cpu_list> | ALL } ]\n"));
143 ***************************************************************************
144 * SIGALRM signal handler. No need to reset the handler here.
147 * @sig Signal number.
148 ***************************************************************************
150 void alarm_handler(int sig)
156 ***************************************************************************
157 * SIGINT signal handler.
160 * @sig Signal number.
161 **************************************************************************
163 void int_handler(int sig)
169 ***************************************************************************
170 * Allocate stats structures and cpu bitmap. Also do it for NUMA nodes
171 * (although the machine may not be a NUMA one). Assume that the number of
172 * nodes is lower or equal than that of CPU.
175 * @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
176 * because we also have to allocate a structure for CPU 'all'.
177 ***************************************************************************
179 void salloc_mp_struct(int nr_cpus)
183 for (i = 0; i < 3; i++) {
185 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
190 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
192 if ((st_node[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
197 memset(st_node[i], 0, STATS_CPU_SIZE * nr_cpus);
199 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
204 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
206 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
211 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
213 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
218 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
221 if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
225 memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
227 if ((node_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
231 memset(node_bitmap, 0, (nr_cpus >> 3) + 1);
233 if ((cpu_per_node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
238 if ((cpu2node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
245 ***************************************************************************
246 * Free structures and bitmap.
247 ***************************************************************************
249 void sfree_mp_struct(void)
253 for (i = 0; i < 3; i++) {
258 free(st_softirqcpu[i]);
268 ***************************************************************************
269 * Get node placement (which node each CPU belongs to, and total number of
270 * CPU that each node has).
273 * @cpu_nr Number of CPU on this machine.
276 * @cpu_per_node Number of CPU per node.
277 * @cpu2node The node the CPU belongs to.
280 * Highest node number found (e.g., 0 means node 0).
281 * A value of -1 means no nodes have been found.
282 ***************************************************************************
284 int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
289 char line[MAX_PF_NAME];
290 int cpu, node, node_nr = -1;
292 /* Init number of CPU per node */
293 memset(cpu_per_node, 0, sizeof(int) * (cpu_nr + 1));
294 /* CPU belongs to no node by default */
295 memset(cpu2node, -1, sizeof(int) * cpu_nr);
297 /* This is node "all" */
298 cpu_per_node[0] = cpu_nr;
300 for (cpu = 0; cpu < cpu_nr; cpu++) {
301 snprintf(line, MAX_PF_NAME, "%s/cpu%d", SYSFS_DEVCPU, cpu);
302 line[MAX_PF_NAME - 1] = '\0';
304 /* Open relevant /sys directory */
305 if ((dir = opendir(line)) == NULL)
308 /* Get current file entry */
309 while ((drd = readdir(dir)) != NULL) {
311 if (!strncmp(drd->d_name, "node", 4) && isdigit(drd->d_name[4])) {
312 node = atoi(drd->d_name + 4);
313 if ((node >= cpu_nr) || (node < 0)) {
314 /* Assume we cannot have more nodes than CPU */
318 cpu_per_node[node + 1]++;
319 cpu2node[cpu] = node;
320 if (node > node_nr) {
323 /* Node placement found for current CPU: Go to next CPU directory */
328 /* Close directory */
336 ***************************************************************************
337 * Compute node statistics: Split CPU statistics among nodes.
340 * @src Structure containing CPU stats to add.
343 * @dest Structure containing global CPU stats.
344 ***************************************************************************
346 void add_cpu_stats(struct stats_cpu *dest, struct stats_cpu *src)
348 dest->cpu_user += src->cpu_user;
349 dest->cpu_nice += src->cpu_nice;
350 dest->cpu_sys += src->cpu_sys;
351 dest->cpu_idle += src->cpu_idle;
352 dest->cpu_iowait += src->cpu_iowait;
353 dest->cpu_hardirq += src->cpu_hardirq;
354 dest->cpu_softirq += src->cpu_softirq;
355 dest->cpu_steal += src->cpu_steal;
356 dest->cpu_guest += src->cpu_guest;
357 dest->cpu_guest_nice += src->cpu_guest_nice;
361 ***************************************************************************
362 * Compute node statistics: Split CPU statistics among nodes.
365 * @prev Index in array where stats used as reference are.
366 * @curr Index in array for current sample statistics.
369 * @st_node Array where CPU stats for each node have been saved.
370 ***************************************************************************
372 void set_node_cpu_stats(int prev, int curr)
375 unsigned long long tot_jiffies_p;
376 struct stats_cpu *scp, *scc, *snp, *snc;
377 struct stats_cpu *scc_all = st_cpu[curr];
378 struct stats_cpu *scp_all = st_cpu[prev];
379 struct stats_cpu *snc_all = st_node[curr];
380 struct stats_cpu *snp_all = st_node[prev];
382 /* Reset structures */
383 memset(st_node[prev], 0, STATS_CPU_SIZE * (cpu_nr + 1));
384 memset(st_node[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
386 /* Node 'all' is the same as CPU 'all' */
390 /* Individual nodes */
391 for (cpu = 0; cpu < cpu_nr; cpu++) {
392 scc = st_cpu[curr] + cpu + 1;
393 scp = st_cpu[prev] + cpu + 1;
394 snp = st_node[prev] + cpu2node[cpu] + 1;
395 snc = st_node[curr] + cpu2node[cpu] + 1;
398 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
399 scp->cpu_sys + scp->cpu_idle +
400 scp->cpu_iowait + scp->cpu_hardirq +
401 scp->cpu_steal + scp->cpu_softirq;
402 if ((tot_jiffies_p == 0) && (interval != 0))
404 * CPU has just come back online with no ref from
405 * previous iteration: Skip it.
409 add_cpu_stats(snp, scp);
410 add_cpu_stats(snc, scc);
415 ***************************************************************************
416 * Compute global CPU statistics as the sum of individual CPU ones, and
417 * calculate interval for global CPU.
418 * Also identify offline CPU.
421 * @prev Index in array where stats used as reference are.
422 * @curr Index in array for current sample statistics.
423 * @offline_cpu_bitmap
424 * CPU bitmap for offline CPU.
427 * @offline_cpu_bitmap
428 * CPU bitmap with offline CPU.
431 * Interval for global CPU.
432 ***************************************************************************
434 unsigned long long get_global_cpu_mpstats(int prev, int curr,
435 unsigned char offline_cpu_bitmap[])
438 unsigned long long tot_jiffies_c, tot_jiffies_p;
439 unsigned long long deltot_jiffies = 0;
440 struct stats_cpu *scc, *scp;
441 struct stats_cpu *scc_all = st_cpu[curr];
442 struct stats_cpu *scp_all = st_cpu[prev];
445 * For UP machines we keep the values read from global CPU line in /proc/stat.
446 * Also look for offline CPU: They won't be displayed, and some of their values may
447 * have to be modified.
450 memset(scc_all, 0, sizeof(struct stats_cpu));
451 memset(scp_all, 0, sizeof(struct stats_cpu));
454 /* This is a UP machine */
455 return get_per_cpu_interval(st_cpu[curr], st_cpu[prev]);
458 for (i = 1; i <= cpu_nr; i++) {
460 scc = st_cpu[curr] + i;
461 scp = st_cpu[prev] + i;
464 * Compute the total number of jiffies spent by current processor.
465 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
466 * already include them.
468 tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
469 scc->cpu_sys + scc->cpu_idle +
470 scc->cpu_iowait + scc->cpu_hardirq +
471 scc->cpu_steal + scc->cpu_softirq;
472 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
473 scp->cpu_sys + scp->cpu_idle +
474 scp->cpu_iowait + scp->cpu_hardirq +
475 scp->cpu_steal + scp->cpu_softirq;
478 * If the CPU is offline then it is omited from /proc/stat:
479 * All the fields couldn't have been read and the sum of them is zero.
481 if (tot_jiffies_c == 0) {
483 * CPU is currently offline.
484 * Set current struct fields (which have been set to zero)
485 * to values from previous iteration. Hence their values won't
486 * jump from zero when the CPU comes back online.
487 * Note that this workaround no longer fully applies with recent kernels,
488 * as I have noticed that when a CPU comes back online, some fields
489 * restart from their previous value (e.g. user, nice, system)
490 * whereas others restart from zero (idle, iowait)! To deal with this,
491 * the get_per_cpu_interval() function will set these previous values
492 * to zero if necessary.
497 * Mark CPU as offline to not display it
498 * (and thus it will not be confused with a tickless CPU).
500 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
503 if ((tot_jiffies_p == 0) && (interval != 0)) {
505 * CPU has just come back online.
506 * Unfortunately, no reference values are available
507 * from a previous iteration, probably because it was
508 * already offline when the first sample has been taken.
509 * So don't display that CPU to prevent "jump-from-zero"
510 * output syndrome, and don't take it into account for CPU "all".
511 * NB: Test for interval != 0 to make sure we don't want stats
514 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
519 * Get interval for current CPU and add it to global CPU.
520 * Note: Previous idle and iowait values (saved in scp) may be modified here.
522 deltot_jiffies += get_per_cpu_interval(scc, scp);
524 add_cpu_stats(scc_all, scc);
525 add_cpu_stats(scp_all, scp);
528 return deltot_jiffies;
532 ***************************************************************************
533 * Display CPU statistics in plain format.
536 * @dis TRUE if a header line must be printed.
538 * Number of jiffies spent on the interval by all processors.
539 * @prev Position in array where statistics used as reference are.
540 * Stats used as reference may be the previous ones read, or
541 * the very first ones when calculating the average.
542 * @curr Position in array where current statistics will be saved.
543 * @prev_string String displayed at the beginning of a header line. This is
544 * the timestamp of the previous sample, or "Average" when
545 * displaying average stats.
546 * @curr_string String displayed at the beginning of current sample stats.
547 * This is the timestamp of the current sample, or "Average"
548 * when displaying average stats.
549 * @offline_cpu_bitmap
550 * CPU bitmap for offline CPU.
551 ***************************************************************************
553 void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
554 char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
557 struct stats_cpu *scc, *scp;
560 printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq "
561 "%%soft %%steal %%guest %%gnice %%idle\n",
566 * Now display CPU statistics (including CPU "all"),
567 * except for offline CPU or CPU that the user doesn't want to see.
569 for (i = 0; i <= cpu_nr; i++) {
571 /* Check if we want stats about this proc */
572 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
573 offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
576 scc = st_cpu[curr] + i;
577 scp = st_cpu[prev] + i;
579 printf("%-11s", curr_string);
582 /* This is CPU "all" */
583 cprintf_in(IS_STR, " %s", " all", 0);
586 cprintf_in(IS_INT, " %4d", "", i - 1);
588 /* Recalculate itv for current proc */
589 deltot_jiffies = get_per_cpu_interval(scc, scp);
591 if (!deltot_jiffies) {
593 * If the CPU is tickless then there is no change in CPU values
594 * but the sum of values is not zero.
596 cprintf_pc(NO_UNIT, 10, 7, 2,
597 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
604 cprintf_pc(NO_UNIT, 10, 7, 2,
605 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
607 ll_sp_value(scp->cpu_user - scp->cpu_guest,
608 scc->cpu_user - scc->cpu_guest, deltot_jiffies),
609 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
611 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
612 scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
613 ll_sp_value(scp->cpu_sys,
614 scc->cpu_sys, deltot_jiffies),
615 ll_sp_value(scp->cpu_iowait,
616 scc->cpu_iowait, deltot_jiffies),
617 ll_sp_value(scp->cpu_hardirq,
618 scc->cpu_hardirq, deltot_jiffies),
619 ll_sp_value(scp->cpu_softirq,
620 scc->cpu_softirq, deltot_jiffies),
621 ll_sp_value(scp->cpu_steal,
622 scc->cpu_steal, deltot_jiffies),
623 ll_sp_value(scp->cpu_guest,
624 scc->cpu_guest, deltot_jiffies),
625 ll_sp_value(scp->cpu_guest_nice,
626 scc->cpu_guest_nice, deltot_jiffies),
627 (scc->cpu_idle < scp->cpu_idle) ?
629 ll_sp_value(scp->cpu_idle,
630 scc->cpu_idle, deltot_jiffies));
636 ***************************************************************************
637 * Display CPU statistics in JSON format.
640 * @tab Number of tabs to print.
642 * Number of jiffies spent on the interval by all processors.
643 * @prev Position in array where statistics used as reference are.
644 * Stats used as reference may be the previous ones read, or
645 * the very first ones when calculating the average.
646 * @curr Position in array where current statistics will be saved.
647 * @offline_cpu_bitmap
648 * CPU bitmap for offline CPU.
649 ***************************************************************************
651 void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev, int curr,
652 unsigned char offline_cpu_bitmap[])
656 struct stats_cpu *scc, *scp;
658 xprintf(tab++, "\"cpu-load\": [");
661 * Now display CPU statistics (including CPU "all"),
662 * except for offline CPU or CPU that the user doesn't want to see.
664 for (i = 0; i <= cpu_nr; i++) {
666 /* Check if we want stats about this proc */
667 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
668 offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
671 scc = st_cpu[curr] + i;
672 scp = st_cpu[prev] + i;
680 /* This is CPU "all" */
681 strcpy(cpu_name, "all");
685 snprintf(cpu_name, 16, "%d", i - 1);
688 /* Recalculate itv for current proc */
689 deltot_jiffies = get_per_cpu_interval(scc, scp);
691 if (!deltot_jiffies) {
693 * If the CPU is tickless then there is no change in CPU values
694 * but the sum of values is not zero.
696 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
697 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
698 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
699 "\"gnice\": 0.00, \"idle\": 100.00}", i - 1);
706 xprintf0(tab, "{\"cpu\": \"%s\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
707 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
708 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", cpu_name,
709 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
711 ll_sp_value(scp->cpu_user - scp->cpu_guest,
712 scc->cpu_user - scc->cpu_guest, deltot_jiffies),
713 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
715 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
716 scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
717 ll_sp_value(scp->cpu_sys,
718 scc->cpu_sys, deltot_jiffies),
719 ll_sp_value(scp->cpu_iowait,
720 scc->cpu_iowait, deltot_jiffies),
721 ll_sp_value(scp->cpu_hardirq,
722 scc->cpu_hardirq, deltot_jiffies),
723 ll_sp_value(scp->cpu_softirq,
724 scc->cpu_softirq, deltot_jiffies),
725 ll_sp_value(scp->cpu_steal,
726 scc->cpu_steal, deltot_jiffies),
727 ll_sp_value(scp->cpu_guest,
728 scc->cpu_guest, deltot_jiffies),
729 ll_sp_value(scp->cpu_guest_nice,
730 scc->cpu_guest_nice, deltot_jiffies),
731 (scc->cpu_idle < scp->cpu_idle) ?
733 ll_sp_value(scp->cpu_idle,
734 scc->cpu_idle, deltot_jiffies));
738 xprintf0(--tab, "]");
742 ***************************************************************************
743 * Display CPU statistics in plain or JSON format.
746 * @dis TRUE if a header line must be printed.
748 * Number of jiffies spent on the interval by all processors.
749 * @prev Position in array where statistics used as reference are.
750 * Stats used as reference may be the previous ones read, or
751 * the very first ones when calculating the average.
752 * @curr Position in array where current statistics will be saved.
753 * @prev_string String displayed at the beginning of a header line. This is
754 * the timestamp of the previous sample, or "Average" when
755 * displaying average stats.
756 * @curr_string String displayed at the beginning of current sample stats.
757 * This is the timestamp of the current sample, or "Average"
758 * when displaying average stats.
759 * @tab Number of tabs to print (JSON format only).
760 * @next TRUE is a previous activity has been displayed (JSON format
762 * @offline_cpu_bitmap
763 * CPU bitmap for offline CPU.
764 ***************************************************************************
766 void write_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
767 char *prev_string, char *curr_string, int tab, int *next,
768 unsigned char offline_cpu_bitmap[])
770 if (!deltot_jiffies) {
771 /* CPU "all" cannot be tickless */
775 if (DISPLAY_JSON_OUTPUT(flags)) {
780 write_json_cpu_stats(tab, deltot_jiffies, prev, curr,
784 write_plain_cpu_stats(dis, deltot_jiffies, prev, curr,
785 prev_string, curr_string, offline_cpu_bitmap);
790 ***************************************************************************
791 * Display CPU statistics for NUMA nodes in plain format.
794 * @dis TRUE if a header line must be printed.
796 * Number of jiffies spent on the interval by all processors.
797 * @prev Position in array where statistics used as reference are.
798 * Stats used as reference may be the previous ones read, or
799 * the very first ones when calculating the average.
800 * @curr Position in array where current statistics will be saved.
801 * @prev_string String displayed at the beginning of a header line. This is
802 * the timestamp of the previous sample, or "Average" when
803 * displaying average stats.
804 * @curr_string String displayed at the beginning of current sample stats.
805 * This is the timestamp of the current sample, or "Average"
806 * when displaying average stats.
807 ***************************************************************************
809 void write_plain_node_stats(int dis, unsigned long long deltot_jiffies,
810 int prev, int curr, char *prev_string, char *curr_string)
812 struct stats_cpu *snc, *snp, *scc, *scp;
816 printf("\n%-11s NODE %%usr %%nice %%sys %%iowait %%irq "
817 "%%soft %%steal %%guest %%gnice %%idle\n",
821 for (node = 0; node <= node_nr + 1; node++) {
823 snc = st_node[curr] + node;
824 snp = st_node[prev] + node;
826 /* Check if we want stats about this node */
827 if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
830 if (!cpu_per_node[node])
831 /* No CPU in this node */
834 printf("%-11s", curr_string);
836 /* This is node "all", i.e. CPU "all" */
837 cprintf_in(IS_STR, " %s", " all", 0);
840 cprintf_in(IS_INT, " %4d", "", node - 1);
842 /* Recalculate interval for current node */
844 for (cpu = 1; cpu <= cpu_nr; cpu++) {
845 scc = st_cpu[curr] + cpu;
846 scp = st_cpu[prev] + cpu;
848 if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
849 scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
850 scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
853 if (cpu2node[cpu - 1] == node - 1) {
854 deltot_jiffies += get_per_cpu_interval(scc, scp);
858 if (!deltot_jiffies) {
859 /* All CPU in node are tickless and/or offline */
860 cprintf_pc(NO_UNIT, 10, 7, 2,
861 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
868 cprintf_pc(NO_UNIT, 10, 7, 2,
869 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
871 ll_sp_value(snp->cpu_user - snp->cpu_guest,
872 snc->cpu_user - snc->cpu_guest, deltot_jiffies),
873 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
875 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
876 snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
877 ll_sp_value(snp->cpu_sys,
878 snc->cpu_sys, deltot_jiffies),
879 ll_sp_value(snp->cpu_iowait,
880 snc->cpu_iowait, deltot_jiffies),
881 ll_sp_value(snp->cpu_hardirq,
882 snc->cpu_hardirq, deltot_jiffies),
883 ll_sp_value(snp->cpu_softirq,
884 snc->cpu_softirq, deltot_jiffies),
885 ll_sp_value(snp->cpu_steal,
886 snc->cpu_steal, deltot_jiffies),
887 ll_sp_value(snp->cpu_guest,
888 snc->cpu_guest, deltot_jiffies),
889 ll_sp_value(snp->cpu_guest_nice,
890 snc->cpu_guest_nice, deltot_jiffies),
891 (snc->cpu_idle < snp->cpu_idle) ?
893 ll_sp_value(snp->cpu_idle,
894 snc->cpu_idle, deltot_jiffies));
900 ***************************************************************************
901 * Display CPU statistics for NUMA nodes in JSON format.
904 * @tab Number of tabs to print.
906 * Number of jiffies spent on the interval by all processors.
907 * @prev Position in array where statistics used as reference are.
908 * Stats used as reference may be the previous ones read, or
909 * the very first ones when calculating the average.
910 * @curr Position in array where current statistics will be saved.
911 ***************************************************************************
913 void write_json_node_stats(int tab, unsigned long long deltot_jiffies,
916 struct stats_cpu *snc, *snp, *scc, *scp;
917 int cpu, node, next = FALSE;
920 xprintf(tab++, "\"node-load\": [");
922 for (node = 0; node <= node_nr + 1; node++) {
924 snc = st_node[curr] + node;
925 snp = st_node[prev] + node;
927 /* Check if we want stats about this node */
928 if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
931 if (!cpu_per_node[node])
932 /* No CPU in this node */
941 /* This is node "all", i.e. CPU "all" */
942 strcpy(node_name, "all");
945 snprintf(node_name, 16, "%d", node - 1);
946 node_name[15] = '\0';
948 /* Recalculate interval for current node */
950 for (cpu = 1; cpu <= cpu_nr; cpu++) {
951 scc = st_cpu[curr] + cpu;
952 scp = st_cpu[prev] + cpu;
954 if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
955 scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
956 scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
959 if (cpu2node[cpu - 1] == node - 1) {
960 deltot_jiffies += get_per_cpu_interval(scc, scp);
964 if (!deltot_jiffies) {
965 /* All CPU in node are tickless and/or offline */
966 xprintf0(tab, "{\"node\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, \"sys\": 0.00, "
967 "\"iowait\": 0.00, \"irq\": 0.00, \"soft\": 0.00, \"steal\": 0.00, "
968 "\"guest\": 0.00, \"gnice\": 0.00, \"idle\": 100.00}", node - 1);
974 xprintf0(tab, "{\"node\": \"%s\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
975 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
976 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node_name,
977 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
979 ll_sp_value(snp->cpu_user - snp->cpu_guest,
980 snc->cpu_user - snc->cpu_guest, deltot_jiffies),
981 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
983 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
984 snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
985 ll_sp_value(snp->cpu_sys,
986 snc->cpu_sys, deltot_jiffies),
987 ll_sp_value(snp->cpu_iowait,
988 snc->cpu_iowait, deltot_jiffies),
989 ll_sp_value(snp->cpu_hardirq,
990 snc->cpu_hardirq, deltot_jiffies),
991 ll_sp_value(snp->cpu_softirq,
992 snc->cpu_softirq, deltot_jiffies),
993 ll_sp_value(snp->cpu_steal,
994 snc->cpu_steal, deltot_jiffies),
995 ll_sp_value(snp->cpu_guest,
996 snc->cpu_guest, deltot_jiffies),
997 ll_sp_value(snp->cpu_guest_nice,
998 snc->cpu_guest_nice, deltot_jiffies),
999 (snc->cpu_idle < snp->cpu_idle) ?
1001 ll_sp_value(snp->cpu_idle,
1002 snc->cpu_idle, deltot_jiffies));
1005 xprintf0(--tab, "]");
1009 ***************************************************************************
1010 * Display nodes statistics in plain or JSON format.
1013 * @dis TRUE if a header line must be printed.
1015 * Number of jiffies spent on the interval by all processors.
1016 * @prev Position in array where statistics used as reference are.
1017 * Stats used as reference may be the previous ones read, or
1018 * the very first ones when calculating the average.
1019 * @curr Position in array where current statistics will be saved.
1020 * @prev_string String displayed at the beginning of a header line. This is
1021 * the timestamp of the previous sample, or "Average" when
1022 * displaying average stats.
1023 * @curr_string String displayed at the beginning of current sample stats.
1024 * This is the timestamp of the current sample, or "Average"
1025 * when displaying average stats.
1026 * @tab Number of tabs to print (JSON format only).
1027 * @next TRUE is a previous activity has been displayed (JSON format
1029 ***************************************************************************
1031 void write_node_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
1032 char *prev_string, char *curr_string, int tab, int *next)
1034 if (!deltot_jiffies) {
1035 /* CPU "all" cannot be tickless */
1039 if (DISPLAY_JSON_OUTPUT(flags)) {
1044 write_json_node_stats(tab, deltot_jiffies, prev, curr);
1047 write_plain_node_stats(dis, deltot_jiffies, prev, curr,
1048 prev_string, curr_string);
1053 ***************************************************************************
1054 * Display total number of interrupts per CPU in plain format.
1057 * @dis TRUE if a header line must be printed.
1058 * @itv Interval value.
1059 * @prev Position in array where statistics used as reference are.
1060 * Stats used as reference may be the previous ones read, or
1061 * the very first ones when calculating the average.
1062 * @curr Position in array where current statistics will be saved.
1063 * @prev_string String displayed at the beginning of a header line. This is
1064 * the timestamp of the previous sample, or "Average" when
1065 * displaying average stats.
1066 * @curr_string String displayed at the beginning of current sample stats.
1067 * This is the timestamp of the current sample, or "Average"
1068 * when displaying average stats.
1069 ***************************************************************************
1071 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1072 char *prev_string, char *curr_string)
1074 struct stats_cpu *scc, *scp;
1075 struct stats_irq *sic, *sip;
1076 unsigned long long pc_itv;
1080 printf("\n%-11s CPU intr/s\n", prev_string);
1083 if (*cpu_bitmap & 1) {
1084 printf("%-11s", curr_string);
1085 cprintf_in(IS_STR, " %s", " all", 0);
1086 /* Print total number of interrupts among all cpu */
1087 cprintf_f(NO_UNIT, 1, 9, 2,
1088 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1092 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1094 sic = st_irq[curr] + cpu;
1095 sip = st_irq[prev] + cpu;
1097 scc = st_cpu[curr] + cpu;
1098 scp = st_cpu[prev] + cpu;
1100 /* Check if we want stats about this CPU */
1101 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1104 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1105 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1106 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1108 /* This is an offline CPU */
1112 printf("%-11s", curr_string);
1113 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1115 /* Recalculate itv for current proc */
1116 pc_itv = get_per_cpu_interval(scc, scp);
1119 /* This is a tickless CPU: Value displayed is 0.00 */
1120 cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1124 /* Display total number of interrupts for current CPU */
1125 cprintf_f(NO_UNIT, 1, 9, 2,
1126 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1133 ***************************************************************************
1134 * Display total number of interrupts per CPU in JSON format.
1137 * @tab Number of tabs to print.
1138 * @itv Interval value.
1139 * @prev Position in array where statistics used as reference are.
1140 * Stats used as reference may be the previous ones read, or
1141 * the very first ones when calculating the average.
1142 * @curr Position in array where current statistics will be saved.
1143 ***************************************************************************
1145 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr)
1147 struct stats_cpu *scc, *scp;
1148 struct stats_irq *sic, *sip;
1149 unsigned long long pc_itv;
1150 int cpu, next = FALSE;
1152 xprintf(tab++, "\"sum-interrupts\": [");
1154 if (*cpu_bitmap & 1) {
1157 /* Print total number of interrupts among all cpu */
1158 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
1159 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1162 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1164 sic = st_irq[curr] + cpu;
1165 sip = st_irq[prev] + cpu;
1167 scc = st_cpu[curr] + cpu;
1168 scp = st_cpu[prev] + cpu;
1170 /* Check if we want stats about this CPU */
1171 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1179 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1180 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1181 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1183 /* This is an offline CPU */
1187 /* Recalculate itv for current proc */
1188 pc_itv = get_per_cpu_interval(scc, scp);
1191 /* This is a tickless CPU: Value displayed is 0.00 */
1192 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1196 /* Display total number of interrupts for current CPU */
1197 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
1199 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1203 xprintf0(--tab, "]");
1207 ***************************************************************************
1208 * Display total number of interrupts per CPU in plain or JSON format.
1211 * @dis TRUE if a header line must be printed.
1212 * @itv Interval value.
1213 * @prev Position in array where statistics used as reference are.
1214 * Stats used as reference may be the previous ones read, or
1215 * the very first ones when calculating the average.
1216 * @curr Position in array where current statistics will be saved.
1217 * @prev_string String displayed at the beginning of a header line. This is
1218 * the timestamp of the previous sample, or "Average" when
1219 * displaying average stats.
1220 * @curr_string String displayed at the beginning of current sample stats.
1221 * This is the timestamp of the current sample, or "Average"
1222 * when displaying average stats.
1223 * @tab Number of tabs to print (JSON format only).
1224 * @next TRUE is a previous activity has been displayed (JSON format
1226 ***************************************************************************
1228 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1229 char *prev_string, char *curr_string, int tab, int *next)
1231 if (DISPLAY_JSON_OUTPUT(flags)) {
1236 write_json_isumcpu_stats(tab, itv, prev, curr);
1239 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
1244 ***************************************************************************
1245 * Display interrupts statistics for each CPU in plain format.
1248 * @st_ic Array for per-CPU statistics.
1249 * @ic_nr Number of interrupts (hard or soft) per CPU.
1250 * @dis TRUE if a header line must be printed.
1251 * @itv Interval value.
1252 * @prev Position in array where statistics used as reference are.
1253 * Stats used as reference may be the previous ones read, or
1254 * the very first ones when calculating the average.
1255 * @curr Position in array where current statistics will be saved.
1256 * @prev_string String displayed at the beginning of a header line. This is
1257 * the timestamp of the previous sample, or "Average" when
1258 * displaying average stats.
1259 * @curr_string String displayed at the beginning of current sample stats.
1260 * This is the timestamp of the current sample, or "Average"
1261 * when displaying average stats.
1262 ***************************************************************************
1264 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1265 unsigned long long itv, int prev, int curr,
1266 char *prev_string, char *curr_string)
1268 struct stats_cpu *scc;
1269 int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
1270 struct stats_irqcpu *p, *q, *p0, *q0;
1273 * Check if number of interrupts has changed.
1274 * If this is the case, the header line will be printed again.
1275 * NB: A zero interval value indicates that we are
1276 * displaying statistics since system startup.
1278 if (!dis && interval) {
1279 for (j = 0; j < ic_nr; j++) {
1280 p0 = st_ic[curr] + j;
1281 q0 = st_ic[prev] + j;
1282 if (strcmp(p0->irq_name, q0->irq_name))
1284 * These are two different interrupts: The header must be displayed
1285 * (maybe an interrupt has disappeared, or a new one has just been registered).
1286 * Note that we compare even empty strings for the case where
1287 * a disappearing interrupt would be the last one in the list.
1293 if (dis || (j < ic_nr)) {
1295 printf("\n%-11s CPU", prev_string);
1296 for (j = 0; j < ic_nr; j++) {
1297 p0 = st_ic[curr] + j;
1298 if (p0->irq_name[0] == '\0')
1299 /* End of the list of interrupts */
1301 printf(" %8s/s", p0->irq_name);
1306 /* Calculate column widths */
1307 for (j = 0; j < ic_nr; j++) {
1308 p0 = st_ic[curr] + j;
1310 * Width is IRQ name + 2 for the trailing "/s".
1311 * Width is calculated even for "undefined" interrupts (with
1312 * an empty irq_name string) to quiet code analysis tools.
1314 colwidth[j] = strlen(p0->irq_name) + 2;
1316 * Normal space for printing a number is 11 chars
1317 * (space + 10 digits including the period).
1319 if (colwidth[j] < 10) {
1324 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1326 scc = st_cpu[curr] + cpu;
1329 * Check if we want stats about this CPU.
1330 * CPU must have been explicitly selected using option -P,
1331 * else we display every CPU.
1333 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
1336 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1337 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1338 scc->cpu_hardirq + scc->cpu_softirq) == 0)
1339 /* Offline CPU found */
1342 printf("%-11s", curr_string);
1343 cprintf_in(IS_INT, " %3d", "", cpu - 1);
1345 for (j = 0; j < ic_nr; j++) {
1346 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1348 * An empty string for irq_name means it is a remaining interrupt
1349 * which is no longer used, for example because the
1350 * number of interrupts has decreased in /proc/interrupts.
1352 if (p0->irq_name[0] == '\0')
1353 /* End of the list of interrupts */
1355 q0 = st_ic[prev] + j;
1359 * If we want stats for the time since system startup,
1360 * we have p0->irq_name != q0->irq_name, since q0 structure
1361 * is completely set to zero.
1363 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1364 /* Check if interrupt exists elsewhere in list */
1365 for (offset = 0; offset < ic_nr; offset++) {
1366 q0 = st_ic[prev] + offset;
1367 if (!strcmp(p0->irq_name, q0->irq_name))
1368 /* Interrupt found at another position */
1373 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1375 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1376 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1377 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1378 S_VALUE(q->interrupt, p->interrupt, itv));
1382 * Instead of printing "N/A", assume that previous value
1383 * for this new interrupt was zero.
1385 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1386 S_VALUE(0, p->interrupt, itv));
1394 ***************************************************************************
1395 * Display interrupts statistics for each CPU in JSON format.
1398 * @tab Number of tabs to print.
1399 * @st_ic Array for per-CPU statistics.
1400 * @ic_nr Number of interrupts (hard or soft) per CPU.
1401 * @itv Interval value.
1402 * @prev Position in array where statistics used as reference are.
1403 * Stats used as reference may be the previous ones read, or
1404 * the very first ones when calculating the average.
1405 * @curr Position in array where current statistics will be saved.
1406 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1407 ***************************************************************************
1409 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
1410 unsigned long long itv, int prev, int curr, int type)
1412 struct stats_cpu *scc;
1413 int j = ic_nr, offset, cpu;
1414 struct stats_irqcpu *p, *q, *p0, *q0;
1415 int nextcpu = FALSE, nextirq;
1417 if (type == M_D_IRQ_CPU) {
1418 xprintf(tab++, "\"individual-interrupts\": [");
1421 xprintf(tab++, "\"soft-interrupts\": [");
1424 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1426 scc = st_cpu[curr] + cpu;
1429 * Check if we want stats about this CPU.
1430 * CPU must have been explicitly selected using option -P,
1431 * else we display every CPU.
1433 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
1436 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1437 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1438 scc->cpu_hardirq + scc->cpu_softirq) == 0)
1439 /* Offline CPU found */
1447 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1449 for (j = 0; j < ic_nr; j++) {
1451 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1453 * An empty string for irq_name means it is a remaining interrupt
1454 * which is no longer used, for example because the
1455 * number of interrupts has decreased in /proc/interrupts.
1457 if (p0->irq_name[0] == '\0')
1458 /* End of the list of interrupts */
1460 q0 = st_ic[prev] + j;
1469 * If we want stats for the time since system startup,
1470 * we have p0->irq_name != q0->irq_name, since q0 structure
1471 * is completely set to zero.
1473 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1474 /* Check if interrupt exists elsewhere in list */
1475 for (offset = 0; offset < ic_nr; offset++) {
1476 q0 = st_ic[prev] + offset;
1477 if (!strcmp(p0->irq_name, q0->irq_name))
1478 /* Interrupt found at another position */
1483 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1485 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1486 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1487 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1489 S_VALUE(q->interrupt, p->interrupt, itv));
1493 * Instead of printing "N/A", assume that previous value
1494 * for this new interrupt was zero.
1496 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1498 S_VALUE(0, p->interrupt, itv));
1502 xprintf0(--tab, "] }");
1505 xprintf0(--tab, "]");
1509 ***************************************************************************
1510 * Display interrupts statistics for each CPU in plain or JSON format.
1513 * @st_ic Array for per-CPU statistics.
1514 * @ic_nr Number of interrupts (hard or soft) per CPU.
1515 * @dis TRUE if a header line must be printed.
1516 * @itv Interval value.
1517 * @prev Position in array where statistics used as reference are.
1518 * Stats used as reference may be the previous ones read, or
1519 * the very first ones when calculating the average.
1520 * @curr Position in array where current statistics will be saved.
1521 * @prev_string String displayed at the beginning of a header line. This is
1522 * the timestamp of the previous sample, or "Average" when
1523 * displaying average stats.
1524 * @curr_string String displayed at the beginning of current sample stats.
1525 * This is the timestamp of the current sample, or "Average"
1526 * when displaying average stats.
1527 * @tab Number of tabs to print (JSON format only).
1528 * @next TRUE is a previous activity has been displayed (JSON format
1530 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1531 ***************************************************************************
1533 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1534 unsigned long long itv, int prev, int curr,
1535 char *prev_string, char *curr_string, int tab,
1536 int *next, int type)
1538 if (DISPLAY_JSON_OUTPUT(flags)) {
1543 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type);
1546 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1547 prev_string, curr_string);
1552 ***************************************************************************
1553 * Core function used to display statistics.
1556 * @prev Position in array where statistics used as reference are.
1557 * Stats used as reference may be the previous ones read, or
1558 * the very first ones when calculating the average.
1559 * @curr Position in array where statistics for current sample are.
1560 * @dis TRUE if a header line must be printed.
1561 * @prev_string String displayed at the beginning of a header line. This is
1562 * the timestamp of the previous sample, or "Average" when
1563 * displaying average stats.
1564 * @curr_string String displayed at the beginning of current sample stats.
1565 * This is the timestamp of the current sample, or "Average"
1566 * when displaying average stats.
1567 ***************************************************************************
1569 void write_stats_core(int prev, int curr, int dis,
1570 char *prev_string, char *curr_string)
1572 unsigned long long itv, deltot_jiffies = 1;
1573 int tab = 4, next = FALSE;
1574 unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
1577 TEST_STDOUT(STDOUT_FILENO);
1580 * Compute CPU "all" as sum of all individual CPU (on SMP machines)
1581 * and look for offline CPU.
1583 deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
1585 if (DISPLAY_JSON_OUTPUT(flags)) {
1586 xprintf(tab++, "{");
1587 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1590 /* Get time interval */
1591 itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
1593 /* Print CPU stats */
1594 if (DISPLAY_CPU(actflags)) {
1595 write_cpu_stats(dis, deltot_jiffies, prev, curr,
1596 prev_string, curr_string, tab, &next, offline_cpu_bitmap);
1599 /* Print node CPU stats */
1600 if (DISPLAY_NODE(actflags)) {
1601 set_node_cpu_stats(prev, curr);
1602 write_node_stats(dis, deltot_jiffies, prev, curr, prev_string,
1603 curr_string, tab, &next);
1606 /* Print total number of interrupts per processor */
1607 if (DISPLAY_IRQ_SUM(actflags)) {
1608 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1612 /* Display each interrupt value for each CPU */
1613 if (DISPLAY_IRQ_CPU(actflags)) {
1614 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1615 prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
1617 if (DISPLAY_SOFTIRQS(actflags)) {
1618 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1619 prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
1622 if (DISPLAY_JSON_OUTPUT(flags)) {
1624 xprintf0(--tab, "}");
1629 ***************************************************************************
1630 * Print statistics average.
1633 * @curr Position in array where statistics for current sample are.
1634 * @dis TRUE if a header line must be printed.
1635 ***************************************************************************
1637 void write_stats_avg(int curr, int dis)
1641 strncpy(string, _("Average:"), 16);
1643 write_stats_core(2, curr, dis, string, string);
1647 ***************************************************************************
1651 * @curr Position in array where statistics for current sample are.
1652 * @dis TRUE if a header line must be printed.
1653 ***************************************************************************
1655 void write_stats(int curr, int dis)
1657 char cur_time[2][TIMESTAMP_LEN];
1659 /* Get previous timestamp */
1660 if (is_iso_time_fmt()) {
1661 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1664 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1667 /* Get current timestamp */
1668 if (is_iso_time_fmt()) {
1669 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &mp_tstamp[curr]);
1672 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1675 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1679 ***************************************************************************
1680 * Read stats from /proc/interrupts or /proc/softirqs.
1683 * @file /proc file to read (interrupts or softirqs).
1684 * @ic_nr Number of interrupts (hard or soft) per CPU.
1685 * @curr Position in array where current statistics will be saved.
1688 * @st_ic Array for per-CPU interrupts statistics.
1689 ***************************************************************************
1691 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1694 struct stats_irq *st_irq_i;
1695 struct stats_irqcpu *p;
1696 char *line = NULL, *li;
1697 unsigned long irq = 0;
1699 int cpu_index[cpu_nr], index = 0, len;
1702 /* Reset total number of interrupts received by each CPU */
1703 for (cpu = 0; cpu < cpu_nr; cpu++) {
1704 st_irq_i = st_irq[curr] + cpu + 1;
1705 st_irq_i->irq_nr = 0;
1708 if ((fp = fopen(file, "r")) != NULL) {
1710 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1713 * Parse header line to see which CPUs are online
1715 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1717 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1718 cpu = strtol(cp + 3, &next, 10);
1719 cpu_index[index++] = cpu;
1722 /* Header line found */
1726 /* Parse each line of interrupts statistics data */
1727 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1730 /* Skip over "<irq>:" */
1731 if ((cp = strchr(line, ':')) == NULL)
1732 /* Chr ':' not found */
1736 p = st_ic[curr] + irq;
1738 /* Remove possible heading spaces in interrupt's name... */
1743 len = strcspn(li, ":");
1744 if (len >= MAX_IRQ_LEN) {
1745 len = MAX_IRQ_LEN - 1;
1747 /* ...then save its name */
1748 strncpy(p->irq_name, li, len);
1749 p->irq_name[len] = '\0';
1751 /* For each interrupt: Get number received by each CPU */
1752 for (cpu = 0; cpu < index; cpu++) {
1753 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1754 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1756 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1757 * This is the same as st_irqcpu->irq_name.
1758 * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1759 * and total number of interrupts received by current CPU (in stats_irq structure).
1761 p->interrupt = strtoul(cp, &next, 10);
1762 st_irq_i->irq_nr += p->interrupt;
1773 while (irq < ic_nr) {
1774 /* Nb of interrupts per processor has changed */
1775 p = st_ic[curr] + irq;
1776 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
1782 ***************************************************************************
1783 * Main loop: Read stats from the relevant sources, and display them.
1786 * @dis_hdr Set to TRUE if the header line must always be printed.
1787 * @rows Number of rows of screen.
1788 ***************************************************************************
1790 void rw_mpstat_loop(int dis_hdr, int rows)
1792 struct stats_cpu *scc;
1794 int curr = 1, dis = 1;
1795 unsigned long lines = rows;
1797 /* Dont buffer data if redirected to a pipe */
1798 setbuf(stdout, NULL);
1800 /* Read system uptime and CPU stats */
1801 read_uptime(&(uptime_cs[0]));
1802 read_stat_cpu(st_cpu[0], cpu_nr + 1);
1805 * Calculate global CPU stats as the sum of individual ones.
1806 * Done only on SMP machines. On UP machines, we keep the values
1807 * read from /proc/stat for global CPU stats.
1810 memset(st_cpu[0], 0, STATS_CPU_SIZE);
1812 for (i = 1; i <= cpu_nr; i++) {
1813 scc = st_cpu[0] + i;
1815 st_cpu[0]->cpu_user += scc->cpu_user;
1816 st_cpu[0]->cpu_nice += scc->cpu_nice;
1817 st_cpu[0]->cpu_sys += scc->cpu_sys;
1818 st_cpu[0]->cpu_idle += scc->cpu_idle;
1819 st_cpu[0]->cpu_iowait += scc->cpu_iowait;
1820 st_cpu[0]->cpu_hardirq += scc->cpu_hardirq;
1821 st_cpu[0]->cpu_steal += scc->cpu_steal;
1822 st_cpu[0]->cpu_softirq += scc->cpu_softirq;
1823 st_cpu[0]->cpu_guest += scc->cpu_guest;
1824 st_cpu[0]->cpu_guest_nice += scc->cpu_guest_nice;
1829 * Read total number of interrupts received among all CPU.
1830 * (this is the first value on the line "intr:" in the /proc/stat file).
1832 if (DISPLAY_IRQ_SUM(actflags)) {
1833 read_stat_irq(st_irq[0], 1);
1837 * Read number of interrupts received by each CPU, for each interrupt,
1838 * and compute the total number of interrupts received by each CPU.
1840 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1841 /* Read this file to display int per CPU or total nr of int per CPU */
1842 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1844 if (DISPLAY_SOFTIRQS(actflags)) {
1845 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1849 /* Display since boot time */
1850 mp_tstamp[1] = mp_tstamp[0];
1851 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1852 memset(st_node[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1853 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1854 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1855 if (DISPLAY_SOFTIRQS(actflags)) {
1856 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1858 write_stats(0, DISP_HDR);
1859 if (DISPLAY_JSON_OUTPUT(flags)) {
1860 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1865 /* Set a handler for SIGALRM */
1866 memset(&alrm_act, 0, sizeof(alrm_act));
1867 alrm_act.sa_handler = alarm_handler;
1868 sigaction(SIGALRM, &alrm_act, NULL);
1871 /* Save the first stats collected. Will be used to compute the average */
1872 mp_tstamp[2] = mp_tstamp[0];
1873 uptime_cs[2] = uptime_cs[0];
1874 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1875 memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
1876 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1877 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1878 if (DISPLAY_SOFTIRQS(actflags)) {
1879 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1880 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1883 /* Set a handler for SIGINT */
1884 memset(&int_act, 0, sizeof(int_act));
1885 int_act.sa_handler = int_handler;
1886 sigaction(SIGINT, &int_act, NULL);
1891 /* SIGINT signal caught during first interval: Exit immediately */
1896 * Resetting the structure not needed since every fields will be set.
1897 * Exceptions are per-CPU structures: Some of them may not be filled
1898 * if corresponding processor is disabled (offline). We set them to zero
1899 * to be able to distinguish between offline and tickless CPUs.
1901 memset(st_cpu[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1904 get_localtime(&(mp_tstamp[curr]), 0);
1906 /* Read uptime and CPU stats */
1907 read_uptime(&(uptime_cs[curr]));
1908 read_stat_cpu(st_cpu[curr], cpu_nr + 1);
1910 /* Read total number of interrupts received among all CPU */
1911 if (DISPLAY_IRQ_SUM(actflags)) {
1912 read_stat_irq(st_irq[curr], 1);
1916 * Read number of interrupts received by each CPU, for each interrupt,
1917 * and compute the total number of interrupts received by each CPU.
1919 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1920 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
1922 if (DISPLAY_SOFTIRQS(actflags)) {
1923 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
1934 write_stats(curr, dis);
1944 if (sigint_caught) {
1945 /* SIGINT signal caught => Display average stats */
1949 if (DISPLAY_JSON_OUTPUT(flags)) {
1958 /* Write stats average */
1959 if (DISPLAY_JSON_OUTPUT(flags)) {
1960 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1963 write_stats_avg(curr, dis_hdr);
1968 ***************************************************************************
1969 * Main entry to the program
1970 ***************************************************************************
1972 int main(int argc, char **argv)
1974 int opt = 0, i, actset = FALSE;
1975 struct utsname header;
1981 /* Init National Language Support */
1985 /* Init color strings */
1991 /* What is the highest processor number on this machine? */
1992 cpu_nr = get_cpu_nr(~0, TRUE);
1994 /* Calculate number of interrupts per processor */
1995 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
1997 /* Calculate number of soft interrupts per processor */
1998 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
2002 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
2003 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
2005 salloc_mp_struct(cpu_nr + 1);
2007 /* Get NUMA node placement */
2008 node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
2010 while (++opt < argc) {
2012 if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2013 /* Get number of decimal places */
2014 dplaces_nr = atoi(argv[opt] + 6);
2015 if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2020 else if (!strcmp(argv[opt], "-I")) {
2026 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2027 if (!strcmp(t, K_SUM)) {
2028 /* Display total number of interrupts per CPU */
2029 actflags |= M_D_IRQ_SUM;
2031 else if (!strcmp(t, K_CPU)) {
2032 /* Display interrupts per CPU */
2033 actflags |= M_D_IRQ_CPU;
2035 else if (!strcmp(t, K_SCPU)) {
2036 /* Display soft interrupts per CPU */
2037 actflags |= M_D_SOFTIRQS;
2039 else if (!strcmp(t, K_ALL)) {
2040 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2048 else if (!strcmp(argv[opt], "-o")) {
2049 /* Select output format */
2050 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2051 flags |= F_JSON_OUTPUT;
2058 else if (!strcmp(argv[opt], "-N")) {
2063 flags |= F_N_OPTION;
2064 actflags |= M_D_NODE;
2067 if (parse_values(argv[opt], node_bitmap, node_nr + 1, K_LOWERALL)) {
2073 else if (!strcmp(argv[opt], "-P")) {
2074 /* '-P ALL' can be used on UP machines */
2078 flags |= F_P_OPTION;
2081 if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
2086 else if (!strncmp(argv[opt], "-", 1)) {
2087 for (i = 1; *(argv[opt] + i); i++) {
2089 switch (*(argv[opt] + i)) {
2092 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2094 actflags |= M_D_NODE;
2095 flags |= F_N_OPTION;
2096 memset(node_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
2099 /* Select all processors */
2100 flags |= F_P_OPTION;
2101 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
2105 /* Display CPU stats based on NUMA node placement */
2107 actflags |= M_D_NODE;
2114 actflags |= M_D_CPU;
2118 /* Print version number */
2128 else if (interval < 0) {
2130 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2133 interval = atol(argv[opt]);
2140 else if (count <= 0) {
2141 /* Get count value */
2142 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2146 count = atol(argv[opt]);
2157 /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
2159 (USE_P_OPTION(flags) && !(actflags & ~M_D_NODE))) {
2160 actflags |= M_D_CPU;
2163 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
2167 if (!USE_P_OPTION(flags)) {
2168 /* Option -P not used: Set bit 0 (global stats among all proc) */
2171 if (!USE_N_OPTION(flags)) {
2172 /* Option -N not used: Set bit 0 (global stats among all nodes) */
2179 /* Get window size */
2180 rows = get_win_height();
2183 /* Interval not set => display stats since boot time */
2187 if (DISPLAY_JSON_OUTPUT(flags)) {
2188 /* Use a decimal point to make JSON code compliant with RFC7159 */
2189 setlocale(LC_NUMERIC, "C");
2193 get_localtime(&(mp_tstamp[0]), 0);
2195 /* Get system name, release number and hostname */
2197 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
2198 header.nodename, header.machine, get_cpu_nr(~0, FALSE),
2199 DISPLAY_JSON_OUTPUT(flags));
2202 rw_mpstat_loop(dis_hdr, rows);
2204 /* Free structures */