2 * mpstat: per-processor statistics
3 * (C) 2000-2020 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>
37 #include <locale.h> /* For setlocale() */
40 #define _(string) gettext(string)
42 #define _(string) (string)
46 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
47 char *sccsid(void) { return (SCCSID); }
50 unsigned long long uptime_cs[3] = {0, 0, 0};
52 /* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
53 unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */
54 unsigned char *node_bitmap; /* Bit 0: Global; Bit 1: 1st NUMA node; etc. */
56 /* Structures used to save CPU and NUMA nodes CPU stats */
57 struct stats_cpu *st_cpu[3];
58 struct stats_cpu *st_node[3];
61 * Structure used to save total number of interrupts received
62 * among all CPU and for each CPU.
64 struct stats_irq *st_irq[3];
67 * Structures used to save, for each interrupt, the number
68 * received by each CPU.
70 struct stats_irqcpu *st_irqcpu[3];
71 struct stats_irqcpu *st_softirqcpu[3];
74 * Number of CPU per node, e.g.:
75 * cpu_per_node[0]: total nr of CPU (this is node "all")
76 * cpu_per_node[1]: nr of CPU for node 0
82 * Node number the CPU belongs to, e.g.:
83 * cpu2node[0]: node nr for CPU 0
88 struct cpu_topology *st_cpu_topology;
90 struct tm mp_tstamp[3];
93 unsigned int actflags = 0;
95 unsigned int flags = 0;
97 /* Interval and count parameters */
98 long interval = -1, count = 0;
99 /* Number of decimal places */
103 * Nb of processors on the machine.
104 * A value of 2 means there are 2 processors (0 and 1).
109 * Highest NUMA node number found on the machine.
110 * A value of 0 means node 0 (one node).
111 * A value of -1 means no nodes found.
112 * We have: node_nr < cpu_nr (see get_node_placement() function).
116 /* Nb of interrupts per processor */
118 /* Nb of soft interrupts per processor */
119 int softirqcpu_nr = 0;
121 struct sigaction alrm_act, int_act;
122 int sigint_caught = 0;
125 ***************************************************************************
126 * Print usage and exit
129 * @progname Name of sysstat command
130 ***************************************************************************
132 void usage(char *progname)
134 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
137 fprintf(stderr, _("Options are:\n"
138 "[ -A ] [ -n ] [ -T ] [ -u ] [ -V ]\n"
139 "[ -I { SUM | CPU | SCPU | ALL } ] [ -N { <node_list> | ALL } ]\n"
140 "[ --dec={ 0 | 1 | 2 } ] [ -o JSON ] [ -P { <cpu_list> | ALL } ]\n"));
145 ***************************************************************************
146 * SIGALRM signal handler. No need to reset the handler here.
149 * @sig Signal number.
150 ***************************************************************************
152 void alarm_handler(int sig)
158 ***************************************************************************
159 * SIGINT signal handler.
162 * @sig Signal number.
163 **************************************************************************
165 void int_handler(int sig)
171 ***************************************************************************
172 * Allocate stats structures and cpu bitmap. Also do it for NUMA nodes
173 * (although the machine may not be a NUMA one). Assume that the number of
174 * nodes is lower or equal than that of CPU.
177 * @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
178 * because we also have to allocate a structure for CPU 'all'.
179 ***************************************************************************
181 void salloc_mp_struct(int nr_cpus)
185 for (i = 0; i < 3; i++) {
187 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
192 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
194 if ((st_node[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
199 memset(st_node[i], 0, STATS_CPU_SIZE * nr_cpus);
201 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
206 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
208 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
213 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
215 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
220 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
223 if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
227 memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
229 if ((node_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
233 memset(node_bitmap, 0, (nr_cpus >> 3) + 1);
235 if ((cpu_per_node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
240 if ((cpu2node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
245 if ((st_cpu_topology = (struct cpu_topology *) malloc(sizeof(struct cpu_topology) * nr_cpus)) == NULL) {
252 ***************************************************************************
253 * Free structures and bitmap.
254 ***************************************************************************
256 void sfree_mp_struct(void)
260 for (i = 0; i < 3; i++) {
265 free(st_softirqcpu[i]);
275 ***************************************************************************
276 * Get node placement (which node each CPU belongs to, and total number of
277 * CPU that each node has).
280 * @nr_cpus Number of CPU on this machine.
283 * @cpu_per_node Number of CPU per node.
284 * @cpu2node The node the CPU belongs to.
287 * Highest node number found (e.g., 0 means node 0).
288 * A value of -1 means no nodes have been found.
289 ***************************************************************************
291 int get_node_placement(int nr_cpus, int cpu_per_node[], int cpu2node[])
296 char line[MAX_PF_NAME];
297 int cpu, node, hi_node_nr = -1;
299 /* Init number of CPU per node */
300 memset(cpu_per_node, 0, sizeof(int) * (nr_cpus + 1));
301 /* CPU belongs to no node by default */
302 memset(cpu2node, -1, sizeof(int) * nr_cpus);
304 /* This is node "all" */
305 cpu_per_node[0] = nr_cpus;
307 for (cpu = 0; cpu < nr_cpus; cpu++) {
308 snprintf(line, sizeof(line), "%s/cpu%d", SYSFS_DEVCPU, cpu);
309 line[sizeof(line) - 1] = '\0';
311 /* Open relevant /sys directory */
312 if ((dir = opendir(line)) == NULL)
315 /* Get current file entry */
316 while ((drd = readdir(dir)) != NULL) {
318 if (!strncmp(drd->d_name, "node", 4) && isdigit(drd->d_name[4])) {
319 node = atoi(drd->d_name + 4);
320 if ((node >= nr_cpus) || (node < 0)) {
321 /* Assume we cannot have more nodes than CPU */
325 cpu_per_node[node + 1]++;
326 cpu2node[cpu] = node;
327 if (node > hi_node_nr) {
330 /* Node placement found for current CPU: Go to next CPU directory */
335 /* Close directory */
343 ***************************************************************************
344 * Read system logical topology: Socket number for each logical core is read
345 * from the /sys/devices/system/cpu/cpu{N}/topology/physical_package_id file,
346 * and the logical core id number is the first number read from the
347 * /sys/devices/system/cpu/cpu{N}/topology/thread_siblings_list file.
348 * Don't use /sys/devices/system/cpu/cpu{N}/topology/core_id as this is the
349 * physical core id (seems to be different from the number displayed by lscpu).
352 * @nr_cpus Number of CPU on this machine.
353 * @cpu_topo Structures where socket and core id numbers will be saved.
356 * @cpu_topo Structures where socket and core id numbers have been saved.
357 ***************************************************************************
359 void read_topology(int nr_cpus, struct cpu_topology *cpu_topo)
361 struct cpu_topology *cpu_topo_i;
363 char filename[MAX_PF_NAME];
366 /* Init system topology */
367 memset(st_cpu_topology, 0, sizeof(struct cpu_topology) * nr_cpus);
369 for (cpu = 0; cpu < nr_cpus; cpu++) {
371 cpu_topo_i = cpu_topo + cpu;
373 /* Read current CPU's socket number */
374 snprintf(filename, sizeof(filename), "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, PHYS_PACK_ID);
375 filename[sizeof(filename) - 1] = '\0';
377 if ((fp = fopen(filename, "r")) != NULL) {
378 rc = fscanf(fp, "%d", &cpu_topo_i->phys_package_id);
382 cpu_topo_i->phys_package_id = -1;
386 /* Read current CPU's logical core id number */
387 snprintf(filename, sizeof(filename), "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, THREAD_SBL_LST);
388 filename[sizeof(filename) - 1] = '\0';
390 if ((fp = fopen(filename, "r")) != NULL) {
391 rc = fscanf(fp, "%d", &cpu_topo_i->logical_core_id);
395 cpu_topo_i->logical_core_id = -1;
402 ***************************************************************************
403 * Compute node statistics: Split CPU statistics among nodes.
406 * @src Structure containing CPU stats to add.
409 * @dest Structure containing global CPU stats.
410 ***************************************************************************
412 void add_cpu_stats(struct stats_cpu *dest, struct stats_cpu *src)
414 dest->cpu_user += src->cpu_user;
415 dest->cpu_nice += src->cpu_nice;
416 dest->cpu_sys += src->cpu_sys;
417 dest->cpu_idle += src->cpu_idle;
418 dest->cpu_iowait += src->cpu_iowait;
419 dest->cpu_hardirq += src->cpu_hardirq;
420 dest->cpu_softirq += src->cpu_softirq;
421 dest->cpu_steal += src->cpu_steal;
422 dest->cpu_guest += src->cpu_guest;
423 dest->cpu_guest_nice += src->cpu_guest_nice;
427 ***************************************************************************
428 * Compute node statistics: Split CPU statistics among nodes.
431 * @prev Index in array where stats used as reference are.
432 * @curr Index in array for current sample statistics.
435 * @st_node Array where CPU stats for each node have been saved.
436 ***************************************************************************
438 void set_node_cpu_stats(int prev, int curr)
441 unsigned long long tot_jiffies_p;
442 struct stats_cpu *scp, *scc, *snp, *snc;
443 struct stats_cpu *scc_all = st_cpu[curr];
444 struct stats_cpu *scp_all = st_cpu[prev];
445 struct stats_cpu *snc_all = st_node[curr];
446 struct stats_cpu *snp_all = st_node[prev];
448 /* Reset structures */
449 memset(st_node[prev], 0, STATS_CPU_SIZE * (cpu_nr + 1));
450 memset(st_node[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
452 /* Node 'all' is the same as CPU 'all' */
456 /* Individual nodes */
457 for (cpu = 0; cpu < cpu_nr; cpu++) {
458 scc = st_cpu[curr] + cpu + 1;
459 scp = st_cpu[prev] + cpu + 1;
460 snp = st_node[prev] + cpu2node[cpu] + 1;
461 snc = st_node[curr] + cpu2node[cpu] + 1;
464 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
465 scp->cpu_sys + scp->cpu_idle +
466 scp->cpu_iowait + scp->cpu_hardirq +
467 scp->cpu_steal + scp->cpu_softirq;
468 if ((tot_jiffies_p == 0) && (interval != 0))
470 * CPU has just come back online with no ref from
471 * previous iteration: Skip it.
475 add_cpu_stats(snp, scp);
476 add_cpu_stats(snc, scc);
481 ***************************************************************************
482 * Compute global CPU statistics as the sum of individual CPU ones, and
483 * calculate interval for global CPU.
484 * Also identify offline CPU.
487 * @prev Index in array where stats used as reference are.
488 * @curr Index in array for current sample statistics.
489 * @offline_cpu_bitmap
490 * CPU bitmap for offline CPU.
493 * @offline_cpu_bitmap
494 * CPU bitmap with offline CPU.
497 * Interval for global CPU.
498 ***************************************************************************
500 unsigned long long get_global_cpu_mpstats(int prev, int curr,
501 unsigned char offline_cpu_bitmap[])
504 unsigned long long tot_jiffies_c, tot_jiffies_p;
505 unsigned long long deltot_jiffies = 0;
506 struct stats_cpu *scc, *scp;
507 struct stats_cpu *scc_all = st_cpu[curr];
508 struct stats_cpu *scp_all = st_cpu[prev];
511 * For UP machines we keep the values read from global CPU line in /proc/stat.
512 * Also look for offline CPU: They won't be displayed, and some of their values may
513 * have to be modified.
516 memset(scc_all, 0, sizeof(struct stats_cpu));
517 memset(scp_all, 0, sizeof(struct stats_cpu));
520 /* This is a UP machine */
521 return get_per_cpu_interval(st_cpu[curr], st_cpu[prev]);
524 for (i = 1; i <= cpu_nr; i++) {
526 scc = st_cpu[curr] + i;
527 scp = st_cpu[prev] + i;
530 * Compute the total number of jiffies spent by current processor.
531 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
532 * already include them.
534 tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
535 scc->cpu_sys + scc->cpu_idle +
536 scc->cpu_iowait + scc->cpu_hardirq +
537 scc->cpu_steal + scc->cpu_softirq;
538 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
539 scp->cpu_sys + scp->cpu_idle +
540 scp->cpu_iowait + scp->cpu_hardirq +
541 scp->cpu_steal + scp->cpu_softirq;
544 * If the CPU is offline then it is omited from /proc/stat:
545 * All the fields couldn't have been read and the sum of them is zero.
547 if (tot_jiffies_c == 0) {
549 * CPU is currently offline.
550 * Set current struct fields (which have been set to zero)
551 * to values from previous iteration. Hence their values won't
552 * jump from zero when the CPU comes back online.
553 * Note that this workaround no longer fully applies with recent kernels,
554 * as I have noticed that when a CPU comes back online, some fields
555 * restart from their previous value (e.g. user, nice, system)
556 * whereas others restart from zero (idle, iowait)! To deal with this,
557 * the get_per_cpu_interval() function will set these previous values
558 * to zero if necessary.
563 * Mark CPU as offline to not display it
564 * (and thus it will not be confused with a tickless CPU).
566 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
569 if ((tot_jiffies_p == 0) && (interval != 0)) {
571 * CPU has just come back online.
572 * Unfortunately, no reference values are available
573 * from a previous iteration, probably because it was
574 * already offline when the first sample has been taken.
575 * So don't display that CPU to prevent "jump-from-zero"
576 * output syndrome, and don't take it into account for CPU "all".
577 * NB: Test for interval != 0 to make sure we don't want stats
580 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
585 * Get interval for current CPU and add it to global CPU.
586 * Note: Previous idle and iowait values (saved in scp) may be modified here.
588 deltot_jiffies += get_per_cpu_interval(scc, scp);
590 add_cpu_stats(scc_all, scc);
591 add_cpu_stats(scp_all, scp);
594 return deltot_jiffies;
598 ***************************************************************************
599 * Display CPU statistics in plain format.
602 * @dis TRUE if a header line must be printed.
604 * Number of jiffies spent on the interval by all processors.
605 * @prev Position in array where statistics used as reference are.
606 * Stats used as reference may be the previous ones read, or
607 * the very first ones when calculating the average.
608 * @curr Position in array where current statistics will be saved.
609 * @prev_string String displayed at the beginning of a header line. This is
610 * the timestamp of the previous sample, or "Average" when
611 * displaying average stats.
612 * @curr_string String displayed at the beginning of current sample stats.
613 * This is the timestamp of the current sample, or "Average"
614 * when displaying average stats.
615 * @offline_cpu_bitmap
616 * CPU bitmap for offline CPU.
617 ***************************************************************************
619 void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
620 char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
623 struct stats_cpu *scc, *scp;
624 struct cpu_topology *cpu_topo_i;
627 printf("\n%-11s CPU", prev_string);
628 if (DISPLAY_TOPOLOGY(flags)) {
629 printf(" CORE SOCK NODE");
631 printf(" %%usr %%nice %%sys %%iowait %%irq "
632 "%%soft %%steal %%guest %%gnice %%idle\n");
636 * Now display CPU statistics (including CPU "all"),
637 * except for offline CPU or CPU that the user doesn't want to see.
639 for (i = 0; i <= cpu_nr; i++) {
641 /* Check if we want stats about this proc */
642 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
643 offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
646 scc = st_cpu[curr] + i;
647 scp = st_cpu[prev] + i;
649 printf("%-11s", curr_string);
652 /* This is CPU "all" */
653 cprintf_in(IS_STR, " %s", " all", 0);
655 if (DISPLAY_TOPOLOGY(flags)) {
660 cprintf_in(IS_INT, " %4d", "", i - 1);
662 if (DISPLAY_TOPOLOGY(flags)) {
663 cpu_topo_i = st_cpu_topology + i - 1;
664 cprintf_in(IS_INT, " %4d", "", cpu_topo_i->logical_core_id);
665 cprintf_in(IS_INT, " %4d", "", cpu_topo_i->phys_package_id);
666 cprintf_in(IS_INT, " %4d", "", cpu2node[i - 1]);
669 /* Recalculate itv for current proc */
670 deltot_jiffies = get_per_cpu_interval(scc, scp);
672 if (!deltot_jiffies) {
674 * If the CPU is tickless then there is no change in CPU values
675 * but the sum of values is not zero.
677 cprintf_pc(NO_UNIT, 10, 7, 2,
678 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
685 cprintf_pc(NO_UNIT, 10, 7, 2,
686 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
688 ll_sp_value(scp->cpu_user - scp->cpu_guest,
689 scc->cpu_user - scc->cpu_guest, deltot_jiffies),
690 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
692 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
693 scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
694 ll_sp_value(scp->cpu_sys,
695 scc->cpu_sys, deltot_jiffies),
696 ll_sp_value(scp->cpu_iowait,
697 scc->cpu_iowait, deltot_jiffies),
698 ll_sp_value(scp->cpu_hardirq,
699 scc->cpu_hardirq, deltot_jiffies),
700 ll_sp_value(scp->cpu_softirq,
701 scc->cpu_softirq, deltot_jiffies),
702 ll_sp_value(scp->cpu_steal,
703 scc->cpu_steal, deltot_jiffies),
704 ll_sp_value(scp->cpu_guest,
705 scc->cpu_guest, deltot_jiffies),
706 ll_sp_value(scp->cpu_guest_nice,
707 scc->cpu_guest_nice, deltot_jiffies),
708 (scc->cpu_idle < scp->cpu_idle) ?
710 ll_sp_value(scp->cpu_idle,
711 scc->cpu_idle, deltot_jiffies));
717 ***************************************************************************
718 * Display CPU statistics in JSON format.
721 * @tab Number of tabs to print.
723 * Number of jiffies spent on the interval by all processors.
724 * @prev Position in array where statistics used as reference are.
725 * Stats used as reference may be the previous ones read, or
726 * the very first ones when calculating the average.
727 * @curr Position in array where current statistics will be saved.
728 * @offline_cpu_bitmap
729 * CPU bitmap for offline CPU.
730 ***************************************************************************
732 void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev, int curr,
733 unsigned char offline_cpu_bitmap[])
736 char cpu_name[16], topology[1024] = "";
737 struct stats_cpu *scc, *scp;
738 struct cpu_topology *cpu_topo_i;
740 xprintf(tab++, "\"cpu-load\": [");
743 * Now display CPU statistics (including CPU "all"),
744 * except for offline CPU or CPU that the user doesn't want to see.
746 for (i = 0; i <= cpu_nr; i++) {
748 /* Check if we want stats about this proc */
749 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
750 offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
753 scc = st_cpu[curr] + i;
754 scp = st_cpu[prev] + i;
762 /* This is CPU "all" */
763 strcpy(cpu_name, "all");
765 if (DISPLAY_TOPOLOGY(flags)) {
766 snprintf(topology, 1024,
767 ", \"core\": \"\", \"socket\": \"\", \"node\": \"\"");
772 snprintf(cpu_name, 16, "%d", i - 1);
775 if (DISPLAY_TOPOLOGY(flags)) {
776 cpu_topo_i = st_cpu_topology + i - 1;
777 snprintf(topology, 1024,
778 ", \"core\": \"%d\", \"socket\": \"%d\", \"node\": \"%d\"",
779 cpu_topo_i->logical_core_id, cpu_topo_i->phys_package_id, cpu2node[i - 1]);
782 /* Recalculate itv for current proc */
783 deltot_jiffies = get_per_cpu_interval(scc, scp);
785 if (!deltot_jiffies) {
787 * If the CPU is tickless then there is no change in CPU values
788 * but the sum of values is not zero.
790 xprintf0(tab, "{\"cpu\": \"%d\"%s, \"usr\": 0.00, \"nice\": 0.00, "
791 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
792 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
793 "\"gnice\": 0.00, \"idle\": 100.00}", i - 1, topology);
800 xprintf0(tab, "{\"cpu\": \"%s\"%s, \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
801 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
802 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
804 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
806 ll_sp_value(scp->cpu_user - scp->cpu_guest,
807 scc->cpu_user - scc->cpu_guest, deltot_jiffies),
808 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
810 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
811 scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
812 ll_sp_value(scp->cpu_sys,
813 scc->cpu_sys, deltot_jiffies),
814 ll_sp_value(scp->cpu_iowait,
815 scc->cpu_iowait, deltot_jiffies),
816 ll_sp_value(scp->cpu_hardirq,
817 scc->cpu_hardirq, deltot_jiffies),
818 ll_sp_value(scp->cpu_softirq,
819 scc->cpu_softirq, deltot_jiffies),
820 ll_sp_value(scp->cpu_steal,
821 scc->cpu_steal, deltot_jiffies),
822 ll_sp_value(scp->cpu_guest,
823 scc->cpu_guest, deltot_jiffies),
824 ll_sp_value(scp->cpu_guest_nice,
825 scc->cpu_guest_nice, deltot_jiffies),
826 (scc->cpu_idle < scp->cpu_idle) ?
828 ll_sp_value(scp->cpu_idle,
829 scc->cpu_idle, deltot_jiffies));
833 xprintf0(--tab, "]");
837 ***************************************************************************
838 * Display CPU statistics in plain or JSON format.
841 * @dis TRUE if a header line must be printed.
843 * Number of jiffies spent on the interval by all processors.
844 * @prev Position in array where statistics used as reference are.
845 * Stats used as reference may be the previous ones read, or
846 * the very first ones when calculating the average.
847 * @curr Position in array where current statistics will be saved.
848 * @prev_string String displayed at the beginning of a header line. This is
849 * the timestamp of the previous sample, or "Average" when
850 * displaying average stats.
851 * @curr_string String displayed at the beginning of current sample stats.
852 * This is the timestamp of the current sample, or "Average"
853 * when displaying average stats.
854 * @tab Number of tabs to print (JSON format only).
855 * @next TRUE is a previous activity has been displayed (JSON format
857 * @offline_cpu_bitmap
858 * CPU bitmap for offline CPU.
859 ***************************************************************************
861 void write_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
862 char *prev_string, char *curr_string, int tab, int *next,
863 unsigned char offline_cpu_bitmap[])
865 if (!deltot_jiffies) {
866 /* CPU "all" cannot be tickless */
870 if (DISPLAY_JSON_OUTPUT(flags)) {
875 write_json_cpu_stats(tab, deltot_jiffies, prev, curr,
879 write_plain_cpu_stats(dis, deltot_jiffies, prev, curr,
880 prev_string, curr_string, offline_cpu_bitmap);
885 ***************************************************************************
886 * Display CPU statistics for NUMA nodes in plain format.
889 * @dis TRUE if a header line must be printed.
891 * Number of jiffies spent on the interval by all processors.
892 * @prev Position in array where statistics used as reference are.
893 * Stats used as reference may be the previous ones read, or
894 * the very first ones when calculating the average.
895 * @curr Position in array where current statistics will be saved.
896 * @prev_string String displayed at the beginning of a header line. This is
897 * the timestamp of the previous sample, or "Average" when
898 * displaying average stats.
899 * @curr_string String displayed at the beginning of current sample stats.
900 * This is the timestamp of the current sample, or "Average"
901 * when displaying average stats.
902 ***************************************************************************
904 void write_plain_node_stats(int dis, unsigned long long deltot_jiffies,
905 int prev, int curr, char *prev_string, char *curr_string)
907 struct stats_cpu *snc, *snp, *scc, *scp;
911 printf("\n%-11s NODE %%usr %%nice %%sys %%iowait %%irq "
912 "%%soft %%steal %%guest %%gnice %%idle\n",
916 for (node = 0; node <= node_nr + 1; node++) {
918 snc = st_node[curr] + node;
919 snp = st_node[prev] + node;
921 /* Check if we want stats about this node */
922 if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
925 if (!cpu_per_node[node])
926 /* No CPU in this node */
929 printf("%-11s", curr_string);
931 /* This is node "all", i.e. CPU "all" */
932 cprintf_in(IS_STR, " %s", " all", 0);
935 cprintf_in(IS_INT, " %4d", "", node - 1);
937 /* Recalculate interval for current node */
939 for (cpu = 1; cpu <= cpu_nr; cpu++) {
940 scc = st_cpu[curr] + cpu;
941 scp = st_cpu[prev] + cpu;
943 if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
944 scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
945 scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
948 if (cpu2node[cpu - 1] == node - 1) {
949 deltot_jiffies += get_per_cpu_interval(scc, scp);
953 if (!deltot_jiffies) {
954 /* All CPU in node are tickless and/or offline */
955 cprintf_pc(NO_UNIT, 10, 7, 2,
956 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
963 cprintf_pc(NO_UNIT, 10, 7, 2,
964 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
966 ll_sp_value(snp->cpu_user - snp->cpu_guest,
967 snc->cpu_user - snc->cpu_guest, deltot_jiffies),
968 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
970 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
971 snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
972 ll_sp_value(snp->cpu_sys,
973 snc->cpu_sys, deltot_jiffies),
974 ll_sp_value(snp->cpu_iowait,
975 snc->cpu_iowait, deltot_jiffies),
976 ll_sp_value(snp->cpu_hardirq,
977 snc->cpu_hardirq, deltot_jiffies),
978 ll_sp_value(snp->cpu_softirq,
979 snc->cpu_softirq, deltot_jiffies),
980 ll_sp_value(snp->cpu_steal,
981 snc->cpu_steal, deltot_jiffies),
982 ll_sp_value(snp->cpu_guest,
983 snc->cpu_guest, deltot_jiffies),
984 ll_sp_value(snp->cpu_guest_nice,
985 snc->cpu_guest_nice, deltot_jiffies),
986 (snc->cpu_idle < snp->cpu_idle) ?
988 ll_sp_value(snp->cpu_idle,
989 snc->cpu_idle, deltot_jiffies));
995 ***************************************************************************
996 * Display CPU statistics for NUMA nodes in JSON format.
999 * @tab Number of tabs to print.
1001 * Number of jiffies spent on the interval by all processors.
1002 * @prev Position in array where statistics used as reference are.
1003 * Stats used as reference may be the previous ones read, or
1004 * the very first ones when calculating the average.
1005 * @curr Position in array where current statistics will be saved.
1006 ***************************************************************************
1008 void write_json_node_stats(int tab, unsigned long long deltot_jiffies,
1011 struct stats_cpu *snc, *snp, *scc, *scp;
1012 int cpu, node, next = FALSE;
1015 xprintf(tab++, "\"node-load\": [");
1017 for (node = 0; node <= node_nr + 1; node++) {
1019 snc = st_node[curr] + node;
1020 snp = st_node[prev] + node;
1022 /* Check if we want stats about this node */
1023 if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
1026 if (!cpu_per_node[node])
1027 /* No CPU in this node */
1036 /* This is node "all", i.e. CPU "all" */
1037 strcpy(node_name, "all");
1040 snprintf(node_name, 16, "%d", node - 1);
1041 node_name[15] = '\0';
1043 /* Recalculate interval for current node */
1045 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1046 scc = st_cpu[curr] + cpu;
1047 scp = st_cpu[prev] + cpu;
1049 if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
1050 scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
1051 scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
1054 if (cpu2node[cpu - 1] == node - 1) {
1055 deltot_jiffies += get_per_cpu_interval(scc, scp);
1059 if (!deltot_jiffies) {
1060 /* All CPU in node are tickless and/or offline */
1061 xprintf0(tab, "{\"node\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, \"sys\": 0.00, "
1062 "\"iowait\": 0.00, \"irq\": 0.00, \"soft\": 0.00, \"steal\": 0.00, "
1063 "\"guest\": 0.00, \"gnice\": 0.00, \"idle\": 100.00}", node - 1);
1069 xprintf0(tab, "{\"node\": \"%s\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
1070 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
1071 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node_name,
1072 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
1074 ll_sp_value(snp->cpu_user - snp->cpu_guest,
1075 snc->cpu_user - snc->cpu_guest, deltot_jiffies),
1076 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
1078 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
1079 snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
1080 ll_sp_value(snp->cpu_sys,
1081 snc->cpu_sys, deltot_jiffies),
1082 ll_sp_value(snp->cpu_iowait,
1083 snc->cpu_iowait, deltot_jiffies),
1084 ll_sp_value(snp->cpu_hardirq,
1085 snc->cpu_hardirq, deltot_jiffies),
1086 ll_sp_value(snp->cpu_softirq,
1087 snc->cpu_softirq, deltot_jiffies),
1088 ll_sp_value(snp->cpu_steal,
1089 snc->cpu_steal, deltot_jiffies),
1090 ll_sp_value(snp->cpu_guest,
1091 snc->cpu_guest, deltot_jiffies),
1092 ll_sp_value(snp->cpu_guest_nice,
1093 snc->cpu_guest_nice, deltot_jiffies),
1094 (snc->cpu_idle < snp->cpu_idle) ?
1096 ll_sp_value(snp->cpu_idle,
1097 snc->cpu_idle, deltot_jiffies));
1100 xprintf0(--tab, "]");
1104 ***************************************************************************
1105 * Display nodes statistics in plain or JSON format.
1108 * @dis TRUE if a header line must be printed.
1110 * Number of jiffies spent on the interval by all processors.
1111 * @prev Position in array where statistics used as reference are.
1112 * Stats used as reference may be the previous ones read, or
1113 * the very first ones when calculating the average.
1114 * @curr Position in array where current statistics will be saved.
1115 * @prev_string String displayed at the beginning of a header line. This is
1116 * the timestamp of the previous sample, or "Average" when
1117 * displaying average stats.
1118 * @curr_string String displayed at the beginning of current sample stats.
1119 * This is the timestamp of the current sample, or "Average"
1120 * when displaying average stats.
1121 * @tab Number of tabs to print (JSON format only).
1122 * @next TRUE is a previous activity has been displayed (JSON format
1124 ***************************************************************************
1126 void write_node_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
1127 char *prev_string, char *curr_string, int tab, int *next)
1129 if (!deltot_jiffies) {
1130 /* CPU "all" cannot be tickless */
1134 if (DISPLAY_JSON_OUTPUT(flags)) {
1139 write_json_node_stats(tab, deltot_jiffies, prev, curr);
1142 write_plain_node_stats(dis, deltot_jiffies, prev, curr,
1143 prev_string, curr_string);
1148 ***************************************************************************
1149 * Display total number of interrupts per CPU in plain format.
1152 * @dis TRUE if a header line must be printed.
1153 * @itv Interval value.
1154 * @prev Position in array where statistics used as reference are.
1155 * Stats used as reference may be the previous ones read, or
1156 * the very first ones when calculating the average.
1157 * @curr Position in array where current statistics will be saved.
1158 * @prev_string String displayed at the beginning of a header line. This is
1159 * the timestamp of the previous sample, or "Average" when
1160 * displaying average stats.
1161 * @curr_string String displayed at the beginning of current sample stats.
1162 * This is the timestamp of the current sample, or "Average"
1163 * when displaying average stats.
1164 ***************************************************************************
1166 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1167 char *prev_string, char *curr_string)
1169 struct stats_cpu *scc, *scp;
1170 struct stats_irq *sic, *sip;
1171 unsigned long long pc_itv;
1175 printf("\n%-11s CPU intr/s\n", prev_string);
1178 if (*cpu_bitmap & 1) {
1179 printf("%-11s", curr_string);
1180 cprintf_in(IS_STR, " %s", " all", 0);
1181 /* Print total number of interrupts among all cpu */
1182 cprintf_f(NO_UNIT, 1, 9, 2,
1183 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1187 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1189 sic = st_irq[curr] + cpu;
1190 sip = st_irq[prev] + cpu;
1192 scc = st_cpu[curr] + cpu;
1193 scp = st_cpu[prev] + cpu;
1195 /* Check if we want stats about this CPU */
1196 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1199 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1200 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1201 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1203 /* This is an offline CPU */
1207 printf("%-11s", curr_string);
1208 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1210 /* Recalculate itv for current proc */
1211 pc_itv = get_per_cpu_interval(scc, scp);
1214 /* This is a tickless CPU: Value displayed is 0.00 */
1215 cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1219 /* Display total number of interrupts for current CPU */
1220 cprintf_f(NO_UNIT, 1, 9, 2,
1221 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1228 ***************************************************************************
1229 * Display total number of interrupts per CPU in JSON format.
1232 * @tab Number of tabs to print.
1233 * @itv Interval value.
1234 * @prev Position in array where statistics used as reference are.
1235 * Stats used as reference may be the previous ones read, or
1236 * the very first ones when calculating the average.
1237 * @curr Position in array where current statistics will be saved.
1238 ***************************************************************************
1240 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr)
1242 struct stats_cpu *scc, *scp;
1243 struct stats_irq *sic, *sip;
1244 unsigned long long pc_itv;
1245 int cpu, next = FALSE;
1247 xprintf(tab++, "\"sum-interrupts\": [");
1249 if (*cpu_bitmap & 1) {
1252 /* Print total number of interrupts among all cpu */
1253 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
1254 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1257 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1259 sic = st_irq[curr] + cpu;
1260 sip = st_irq[prev] + cpu;
1262 scc = st_cpu[curr] + cpu;
1263 scp = st_cpu[prev] + cpu;
1265 /* Check if we want stats about this CPU */
1266 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1274 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1275 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1276 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1278 /* This is an offline CPU */
1282 /* Recalculate itv for current proc */
1283 pc_itv = get_per_cpu_interval(scc, scp);
1286 /* This is a tickless CPU: Value displayed is 0.00 */
1287 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1291 /* Display total number of interrupts for current CPU */
1292 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
1294 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1298 xprintf0(--tab, "]");
1302 ***************************************************************************
1303 * Display total number of interrupts per CPU in plain or JSON format.
1306 * @dis TRUE if a header line must be printed.
1307 * @itv Interval value.
1308 * @prev Position in array where statistics used as reference are.
1309 * Stats used as reference may be the previous ones read, or
1310 * the very first ones when calculating the average.
1311 * @curr Position in array where current statistics will be saved.
1312 * @prev_string String displayed at the beginning of a header line. This is
1313 * the timestamp of the previous sample, or "Average" when
1314 * displaying average stats.
1315 * @curr_string String displayed at the beginning of current sample stats.
1316 * This is the timestamp of the current sample, or "Average"
1317 * when displaying average stats.
1318 * @tab Number of tabs to print (JSON format only).
1319 * @next TRUE is a previous activity has been displayed (JSON format
1321 ***************************************************************************
1323 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1324 char *prev_string, char *curr_string, int tab, int *next)
1326 if (DISPLAY_JSON_OUTPUT(flags)) {
1331 write_json_isumcpu_stats(tab, itv, prev, curr);
1334 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
1339 ***************************************************************************
1340 * Display interrupts statistics for each CPU in plain format.
1343 * @st_ic Array for per-CPU statistics.
1344 * @ic_nr Number of interrupts (hard or soft) per CPU.
1345 * @dis TRUE if a header line must be printed.
1346 * @itv Interval value.
1347 * @prev Position in array where statistics used as reference are.
1348 * Stats used as reference may be the previous ones read, or
1349 * the very first ones when calculating the average.
1350 * @curr Position in array where current statistics will be saved.
1351 * @prev_string String displayed at the beginning of a header line. This is
1352 * the timestamp of the previous sample, or "Average" when
1353 * displaying average stats.
1354 * @curr_string String displayed at the beginning of current sample stats.
1355 * This is the timestamp of the current sample, or "Average"
1356 * when displaying average stats.
1357 ***************************************************************************
1359 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1360 unsigned long long itv, int prev, int curr,
1361 char *prev_string, char *curr_string)
1363 struct stats_cpu *scc;
1364 int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
1365 struct stats_irqcpu *p, *q, *p0, *q0;
1368 * Check if number of interrupts has changed.
1369 * If this is the case, the header line will be printed again.
1370 * NB: A zero interval value indicates that we are
1371 * displaying statistics since system startup.
1373 if (!dis && interval) {
1374 for (j = 0; j < ic_nr; j++) {
1375 p0 = st_ic[curr] + j;
1376 q0 = st_ic[prev] + j;
1377 if (strcmp(p0->irq_name, q0->irq_name))
1379 * These are two different interrupts: The header must be displayed
1380 * (maybe an interrupt has disappeared, or a new one has just been registered).
1381 * Note that we compare even empty strings for the case where
1382 * a disappearing interrupt would be the last one in the list.
1388 if (dis || (j < ic_nr)) {
1390 printf("\n%-11s CPU", prev_string);
1391 for (j = 0; j < ic_nr; j++) {
1392 p0 = st_ic[curr] + j;
1393 if (p0->irq_name[0] == '\0')
1394 /* End of the list of interrupts */
1396 printf(" %8s/s", p0->irq_name);
1401 /* Calculate column widths */
1402 for (j = 0; j < ic_nr; j++) {
1403 p0 = st_ic[curr] + j;
1405 * Width is IRQ name + 2 for the trailing "/s".
1406 * Width is calculated even for "undefined" interrupts (with
1407 * an empty irq_name string) to quiet code analysis tools.
1409 colwidth[j] = strlen(p0->irq_name) + 2;
1411 * Normal space for printing a number is 11 chars
1412 * (space + 10 digits including the period).
1414 if (colwidth[j] < 10) {
1419 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1421 scc = st_cpu[curr] + cpu;
1424 * Check if we want stats about this CPU.
1425 * CPU must have been explicitly selected using option -P,
1426 * else we display every CPU.
1428 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags))
1431 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1432 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1433 scc->cpu_hardirq + scc->cpu_softirq) == 0)
1434 /* Offline CPU found */
1437 printf("%-11s", curr_string);
1438 cprintf_in(IS_INT, " %3d", "", cpu - 1);
1440 for (j = 0; j < ic_nr; j++) {
1441 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1443 * An empty string for irq_name means it is a remaining interrupt
1444 * which is no longer used, for example because the
1445 * number of interrupts has decreased in /proc/interrupts.
1447 if (p0->irq_name[0] == '\0')
1448 /* End of the list of interrupts */
1450 q0 = st_ic[prev] + j;
1454 * If we want stats for the time since system startup,
1455 * we have p0->irq_name != q0->irq_name, since q0 structure
1456 * is completely set to zero.
1458 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1459 /* Check if interrupt exists elsewhere in list */
1460 for (offset = 0; offset < ic_nr; offset++) {
1461 q0 = st_ic[prev] + offset;
1462 if (!strcmp(p0->irq_name, q0->irq_name))
1463 /* Interrupt found at another position */
1468 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1470 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1471 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1472 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1473 S_VALUE(q->interrupt, p->interrupt, itv));
1477 * Instead of printing "N/A", assume that previous value
1478 * for this new interrupt was zero.
1480 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1481 S_VALUE(0, p->interrupt, itv));
1489 ***************************************************************************
1490 * Display interrupts statistics for each CPU in JSON format.
1493 * @tab Number of tabs to print.
1494 * @st_ic Array for per-CPU statistics.
1495 * @ic_nr Number of interrupts (hard or soft) per CPU.
1496 * @itv Interval value.
1497 * @prev Position in array where statistics used as reference are.
1498 * Stats used as reference may be the previous ones read, or
1499 * the very first ones when calculating the average.
1500 * @curr Position in array where current statistics will be saved.
1501 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1502 ***************************************************************************
1504 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
1505 unsigned long long itv, int prev, int curr, int type)
1507 struct stats_cpu *scc;
1508 int j = ic_nr, offset, cpu;
1509 struct stats_irqcpu *p, *q, *p0, *q0;
1510 int nextcpu = FALSE, nextirq;
1512 if (type == M_D_IRQ_CPU) {
1513 xprintf(tab++, "\"individual-interrupts\": [");
1516 xprintf(tab++, "\"soft-interrupts\": [");
1519 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1521 scc = st_cpu[curr] + cpu;
1524 * Check if we want stats about this CPU.
1525 * CPU must have been explicitly selected using option -P,
1526 * else we display every CPU.
1528 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags))
1531 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1532 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1533 scc->cpu_hardirq + scc->cpu_softirq) == 0)
1534 /* Offline CPU found */
1542 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1544 for (j = 0; j < ic_nr; j++) {
1546 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1548 * An empty string for irq_name means it is a remaining interrupt
1549 * which is no longer used, for example because the
1550 * number of interrupts has decreased in /proc/interrupts.
1552 if (p0->irq_name[0] == '\0')
1553 /* End of the list of interrupts */
1555 q0 = st_ic[prev] + j;
1564 * If we want stats for the time since system startup,
1565 * we have p0->irq_name != q0->irq_name, since q0 structure
1566 * is completely set to zero.
1568 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1569 /* Check if interrupt exists elsewhere in list */
1570 for (offset = 0; offset < ic_nr; offset++) {
1571 q0 = st_ic[prev] + offset;
1572 if (!strcmp(p0->irq_name, q0->irq_name))
1573 /* Interrupt found at another position */
1578 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1580 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1581 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1582 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1584 S_VALUE(q->interrupt, p->interrupt, itv));
1588 * Instead of printing "N/A", assume that previous value
1589 * for this new interrupt was zero.
1591 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1593 S_VALUE(0, p->interrupt, itv));
1597 xprintf0(--tab, "] }");
1600 xprintf0(--tab, "]");
1604 ***************************************************************************
1605 * Display interrupts statistics for each CPU in plain or JSON format.
1608 * @st_ic Array for per-CPU statistics.
1609 * @ic_nr Number of interrupts (hard or soft) per CPU.
1610 * @dis TRUE if a header line must be printed.
1611 * @itv Interval value.
1612 * @prev Position in array where statistics used as reference are.
1613 * Stats used as reference may be the previous ones read, or
1614 * the very first ones when calculating the average.
1615 * @curr Position in array where current statistics will be saved.
1616 * @prev_string String displayed at the beginning of a header line. This is
1617 * the timestamp of the previous sample, or "Average" when
1618 * displaying average stats.
1619 * @curr_string String displayed at the beginning of current sample stats.
1620 * This is the timestamp of the current sample, or "Average"
1621 * when displaying average stats.
1622 * @tab Number of tabs to print (JSON format only).
1623 * @next TRUE is a previous activity has been displayed (JSON format
1625 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1626 ***************************************************************************
1628 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1629 unsigned long long itv, int prev, int curr,
1630 char *prev_string, char *curr_string, int tab,
1631 int *next, int type)
1633 if (DISPLAY_JSON_OUTPUT(flags)) {
1638 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type);
1641 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1642 prev_string, curr_string);
1647 ***************************************************************************
1648 * Core function used to display statistics.
1651 * @prev Position in array where statistics used as reference are.
1652 * Stats used as reference may be the previous ones read, or
1653 * the very first ones when calculating the average.
1654 * @curr Position in array where statistics for current sample are.
1655 * @dis TRUE if a header line must be printed.
1656 * @prev_string String displayed at the beginning of a header line. This is
1657 * the timestamp of the previous sample, or "Average" when
1658 * displaying average stats.
1659 * @curr_string String displayed at the beginning of current sample stats.
1660 * This is the timestamp of the current sample, or "Average"
1661 * when displaying average stats.
1662 ***************************************************************************
1664 void write_stats_core(int prev, int curr, int dis,
1665 char *prev_string, char *curr_string)
1667 unsigned long long itv, deltot_jiffies = 1;
1668 int tab = 4, next = FALSE;
1669 unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
1672 TEST_STDOUT(STDOUT_FILENO);
1675 * Compute CPU "all" as sum of all individual CPU (on SMP machines)
1676 * and look for offline CPU.
1678 deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
1680 if (DISPLAY_JSON_OUTPUT(flags)) {
1681 xprintf(tab++, "{");
1682 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1685 /* Get time interval */
1686 itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
1688 /* Print CPU stats */
1689 if (DISPLAY_CPU(actflags)) {
1690 write_cpu_stats(dis, deltot_jiffies, prev, curr,
1691 prev_string, curr_string, tab, &next, offline_cpu_bitmap);
1694 /* Print node CPU stats */
1695 if (DISPLAY_NODE(actflags)) {
1696 set_node_cpu_stats(prev, curr);
1697 write_node_stats(dis, deltot_jiffies, prev, curr, prev_string,
1698 curr_string, tab, &next);
1701 /* Print total number of interrupts per processor */
1702 if (DISPLAY_IRQ_SUM(actflags)) {
1703 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1707 /* Display each interrupt value for each CPU */
1708 if (DISPLAY_IRQ_CPU(actflags)) {
1709 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1710 prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
1712 if (DISPLAY_SOFTIRQS(actflags)) {
1713 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1714 prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
1717 if (DISPLAY_JSON_OUTPUT(flags)) {
1719 xprintf0(--tab, "}");
1724 ***************************************************************************
1725 * Print statistics average.
1728 * @curr Position in array where statistics for current sample are.
1729 * @dis TRUE if a header line must be printed.
1730 ***************************************************************************
1732 void write_stats_avg(int curr, int dis)
1736 strncpy(string, _("Average:"), 16);
1738 write_stats_core(2, curr, dis, string, string);
1742 ***************************************************************************
1746 * @curr Position in array where statistics for current sample are.
1747 * @dis TRUE if a header line must be printed.
1748 ***************************************************************************
1750 void write_stats(int curr, int dis)
1752 char cur_time[2][TIMESTAMP_LEN];
1754 /* Get previous timestamp */
1755 if (is_iso_time_fmt()) {
1756 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1759 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1762 /* Get current timestamp */
1763 if (is_iso_time_fmt()) {
1764 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &mp_tstamp[curr]);
1767 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1770 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1774 ***************************************************************************
1775 * Read stats from /proc/interrupts or /proc/softirqs.
1778 * @file /proc file to read (interrupts or softirqs).
1779 * @ic_nr Number of interrupts (hard or soft) per CPU.
1780 * @curr Position in array where current statistics will be saved.
1783 * @st_ic Array for per-CPU interrupts statistics.
1784 ***************************************************************************
1786 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1789 struct stats_irq *st_irq_i;
1790 struct stats_irqcpu *p;
1791 char *line = NULL, *li;
1792 unsigned long irq = 0;
1794 int cpu_index[cpu_nr], index = 0, len;
1797 /* Reset total number of interrupts received by each CPU */
1798 for (cpu = 0; cpu < cpu_nr; cpu++) {
1799 st_irq_i = st_irq[curr] + cpu + 1;
1800 st_irq_i->irq_nr = 0;
1803 if ((fp = fopen(file, "r")) != NULL) {
1805 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1808 * Parse header line to see which CPUs are online
1810 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1812 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1813 cpu = strtol(cp + 3, &next, 10);
1814 cpu_index[index++] = cpu;
1817 /* Header line found */
1821 /* Parse each line of interrupts statistics data */
1822 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1825 /* Skip over "<irq>:" */
1826 if ((cp = strchr(line, ':')) == NULL)
1827 /* Chr ':' not found */
1831 p = st_ic[curr] + irq;
1833 /* Remove possible heading spaces in interrupt's name... */
1838 len = strcspn(li, ":");
1839 if (len >= MAX_IRQ_LEN) {
1840 len = MAX_IRQ_LEN - 1;
1842 /* ...then save its name */
1843 strncpy(p->irq_name, li, len);
1844 p->irq_name[len] = '\0';
1846 /* For each interrupt: Get number received by each CPU */
1847 for (cpu = 0; cpu < index; cpu++) {
1848 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1849 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1851 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1852 * This is the same as st_irqcpu->irq_name.
1853 * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1854 * and total number of interrupts received by current CPU (in stats_irq structure).
1856 p->interrupt = strtoul(cp, &next, 10);
1857 st_irq_i->irq_nr += p->interrupt;
1868 while (irq < ic_nr) {
1869 /* Nb of interrupts per processor has changed */
1870 p = st_ic[curr] + irq;
1871 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
1877 ***************************************************************************
1878 * Main loop: Read stats from the relevant sources, and display them.
1881 * @dis_hdr Set to TRUE if the header line must always be printed.
1882 * @rows Number of rows of screen.
1883 ***************************************************************************
1885 void rw_mpstat_loop(int dis_hdr, int rows)
1887 struct stats_cpu *scc;
1889 int curr = 1, dis = 1;
1890 unsigned long lines = rows;
1892 /* Read system uptime and CPU stats */
1893 read_uptime(&(uptime_cs[0]));
1894 read_stat_cpu(st_cpu[0], cpu_nr + 1);
1897 * Calculate global CPU stats as the sum of individual ones.
1898 * Done only on SMP machines. On UP machines, we keep the values
1899 * read from /proc/stat for global CPU stats.
1902 memset(st_cpu[0], 0, STATS_CPU_SIZE);
1904 for (i = 1; i <= cpu_nr; i++) {
1905 scc = st_cpu[0] + i;
1907 st_cpu[0]->cpu_user += scc->cpu_user;
1908 st_cpu[0]->cpu_nice += scc->cpu_nice;
1909 st_cpu[0]->cpu_sys += scc->cpu_sys;
1910 st_cpu[0]->cpu_idle += scc->cpu_idle;
1911 st_cpu[0]->cpu_iowait += scc->cpu_iowait;
1912 st_cpu[0]->cpu_hardirq += scc->cpu_hardirq;
1913 st_cpu[0]->cpu_steal += scc->cpu_steal;
1914 st_cpu[0]->cpu_softirq += scc->cpu_softirq;
1915 st_cpu[0]->cpu_guest += scc->cpu_guest;
1916 st_cpu[0]->cpu_guest_nice += scc->cpu_guest_nice;
1920 /* Read system topology */
1921 if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
1922 read_topology(cpu_nr, st_cpu_topology);
1926 * Read total number of interrupts received among all CPU.
1927 * (this is the first value on the line "intr:" in the /proc/stat file).
1929 if (DISPLAY_IRQ_SUM(actflags)) {
1930 read_stat_irq(st_irq[0], 1);
1934 * Read number of interrupts received by each CPU, for each interrupt,
1935 * and compute the total number of interrupts received by each CPU.
1937 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1938 /* Read this file to display int per CPU or total nr of int per CPU */
1939 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1941 if (DISPLAY_SOFTIRQS(actflags)) {
1942 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1946 /* Display since boot time */
1947 mp_tstamp[1] = mp_tstamp[0];
1948 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1949 memset(st_node[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1950 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1951 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1952 if (DISPLAY_SOFTIRQS(actflags)) {
1953 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1955 write_stats(0, DISP_HDR);
1956 if (DISPLAY_JSON_OUTPUT(flags)) {
1957 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1962 /* Set a handler for SIGALRM */
1963 memset(&alrm_act, 0, sizeof(alrm_act));
1964 alrm_act.sa_handler = alarm_handler;
1965 sigaction(SIGALRM, &alrm_act, NULL);
1968 /* Save the first stats collected. Will be used to compute the average */
1969 mp_tstamp[2] = mp_tstamp[0];
1970 uptime_cs[2] = uptime_cs[0];
1971 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1972 memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
1973 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1974 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1975 if (DISPLAY_SOFTIRQS(actflags)) {
1976 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1977 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1980 /* Set a handler for SIGINT */
1981 memset(&int_act, 0, sizeof(int_act));
1982 int_act.sa_handler = int_handler;
1983 sigaction(SIGINT, &int_act, NULL);
1988 /* SIGINT signal caught during first interval: Exit immediately */
1993 * Resetting the structure not needed since every fields will be set.
1994 * Exceptions are per-CPU structures: Some of them may not be filled
1995 * if corresponding processor is disabled (offline). We set them to zero
1996 * to be able to distinguish between offline and tickless CPUs.
1998 memset(st_cpu[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
2001 get_localtime(&(mp_tstamp[curr]), 0);
2003 /* Read uptime and CPU stats */
2004 read_uptime(&(uptime_cs[curr]));
2005 read_stat_cpu(st_cpu[curr], cpu_nr + 1);
2007 /* Read system topology */
2008 if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
2009 read_topology(cpu_nr, st_cpu_topology);
2012 /* Read total number of interrupts received among all CPU */
2013 if (DISPLAY_IRQ_SUM(actflags)) {
2014 read_stat_irq(st_irq[curr], 1);
2018 * Read number of interrupts received by each CPU, for each interrupt,
2019 * and compute the total number of interrupts received by each CPU.
2021 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
2022 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
2024 if (DISPLAY_SOFTIRQS(actflags)) {
2025 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
2036 write_stats(curr, dis);
2046 if (sigint_caught) {
2047 /* SIGINT signal caught => Display average stats */
2051 if (DISPLAY_JSON_OUTPUT(flags)) {
2060 /* Write stats average */
2061 if (DISPLAY_JSON_OUTPUT(flags)) {
2062 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
2065 write_stats_avg(curr, dis_hdr);
2070 ***************************************************************************
2071 * Main entry to the program
2072 ***************************************************************************
2074 int main(int argc, char **argv)
2076 int opt = 0, i, actset = FALSE;
2077 struct utsname header;
2083 /* Init National Language Support */
2087 /* Init color strings */
2093 /* What is the highest processor number on this machine? */
2094 cpu_nr = get_cpu_nr(~0, TRUE);
2096 /* Calculate number of interrupts per processor */
2097 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
2099 /* Calculate number of soft interrupts per processor */
2100 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
2104 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
2105 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
2107 salloc_mp_struct(cpu_nr + 1);
2109 /* Get NUMA node placement */
2110 node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
2112 while (++opt < argc) {
2114 if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2115 /* Get number of decimal places */
2116 dplaces_nr = atoi(argv[opt] + 6);
2117 if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2122 else if (!strcmp(argv[opt], "-I")) {
2128 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2129 if (!strcmp(t, K_SUM)) {
2130 /* Display total number of interrupts per CPU */
2131 actflags |= M_D_IRQ_SUM;
2133 else if (!strcmp(t, K_CPU)) {
2134 /* Display interrupts per CPU */
2135 actflags |= M_D_IRQ_CPU;
2137 else if (!strcmp(t, K_SCPU)) {
2138 /* Display soft interrupts per CPU */
2139 actflags |= M_D_SOFTIRQS;
2141 else if (!strcmp(t, K_ALL)) {
2142 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2150 else if (!strcmp(argv[opt], "-o")) {
2151 /* Select output format */
2152 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2153 flags |= F_JSON_OUTPUT;
2160 else if (!strcmp(argv[opt], "-N")) {
2165 flags |= F_OPTION_N;
2166 actflags |= M_D_NODE;
2169 if (parse_values(argv[opt], node_bitmap, node_nr + 1, K_LOWERALL)) {
2175 else if (!strcmp(argv[opt], "-P")) {
2176 /* '-P ALL' can be used on UP machines */
2180 flags |= F_OPTION_P;
2183 if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
2188 else if (!strncmp(argv[opt], "-", 1)) {
2189 for (i = 1; *(argv[opt] + i); i++) {
2191 switch (*(argv[opt] + i)) {
2194 flags |= F_OPTION_A;
2195 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2197 actflags |= M_D_NODE;
2203 /* Display CPU stats based on NUMA node placement */
2205 actflags |= M_D_NODE;
2211 /* Display logical topology */
2212 flags |= F_TOPOLOGY;
2217 actflags |= M_D_CPU;
2221 /* Print version number */
2231 else if (interval < 0) {
2233 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2236 interval = atol(argv[opt]);
2243 else if (count <= 0) {
2244 /* Get count value */
2245 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2249 count = atol(argv[opt]);
2260 /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
2262 (USE_OPTION_P(flags) && !(actflags & ~M_D_NODE))) {
2263 actflags |= M_D_CPU;
2266 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
2270 if (USE_OPTION_A(flags)) {
2272 * Set -P ALL -N ALL only if individual CPU and/or nodes
2273 * have not been selected.
2275 if ((node_nr >= 0) && !USE_OPTION_N(flags)) {
2276 memset(node_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
2277 flags += F_OPTION_N;
2279 if (!USE_OPTION_P(flags)) {
2280 memset(cpu_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
2281 flags += F_OPTION_P;
2285 if (!USE_OPTION_P(flags)) {
2286 /* Option -P not used: Set bit 0 (global stats among all proc) */
2289 if (!USE_OPTION_N(flags)) {
2290 /* Option -N not used: Set bit 0 (global stats among all nodes) */
2297 /* Get window size */
2298 rows = get_win_height();
2301 /* Interval not set => display stats since boot time */
2305 if (DISPLAY_JSON_OUTPUT(flags)) {
2306 /* Use a decimal point to make JSON code compliant with RFC7159 */
2307 setlocale(LC_NUMERIC, "C");
2311 get_localtime(&(mp_tstamp[0]), 0);
2314 * Don't buffer data if redirected to a pipe.
2315 * Note: With musl-c, the behavior of this function is undefined except
2316 * when it is the first operation on the stream.
2318 setbuf(stdout, NULL);
2320 /* Get system name, release number and hostname */
2322 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
2323 header.nodename, header.machine, get_cpu_nr(~0, FALSE),
2324 DISPLAY_JSON_OUTPUT(flags));
2327 rw_mpstat_loop(dis_hdr, rows);
2329 /* Free structures */