2 * mpstat: per-processor statistics
3 * (C) 2000-2017 by Sebastien GODARD (sysstat <at> orange.fr)
5 ***************************************************************************
6 * This program is free software; you can redistribute it and/or modify it *
7 * under the terms of the GNU General Public License as published by the *
8 * Free Software Foundation; either version 2 of the License, or (at your *
9 * option) any later version. *
11 * This program is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * You should have received a copy of the GNU General Public License along *
17 * with this program; if not, write to the Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *
19 ***************************************************************************
30 #include <sys/utsname.h>
38 #include <locale.h> /* For setlocale() */
41 #define _(string) gettext(string)
43 #define _(string) (string)
46 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
47 char *sccsid(void) { return (SCCSID); }
49 unsigned long long uptime[3] = {0, 0, 0};
50 unsigned long long uptime0[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]: nr of CPU for node 0..
80 * Node number the CPU belongs to, e.g.:
81 * cpu2node[0]: node nr for CPU 0
85 struct tm mp_tstamp[3];
88 unsigned int actflags = 0;
90 unsigned int flags = 0;
92 /* Interval and count parameters */
93 long interval = -1, count = 0;
96 * Nb of processors on the machine.
97 * A value of 2 means there are 2 processors (0 and 1).
102 * Highest NUMA node number found on the machine.
103 * A value of 0 means node 0 (one node).
104 * A value of -1 means no nodes found.
108 /* Nb of interrupts per processor */
110 /* Nb of soft interrupts per processor */
111 int softirqcpu_nr = 0;
113 struct sigaction alrm_act, int_act;
114 int sigint_caught = 0;
117 ***************************************************************************
118 * Print usage and exit
121 * @progname Name of sysstat command
122 ***************************************************************************
124 void usage(char *progname)
126 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
129 fprintf(stderr, _("Options are:\n"
130 "[ -A ] [ -n ] [ -u ] [ -V ] [ -I { SUM | CPU | SCPU | ALL } ]\n"
131 "[ -N { <node_list> | ALL } ] [ -o JSON ] [ -P { <cpu_list> | ON | ALL } ]\n"));
136 ***************************************************************************
137 * SIGALRM signal handler. No need to reset the handler here.
140 * @sig Signal number.
141 ***************************************************************************
143 void alarm_handler(int sig)
149 ***************************************************************************
150 * SIGINT signal handler.
153 * @sig Signal number.
154 **************************************************************************
156 void int_handler(int sig)
162 ***************************************************************************
163 * Allocate stats structures and cpu bitmap. Also do it for NUMA nodes
164 * (although the machine may not be a NUMA one). Assume that the number of
165 * nodes is lower or equal than that of CPU.
168 * @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
169 * because we also have to allocate a structure for CPU 'all'.
170 ***************************************************************************
172 void salloc_mp_struct(int nr_cpus)
176 for (i = 0; i < 3; i++) {
178 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
183 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
185 if ((st_node[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
190 memset(st_node[i], 0, STATS_CPU_SIZE * nr_cpus);
192 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
197 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
199 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
204 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
206 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
211 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
214 if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
218 memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
220 if ((node_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
224 memset(node_bitmap, 0, (nr_cpus >> 3) + 1);
226 if ((cpu_per_node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
231 if ((cpu2node = (int *) malloc(sizeof(int) * nr_cpus)) == NULL) {
238 ***************************************************************************
239 * Free structures and bitmap.
240 ***************************************************************************
242 void sfree_mp_struct(void)
246 for (i = 0; i < 3; i++) {
251 free(st_softirqcpu[i]);
261 ***************************************************************************
262 * Get node placement (which node each CPU belongs to, and total number of
263 * CPU that each node has).
266 * @cpu_nr Number of CPU on this machine.
269 * @cpu_per_node Number of CPU per node.
270 * @cpu2node The node the CPU belongs to.
273 * Highest node number found (e.g., 0 means node 0).
274 * A value of -1 means no nodes have been found.
275 ***************************************************************************
277 int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
282 char line[MAX_PF_NAME];
283 int cpu, node, node_nr = -1;
285 /* Init number of CPU per node */
286 memset(cpu_per_node, 0, sizeof(int) * cpu_nr);
287 /* CPU belongs to no node by default */
288 memset(cpu2node, -1, sizeof(int) * cpu_nr);
290 for (cpu = 0; cpu < cpu_nr; cpu++) {
291 snprintf(line, MAX_PF_NAME, "%s/cpu%d", SYSFS_DEVCPU, cpu);
292 line[MAX_PF_NAME - 1] = '\0';
294 /* Open relevant /sys directory */
295 if ((dir = opendir(line)) == NULL)
298 /* Get current file entry */
299 while ((drd = readdir(dir)) != NULL) {
301 if (!strncmp(drd->d_name, "node", 4) && isdigit(drd->d_name[4])) {
302 node = atoi(drd->d_name + 4);
303 if ((node >= cpu_nr) || (node < 0)) {
304 /* Assume we cannot have more nodes than CPU */
308 cpu_per_node[node]++;
309 cpu2node[cpu] = node;
310 if (node > node_nr) {
313 /* Node placement found for current CPU: Go to next CPU directory */
318 /* Close directory */
326 ***************************************************************************
327 * Compute node statistics: Split CPU statistics among nodes.
330 * @st_cpu Array where current CPU stats have been read.
333 * @st_node Array where CPU stats for each node have been saved.
334 ***************************************************************************
336 void set_node_cpu_stats(struct stats_cpu *st_node, struct stats_cpu *st_cpu)
339 struct stats_cpu *st_cpu_i, *st_node_i;
341 for (cpu = 0; cpu < cpu_nr; cpu++) {
342 /* Don't store stats for node 'all'. They are the same as CPU 'all' */
343 st_cpu_i = st_cpu + cpu + 1;
344 st_node_i = st_node + cpu2node[cpu] + 1;
346 st_node_i->cpu_user += st_cpu_i->cpu_user;
347 st_node_i->cpu_nice += st_cpu_i->cpu_nice;
348 st_node_i->cpu_sys += st_cpu_i->cpu_sys;
349 st_node_i->cpu_idle += st_cpu_i->cpu_idle;
350 st_node_i->cpu_iowait += st_cpu_i->cpu_iowait;
351 st_node_i->cpu_hardirq += st_cpu_i->cpu_hardirq;
352 st_node_i->cpu_softirq += st_cpu_i->cpu_softirq;
353 st_node_i->cpu_steal += st_cpu_i->cpu_steal;
354 st_node_i->cpu_guest += st_cpu_i->cpu_guest;
355 st_node_i->cpu_guest_nice += st_cpu_i->cpu_guest_nice;
360 ***************************************************************************
361 * Display CPU statistics in plain format.
364 * @dis TRUE if a header line must be printed.
365 * @g_itv Interval value in jiffies multiplied by the number of CPU.
366 * @prev Position in array where statistics used as reference are.
367 * Stats used as reference may be the previous ones read, or
368 * the very first ones when calculating the average.
369 * @curr Position in array where current statistics will be saved.
370 * @prev_string String displayed at the beginning of a header line. This is
371 * the timestamp of the previous sample, or "Average" when
372 * displaying average stats.
373 * @curr_string String displayed at the beginning of current sample stats.
374 * This is the timestamp of the current sample, or "Average"
375 * when displaying average stats.
376 ***************************************************************************
378 void write_plain_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,
379 char *prev_string, char *curr_string)
381 struct stats_cpu *scc, *scp;
382 unsigned long long pc_itv;
386 printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq "
387 "%%soft %%steal %%guest %%gnice %%idle\n",
391 /* Check if we want global stats among all proc */
392 if (*cpu_bitmap & 1) {
394 printf("%-11s", curr_string);
395 cprintf_in(IS_STR, " %s", " all", 0);
398 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
399 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
401 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
402 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
404 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
405 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
407 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
408 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
410 ll_sp_value(st_cpu[prev]->cpu_sys,
411 st_cpu[curr]->cpu_sys,
413 ll_sp_value(st_cpu[prev]->cpu_iowait,
414 st_cpu[curr]->cpu_iowait,
416 ll_sp_value(st_cpu[prev]->cpu_hardirq,
417 st_cpu[curr]->cpu_hardirq,
419 ll_sp_value(st_cpu[prev]->cpu_softirq,
420 st_cpu[curr]->cpu_softirq,
422 ll_sp_value(st_cpu[prev]->cpu_steal,
423 st_cpu[curr]->cpu_steal,
425 ll_sp_value(st_cpu[prev]->cpu_guest,
426 st_cpu[curr]->cpu_guest,
428 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
429 st_cpu[curr]->cpu_guest_nice,
431 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
433 ll_sp_value(st_cpu[prev]->cpu_idle,
434 st_cpu[curr]->cpu_idle,
439 for (cpu = 1; cpu <= cpu_nr; cpu++) {
441 scc = st_cpu[curr] + cpu;
442 scp = st_cpu[prev] + cpu;
444 /* Check if we want stats about this proc */
445 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
449 * If the CPU is offline then it is omited from /proc/stat
450 * and the sum of all values is zero.
451 * (Remember that guest/guest_nice times are already included in
454 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
455 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
456 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
458 if (!DISPLAY_ONLINE_CPU(flags)) {
459 printf("%-11s", curr_string);
460 cprintf_in(IS_INT, " %4d", "", cpu - 1);
462 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
468 printf("%-11s", curr_string);
469 cprintf_in(IS_INT, " %4d", "", cpu - 1);
471 /* Recalculate itv for current proc */
472 pc_itv = get_per_cpu_interval(scc, scp);
476 * If the CPU is tickless then there is no change in CPU values
477 * but the sum of values is not zero.
480 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
486 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
488 ll_sp_value(scp->cpu_user - scp->cpu_guest,
489 scc->cpu_user - scc->cpu_guest,
491 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
493 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
494 scc->cpu_nice - scc->cpu_guest_nice,
496 ll_sp_value(scp->cpu_sys,
499 ll_sp_value(scp->cpu_iowait,
502 ll_sp_value(scp->cpu_hardirq,
505 ll_sp_value(scp->cpu_softirq,
508 ll_sp_value(scp->cpu_steal,
511 ll_sp_value(scp->cpu_guest,
514 ll_sp_value(scp->cpu_guest_nice,
517 (scc->cpu_idle < scp->cpu_idle) ?
519 ll_sp_value(scp->cpu_idle,
528 ***************************************************************************
529 * Display CPU statistics in JSON format.
532 * @tab Number of tabs to print.
533 * @g_itv Interval value in jiffies multiplied by the number of CPU.
534 * @prev Position in array where statistics used as reference are.
535 * Stats used as reference may be the previous ones read, or
536 * the very first ones when calculating the average.
537 * @curr Position in array where current statistics will be saved.
538 ***************************************************************************
540 void write_json_cpu_stats(int tab, unsigned long long g_itv, int prev, int curr)
542 struct stats_cpu *scc, *scp;
543 unsigned long long pc_itv;
544 int cpu, next = FALSE;
546 xprintf(tab++, "\"cpu-load\": [");
548 /* Check if we want global stats among all proc */
549 if (*cpu_bitmap & 1) {
552 xprintf0(tab, "{\"cpu\": \"all\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
553 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
554 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
555 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
556 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
558 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
559 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
561 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
562 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
564 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
565 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
567 ll_sp_value(st_cpu[prev]->cpu_sys,
568 st_cpu[curr]->cpu_sys,
570 ll_sp_value(st_cpu[prev]->cpu_iowait,
571 st_cpu[curr]->cpu_iowait,
573 ll_sp_value(st_cpu[prev]->cpu_hardirq,
574 st_cpu[curr]->cpu_hardirq,
576 ll_sp_value(st_cpu[prev]->cpu_softirq,
577 st_cpu[curr]->cpu_softirq,
579 ll_sp_value(st_cpu[prev]->cpu_steal,
580 st_cpu[curr]->cpu_steal,
582 ll_sp_value(st_cpu[prev]->cpu_guest,
583 st_cpu[curr]->cpu_guest,
585 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
586 st_cpu[curr]->cpu_guest_nice,
588 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
590 ll_sp_value(st_cpu[prev]->cpu_idle,
591 st_cpu[curr]->cpu_idle,
595 for (cpu = 1; cpu <= cpu_nr; cpu++) {
597 scc = st_cpu[curr] + cpu;
598 scp = st_cpu[prev] + cpu;
600 /* Check if we want stats about this proc */
601 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
610 * If the CPU is offline then it is omited from /proc/stat
611 * and the sum of all values is zero.
612 * (Remember that guest/guest_nice times are already included in
615 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
616 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
617 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
619 if (!DISPLAY_ONLINE_CPU(flags)) {
620 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
621 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
622 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
623 "\"gnice\": 0.00, \"idle\": 0.00}", cpu - 1);
628 /* Recalculate itv for current proc */
629 pc_itv = get_per_cpu_interval(scc, scp);
633 * If the CPU is tickless then there is no change in CPU values
634 * but the sum of values is not zero.
636 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
637 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
638 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
639 "\"gnice\": 0.00, \"idle\": 100.00}", cpu - 1);
643 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
644 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
645 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", cpu - 1,
646 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
648 ll_sp_value(scp->cpu_user - scp->cpu_guest,
649 scc->cpu_user - scc->cpu_guest,
651 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
653 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
654 scc->cpu_nice - scc->cpu_guest_nice,
656 ll_sp_value(scp->cpu_sys,
659 ll_sp_value(scp->cpu_iowait,
662 ll_sp_value(scp->cpu_hardirq,
665 ll_sp_value(scp->cpu_softirq,
668 ll_sp_value(scp->cpu_steal,
671 ll_sp_value(scp->cpu_guest,
674 ll_sp_value(scp->cpu_guest_nice,
677 (scc->cpu_idle < scp->cpu_idle) ?
679 ll_sp_value(scp->cpu_idle,
685 xprintf0(--tab, "]");
689 ***************************************************************************
690 * Display CPU statistics in plain or JSON format.
693 * @dis TRUE if a header line must be printed.
694 * @g_itv Interval value in jiffies multiplied by the number of CPU.
695 * @prev Position in array where statistics used as reference are.
696 * Stats used as reference may be the previous ones read, or
697 * the very first ones when calculating the average.
698 * @curr Position in array where current statistics will be saved.
699 * @prev_string String displayed at the beginning of a header line. This is
700 * the timestamp of the previous sample, or "Average" when
701 * displaying average stats.
702 * @curr_string String displayed at the beginning of current sample stats.
703 * This is the timestamp of the current sample, or "Average"
704 * when displaying average stats.
705 * @tab Number of tabs to print (JSON format only).
706 * @next TRUE is a previous activity has been displayed (JSON format
708 ***************************************************************************
710 void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,
711 char *prev_string, char *curr_string, int tab, int *next)
713 if (DISPLAY_JSON_OUTPUT(flags)) {
718 write_json_cpu_stats(tab, g_itv, prev, curr);
721 write_plain_cpu_stats(dis, g_itv, prev, curr, prev_string, curr_string);
726 ***************************************************************************
727 * Display CPU statistics for NUMA nodes in plain format.
730 * @dis TRUE if a header line must be printed.
731 * @g_itv Interval value in jiffies multiplied by the number of CPU.
732 * @itv Interval value.
733 * @prev Position in array where statistics used as reference are.
734 * Stats used as reference may be the previous ones read, or
735 * the very first ones when calculating the average.
736 * @curr Position in array where current statistics will be saved.
737 * @prev_string String displayed at the beginning of a header line. This is
738 * the timestamp of the previous sample, or "Average" when
739 * displaying average stats.
740 * @curr_string String displayed at the beginning of current sample stats.
741 * This is the timestamp of the current sample, or "Average"
742 * when displaying average stats.
743 ***************************************************************************
745 void write_plain_node_stats(int dis, unsigned long long g_itv, unsigned long long itv,
746 int prev, int curr, char *prev_string, char *curr_string)
748 struct stats_cpu *snc, *snp;
752 printf("\n%-11s NODE %%usr %%nice %%sys %%iowait %%irq "
753 "%%soft %%steal %%guest %%gnice %%idle\n",
758 * Check if we want global stats among all nodes.
759 * Stats are the same as global CPU stats among all processors.
761 if (*node_bitmap & 1) {
763 printf("%-11s", curr_string);
764 cprintf_in(IS_STR, " %s", " all", 0);
767 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
768 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
770 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
771 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
773 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
774 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
776 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
777 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
779 ll_sp_value(st_cpu[prev]->cpu_sys,
780 st_cpu[curr]->cpu_sys,
782 ll_sp_value(st_cpu[prev]->cpu_iowait,
783 st_cpu[curr]->cpu_iowait,
785 ll_sp_value(st_cpu[prev]->cpu_hardirq,
786 st_cpu[curr]->cpu_hardirq,
788 ll_sp_value(st_cpu[prev]->cpu_softirq,
789 st_cpu[curr]->cpu_softirq,
791 ll_sp_value(st_cpu[prev]->cpu_steal,
792 st_cpu[curr]->cpu_steal,
794 ll_sp_value(st_cpu[prev]->cpu_guest,
795 st_cpu[curr]->cpu_guest,
797 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
798 st_cpu[curr]->cpu_guest_nice,
800 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
802 ll_sp_value(st_cpu[prev]->cpu_idle,
803 st_cpu[curr]->cpu_idle,
808 for (node = 0; node <= node_nr; node++) {
810 snc = st_node[curr] + node + 1;
811 snp = st_node[prev] + node + 1;
813 /* Check if we want stats about this node */
814 if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
817 if (!cpu_per_node[node])
818 /* No CPU in this node */
821 printf("%-11s", curr_string);
822 cprintf_in(IS_INT, " %4d", "", node);
825 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
827 ll_sp_value(snp->cpu_user - snp->cpu_guest,
828 snc->cpu_user - snc->cpu_guest,
829 itv * cpu_per_node[node]),
830 (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
832 ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
833 snc->cpu_nice - snc->cpu_guest_nice,
834 itv * cpu_per_node[node]),
835 ll_sp_value(snp->cpu_sys,
837 itv * cpu_per_node[node]),
838 ll_sp_value(snp->cpu_iowait,
840 itv * cpu_per_node[node]),
841 ll_sp_value(snp->cpu_hardirq,
843 itv * cpu_per_node[node]),
844 ll_sp_value(snp->cpu_softirq,
846 itv * cpu_per_node[node]),
847 ll_sp_value(snp->cpu_steal,
849 itv * cpu_per_node[node]),
850 ll_sp_value(snp->cpu_guest,
852 itv * cpu_per_node[node]),
853 ll_sp_value(snp->cpu_guest_nice,
855 itv * cpu_per_node[node]),
856 (snc->cpu_idle < snp->cpu_idle) ?
858 ll_sp_value(snp->cpu_idle,
860 itv * cpu_per_node[node]));
866 ***************************************************************************
867 * Display CPU statistics for NUMA nodes in JSON format.
870 * @tab Number of tabs to print.
871 * @g_itv Interval value in jiffies multiplied by the number of CPU.
872 * @itv Interval value.
873 * @prev Position in array where statistics used as reference are.
874 * Stats used as reference may be the previous ones read, or
875 * the very first ones when calculating the average.
876 * @curr Position in array where current statistics will be saved.
877 ***************************************************************************
879 void write_json_node_stats(int tab, unsigned long long g_itv, unsigned long long itv,
882 struct stats_cpu *snc, *snp;
883 int node, next = FALSE;
885 xprintf(tab++, "\"node-load\": [");
887 /* Check if we want global stats among all nodes */
888 if (*node_bitmap & 1) {
891 xprintf0(tab, "{\"node\": \"all\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
892 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
893 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
894 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
895 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
897 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
898 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
900 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
901 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
903 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
904 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
906 ll_sp_value(st_cpu[prev]->cpu_sys,
907 st_cpu[curr]->cpu_sys,
909 ll_sp_value(st_cpu[prev]->cpu_iowait,
910 st_cpu[curr]->cpu_iowait,
912 ll_sp_value(st_cpu[prev]->cpu_hardirq,
913 st_cpu[curr]->cpu_hardirq,
915 ll_sp_value(st_cpu[prev]->cpu_softirq,
916 st_cpu[curr]->cpu_softirq,
918 ll_sp_value(st_cpu[prev]->cpu_steal,
919 st_cpu[curr]->cpu_steal,
921 ll_sp_value(st_cpu[prev]->cpu_guest,
922 st_cpu[curr]->cpu_guest,
924 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
925 st_cpu[curr]->cpu_guest_nice,
927 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
929 ll_sp_value(st_cpu[prev]->cpu_idle,
930 st_cpu[curr]->cpu_idle,
934 for (node = 0; node <= node_nr; node++) {
936 snc = st_node[curr] + node + 1;
937 snp = st_node[prev] + node + 1;
939 /* Check if we want stats about this node */
940 if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
943 if (!cpu_per_node[node])
944 /* No CPU in this node */
952 xprintf0(tab, "{\"node\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
953 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
954 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node,
955 (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
957 ll_sp_value(snp->cpu_user - snp->cpu_guest,
958 snc->cpu_user - snc->cpu_guest,
959 itv * cpu_per_node[node]),
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,
964 itv * cpu_per_node[node]),
965 ll_sp_value(snp->cpu_sys,
967 itv * cpu_per_node[node]),
968 ll_sp_value(snp->cpu_iowait,
970 itv * cpu_per_node[node]),
971 ll_sp_value(snp->cpu_hardirq,
973 itv * cpu_per_node[node]),
974 ll_sp_value(snp->cpu_softirq,
976 itv * cpu_per_node[node]),
977 ll_sp_value(snp->cpu_steal,
979 itv * cpu_per_node[node]),
980 ll_sp_value(snp->cpu_guest,
982 itv * cpu_per_node[node]),
983 ll_sp_value(snp->cpu_guest_nice,
985 itv * cpu_per_node[node]),
986 (snc->cpu_idle < snp->cpu_idle) ?
988 ll_sp_value(snp->cpu_idle,
990 itv * cpu_per_node[node]));
993 xprintf0(--tab, "]");
997 ***************************************************************************
998 * Display nodes statistics in plain or JSON format.
1001 * @dis TRUE if a header line must be printed.
1002 * @g_itv Interval value in jiffies multiplied by the number of CPU.
1003 * @itv Interval value.
1004 * @prev Position in array where statistics used as reference are.
1005 * Stats used as reference may be the previous ones read, or
1006 * the very first ones when calculating the average.
1007 * @curr Position in array where current statistics will be saved.
1008 * @prev_string String displayed at the beginning of a header line. This is
1009 * the timestamp of the previous sample, or "Average" when
1010 * displaying average stats.
1011 * @curr_string String displayed at the beginning of current sample stats.
1012 * This is the timestamp of the current sample, or "Average"
1013 * when displaying average stats.
1014 * @tab Number of tabs to print (JSON format only).
1015 * @next TRUE is a previous activity has been displayed (JSON format
1017 ***************************************************************************
1019 void write_node_stats(int dis, unsigned long long g_itv, unsigned long long itv,
1020 int prev, int curr, char *prev_string, char *curr_string,
1023 if (DISPLAY_JSON_OUTPUT(flags)) {
1028 write_json_node_stats(tab, g_itv, itv, prev, curr);
1031 write_plain_node_stats(dis, g_itv, itv, prev, curr, prev_string, curr_string);
1036 ***************************************************************************
1037 * Display total number of interrupts per CPU in plain format.
1040 * @dis TRUE if a header line must be printed.
1041 * @itv Interval value.
1042 * @prev Position in array where statistics used as reference are.
1043 * Stats used as reference may be the previous ones read, or
1044 * the very first ones when calculating the average.
1045 * @curr Position in array where current statistics will be saved.
1046 * @prev_string String displayed at the beginning of a header line. This is
1047 * the timestamp of the previous sample, or "Average" when
1048 * displaying average stats.
1049 * @curr_string String displayed at the beginning of current sample stats.
1050 * This is the timestamp of the current sample, or "Average"
1051 * when displaying average stats.
1052 ***************************************************************************
1054 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1055 char *prev_string, char *curr_string)
1057 struct stats_cpu *scc, *scp;
1058 struct stats_irq *sic, *sip;
1059 unsigned long long pc_itv;
1063 printf("\n%-11s CPU intr/s\n", prev_string);
1066 if (*cpu_bitmap & 1) {
1067 printf("%-11s", curr_string);
1068 cprintf_in(IS_STR, " %s", " all", 0);
1069 /* Print total number of interrupts among all cpu */
1070 cprintf_f(-1, 1, 9, 2,
1071 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1075 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1077 sic = st_irq[curr] + cpu;
1078 sip = st_irq[prev] + cpu;
1080 scc = st_cpu[curr] + cpu;
1081 scp = st_cpu[prev] + cpu;
1083 /* Check if we want stats about this CPU */
1084 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1087 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1088 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1089 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1091 /* This is an offline CPU */
1093 if (!DISPLAY_ONLINE_CPU(flags)) {
1095 * Display offline CPU if requested by the user.
1096 * Value displayed is 0.00.
1098 printf("%-11s", curr_string);
1099 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1100 cprintf_f(-1, 1, 9, 2, 0.0);
1106 printf("%-11s", curr_string);
1107 cprintf_in(IS_INT, " %4d", "", cpu - 1);
1109 /* Recalculate itv for current proc */
1110 pc_itv = get_per_cpu_interval(scc, scp);
1113 /* This is a tickless CPU: Value displayed is 0.00 */
1114 cprintf_f(-1, 1, 9, 2, 0.0);
1118 /* Display total number of interrupts for current CPU */
1119 cprintf_f(-1, 1, 9, 2,
1120 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1127 ***************************************************************************
1128 * Display total number of interrupts per CPU in JSON format.
1131 * @tab Number of tabs to print.
1132 * @itv Interval value.
1133 * @prev Position in array where statistics used as reference are.
1134 * Stats used as reference may be the previous ones read, or
1135 * the very first ones when calculating the average.
1136 * @curr Position in array where current statistics will be saved.
1137 ***************************************************************************
1139 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr)
1141 struct stats_cpu *scc, *scp;
1142 struct stats_irq *sic, *sip;
1143 unsigned long long pc_itv;
1144 int cpu, next = FALSE;
1146 xprintf(tab++, "\"sum-interrupts\": [");
1148 if (*cpu_bitmap & 1) {
1151 /* Print total number of interrupts among all cpu */
1152 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
1153 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
1156 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1158 sic = st_irq[curr] + cpu;
1159 sip = st_irq[prev] + cpu;
1161 scc = st_cpu[curr] + cpu;
1162 scp = st_cpu[prev] + cpu;
1164 /* Check if we want stats about this CPU */
1165 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
1173 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1174 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1175 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1177 /* This is an offline CPU */
1179 if (!DISPLAY_ONLINE_CPU(flags)) {
1181 * Display offline CPU if requested by the user.
1182 * Value displayed is 0.00.
1184 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1190 /* Recalculate itv for current proc */
1191 pc_itv = get_per_cpu_interval(scc, scp);
1194 /* This is a tickless CPU: Value displayed is 0.00 */
1195 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
1199 /* Display total number of interrupts for current CPU */
1200 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
1202 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
1206 xprintf0(--tab, "]");
1210 ***************************************************************************
1211 * Display total number of interrupts per CPU in plain or JSON format.
1214 * @dis TRUE if a header line must be printed.
1215 * @itv Interval value.
1216 * @prev Position in array where statistics used as reference are.
1217 * Stats used as reference may be the previous ones read, or
1218 * the very first ones when calculating the average.
1219 * @curr Position in array where current statistics will be saved.
1220 * @prev_string String displayed at the beginning of a header line. This is
1221 * the timestamp of the previous sample, or "Average" when
1222 * displaying average stats.
1223 * @curr_string String displayed at the beginning of current sample stats.
1224 * This is the timestamp of the current sample, or "Average"
1225 * when displaying average stats.
1226 * @tab Number of tabs to print (JSON format only).
1227 * @next TRUE is a previous activity has been displayed (JSON format
1229 ***************************************************************************
1231 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
1232 char *prev_string, char *curr_string, int tab, int *next)
1234 if (DISPLAY_JSON_OUTPUT(flags)) {
1239 write_json_isumcpu_stats(tab, itv, prev, curr);
1242 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
1247 ***************************************************************************
1248 * Display interrupts statistics for each CPU in plain format.
1251 * @st_ic Array for per-CPU statistics.
1252 * @ic_nr Number of interrupts (hard or soft) per CPU.
1253 * @dis TRUE if a header line must be printed.
1254 * @itv Interval value.
1255 * @prev Position in array where statistics used as reference are.
1256 * Stats used as reference may be the previous ones read, or
1257 * the very first ones when calculating the average.
1258 * @curr Position in array where current statistics will be saved.
1259 * @prev_string String displayed at the beginning of a header line. This is
1260 * the timestamp of the previous sample, or "Average" when
1261 * displaying average stats.
1262 * @curr_string String displayed at the beginning of current sample stats.
1263 * This is the timestamp of the current sample, or "Average"
1264 * when displaying average stats.
1265 ***************************************************************************
1267 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1268 unsigned long long itv, int prev, int curr,
1269 char *prev_string, char *curr_string)
1271 struct stats_cpu *scc;
1272 int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
1273 struct stats_irqcpu *p, *q, *p0, *q0;
1276 * Check if number of interrupts has changed.
1277 * If this is the case, the header line will be printed again.
1278 * NB: A zero interval value indicates that we are
1279 * displaying statistics since system startup.
1281 if (!dis && interval) {
1282 for (j = 0; j < ic_nr; j++) {
1283 p0 = st_ic[curr] + j;
1284 q0 = st_ic[prev] + j;
1285 if (strcmp(p0->irq_name, q0->irq_name))
1287 * These are two different interrupts: The header must be displayed
1288 * (maybe an interrupt has disappeared, or a new one has just been registered).
1289 * Note that we compare even empty strings for the case where
1290 * a disappearing interrupt would be the last one in the list.
1296 if (dis || (j < ic_nr)) {
1298 printf("\n%-11s CPU", prev_string);
1299 for (j = 0; j < ic_nr; j++) {
1300 p0 = st_ic[curr] + j;
1301 if (p0->irq_name[0] == '\0')
1302 /* End of the list of interrupts */
1304 printf(" %8s/s", p0->irq_name);
1309 /* Calculate column widths */
1310 for (j = 0; j < ic_nr; j++) {
1311 p0 = st_ic[curr] + j;
1313 * Width is IRQ name + 2 for the trailing "/s".
1314 * Width is calculated even for "undefined" interrupts (with
1315 * an empty irq_name string) to quiet code analysis tools.
1317 colwidth[j] = strlen(p0->irq_name) + 2;
1319 * Normal space for printing a number is 11 chars
1320 * (space + 10 digits including the period).
1322 if (colwidth[j] < 10) {
1327 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1329 scc = st_cpu[curr] + cpu;
1332 * Check if we want stats about this CPU.
1333 * CPU must have been explicitly selected using option -P,
1334 * else we display every CPU.
1336 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
1339 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1340 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1341 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1343 /* Offline CPU found */
1345 if (DISPLAY_ONLINE_CPU(flags))
1349 printf("%-11s", curr_string);
1350 cprintf_in(IS_INT, " %3d", "", cpu - 1);
1352 for (j = 0; j < ic_nr; j++) {
1353 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1355 * An empty string for irq_name means it is a remaining interrupt
1356 * which is no longer used, for example because the
1357 * number of interrupts has decreased in /proc/interrupts.
1359 if (p0->irq_name[0] == '\0')
1360 /* End of the list of interrupts */
1362 q0 = st_ic[prev] + j;
1366 * If we want stats for the time since system startup,
1367 * we have p0->irq_name != q0->irq_name, since q0 structure
1368 * is completely set to zero.
1370 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1371 /* Check if interrupt exists elsewhere in list */
1372 for (offset = 0; offset < ic_nr; offset++) {
1373 q0 = st_ic[prev] + offset;
1374 if (!strcmp(p0->irq_name, q0->irq_name))
1375 /* Interrupt found at another position */
1380 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1382 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1383 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1384 cprintf_f(-1, 1, colwidth[j], 2,
1385 S_VALUE(q->interrupt, p->interrupt, itv));
1389 * Instead of printing "N/A", assume that previous value
1390 * for this new interrupt was zero.
1392 cprintf_f(-1, 1, colwidth[j], 2,
1393 S_VALUE(0, p->interrupt, itv));
1401 ***************************************************************************
1402 * Display interrupts statistics for each CPU in JSON format.
1405 * @tab Number of tabs to print.
1406 * @st_ic Array for per-CPU statistics.
1407 * @ic_nr Number of interrupts (hard or soft) per CPU.
1408 * @itv Interval value.
1409 * @prev Position in array where statistics used as reference are.
1410 * Stats used as reference may be the previous ones read, or
1411 * the very first ones when calculating the average.
1412 * @curr Position in array where current statistics will be saved.
1413 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1414 ***************************************************************************
1416 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
1417 unsigned long long itv, int prev, int curr, int type)
1419 struct stats_cpu *scc;
1420 int j = ic_nr, offset, cpu;
1421 struct stats_irqcpu *p, *q, *p0, *q0;
1422 int nextcpu = FALSE, nextirq;
1424 if (type == M_D_IRQ_CPU) {
1425 xprintf(tab++, "\"individual-interrupts\": [");
1428 xprintf(tab++, "\"soft-interrupts\": [");
1431 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1433 scc = st_cpu[curr] + cpu;
1436 * Check if we want stats about this CPU.
1437 * CPU must have been explicitly selected using option -P,
1438 * else we display every CPU.
1440 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
1443 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1444 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1445 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1447 /* Offline CPU found */
1449 if (DISPLAY_ONLINE_CPU(flags))
1458 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1460 for (j = 0; j < ic_nr; j++) {
1462 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1464 * An empty string for irq_name means it is a remaining interrupt
1465 * which is no longer used, for example because the
1466 * number of interrupts has decreased in /proc/interrupts.
1468 if (p0->irq_name[0] == '\0')
1469 /* End of the list of interrupts */
1471 q0 = st_ic[prev] + j;
1480 * If we want stats for the time since system startup,
1481 * we have p0->irq_name != q0->irq_name, since q0 structure
1482 * is completely set to zero.
1484 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1485 /* Check if interrupt exists elsewhere in list */
1486 for (offset = 0; offset < ic_nr; offset++) {
1487 q0 = st_ic[prev] + offset;
1488 if (!strcmp(p0->irq_name, q0->irq_name))
1489 /* Interrupt found at another position */
1494 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1496 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1497 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1498 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1500 S_VALUE(q->interrupt, p->interrupt, itv));
1504 * Instead of printing "N/A", assume that previous value
1505 * for this new interrupt was zero.
1507 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1509 S_VALUE(0, p->interrupt, itv));
1513 xprintf0(--tab, "] }");
1516 xprintf0(--tab, "]");
1520 ***************************************************************************
1521 * Display interrupts statistics for each CPU in plain or JSON format.
1524 * @st_ic Array for per-CPU statistics.
1525 * @ic_nr Number of interrupts (hard or soft) per CPU.
1526 * @dis TRUE if a header line must be printed.
1527 * @itv Interval value.
1528 * @prev Position in array where statistics used as reference are.
1529 * Stats used as reference may be the previous ones read, or
1530 * the very first ones when calculating the average.
1531 * @curr Position in array where current statistics will be saved.
1532 * @prev_string String displayed at the beginning of a header line. This is
1533 * the timestamp of the previous sample, or "Average" when
1534 * displaying average stats.
1535 * @curr_string String displayed at the beginning of current sample stats.
1536 * This is the timestamp of the current sample, or "Average"
1537 * when displaying average stats.
1538 * @tab Number of tabs to print (JSON format only).
1539 * @next TRUE is a previous activity has been displayed (JSON format
1541 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1542 ***************************************************************************
1544 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1545 unsigned long long itv, int prev, int curr,
1546 char *prev_string, char *curr_string, int tab,
1547 int *next, int type)
1549 if (DISPLAY_JSON_OUTPUT(flags)) {
1554 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type);
1557 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1558 prev_string, curr_string);
1563 ***************************************************************************
1564 * Core function used to display statistics.
1567 * @prev Position in array where statistics used as reference are.
1568 * Stats used as reference may be the previous ones read, or
1569 * the very first ones when calculating the average.
1570 * @curr Position in array where statistics for current sample are.
1571 * @dis TRUE if a header line must be printed.
1572 * @prev_string String displayed at the beginning of a header line. This is
1573 * the timestamp of the previous sample, or "Average" when
1574 * displaying average stats.
1575 * @curr_string String displayed at the beginning of current sample stats.
1576 * This is the timestamp of the current sample, or "Average"
1577 * when displaying average stats.
1578 ***************************************************************************
1580 void write_stats_core(int prev, int curr, int dis,
1581 char *prev_string, char *curr_string)
1583 struct stats_cpu *scc, *scp;
1584 unsigned long long itv, g_itv;
1585 int cpu, tab = 4, next = FALSE;
1588 TEST_STDOUT(STDOUT_FILENO);
1590 if (DISPLAY_JSON_OUTPUT(flags)) {
1591 xprintf(tab++, "{");
1592 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1595 /* Compute time interval */
1596 g_itv = get_interval(uptime[prev], uptime[curr]);
1598 /* Reduce interval value to one processor */
1600 itv = get_interval(uptime0[prev], uptime0[curr]);
1606 /* Print CPU stats */
1607 if (DISPLAY_CPU(actflags)) {
1608 write_cpu_stats(dis, g_itv, prev, curr, prev_string, curr_string,
1612 /* Print node CPU stats */
1613 if (DISPLAY_NODE(actflags)) {
1614 write_node_stats(dis, g_itv, itv, prev, curr, prev_string, curr_string,
1618 /* Print total number of interrupts per processor */
1619 if (DISPLAY_IRQ_SUM(actflags)) {
1620 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1624 /* Display each interrupt value for each CPU */
1625 if (DISPLAY_IRQ_CPU(actflags)) {
1626 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1627 prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
1629 if (DISPLAY_SOFTIRQS(actflags)) {
1630 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1631 prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
1634 if (DISPLAY_JSON_OUTPUT(flags)) {
1636 xprintf0(--tab, "}");
1639 /* Fix CPU counter values for every offline CPU */
1640 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1642 scc = st_cpu[curr] + cpu;
1643 scp = st_cpu[prev] + cpu;
1645 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1646 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1647 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1649 * Offline CPU found.
1650 * Set current struct fields (which have been set to zero)
1651 * to values from previous iteration. Hence their values won't
1652 * jump from zero when the CPU comes back online.
1660 ***************************************************************************
1661 * Print statistics average.
1664 * @curr Position in array where statistics for current sample are.
1665 * @dis TRUE if a header line must be printed.
1666 ***************************************************************************
1668 void write_stats_avg(int curr, int dis)
1672 strncpy(string, _("Average:"), 16);
1674 write_stats_core(2, curr, dis, string, string);
1678 ***************************************************************************
1682 * @curr Position in array where statistics for current sample are.
1683 * @dis TRUE if a header line must be printed.
1684 ***************************************************************************
1686 void write_stats(int curr, int dis)
1688 char cur_time[2][TIMESTAMP_LEN];
1690 /* Get previous timestamp */
1691 if (is_iso_time_fmt()) {
1692 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1695 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1698 /* Get current timestamp */
1699 if (is_iso_time_fmt()) {
1700 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &mp_tstamp[curr]);
1703 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1706 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1710 ***************************************************************************
1711 * Read stats from /proc/interrupts or /proc/softirqs.
1714 * @file /proc file to read (interrupts or softirqs).
1715 * @ic_nr Number of interrupts (hard or soft) per CPU.
1716 * @curr Position in array where current statistics will be saved.
1719 * @st_ic Array for per-CPU interrupts statistics.
1720 ***************************************************************************
1722 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1725 struct stats_irq *st_irq_i;
1726 struct stats_irqcpu *p;
1727 char *line = NULL, *li;
1728 unsigned long irq = 0;
1730 int cpu_index[cpu_nr], index = 0, len;
1733 /* Reset total number of interrupts received by each CPU */
1734 for (cpu = 0; cpu < cpu_nr; cpu++) {
1735 st_irq_i = st_irq[curr] + cpu + 1;
1736 st_irq_i->irq_nr = 0;
1739 if ((fp = fopen(file, "r")) != NULL) {
1741 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1744 * Parse header line to see which CPUs are online
1746 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1748 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1749 cpu = strtol(cp + 3, &next, 10);
1750 cpu_index[index++] = cpu;
1753 /* Header line found */
1757 /* Parse each line of interrupts statistics data */
1758 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1761 /* Skip over "<irq>:" */
1762 if ((cp = strchr(line, ':')) == NULL)
1763 /* Chr ':' not found */
1767 p = st_ic[curr] + irq;
1769 /* Remove possible heading spaces in interrupt's name... */
1774 len = strcspn(li, ":");
1775 if (len >= MAX_IRQ_LEN) {
1776 len = MAX_IRQ_LEN - 1;
1778 /* ...then save its name */
1779 strncpy(p->irq_name, li, len);
1780 p->irq_name[len] = '\0';
1782 /* For each interrupt: Get number received by each CPU */
1783 for (cpu = 0; cpu < index; cpu++) {
1784 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1785 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1787 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1788 * This is the same as st_irqcpu->irq_name.
1789 * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1790 * and total number of interrupts received by current CPU (in stats_irq structure).
1792 p->interrupt = strtoul(cp, &next, 10);
1793 st_irq_i->irq_nr += p->interrupt;
1804 while (irq < ic_nr) {
1805 /* Nb of interrupts per processor has changed */
1806 p = st_ic[curr] + irq;
1807 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
1813 ***************************************************************************
1814 * Main loop: Read stats from the relevant sources, and display them.
1817 * @dis_hdr Set to TRUE if the header line must always be printed.
1818 * @rows Number of rows of screen.
1819 ***************************************************************************
1821 void rw_mpstat_loop(int dis_hdr, int rows)
1823 struct stats_cpu *scc;
1825 int curr = 1, dis = 1;
1826 unsigned long lines = rows;
1828 /* Dont buffer data if redirected to a pipe */
1829 setbuf(stdout, NULL);
1831 /* Read uptime and CPU stats */
1834 * Init uptime0. So if /proc/uptime cannot fill it,
1835 * this will be done by /proc/stat.
1838 read_uptime(&(uptime0[0]));
1840 read_stat_cpu(st_cpu[0], cpu_nr + 1, &(uptime[0]), &(uptime0[0]));
1841 if (DISPLAY_NODE(actflags)) {
1842 set_node_cpu_stats(st_node[0], st_cpu[0]);
1846 * Read total number of interrupts received among all CPU.
1847 * (this is the first value on the line "intr:" in the /proc/stat file).
1849 if (DISPLAY_IRQ_SUM(actflags)) {
1850 read_stat_irq(st_irq[0], 1);
1854 * Read number of interrupts received by each CPU, for each interrupt,
1855 * and compute the total number of interrupts received by each CPU.
1857 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1858 /* Read this file to display int per CPU or total nr of int per CPU */
1859 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1861 if (DISPLAY_SOFTIRQS(actflags)) {
1862 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1866 /* Display since boot time */
1867 mp_tstamp[1] = mp_tstamp[0];
1868 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1869 memset(st_node[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1870 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1871 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1872 if (DISPLAY_SOFTIRQS(actflags)) {
1873 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1875 write_stats(0, DISP_HDR);
1876 if (DISPLAY_JSON_OUTPUT(flags)) {
1877 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1882 /* Set a handler for SIGALRM */
1883 memset(&alrm_act, 0, sizeof(alrm_act));
1884 alrm_act.sa_handler = alarm_handler;
1885 sigaction(SIGALRM, &alrm_act, NULL);
1888 /* Save the first stats collected. Will be used to compute the average */
1889 mp_tstamp[2] = mp_tstamp[0];
1890 uptime[2] = uptime[0];
1891 uptime0[2] = uptime0[0];
1892 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1893 memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
1894 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1895 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1896 if (DISPLAY_SOFTIRQS(actflags)) {
1897 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1898 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1901 if (!DISPLAY_JSON_OUTPUT(flags)) {
1902 /* Set a handler for SIGINT */
1903 memset(&int_act, 0, sizeof(int_act));
1904 int_act.sa_handler = int_handler;
1905 sigaction(SIGINT, &int_act, NULL);
1911 /* SIGINT signal caught during first interval: Exit immediately */
1916 * Resetting the structure not needed since every fields will be set.
1917 * Exceptions are per-CPU structures: Some of them may not be filled
1918 * if corresponding processor is disabled (offline). We set them to zero
1919 * to be able to distinguish between offline and tickless CPUs.
1921 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1922 scc = st_cpu[curr] + cpu;
1923 memset(scc, 0, STATS_CPU_SIZE);
1924 scc = st_node[curr] + cpu;
1925 memset(scc, 0, STATS_CPU_SIZE);
1929 get_localtime(&(mp_tstamp[curr]), 0);
1931 /* Read uptime and CPU stats */
1934 read_uptime(&(uptime0[curr]));
1936 read_stat_cpu(st_cpu[curr], cpu_nr + 1, &(uptime[curr]), &(uptime0[curr]));
1937 if (DISPLAY_NODE(actflags)) {
1938 set_node_cpu_stats(st_node[curr], st_cpu[curr]);
1941 /* Read total number of interrupts received among all CPU */
1942 if (DISPLAY_IRQ_SUM(actflags)) {
1943 read_stat_irq(st_irq[curr], 1);
1947 * Read number of interrupts received by each CPU, for each interrupt,
1948 * and compute the total number of interrupts received by each CPU.
1950 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1951 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
1953 if (DISPLAY_SOFTIRQS(actflags)) {
1954 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
1965 write_stats(curr, dis);
1973 if (DISPLAY_JSON_OUTPUT(flags)) {
1978 if (sigint_caught) {
1979 /* SIGINT signal caught => Display average stats */
1981 printf("\n"); /* Skip "^C" displayed on screen */
1990 /* Write stats average */
1991 if (DISPLAY_JSON_OUTPUT(flags)) {
1992 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1995 write_stats_avg(curr, dis_hdr);
2000 ***************************************************************************
2001 * Main entry to the program
2002 ***************************************************************************
2004 int main(int argc, char **argv)
2006 int opt = 0, i, actset = FALSE;
2007 struct utsname header;
2013 /* Init National Language Support */
2017 /* Init color strings */
2023 /* What is the highest processor number on this machine? */
2024 cpu_nr = get_cpu_nr(~0, TRUE);
2026 /* Calculate number of interrupts per processor */
2027 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
2029 /* Calculate number of soft interrupts per processor */
2030 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
2034 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
2035 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
2037 salloc_mp_struct(cpu_nr + 1);
2039 /* Get NUMA node placement */
2040 node_nr = get_node_placement(cpu_nr, cpu_per_node, cpu2node);
2042 while (++opt < argc) {
2044 if (!strcmp(argv[opt], "-I")) {
2048 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
2049 if (!strcmp(t, K_SUM)) {
2050 /* Display total number of interrupts per CPU */
2051 actflags |= M_D_IRQ_SUM;
2053 else if (!strcmp(t, K_CPU)) {
2054 /* Display interrupts per CPU */
2055 actflags |= M_D_IRQ_CPU;
2057 else if (!strcmp(t, K_SCPU)) {
2058 /* Display soft interrupts per CPU */
2059 actflags |= M_D_SOFTIRQS;
2061 else if (!strcmp(t, K_ALL)) {
2062 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2074 else if (!strcmp(argv[opt], "-o")) {
2075 /* Select output format */
2076 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
2077 flags |= F_JSON_OUTPUT;
2084 else if (!strcmp(argv[opt], "-N")) {
2087 flags |= F_N_OPTION;
2088 actflags |= M_D_NODE;
2091 if (parse_values(argv[opt], node_bitmap, node_nr + 1, K_LOWERALL)) {
2101 else if (!strcmp(argv[opt], "-P")) {
2102 /* '-P ALL' can be used on UP machines */
2104 flags |= F_P_OPTION;
2107 if (!strcmp(argv[opt], K_ON)) {
2108 /* Display stats for all online CPU */
2110 memset(cpu_bitmap, ~0, BITMAP_SIZE(cpu_nr));
2112 else if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
2121 else if (!strncmp(argv[opt], "-", 1)) {
2122 for (i = 1; *(argv[opt] + i); i++) {
2124 switch (*(argv[opt] + i)) {
2127 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
2129 actflags |= M_D_NODE;
2130 flags |= F_N_OPTION;
2131 memset(node_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
2134 /* Select all processors */
2135 flags |= F_P_OPTION;
2136 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
2140 /* Display CPU stats based on NUMA node placement */
2142 actflags |= M_D_NODE;
2149 actflags |= M_D_CPU;
2153 /* Print version number */
2163 else if (interval < 0) {
2165 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
2168 interval = atol(argv[opt]);
2175 else if (count <= 0) {
2176 /* Get count value */
2177 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
2181 count = atol(argv[opt]);
2192 /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
2194 (USE_P_OPTION(flags) && !(actflags & ~M_D_NODE))) {
2195 actflags |= M_D_CPU;
2198 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
2202 if (!USE_P_OPTION(flags)) {
2203 /* Option -P not used: Set bit 0 (global stats among all proc) */
2206 if (!USE_N_OPTION(flags)) {
2207 /* Option -N not used: Set bit 0 (global stats among all nodes) */
2214 /* Get window size */
2215 rows = get_win_height();
2218 /* Interval not set => display stats since boot time */
2222 if (DISPLAY_JSON_OUTPUT(flags)) {
2223 /* Use a decimal point to make JSON code compliant with RFC7159 */
2224 setlocale(LC_NUMERIC, "C");
2228 get_localtime(&(mp_tstamp[0]), 0);
2230 /* Get system name, release number and hostname */
2232 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
2233 header.nodename, header.machine, get_cpu_nr(~0, FALSE),
2234 DISPLAY_JSON_OUTPUT(flags));
2237 rw_mpstat_loop(dis_hdr, rows);
2239 /* Free structures */