2 * mpstat: per-processor statistics
3 * (C) 2000-2018 by Sebastien GODARD (sysstat <at> orange.fr)
5 ***************************************************************************
6 * This program is free software; you can redistribute it and/or modify it *
7 * under the terms of the GNU General Public License as published by the *
8 * Free Software Foundation; either version 2 of the License, or (at your *
9 * option) any later version. *
11 * This program is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * You should have received a copy of the GNU General Public License along *
17 * with this program; if not, write to the Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *
19 ***************************************************************************
30 #include <sys/utsname.h>
38 #include <locale.h> /* For setlocale() */
41 #define _(string) gettext(string)
43 #define _(string) (string)
47 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
48 char *sccsid(void) { return (SCCSID); }
51 unsigned long long tot_jiffies[3] = {0, 0, 0};
52 unsigned long long uptime_cs[3] = {0, 0, 0};
54 /* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
55 unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */
56 unsigned char *node_bitmap; /* Bit 0: Global; Bit 1: 1st NUMA node; etc. */
58 /* Structures used to save CPU and NUMA nodes CPU stats */
59 struct stats_cpu *st_cpu[3];
60 struct stats_cpu *st_node[3];
63 * Structure used to save total number of interrupts received
64 * among all CPU and for each CPU.
66 struct stats_irq *st_irq[3];
69 * Structures used to save, for each interrupt, the number
70 * received by each CPU.
72 struct stats_irqcpu *st_irqcpu[3];
73 struct stats_irqcpu *st_softirqcpu[3];
76 * Number of CPU per node, e.g.:
77 * cpu_per_node[0]: nr of CPU for node 0..
82 * Node number the CPU belongs to, e.g.:
83 * cpu2node[0]: node nr for CPU 0
87 struct tm mp_tstamp[3];
90 unsigned int actflags = 0;
92 unsigned int flags = 0;
94 /* Interval and count parameters */
95 long interval = -1, count = 0;
98 * Nb of processors on the machine.
99 * A value of 2 means there are 2 processors (0 and 1).
104 * Highest NUMA node number found on the machine.
105 * A value of 0 means node 0 (one node).
106 * A value of -1 means no nodes found.
110 /* Nb of interrupts per processor */
112 /* Nb of soft interrupts per processor */
113 int softirqcpu_nr = 0;
115 struct sigaction alrm_act, int_act;
116 int sigint_caught = 0;
119 ***************************************************************************
120 * Print usage and exit
123 * @progname Name of sysstat command
124 ***************************************************************************
126 void usage(char *progname)
128 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
131 fprintf(stderr, _("Options are:\n"
132 "[ -A ] [ -n ] [ -u ] [ -V ] [ -I { SUM | CPU | SCPU | ALL } ]\n"
133 "[ -N { <node_list> | ALL } ] [ -o JSON ] [ -P { <cpu_list> | ON | ALL } ]\n"));
138 ***************************************************************************
139 * SIGALRM signal handler. No need to reset the handler here.
142 * @sig Signal number.
143 ***************************************************************************
145 void alarm_handler(int sig)
151 ***************************************************************************
152 * SIGINT signal handler.
155 * @sig Signal number.
156 **************************************************************************
158 void int_handler(int sig)
164 ***************************************************************************
165 * Allocate stats structures and cpu bitmap. Also do it for NUMA nodes
166 * (although the machine may not be a NUMA one). Assume that the number of
167 * nodes is lower or equal than that of CPU.
170 * @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
171 * because we also have to allocate a structure for CPU 'all'.
172 ***************************************************************************
174 void salloc_mp_struct(int nr_cpus)
178 for (i = 0; i < 3; i++) {
180 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
185 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
187 if ((st_node[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
192 memset(st_node[i], 0, STATS_CPU_SIZE * nr_cpus);
194 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
199 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
201 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
206 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
208 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
213 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
216 if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
220 memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
222 if ((node_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
226 memset(node_bitmap, 0, (nr_cpus >> 3) + 1);
228 if ((cpu_per_node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
233 if ((cpu2node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
240 ***************************************************************************
241 * Free structures and bitmap.
242 ***************************************************************************
244 void sfree_mp_struct(void)
248 for (i = 0; i < 3; i++) {
253 free(st_softirqcpu[i]);
263 ***************************************************************************
264 * Get node placement (which node each CPU belongs to, and total number of
265 * CPU that each node has).
268 * @cpu_nr Number of CPU on this machine.
271 * @cpu_per_node Number of CPU per node.
272 * @cpu2node The node the CPU belongs to.
275 * Highest node number found (e.g., 0 means node 0).
276 * A value of -1 means no nodes have been found.
277 ***************************************************************************
279 int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
284 char line[MAX_PF_NAME];
285 int cpu, node, node_nr = -1;
287 /* Init number of CPU per node */
288 memset(cpu_per_node, 0, sizeof(int) * cpu_nr);
289 /* CPU belongs to no node by default */
290 memset(cpu2node, -1, sizeof(int) * cpu_nr);
292 for (cpu = 0; cpu < cpu_nr; cpu++) {
293 snprintf(line, MAX_PF_NAME, "%s/cpu%d", SYSFS_DEVCPU, cpu);
294 line[MAX_PF_NAME - 1] = '\0';
296 /* Open relevant /sys directory */
297 if ((dir = opendir(line)) == NULL)
300 /* Get current file entry */
301 while ((drd = readdir(dir)) != NULL) {
303 if (!strncmp(drd->d_name, "node", 4) && isdigit(drd->d_name[4])) {
304 node = atoi(drd->d_name + 4);
305 if ((node >= cpu_nr) || (node < 0)) {
306 /* Assume we cannot have more nodes than CPU */
310 cpu_per_node[node]++;
311 cpu2node[cpu] = node;
312 if (node > node_nr) {
315 /* Node placement found for current CPU: Go to next CPU directory */
320 /* Close directory */
328 ***************************************************************************
329 * Compute node statistics: Split CPU statistics among nodes.
332 * @st_cpu Array where current CPU stats have been read.
335 * @st_node Array where CPU stats for each node have been saved.
336 ***************************************************************************
338 void set_node_cpu_stats(struct stats_cpu *st_node, struct stats_cpu *st_cpu)
341 struct stats_cpu *st_cpu_i, *st_node_i;
343 for (cpu = 0; cpu < cpu_nr; cpu++) {
344 /* Don't store stats for node 'all'. They are the same as CPU 'all' */
345 st_cpu_i = st_cpu + cpu + 1;
346 st_node_i = st_node + cpu2node[cpu] + 1;
348 st_node_i->cpu_user += st_cpu_i->cpu_user;
349 st_node_i->cpu_nice += st_cpu_i->cpu_nice;
350 st_node_i->cpu_sys += st_cpu_i->cpu_sys;
351 st_node_i->cpu_idle += st_cpu_i->cpu_idle;
352 st_node_i->cpu_iowait += st_cpu_i->cpu_iowait;
353 st_node_i->cpu_hardirq += st_cpu_i->cpu_hardirq;
354 st_node_i->cpu_softirq += st_cpu_i->cpu_softirq;
355 st_node_i->cpu_steal += st_cpu_i->cpu_steal;
356 st_node_i->cpu_guest += st_cpu_i->cpu_guest;
357 st_node_i->cpu_guest_nice += st_cpu_i->cpu_guest_nice;
362 ***************************************************************************
363 * Compute global CPU statistics as the sum of individual CPU ones, and
364 * calculate interval for global CPU.
365 * Also identify offline CPU.
368 * @prev Index in array where stats used as reference are.
369 * @curr Index in array for current sample statistics.
370 * @offline_cpu_bitmap
371 * CPU bitmap for offline CPU.
374 * @offline_cpu_bitmap
375 * CPU bitmap with offline CPU.
378 * Interval for global CPU.
379 ***************************************************************************
381 unsigned long long get_global_cpu_mpstats(int prev, int curr,
382 unsigned char offline_cpu_bitmap[])
385 unsigned long long tot_jiffies_c, tot_jiffies_p;
386 unsigned long long deltot_jiffies = 0;
387 struct stats_cpu *scc, *scp;
388 struct stats_cpu *scc_all = st_cpu[curr];
389 struct stats_cpu *scp_all = st_cpu[prev];
392 * For UP machines we keep the values read from global CPU line in /proc/stat.
393 * Also look for offline CPU: They won't be displayed, and some of their values may
394 * have to be modified.
397 memset(scc_all, 0, sizeof(struct stats_cpu));
398 memset(scp_all, 0, sizeof(struct stats_cpu));
401 for (i = 1; i <= cpu_nr; i++) {
403 scc = st_cpu[curr] + i;
404 scp = st_cpu[prev] + i;
407 * Compute the total number of jiffies spent by current processor.
408 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
409 * already include them.
411 tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
412 scc->cpu_sys + scc->cpu_idle +
413 scc->cpu_iowait + scc->cpu_hardirq +
414 scc->cpu_steal + scc->cpu_softirq;
415 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
416 scp->cpu_sys + scp->cpu_idle +
417 scp->cpu_iowait + scp->cpu_hardirq +
418 scp->cpu_steal + scp->cpu_softirq;
421 * If the CPU is offline then it is omited from /proc/stat:
422 * All the fields couldn't have been read and the sum of them is zero.
424 if (tot_jiffies_c == 0) {
426 * CPU is currently offline.
427 * Set current struct fields (which have been set to zero)
428 * to values from previous iteration. Hence their values won't
429 * jump from zero when the CPU comes back online.
430 * Note that this workaround no longer fully applies with recent kernels,
431 * as I have noticed that when a CPU comes back online, some fields
432 * restart from their previous value (e.g. user, nice, system)
433 * whereas others restart from zero (idle, iowait)! To deal with this,
434 * the get_per_cpu_interval() function will set these previous values
435 * to zero if necessary.
440 * Mark CPU as offline to not display it
441 * (and thus it will not be confused with a tickless CPU).
443 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
446 if ((tot_jiffies_p == 0) && (interval != 0)) {
448 * CPU has just come back online.
449 * Unfortunately, no reference values are available
450 * from a previous iteration, probably because it was
451 * already offline when the first sample has been taken.
452 * So don't display that CPU to prevent "jump-from-zero"
453 * output syndrome, and don't take it into account for CPU "all".
454 * NB: Test for interval != 0 to make sure we don't stats since boot time.
456 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
461 * Get interval for current CPU and add it to global CPU.
462 * Note: Previous idle and iowait values (saved in scp) may be modified here.
464 deltot_jiffies += get_per_cpu_interval(scc, scp);
466 scc_all->cpu_user += scc->cpu_user;
467 scp_all->cpu_user += scp->cpu_user;
469 scc_all->cpu_nice += scc->cpu_nice;
470 scp_all->cpu_nice += scp->cpu_nice;
472 scc_all->cpu_sys += scc->cpu_sys;
473 scp_all->cpu_sys += scp->cpu_sys;
475 scc_all->cpu_idle += scc->cpu_idle;
476 scp_all->cpu_idle += scp->cpu_idle;
478 scc_all->cpu_iowait += scc->cpu_iowait;
479 scp_all->cpu_iowait += scp->cpu_iowait;
481 scc_all->cpu_hardirq += scc->cpu_hardirq;
482 scp_all->cpu_hardirq += scp->cpu_hardirq;
484 scc_all->cpu_steal += scc->cpu_steal;
485 scp_all->cpu_steal += scp->cpu_steal;
487 scc_all->cpu_softirq += scc->cpu_softirq;
488 scp_all->cpu_softirq += scp->cpu_softirq;
490 scc_all->cpu_guest += scc->cpu_guest;
491 scp_all->cpu_guest += scp->cpu_guest;
493 scc_all->cpu_guest_nice += scc->cpu_guest_nice;
494 scp_all->cpu_guest_nice += scp->cpu_guest_nice;
497 return deltot_jiffies;
501 ***************************************************************************
502 * Display CPU statistics in plain format.
505 * @dis TRUE if a header line must be printed.
506 * @prev Position in array where statistics used as reference are.
507 * Stats used as reference may be the previous ones read, or
508 * the very first ones when calculating the average.
509 * @curr Position in array where current statistics will be saved.
510 * @prev_string String displayed at the beginning of a header line. This is
511 * the timestamp of the previous sample, or "Average" when
512 * displaying average stats.
513 * @curr_string String displayed at the beginning of current sample stats.
514 * This is the timestamp of the current sample, or "Average"
515 * when displaying average stats.
516 ***************************************************************************
518 void write_plain_cpu_stats(int dis, int prev, int curr,
519 char *prev_string, char *curr_string)
522 struct stats_cpu *scc, *scp;
523 unsigned long long deltot_jiffies = 1;
524 unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
527 printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq "
528 "%%soft %%steal %%guest %%gnice %%idle\n",
533 * Compute CPU "all" as sum of all individual CPU (on SMP machines)
534 * and look for offline CPU.
537 deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
541 * Now display CPU statistics (including CPU "all"),
542 * except for offline CPU or CPU that the user doesn't want to see.
544 for (i = 0; i <= cpu_nr; i++) {
546 /* Check if we want stats about this proc */
547 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
548 offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
551 scc = st_cpu[curr] + i;
552 scp = st_cpu[prev] + i;
554 printf("%-11s", curr_string);
557 /* This is CPU "all" */
558 cprintf_in(IS_STR, " %s", " all", 0);
562 * This is a UP machine. In this case
563 * interval has still not been calculated.
565 deltot_jiffies = get_per_cpu_interval(scc, scp);
569 cprintf_in(IS_INT, " %4d", "", i - 1);
571 /* Recalculate itv for current proc */
572 deltot_jiffies = get_per_cpu_interval(scc, scp);
574 if (!deltot_jiffies) {
576 * If the CPU is tickless then there is no change in CPU values
577 * but the sum of values is not zero.
579 cprintf_pc(NO_UNIT, 10, 7, 2,
580 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
587 cprintf_pc(NO_UNIT, 10, 7, 2,
588 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
590 ll_sp_value(scp->cpu_user - scp->cpu_guest,
591 scc->cpu_user - scc->cpu_guest, deltot_jiffies),
592 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
594 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
595 scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
596 ll_sp_value(scp->cpu_sys,
597 scc->cpu_sys, deltot_jiffies),
598 ll_sp_value(scp->cpu_iowait,
599 scc->cpu_iowait, deltot_jiffies),
600 ll_sp_value(scp->cpu_hardirq,
601 scc->cpu_hardirq, deltot_jiffies),
602 ll_sp_value(scp->cpu_softirq,
603 scc->cpu_softirq, deltot_jiffies),
604 ll_sp_value(scp->cpu_steal,
605 scc->cpu_steal, deltot_jiffies),
606 ll_sp_value(scp->cpu_guest,
607 scc->cpu_guest, deltot_jiffies),
608 ll_sp_value(scp->cpu_guest_nice,
609 scc->cpu_guest_nice, deltot_jiffies),
610 (scc->cpu_idle < scp->cpu_idle) ?
612 ll_sp_value(scp->cpu_idle,
613 scc->cpu_idle, deltot_jiffies));
619 ***************************************************************************
620 * Display CPU statistics in JSON format.
623 * @tab Number of tabs to print.
624 * @prev Position in array where statistics used as reference are.
625 * Stats used as reference may be the previous ones read, or
626 * the very first ones when calculating the average.
627 * @curr Position in array where current statistics will be saved.
628 ***************************************************************************
630 void write_json_cpu_stats(int tab, int prev, int curr)
633 struct stats_cpu *scc, *scp;
634 unsigned long long deltot_jiffies = 1;
635 unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
637 xprintf(tab++, "\"cpu-load\": [");
640 * Compute CPU "all" as sum of all individual CPU (on SMP machines)
641 * and look for offline CPU.
644 deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
648 * Now display CPU statistics (including CPU "all"),
649 * except for offline CPU or CPU that the user doesn't want to see.
651 for (i = 0; i <= cpu_nr; i++) {
653 /* Check if we want stats about this proc */
654 if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
655 offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
658 scc = st_cpu[curr] + i;
659 scp = st_cpu[prev] + i;
670 * This is a UP machine. In this case
671 * interval has still not been calculated.
673 deltot_jiffies = get_per_cpu_interval(scc, scp);
677 /* Recalculate itv for current proc */
678 deltot_jiffies = get_per_cpu_interval(scc, scp);
680 if (!deltot_jiffies) {
682 * If the CPU is tickless then there is no change in CPU values
683 * but the sum of values is not zero.
685 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
686 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
687 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
688 "\"gnice\": 0.00, \"idle\": 100.00}", i - 1);
695 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
696 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
697 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", i - 1,
698 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
700 ll_sp_value(scp->cpu_user - scp->cpu_guest,
701 scc->cpu_user - scc->cpu_guest, deltot_jiffies),
702 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
704 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
705 scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
706 ll_sp_value(scp->cpu_sys,
707 scc->cpu_sys, deltot_jiffies),
708 ll_sp_value(scp->cpu_iowait,
709 scc->cpu_iowait, deltot_jiffies),
710 ll_sp_value(scp->cpu_hardirq,
711 scc->cpu_hardirq, deltot_jiffies),
712 ll_sp_value(scp->cpu_softirq,
713 scc->cpu_softirq, deltot_jiffies),
714 ll_sp_value(scp->cpu_steal,
715 scc->cpu_steal, deltot_jiffies),
716 ll_sp_value(scp->cpu_guest,
717 scc->cpu_guest, deltot_jiffies),
718 ll_sp_value(scp->cpu_guest_nice,
719 scc->cpu_guest_nice, deltot_jiffies),
720 (scc->cpu_idle < scp->cpu_idle) ?
722 ll_sp_value(scp->cpu_idle,
723 scc->cpu_idle, deltot_jiffies));
727 xprintf0(--tab, "]");
731 ***************************************************************************
732 * Display CPU statistics in plain or JSON format.
735 * @dis TRUE if a header line must be printed.
736 * @prev Position in array where statistics used as reference are.
737 * Stats used as reference may be the previous ones read, or
738 * the very first ones when calculating the average.
739 * @curr Position in array where current statistics will be saved.
740 * @prev_string String displayed at the beginning of a header line. This is
741 * the timestamp of the previous sample, or "Average" when
742 * displaying average stats.
743 * @curr_string String displayed at the beginning of current sample stats.
744 * This is the timestamp of the current sample, or "Average"
745 * when displaying average stats.
746 * @tab Number of tabs to print (JSON format only).
747 * @next TRUE is a previous activity has been displayed (JSON format
749 ***************************************************************************
751 void write_cpu_stats(int dis, int prev, int curr, char *prev_string,
752 char *curr_string, int tab, int *next)
754 if (DISPLAY_JSON_OUTPUT(flags)) {
759 write_json_cpu_stats(tab, prev, curr);
762 write_plain_cpu_stats(dis, prev, curr, prev_string, curr_string);
767 ***************************************************************************
768 * Display CPU statistics for NUMA nodes in plain format.
771 * @dis TRUE if a header line must be printed.
773 * Number of jiffies spent on the interval by all processors.
774 * @itv Interval value in 1/100th of a second.
775 * @prev Position in array where statistics used as reference are.
776 * Stats used as reference may be the previous ones read, or
777 * the very first ones when calculating the average.
778 * @curr Position in array where current statistics will be saved.
779 * @prev_string String displayed at the beginning of a header line. This is
780 * the timestamp of the previous sample, or "Average" when
781 * displaying average stats.
782 * @curr_string String displayed at the beginning of current sample stats.
783 * This is the timestamp of the current sample, or "Average"
784 * when displaying average stats.
785 ***************************************************************************
787 void write_plain_node_stats(int dis, unsigned long long deltot_jiffies, unsigned long long itv,
788 int prev, int curr, char *prev_string, char *curr_string)
790 struct stats_cpu *snc, *snp;
794 printf("\n%-11s NODE %%usr %%nice %%sys %%iowait %%irq "
795 "%%soft %%steal %%guest %%gnice %%idle\n",
800 * Check if we want global stats among all nodes.
801 * Stats are the same as global CPU stats among all processors.
803 if (*node_bitmap & 1) {
805 printf("%-11s", curr_string);
806 cprintf_in(IS_STR, " %s", " all", 0);
808 cprintf_pc(NO_UNIT, 10, 7, 2,
809 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
810 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
812 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
813 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
815 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
816 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
818 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
819 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
821 ll_sp_value(st_cpu[prev]->cpu_sys,
822 st_cpu[curr]->cpu_sys,
824 ll_sp_value(st_cpu[prev]->cpu_iowait,
825 st_cpu[curr]->cpu_iowait,
827 ll_sp_value(st_cpu[prev]->cpu_hardirq,
828 st_cpu[curr]->cpu_hardirq,
830 ll_sp_value(st_cpu[prev]->cpu_softirq,
831 st_cpu[curr]->cpu_softirq,
833 ll_sp_value(st_cpu[prev]->cpu_steal,
834 st_cpu[curr]->cpu_steal,
836 ll_sp_value(st_cpu[prev]->cpu_guest,
837 st_cpu[curr]->cpu_guest,
839 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
840 st_cpu[curr]->cpu_guest_nice,
842 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
844 ll_sp_value(st_cpu[prev]->cpu_idle,
845 st_cpu[curr]->cpu_idle,
850 for (node = 0; node <= node_nr; node++) {
852 snc = st_node[curr] + node + 1;
853 snp = st_node[prev] + node + 1;
855 /* Check if we want stats about this node */
856 if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
859 if (!cpu_per_node[node])
860 /* No CPU in this node */
863 printf("%-11s", curr_string);
864 cprintf_in(IS_INT, " %4d", "", node);
866 cprintf_pc(NO_UNIT, 10, 7, 2,
867 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
869 ll_sp_value(snp->cpu_user - snp->cpu_guest,
870 snc->cpu_user - snc->cpu_guest,
871 itv * HZ / 100 * cpu_per_node[node]),
872 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
874 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
875 snc->cpu_nice - snc->cpu_guest_nice,
876 itv * HZ / 100 * cpu_per_node[node]),
877 ll_sp_value(snp->cpu_sys,
879 itv * HZ / 100 * cpu_per_node[node]),
880 ll_sp_value(snp->cpu_iowait,
882 itv * HZ / 100 * cpu_per_node[node]),
883 ll_sp_value(snp->cpu_hardirq,
885 itv * HZ / 100 * cpu_per_node[node]),
886 ll_sp_value(snp->cpu_softirq,
888 itv * HZ / 100 * cpu_per_node[node]),
889 ll_sp_value(snp->cpu_steal,
891 itv * HZ / 100 * cpu_per_node[node]),
892 ll_sp_value(snp->cpu_guest,
894 itv * HZ / 100 * cpu_per_node[node]),
895 ll_sp_value(snp->cpu_guest_nice,
897 itv * HZ / 100 * cpu_per_node[node]),
898 (snc->cpu_idle < snp->cpu_idle) ?
900 ll_sp_value(snp->cpu_idle,
902 itv * HZ / 100 * cpu_per_node[node]));
908 ***************************************************************************
909 * Display CPU statistics for NUMA nodes in JSON format.
912 * @tab Number of tabs to print.
914 * Number of jiffies spent on the interval by all processors.
915 * @itv Interval value.
916 * @prev Position in array where statistics used as reference are.
917 * Stats used as reference may be the previous ones read, or
918 * the very first ones when calculating the average.
919 * @curr Position in array where current statistics will be saved.
920 ***************************************************************************
922 void write_json_node_stats(int tab, unsigned long long deltot_jiffies, unsigned long long itv,
925 struct stats_cpu *snc, *snp;
926 int node, next = FALSE;
928 xprintf(tab++, "\"node-load\": [");
930 /* Check if we want global stats among all nodes */
931 if (*node_bitmap & 1) {
934 xprintf0(tab, "{\"node\": \"all\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
935 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
936 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
937 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
938 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
940 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
941 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
943 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
944 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
946 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
947 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
949 ll_sp_value(st_cpu[prev]->cpu_sys,
950 st_cpu[curr]->cpu_sys,
952 ll_sp_value(st_cpu[prev]->cpu_iowait,
953 st_cpu[curr]->cpu_iowait,
955 ll_sp_value(st_cpu[prev]->cpu_hardirq,
956 st_cpu[curr]->cpu_hardirq,
958 ll_sp_value(st_cpu[prev]->cpu_softirq,
959 st_cpu[curr]->cpu_softirq,
961 ll_sp_value(st_cpu[prev]->cpu_steal,
962 st_cpu[curr]->cpu_steal,
964 ll_sp_value(st_cpu[prev]->cpu_guest,
965 st_cpu[curr]->cpu_guest,
967 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
968 st_cpu[curr]->cpu_guest_nice,
970 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
972 ll_sp_value(st_cpu[prev]->cpu_idle,
973 st_cpu[curr]->cpu_idle,
977 for (node = 0; node <= node_nr; node++) {
979 snc = st_node[curr] + node + 1;
980 snp = st_node[prev] + node + 1;
982 /* Check if we want stats about this node */
983 if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
986 if (!cpu_per_node[node])
987 /* No CPU in this node */
995 xprintf0(tab, "{\"node\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
996 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
997 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node,
998 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
1000 ll_sp_value(snp->cpu_user - snp->cpu_guest,
1001 snc->cpu_user - snc->cpu_guest,
1002 itv * HZ / 100 * cpu_per_node[node]),
1003 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
1005 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
1006 snc->cpu_nice - snc->cpu_guest_nice,
1007 itv * HZ / 100 * cpu_per_node[node]),
1008 ll_sp_value(snp->cpu_sys,
1010 itv * HZ / 100 * cpu_per_node[node]),
1011 ll_sp_value(snp->cpu_iowait,
1013 itv * HZ / 100 * cpu_per_node[node]),
1014 ll_sp_value(snp->cpu_hardirq,
1016 itv * HZ / 100 * cpu_per_node[node]),
1017 ll_sp_value(snp->cpu_softirq,
1019 itv * HZ / 100 * cpu_per_node[node]),
1020 ll_sp_value(snp->cpu_steal,
1022 itv * HZ / 100 * cpu_per_node[node]),
1023 ll_sp_value(snp->cpu_guest,
1025 itv * HZ / 100 * cpu_per_node[node]),
1026 ll_sp_value(snp->cpu_guest_nice,
1027 snc->cpu_guest_nice,
1028 itv * HZ / 100 * cpu_per_node[node]),
1029 (snc->cpu_idle < snp->cpu_idle) ?
1031 ll_sp_value(snp->cpu_idle,
1033 itv * HZ / 100 * cpu_per_node[node]));
1036 xprintf0(--tab, "]");
1040 ***************************************************************************
1041 * Display nodes statistics in plain or JSON format.
1044 * @dis TRUE if a header line must be printed.
1046 * Number of jiffies spent on the interval by all processors.
1047 * @itv Interval value.
1048 * @prev Position in array where statistics used as reference are.
1049 * Stats used as reference may be the previous ones read, or
1050 * the very first ones when calculating the average.
1051 * @curr Position in array where current statistics will be saved.
1052 * @prev_string String displayed at the beginning of a header line. This is
1053 * the timestamp of the previous sample, or "Average" when
1054 * displaying average stats.
1055 * @curr_string String displayed at the beginning of current sample stats.
1056 * This is the timestamp of the current sample, or "Average"
1057 * when displaying average stats.
1058 * @tab Number of tabs to print (JSON format only).
1059 * @next TRUE is a previous activity has been displayed (JSON format
1061 ***************************************************************************
1063 void write_node_stats(int dis, unsigned long long deltot_jiffies, unsigned long long itv,
1064 int prev, int curr, char *prev_string, char *curr_string,
1067 if (DISPLAY_JSON_OUTPUT(flags)) {
1072 write_json_node_stats(tab, deltot_jiffies, itv, prev, curr);
1075 write_plain_node_stats(dis, deltot_jiffies, itv, prev, curr,
1076 prev_string, curr_string);
1081 ***************************************************************************
1082 * Display total number of interrupts per CPU in plain format.
1085 * @dis TRUE if a header line must be printed.
1086 * @itv Interval value.
1087 * @prev Position in array where statistics used as reference are.
1088 * Stats used as reference may be the previous ones read, or
1089 * the very first ones when calculating the average.
1090 * @curr Position in array where current statistics will be saved.
1091 * @prev_string String displayed at the beginning of a header line. This is
1092 * the timestamp of the previous sample, or "Average" when
1093 * displaying average stats.
1094 * @curr_string String displayed at the beginning of current sample stats.
1095 * This is the timestamp of the current sample, or "Average"
1096 * when displaying average stats.
1097 ***************************************************************************
1099 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1100 char *prev_string, char *curr_string)
1102 struct stats_cpu *scc, *scp;
1103 struct stats_irq *sic, *sip;
1104 unsigned long long pc_itv;
1108 printf("\n%-11s CPU intr/s\n", prev_string);
1111 if (*cpu_bitmap & 1) {
1112 printf("%-11s", curr_string);
1113 cprintf_in(IS_STR, " %s", " all", 0);
1114 /* Print total number of interrupts among all cpu */
1115 cprintf_f(NO_UNIT, 1, 9, 2,
1116 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1120 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1122 sic = st_irq[curr] + cpu;
1123 sip = st_irq[prev] + cpu;
1125 scc = st_cpu[curr] + cpu;
1126 scp = st_cpu[prev] + cpu;
1128 /* Check if we want stats about this CPU */
1129 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1132 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1133 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1134 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1136 /* This is an offline CPU */
1138 if (!DISPLAY_ONLINE_CPU(flags)) {
1140 * Display offline CPU if requested by the user.
1141 * Value displayed is 0.00.
1143 printf("%-11s", curr_string);
1144 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1145 cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1151 printf("%-11s", curr_string);
1152 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1154 /* Recalculate itv for current proc */
1155 pc_itv = get_per_cpu_interval(scc, scp);
1158 /* This is a tickless CPU: Value displayed is 0.00 */
1159 cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
1163 /* Display total number of interrupts for current CPU */
1164 cprintf_f(NO_UNIT, 1, 9, 2,
1165 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1172 ***************************************************************************
1173 * Display total number of interrupts per CPU in JSON format.
1176 * @tab Number of tabs to print.
1177 * @itv Interval value.
1178 * @prev Position in array where statistics used as reference are.
1179 * Stats used as reference may be the previous ones read, or
1180 * the very first ones when calculating the average.
1181 * @curr Position in array where current statistics will be saved.
1182 ***************************************************************************
1184 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr)
1186 struct stats_cpu *scc, *scp;
1187 struct stats_irq *sic, *sip;
1188 unsigned long long pc_itv;
1189 int cpu, next = FALSE;
1191 xprintf(tab++, "\"sum-interrupts\": [");
1193 if (*cpu_bitmap & 1) {
1196 /* Print total number of interrupts among all cpu */
1197 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
1198 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1201 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1203 sic = st_irq[curr] + cpu;
1204 sip = st_irq[prev] + cpu;
1206 scc = st_cpu[curr] + cpu;
1207 scp = st_cpu[prev] + cpu;
1209 /* Check if we want stats about this CPU */
1210 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1218 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1219 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1220 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1222 /* This is an offline CPU */
1224 if (!DISPLAY_ONLINE_CPU(flags)) {
1226 * Display offline CPU if requested by the user.
1227 * Value displayed is 0.00.
1229 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1235 /* Recalculate itv for current proc */
1236 pc_itv = get_per_cpu_interval(scc, scp);
1239 /* This is a tickless CPU: Value displayed is 0.00 */
1240 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1244 /* Display total number of interrupts for current CPU */
1245 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
1247 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1251 xprintf0(--tab, "]");
1255 ***************************************************************************
1256 * Display total number of interrupts per CPU in plain or JSON format.
1259 * @dis TRUE if a header line must be printed.
1260 * @itv Interval value.
1261 * @prev Position in array where statistics used as reference are.
1262 * Stats used as reference may be the previous ones read, or
1263 * the very first ones when calculating the average.
1264 * @curr Position in array where current statistics will be saved.
1265 * @prev_string String displayed at the beginning of a header line. This is
1266 * the timestamp of the previous sample, or "Average" when
1267 * displaying average stats.
1268 * @curr_string String displayed at the beginning of current sample stats.
1269 * This is the timestamp of the current sample, or "Average"
1270 * when displaying average stats.
1271 * @tab Number of tabs to print (JSON format only).
1272 * @next TRUE is a previous activity has been displayed (JSON format
1274 ***************************************************************************
1276 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1277 char *prev_string, char *curr_string, int tab, int *next)
1279 if (DISPLAY_JSON_OUTPUT(flags)) {
1284 write_json_isumcpu_stats(tab, itv, prev, curr);
1287 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
1292 ***************************************************************************
1293 * Display interrupts statistics for each CPU in plain format.
1296 * @st_ic Array for per-CPU statistics.
1297 * @ic_nr Number of interrupts (hard or soft) per CPU.
1298 * @dis TRUE if a header line must be printed.
1299 * @itv Interval value.
1300 * @prev Position in array where statistics used as reference are.
1301 * Stats used as reference may be the previous ones read, or
1302 * the very first ones when calculating the average.
1303 * @curr Position in array where current statistics will be saved.
1304 * @prev_string String displayed at the beginning of a header line. This is
1305 * the timestamp of the previous sample, or "Average" when
1306 * displaying average stats.
1307 * @curr_string String displayed at the beginning of current sample stats.
1308 * This is the timestamp of the current sample, or "Average"
1309 * when displaying average stats.
1310 ***************************************************************************
1312 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1313 unsigned long long itv, int prev, int curr,
1314 char *prev_string, char *curr_string)
1316 struct stats_cpu *scc;
1317 int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
1318 struct stats_irqcpu *p, *q, *p0, *q0;
1321 * Check if number of interrupts has changed.
1322 * If this is the case, the header line will be printed again.
1323 * NB: A zero interval value indicates that we are
1324 * displaying statistics since system startup.
1326 if (!dis && interval) {
1327 for (j = 0; j < ic_nr; j++) {
1328 p0 = st_ic[curr] + j;
1329 q0 = st_ic[prev] + j;
1330 if (strcmp(p0->irq_name, q0->irq_name))
1332 * These are two different interrupts: The header must be displayed
1333 * (maybe an interrupt has disappeared, or a new one has just been registered).
1334 * Note that we compare even empty strings for the case where
1335 * a disappearing interrupt would be the last one in the list.
1341 if (dis || (j < ic_nr)) {
1343 printf("\n%-11s CPU", prev_string);
1344 for (j = 0; j < ic_nr; j++) {
1345 p0 = st_ic[curr] + j;
1346 if (p0->irq_name[0] == '\0')
1347 /* End of the list of interrupts */
1349 printf(" %8s/s", p0->irq_name);
1354 /* Calculate column widths */
1355 for (j = 0; j < ic_nr; j++) {
1356 p0 = st_ic[curr] + j;
1358 * Width is IRQ name + 2 for the trailing "/s".
1359 * Width is calculated even for "undefined" interrupts (with
1360 * an empty irq_name string) to quiet code analysis tools.
1362 colwidth[j] = strlen(p0->irq_name) + 2;
1364 * Normal space for printing a number is 11 chars
1365 * (space + 10 digits including the period).
1367 if (colwidth[j] < 10) {
1372 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1374 scc = st_cpu[curr] + cpu;
1377 * Check if we want stats about this CPU.
1378 * CPU must have been explicitly selected using option -P,
1379 * else we display every CPU.
1381 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
1384 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1385 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1386 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1388 /* Offline CPU found */
1390 if (DISPLAY_ONLINE_CPU(flags))
1394 printf("%-11s", curr_string);
1395 cprintf_in(IS_INT, " %3d", "", cpu - 1);
1397 for (j = 0; j < ic_nr; j++) {
1398 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1400 * An empty string for irq_name means it is a remaining interrupt
1401 * which is no longer used, for example because the
1402 * number of interrupts has decreased in /proc/interrupts.
1404 if (p0->irq_name[0] == '\0')
1405 /* End of the list of interrupts */
1407 q0 = st_ic[prev] + j;
1411 * If we want stats for the time since system startup,
1412 * we have p0->irq_name != q0->irq_name, since q0 structure
1413 * is completely set to zero.
1415 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1416 /* Check if interrupt exists elsewhere in list */
1417 for (offset = 0; offset < ic_nr; offset++) {
1418 q0 = st_ic[prev] + offset;
1419 if (!strcmp(p0->irq_name, q0->irq_name))
1420 /* Interrupt found at another position */
1425 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1427 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1428 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1429 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1430 S_VALUE(q->interrupt, p->interrupt, itv));
1434 * Instead of printing "N/A", assume that previous value
1435 * for this new interrupt was zero.
1437 cprintf_f(NO_UNIT, 1, colwidth[j], 2,
1438 S_VALUE(0, p->interrupt, itv));
1446 ***************************************************************************
1447 * Display interrupts statistics for each CPU in JSON format.
1450 * @tab Number of tabs to print.
1451 * @st_ic Array for per-CPU statistics.
1452 * @ic_nr Number of interrupts (hard or soft) per CPU.
1453 * @itv Interval value.
1454 * @prev Position in array where statistics used as reference are.
1455 * Stats used as reference may be the previous ones read, or
1456 * the very first ones when calculating the average.
1457 * @curr Position in array where current statistics will be saved.
1458 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1459 ***************************************************************************
1461 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
1462 unsigned long long itv, int prev, int curr, int type)
1464 struct stats_cpu *scc;
1465 int j = ic_nr, offset, cpu;
1466 struct stats_irqcpu *p, *q, *p0, *q0;
1467 int nextcpu = FALSE, nextirq;
1469 if (type == M_D_IRQ_CPU) {
1470 xprintf(tab++, "\"individual-interrupts\": [");
1473 xprintf(tab++, "\"soft-interrupts\": [");
1476 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1478 scc = st_cpu[curr] + cpu;
1481 * Check if we want stats about this CPU.
1482 * CPU must have been explicitly selected using option -P,
1483 * else we display every CPU.
1485 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
1488 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1489 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1490 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1492 /* Offline CPU found */
1494 if (DISPLAY_ONLINE_CPU(flags))
1503 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1505 for (j = 0; j < ic_nr; j++) {
1507 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1509 * An empty string for irq_name means it is a remaining interrupt
1510 * which is no longer used, for example because the
1511 * number of interrupts has decreased in /proc/interrupts.
1513 if (p0->irq_name[0] == '\0')
1514 /* End of the list of interrupts */
1516 q0 = st_ic[prev] + j;
1525 * If we want stats for the time since system startup,
1526 * we have p0->irq_name != q0->irq_name, since q0 structure
1527 * is completely set to zero.
1529 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1530 /* Check if interrupt exists elsewhere in list */
1531 for (offset = 0; offset < ic_nr; offset++) {
1532 q0 = st_ic[prev] + offset;
1533 if (!strcmp(p0->irq_name, q0->irq_name))
1534 /* Interrupt found at another position */
1539 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1541 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1542 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1543 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1545 S_VALUE(q->interrupt, p->interrupt, itv));
1549 * Instead of printing "N/A", assume that previous value
1550 * for this new interrupt was zero.
1552 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1554 S_VALUE(0, p->interrupt, itv));
1558 xprintf0(--tab, "] }");
1561 xprintf0(--tab, "]");
1565 ***************************************************************************
1566 * Display interrupts statistics for each CPU in plain or JSON format.
1569 * @st_ic Array for per-CPU statistics.
1570 * @ic_nr Number of interrupts (hard or soft) per CPU.
1571 * @dis TRUE if a header line must be printed.
1572 * @itv Interval value.
1573 * @prev Position in array where statistics used as reference are.
1574 * Stats used as reference may be the previous ones read, or
1575 * the very first ones when calculating the average.
1576 * @curr Position in array where current statistics will be saved.
1577 * @prev_string String displayed at the beginning of a header line. This is
1578 * the timestamp of the previous sample, or "Average" when
1579 * displaying average stats.
1580 * @curr_string String displayed at the beginning of current sample stats.
1581 * This is the timestamp of the current sample, or "Average"
1582 * when displaying average stats.
1583 * @tab Number of tabs to print (JSON format only).
1584 * @next TRUE is a previous activity has been displayed (JSON format
1586 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1587 ***************************************************************************
1589 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1590 unsigned long long itv, int prev, int curr,
1591 char *prev_string, char *curr_string, int tab,
1592 int *next, int type)
1594 if (DISPLAY_JSON_OUTPUT(flags)) {
1599 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type);
1602 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1603 prev_string, curr_string);
1608 ***************************************************************************
1609 * Core function used to display statistics.
1612 * @prev Position in array where statistics used as reference are.
1613 * Stats used as reference may be the previous ones read, or
1614 * the very first ones when calculating the average.
1615 * @curr Position in array where statistics for current sample are.
1616 * @dis TRUE if a header line must be printed.
1617 * @prev_string String displayed at the beginning of a header line. This is
1618 * the timestamp of the previous sample, or "Average" when
1619 * displaying average stats.
1620 * @curr_string String displayed at the beginning of current sample stats.
1621 * This is the timestamp of the current sample, or "Average"
1622 * when displaying average stats.
1623 ***************************************************************************
1625 void write_stats_core(int prev, int curr, int dis,
1626 char *prev_string, char *curr_string)
1628 struct stats_cpu *scc, *scp;
1629 unsigned long long itv, deltot_jiffies;
1630 int cpu, tab = 4, next = FALSE;
1633 TEST_STDOUT(STDOUT_FILENO);
1635 if (DISPLAY_JSON_OUTPUT(flags)) {
1636 xprintf(tab++, "{");
1637 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1641 * Compute the total number of jiffies spent by all processors.
1642 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
1643 * already include them.
1645 tot_jiffies[curr] = st_cpu[curr]->cpu_user + st_cpu[curr]->cpu_nice +
1646 st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_idle +
1647 st_cpu[curr]->cpu_iowait + st_cpu[curr]->cpu_hardirq +
1648 st_cpu[curr]->cpu_steal + st_cpu[curr]->cpu_softirq;
1649 /* Total number of jiffies spent on the interval */
1650 deltot_jiffies = get_interval(tot_jiffies[prev], tot_jiffies[curr]);
1652 /* Get time interval */
1653 itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
1655 /* Print CPU stats */
1656 if (DISPLAY_CPU(actflags)) {
1657 write_cpu_stats(dis, prev, curr, prev_string,
1658 curr_string, tab, &next);
1661 /* Print node CPU stats */
1662 if (DISPLAY_NODE(actflags)) {
1663 write_node_stats(dis, deltot_jiffies, itv, prev, curr, prev_string,
1664 curr_string, tab, &next);
1667 /* Print total number of interrupts per processor */
1668 if (DISPLAY_IRQ_SUM(actflags)) {
1669 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1673 /* Display each interrupt value for each CPU */
1674 if (DISPLAY_IRQ_CPU(actflags)) {
1675 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1676 prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
1678 if (DISPLAY_SOFTIRQS(actflags)) {
1679 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1680 prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
1683 if (DISPLAY_JSON_OUTPUT(flags)) {
1685 xprintf0(--tab, "}");
1688 /* Fix CPU counter values for every offline CPU */
1689 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1691 scc = st_cpu[curr] + cpu;
1692 scp = st_cpu[prev] + cpu;
1694 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1695 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1696 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1698 * Offline CPU found.
1699 * Set current struct fields (which have been set to zero)
1700 * to values from previous iteration. Hence their values won't
1701 * jump from zero when the CPU comes back online.
1709 ***************************************************************************
1710 * Print statistics average.
1713 * @curr Position in array where statistics for current sample are.
1714 * @dis TRUE if a header line must be printed.
1715 ***************************************************************************
1717 void write_stats_avg(int curr, int dis)
1721 strncpy(string, _("Average:"), 16);
1723 write_stats_core(2, curr, dis, string, string);
1727 ***************************************************************************
1731 * @curr Position in array where statistics for current sample are.
1732 * @dis TRUE if a header line must be printed.
1733 ***************************************************************************
1735 void write_stats(int curr, int dis)
1737 char cur_time[2][TIMESTAMP_LEN];
1739 /* Get previous timestamp */
1740 if (is_iso_time_fmt()) {
1741 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1744 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1747 /* Get current timestamp */
1748 if (is_iso_time_fmt()) {
1749 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &mp_tstamp[curr]);
1752 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1755 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1759 ***************************************************************************
1760 * Read stats from /proc/interrupts or /proc/softirqs.
1763 * @file /proc file to read (interrupts or softirqs).
1764 * @ic_nr Number of interrupts (hard or soft) per CPU.
1765 * @curr Position in array where current statistics will be saved.
1768 * @st_ic Array for per-CPU interrupts statistics.
1769 ***************************************************************************
1771 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1774 struct stats_irq *st_irq_i;
1775 struct stats_irqcpu *p;
1776 char *line = NULL, *li;
1777 unsigned long irq = 0;
1779 int cpu_index[cpu_nr], index = 0, len;
1782 /* Reset total number of interrupts received by each CPU */
1783 for (cpu = 0; cpu < cpu_nr; cpu++) {
1784 st_irq_i = st_irq[curr] + cpu + 1;
1785 st_irq_i->irq_nr = 0;
1788 if ((fp = fopen(file, "r")) != NULL) {
1790 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1793 * Parse header line to see which CPUs are online
1795 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1797 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1798 cpu = strtol(cp + 3, &next, 10);
1799 cpu_index[index++] = cpu;
1802 /* Header line found */
1806 /* Parse each line of interrupts statistics data */
1807 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1810 /* Skip over "<irq>:" */
1811 if ((cp = strchr(line, ':')) == NULL)
1812 /* Chr ':' not found */
1816 p = st_ic[curr] + irq;
1818 /* Remove possible heading spaces in interrupt's name... */
1823 len = strcspn(li, ":");
1824 if (len >= MAX_IRQ_LEN) {
1825 len = MAX_IRQ_LEN - 1;
1827 /* ...then save its name */
1828 strncpy(p->irq_name, li, len);
1829 p->irq_name[len] = '\0';
1831 /* For each interrupt: Get number received by each CPU */
1832 for (cpu = 0; cpu < index; cpu++) {
1833 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1834 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1836 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1837 * This is the same as st_irqcpu->irq_name.
1838 * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1839 * and total number of interrupts received by current CPU (in stats_irq structure).
1841 p->interrupt = strtoul(cp, &next, 10);
1842 st_irq_i->irq_nr += p->interrupt;
1853 while (irq < ic_nr) {
1854 /* Nb of interrupts per processor has changed */
1855 p = st_ic[curr] + irq;
1856 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
1862 ***************************************************************************
1863 * Main loop: Read stats from the relevant sources, and display them.
1866 * @dis_hdr Set to TRUE if the header line must always be printed.
1867 * @rows Number of rows of screen.
1868 ***************************************************************************
1870 void rw_mpstat_loop(int dis_hdr, int rows)
1872 struct stats_cpu *scc;
1874 int curr = 1, dis = 1;
1875 unsigned long lines = rows;
1877 /* Dont buffer data if redirected to a pipe */
1878 setbuf(stdout, NULL);
1880 /* Read system uptime and CPU stats */
1881 read_uptime(&(uptime_cs[0]));
1882 read_stat_cpu(st_cpu[0], cpu_nr + 1);
1883 tot_jiffies[0] = st_cpu[0]->cpu_user + st_cpu[0]->cpu_nice +
1884 st_cpu[0]->cpu_sys + st_cpu[0]->cpu_idle +
1885 st_cpu[0]->cpu_iowait + st_cpu[0]->cpu_hardirq +
1886 st_cpu[0]->cpu_steal + st_cpu[0]->cpu_softirq;
1887 if (DISPLAY_NODE(actflags)) {
1888 set_node_cpu_stats(st_node[0], st_cpu[0]);
1892 * Read total number of interrupts received among all CPU.
1893 * (this is the first value on the line "intr:" in the /proc/stat file).
1895 if (DISPLAY_IRQ_SUM(actflags)) {
1896 read_stat_irq(st_irq[0], 1);
1900 * Read number of interrupts received by each CPU, for each interrupt,
1901 * and compute the total number of interrupts received by each CPU.
1903 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1904 /* Read this file to display int per CPU or total nr of int per CPU */
1905 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1907 if (DISPLAY_SOFTIRQS(actflags)) {
1908 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1912 /* Display since boot time */
1913 mp_tstamp[1] = mp_tstamp[0];
1914 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1915 memset(st_node[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1916 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1917 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1918 if (DISPLAY_SOFTIRQS(actflags)) {
1919 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1921 write_stats(0, DISP_HDR);
1922 if (DISPLAY_JSON_OUTPUT(flags)) {
1923 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1928 /* Set a handler for SIGALRM */
1929 memset(&alrm_act, 0, sizeof(alrm_act));
1930 alrm_act.sa_handler = alarm_handler;
1931 sigaction(SIGALRM, &alrm_act, NULL);
1934 /* Save the first stats collected. Will be used to compute the average */
1935 mp_tstamp[2] = mp_tstamp[0];
1936 tot_jiffies[2] = tot_jiffies[0];
1937 uptime_cs[2] = uptime_cs[0];
1938 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1939 memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
1940 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1941 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1942 if (DISPLAY_SOFTIRQS(actflags)) {
1943 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1944 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1947 if (!DISPLAY_JSON_OUTPUT(flags)) {
1948 /* Set a handler for SIGINT */
1949 memset(&int_act, 0, sizeof(int_act));
1950 int_act.sa_handler = int_handler;
1951 sigaction(SIGINT, &int_act, NULL);
1957 /* SIGINT signal caught during first interval: Exit immediately */
1962 * Resetting the structure not needed since every fields will be set.
1963 * Exceptions are per-CPU structures: Some of them may not be filled
1964 * if corresponding processor is disabled (offline). We set them to zero
1965 * to be able to distinguish between offline and tickless CPUs.
1967 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1968 scc = st_cpu[curr] + cpu;
1969 memset(scc, 0, STATS_CPU_SIZE);
1970 scc = st_node[curr] + cpu;
1971 memset(scc, 0, STATS_CPU_SIZE);
1975 get_localtime(&(mp_tstamp[curr]), 0);
1977 /* Read uptime and CPU stats */
1978 read_uptime(&(uptime_cs[curr]));
1979 read_stat_cpu(st_cpu[curr], cpu_nr + 1);
1980 if (DISPLAY_NODE(actflags)) {
1981 set_node_cpu_stats(st_node[curr], st_cpu[curr]);
1984 /* Read total number of interrupts received among all CPU */
1985 if (DISPLAY_IRQ_SUM(actflags)) {
1986 read_stat_irq(st_irq[curr], 1);
1990 * Read number of interrupts received by each CPU, for each interrupt,
1991 * and compute the total number of interrupts received by each CPU.
1993 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1994 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
1996 if (DISPLAY_SOFTIRQS(actflags)) {
1997 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
2008 write_stats(curr, dis);
2016 if (DISPLAY_JSON_OUTPUT(flags)) {
2021 if (sigint_caught) {
2022 /* SIGINT signal caught => Display average stats */
2024 printf("\n"); /* Skip "^C" displayed on screen */
2033 /* Write stats average */
2034 if (DISPLAY_JSON_OUTPUT(flags)) {
2035 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
2038 write_stats_avg(curr, dis_hdr);
2043 ***************************************************************************
2044 * Main entry to the program
2045 ***************************************************************************
2047 int main(int argc, char **argv)
2049 int opt = 0, i, actset = FALSE;
2050 struct utsname header;
2056 /* Init National Language Support */
2060 /* Init color strings */
2066 /* What is the highest processor number on this machine? */
2067 cpu_nr = get_cpu_nr(~0, TRUE);
2069 /* Calculate number of interrupts per processor */
2070 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
2072 /* Calculate number of soft interrupts per processor */
2073 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
2077 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
2078 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
2080 salloc_mp_struct(cpu_nr + 1);
2082 /* Get NUMA node placement */
2083 node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
2085 while (++opt < argc) {
2087 if (!strcmp(argv[opt], "-I")) {
2093 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2094 if (!strcmp(t, K_SUM)) {
2095 /* Display total number of interrupts per CPU */
2096 actflags |= M_D_IRQ_SUM;
2098 else if (!strcmp(t, K_CPU)) {
2099 /* Display interrupts per CPU */
2100 actflags |= M_D_IRQ_CPU;
2102 else if (!strcmp(t, K_SCPU)) {
2103 /* Display soft interrupts per CPU */
2104 actflags |= M_D_SOFTIRQS;
2106 else if (!strcmp(t, K_ALL)) {
2107 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2115 else if (!strcmp(argv[opt], "-o")) {
2116 /* Select output format */
2117 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2118 flags |= F_JSON_OUTPUT;
2125 else if (!strcmp(argv[opt], "-N")) {
2130 flags |= F_N_OPTION;
2131 actflags |= M_D_NODE;
2134 if (parse_values(argv[opt], node_bitmap, node_nr + 1, K_LOWERALL)) {
2140 else if (!strcmp(argv[opt], "-P")) {
2141 /* '-P ALL' can be used on UP machines */
2145 flags |= F_P_OPTION;
2148 if (!strcmp(argv[opt], K_ON)) {
2149 /* Display stats for all online CPU */
2151 memset(cpu_bitmap, ~0, BITMAP_SIZE(cpu_nr));
2153 else if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
2158 else if (!strncmp(argv[opt], "-", 1)) {
2159 for (i = 1; *(argv[opt] + i); i++) {
2161 switch (*(argv[opt] + i)) {
2164 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2166 actflags |= M_D_NODE;
2167 flags |= F_N_OPTION;
2168 memset(node_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
2171 /* Select all processors */
2172 flags |= F_P_OPTION;
2173 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
2177 /* Display CPU stats based on NUMA node placement */
2179 actflags |= M_D_NODE;
2186 actflags |= M_D_CPU;
2190 /* Print version number */
2200 else if (interval < 0) {
2202 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2205 interval = atol(argv[opt]);
2212 else if (count <= 0) {
2213 /* Get count value */
2214 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2218 count = atol(argv[opt]);
2229 /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
2231 (USE_P_OPTION(flags) && !(actflags & ~M_D_NODE))) {
2232 actflags |= M_D_CPU;
2235 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
2239 if (!USE_P_OPTION(flags)) {
2240 /* Option -P not used: Set bit 0 (global stats among all proc) */
2243 if (!USE_N_OPTION(flags)) {
2244 /* Option -N not used: Set bit 0 (global stats among all nodes) */
2251 /* Get window size */
2252 rows = get_win_height();
2255 /* Interval not set => display stats since boot time */
2259 if (DISPLAY_JSON_OUTPUT(flags)) {
2260 /* Use a decimal point to make JSON code compliant with RFC7159 */
2261 setlocale(LC_NUMERIC, "C");
2265 get_localtime(&(mp_tstamp[0]), 0);
2267 /* Get system name, release number and hostname */
2269 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
2270 header.nodename, header.machine, get_cpu_nr(~0, FALSE),
2271 DISPLAY_JSON_OUTPUT(flags));
2274 rw_mpstat_loop(dis_hdr, rows);
2276 /* Free structures */