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>
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 ] [ -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, MAX_PF_NAME, "%s/cpu%d", SYSFS_DEVCPU, cpu);
309 line[MAX_PF_NAME - 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, MAX_PF_NAME, "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, PHYS_PACK_ID);
375 filename[MAX_PF_NAME - 1] = '\0';
377 if ((fp = fopen(filename, "r")) != NULL) {
378 fscanf(fp, "%d", &cpu_topo_i->phys_package_id);
382 /* Read current CPU's logical core id number */
383 snprintf(filename, MAX_PF_NAME, "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, THREAD_SBL_LST);
384 filename[MAX_PF_NAME - 1] = '\0';
386 if ((fp = fopen(filename, "r")) != NULL) {
387 fscanf(fp, "%d", &cpu_topo_i->logical_core_id);
394 ***************************************************************************
395 * Compute node statistics: Split CPU statistics among nodes.
398 * @src Structure containing CPU stats to add.
401 * @dest Structure containing global CPU stats.
402 ***************************************************************************
404 void add_cpu_stats(struct stats_cpu *dest, struct stats_cpu *src)
406 dest->cpu_user += src->cpu_user;
407 dest->cpu_nice += src->cpu_nice;
408 dest->cpu_sys += src->cpu_sys;
409 dest->cpu_idle += src->cpu_idle;
410 dest->cpu_iowait += src->cpu_iowait;
411 dest->cpu_hardirq += src->cpu_hardirq;
412 dest->cpu_softirq += src->cpu_softirq;
413 dest->cpu_steal += src->cpu_steal;
414 dest->cpu_guest += src->cpu_guest;
415 dest->cpu_guest_nice += src->cpu_guest_nice;
419 ***************************************************************************
420 * Compute node statistics: Split CPU statistics among nodes.
423 * @prev Index in array where stats used as reference are.
424 * @curr Index in array for current sample statistics.
427 * @st_node Array where CPU stats for each node have been saved.
428 ***************************************************************************
430 void set_node_cpu_stats(int prev, int curr)
433 unsigned long long tot_jiffies_p;
434 struct stats_cpu *scp, *scc, *snp, *snc;
435 struct stats_cpu *scc_all = st_cpu[curr];
436 struct stats_cpu *scp_all = st_cpu[prev];
437 struct stats_cpu *snc_all = st_node[curr];
438 struct stats_cpu *snp_all = st_node[prev];
440 /* Reset structures */
441 memset(st_node[prev], 0, STATS_CPU_SIZE * (cpu_nr + 1));
442 memset(st_node[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
444 /* Node 'all' is the same as CPU 'all' */
448 /* Individual nodes */
449 for (cpu = 0; cpu < cpu_nr; cpu++) {
450 scc = st_cpu[curr] + cpu + 1;
451 scp = st_cpu[prev] + cpu + 1;
452 snp = st_node[prev] + cpu2node[cpu] + 1;
453 snc = st_node[curr] + cpu2node[cpu] + 1;
456 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
457 scp->cpu_sys + scp->cpu_idle +
458 scp->cpu_iowait + scp->cpu_hardirq +
459 scp->cpu_steal + scp->cpu_softirq;
460 if ((tot_jiffies_p == 0) && (interval != 0))
462 * CPU has just come back online with no ref from
463 * previous iteration: Skip it.
467 add_cpu_stats(snp, scp);
468 add_cpu_stats(snc, scc);
473 ***************************************************************************
474 * Compute global CPU statistics as the sum of individual CPU ones, and
475 * calculate interval for global CPU.
476 * Also identify offline CPU.
479 * @prev Index in array where stats used as reference are.
480 * @curr Index in array for current sample statistics.
481 * @offline_cpu_bitmap
482 * CPU bitmap for offline CPU.
485 * @offline_cpu_bitmap
486 * CPU bitmap with offline CPU.
489 * Interval for global CPU.
490 ***************************************************************************
492 unsigned long long get_global_cpu_mpstats(int prev, int curr,
493 unsigned char offline_cpu_bitmap[])
496 unsigned long long tot_jiffies_c, tot_jiffies_p;
497 unsigned long long deltot_jiffies = 0;
498 struct stats_cpu *scc, *scp;
499 struct stats_cpu *scc_all = st_cpu[curr];
500 struct stats_cpu *scp_all = st_cpu[prev];
503 * For UP machines we keep the values read from global CPU line in /proc/stat.
504 * Also look for offline CPU: They won't be displayed, and some of their values may
505 * have to be modified.
508 memset(scc_all, 0, sizeof(struct stats_cpu));
509 memset(scp_all, 0, sizeof(struct stats_cpu));
512 /* This is a UP machine */
513 return get_per_cpu_interval(st_cpu[curr], st_cpu[prev]);
516 for (i = 1; i <= cpu_nr; i++) {
518 scc = st_cpu[curr] + i;
519 scp = st_cpu[prev] + i;
522 * Compute the total number of jiffies spent by current processor.
523 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
524 * already include them.
526 tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
527 scc->cpu_sys + scc->cpu_idle +
528 scc->cpu_iowait + scc->cpu_hardirq +
529 scc->cpu_steal + scc->cpu_softirq;
530 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
531 scp->cpu_sys + scp->cpu_idle +
532 scp->cpu_iowait + scp->cpu_hardirq +
533 scp->cpu_steal + scp->cpu_softirq;
536 * If the CPU is offline then it is omited from /proc/stat:
537 * All the fields couldn't have been read and the sum of them is zero.
539 if (tot_jiffies_c == 0) {
541 * CPU is currently offline.
542 * Set current struct fields (which have been set to zero)
543 * to values from previous iteration. Hence their values won't
544 * jump from zero when the CPU comes back online.
545 * Note that this workaround no longer fully applies with recent kernels,
546 * as I have noticed that when a CPU comes back online, some fields
547 * restart from their previous value (e.g. user, nice, system)
548 * whereas others restart from zero (idle, iowait)! To deal with this,
549 * the get_per_cpu_interval() function will set these previous values
550 * to zero if necessary.
555 * Mark CPU as offline to not display it
556 * (and thus it will not be confused with a tickless CPU).
558 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
561 if ((tot_jiffies_p == 0) && (interval != 0)) {
563 * CPU has just come back online.
564 * Unfortunately, no reference values are available
565 * from a previous iteration, probably because it was
566 * already offline when the first sample has been taken.
567 * So don't display that CPU to prevent "jump-from-zero"
568 * output syndrome, and don't take it into account for CPU "all".
569 * NB: Test for interval != 0 to make sure we don't want stats
572 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
577 * Get interval for current CPU and add it to global CPU.
578 * Note: Previous idle and iowait values (saved in scp) may be modified here.
580 deltot_jiffies += get_per_cpu_interval(scc, scp);
582 add_cpu_stats(scc_all, scc);
583 add_cpu_stats(scp_all, scp);
586 return deltot_jiffies;
590 ***************************************************************************
591 * Display CPU statistics in plain format.
594 * @dis TRUE if a header line must be printed.
596 * Number of jiffies spent on the interval by all processors.
597 * @prev Position in array where statistics used as reference are.
598 * Stats used as reference may be the previous ones read, or
599 * the very first ones when calculating the average.
600 * @curr Position in array where current statistics will be saved.
601 * @prev_string String displayed at the beginning of a header line. This is
602 * the timestamp of the previous sample, or "Average" when
603 * displaying average stats.
604 * @curr_string String displayed at the beginning of current sample stats.
605 * This is the timestamp of the current sample, or "Average"
606 * when displaying average stats.
607 * @offline_cpu_bitmap
608 * CPU bitmap for offline CPU.
609 ***************************************************************************
611 void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
612 char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
615 struct stats_cpu *scc, *scp;
616 struct cpu_topology *cpu_topo_i;
619 printf("\n%-11s CPU", prev_string);
620 if (DISPLAY_TOPOLOGY(flags)) {
621 printf(" CORE SOCK NODE");
623 printf(" %%usr %%nice %%sys %%iowait %%irq "
624 "%%soft %%steal %%guest %%gnice %%idle\n");
628 * Now display CPU statistics (including CPU "all"),
629 * except for offline CPU or CPU that the user doesn't want to see.
631 for (i = 0; i <= cpu_nr; i++) {
633 /* Check if we want stats about this proc */
634 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
635 offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
638 scc = st_cpu[curr] + i;
639 scp = st_cpu[prev] + i;
641 printf("%-11s", curr_string);
644 /* This is CPU "all" */
645 cprintf_in(IS_STR, " %s", " all", 0);
647 if (DISPLAY_TOPOLOGY(flags)) {
652 cprintf_in(IS_INT, " %4d", "", i - 1);
654 if (DISPLAY_TOPOLOGY(flags)) {
655 cpu_topo_i = st_cpu_topology + i - 1;
656 cprintf_in(IS_INT, " %4d", "", cpu_topo_i->logical_core_id);
657 cprintf_in(IS_INT, " %4d", "", cpu_topo_i->phys_package_id);
658 cprintf_in(IS_INT, " %4d", "", cpu2node[i - 1]);
661 /* Recalculate itv for current proc */
662 deltot_jiffies = get_per_cpu_interval(scc, scp);
664 if (!deltot_jiffies) {
666 * If the CPU is tickless then there is no change in CPU values
667 * but the sum of values is not zero.
669 cprintf_pc(NO_UNIT, 10, 7, 2,
670 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
677 cprintf_pc(NO_UNIT, 10, 7, 2,
678 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
680 ll_sp_value(scp->cpu_user - scp->cpu_guest,
681 scc->cpu_user - scc->cpu_guest, deltot_jiffies),
682 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
684 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
685 scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
686 ll_sp_value(scp->cpu_sys,
687 scc->cpu_sys, deltot_jiffies),
688 ll_sp_value(scp->cpu_iowait,
689 scc->cpu_iowait, deltot_jiffies),
690 ll_sp_value(scp->cpu_hardirq,
691 scc->cpu_hardirq, deltot_jiffies),
692 ll_sp_value(scp->cpu_softirq,
693 scc->cpu_softirq, deltot_jiffies),
694 ll_sp_value(scp->cpu_steal,
695 scc->cpu_steal, deltot_jiffies),
696 ll_sp_value(scp->cpu_guest,
697 scc->cpu_guest, deltot_jiffies),
698 ll_sp_value(scp->cpu_guest_nice,
699 scc->cpu_guest_nice, deltot_jiffies),
700 (scc->cpu_idle < scp->cpu_idle) ?
702 ll_sp_value(scp->cpu_idle,
703 scc->cpu_idle, deltot_jiffies));
709 ***************************************************************************
710 * Display CPU statistics in JSON format.
713 * @tab Number of tabs to print.
715 * Number of jiffies spent on the interval by all processors.
716 * @prev Position in array where statistics used as reference are.
717 * Stats used as reference may be the previous ones read, or
718 * the very first ones when calculating the average.
719 * @curr Position in array where current statistics will be saved.
720 * @offline_cpu_bitmap
721 * CPU bitmap for offline CPU.
722 ***************************************************************************
724 void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev, int curr,
725 unsigned char offline_cpu_bitmap[])
728 char cpu_name[16], topology[1024] = "";
729 struct stats_cpu *scc, *scp;
730 struct cpu_topology *cpu_topo_i;
732 xprintf(tab++, "\"cpu-load\": [");
735 * Now display CPU statistics (including CPU "all"),
736 * except for offline CPU or CPU that the user doesn't want to see.
738 for (i = 0; i <= cpu_nr; i++) {
740 /* Check if we want stats about this proc */
741 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
742 offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
745 scc = st_cpu[curr] + i;
746 scp = st_cpu[prev] + i;
754 /* This is CPU "all" */
755 strcpy(cpu_name, "all");
757 if (DISPLAY_TOPOLOGY(flags)) {
758 snprintf(topology, 1024,
759 ", \"core\": \"\", \"socket\": \"\", \"node\": \"\"");
764 snprintf(cpu_name, 16, "%d", i - 1);
767 if (DISPLAY_TOPOLOGY(flags)) {
768 cpu_topo_i = st_cpu_topology + i - 1;
769 snprintf(topology, 1024,
770 ", \"core\": \"%d\", \"socket\": \"%d\", \"node\": \"%d\"",
771 cpu_topo_i->logical_core_id, cpu_topo_i->phys_package_id, cpu2node[i - 1]);
774 /* Recalculate itv for current proc */
775 deltot_jiffies = get_per_cpu_interval(scc, scp);
777 if (!deltot_jiffies) {
779 * If the CPU is tickless then there is no change in CPU values
780 * but the sum of values is not zero.
782 xprintf0(tab, "{\"cpu\": \"%d\"%s, \"usr\": 0.00, \"nice\": 0.00, "
783 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
784 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
785 "\"gnice\": 0.00, \"idle\": 100.00}", i - 1, topology);
792 xprintf0(tab, "{\"cpu\": \"%s\"%s, \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
793 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
794 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
796 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
798 ll_sp_value(scp->cpu_user - scp->cpu_guest,
799 scc->cpu_user - scc->cpu_guest, deltot_jiffies),
800 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
802 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
803 scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
804 ll_sp_value(scp->cpu_sys,
805 scc->cpu_sys, deltot_jiffies),
806 ll_sp_value(scp->cpu_iowait,
807 scc->cpu_iowait, deltot_jiffies),
808 ll_sp_value(scp->cpu_hardirq,
809 scc->cpu_hardirq, deltot_jiffies),
810 ll_sp_value(scp->cpu_softirq,
811 scc->cpu_softirq, deltot_jiffies),
812 ll_sp_value(scp->cpu_steal,
813 scc->cpu_steal, deltot_jiffies),
814 ll_sp_value(scp->cpu_guest,
815 scc->cpu_guest, deltot_jiffies),
816 ll_sp_value(scp->cpu_guest_nice,
817 scc->cpu_guest_nice, deltot_jiffies),
818 (scc->cpu_idle < scp->cpu_idle) ?
820 ll_sp_value(scp->cpu_idle,
821 scc->cpu_idle, deltot_jiffies));
825 xprintf0(--tab, "]");
829 ***************************************************************************
830 * Display CPU statistics in plain or JSON format.
833 * @dis TRUE if a header line must be printed.
835 * Number of jiffies spent on the interval by all processors.
836 * @prev Position in array where statistics used as reference are.
837 * Stats used as reference may be the previous ones read, or
838 * the very first ones when calculating the average.
839 * @curr Position in array where current statistics will be saved.
840 * @prev_string String displayed at the beginning of a header line. This is
841 * the timestamp of the previous sample, or "Average" when
842 * displaying average stats.
843 * @curr_string String displayed at the beginning of current sample stats.
844 * This is the timestamp of the current sample, or "Average"
845 * when displaying average stats.
846 * @tab Number of tabs to print (JSON format only).
847 * @next TRUE is a previous activity has been displayed (JSON format
849 * @offline_cpu_bitmap
850 * CPU bitmap for offline CPU.
851 ***************************************************************************
853 void write_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
854 char *prev_string, char *curr_string, int tab, int *next,
855 unsigned char offline_cpu_bitmap[])
857 if (!deltot_jiffies) {
858 /* CPU "all" cannot be tickless */
862 if (DISPLAY_JSON_OUTPUT(flags)) {
867 write_json_cpu_stats(tab, deltot_jiffies, prev, curr,
871 write_plain_cpu_stats(dis, deltot_jiffies, prev, curr,
872 prev_string, curr_string, offline_cpu_bitmap);
877 ***************************************************************************
878 * Display CPU statistics for NUMA nodes in plain format.
881 * @dis TRUE if a header line must be printed.
883 * Number of jiffies spent on the interval by all processors.
884 * @prev Position in array where statistics used as reference are.
885 * Stats used as reference may be the previous ones read, or
886 * the very first ones when calculating the average.
887 * @curr Position in array where current statistics will be saved.
888 * @prev_string String displayed at the beginning of a header line. This is
889 * the timestamp of the previous sample, or "Average" when
890 * displaying average stats.
891 * @curr_string String displayed at the beginning of current sample stats.
892 * This is the timestamp of the current sample, or "Average"
893 * when displaying average stats.
894 ***************************************************************************
896 void write_plain_node_stats(int dis, unsigned long long deltot_jiffies,
897 int prev, int curr, char *prev_string, char *curr_string)
899 struct stats_cpu *snc, *snp, *scc, *scp;
903 printf("\n%-11s NODE %%usr %%nice %%sys %%iowait %%irq "
904 "%%soft %%steal %%guest %%gnice %%idle\n",
908 for (node = 0; node <= node_nr + 1; node++) {
910 snc = st_node[curr] + node;
911 snp = st_node[prev] + node;
913 /* Check if we want stats about this node */
914 if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
917 if (!cpu_per_node[node])
918 /* No CPU in this node */
921 printf("%-11s", curr_string);
923 /* This is node "all", i.e. CPU "all" */
924 cprintf_in(IS_STR, " %s", " all", 0);
927 cprintf_in(IS_INT, " %4d", "", node - 1);
929 /* Recalculate interval for current node */
931 for (cpu = 1; cpu <= cpu_nr; cpu++) {
932 scc = st_cpu[curr] + cpu;
933 scp = st_cpu[prev] + cpu;
935 if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
936 scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
937 scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
940 if (cpu2node[cpu - 1] == node - 1) {
941 deltot_jiffies += get_per_cpu_interval(scc, scp);
945 if (!deltot_jiffies) {
946 /* All CPU in node are tickless and/or offline */
947 cprintf_pc(NO_UNIT, 10, 7, 2,
948 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
955 cprintf_pc(NO_UNIT, 10, 7, 2,
956 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
958 ll_sp_value(snp->cpu_user - snp->cpu_guest,
959 snc->cpu_user - snc->cpu_guest, deltot_jiffies),
960 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
962 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
963 snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
964 ll_sp_value(snp->cpu_sys,
965 snc->cpu_sys, deltot_jiffies),
966 ll_sp_value(snp->cpu_iowait,
967 snc->cpu_iowait, deltot_jiffies),
968 ll_sp_value(snp->cpu_hardirq,
969 snc->cpu_hardirq, deltot_jiffies),
970 ll_sp_value(snp->cpu_softirq,
971 snc->cpu_softirq, deltot_jiffies),
972 ll_sp_value(snp->cpu_steal,
973 snc->cpu_steal, deltot_jiffies),
974 ll_sp_value(snp->cpu_guest,
975 snc->cpu_guest, deltot_jiffies),
976 ll_sp_value(snp->cpu_guest_nice,
977 snc->cpu_guest_nice, deltot_jiffies),
978 (snc->cpu_idle < snp->cpu_idle) ?
980 ll_sp_value(snp->cpu_idle,
981 snc->cpu_idle, deltot_jiffies));
987 ***************************************************************************
988 * Display CPU statistics for NUMA nodes in JSON format.
991 * @tab Number of tabs to print.
993 * Number of jiffies spent on the interval by all processors.
994 * @prev Position in array where statistics used as reference are.
995 * Stats used as reference may be the previous ones read, or
996 * the very first ones when calculating the average.
997 * @curr Position in array where current statistics will be saved.
998 ***************************************************************************
1000 void write_json_node_stats(int tab, unsigned long long deltot_jiffies,
1003 struct stats_cpu *snc, *snp, *scc, *scp;
1004 int cpu, node, next = FALSE;
1007 xprintf(tab++, "\"node-load\": [");
1009 for (node = 0; node <= node_nr + 1; node++) {
1011 snc = st_node[curr] + node;
1012 snp = st_node[prev] + node;
1014 /* Check if we want stats about this node */
1015 if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
1018 if (!cpu_per_node[node])
1019 /* No CPU in this node */
1028 /* This is node "all", i.e. CPU "all" */
1029 strcpy(node_name, "all");
1032 snprintf(node_name, 16, "%d", node - 1);
1033 node_name[15] = '\0';
1035 /* Recalculate interval for current node */
1037 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1038 scc = st_cpu[curr] + cpu;
1039 scp = st_cpu[prev] + cpu;
1041 if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
1042 scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
1043 scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
1046 if (cpu2node[cpu - 1] == node - 1) {
1047 deltot_jiffies += get_per_cpu_interval(scc, scp);
1051 if (!deltot_jiffies) {
1052 /* All CPU in node are tickless and/or offline */
1053 xprintf0(tab, "{\"node\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, \"sys\": 0.00, "
1054 "\"iowait\": 0.00, \"irq\": 0.00, \"soft\": 0.00, \"steal\": 0.00, "
1055 "\"guest\": 0.00, \"gnice\": 0.00, \"idle\": 100.00}", node - 1);
1061 xprintf0(tab, "{\"node\": \"%s\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
1062 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
1063 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node_name,
1064 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
1066 ll_sp_value(snp->cpu_user - snp->cpu_guest,
1067 snc->cpu_user - snc->cpu_guest, deltot_jiffies),
1068 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
1070 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
1071 snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
1072 ll_sp_value(snp->cpu_sys,
1073 snc->cpu_sys, deltot_jiffies),
1074 ll_sp_value(snp->cpu_iowait,
1075 snc->cpu_iowait, deltot_jiffies),
1076 ll_sp_value(snp->cpu_hardirq,
1077 snc->cpu_hardirq, deltot_jiffies),
1078 ll_sp_value(snp->cpu_softirq,
1079 snc->cpu_softirq, deltot_jiffies),
1080 ll_sp_value(snp->cpu_steal,
1081 snc->cpu_steal, deltot_jiffies),
1082 ll_sp_value(snp->cpu_guest,
1083 snc->cpu_guest, deltot_jiffies),
1084 ll_sp_value(snp->cpu_guest_nice,
1085 snc->cpu_guest_nice, deltot_jiffies),
1086 (snc->cpu_idle < snp->cpu_idle) ?
1088 ll_sp_value(snp->cpu_idle,
1089 snc->cpu_idle, deltot_jiffies));
1092 xprintf0(--tab, "]");
1096 ***************************************************************************
1097 * Display nodes statistics in plain or JSON format.
1100 * @dis TRUE if a header line must be printed.
1102 * Number of jiffies spent on the interval by all processors.
1103 * @prev Position in array where statistics used as reference are.
1104 * Stats used as reference may be the previous ones read, or
1105 * the very first ones when calculating the average.
1106 * @curr Position in array where current statistics will be saved.
1107 * @prev_string String displayed at the beginning of a header line. This is
1108 * the timestamp of the previous sample, or "Average" when
1109 * displaying average stats.
1110 * @curr_string String displayed at the beginning of current sample stats.
1111 * This is the timestamp of the current sample, or "Average"
1112 * when displaying average stats.
1113 * @tab Number of tabs to print (JSON format only).
1114 * @next TRUE is a previous activity has been displayed (JSON format
1116 ***************************************************************************
1118 void write_node_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
1119 char *prev_string, char *curr_string, int tab, int *next)
1121 if (!deltot_jiffies) {
1122 /* CPU "all" cannot be tickless */
1126 if (DISPLAY_JSON_OUTPUT(flags)) {
1131 write_json_node_stats(tab, deltot_jiffies, prev, curr);
1134 write_plain_node_stats(dis, deltot_jiffies, prev, curr,
1135 prev_string, curr_string);
1140 ***************************************************************************
1141 * Display total number of interrupts per CPU in plain format.
1144 * @dis TRUE if a header line must be printed.
1145 * @itv Interval value.
1146 * @prev Position in array where statistics used as reference are.
1147 * Stats used as reference may be the previous ones read, or
1148 * the very first ones when calculating the average.
1149 * @curr Position in array where current statistics will be saved.
1150 * @prev_string String displayed at the beginning of a header line. This is
1151 * the timestamp of the previous sample, or "Average" when
1152 * displaying average stats.
1153 * @curr_string String displayed at the beginning of current sample stats.
1154 * This is the timestamp of the current sample, or "Average"
1155 * when displaying average stats.
1156 ***************************************************************************
1158 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1159 char *prev_string, char *curr_string)
1161 struct stats_cpu *scc, *scp;
1162 struct stats_irq *sic, *sip;
1163 unsigned long long pc_itv;
1167 printf("\n%-11s CPU intr/s\n", prev_string);
1170 if (*cpu_bitmap & 1) {
1171 printf("%-11s", curr_string);
1172 cprintf_in(IS_STR, " %s", " all", 0);
1173 /* Print total number of interrupts among all cpu */
1174 cprintf_f(NO_UNIT, 1, 9, 2,
1175 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1179 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1181 sic = st_irq[curr] + cpu;
1182 sip = st_irq[prev] + cpu;
1184 scc = st_cpu[curr] + cpu;
1185 scp = st_cpu[prev] + cpu;
1187 /* Check if we want stats about this CPU */
1188 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1191 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1192 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1193 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1195 /* This is an offline CPU */
1199 printf("%-11s", curr_string);
1200 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1202 /* Recalculate itv for current proc */
1203 pc_itv = get_per_cpu_interval(scc, scp);
1206 /* This is a tickless CPU: Value displayed is 0.00 */
1207 cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1211 /* Display total number of interrupts for current CPU */
1212 cprintf_f(NO_UNIT, 1, 9, 2,
1213 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1220 ***************************************************************************
1221 * Display total number of interrupts per CPU in JSON format.
1224 * @tab Number of tabs to print.
1225 * @itv Interval value.
1226 * @prev Position in array where statistics used as reference are.
1227 * Stats used as reference may be the previous ones read, or
1228 * the very first ones when calculating the average.
1229 * @curr Position in array where current statistics will be saved.
1230 ***************************************************************************
1232 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr)
1234 struct stats_cpu *scc, *scp;
1235 struct stats_irq *sic, *sip;
1236 unsigned long long pc_itv;
1237 int cpu, next = FALSE;
1239 xprintf(tab++, "\"sum-interrupts\": [");
1241 if (*cpu_bitmap & 1) {
1244 /* Print total number of interrupts among all cpu */
1245 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
1246 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1249 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1251 sic = st_irq[curr] + cpu;
1252 sip = st_irq[prev] + cpu;
1254 scc = st_cpu[curr] + cpu;
1255 scp = st_cpu[prev] + cpu;
1257 /* Check if we want stats about this CPU */
1258 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1266 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1267 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1268 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1270 /* This is an offline CPU */
1274 /* Recalculate itv for current proc */
1275 pc_itv = get_per_cpu_interval(scc, scp);
1278 /* This is a tickless CPU: Value displayed is 0.00 */
1279 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1283 /* Display total number of interrupts for current CPU */
1284 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
1286 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1290 xprintf0(--tab, "]");
1294 ***************************************************************************
1295 * Display total number of interrupts per CPU in plain or JSON format.
1298 * @dis TRUE if a header line must be printed.
1299 * @itv Interval value.
1300 * @prev Position in array where statistics used as reference are.
1301 * Stats used as reference may be the previous ones read, or
1302 * the very first ones when calculating the average.
1303 * @curr Position in array where current statistics will be saved.
1304 * @prev_string String displayed at the beginning of a header line. This is
1305 * the timestamp of the previous sample, or "Average" when
1306 * displaying average stats.
1307 * @curr_string String displayed at the beginning of current sample stats.
1308 * This is the timestamp of the current sample, or "Average"
1309 * when displaying average stats.
1310 * @tab Number of tabs to print (JSON format only).
1311 * @next TRUE is a previous activity has been displayed (JSON format
1313 ***************************************************************************
1315 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1316 char *prev_string, char *curr_string, int tab, int *next)
1318 if (DISPLAY_JSON_OUTPUT(flags)) {
1323 write_json_isumcpu_stats(tab, itv, prev, curr);
1326 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
1331 ***************************************************************************
1332 * Display interrupts statistics for each CPU in plain format.
1335 * @st_ic Array for per-CPU statistics.
1336 * @ic_nr Number of interrupts (hard or soft) per CPU.
1337 * @dis TRUE if a header line must be printed.
1338 * @itv Interval value.
1339 * @prev Position in array where statistics used as reference are.
1340 * Stats used as reference may be the previous ones read, or
1341 * the very first ones when calculating the average.
1342 * @curr Position in array where current statistics will be saved.
1343 * @prev_string String displayed at the beginning of a header line. This is
1344 * the timestamp of the previous sample, or "Average" when
1345 * displaying average stats.
1346 * @curr_string String displayed at the beginning of current sample stats.
1347 * This is the timestamp of the current sample, or "Average"
1348 * when displaying average stats.
1349 ***************************************************************************
1351 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1352 unsigned long long itv, int prev, int curr,
1353 char *prev_string, char *curr_string)
1355 struct stats_cpu *scc;
1356 int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
1357 struct stats_irqcpu *p, *q, *p0, *q0;
1360 * Check if number of interrupts has changed.
1361 * If this is the case, the header line will be printed again.
1362 * NB: A zero interval value indicates that we are
1363 * displaying statistics since system startup.
1365 if (!dis && interval) {
1366 for (j = 0; j < ic_nr; j++) {
1367 p0 = st_ic[curr] + j;
1368 q0 = st_ic[prev] + j;
1369 if (strcmp(p0->irq_name, q0->irq_name))
1371 * These are two different interrupts: The header must be displayed
1372 * (maybe an interrupt has disappeared, or a new one has just been registered).
1373 * Note that we compare even empty strings for the case where
1374 * a disappearing interrupt would be the last one in the list.
1380 if (dis || (j < ic_nr)) {
1382 printf("\n%-11s CPU", prev_string);
1383 for (j = 0; j < ic_nr; j++) {
1384 p0 = st_ic[curr] + j;
1385 if (p0->irq_name[0] == '\0')
1386 /* End of the list of interrupts */
1388 printf(" %8s/s", p0->irq_name);
1393 /* Calculate column widths */
1394 for (j = 0; j < ic_nr; j++) {
1395 p0 = st_ic[curr] + j;
1397 * Width is IRQ name + 2 for the trailing "/s".
1398 * Width is calculated even for "undefined" interrupts (with
1399 * an empty irq_name string) to quiet code analysis tools.
1401 colwidth[j] = strlen(p0->irq_name) + 2;
1403 * Normal space for printing a number is 11 chars
1404 * (space + 10 digits including the period).
1406 if (colwidth[j] < 10) {
1411 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1413 scc = st_cpu[curr] + cpu;
1416 * Check if we want stats about this CPU.
1417 * CPU must have been explicitly selected using option -P,
1418 * else we display every CPU.
1420 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags))
1423 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1424 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1425 scc->cpu_hardirq + scc->cpu_softirq) == 0)
1426 /* Offline CPU found */
1429 printf("%-11s", curr_string);
1430 cprintf_in(IS_INT, " %3d", "", cpu - 1);
1432 for (j = 0; j < ic_nr; j++) {
1433 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1435 * An empty string for irq_name means it is a remaining interrupt
1436 * which is no longer used, for example because the
1437 * number of interrupts has decreased in /proc/interrupts.
1439 if (p0->irq_name[0] == '\0')
1440 /* End of the list of interrupts */
1442 q0 = st_ic[prev] + j;
1446 * If we want stats for the time since system startup,
1447 * we have p0->irq_name != q0->irq_name, since q0 structure
1448 * is completely set to zero.
1450 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1451 /* Check if interrupt exists elsewhere in list */
1452 for (offset = 0; offset < ic_nr; offset++) {
1453 q0 = st_ic[prev] + offset;
1454 if (!strcmp(p0->irq_name, q0->irq_name))
1455 /* Interrupt found at another position */
1460 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1462 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1463 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1464 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1465 S_VALUE(q->interrupt, p->interrupt, itv));
1469 * Instead of printing "N/A", assume that previous value
1470 * for this new interrupt was zero.
1472 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1473 S_VALUE(0, p->interrupt, itv));
1481 ***************************************************************************
1482 * Display interrupts statistics for each CPU in JSON format.
1485 * @tab Number of tabs to print.
1486 * @st_ic Array for per-CPU statistics.
1487 * @ic_nr Number of interrupts (hard or soft) per CPU.
1488 * @itv Interval value.
1489 * @prev Position in array where statistics used as reference are.
1490 * Stats used as reference may be the previous ones read, or
1491 * the very first ones when calculating the average.
1492 * @curr Position in array where current statistics will be saved.
1493 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1494 ***************************************************************************
1496 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
1497 unsigned long long itv, int prev, int curr, int type)
1499 struct stats_cpu *scc;
1500 int j = ic_nr, offset, cpu;
1501 struct stats_irqcpu *p, *q, *p0, *q0;
1502 int nextcpu = FALSE, nextirq;
1504 if (type == M_D_IRQ_CPU) {
1505 xprintf(tab++, "\"individual-interrupts\": [");
1508 xprintf(tab++, "\"soft-interrupts\": [");
1511 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1513 scc = st_cpu[curr] + cpu;
1516 * Check if we want stats about this CPU.
1517 * CPU must have been explicitly selected using option -P,
1518 * else we display every CPU.
1520 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags))
1523 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1524 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1525 scc->cpu_hardirq + scc->cpu_softirq) == 0)
1526 /* Offline CPU found */
1534 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1536 for (j = 0; j < ic_nr; j++) {
1538 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1540 * An empty string for irq_name means it is a remaining interrupt
1541 * which is no longer used, for example because the
1542 * number of interrupts has decreased in /proc/interrupts.
1544 if (p0->irq_name[0] == '\0')
1545 /* End of the list of interrupts */
1547 q0 = st_ic[prev] + j;
1556 * If we want stats for the time since system startup,
1557 * we have p0->irq_name != q0->irq_name, since q0 structure
1558 * is completely set to zero.
1560 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1561 /* Check if interrupt exists elsewhere in list */
1562 for (offset = 0; offset < ic_nr; offset++) {
1563 q0 = st_ic[prev] + offset;
1564 if (!strcmp(p0->irq_name, q0->irq_name))
1565 /* Interrupt found at another position */
1570 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1572 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1573 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1574 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1576 S_VALUE(q->interrupt, p->interrupt, itv));
1580 * Instead of printing "N/A", assume that previous value
1581 * for this new interrupt was zero.
1583 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1585 S_VALUE(0, p->interrupt, itv));
1589 xprintf0(--tab, "] }");
1592 xprintf0(--tab, "]");
1596 ***************************************************************************
1597 * Display interrupts statistics for each CPU in plain or JSON format.
1600 * @st_ic Array for per-CPU statistics.
1601 * @ic_nr Number of interrupts (hard or soft) per CPU.
1602 * @dis TRUE if a header line must be printed.
1603 * @itv Interval value.
1604 * @prev Position in array where statistics used as reference are.
1605 * Stats used as reference may be the previous ones read, or
1606 * the very first ones when calculating the average.
1607 * @curr Position in array where current statistics will be saved.
1608 * @prev_string String displayed at the beginning of a header line. This is
1609 * the timestamp of the previous sample, or "Average" when
1610 * displaying average stats.
1611 * @curr_string String displayed at the beginning of current sample stats.
1612 * This is the timestamp of the current sample, or "Average"
1613 * when displaying average stats.
1614 * @tab Number of tabs to print (JSON format only).
1615 * @next TRUE is a previous activity has been displayed (JSON format
1617 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1618 ***************************************************************************
1620 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1621 unsigned long long itv, int prev, int curr,
1622 char *prev_string, char *curr_string, int tab,
1623 int *next, int type)
1625 if (DISPLAY_JSON_OUTPUT(flags)) {
1630 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type);
1633 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1634 prev_string, curr_string);
1639 ***************************************************************************
1640 * Core function used to display statistics.
1643 * @prev Position in array where statistics used as reference are.
1644 * Stats used as reference may be the previous ones read, or
1645 * the very first ones when calculating the average.
1646 * @curr Position in array where statistics for current sample are.
1647 * @dis TRUE if a header line must be printed.
1648 * @prev_string String displayed at the beginning of a header line. This is
1649 * the timestamp of the previous sample, or "Average" when
1650 * displaying average stats.
1651 * @curr_string String displayed at the beginning of current sample stats.
1652 * This is the timestamp of the current sample, or "Average"
1653 * when displaying average stats.
1654 ***************************************************************************
1656 void write_stats_core(int prev, int curr, int dis,
1657 char *prev_string, char *curr_string)
1659 unsigned long long itv, deltot_jiffies = 1;
1660 int tab = 4, next = FALSE;
1661 unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
1664 TEST_STDOUT(STDOUT_FILENO);
1667 * Compute CPU "all" as sum of all individual CPU (on SMP machines)
1668 * and look for offline CPU.
1670 deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
1672 if (DISPLAY_JSON_OUTPUT(flags)) {
1673 xprintf(tab++, "{");
1674 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1677 /* Get time interval */
1678 itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
1680 /* Print CPU stats */
1681 if (DISPLAY_CPU(actflags)) {
1682 write_cpu_stats(dis, deltot_jiffies, prev, curr,
1683 prev_string, curr_string, tab, &next, offline_cpu_bitmap);
1686 /* Print node CPU stats */
1687 if (DISPLAY_NODE(actflags)) {
1688 set_node_cpu_stats(prev, curr);
1689 write_node_stats(dis, deltot_jiffies, prev, curr, prev_string,
1690 curr_string, tab, &next);
1693 /* Print total number of interrupts per processor */
1694 if (DISPLAY_IRQ_SUM(actflags)) {
1695 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1699 /* Display each interrupt value for each CPU */
1700 if (DISPLAY_IRQ_CPU(actflags)) {
1701 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1702 prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
1704 if (DISPLAY_SOFTIRQS(actflags)) {
1705 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1706 prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
1709 if (DISPLAY_JSON_OUTPUT(flags)) {
1711 xprintf0(--tab, "}");
1716 ***************************************************************************
1717 * Print statistics average.
1720 * @curr Position in array where statistics for current sample are.
1721 * @dis TRUE if a header line must be printed.
1722 ***************************************************************************
1724 void write_stats_avg(int curr, int dis)
1728 strncpy(string, _("Average:"), 16);
1730 write_stats_core(2, curr, dis, string, string);
1734 ***************************************************************************
1738 * @curr Position in array where statistics for current sample are.
1739 * @dis TRUE if a header line must be printed.
1740 ***************************************************************************
1742 void write_stats(int curr, int dis)
1744 char cur_time[2][TIMESTAMP_LEN];
1746 /* Get previous timestamp */
1747 if (is_iso_time_fmt()) {
1748 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1751 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1754 /* Get current 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 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1766 ***************************************************************************
1767 * Read stats from /proc/interrupts or /proc/softirqs.
1770 * @file /proc file to read (interrupts or softirqs).
1771 * @ic_nr Number of interrupts (hard or soft) per CPU.
1772 * @curr Position in array where current statistics will be saved.
1775 * @st_ic Array for per-CPU interrupts statistics.
1776 ***************************************************************************
1778 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1781 struct stats_irq *st_irq_i;
1782 struct stats_irqcpu *p;
1783 char *line = NULL, *li;
1784 unsigned long irq = 0;
1786 int cpu_index[cpu_nr], index = 0, len;
1789 /* Reset total number of interrupts received by each CPU */
1790 for (cpu = 0; cpu < cpu_nr; cpu++) {
1791 st_irq_i = st_irq[curr] + cpu + 1;
1792 st_irq_i->irq_nr = 0;
1795 if ((fp = fopen(file, "r")) != NULL) {
1797 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1800 * Parse header line to see which CPUs are online
1802 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1804 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1805 cpu = strtol(cp + 3, &next, 10);
1806 cpu_index[index++] = cpu;
1809 /* Header line found */
1813 /* Parse each line of interrupts statistics data */
1814 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1817 /* Skip over "<irq>:" */
1818 if ((cp = strchr(line, ':')) == NULL)
1819 /* Chr ':' not found */
1823 p = st_ic[curr] + irq;
1825 /* Remove possible heading spaces in interrupt's name... */
1830 len = strcspn(li, ":");
1831 if (len >= MAX_IRQ_LEN) {
1832 len = MAX_IRQ_LEN - 1;
1834 /* ...then save its name */
1835 strncpy(p->irq_name, li, len);
1836 p->irq_name[len] = '\0';
1838 /* For each interrupt: Get number received by each CPU */
1839 for (cpu = 0; cpu < index; cpu++) {
1840 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1841 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1843 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1844 * This is the same as st_irqcpu->irq_name.
1845 * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1846 * and total number of interrupts received by current CPU (in stats_irq structure).
1848 p->interrupt = strtoul(cp, &next, 10);
1849 st_irq_i->irq_nr += p->interrupt;
1860 while (irq < ic_nr) {
1861 /* Nb of interrupts per processor has changed */
1862 p = st_ic[curr] + irq;
1863 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
1869 ***************************************************************************
1870 * Main loop: Read stats from the relevant sources, and display them.
1873 * @dis_hdr Set to TRUE if the header line must always be printed.
1874 * @rows Number of rows of screen.
1875 ***************************************************************************
1877 void rw_mpstat_loop(int dis_hdr, int rows)
1879 struct stats_cpu *scc;
1881 int curr = 1, dis = 1;
1882 unsigned long lines = rows;
1884 /* Dont buffer data if redirected to a pipe */
1885 setbuf(stdout, NULL);
1887 /* Read system uptime and CPU stats */
1888 read_uptime(&(uptime_cs[0]));
1889 read_stat_cpu(st_cpu[0], cpu_nr + 1);
1892 * Calculate global CPU stats as the sum of individual ones.
1893 * Done only on SMP machines. On UP machines, we keep the values
1894 * read from /proc/stat for global CPU stats.
1897 memset(st_cpu[0], 0, STATS_CPU_SIZE);
1899 for (i = 1; i <= cpu_nr; i++) {
1900 scc = st_cpu[0] + i;
1902 st_cpu[0]->cpu_user += scc->cpu_user;
1903 st_cpu[0]->cpu_nice += scc->cpu_nice;
1904 st_cpu[0]->cpu_sys += scc->cpu_sys;
1905 st_cpu[0]->cpu_idle += scc->cpu_idle;
1906 st_cpu[0]->cpu_iowait += scc->cpu_iowait;
1907 st_cpu[0]->cpu_hardirq += scc->cpu_hardirq;
1908 st_cpu[0]->cpu_steal += scc->cpu_steal;
1909 st_cpu[0]->cpu_softirq += scc->cpu_softirq;
1910 st_cpu[0]->cpu_guest += scc->cpu_guest;
1911 st_cpu[0]->cpu_guest_nice += scc->cpu_guest_nice;
1915 /* Read system topology */
1916 if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
1917 read_topology(cpu_nr, st_cpu_topology);
1921 * Read total number of interrupts received among all CPU.
1922 * (this is the first value on the line "intr:" in the /proc/stat file).
1924 if (DISPLAY_IRQ_SUM(actflags)) {
1925 read_stat_irq(st_irq[0], 1);
1929 * Read number of interrupts received by each CPU, for each interrupt,
1930 * and compute the total number of interrupts received by each CPU.
1932 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1933 /* Read this file to display int per CPU or total nr of int per CPU */
1934 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1936 if (DISPLAY_SOFTIRQS(actflags)) {
1937 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1941 /* Display since boot time */
1942 mp_tstamp[1] = mp_tstamp[0];
1943 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1944 memset(st_node[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1945 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1946 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1947 if (DISPLAY_SOFTIRQS(actflags)) {
1948 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1950 write_stats(0, DISP_HDR);
1951 if (DISPLAY_JSON_OUTPUT(flags)) {
1952 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1957 /* Set a handler for SIGALRM */
1958 memset(&alrm_act, 0, sizeof(alrm_act));
1959 alrm_act.sa_handler = alarm_handler;
1960 sigaction(SIGALRM, &alrm_act, NULL);
1963 /* Save the first stats collected. Will be used to compute the average */
1964 mp_tstamp[2] = mp_tstamp[0];
1965 uptime_cs[2] = uptime_cs[0];
1966 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1967 memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
1968 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1969 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1970 if (DISPLAY_SOFTIRQS(actflags)) {
1971 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1972 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1975 /* Set a handler for SIGINT */
1976 memset(&int_act, 0, sizeof(int_act));
1977 int_act.sa_handler = int_handler;
1978 sigaction(SIGINT, &int_act, NULL);
1983 /* SIGINT signal caught during first interval: Exit immediately */
1988 * Resetting the structure not needed since every fields will be set.
1989 * Exceptions are per-CPU structures: Some of them may not be filled
1990 * if corresponding processor is disabled (offline). We set them to zero
1991 * to be able to distinguish between offline and tickless CPUs.
1993 memset(st_cpu[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1996 get_localtime(&(mp_tstamp[curr]), 0);
1998 /* Read uptime and CPU stats */
1999 read_uptime(&(uptime_cs[curr]));
2000 read_stat_cpu(st_cpu[curr], cpu_nr + 1);
2002 /* Read system topology */
2003 if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
2004 read_topology(cpu_nr, st_cpu_topology);
2007 /* Read total number of interrupts received among all CPU */
2008 if (DISPLAY_IRQ_SUM(actflags)) {
2009 read_stat_irq(st_irq[curr], 1);
2013 * Read number of interrupts received by each CPU, for each interrupt,
2014 * and compute the total number of interrupts received by each CPU.
2016 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
2017 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
2019 if (DISPLAY_SOFTIRQS(actflags)) {
2020 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
2031 write_stats(curr, dis);
2041 if (sigint_caught) {
2042 /* SIGINT signal caught => Display average stats */
2046 if (DISPLAY_JSON_OUTPUT(flags)) {
2055 /* Write stats average */
2056 if (DISPLAY_JSON_OUTPUT(flags)) {
2057 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
2060 write_stats_avg(curr, dis_hdr);
2065 ***************************************************************************
2066 * Main entry to the program
2067 ***************************************************************************
2069 int main(int argc, char **argv)
2071 int opt = 0, i, actset = FALSE;
2072 struct utsname header;
2078 /* Init National Language Support */
2082 /* Init color strings */
2088 /* What is the highest processor number on this machine? */
2089 cpu_nr = get_cpu_nr(~0, TRUE);
2091 /* Calculate number of interrupts per processor */
2092 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
2094 /* Calculate number of soft interrupts per processor */
2095 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
2099 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
2100 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
2102 salloc_mp_struct(cpu_nr + 1);
2104 /* Get NUMA node placement */
2105 node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
2107 while (++opt < argc) {
2109 if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
2110 /* Get number of decimal places */
2111 dplaces_nr = atoi(argv[opt] + 6);
2112 if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
2117 else if (!strcmp(argv[opt], "-I")) {
2123 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2124 if (!strcmp(t, K_SUM)) {
2125 /* Display total number of interrupts per CPU */
2126 actflags |= M_D_IRQ_SUM;
2128 else if (!strcmp(t, K_CPU)) {
2129 /* Display interrupts per CPU */
2130 actflags |= M_D_IRQ_CPU;
2132 else if (!strcmp(t, K_SCPU)) {
2133 /* Display soft interrupts per CPU */
2134 actflags |= M_D_SOFTIRQS;
2136 else if (!strcmp(t, K_ALL)) {
2137 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2145 else if (!strcmp(argv[opt], "-o")) {
2146 /* Select output format */
2147 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2148 flags |= F_JSON_OUTPUT;
2155 else if (!strcmp(argv[opt], "-N")) {
2160 flags |= F_OPTION_N;
2161 actflags |= M_D_NODE;
2164 if (parse_values(argv[opt], node_bitmap, node_nr + 1, K_LOWERALL)) {
2170 else if (!strcmp(argv[opt], "-P")) {
2171 /* '-P ALL' can be used on UP machines */
2175 flags |= F_OPTION_P;
2178 if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
2183 else if (!strncmp(argv[opt], "-", 1)) {
2184 for (i = 1; *(argv[opt] + i); i++) {
2186 switch (*(argv[opt] + i)) {
2189 flags |= F_OPTION_A;
2190 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2192 actflags |= M_D_NODE;
2198 /* Display CPU stats based on NUMA node placement */
2200 actflags |= M_D_NODE;
2206 /* Display logical topology */
2207 flags |= F_TOPOLOGY;
2212 actflags |= M_D_CPU;
2216 /* Print version number */
2226 else if (interval < 0) {
2228 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2231 interval = atol(argv[opt]);
2238 else if (count <= 0) {
2239 /* Get count value */
2240 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2244 count = atol(argv[opt]);
2255 /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
2257 (USE_OPTION_P(flags) && !(actflags & ~M_D_NODE))) {
2258 actflags |= M_D_CPU;
2261 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
2265 if (USE_OPTION_A(flags)) {
2267 * Set -P ALL -N ALL only if individual CPU and/or nodes
2268 * have not been selected.
2270 if ((node_nr >= 0) && !USE_OPTION_N(flags)) {
2271 memset(node_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
2272 flags += F_OPTION_N;
2274 if (!USE_OPTION_P(flags)) {
2275 memset(cpu_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
2276 flags += F_OPTION_P;
2280 if (!USE_OPTION_P(flags)) {
2281 /* Option -P not used: Set bit 0 (global stats among all proc) */
2284 if (!USE_OPTION_N(flags)) {
2285 /* Option -N not used: Set bit 0 (global stats among all nodes) */
2292 /* Get window size */
2293 rows = get_win_height();
2296 /* Interval not set => display stats since boot time */
2300 if (DISPLAY_JSON_OUTPUT(flags)) {
2301 /* Use a decimal point to make JSON code compliant with RFC7159 */
2302 setlocale(LC_NUMERIC, "C");
2306 get_localtime(&(mp_tstamp[0]), 0);
2308 /* Get system name, release number and hostname */
2310 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
2311 header.nodename, header.machine, get_cpu_nr(~0, FALSE),
2312 DISPLAY_JSON_OUTPUT(flags));
2315 rw_mpstat_loop(dis_hdr, rows);
2317 /* Free structures */