2 * mpstat: per-processor statistics
3 * (C) 2000-2016 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 ***************************************************************************
29 #include <sys/utsname.h>
40 #define _(string) gettext(string)
42 #define _(string) (string)
45 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
46 char *sccsid(void) { return (SCCSID); }
48 unsigned long long uptime[3] = {0, 0, 0};
49 unsigned long long uptime0[3] = {0, 0, 0};
51 /* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
52 unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */
54 /* Structure used to save CPU stats */
55 struct stats_cpu *st_cpu[3];
57 * Structure used to save total number of interrupts received
58 * among all CPU and for each CPU.
60 struct stats_irq *st_irq[3];
62 * Structures used to save, for each interrupt, the number
63 * received by each CPU.
65 struct stats_irqcpu *st_irqcpu[3];
66 struct stats_irqcpu *st_softirqcpu[3];
68 struct tm mp_tstamp[3];
71 unsigned int actflags = 0;
73 unsigned int flags = 0;
75 /* Interval and count parameters */
76 long interval = -1, count = 0;
78 /* Nb of processors on the machine */
80 /* Nb of interrupts per processor */
82 /* Nb of soft interrupts per processor */
83 int softirqcpu_nr = 0;
85 struct sigaction alrm_act, int_act;
86 int sigint_caught = 0;
89 ***************************************************************************
90 * Print usage and exit
93 * @progname Name of sysstat command
94 ***************************************************************************
96 void usage(char *progname)
98 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
101 fprintf(stderr, _("Options are:\n"
102 "[ -A ] [ -u ] [ -V ] [ -I { SUM | CPU | SCPU | ALL } ]\n"
103 "[ -o JSON ] [ -P { <cpu> [,...] | ON | ALL } ]\n"));
108 ***************************************************************************
109 * SIGALRM signal handler. No need to reset the handler here.
112 * @sig Signal number.
113 ***************************************************************************
115 void alarm_handler(int sig)
121 ***************************************************************************
122 * SIGINT signal handler.
125 * @sig Signal number.
126 **************************************************************************
128 void int_handler(int sig)
134 ***************************************************************************
135 * Allocate stats structures and cpu bitmap.
138 * @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
139 * because we also have to allocate a structure for CPU 'all'.
140 ***************************************************************************
142 void salloc_mp_struct(int nr_cpus)
146 for (i = 0; i < 3; i++) {
148 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
153 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
155 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
160 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
162 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
167 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
169 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
174 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
177 if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
181 memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
185 ***************************************************************************
186 * Free structures and bitmap.
187 ***************************************************************************
189 void sfree_mp_struct(void)
193 for (i = 0; i < 3; i++) {
197 free(st_softirqcpu[i]);
204 ***************************************************************************
205 * Display CPU statistics in plain format.
208 * @dis TRUE if a header line must be printed.
209 * @g_itv Interval value in jiffies multiplied by the number of CPU.
210 * @prev Position in array where statistics used as reference are.
211 * Stats used as reference may be the previous ones read, or
212 * the very first ones when calculating the average.
213 * @curr Position in array where current statistics will be saved.
214 * @prev_string String displayed at the beginning of a header line. This is
215 * the timestamp of the previous sample, or "Average" when
216 * displaying average stats.
217 * @curr_string String displayed at the beginning of current sample stats.
218 * This is the timestamp of the current sample, or "Average"
219 * when displaying average stats.
220 ***************************************************************************
222 void write_plain_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,
223 char *prev_string, char *curr_string)
225 struct stats_cpu *scc, *scp;
226 unsigned long long pc_itv;
230 printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq "
231 "%%soft %%steal %%guest %%gnice %%idle\n",
235 /* Check if we want global stats among all proc */
236 if (*cpu_bitmap & 1) {
238 printf("%-11s", curr_string);
239 cprintf_in(IS_STR, " %s", " all", 0);
242 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
243 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
245 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
246 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
248 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
249 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
251 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
252 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
254 ll_sp_value(st_cpu[prev]->cpu_sys,
255 st_cpu[curr]->cpu_sys,
257 ll_sp_value(st_cpu[prev]->cpu_iowait,
258 st_cpu[curr]->cpu_iowait,
260 ll_sp_value(st_cpu[prev]->cpu_hardirq,
261 st_cpu[curr]->cpu_hardirq,
263 ll_sp_value(st_cpu[prev]->cpu_softirq,
264 st_cpu[curr]->cpu_softirq,
266 ll_sp_value(st_cpu[prev]->cpu_steal,
267 st_cpu[curr]->cpu_steal,
269 ll_sp_value(st_cpu[prev]->cpu_guest,
270 st_cpu[curr]->cpu_guest,
272 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
273 st_cpu[curr]->cpu_guest_nice,
275 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
277 ll_sp_value(st_cpu[prev]->cpu_idle,
278 st_cpu[curr]->cpu_idle,
283 for (cpu = 1; cpu <= cpu_nr; cpu++) {
285 scc = st_cpu[curr] + cpu;
286 scp = st_cpu[prev] + cpu;
288 /* Check if we want stats about this proc */
289 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
293 * If the CPU is offline then it is omited from /proc/stat
294 * and the sum of all values is zero.
295 * (Remember that guest/guest_nice times are already included in
298 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
299 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
300 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
302 if (!DISPLAY_ONLINE_CPU(flags)) {
303 printf("%-11s", curr_string);
304 cprintf_in(IS_INT, " %4d", "", cpu - 1);
306 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
312 printf("%-11s", curr_string);
313 cprintf_in(IS_INT, " %4d", "", cpu - 1);
315 /* Recalculate itv for current proc */
316 pc_itv = get_per_cpu_interval(scc, scp);
320 * If the CPU is tickless then there is no change in CPU values
321 * but the sum of values is not zero.
324 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
330 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
332 ll_sp_value(scp->cpu_user - scp->cpu_guest,
333 scc->cpu_user - scc->cpu_guest,
335 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
337 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
338 scc->cpu_nice - scc->cpu_guest_nice,
340 ll_sp_value(scp->cpu_sys,
343 ll_sp_value(scp->cpu_iowait,
346 ll_sp_value(scp->cpu_hardirq,
349 ll_sp_value(scp->cpu_softirq,
352 ll_sp_value(scp->cpu_steal,
355 ll_sp_value(scp->cpu_guest,
358 ll_sp_value(scp->cpu_guest_nice,
361 (scc->cpu_idle < scp->cpu_idle) ?
363 ll_sp_value(scp->cpu_idle,
372 ***************************************************************************
373 * Display CPU statistics in JSON format.
376 * @tab Number of tabs to print.
377 * @g_itv Interval value in jiffies multiplied by the number of CPU.
378 * @prev Position in array where statistics used as reference are.
379 * Stats used as reference may be the previous ones read, or
380 * the very first ones when calculating the average.
381 * @curr Position in array where current statistics will be saved.
382 * @curr_string String displayed at the beginning of current sample stats.
383 * This is the timestamp of the current sample.
384 ***************************************************************************
386 void write_json_cpu_stats(int tab, unsigned long long g_itv, int prev, int curr,
389 struct stats_cpu *scc, *scp;
390 unsigned long long pc_itv;
391 int cpu, next = FALSE;
393 xprintf(tab++, "\"cpu-load\": [");
395 /* Check if we want global stats among all proc */
396 if (*cpu_bitmap & 1) {
399 xprintf0(tab, "{\"cpu\": \"all\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
400 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
401 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
402 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
403 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
405 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
406 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
408 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
409 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
411 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
412 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
414 ll_sp_value(st_cpu[prev]->cpu_sys,
415 st_cpu[curr]->cpu_sys,
417 ll_sp_value(st_cpu[prev]->cpu_iowait,
418 st_cpu[curr]->cpu_iowait,
420 ll_sp_value(st_cpu[prev]->cpu_hardirq,
421 st_cpu[curr]->cpu_hardirq,
423 ll_sp_value(st_cpu[prev]->cpu_softirq,
424 st_cpu[curr]->cpu_softirq,
426 ll_sp_value(st_cpu[prev]->cpu_steal,
427 st_cpu[curr]->cpu_steal,
429 ll_sp_value(st_cpu[prev]->cpu_guest,
430 st_cpu[curr]->cpu_guest,
432 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
433 st_cpu[curr]->cpu_guest_nice,
435 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
437 ll_sp_value(st_cpu[prev]->cpu_idle,
438 st_cpu[curr]->cpu_idle,
442 for (cpu = 1; cpu <= cpu_nr; cpu++) {
444 scc = st_cpu[curr] + cpu;
445 scp = st_cpu[prev] + cpu;
447 /* Check if we want stats about this proc */
448 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
457 * If the CPU is offline then it is omited from /proc/stat
458 * and the sum of all values is zero.
459 * (Remember that guest/guest_nice times are already included in
462 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
463 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
464 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
466 if (!DISPLAY_ONLINE_CPU(flags)) {
467 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
468 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
469 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
470 "\"gnice\": 0.00, \"idle\": 0.00}", cpu - 1);
475 /* Recalculate itv for current proc */
476 pc_itv = get_per_cpu_interval(scc, scp);
480 * If the CPU is tickless then there is no change in CPU values
481 * but the sum of values is not zero.
483 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, "
484 "\"sys\": 0.00, \"iowait\": 0.00, \"irq\": 0.00, "
485 "\"soft\": 0.00, \"steal\": 0.00, \"guest\": 0.00, "
486 "\"gnice\": 0.00, \"idle\": 100.00}", cpu - 1);
490 xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
491 "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
492 "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", cpu - 1,
493 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
495 ll_sp_value(scp->cpu_user - scp->cpu_guest,
496 scc->cpu_user - scc->cpu_guest,
498 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
500 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
501 scc->cpu_nice - scc->cpu_guest_nice,
503 ll_sp_value(scp->cpu_sys,
506 ll_sp_value(scp->cpu_iowait,
509 ll_sp_value(scp->cpu_hardirq,
512 ll_sp_value(scp->cpu_softirq,
515 ll_sp_value(scp->cpu_steal,
518 ll_sp_value(scp->cpu_guest,
521 ll_sp_value(scp->cpu_guest_nice,
524 (scc->cpu_idle < scp->cpu_idle) ?
526 ll_sp_value(scp->cpu_idle,
532 xprintf0(--tab, "]");
536 ***************************************************************************
537 * Display CPU statistics in plain or JSON format.
540 * @dis TRUE if a header line must be printed.
541 * @g_itv Interval value in jiffies multiplied by the number of CPU.
542 * @prev Position in array where statistics used as reference are.
543 * Stats used as reference may be the previous ones read, or
544 * the very first ones when calculating the average.
545 * @curr Position in array where current statistics will be saved.
546 * @prev_string String displayed at the beginning of a header line. This is
547 * the timestamp of the previous sample, or "Average" when
548 * displaying average stats.
549 * @curr_string String displayed at the beginning of current sample stats.
550 * This is the timestamp of the current sample, or "Average"
551 * when displaying average stats.
552 * @tab Number of tabs to print (JSON format only).
553 * @next TRUE is a previous activity has been displayed (JSON format
555 ***************************************************************************
557 void write_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,
558 char *prev_string, char *curr_string, int tab, int *next)
560 if (DISPLAY_JSON_OUTPUT(flags)) {
565 write_json_cpu_stats(tab, g_itv, prev, curr, curr_string);
568 write_plain_cpu_stats(dis, g_itv, prev, curr, prev_string, curr_string);
573 ***************************************************************************
574 * Display total number of interrupts per CPU in plain format.
577 * @dis TRUE if a header line must be printed.
578 * @itv Interval value.
579 * @prev Position in array where statistics used as reference are.
580 * Stats used as reference may be the previous ones read, or
581 * the very first ones when calculating the average.
582 * @curr Position in array where current statistics will be saved.
583 * @prev_string String displayed at the beginning of a header line. This is
584 * the timestamp of the previous sample, or "Average" when
585 * displaying average stats.
586 * @curr_string String displayed at the beginning of current sample stats.
587 * This is the timestamp of the current sample, or "Average"
588 * when displaying average stats.
589 ***************************************************************************
591 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
592 char *prev_string, char *curr_string)
594 struct stats_cpu *scc, *scp;
595 struct stats_irq *sic, *sip;
596 unsigned long long pc_itv;
600 printf("\n%-11s CPU intr/s\n", prev_string);
603 if (*cpu_bitmap & 1) {
604 printf("%-11s", curr_string);
605 cprintf_in(IS_STR, " %s", " all", 0);
606 /* Print total number of interrupts among all cpu */
608 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
612 for (cpu = 1; cpu <= cpu_nr; cpu++) {
614 sic = st_irq[curr] + cpu;
615 sip = st_irq[prev] + cpu;
617 scc = st_cpu[curr] + cpu;
618 scp = st_cpu[prev] + cpu;
620 /* Check if we want stats about this CPU */
621 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
624 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
625 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
626 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
628 /* This is an offline CPU */
630 if (!DISPLAY_ONLINE_CPU(flags)) {
632 * Display offline CPU if requested by the user.
633 * Value displayed is 0.00.
635 printf("%-11s", curr_string);
636 cprintf_in(IS_INT, " %4d", "", cpu - 1);
637 cprintf_f(1, 9, 2, 0.0);
643 printf("%-11s", curr_string);
644 cprintf_in(IS_INT, " %4d", "", cpu - 1);
646 /* Recalculate itv for current proc */
647 pc_itv = get_per_cpu_interval(scc, scp);
650 /* This is a tickless CPU: Value displayed is 0.00 */
651 cprintf_f(1, 9, 2, 0.0);
655 /* Display total number of interrupts for current CPU */
657 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
664 ***************************************************************************
665 * Display total number of interrupts per CPU in JSON format.
668 * @tab Number of tabs to print.
669 * @itv Interval value.
670 * @prev Position in array where statistics used as reference are.
671 * Stats used as reference may be the previous ones read, or
672 * the very first ones when calculating the average.
673 * @curr Position in array where current statistics will be saved.
674 * @curr_string String displayed at the beginning of current sample stats.
675 * This is the timestamp of the current sample.
676 ***************************************************************************
678 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr,
681 struct stats_cpu *scc, *scp;
682 struct stats_irq *sic, *sip;
683 unsigned long long pc_itv;
684 int cpu, next = FALSE;
686 xprintf(tab++, "\"sum-interrupts\": [");
688 if (*cpu_bitmap & 1) {
691 /* Print total number of interrupts among all cpu */
692 xprintf0(tab, "{\"cpu\": \"all\", \"intr\": %.2f}",
693 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
696 for (cpu = 1; cpu <= cpu_nr; cpu++) {
698 sic = st_irq[curr] + cpu;
699 sip = st_irq[prev] + cpu;
701 scc = st_cpu[curr] + cpu;
702 scp = st_cpu[prev] + cpu;
704 /* Check if we want stats about this CPU */
705 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
713 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
714 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
715 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
717 /* This is an offline CPU */
719 if (!DISPLAY_ONLINE_CPU(flags)) {
721 * Display offline CPU if requested by the user.
722 * Value displayed is 0.00.
724 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
730 /* Recalculate itv for current proc */
731 pc_itv = get_per_cpu_interval(scc, scp);
734 /* This is a tickless CPU: Value displayed is 0.00 */
735 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
739 /* Display total number of interrupts for current CPU */
740 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
742 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
746 xprintf0(--tab, "]");
750 ***************************************************************************
751 * Display total number of interrupts per CPU in plain or JSON format.
754 * @dis TRUE if a header line must be printed.
755 * @itv Interval value.
756 * @prev Position in array where statistics used as reference are.
757 * Stats used as reference may be the previous ones read, or
758 * the very first ones when calculating the average.
759 * @curr Position in array where current statistics will be saved.
760 * @prev_string String displayed at the beginning of a header line. This is
761 * the timestamp of the previous sample, or "Average" when
762 * displaying average stats.
763 * @curr_string String displayed at the beginning of current sample stats.
764 * This is the timestamp of the current sample, or "Average"
765 * when displaying average stats.
766 * @tab Number of tabs to print (JSON format only).
767 * @next TRUE is a previous activity has been displayed (JSON format
769 ***************************************************************************
771 void write_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
772 char *prev_string, char *curr_string, int tab, int *next)
774 if (DISPLAY_JSON_OUTPUT(flags)) {
779 write_json_isumcpu_stats(tab, itv, prev, curr, curr_string);
782 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
787 ***************************************************************************
788 * Display interrupts statistics for each CPU in plain format.
791 * @st_ic Array for per-CPU statistics.
792 * @ic_nr Number of interrupts (hard or soft) per CPU.
793 * @dis TRUE if a header line must be printed.
794 * @itv Interval value.
795 * @prev Position in array where statistics used as reference are.
796 * Stats used as reference may be the previous ones read, or
797 * the very first ones when calculating the average.
798 * @curr Position in array where current statistics will be saved.
799 * @prev_string String displayed at the beginning of a header line. This is
800 * the timestamp of the previous sample, or "Average" when
801 * displaying average stats.
802 * @curr_string String displayed at the beginning of current sample stats.
803 * This is the timestamp of the current sample, or "Average"
804 * when displaying average stats.
805 ***************************************************************************
807 void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
808 unsigned long long itv, int prev, int curr,
809 char *prev_string, char *curr_string)
811 struct stats_cpu *scc;
812 int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
813 struct stats_irqcpu *p, *q, *p0, *q0;
816 * Check if number of interrupts has changed.
817 * If this is the case, the header line will be printed again.
818 * NB: A zero interval value indicates that we are
819 * displaying statistics since system startup.
821 if (!dis && interval) {
822 for (j = 0; j < ic_nr; j++) {
823 p0 = st_ic[curr] + j;
824 q0 = st_ic[prev] + j;
825 if (strcmp(p0->irq_name, q0->irq_name))
827 * These are two different interrupts: The header must be displayed
828 * (maybe an interrupt has disappeared, or a new one has just been registered).
829 * Note that we compare even empty strings for the case where
830 * a disappearing interrupt would be the last one in the list.
836 if (dis || (j < ic_nr)) {
838 printf("\n%-11s CPU", prev_string);
839 for (j = 0; j < ic_nr; j++) {
840 p0 = st_ic[curr] + j;
841 if (p0->irq_name[0] == '\0')
842 /* End of the list of interrupts */
844 printf(" %8s/s", p0->irq_name);
849 /* Calculate column widths */
850 for (j = 0; j < ic_nr; j++) {
851 p0 = st_ic[curr] + j;
853 * Width is IRQ name + 2 for the trailing "/s".
854 * Width is calculated even for "undefined" interrupts (with
855 * an empty irq_name string) to quiet code analysis tools.
857 colwidth[j] = strlen(p0->irq_name) + 2;
859 * Normal space for printing a number is 11 chars
860 * (space + 10 digits including the period).
862 if (colwidth[j] < 10) {
867 for (cpu = 1; cpu <= cpu_nr; cpu++) {
869 scc = st_cpu[curr] + cpu;
872 * Check if we want stats about this CPU.
873 * CPU must have been explicitly selected using option -P,
874 * else we display every CPU.
876 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
879 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
880 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
881 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
883 /* Offline CPU found */
885 if (DISPLAY_ONLINE_CPU(flags))
889 printf("%-11s", curr_string);
890 cprintf_in(IS_INT, " %3d", "", cpu - 1);
892 for (j = 0; j < ic_nr; j++) {
893 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
895 * An empty string for irq_name means it is a remaining interrupt
896 * which is no longer used, for example because the
897 * number of interrupts has decreased in /proc/interrupts.
899 if (p0->irq_name[0] == '\0')
900 /* End of the list of interrupts */
902 q0 = st_ic[prev] + j;
906 * If we want stats for the time since system startup,
907 * we have p0->irq_name != q0->irq_name, since q0 structure
908 * is completely set to zero.
910 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
911 /* Check if interrupt exists elsewhere in list */
912 for (offset = 0; offset < ic_nr; offset++) {
913 q0 = st_ic[prev] + offset;
914 if (!strcmp(p0->irq_name, q0->irq_name))
915 /* Interrupt found at another position */
920 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
922 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
923 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
924 cprintf_f(1, colwidth[j], 2,
925 S_VALUE(q->interrupt, p->interrupt, itv));
929 * Instead of printing "N/A", assume that previous value
930 * for this new interrupt was zero.
932 cprintf_f(1, colwidth[j], 2,
933 S_VALUE(0, p->interrupt, itv));
941 ***************************************************************************
942 * Display interrupts statistics for each CPU in JSON format.
945 * @tab Number of tabs to print.
946 * @st_ic Array for per-CPU statistics.
947 * @ic_nr Number of interrupts (hard or soft) per CPU.
948 * @itv Interval value.
949 * @prev Position in array where statistics used as reference are.
950 * Stats used as reference may be the previous ones read, or
951 * the very first ones when calculating the average.
952 * @curr Position in array where current statistics will be saved.
953 * @curr_string String displayed at the beginning of current sample stats.
954 * This is the timestamp of the current sample.
955 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
956 ***************************************************************************
958 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
959 unsigned long long itv, int prev, int curr,
960 char *curr_string, int type)
962 struct stats_cpu *scc;
963 int j = ic_nr, offset, cpu;
964 struct stats_irqcpu *p, *q, *p0, *q0;
965 int nextcpu = FALSE, nextirq;
967 if (type == M_D_IRQ_CPU) {
968 xprintf(tab++, "\"individual-interrupts\": [");
971 xprintf(tab++, "\"soft-interrupts\": [");
974 for (cpu = 1; cpu <= cpu_nr; cpu++) {
976 scc = st_cpu[curr] + cpu;
979 * Check if we want stats about this CPU.
980 * CPU must have been explicitly selected using option -P,
981 * else we display every CPU.
983 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
986 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
987 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
988 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
990 /* Offline CPU found */
992 if (DISPLAY_ONLINE_CPU(flags))
1001 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1003 for (j = 0; j < ic_nr; j++) {
1005 p0 = st_ic[curr] + j; /* irq_name set only for CPU#0 */
1007 * An empty string for irq_name means it is a remaining interrupt
1008 * which is no longer used, for example because the
1009 * number of interrupts has decreased in /proc/interrupts.
1011 if (p0->irq_name[0] == '\0')
1012 /* End of the list of interrupts */
1014 q0 = st_ic[prev] + j;
1023 * If we want stats for the time since system startup,
1024 * we have p0->irq_name != q0->irq_name, since q0 structure
1025 * is completely set to zero.
1027 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
1028 /* Check if interrupt exists elsewhere in list */
1029 for (offset = 0; offset < ic_nr; offset++) {
1030 q0 = st_ic[prev] + offset;
1031 if (!strcmp(p0->irq_name, q0->irq_name))
1032 /* Interrupt found at another position */
1037 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1039 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
1040 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
1041 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1043 S_VALUE(q->interrupt, p->interrupt, itv));
1047 * Instead of printing "N/A", assume that previous value
1048 * for this new interrupt was zero.
1050 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1052 S_VALUE(0, p->interrupt, itv));
1056 xprintf0(--tab, "] }");
1059 xprintf0(--tab, "]");
1063 ***************************************************************************
1064 * Display interrupts statistics for each CPU in plain or JSON format.
1067 * @st_ic Array for per-CPU statistics.
1068 * @ic_nr Number of interrupts (hard or soft) per CPU.
1069 * @dis TRUE if a header line must be printed.
1070 * @itv Interval value.
1071 * @prev Position in array where statistics used as reference are.
1072 * Stats used as reference may be the previous ones read, or
1073 * the very first ones when calculating the average.
1074 * @curr Position in array where current statistics will be saved.
1075 * @prev_string String displayed at the beginning of a header line. This is
1076 * the timestamp of the previous sample, or "Average" when
1077 * displaying average stats.
1078 * @curr_string String displayed at the beginning of current sample stats.
1079 * This is the timestamp of the current sample, or "Average"
1080 * when displaying average stats.
1081 * @tab Number of tabs to print (JSON format only).
1082 * @next TRUE is a previous activity has been displayed (JSON format
1084 * @type Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1085 ***************************************************************************
1087 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
1088 unsigned long long itv, int prev, int curr,
1089 char *prev_string, char *curr_string, int tab,
1090 int *next, int type)
1092 if (DISPLAY_JSON_OUTPUT(flags)) {
1097 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr,
1101 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1102 prev_string, curr_string);
1107 ***************************************************************************
1108 * Core function used to display statistics.
1111 * @prev Position in array where statistics used as reference are.
1112 * Stats used as reference may be the previous ones read, or
1113 * the very first ones when calculating the average.
1114 * @curr Position in array where statistics for current sample are.
1115 * @dis TRUE if a header line must be printed.
1116 * @prev_string String displayed at the beginning of a header line. This is
1117 * the timestamp of the previous sample, or "Average" when
1118 * displaying average stats.
1119 * @curr_string String displayed at the beginning of current sample stats.
1120 * This is the timestamp of the current sample, or "Average"
1121 * when displaying average stats.
1122 ***************************************************************************
1124 void write_stats_core(int prev, int curr, int dis,
1125 char *prev_string, char *curr_string)
1127 struct stats_cpu *scc, *scp;
1128 unsigned long long itv, g_itv;
1129 int cpu, tab = 4, next = FALSE;
1132 TEST_STDOUT(STDOUT_FILENO);
1134 if (DISPLAY_JSON_OUTPUT(flags)) {
1135 xprintf(tab++, "{");
1136 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1139 /* Compute time interval */
1140 g_itv = get_interval(uptime[prev], uptime[curr]);
1142 /* Reduce interval value to one processor */
1144 itv = get_interval(uptime0[prev], uptime0[curr]);
1150 /* Print CPU stats */
1151 if (DISPLAY_CPU(actflags)) {
1152 write_cpu_stats(dis, g_itv, prev, curr, prev_string, curr_string,
1156 /* Print total number of interrupts per processor */
1157 if (DISPLAY_IRQ_SUM(actflags)) {
1158 write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
1162 /* Display each interrupt value for each CPU */
1163 if (DISPLAY_IRQ_CPU(actflags)) {
1164 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
1165 prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
1167 if (DISPLAY_SOFTIRQS(actflags)) {
1168 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
1169 prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
1172 if (DISPLAY_JSON_OUTPUT(flags)) {
1174 xprintf0(--tab, "}");
1177 /* Fix CPU counter values for every offline CPU */
1178 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1180 scc = st_cpu[curr] + cpu;
1181 scp = st_cpu[prev] + cpu;
1183 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
1184 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
1185 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
1187 * Offline CPU found.
1188 * Set current struct fields (which have been set to zero)
1189 * to values from previous iteration. Hence their values won't
1190 * jump from zero when the CPU comes back online.
1198 ***************************************************************************
1199 * Print statistics average.
1202 * @curr Position in array where statistics for current sample are.
1203 * @dis TRUE if a header line must be printed.
1204 ***************************************************************************
1206 void write_stats_avg(int curr, int dis)
1210 strncpy(string, _("Average:"), 16);
1212 write_stats_core(2, curr, dis, string, string);
1216 ***************************************************************************
1220 * @curr Position in array where statistics for current sample are.
1221 * @dis TRUE if a header line must be printed.
1222 ***************************************************************************
1224 void write_stats(int curr, int dis)
1226 char cur_time[2][16];
1228 /* Get previous timestamp */
1229 if (is_iso_time_fmt()) {
1230 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%H:%M:%S", &mp_tstamp[!curr]);
1233 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1236 /* Get current timestamp */
1237 if (is_iso_time_fmt()) {
1238 strftime(cur_time[curr], sizeof(cur_time[curr]), "%H:%M:%S", &mp_tstamp[curr]);
1241 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1244 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1248 ***************************************************************************
1249 * Read stats from /proc/interrupts or /proc/softirqs.
1252 * @file /proc file to read (interrupts or softirqs).
1253 * @ic_nr Number of interrupts (hard or soft) per CPU.
1254 * @curr Position in array where current statistics will be saved.
1257 * @st_ic Array for per-CPU interrupts statistics.
1258 ***************************************************************************
1260 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1263 struct stats_irq *st_irq_i;
1264 struct stats_irqcpu *p;
1265 char *line = NULL, *li;
1266 unsigned long irq = 0;
1268 int cpu_index[cpu_nr], index = 0, len;
1271 /* Reset total number of interrupts received by each CPU */
1272 for (cpu = 0; cpu < cpu_nr; cpu++) {
1273 st_irq_i = st_irq[curr] + cpu + 1;
1274 st_irq_i->irq_nr = 0;
1277 if ((fp = fopen(file, "r")) != NULL) {
1279 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1282 * Parse header line to see which CPUs are online
1284 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1286 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1287 cpu = strtol(cp + 3, &next, 10);
1288 cpu_index[index++] = cpu;
1291 /* Header line found */
1295 /* Parse each line of interrupts statistics data */
1296 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1299 /* Skip over "<irq>:" */
1300 if ((cp = strchr(line, ':')) == NULL)
1301 /* Chr ':' not found */
1305 p = st_ic[curr] + irq;
1307 /* Remove possible heading spaces in interrupt's name... */
1312 len = strcspn(li, ":");
1313 if (len >= MAX_IRQ_LEN) {
1314 len = MAX_IRQ_LEN - 1;
1316 /* ...then save its name */
1317 strncpy(p->irq_name, li, len);
1318 p->irq_name[len] = '\0';
1320 /* For each interrupt: Get number received by each CPU */
1321 for (cpu = 0; cpu < index; cpu++) {
1322 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
1323 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
1325 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq_name:
1326 * This is the same as st_irqcpu->irq_name.
1327 * Now save current interrupt value for current CPU (in stats_irqcpu structure)
1328 * and total number of interrupts received by current CPU (in stats_irq structure).
1330 p->interrupt = strtoul(cp, &next, 10);
1331 st_irq_i->irq_nr += p->interrupt;
1342 while (irq < ic_nr) {
1343 /* Nb of interrupts per processor has changed */
1344 p = st_ic[curr] + irq;
1345 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
1351 ***************************************************************************
1352 * Main loop: Read stats from the relevant sources, and display them.
1355 * @dis_hdr Set to TRUE if the header line must always be printed.
1356 * @rows Number of rows of screen.
1357 ***************************************************************************
1359 void rw_mpstat_loop(int dis_hdr, int rows)
1361 struct stats_cpu *scc;
1363 int curr = 1, dis = 1;
1364 unsigned long lines = rows;
1366 /* Dont buffer data if redirected to a pipe */
1367 setbuf(stdout, NULL);
1369 /* Read uptime and CPU stats */
1372 * Init uptime0. So if /proc/uptime cannot fill it,
1373 * this will be done by /proc/stat.
1376 read_uptime(&(uptime0[0]));
1378 read_stat_cpu(st_cpu[0], cpu_nr + 1, &(uptime[0]), &(uptime0[0]));
1381 * Read total number of interrupts received among all CPU.
1382 * (this is the first value on the line "intr:" in the /proc/stat file).
1384 if (DISPLAY_IRQ_SUM(actflags)) {
1385 read_stat_irq(st_irq[0], 1);
1389 * Read number of interrupts received by each CPU, for each interrupt,
1390 * and compute the total number of interrupts received by each CPU.
1392 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1393 /* Read this file to display int per CPU or total nr of int per CPU */
1394 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
1396 if (DISPLAY_SOFTIRQS(actflags)) {
1397 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1401 /* Display since boot time */
1402 mp_tstamp[1] = mp_tstamp[0];
1403 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
1404 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
1405 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1406 if (DISPLAY_SOFTIRQS(actflags)) {
1407 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1409 write_stats(0, DISP_HDR);
1410 if (DISPLAY_JSON_OUTPUT(flags)) {
1411 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1416 /* Set a handler for SIGALRM */
1417 memset(&alrm_act, 0, sizeof(alrm_act));
1418 alrm_act.sa_handler = alarm_handler;
1419 sigaction(SIGALRM, &alrm_act, NULL);
1422 /* Save the first stats collected. Will be used to compute the average */
1423 mp_tstamp[2] = mp_tstamp[0];
1424 uptime[2] = uptime[0];
1425 uptime0[2] = uptime0[0];
1426 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
1427 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
1428 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
1429 if (DISPLAY_SOFTIRQS(actflags)) {
1430 memcpy(st_softirqcpu[2], st_softirqcpu[0],
1431 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
1434 if (!DISPLAY_JSON_OUTPUT(flags)) {
1435 /* Set a handler for SIGINT */
1436 memset(&int_act, 0, sizeof(int_act));
1437 int_act.sa_handler = int_handler;
1438 sigaction(SIGINT, &int_act, NULL);
1444 /* SIGINT signal caught during first interval: Exit immediately */
1449 * Resetting the structure not needed since every fields will be set.
1450 * Exceptions are per-CPU structures: Some of them may not be filled
1451 * if corresponding processor is disabled (offline). We set them to zero
1452 * to be able to distinguish between offline and tickless CPUs.
1454 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1455 scc = st_cpu[curr] + cpu;
1456 memset(scc, 0, STATS_CPU_SIZE);
1460 get_localtime(&(mp_tstamp[curr]), 0);
1462 /* Read uptime and CPU stats */
1465 read_uptime(&(uptime0[curr]));
1467 read_stat_cpu(st_cpu[curr], cpu_nr + 1, &(uptime[curr]), &(uptime0[curr]));
1469 /* Read total number of interrupts received among all CPU */
1470 if (DISPLAY_IRQ_SUM(actflags)) {
1471 read_stat_irq(st_irq[curr], 1);
1475 * Read number of interrupts received by each CPU, for each interrupt,
1476 * and compute the total number of interrupts received by each CPU.
1478 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1479 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
1481 if (DISPLAY_SOFTIRQS(actflags)) {
1482 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
1493 write_stats(curr, dis);
1501 if (DISPLAY_JSON_OUTPUT(flags)) {
1506 if (sigint_caught) {
1507 /* SIGINT signal caught => Display average stats */
1509 printf("\n"); /* Skip "^C" displayed on screen */
1518 /* Write stats average */
1519 if (DISPLAY_JSON_OUTPUT(flags)) {
1520 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1523 write_stats_avg(curr, dis_hdr);
1528 ***************************************************************************
1529 * Main entry to the program
1530 ***************************************************************************
1532 int main(int argc, char **argv)
1534 int opt = 0, i, actset = FALSE;
1535 struct utsname header;
1541 /* Init National Language Support */
1545 /* Init color strings */
1551 /* What is the highest processor number on this machine? */
1552 cpu_nr = get_cpu_nr(~0, TRUE);
1554 /* Calculate number of interrupts per processor */
1555 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
1557 /* Calculate number of soft interrupts per processor */
1558 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
1562 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
1563 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
1565 salloc_mp_struct(cpu_nr + 1);
1567 while (++opt < argc) {
1569 if (!strcmp(argv[opt], "-I")) {
1573 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
1574 if (!strcmp(t, K_SUM)) {
1575 /* Display total number of interrupts per CPU */
1576 actflags |= M_D_IRQ_SUM;
1578 else if (!strcmp(t, K_CPU)) {
1579 /* Display interrupts per CPU */
1580 actflags |= M_D_IRQ_CPU;
1582 else if (!strcmp(t, K_SCPU)) {
1583 /* Display soft interrupts per CPU */
1584 actflags |= M_D_SOFTIRQS;
1586 else if (!strcmp(t, K_ALL)) {
1587 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
1599 else if (!strcmp(argv[opt], "-o")) {
1600 /* Select output format */
1601 if (argv[++opt] && !strcmp(argv[opt], K_JSON)) {
1602 flags |= F_JSON_OUTPUT;
1609 else if (!strcmp(argv[opt], "-P")) {
1610 /* '-P ALL' can be used on UP machines */
1612 flags |= F_P_OPTION;
1615 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
1616 if (!strcmp(t, K_ALL) || !strcmp(t, K_ON)) {
1621 * Set bit for every processor.
1622 * Also indicate to display stats for CPU 'all'.
1624 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
1625 if (!strcmp(t, K_ON)) {
1626 /* Display stats only for online CPU */
1631 if (strspn(t, DIGITS) != strlen(t)) {
1634 i = atoi(t); /* Get cpu number */
1636 fprintf(stderr, _("Not that many processors!\n"));
1640 *(cpu_bitmap + (i >> 3)) |= 1 << (i & 0x07);
1649 else if (!strncmp(argv[opt], "-", 1)) {
1650 for (i = 1; *(argv[opt] + i); i++) {
1652 switch (*(argv[opt] + i)) {
1655 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
1657 /* Select all processors */
1658 flags |= F_P_OPTION;
1659 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
1664 actflags |= M_D_CPU;
1668 /* Print version number */
1678 else if (interval < 0) {
1680 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
1683 interval = atol(argv[opt]);
1690 else if (count <= 0) {
1691 /* Get count value */
1692 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
1696 count = atol(argv[opt]);
1707 /* Default: Display CPU */
1709 actflags |= M_D_CPU;
1712 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
1716 if (!USE_P_OPTION(flags)) {
1717 /* Option -P not used: Set bit 0 (global stats among all proc) */
1724 /* Get window size */
1725 rows = get_win_height();
1728 /* Interval not set => display stats since boot time */
1733 get_localtime(&(mp_tstamp[0]), 0);
1735 /* Get system name, release number and hostname */
1737 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
1738 header.nodename, header.machine, get_cpu_nr(~0, FALSE),
1739 DISPLAY_JSON_OUTPUT(flags));
1742 rw_mpstat_loop(dis_hdr, rows);
1744 /* Free structures */