2 * mpstat: per-processor statistics
3 * (C) 2000-2015 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>
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 /* Structures used to store stats */
55 struct stats_cpu *st_cpu[3];
56 struct stats_irq *st_irq[3];
57 struct stats_irqcpu *st_irqcpu[3];
58 struct stats_irqcpu *st_softirqcpu[3];
60 struct tm mp_tstamp[3];
63 unsigned int actflags = 0;
65 unsigned int flags = 0;
67 /* Interval and count parameters */
68 long interval = -1, count = 0;
70 /* Nb of processors on the machine */
72 /* Nb of interrupts per processor */
74 /* Nb of soft interrupts per processor */
75 int softirqcpu_nr = 0;
77 struct sigaction alrm_act, int_act;
78 int sigint_caught = 0;
81 ***************************************************************************
82 * Print usage and exit
85 * @progname Name of sysstat command
86 ***************************************************************************
88 void usage(char *progname)
90 fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
93 fprintf(stderr, _("Options are:\n"
94 "[ -A ] [ -u ] [ -V ] [ -I { SUM | CPU | SCPU | ALL } ]\n"
95 "[ -P { <cpu> [,...] | ON | ALL } ]\n"));
100 ***************************************************************************
101 * SIGALRM signal handler. No need to reset the handler here.
104 * @sig Signal number.
105 ***************************************************************************
107 void alarm_handler(int sig)
113 ***************************************************************************
114 * SIGINT signal handler.
117 * @sig Signal number.
118 **************************************************************************
120 void int_handler(int sig)
126 ***************************************************************************
127 * Allocate stats structures and cpu bitmap.
130 * @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
131 * because we also have to allocate a structure for CPU 'all'.
132 ***************************************************************************
134 void salloc_mp_struct(int nr_cpus)
138 for (i = 0; i < 3; i++) {
140 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
145 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
147 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
152 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
154 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
159 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
161 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
166 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
169 if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
173 memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
177 ***************************************************************************
178 * Free structures and bitmap.
179 ***************************************************************************
181 void sfree_mp_struct(void)
185 for (i = 0; i < 3; i++) {
189 free(st_softirqcpu[i]);
196 ***************************************************************************
197 * Display per CPU statistics.
200 * @st_ic Array for per-CPU statistics.
201 * @ic_nr Number of interrupts (hard or soft) per CPU.
202 * @dis TRUE if a header line must be printed.
203 * @itv Interval value.
204 * @prev Position in array where statistics used as reference are.
205 * Stats used as reference may be the previous ones read, or
206 * the very first ones when calculating the average.
207 * @curr Position in array where current statistics will be saved.
208 * @prev_string String displayed at the beginning of a header line. This is
209 * the timestamp of the previous sample, or "Average" when
210 * displaying average stats.
211 * @curr_string String displayed at the beginning of current sample stats.
212 * This is the timestamp of the current sample, or "Average"
213 * when displaying average stats.
214 ***************************************************************************
216 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
217 unsigned long long itv, int prev, int curr,
218 char *prev_string, char *curr_string)
220 struct stats_cpu *scc;
221 int j = 0, offset, cpu, colwidth[NR_IRQS];
222 struct stats_irqcpu *p, *q, *p0, *q0;
225 * Check if number of interrupts has changed.
226 * NB: A null interval value indicates that we are
227 * displaying statistics since system startup.
229 if (!dis && interval) {
231 p0 = st_ic[curr] + j;
232 if (p0->irq_name[0] != '\0') {
233 q0 = st_ic[prev] + j;
234 if (strcmp(p0->irq_name, q0->irq_name)) {
235 /* These are two different irq */
241 while ((j > 0) && (j <= ic_nr));
244 if (dis || (j < 0)) {
246 printf("\n%-11s CPU", prev_string);
247 for (j = 0; j < ic_nr; j++) {
248 p0 = st_ic[curr] + j;
249 if (p0->irq_name[0] != '\0') { /* Nb of irq per proc may have varied... */
250 printf(" %8s/s", p0->irq_name);
256 /* Calculate column widths */
257 for (j = 0; j < ic_nr; j++) {
258 p0 = st_ic[curr] + j;
259 if (p0->irq_name[0] != '\0') {
260 /* Width is IRQ name + 2 for the trailing "/s" */
261 colwidth[j] = strlen(p0->irq_name) + 2;
263 * Normal space for printing a number is 11 chars
264 * (space + 10 digits including the period).
266 if (colwidth[j] < 10) {
272 for (cpu = 1; cpu <= cpu_nr; cpu++) {
274 scc = st_cpu[curr] + cpu;
277 * Check if we want stats about this CPU.
278 * CPU must have been explicitly selected using option -P,
279 * else we display every CPU.
281 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
284 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
285 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
286 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
288 /* Offline CPU found */
290 if (DISPLAY_ONLINE_CPU(flags))
294 printf("%-11s", curr_string);
295 cprintf_in(IS_INT, " %3d", "", cpu - 1);
297 for (j = 0; j < ic_nr; j++) {
298 p0 = st_ic[curr] + j; /* irq field set only for proc #0 */
300 * An empty string for irq name means it is a remaining interrupt
301 * which is no longer used, for example because the
302 * number of interrupts has decreased in /proc/interrupts.
304 if (p0->irq_name[0] != '\0') {
305 q0 = st_ic[prev] + j;
309 * If we want stats for the time since system startup,
310 * we have p0->irq != q0->irq, since q0 structure is
311 * completely set to zero.
313 if (strcmp(p0->irq_name, q0->irq_name) && interval) {
316 q0 = st_ic[prev] + offset;
317 if (strcmp(p0->irq_name, q0->irq_name) && (j + 1 < ic_nr))
319 q0 = st_ic[prev] + offset;
322 if (!strcmp(p0->irq_name, q0->irq_name) || !interval) {
323 p = st_ic[curr] + (cpu - 1) * ic_nr + j;
324 q = st_ic[prev] + (cpu - 1) * ic_nr + offset;
325 cprintf_f(1, colwidth[j], 2,
326 S_VALUE(q->interrupt, p->interrupt, itv));
337 ***************************************************************************
338 * Core function used to display statistics.
341 * @prev Position in array where statistics used as reference are.
342 * Stats used as reference may be the previous ones read, or
343 * the very first ones when calculating the average.
344 * @curr Position in array where statistics for current sample are.
345 * @dis TRUE if a header line must be printed.
346 * @prev_string String displayed at the beginning of a header line. This is
347 * the timestamp of the previous sample, or "Average" when
348 * displaying average stats.
349 * @curr_string String displayed at the beginning of current sample stats.
350 * This is the timestamp of the current sample, or "Average"
351 * when displaying average stats.
352 ***************************************************************************
354 void write_stats_core(int prev, int curr, int dis,
355 char *prev_string, char *curr_string)
357 struct stats_cpu *scc, *scp;
358 unsigned long long itv, pc_itv, g_itv;
362 TEST_STDOUT(STDOUT_FILENO);
364 /* Compute time interval */
365 g_itv = get_interval(uptime[prev], uptime[curr]);
367 /* Reduce interval value to one processor */
369 itv = get_interval(uptime0[prev], uptime0[curr]);
375 /* Print CPU stats */
376 if (DISPLAY_CPU(actflags)) {
378 printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq "
379 "%%soft %%steal %%guest %%gnice %%idle\n",
383 /* Check if we want global stats among all proc */
384 if (*cpu_bitmap & 1) {
386 printf("%-11s", curr_string);
387 cprintf_in(IS_STR, " %s", " all", 0);
390 (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
391 (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
393 ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
394 st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
396 (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
397 (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
399 ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
400 st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
402 ll_sp_value(st_cpu[prev]->cpu_sys,
403 st_cpu[curr]->cpu_sys,
405 ll_sp_value(st_cpu[prev]->cpu_iowait,
406 st_cpu[curr]->cpu_iowait,
408 ll_sp_value(st_cpu[prev]->cpu_hardirq,
409 st_cpu[curr]->cpu_hardirq,
411 ll_sp_value(st_cpu[prev]->cpu_softirq,
412 st_cpu[curr]->cpu_softirq,
414 ll_sp_value(st_cpu[prev]->cpu_steal,
415 st_cpu[curr]->cpu_steal,
417 ll_sp_value(st_cpu[prev]->cpu_guest,
418 st_cpu[curr]->cpu_guest,
420 ll_sp_value(st_cpu[prev]->cpu_guest_nice,
421 st_cpu[curr]->cpu_guest_nice,
423 (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
425 ll_sp_value(st_cpu[prev]->cpu_idle,
426 st_cpu[curr]->cpu_idle,
431 for (cpu = 1; cpu <= cpu_nr; cpu++) {
433 scc = st_cpu[curr] + cpu;
434 scp = st_cpu[prev] + cpu;
436 /* Check if we want stats about this proc */
437 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
441 * If the CPU is offline then it is omited from /proc/stat
442 * and the sum of all values is zero.
443 * (Remember that guest/guest_nice times are already included in
446 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
447 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
448 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
450 if (!DISPLAY_ONLINE_CPU(flags)) {
451 printf("%-11s", curr_string);
452 cprintf_in(IS_INT, " %4d", "", cpu - 1);
454 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
460 printf("%-11s", curr_string);
461 cprintf_in(IS_INT, " %4d", "", cpu - 1);
463 /* Recalculate itv for current proc */
464 pc_itv = get_per_cpu_interval(scc, scp);
468 * If the CPU is tickless then there is no change in CPU values
469 * but the sum of values is not zero.
472 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
478 (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
480 ll_sp_value(scp->cpu_user - scp->cpu_guest,
481 scc->cpu_user - scc->cpu_guest,
483 (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
485 ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
486 scc->cpu_nice - scc->cpu_guest_nice,
488 ll_sp_value(scp->cpu_sys,
491 ll_sp_value(scp->cpu_iowait,
494 ll_sp_value(scp->cpu_hardirq,
497 ll_sp_value(scp->cpu_softirq,
500 ll_sp_value(scp->cpu_steal,
503 ll_sp_value(scp->cpu_guest,
506 ll_sp_value(scp->cpu_guest_nice,
509 (scc->cpu_idle < scp->cpu_idle) ?
511 ll_sp_value(scp->cpu_idle,
519 /* Print total number of interrupts per processor */
520 if (DISPLAY_IRQ_SUM(actflags)) {
521 struct stats_irq *sic, *sip;
524 printf("\n%-11s CPU intr/s\n", prev_string);
527 if (*cpu_bitmap & 1) {
528 printf("%-11s", curr_string);
529 cprintf_in(IS_STR, " %s", " all", 0);
531 S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
535 for (cpu = 1; cpu <= cpu_nr; cpu++) {
537 sic = st_irq[curr] + cpu;
538 sip = st_irq[prev] + cpu;
540 scc = st_cpu[curr] + cpu;
541 scp = st_cpu[prev] + cpu;
543 /* Check if we want stats about this proc */
544 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
547 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
548 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
549 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
551 /* This is an offline CPU */
553 if (!DISPLAY_ONLINE_CPU(flags)) {
554 printf("%-11s", curr_string);
555 cprintf_in(IS_INT, " %4d", "", cpu- 1);
556 cprintf_f(1, 9, 2, 0.0);
562 printf("%-11s", curr_string);
563 cprintf_in(IS_INT, " %4d", "", cpu- 1);
565 /* Recalculate itv for current proc */
566 pc_itv = get_per_cpu_interval(scc, scp);
569 /* This is a tickless CPU */
570 cprintf_f(1, 9, 2, 0.0);
575 S_VALUE(sip->irq_nr, sic->irq_nr, itv));
581 if (DISPLAY_IRQ_CPU(actflags)) {
582 write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
583 prev_string, curr_string);
586 if (DISPLAY_SOFTIRQS(actflags)) {
587 write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
588 prev_string, curr_string);
591 /* Fix CPU counter values for every offline CPU */
592 for (cpu = 1; cpu <= cpu_nr; cpu++) {
594 scc = st_cpu[curr] + cpu;
595 scp = st_cpu[prev] + cpu;
597 if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
598 scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
599 scc->cpu_hardirq + scc->cpu_softirq) == 0) {
602 * Set current struct fields (which have been set to zero)
603 * to values from previous iteration. Hence their values won't
604 * jump from zero when the CPU comes back online.
612 ***************************************************************************
613 * Print statistics average.
616 * @curr Position in array where statistics for current sample are.
617 * @dis TRUE if a header line must be printed.
618 ***************************************************************************
620 void write_stats_avg(int curr, int dis)
624 strncpy(string, _("Average:"), 16);
626 write_stats_core(2, curr, dis, string, string);
630 ***************************************************************************
634 * @curr Position in array where statistics for current sample are.
635 * @dis TRUE if a header line must be printed.
636 ***************************************************************************
638 void write_stats(int curr, int dis)
640 char cur_time[2][16];
642 /* Get previous timestamp */
643 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
645 /* Get current timestamp */
646 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
648 write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
652 ***************************************************************************
653 * Read stats from /proc/interrupts or /proc/softirqs.
656 * @file /proc file to read (interrupts or softirqs).
657 * @ic_nr Number of interrupts (hard or soft) per CPU.
658 * @curr Position in array where current statistics will be saved.
661 * @st_ic Array for per-CPU statistics.
662 ***************************************************************************
664 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
667 struct stats_irq *st_irq_i;
668 struct stats_irqcpu *p;
669 char *line = NULL, *li;
670 unsigned long irq = 0;
672 int cpu_index[cpu_nr], index = 0, len;
675 for (cpu = 0; cpu < cpu_nr; cpu++) {
676 st_irq_i = st_irq[curr] + cpu + 1;
677 st_irq_i->irq_nr = 0;
680 if ((fp = fopen(file, "r")) != NULL) {
682 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
685 * Parse header line to see which CPUs are online
687 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
689 while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
690 cpu = strtol(cp + 3, &next, 10);
691 cpu_index[index++] = cpu;
694 /* Header line found */
698 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
701 /* Skip over "<irq>:" */
702 if ((cp = strchr(line, ':')) == NULL)
703 /* Chr ':' not found */
707 p = st_ic[curr] + irq;
713 len = strcspn(li, ":");
714 if (len >= MAX_IRQ_LEN) {
715 len = MAX_IRQ_LEN - 1;
717 strncpy(p->irq_name, li, len);
718 p->irq_name[len] = '\0';
720 for (cpu = 0; cpu < index; cpu++) {
721 p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
722 st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
724 * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq:
725 * This is the same as st_irqcpu->irq.
727 p->interrupt = strtoul(cp, &next, 10);
728 st_irq_i->irq_nr += p->interrupt;
739 while (irq < ic_nr) {
740 /* Nb of interrupts per processor has changed */
741 p = st_ic[curr] + irq;
742 p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
748 ***************************************************************************
749 * Main loop: Read stats from the relevant sources, and display them.
752 * @dis_hdr Set to TRUE if the header line must always be printed.
753 * @rows Number of rows of screen.
754 ***************************************************************************
756 void rw_mpstat_loop(int dis_hdr, int rows)
758 struct stats_cpu *scc;
760 int curr = 1, dis = 1;
761 unsigned long lines = rows;
763 /* Dont buffer data if redirected to a pipe */
764 setbuf(stdout, NULL);
769 * Init uptime0. So if /proc/uptime cannot fill it,
770 * this will be done by /proc/stat.
773 read_uptime(&(uptime0[0]));
775 read_stat_cpu(st_cpu[0], cpu_nr + 1, &(uptime[0]), &(uptime0[0]));
777 if (DISPLAY_IRQ_SUM(actflags)) {
778 read_stat_irq(st_irq[0], 1);
781 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
782 /* Read this file to display int per CPU or total nr of int per CPU */
783 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
786 if (DISPLAY_SOFTIRQS(actflags)) {
787 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
791 /* Display since boot time */
792 mp_tstamp[1] = mp_tstamp[0];
793 memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
794 memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
795 memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
796 if (DISPLAY_SOFTIRQS(actflags)) {
797 memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
799 write_stats(0, DISP_HDR);
803 /* Set a handler for SIGALRM */
804 memset(&alrm_act, 0, sizeof(alrm_act));
805 alrm_act.sa_handler = alarm_handler;
806 sigaction(SIGALRM, &alrm_act, NULL);
809 /* Save the first stats collected. Will be used to compute the average */
810 mp_tstamp[2] = mp_tstamp[0];
811 uptime[2] = uptime[0];
812 uptime0[2] = uptime0[0];
813 memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
814 memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
815 memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
816 if (DISPLAY_SOFTIRQS(actflags)) {
817 memcpy(st_softirqcpu[2], st_softirqcpu[0],
818 STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
821 /* Set a handler for SIGINT */
822 memset(&int_act, 0, sizeof(int_act));
823 int_act.sa_handler = int_handler;
824 sigaction(SIGINT, &int_act, NULL);
829 /* SIGINT signal caught during first interval: Exit immediately */
834 * Resetting the structure not needed since every fields will be set.
835 * Exceptions are per-CPU structures: Some of them may not be filled
836 * if corresponding processor is disabled (offline). We set them to zero
837 * to be able to distinguish between offline and tickless CPUs.
839 for (cpu = 1; cpu <= cpu_nr; cpu++) {
840 scc = st_cpu[curr] + cpu;
841 memset(scc, 0, STATS_CPU_SIZE);
845 get_localtime(&(mp_tstamp[curr]), 0);
850 read_uptime(&(uptime0[curr]));
852 read_stat_cpu(st_cpu[curr], cpu_nr + 1, &(uptime[curr]), &(uptime0[curr]));
854 if (DISPLAY_IRQ_SUM(actflags)) {
855 read_stat_irq(st_irq[curr], 1);
858 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
859 read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
862 if (DISPLAY_SOFTIRQS(actflags)) {
863 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
874 write_stats(curr, dis);
885 /* SIGINT signal caught => Display average stats */
887 printf("\n"); /* Skip "^C" displayed on screen */
896 /* Write stats average */
897 write_stats_avg(curr, dis_hdr);
901 ***************************************************************************
902 * Main entry to the program
903 ***************************************************************************
905 int main(int argc, char **argv)
907 int opt = 0, i, actset = FALSE;
908 struct utsname header;
914 /* Init National Language Support */
918 /* Init color strings */
924 /* What is the highest processor number on this machine? */
925 cpu_nr = get_cpu_nr(~0, TRUE);
927 /* Calculate number of interrupts per processor */
928 irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
930 /* Calculate number of soft interrupts per processor */
931 softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
935 * cpu_nr: a value of 2 means there are 2 processors (0 and 1).
936 * In this case, we have to allocate 3 structures: global, proc0 and proc1.
938 salloc_mp_struct(cpu_nr + 1);
940 while (++opt < argc) {
942 if (!strcmp(argv[opt], "-I")) {
945 if (!strcmp(argv[opt], K_SUM)) {
946 /* Display total number of interrupts per CPU */
947 actflags |= M_D_IRQ_SUM;
949 else if (!strcmp(argv[opt], K_CPU)) {
950 /* Display interrupts per CPU */
951 actflags |= M_D_IRQ_CPU;
953 else if (!strcmp(argv[opt], K_SCPU)) {
954 /* Display soft interrupts per CPU */
955 actflags |= M_D_SOFTIRQS;
957 else if (!strcmp(argv[opt], K_ALL)) {
958 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
969 else if (!strcmp(argv[opt], "-P")) {
970 /* '-P ALL' can be used on UP machines */
975 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
976 if (!strcmp(t, K_ALL) || !strcmp(t, K_ON)) {
981 * Set bit for every processor.
982 * Also indicate to display stats for CPU 'all'.
984 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
985 if (!strcmp(t, K_ON)) {
986 /* Display stats only for online CPU */
991 if (strspn(t, DIGITS) != strlen(t)) {
994 i = atoi(t); /* Get cpu number */
996 fprintf(stderr, _("Not that many processors!\n"));
1000 *(cpu_bitmap + (i >> 3)) |= 1 << (i & 0x07);
1009 else if (!strncmp(argv[opt], "-", 1)) {
1010 for (i = 1; *(argv[opt] + i); i++) {
1012 switch (*(argv[opt] + i)) {
1015 actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
1017 /* Select all processors */
1018 flags |= F_P_OPTION;
1019 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
1024 actflags |= M_D_CPU;
1028 /* Print version number */
1038 else if (interval < 0) {
1040 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
1043 interval = atol(argv[opt]);
1050 else if (count <= 0) {
1051 /* Get count value */
1052 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
1056 count = atol(argv[opt]);
1067 /* Default: Display CPU */
1069 actflags |= M_D_CPU;
1072 if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
1076 if (!USE_P_OPTION(flags)) {
1077 /* Option -P not used: Set bit 0 (global stats among all proc) */
1084 /* Get window size */
1085 rows = get_win_height();
1088 /* Interval not set => display stats since boot time */
1093 get_localtime(&(mp_tstamp[0]), 0);
1095 /* Get system name, release number and hostname */
1097 print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
1098 header.nodename, header.machine, get_cpu_nr(~0, FALSE));
1101 rw_mpstat_loop(dis_hdr, rows);
1103 /* Free structures */