]> granicus.if.org Git - sysstat/blob - mpstat.c
Cosmetic fixes
[sysstat] / mpstat.c
1 /*
2  * mpstat: per-processor statistics
3  * (C) 2000-2016 by Sebastien GODARD (sysstat <at> orange.fr)
4  *
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.                                              *
10  *                                                                         *
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 *
14  * for more details.                                                       *
15  *                                                                         *
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  ***************************************************************************
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <sys/utsname.h>
30
31 #include "version.h"
32 #include "mpstat.h"
33 #include "common.h"
34 #include "rd_stats.h"
35 #include "count.h"
36
37 #ifdef USE_NLS
38 #include <locale.h>
39 #include <libintl.h>
40 #define _(string) gettext(string)
41 #else
42 #define _(string) (string)
43 #endif
44
45 #define SCCSID "@(#)sysstat-" VERSION ": "  __FILE__ " compiled " __DATE__ " " __TIME__
46 char *sccsid(void) { return (SCCSID); }
47
48 unsigned long long uptime[3] = {0, 0, 0};
49 unsigned long long uptime0[3] = {0, 0, 0};
50
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. */
53
54 /* Structure used to save CPU stats */
55 struct stats_cpu *st_cpu[3];
56 /*
57  * Structure used to save total number of interrupts received
58  * among all CPU and for each CPU.
59  */
60 struct stats_irq *st_irq[3];
61 /*
62  * Structures used to save, for each interrupt, the number
63  * received by each CPU.
64  */
65 struct stats_irqcpu *st_irqcpu[3];
66 struct stats_irqcpu *st_softirqcpu[3];
67
68 struct tm mp_tstamp[3];
69
70 /* Activity flag */
71 unsigned int actflags = 0;
72
73 unsigned int flags = 0;
74
75 /* Interval and count parameters */
76 long interval = -1, count = 0;
77
78 /* Nb of processors on the machine */
79 int cpu_nr = 0;
80 /* Nb of interrupts per processor */
81 int irqcpu_nr = 0;
82 /* Nb of soft interrupts per processor */
83 int softirqcpu_nr = 0;
84
85 struct sigaction alrm_act, int_act;
86 int sigint_caught = 0;
87
88 /*
89  ***************************************************************************
90  * Print usage and exit
91  *
92  * IN:
93  * @progname    Name of sysstat command
94  ***************************************************************************
95  */
96 void usage(char *progname)
97 {
98         fprintf(stderr, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
99                 progname);
100
101         fprintf(stderr, _("Options are:\n"
102                           "[ -A ] [ -u ] [ -V ] [ -I { SUM | CPU | SCPU | ALL } ]\n"
103                           "[ -o JSON ] [ -P { <cpu> [,...] | ON | ALL } ]\n"));
104         exit(1);
105 }
106
107 /*
108  ***************************************************************************
109  * SIGALRM signal handler. No need to reset the handler here.
110  *
111  * IN:
112  * @sig Signal number.
113  ***************************************************************************
114  */
115 void alarm_handler(int sig)
116 {
117         alarm(interval);
118 }
119
120 /*
121  ***************************************************************************
122  * SIGINT signal handler.
123  *
124  * IN:
125  * @sig Signal number.
126  **************************************************************************
127  */
128 void int_handler(int sig)
129 {
130         sigint_caught = 1;
131 }
132
133 /*
134  ***************************************************************************
135  * Allocate stats structures and cpu bitmap.
136  *
137  * IN:
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  ***************************************************************************
141  */
142 void salloc_mp_struct(int nr_cpus)
143 {
144         int i;
145
146         for (i = 0; i < 3; i++) {
147
148                 if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
149                     == NULL) {
150                         perror("malloc");
151                         exit(4);
152                 }
153                 memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
154
155                 if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
156                     == NULL) {
157                         perror("malloc");
158                         exit(4);
159                 }
160                 memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
161
162                 if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
163                     == NULL) {
164                         perror("malloc");
165                         exit(4);
166                 }
167                 memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
168
169                 if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
170                      == NULL) {
171                         perror("malloc");
172                         exit(4);
173                 }
174                 memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
175         }
176
177         if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
178                 perror("malloc");
179                 exit(4);
180         }
181         memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
182 }
183
184 /*
185  ***************************************************************************
186  * Free structures and bitmap.
187  ***************************************************************************
188  */
189 void sfree_mp_struct(void)
190 {
191         int i;
192
193         for (i = 0; i < 3; i++) {
194                 free(st_cpu[i]);
195                 free(st_irq[i]);
196                 free(st_irqcpu[i]);
197                 free(st_softirqcpu[i]);
198         }
199
200         free(cpu_bitmap);
201 }
202
203 /*
204  ***************************************************************************
205  * Display CPU statistics in plain format.
206  *
207  * IN:
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  ***************************************************************************
221  */
222 void write_plain_cpu_stats(int dis, unsigned long long g_itv, int prev, int curr,
223                            char *prev_string, char *curr_string)
224 {
225         struct stats_cpu *scc, *scp;
226         unsigned long long pc_itv;
227         int cpu;
228
229         if (dis) {
230                 printf("\n%-11s  CPU    %%usr   %%nice    %%sys %%iowait    %%irq   "
231                        "%%soft  %%steal  %%guest  %%gnice   %%idle\n",
232                        prev_string);
233         }
234
235         /* Check if we want global stats among all proc */
236         if (*cpu_bitmap & 1) {
237
238                 printf("%-11s", curr_string);
239                 cprintf_in(IS_STR, " %s", " all", 0);
240
241                 cprintf_pc(10, 7, 2,
242                            (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
243                            (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
244                            0.0 :
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,
247                                        g_itv),
248                            (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
249                            (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
250                            0.0 :
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,
253                                        g_itv),
254                            ll_sp_value(st_cpu[prev]->cpu_sys,
255                                        st_cpu[curr]->cpu_sys,
256                                        g_itv),
257                            ll_sp_value(st_cpu[prev]->cpu_iowait,
258                                        st_cpu[curr]->cpu_iowait,
259                                        g_itv),
260                            ll_sp_value(st_cpu[prev]->cpu_hardirq,
261                                        st_cpu[curr]->cpu_hardirq,
262                                        g_itv),
263                            ll_sp_value(st_cpu[prev]->cpu_softirq,
264                                        st_cpu[curr]->cpu_softirq,
265                                        g_itv),
266                            ll_sp_value(st_cpu[prev]->cpu_steal,
267                                        st_cpu[curr]->cpu_steal,
268                                        g_itv),
269                            ll_sp_value(st_cpu[prev]->cpu_guest,
270                                        st_cpu[curr]->cpu_guest,
271                                        g_itv),
272                            ll_sp_value(st_cpu[prev]->cpu_guest_nice,
273                                        st_cpu[curr]->cpu_guest_nice,
274                                        g_itv),
275                            (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
276                            0.0 :
277                            ll_sp_value(st_cpu[prev]->cpu_idle,
278                                        st_cpu[curr]->cpu_idle,
279                                        g_itv));
280                 printf("\n");
281         }
282
283         for (cpu = 1; cpu <= cpu_nr; cpu++) {
284
285                 scc = st_cpu[curr] + cpu;
286                 scp = st_cpu[prev] + cpu;
287
288                 /* Check if we want stats about this proc */
289                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
290                         continue;
291
292                 /*
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
296                  * user/nice modes.)
297                  */
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) {
301
302                         if (!DISPLAY_ONLINE_CPU(flags)) {
303                                 printf("%-11s", curr_string);
304                                 cprintf_in(IS_INT, " %4d", "", cpu - 1);
305                                 cprintf_pc(10, 7, 2,
306                                            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
307                                 printf("\n");
308                         }
309                         continue;
310                 }
311
312                 printf("%-11s", curr_string);
313                 cprintf_in(IS_INT, " %4d", "", cpu - 1);
314
315                 /* Recalculate itv for current proc */
316                 pc_itv = get_per_cpu_interval(scc, scp);
317
318                 if (!pc_itv) {
319                         /*
320                          * If the CPU is tickless then there is no change in CPU values
321                          * but the sum of values is not zero.
322                          */
323                         cprintf_pc(10, 7, 2,
324                                    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
325                         printf("\n");
326                 }
327
328                 else {
329                         cprintf_pc(10, 7, 2,
330                                    (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
331                                    0.0 :
332                                    ll_sp_value(scp->cpu_user - scp->cpu_guest,
333                                                scc->cpu_user - scc->cpu_guest,
334                                                pc_itv),
335                                    (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
336                                    0.0 :
337                                    ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
338                                                scc->cpu_nice - scc->cpu_guest_nice,
339                                                pc_itv),
340                                    ll_sp_value(scp->cpu_sys,
341                                                scc->cpu_sys,
342                                                pc_itv),
343                                    ll_sp_value(scp->cpu_iowait,
344                                                scc->cpu_iowait,
345                                                pc_itv),
346                                    ll_sp_value(scp->cpu_hardirq,
347                                                scc->cpu_hardirq,
348                                                pc_itv),
349                                    ll_sp_value(scp->cpu_softirq,
350                                                scc->cpu_softirq,
351                                                pc_itv),
352                                    ll_sp_value(scp->cpu_steal,
353                                                scc->cpu_steal,
354                                                pc_itv),
355                                    ll_sp_value(scp->cpu_guest,
356                                                scc->cpu_guest,
357                                                pc_itv),
358                                    ll_sp_value(scp->cpu_guest_nice,
359                                                scc->cpu_guest_nice,
360                                                pc_itv),
361                                    (scc->cpu_idle < scp->cpu_idle) ?
362                                    0.0 :
363                                    ll_sp_value(scp->cpu_idle,
364                                                scc->cpu_idle,
365                                                pc_itv));
366                         printf("\n");
367                 }
368         }
369 }
370
371 /*
372  ***************************************************************************
373  * Display CPU statistics in JSON format.
374  *
375  * IN:
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  ***************************************************************************
385  */
386 void write_json_cpu_stats(int tab, unsigned long long g_itv, int prev, int curr,
387                           char *curr_string)
388 {
389         struct stats_cpu *scc, *scp;
390         unsigned long long pc_itv;
391         int cpu, next = FALSE;
392
393         xprintf(tab++, "\"cpu-load\": [");
394
395         /* Check if we want global stats among all proc */
396         if (*cpu_bitmap & 1) {
397
398                 next = TRUE;
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) ?
404                          0.0 :
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,
407                                      g_itv),
408                          (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
409                          (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
410                          0.0 :
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,
413                                      g_itv),
414                          ll_sp_value(st_cpu[prev]->cpu_sys,
415                                      st_cpu[curr]->cpu_sys,
416                                      g_itv),
417                          ll_sp_value(st_cpu[prev]->cpu_iowait,
418                                      st_cpu[curr]->cpu_iowait,
419                                      g_itv),
420                          ll_sp_value(st_cpu[prev]->cpu_hardirq,
421                                      st_cpu[curr]->cpu_hardirq,
422                                      g_itv),
423                          ll_sp_value(st_cpu[prev]->cpu_softirq,
424                                      st_cpu[curr]->cpu_softirq,
425                                      g_itv),
426                          ll_sp_value(st_cpu[prev]->cpu_steal,
427                                      st_cpu[curr]->cpu_steal,
428                                      g_itv),
429                          ll_sp_value(st_cpu[prev]->cpu_guest,
430                                      st_cpu[curr]->cpu_guest,
431                                      g_itv),
432                          ll_sp_value(st_cpu[prev]->cpu_guest_nice,
433                                      st_cpu[curr]->cpu_guest_nice,
434                                      g_itv),
435                          (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
436                          0.0 :
437                          ll_sp_value(st_cpu[prev]->cpu_idle,
438                                      st_cpu[curr]->cpu_idle,
439                                      g_itv));
440         }
441
442         for (cpu = 1; cpu <= cpu_nr; cpu++) {
443
444                 scc = st_cpu[curr] + cpu;
445                 scp = st_cpu[prev] + cpu;
446
447                 /* Check if we want stats about this proc */
448                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
449                         continue;
450
451                 if (next) {
452                         printf(",\n");
453                 }
454                 next = TRUE;
455
456                 /*
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
460                  * user/nice modes.)
461                  */
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) {
465
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);
471                         }
472                         continue;
473                 }
474
475                 /* Recalculate itv for current proc */
476                 pc_itv = get_per_cpu_interval(scc, scp);
477
478                 if (!pc_itv) {
479                         /*
480                          * If the CPU is tickless then there is no change in CPU values
481                          * but the sum of values is not zero.
482                          */
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);
487                 }
488
489                 else {
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) ?
494                                  0.0 :
495                                  ll_sp_value(scp->cpu_user - scp->cpu_guest,
496                                              scc->cpu_user - scc->cpu_guest,
497                                              pc_itv),
498                                  (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
499                                  0.0 :
500                                  ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
501                                              scc->cpu_nice - scc->cpu_guest_nice,
502                                              pc_itv),
503                                  ll_sp_value(scp->cpu_sys,
504                                              scc->cpu_sys,
505                                              pc_itv),
506                                  ll_sp_value(scp->cpu_iowait,
507                                              scc->cpu_iowait,
508                                              pc_itv),
509                                  ll_sp_value(scp->cpu_hardirq,
510                                              scc->cpu_hardirq,
511                                              pc_itv),
512                                  ll_sp_value(scp->cpu_softirq,
513                                              scc->cpu_softirq,
514                                              pc_itv),
515                                  ll_sp_value(scp->cpu_steal,
516                                              scc->cpu_steal,
517                                              pc_itv),
518                                  ll_sp_value(scp->cpu_guest,
519                                              scc->cpu_guest,
520                                              pc_itv),
521                                  ll_sp_value(scp->cpu_guest_nice,
522                                              scc->cpu_guest_nice,
523                                              pc_itv),
524                                  (scc->cpu_idle < scp->cpu_idle) ?
525                                  0.0 :
526                                  ll_sp_value(scp->cpu_idle,
527                                              scc->cpu_idle,
528                                              pc_itv));
529                 }
530         }
531         printf("\n");
532         xprintf0(--tab, "]");
533 }
534
535 /*
536  ***************************************************************************
537  * Display CPU statistics in plain or JSON format.
538  *
539  * IN:
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
554  *              only).
555  ***************************************************************************
556  */
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)
559 {
560         if (DISPLAY_JSON_OUTPUT(flags)) {
561                 if (*next) {
562                         printf(",\n");
563                 }
564                 *next = TRUE;
565                 write_json_cpu_stats(tab, g_itv, prev, curr, curr_string);
566         }
567         else {
568                 write_plain_cpu_stats(dis, g_itv, prev, curr, prev_string, curr_string);
569         }
570 }
571
572 /*
573  ***************************************************************************
574  * Display total number of interrupts per CPU in plain format.
575  *
576  * IN:
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  ***************************************************************************
590  */
591 void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
592                                char *prev_string, char *curr_string)
593 {
594         struct stats_cpu *scc, *scp;
595         struct stats_irq *sic, *sip;
596         unsigned long long pc_itv;
597         int cpu;
598
599         if (dis) {
600                 printf("\n%-11s  CPU    intr/s\n", prev_string);
601                 }
602
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 */
607                 cprintf_f(1, 9, 2,
608                           S_VALUE(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv));
609                 printf("\n");
610         }
611
612         for (cpu = 1; cpu <= cpu_nr; cpu++) {
613
614                 sic = st_irq[curr] + cpu;
615                 sip = st_irq[prev] + cpu;
616
617                 scc = st_cpu[curr] + cpu;
618                 scp = st_cpu[prev] + cpu;
619
620                 /* Check if we want stats about this CPU */
621                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
622                         continue;
623
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) {
627
628                         /* This is an offline CPU */
629
630                         if (!DISPLAY_ONLINE_CPU(flags)) {
631                                 /*
632                                  * Display offline CPU if requested by the user.
633                                  * Value displayed is 0.00.
634                                  */
635                                 printf("%-11s", curr_string);
636                                 cprintf_in(IS_INT, " %4d", "", cpu - 1);
637                                 cprintf_f(1, 9, 2, 0.0);
638                                 printf("\n");
639                         }
640                         continue;
641                 }
642
643                 printf("%-11s", curr_string);
644                 cprintf_in(IS_INT, " %4d", "", cpu - 1);
645
646                 /* Recalculate itv for current proc */
647                 pc_itv = get_per_cpu_interval(scc, scp);
648
649                 if (!pc_itv) {
650                         /* This is a tickless CPU: Value displayed is 0.00 */
651                         cprintf_f(1, 9, 2, 0.0);
652                         printf("\n");
653                 }
654                 else {
655                         /* Display total number of interrupts for current CPU */
656                         cprintf_f(1, 9, 2,
657                                   S_VALUE(sip->irq_nr, sic->irq_nr, itv));
658                         printf("\n");
659                 }
660         }
661 }
662
663 /*
664  ***************************************************************************
665  * Display total number of interrupts per CPU in JSON format.
666  *
667  * IN:
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  ***************************************************************************
677  */
678 void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr,
679                               char *curr_string)
680 {
681         struct stats_cpu *scc, *scp;
682         struct stats_irq *sic, *sip;
683         unsigned long long pc_itv;
684         int cpu, next = FALSE;
685
686         xprintf(tab++, "\"sum-interrupts\": [");
687
688         if (*cpu_bitmap & 1) {
689
690                 next = TRUE;
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));
694         }
695
696         for (cpu = 1; cpu <= cpu_nr; cpu++) {
697
698                 sic = st_irq[curr] + cpu;
699                 sip = st_irq[prev] + cpu;
700
701                 scc = st_cpu[curr] + cpu;
702                 scp = st_cpu[prev] + cpu;
703
704                 /* Check if we want stats about this CPU */
705                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
706                         continue;
707
708                 if (next) {
709                         printf(",\n");
710                 }
711                 next = TRUE;
712
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) {
716
717                         /* This is an offline CPU */
718
719                         if (!DISPLAY_ONLINE_CPU(flags)) {
720                                 /*
721                                  * Display offline CPU if requested by the user.
722                                  * Value displayed is 0.00.
723                                  */
724                                 xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
725                                          cpu - 1);
726                         }
727                         continue;
728                 }
729
730                 /* Recalculate itv for current proc */
731                 pc_itv = get_per_cpu_interval(scc, scp);
732
733                 if (!pc_itv) {
734                         /* This is a tickless CPU: Value displayed is 0.00 */
735                         xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
736                                  cpu - 1);
737                 }
738                 else {
739                         /* Display total number of interrupts for current CPU */
740                         xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": %.2f}",
741                                  cpu - 1,
742                                  S_VALUE(sip->irq_nr, sic->irq_nr, itv));
743                 }
744         }
745         printf("\n");
746         xprintf0(--tab, "]");
747 }
748
749 /*
750  ***************************************************************************
751  * Display total number of interrupts per CPU in plain or JSON format.
752  *
753  * IN:
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
768  *              only).
769  ***************************************************************************
770  */
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)
773 {
774         if (DISPLAY_JSON_OUTPUT(flags)) {
775                 if (*next) {
776                         printf(",\n");
777                 }
778                 *next = TRUE;
779                 write_json_isumcpu_stats(tab, itv, prev, curr, curr_string);
780         }
781         else {
782                 write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
783         }
784 }
785
786 /*
787  ***************************************************************************
788  * Display interrupts statistics for each CPU in plain format.
789  *
790  * IN:
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  ***************************************************************************
806  */
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)
810 {
811         struct stats_cpu *scc;
812         int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
813         struct stats_irqcpu *p, *q, *p0, *q0;
814
815         /*
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.
820          */
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))
826                                 /*
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.
831                                  */
832                                 break;
833                 }
834         }
835
836         if (dis || (j < ic_nr)) {
837                 /* Print header */
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 */
843                                 break;
844                         printf(" %8s/s", p0->irq_name);
845                 }
846                 printf("\n");
847         }
848
849         /* Calculate column widths */
850         for (j = 0; j < ic_nr; j++) {
851                 p0 = st_ic[curr] + j;
852                 /*
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.
856                  */
857                 colwidth[j] = strlen(p0->irq_name) + 2;
858                 /*
859                  * Normal space for printing a number is 11 chars
860                  * (space + 10 digits including the period).
861                  */
862                 if (colwidth[j] < 10) {
863                         colwidth[j] = 10;
864                 }
865         }
866
867         for (cpu = 1; cpu <= cpu_nr; cpu++) {
868
869                 scc = st_cpu[curr] + cpu;
870
871                 /*
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.
875                  */
876                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
877                         continue;
878
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) {
882
883                         /* Offline CPU found */
884
885                         if (DISPLAY_ONLINE_CPU(flags))
886                                 continue;
887                 }
888
889                 printf("%-11s", curr_string);
890                 cprintf_in(IS_INT, "  %3d", "", cpu - 1);
891
892                 for (j = 0; j < ic_nr; j++) {
893                         p0 = st_ic[curr] + j;   /* irq_name set only for CPU#0 */
894                         /*
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.
898                          */
899                         if (p0->irq_name[0] == '\0')
900                                 /* End of the list of interrupts */
901                                 break;
902                         q0 = st_ic[prev] + j;
903                         offset = j;
904
905                         /*
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.
909                          */
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 */
916                                                 break;
917                                 }
918                         }
919
920                         p = st_ic[curr] + (cpu - 1) * ic_nr + j;
921
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));
926                         }
927                         else {
928                                 /*
929                                  * Instead of printing "N/A", assume that previous value
930                                  * for this new interrupt was zero.
931                                  */
932                                 cprintf_f(1, colwidth[j], 2,
933                                           S_VALUE(0, p->interrupt, itv));
934                         }
935                 }
936                 printf("\n");
937         }
938 }
939
940 /*
941  ***************************************************************************
942  * Display interrupts statistics for each CPU in JSON format.
943  *
944  * IN:
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  ***************************************************************************
957  */
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)
961 {
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;
966
967         if (type == M_D_IRQ_CPU) {
968                 xprintf(tab++, "\"individual-interrupts\": [");
969         }
970         else {
971                 xprintf(tab++, "\"soft-interrupts\": [");
972         }
973
974         for (cpu = 1; cpu <= cpu_nr; cpu++) {
975
976                 scc = st_cpu[curr] + cpu;
977
978                 /*
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.
982                  */
983                 if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
984                         continue;
985
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) {
989
990                         /* Offline CPU found */
991
992                         if (DISPLAY_ONLINE_CPU(flags))
993                                 continue;
994                 }
995
996                 if (nextcpu) {
997                         printf(",\n");
998                 }
999                 nextcpu = TRUE;
1000                 nextirq = FALSE;
1001                 xprintf(tab++, "{\"cpu\": \"%d\", \"intr\": [", cpu - 1);
1002
1003                 for (j = 0; j < ic_nr; j++) {
1004
1005                         p0 = st_ic[curr] + j;   /* irq_name set only for CPU#0 */
1006                         /*
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.
1010                          */
1011                         if (p0->irq_name[0] == '\0')
1012                                 /* End of the list of interrupts */
1013                                 break;
1014                         q0 = st_ic[prev] + j;
1015                         offset = j;
1016
1017                         if (nextirq) {
1018                                 printf(",\n");
1019                         }
1020                         nextirq = TRUE;
1021
1022                         /*
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.
1026                          */
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 */
1033                                                 break;
1034                                 }
1035                         }
1036
1037                         p = st_ic[curr] + (cpu - 1) * ic_nr + j;
1038
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}",
1042                                          p0->irq_name,
1043                                          S_VALUE(q->interrupt, p->interrupt, itv));
1044                         }
1045                         else {
1046                                 /*
1047                                  * Instead of printing "N/A", assume that previous value
1048                                  * for this new interrupt was zero.
1049                                  */
1050                                 xprintf0(tab, "{\"name\": \"%s\", \"value\": %.2f}",
1051                                          p0->irq_name,
1052                                          S_VALUE(0, p->interrupt, itv));
1053                         }
1054                 }
1055                 printf("\n");
1056                 xprintf0(--tab, "] }");
1057         }
1058         printf("\n");
1059         xprintf0(--tab, "]");
1060 }
1061
1062 /*
1063  ***************************************************************************
1064  * Display interrupts statistics for each CPU in plain or JSON format.
1065  *
1066  * IN:
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
1083  *              only).
1084  * @type        Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
1085  ***************************************************************************
1086  */
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)
1091 {
1092         if (DISPLAY_JSON_OUTPUT(flags)) {
1093                 if (*next) {
1094                         printf(",\n");
1095                 }
1096                 *next = TRUE;
1097                 write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr,
1098                                         curr_string, type);
1099         }
1100         else {
1101                 write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
1102                                          prev_string, curr_string);
1103         }
1104 }
1105
1106 /*
1107  ***************************************************************************
1108  * Core function used to display statistics.
1109  *
1110  * IN:
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  ***************************************************************************
1123  */
1124 void write_stats_core(int prev, int curr, int dis,
1125                       char *prev_string, char *curr_string)
1126 {
1127         struct stats_cpu *scc, *scp;
1128         unsigned long long itv, g_itv;
1129         int cpu, tab = 4, next = FALSE;
1130
1131         /* Test stdout */
1132         TEST_STDOUT(STDOUT_FILENO);
1133
1134         if (DISPLAY_JSON_OUTPUT(flags)) {
1135                 xprintf(tab++, "{");
1136                 xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
1137         }
1138
1139         /* Compute time interval */
1140         g_itv = get_interval(uptime[prev], uptime[curr]);
1141
1142         /* Reduce interval value to one processor */
1143         if (cpu_nr > 1) {
1144                 itv = get_interval(uptime0[prev], uptime0[curr]);
1145         }
1146         else {
1147                 itv = g_itv;
1148         }
1149
1150         /* Print CPU stats */
1151         if (DISPLAY_CPU(actflags)) {
1152                 write_cpu_stats(dis, g_itv, prev, curr, prev_string, curr_string,
1153                                 tab, &next);
1154         }
1155
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,
1159                                     tab, &next);
1160         }
1161
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);
1166         }
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);
1170         }
1171
1172         if (DISPLAY_JSON_OUTPUT(flags)) {
1173                 printf("\n");
1174                 xprintf0(--tab, "}");
1175         }
1176
1177         /* Fix CPU counter values for every offline CPU */
1178         for (cpu = 1; cpu <= cpu_nr; cpu++) {
1179
1180                 scc = st_cpu[curr] + cpu;
1181                 scp = st_cpu[prev] + cpu;
1182
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) {
1186                         /*
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.
1191                          */
1192                         *scc = *scp;
1193                 }
1194         }
1195 }
1196
1197 /*
1198  ***************************************************************************
1199  * Print statistics average.
1200  *
1201  * IN:
1202  * @curr        Position in array where statistics for current sample are.
1203  * @dis         TRUE if a header line must be printed.
1204  ***************************************************************************
1205  */
1206 void write_stats_avg(int curr, int dis)
1207 {
1208         char string[16];
1209
1210         strncpy(string, _("Average:"), 16);
1211         string[15] = '\0';
1212         write_stats_core(2, curr, dis, string, string);
1213 }
1214
1215 /*
1216  ***************************************************************************
1217  * Print statistics.
1218  *
1219  * IN:
1220  * @curr        Position in array where statistics for current sample are.
1221  * @dis         TRUE if a header line must be printed.
1222  ***************************************************************************
1223  */
1224 void write_stats(int curr, int dis)
1225 {
1226         char cur_time[2][16];
1227
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]);
1231         }
1232         else {
1233                 strftime(cur_time[!curr], sizeof(cur_time[!curr]), "%X", &(mp_tstamp[!curr]));
1234         }
1235
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]);
1239         }
1240         else {
1241                 strftime(cur_time[curr], sizeof(cur_time[curr]), "%X", &(mp_tstamp[curr]));
1242         }
1243
1244         write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]);
1245 }
1246
1247 /*
1248  ***************************************************************************
1249  * Read stats from /proc/interrupts or /proc/softirqs.
1250  *
1251  * IN:
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.
1255  *
1256  * OUT:
1257  * @st_ic       Array for per-CPU interrupts statistics.
1258  ***************************************************************************
1259  */
1260 void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
1261 {
1262         FILE *fp;
1263         struct stats_irq *st_irq_i;
1264         struct stats_irqcpu *p;
1265         char *line = NULL, *li;
1266         unsigned long irq = 0;
1267         unsigned int cpu;
1268         int cpu_index[cpu_nr], index = 0, len;
1269         char *cp, *next;
1270
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;
1275         }
1276
1277         if ((fp = fopen(file, "r")) != NULL) {
1278
1279                 SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
1280
1281                 /*
1282                  * Parse header line to see which CPUs are online
1283                  */
1284                 while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
1285                         next = line;
1286                         while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
1287                                 cpu = strtol(cp + 3, &next, 10);
1288                                 cpu_index[index++] = cpu;
1289                         }
1290                         if (index)
1291                                 /* Header line found */
1292                                 break;
1293                 }
1294
1295                 /* Parse each line of interrupts statistics data */
1296                 while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
1297                        (irq < ic_nr)) {
1298
1299                         /* Skip over "<irq>:" */
1300                         if ((cp = strchr(line, ':')) == NULL)
1301                                 /* Chr ':' not found */
1302                                 continue;
1303                         cp++;
1304
1305                         p = st_ic[curr] + irq;
1306
1307                         /* Remove possible heading spaces in interrupt's name... */
1308                         li = line;
1309                         while (*li == ' ')
1310                                 li++;
1311
1312                         len = strcspn(li, ":");
1313                         if (len >= MAX_IRQ_LEN) {
1314                                 len = MAX_IRQ_LEN - 1;
1315                         }
1316                         /* ...then save its name */
1317                         strncpy(p->irq_name, li, len);
1318                         p->irq_name[len] = '\0';
1319
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;
1324                                 /*
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).
1329                                  */
1330                                 p->interrupt = strtoul(cp, &next, 10);
1331                                 st_irq_i->irq_nr += p->interrupt;
1332                                 cp = next;
1333                         }
1334                         irq++;
1335                 }
1336
1337                 fclose(fp);
1338
1339                 free(line);
1340         }
1341
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 */
1346                 irq++;
1347         }
1348 }
1349
1350 /*
1351  ***************************************************************************
1352  * Main loop: Read stats from the relevant sources, and display them.
1353  *
1354  * IN:
1355  * @dis_hdr     Set to TRUE if the header line must always be printed.
1356  * @rows        Number of rows of screen.
1357  ***************************************************************************
1358  */
1359 void rw_mpstat_loop(int dis_hdr, int rows)
1360 {
1361         struct stats_cpu *scc;
1362         int cpu;
1363         int curr = 1, dis = 1;
1364         unsigned long lines = rows;
1365
1366         /* Dont buffer data if redirected to a pipe */
1367         setbuf(stdout, NULL);
1368
1369         /* Read uptime and CPU stats */
1370         if (cpu_nr > 1) {
1371                 /*
1372                  * Init uptime0. So if /proc/uptime cannot fill it,
1373                  * this will be done by /proc/stat.
1374                  */
1375                 uptime0[0] = 0;
1376                 read_uptime(&(uptime0[0]));
1377         }
1378         read_stat_cpu(st_cpu[0], cpu_nr + 1, &(uptime[0]), &(uptime0[0]));
1379
1380         /*
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).
1383          */
1384         if (DISPLAY_IRQ_SUM(actflags)) {
1385                 read_stat_irq(st_irq[0], 1);
1386         }
1387
1388         /*
1389          * Read number of interrupts received by each CPU, for each interrupt,
1390          * and compute the total number of interrupts received by each CPU.
1391          */
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);
1395         }
1396         if (DISPLAY_SOFTIRQS(actflags)) {
1397                 read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
1398         }
1399
1400         if (!interval) {
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);
1408                 }
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");
1412                 }
1413                 exit(0);
1414         }
1415
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);
1420         alarm(interval);
1421
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);
1432         }
1433
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);
1439         }
1440
1441         pause();
1442
1443         if (sigint_caught)
1444                 /* SIGINT signal caught during first interval: Exit immediately */
1445                 return;
1446
1447         do {
1448                 /*
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.
1453                  */
1454                 for (cpu = 1; cpu <= cpu_nr; cpu++) {
1455                         scc = st_cpu[curr] + cpu;
1456                         memset(scc, 0, STATS_CPU_SIZE);
1457                 }
1458
1459                 /* Get time */
1460                 get_localtime(&(mp_tstamp[curr]), 0);
1461
1462                 /* Read uptime and CPU stats */
1463                 if (cpu_nr > 1) {
1464                         uptime0[curr] = 0;
1465                         read_uptime(&(uptime0[curr]));
1466                 }
1467                 read_stat_cpu(st_cpu[curr], cpu_nr + 1, &(uptime[curr]), &(uptime0[curr]));
1468
1469                 /* Read total number of interrupts received among all CPU */
1470                 if (DISPLAY_IRQ_SUM(actflags)) {
1471                         read_stat_irq(st_irq[curr], 1);
1472                 }
1473
1474                 /*
1475                  * Read number of interrupts received by each CPU, for each interrupt,
1476                  * and compute the total number of interrupts received by each CPU.
1477                  */
1478                 if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
1479                         read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
1480                 }
1481                 if (DISPLAY_SOFTIRQS(actflags)) {
1482                         read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
1483                 }
1484
1485                 /* Write stats */
1486                 if (!dis_hdr) {
1487                         dis = lines / rows;
1488                         if (dis) {
1489                                 lines %= rows;
1490                         }
1491                         lines++;
1492                 }
1493                 write_stats(curr, dis);
1494
1495                 if (count > 0) {
1496                         count--;
1497                 }
1498
1499                 if (count) {
1500
1501                         if (DISPLAY_JSON_OUTPUT(flags)) {
1502                                 printf(",\n");
1503                         }
1504                         pause();
1505
1506                         if (sigint_caught) {
1507                                 /* SIGINT signal caught => Display average stats */
1508                                 count = 0;
1509                                 printf("\n");   /* Skip "^C" displayed on screen */
1510                         }
1511                         else {
1512                                 curr ^= 1;
1513                         }
1514                 }
1515         }
1516         while (count);
1517
1518         /* Write stats average */
1519         if (DISPLAY_JSON_OUTPUT(flags)) {
1520                 printf("\n\t\t\t]\n\t\t}\n\t]\n}}\n");
1521         }
1522         else {
1523                 write_stats_avg(curr, dis_hdr);
1524         }
1525 }
1526
1527 /*
1528  ***************************************************************************
1529  * Main entry to the program
1530  ***************************************************************************
1531  */
1532 int main(int argc, char **argv)
1533 {
1534         int opt = 0, i, actset = FALSE;
1535         struct utsname header;
1536         int dis_hdr = -1;
1537         int rows = 23;
1538         char *t;
1539
1540 #ifdef USE_NLS
1541         /* Init National Language Support */
1542         init_nls();
1543 #endif
1544
1545         /* Init color strings */
1546         init_colors();
1547
1548         /* Get HZ */
1549         get_HZ();
1550
1551         /* What is the highest processor number on this machine? */
1552         cpu_nr = get_cpu_nr(~0, TRUE);
1553
1554         /* Calculate number of interrupts per processor */
1555         irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
1556                     NR_IRQCPU_PREALLOC;
1557         /* Calculate number of soft interrupts per processor */
1558         softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
1559                         NR_IRQCPU_PREALLOC;
1560
1561         /*
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.
1564          */
1565         salloc_mp_struct(cpu_nr + 1);
1566
1567         while (++opt < argc) {
1568
1569                 if (!strcmp(argv[opt], "-I")) {
1570                         if (argv[++opt]) {
1571                                 actset = TRUE;
1572
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;
1577                                         }
1578                                         else if (!strcmp(t, K_CPU)) {
1579                                                 /* Display interrupts per CPU */
1580                                                 actflags |= M_D_IRQ_CPU;
1581                                         }
1582                                         else if (!strcmp(t, K_SCPU)) {
1583                                                 /* Display soft interrupts per CPU */
1584                                                 actflags |= M_D_SOFTIRQS;
1585                                         }
1586                                         else if (!strcmp(t, K_ALL)) {
1587                                                 actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
1588                                         }
1589                                         else {
1590                                                 usage(argv[0]);
1591                                         }
1592                                 }
1593                         }
1594                         else {
1595                                 usage(argv[0]);
1596                         }
1597                 }
1598
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;
1603                         }
1604                         else {
1605                                 usage(argv[0]);
1606                         }
1607                 }
1608
1609                 else if (!strcmp(argv[opt], "-P")) {
1610                         /* '-P ALL' can be used on UP machines */
1611                         if (argv[++opt]) {
1612                                 flags |= F_P_OPTION;
1613                                 dis_hdr++;
1614
1615                                 for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) {
1616                                         if (!strcmp(t, K_ALL) || !strcmp(t, K_ON)) {
1617                                                 if (cpu_nr) {
1618                                                         dis_hdr = 9;
1619                                                 }
1620                                                 /*
1621                                                  * Set bit for every processor.
1622                                                  * Also indicate to display stats for CPU 'all'.
1623                                                  */
1624                                                 memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
1625                                                 if (!strcmp(t, K_ON)) {
1626                                                         /* Display stats only for online CPU */
1627                                                         flags |= F_P_ON;
1628                                                 }
1629                                         }
1630                                         else {
1631                                                 if (strspn(t, DIGITS) != strlen(t)) {
1632                                                         usage(argv[0]);
1633                                                 }
1634                                                 i = atoi(t);    /* Get cpu number */
1635                                                 if (i >= cpu_nr) {
1636                                                         fprintf(stderr, _("Not that many processors!\n"));
1637                                                         exit(1);
1638                                                 }
1639                                                 i++;
1640                                                 *(cpu_bitmap + (i >> 3)) |= 1 << (i & 0x07);
1641                                         }
1642                                 }
1643                         }
1644                         else {
1645                                 usage(argv[0]);
1646                         }
1647                 }
1648
1649                 else if (!strncmp(argv[opt], "-", 1)) {
1650                         for (i = 1; *(argv[opt] + i); i++) {
1651
1652                                 switch (*(argv[opt] + i)) {
1653
1654                                 case 'A':
1655                                         actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
1656                                         actset = TRUE;
1657                                         /* Select all processors */
1658                                         flags |= F_P_OPTION;
1659                                         memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
1660                                         break;
1661
1662                                 case 'u':
1663                                         /* Display CPU */
1664                                         actflags |= M_D_CPU;
1665                                         break;
1666
1667                                 case 'V':
1668                                         /* Print version number */
1669                                         print_version();
1670                                         break;
1671
1672                                 default:
1673                                         usage(argv[0]);
1674                                 }
1675                         }
1676                 }
1677
1678                 else if (interval < 0) {
1679                         /* Get interval */
1680                         if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
1681                                 usage(argv[0]);
1682                         }
1683                         interval = atol(argv[opt]);
1684                         if (interval < 0) {
1685                                 usage(argv[0]);
1686                         }
1687                         count = -1;
1688                 }
1689
1690                 else if (count <= 0) {
1691                         /* Get count value */
1692                         if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
1693                             !interval) {
1694                                 usage(argv[0]);
1695                         }
1696                         count = atol(argv[opt]);
1697                         if (count < 1) {
1698                                 usage(argv[0]);
1699                         }
1700                 }
1701
1702                 else {
1703                         usage(argv[0]);
1704                 }
1705         }
1706
1707         /* Default: Display CPU */
1708         if (!actset) {
1709                 actflags |= M_D_CPU;
1710         }
1711
1712         if (count_bits(&actflags, sizeof(unsigned int)) > 1) {
1713                 dis_hdr = 9;
1714         }
1715
1716         if (!USE_P_OPTION(flags)) {
1717                 /* Option -P not used: Set bit 0 (global stats among all proc) */
1718                 *cpu_bitmap = 1;
1719         }
1720         if (dis_hdr < 0) {
1721                 dis_hdr = 0;
1722         }
1723         if (!dis_hdr) {
1724                 /* Get window size */
1725                 rows = get_win_height();
1726         }
1727         if (interval < 0) {
1728                 /* Interval not set => display stats since boot time */
1729                 interval = 0;
1730         }
1731
1732         /* Get time */
1733         get_localtime(&(mp_tstamp[0]), 0);
1734
1735         /* Get system name, release number and hostname */
1736         uname(&header);
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));
1740
1741         /* Main loop */
1742         rw_mpstat_loop(dis_hdr, rows);
1743
1744         /* Free structures */
1745         sfree_mp_struct();
1746
1747         return 0;
1748 }