2 * mpstat: per-processor statistics
3 * (C) 2000-2011 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 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
19 ***************************************************************************
29 #include <sys/utsname.h>
39 #define _(string) gettext(string)
41 #define _(string) (string)
44 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
45 char *sccsid(void) { return (SCCSID); }
47 unsigned long long uptime[3] = {0, 0, 0};
48 unsigned long long uptime0[3] = {0, 0, 0};
50 /* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
51 unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */
53 /* Structures used to store stats */
54 struct stats_cpu *st_cpu[3];
55 struct stats_irq *st_irq[3];
56 struct stats_irqcpu *st_irqcpu[3];
57 struct stats_irqcpu *st_softirqcpu[3];
59 struct tm mp_tstamp[3];
62 unsigned int actflags = 0;
64 unsigned int flags = 0;
66 /* Interval and count parameters */
67 long interval = -1, count = 0;
69 /* Nb of processors on the machine */
71 /* Nb of interrupts per processor */
73 /* Nb of soft interrupts per processor */
74 int softirqcpu_nr = 0;
77 ***************************************************************************
78 * Print usage and exit
81 * @progname Name of sysstat command
82 ***************************************************************************
84 void usage(char *progname)
86 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
89 fprintf(stderr, _("Options are:\n"
90 "[ -A ] [ -I { SUM | CPU | SCPU | ALL } ] [ -u ]\n"
91 "[ -P { <cpu> [,...] | ON | ALL } ] [ -V ]\n"));
96 ***************************************************************************
97 * SIGALRM signal handler
100 * @sig Signal number. Set to 0 for the first time, then to SIGALRM.
101 ***************************************************************************
103 void alarm_handler(int sig)
105 signal(SIGALRM, alarm_handler);
110 ***************************************************************************
111 * Allocate stats structures and cpu bitmap.
114 * @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
115 * because we also have to allocate a structure for CPU 'all'.
116 ***************************************************************************
118 void salloc_mp_struct(int nr_cpus)
122 for (i = 0; i < 3; i++) {
124 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
129 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
131 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
136 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
138 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
143 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
145 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
150 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
153 if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
157 memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
161 ***************************************************************************
162 * Free structures and bitmap.
163 ***************************************************************************
165 void sfree_mp_struct(void)
169 for (i = 0; i < 3; i++) {
180 if (st_softirqcpu[i]) {
181 free(st_softirqcpu[i]);
191 ***************************************************************************
192 * Display per CPU statistics.
195 * @st_ic Array for per-CPU statistics.
196 * @ic_nr Number of interrupts (hard or soft) per CPU.
197 * @dis TRUE if a header line must be printed.
198 * @itv Interval value.
199 * @prev Position in array where statistics used as reference are.
200 * Stats used as reference may be the previous ones read, or
201 * the very first ones when calculating the average.
202 * @curr Position in array where current statistics will be saved.
203 * @prev_string String displayed at the beginning of a header line. This is
204 * the timestamp of the previous sample, or "Average" when
205 * displaying average stats.
206 * @curr_string String displayed at the beginning of current sample stats.
207 * This is the timestamp of the current sample, or "Average"
208 * when displaying average stats.
209 ***************************************************************************
211 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
212 unsigned long long itv, int prev, int curr,
213 char *prev_string, char *curr_string)
215 struct stats_cpu *scc, *scp;
216 int j = 0, offset, cpu;
217 struct stats_irqcpu *p, *q, *p0, *q0;
220 * Check if number of interrupts has changed.
221 * NB: A null interval value indicates that we are
222 * displaying statistics since system startup.
224 if (!dis && interval) {
226 p0 = st_ic[curr] + j;
227 if (p0->irq_name[0] != '\0') {
228 q0 = st_ic[prev] + j;
229 if (strcmp(p0->irq_name, q0->irq_name)) {
230 /* These are two different irq */
236 while ((j > 0) && (j <= ic_nr));
239 if (dis || (j < 0)) {
241 printf("\n%-11s CPU", prev_string);
242 for (j = 0; j < ic_nr; j++) {
243 p0 = st_ic[curr] + j;
244 if (p0->irq_name[0] != '\0') { /* Nb of irq per proc may have varied... */
245 printf(" %8s/s", p0->irq_name);
251 for (cpu = 1; cpu <= cpu_nr; cpu++) {
253 scc = st_cpu[curr] + cpu;
254 scp = st_cpu[prev] + cpu;
257 * Check if we want stats about this CPU.
258 * CPU must have been explicitly selected using option -P,
259 * else we display every CPU.
261 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
264 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
265 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
266 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
268 /* Offline CPU found */
270 if (DISPLAY_ONLINE_CPU(flags))
274 printf("%-11s %3d", curr_string, cpu - 1);
276 for (j = 0; j < ic_nr; j++) {
277 p0 = st_ic[curr] + j; /* irq field set only for proc #0 */
279 * An empty string for irq name means it is a remaining interrupt
280 * which is no longer used, for example because the
281 * number of interrupts has decreased in /proc/interrupts.
283 if (p0->irq_name[0] != '\0') {
284 q0 = st_ic[prev] + j;
288 * If we want stats for the time since system startup,
289 * we have p0->irq != q0->irq, since q0 structure is
290 * completely set to zero.
292 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
295 q0 = st_ic[prev] + offset;
296 if (strcmp(p0->irq_name, q0->irq_name) && (j + 1 < ic_nr))
298 q0 = st_ic[prev] + offset;
301 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
302 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
303 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
305 S_VALUE(q->interrupt, p->interrupt, itv));
316 ***************************************************************************
317 * Core function used to display statistics.
320 * @prev Position in array where statistics used as reference are.
321 * Stats used as reference may be the previous ones read, or
322 * the very first ones when calculating the average.
323 * @curr Position in array where statistics for current sample are.
324 * @dis TRUE if a header line must be printed.
325 * @prev_string String displayed at the beginning of a header line. This is
326 * the timestamp of the previous sample, or "Average" when
327 * displaying average stats.
328 * @curr_string String displayed at the beginning of current sample stats.
329 * This is the timestamp of the current sample, or "Average"
330 * when displaying average stats.
331 ***************************************************************************
333 void write_stats_core(int prev, int curr, int dis,
334 char *prev_string, char *curr_string)
336 struct stats_cpu *scc, *scp;
337 unsigned long long itv, pc_itv, g_itv;
341 TEST_STDOUT(STDOUT_FILENO);
343 /* Compute time interval */
344 g_itv = get_interval(uptime[prev], uptime[curr]);
346 /* Reduce interval value to one processor */
348 itv = get_interval(uptime0[prev], uptime0[curr]);
354 /* Print CPU stats */
355 if (DISPLAY_CPU(actflags)) {
357 printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq "
358 "%%soft %%steal %%guest %%idle\n",
362 /* Check if we want global stats among all proc */
363 if (*cpu_bitmap & 1) {
365 printf("%-11s all", curr_string);
367 printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n",
368 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
369 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
371 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
372 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
374 ll_sp_value(st_cpu[prev]->cpu_nice,
375 st_cpu[curr]->cpu_nice,
377 ll_sp_value(st_cpu[prev]->cpu_sys,
378 st_cpu[curr]->cpu_sys,
380 ll_sp_value(st_cpu[prev]->cpu_iowait,
381 st_cpu[curr]->cpu_iowait,
383 ll_sp_value(st_cpu[prev]->cpu_hardirq,
384 st_cpu[curr]->cpu_hardirq,
386 ll_sp_value(st_cpu[prev]->cpu_softirq,
387 st_cpu[curr]->cpu_softirq,
389 ll_sp_value(st_cpu[prev]->cpu_steal,
390 st_cpu[curr]->cpu_steal,
392 ll_sp_value(st_cpu[prev]->cpu_guest,
393 st_cpu[curr]->cpu_guest,
395 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
397 ll_sp_value(st_cpu[prev]->cpu_idle,
398 st_cpu[curr]->cpu_idle,
402 for (cpu = 1; cpu <= cpu_nr; cpu++) {
404 scc = st_cpu[curr] + cpu;
405 scp = st_cpu[prev] + cpu;
407 /* Check if we want stats about this proc */
408 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
412 * If the CPU is offline then it is omited from /proc/stat
413 * and the sum of all values is zero.
414 * (Remember that guest time is already included in user mode.)
416 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
417 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
418 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
420 if (!DISPLAY_ONLINE_CPU(flags)) {
422 " %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
423 " %6.2f %6.2f %6.2f\n",
424 curr_string, cpu - 1,
425 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
430 printf("%-11s %4d", curr_string, cpu - 1);
432 /* Recalculate itv for current proc */
433 pc_itv = get_per_cpu_interval(scc, scp);
437 * If the CPU is tickless then there is no change in CPU values
438 * but the sum of values is not zero.
440 printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
441 " %6.2f %6.2f %6.2f\n",
442 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
446 printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
447 " %6.2f %6.2f %6.2f\n",
448 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
450 ll_sp_value(scp->cpu_user - scp->cpu_guest,
451 scc->cpu_user - scc->cpu_guest,
453 ll_sp_value(scp->cpu_nice,
456 ll_sp_value(scp->cpu_sys,
459 ll_sp_value(scp->cpu_iowait,
462 ll_sp_value(scp->cpu_hardirq,
465 ll_sp_value(scp->cpu_softirq,
468 ll_sp_value(scp->cpu_steal,
471 ll_sp_value(scp->cpu_guest,
474 (scc->cpu_idle < scp->cpu_idle) ?
476 ll_sp_value(scp->cpu_idle,
483 /* Print total number of interrupts per processor */
484 if (DISPLAY_IRQ_SUM(actflags)) {
485 struct stats_irq *sic, *sip;
488 printf("\n%-11s CPU intr/s\n", prev_string);
491 if (*cpu_bitmap & 1) {
492 printf("%-11s all %9.2f\n", curr_string,
493 ll_s_value(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
496 for (cpu = 1; cpu <= cpu_nr; cpu++) {
498 sic = st_irq[curr] + cpu;
499 sip = st_irq[prev] + cpu;
501 scc = st_cpu[curr] + cpu;
502 scp = st_cpu[prev] + cpu;
504 /* Check if we want stats about this proc */
505 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
508 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
509 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
510 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
512 /* This is an offline CPU */
514 if (!DISPLAY_ONLINE_CPU(flags)) {
517 curr_string, cpu - 1,
523 printf("%-11s %4d", curr_string, cpu - 1);
525 /* Recalculate itv for current proc */
526 pc_itv = get_per_cpu_interval(scc, scp);
529 /* This is a tickless CPU */
530 printf(" %9.2f\n", 0.0);
534 ll_s_value(sip->irq_nr, sic->irq_nr, itv));
539 if (DISPLAY_IRQ_CPU(actflags)) {
540 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
541 prev_string, curr_string);
544 if (DISPLAY_SOFTIRQS(actflags)) {
545 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
546 prev_string, curr_string);
549 /* Fix CPU counter values for every offline CPU */
550 for (cpu = 1; cpu <= cpu_nr; cpu++) {
552 scc = st_cpu[curr] + cpu;
553 scp = st_cpu[prev] + cpu;
555 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
556 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
557 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
560 * Set current struct fields (which have been set to zero)
561 * to values from previous iteration. Hence their values won't
562 * jump from zero when the CPU comes back online.
570 ***************************************************************************
571 * Print statistics average.
574 * @curr Position in array where statistics for current sample are.
575 * @dis TRUE if a header line must be printed.
576 ***************************************************************************
578 void write_stats_avg(int curr, int dis)
582 strncpy(string, _("Average:"), 16);
584 write_stats_core(2, curr, dis, string, string);
588 ***************************************************************************
592 * @curr Position in array where statistics for current sample are.
593 * @dis TRUE if a header line must be printed.
594 ***************************************************************************
596 void write_stats(int curr, int dis)
598 char cur_time[2][16];
600 /* Get previous timestamp */
601 strftime(cur_time[!curr], 16, "%X", &(mp_tstamp[!curr]));
603 /* Get current timestamp */
604 strftime(cur_time[curr], 16, "%X", &(mp_tstamp[curr]));
606 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
610 ***************************************************************************
611 * Read stats from /proc/interrupts or /proc/softirqs.
614 * @file /proc file to read (interrupts or softirqs).
615 * @ic_nr Number of interrupts (hard or soft) per CPU.
616 * @curr Position in array where current statistics will be saved.
619 * @st_ic Array for per-CPU statistics.
620 ***************************************************************************
622 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
625 struct stats_irq *st_irq_i;
626 struct stats_irqcpu *p;
628 unsigned long irq = 0;
630 int cpu_index[cpu_nr], index = 0, dgt, len;
633 for (cpu = 0; cpu < cpu_nr; cpu++) {
634 st_irq_i = st_irq[curr] + cpu + 1;
635 st_irq_i->irq_nr = 0;
638 if ((fp = fopen(file, "r")) != NULL) {
640 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
643 * Parse header line to see which CPUs are online
645 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
647 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
648 cpu = strtol(cp + 3, &next, 10);
649 cpu_index[index++] = cpu;
652 /* Header line found */
656 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
659 /* Skip over "<irq>:" */
660 if ((cp = strchr(line, ':')) == NULL)
664 p = st_ic[curr] + irq;
665 len = strcspn(line, ":");
666 if (len >= MAX_IRQ_LEN) {
667 len = MAX_IRQ_LEN - 1;
669 strncpy(p->irq_name, line, len);
670 p->irq_name[len] = '\0';
671 dgt = isdigit(line[len - 1]);
673 for (cpu = 0; cpu < index; cpu++) {
674 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
675 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
677 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq:
678 * This is the same as st_irqcpu->irq.
680 p->interrupt = strtoul(cp, &next, 10);
682 /* Sum only numerical irq (and not NMI, LOC, etc.) */
683 st_irq_i->irq_nr += p->interrupt;
697 while (irq < ic_nr) {
698 /* Nb of interrupts per processor has changed */
699 p = st_ic[curr] + irq;
700 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
706 ***************************************************************************
707 * Main loop: Read stats from the relevant sources, and display them.
710 * @dis_hdr Set to TRUE if the header line must always be printed.
711 * @rows Number of rows of screen.
712 ***************************************************************************
714 void rw_mpstat_loop(int dis_hdr, int rows)
716 struct stats_cpu *scc;
718 int curr = 1, dis = 1;
719 unsigned long lines = rows;
721 /* Dont buffer data if redirected to a pipe */
722 setbuf(stdout, NULL);
727 * Init uptime0. So if /proc/uptime cannot fill it,
728 * this will be done by /proc/stat.
731 read_uptime(&(uptime0[0]));
733 read_stat_cpu(st_cpu[0], cpu_nr + 1, &(uptime[0]), &(uptime0[0]));
735 if (DISPLAY_IRQ_SUM(actflags)) {
736 read_stat_irq(st_irq[0], 1);
739 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
740 /* Read this file to display int per CPU or total nr of int per CPU */
741 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
744 if (DISPLAY_SOFTIRQS(actflags)) {
745 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
749 /* Display since boot time */
750 mp_tstamp[1] = mp_tstamp[0];
751 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
752 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
753 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
754 if (DISPLAY_SOFTIRQS(actflags)) {
755 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
757 write_stats(0, DISP_HDR);
761 /* Set a handler for SIGALRM */
764 /* Save the first stats collected. Will be used to compute the average */
765 mp_tstamp[2] = mp_tstamp[0];
766 uptime[2] = uptime[0];
767 uptime0[2] = uptime0[0];
768 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
769 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
770 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
771 if (DISPLAY_SOFTIRQS(actflags)) {
772 memcpy(st_softirqcpu[2], st_softirqcpu[0],
773 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
780 * Resetting the structure not needed since every fields will be set.
781 * Exceptions are per-CPU structures: Some of them may not be filled
782 * if corresponding processor is disabled (offline). We set them to zero
783 * to be able to distinguish between offline and tickless CPUs.
785 for (cpu = 1; cpu <= cpu_nr; cpu++) {
786 scc = st_cpu[curr] + cpu;
787 memset(scc, 0, STATS_CPU_SIZE);
791 get_localtime(&(mp_tstamp[curr]));
796 read_uptime(&(uptime0[curr]));
798 read_stat_cpu(st_cpu[curr], cpu_nr + 1, &(uptime[curr]), &(uptime0[curr]));
800 if (DISPLAY_IRQ_SUM(actflags)) {
801 read_stat_irq(st_irq[curr], 1);
804 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
805 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
808 if (DISPLAY_SOFTIRQS(actflags)) {
809 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
820 write_stats(curr, dis);
832 /* Write stats average */
833 write_stats_avg(curr, dis_hdr);
837 ***************************************************************************
838 * Main entry to the program
839 ***************************************************************************
841 int main(int argc, char **argv)
843 int opt = 0, i, actset = FALSE;
844 struct utsname header;
850 /* Init National Language Support */
857 /* How many processors on this machine ? */
858 cpu_nr = get_cpu_nr(~0);
860 /* Calculate number of interrupts per processor */
861 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
863 /* Calculate number of soft interrupts per processor */
864 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
868 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
869 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
871 salloc_mp_struct(cpu_nr + 1);
873 while (++opt < argc) {
875 if (!strcmp(argv[opt], "-I")) {
878 if (!strcmp(argv[opt], K_SUM)) {
879 /* Display total number of interrupts per CPU */
880 actflags |= M_D_IRQ_SUM;
882 else if (!strcmp(argv[opt], K_CPU)) {
883 /* Display interrupts per CPU */
884 actflags |= M_D_IRQ_CPU;
886 else if (!strcmp(argv[opt], K_SCPU)) {
887 /* Display soft interrupts per CPU */
888 actflags |= M_D_SOFTIRQS;
890 else if (!strcmp(argv[opt], K_ALL)) {
891 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
902 else if (!strcmp(argv[opt], "-P")) {
903 /* '-P ALL' can be used on UP machines */
908 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
909 if (!strcmp(t, K_ALL) || !strcmp(t, K_ON)) {
914 * Set bit for every processor.
915 * Also indicate to display stats for CPU 'all'.
917 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
918 if (!strcmp(t, K_ON)) {
919 /* Display stats only for online CPU */
924 if (strspn(t, DIGITS) != strlen(t)) {
927 i = atoi(t); /* Get cpu number */
929 fprintf(stderr, _("Not that many processors!\n"));
933 *(cpu_bitmap + (i >> 3)) |= 1 << (i & 0x07);
942 else if (!strncmp(argv[opt], "-", 1)) {
943 for (i = 1; *(argv[opt] + i); i++) {
945 switch (*(argv[opt] + i)) {
948 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
950 /* Select all processors */
952 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
961 /* Print version number */
971 else if (interval < 0) {
973 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
976 interval = atol(argv[opt]);
983 else if (count <= 0) {
984 /* Get count value */
985 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
989 count = atol(argv[opt]);
1000 /* Default: Display CPU */
1002 actflags |= M_D_CPU;
1005 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
1009 if (!USE_P_OPTION(flags)) {
1010 /* Option -P not used: Set bit 0 (global stats among all proc) */
1017 /* Get window size */
1018 rows = get_win_height();
1021 /* Interval not set => display stats since boot time */
1026 get_localtime(&(mp_tstamp[0]));
1028 /* Get system name, release number and hostname */
1030 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
1031 header.nodename, header.machine, cpu_nr);
1034 rw_mpstat_loop(dis_hdr, rows);
1036 /* Free structures */