perfmonger 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +15 -0
  2. data/.dir-locals.el +2 -0
  3. data/.gitignore +4 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +12 -0
  6. data/COPYING +674 -0
  7. data/Gemfile +5 -0
  8. data/HOWTO.md +15 -0
  9. data/NEWS +115 -0
  10. data/README.md +61 -0
  11. data/Rakefile +8 -0
  12. data/bin/perfmonger +6 -0
  13. data/data/NOTICE +8 -0
  14. data/data/Twitter_Bootstrap_LICENSE.txt +176 -0
  15. data/data/assets/css/bootstrap-responsive.css +1109 -0
  16. data/data/assets/css/bootstrap.css +6167 -0
  17. data/data/assets/css/perfmonger.css +17 -0
  18. data/data/assets/dashboard.erb +319 -0
  19. data/data/assets/img/glyphicons-halflings-white.png +0 -0
  20. data/data/assets/img/glyphicons-halflings.png +0 -0
  21. data/data/assets/js/bootstrap.js +2280 -0
  22. data/data/assets/js/bootstrap.min.js +6 -0
  23. data/data/assets/js/canvasjs.js +9042 -0
  24. data/data/assets/js/canvasjs.min.js +271 -0
  25. data/data/sysstat.ioconf +268 -0
  26. data/ext/perfmonger/extconf.rb +19 -0
  27. data/ext/perfmonger/perfmonger.h +58 -0
  28. data/ext/perfmonger/perfmonger_record.c +754 -0
  29. data/ext/perfmonger/sysstat/common.c +627 -0
  30. data/ext/perfmonger/sysstat/common.h +207 -0
  31. data/ext/perfmonger/sysstat/ioconf.c +515 -0
  32. data/ext/perfmonger/sysstat/ioconf.h +84 -0
  33. data/ext/perfmonger/sysstat/iostat.c +1100 -0
  34. data/ext/perfmonger/sysstat/iostat.h +121 -0
  35. data/ext/perfmonger/sysstat/libsysstat.h +19 -0
  36. data/ext/perfmonger/sysstat/mpstat.c +953 -0
  37. data/ext/perfmonger/sysstat/mpstat.h +79 -0
  38. data/ext/perfmonger/sysstat/rd_stats.c +2388 -0
  39. data/ext/perfmonger/sysstat/rd_stats.h +651 -0
  40. data/ext/perfmonger/sysstat/sysconfig.h +13 -0
  41. data/lib/perfmonger/cli.rb +115 -0
  42. data/lib/perfmonger/command/base_command.rb +39 -0
  43. data/lib/perfmonger/command/fingerprint.rb +453 -0
  44. data/lib/perfmonger/command/plot.rb +429 -0
  45. data/lib/perfmonger/command/record.rb +32 -0
  46. data/lib/perfmonger/command/record_option.rb +149 -0
  47. data/lib/perfmonger/command/server.rb +294 -0
  48. data/lib/perfmonger/command/stat.rb +60 -0
  49. data/lib/perfmonger/command/stat_option.rb +29 -0
  50. data/lib/perfmonger/command/summary.rb +402 -0
  51. data/lib/perfmonger/config.rb +6 -0
  52. data/lib/perfmonger/version.rb +5 -0
  53. data/lib/perfmonger.rb +12 -0
  54. data/misc/release-howto.txt +17 -0
  55. data/misc/sample-cpu.png +0 -0
  56. data/misc/sample-read-iops.png +0 -0
  57. data/perfmonger.gemspec +44 -0
  58. data/test/run-test.sh +39 -0
  59. data/test/spec/bin_spec.rb +37 -0
  60. data/test/spec/data/2devices.expected +42 -0
  61. data/test/spec/data/2devices.output +42 -0
  62. data/test/spec/spec_helper.rb +20 -0
  63. data/test/spec/summary_spec.rb +193 -0
  64. data/test/test-perfmonger.c +145 -0
  65. data/test/test.h +9 -0
  66. metadata +154 -0
@@ -0,0 +1,953 @@
1
+ /*
2
+ * mpstat: per-processor statistics
3
+ * (C) 2000-2010 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
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "mpstat.h"
32
+ #include "common.h"
33
+ #include "rd_stats.h"
34
+
35
+ #ifdef USE_NLS
36
+ #include <locale.h>
37
+ #include <libintl.h>
38
+ #define _(string) gettext(string)
39
+ #else
40
+ #define _(string) (string)
41
+ #endif
42
+
43
+ unsigned long long uptime[3] = {0, 0, 0};
44
+ unsigned long long uptime0[3] = {0, 0, 0};
45
+
46
+ /* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
47
+ unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */
48
+
49
+ /* Structures used to store stats */
50
+ struct stats_cpu *st_cpu[3];
51
+ struct stats_irq *st_irq[3];
52
+ struct stats_irqcpu *st_irqcpu[3];
53
+ struct stats_irqcpu *st_softirqcpu[3];
54
+
55
+ struct tm mp_tstamp[3];
56
+
57
+ /* Activity flag */
58
+ unsigned int actflags = 0;
59
+ // unsigned int flags = 0;
60
+
61
+ /* Interval and count parameters */
62
+ extern long interval;
63
+ long count = 0;
64
+
65
+ /* Nb of processors on the machine */
66
+ extern int cpu_nr;
67
+ /* Nb of interrupts per processor */
68
+ int irqcpu_nr = 0;
69
+ /* Nb of soft interrupts per processor */
70
+ int softirqcpu_nr = 0;
71
+
72
+ /*
73
+ ***************************************************************************
74
+ * Allocate stats structures and cpu bitmap.
75
+ *
76
+ * IN:
77
+ * @nr_cpus Number of CPUs. This is the real number of available CPUs + 1
78
+ * because we also have to allocate a structure for CPU 'all'.
79
+ ***************************************************************************
80
+ */
81
+ void salloc_mp_struct(int nr_cpus)
82
+ {
83
+ int i;
84
+
85
+ for (i = 0; i < 3; i++) {
86
+
87
+ if ((st_cpu[i] = (struct stats_cpu *) malloc(STATS_CPU_SIZE * nr_cpus))
88
+ == NULL) {
89
+ perror("malloc");
90
+ exit(4);
91
+ }
92
+ memset(st_cpu[i], 0, STATS_CPU_SIZE * nr_cpus);
93
+
94
+ if ((st_irq[i] = (struct stats_irq *) malloc(STATS_IRQ_SIZE * nr_cpus))
95
+ == NULL) {
96
+ perror("malloc");
97
+ exit(4);
98
+ }
99
+ memset(st_irq[i], 0, STATS_IRQ_SIZE * nr_cpus);
100
+
101
+ if ((st_irqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr))
102
+ == NULL) {
103
+ perror("malloc");
104
+ exit(4);
105
+ }
106
+ memset(st_irqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * irqcpu_nr);
107
+
108
+ if ((st_softirqcpu[i] = (struct stats_irqcpu *) malloc(STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr))
109
+ == NULL) {
110
+ perror("malloc");
111
+ exit(4);
112
+ }
113
+ memset(st_softirqcpu[i], 0, STATS_IRQCPU_SIZE * nr_cpus * softirqcpu_nr);
114
+ }
115
+
116
+ if ((cpu_bitmap = (unsigned char *) malloc((nr_cpus >> 3) + 1)) == NULL) {
117
+ perror("malloc");
118
+ exit(4);
119
+ }
120
+ memset(cpu_bitmap, 0, (nr_cpus >> 3) + 1);
121
+ }
122
+
123
+ /*
124
+ ***************************************************************************
125
+ * Free structures and bitmap.
126
+ ***************************************************************************
127
+ */
128
+ void sfree_mp_struct(void)
129
+ {
130
+ int i;
131
+
132
+ for (i = 0; i < 3; i++) {
133
+
134
+ if (st_cpu[i]) {
135
+ free(st_cpu[i]);
136
+ }
137
+ if (st_irq[i]) {
138
+ free(st_irq[i]);
139
+ }
140
+ if (st_irqcpu[i]) {
141
+ free(st_irqcpu[i]);
142
+ }
143
+ if (st_softirqcpu[i]) {
144
+ free(st_softirqcpu[i]);
145
+ }
146
+ }
147
+
148
+ if (cpu_bitmap) {
149
+ free(cpu_bitmap);
150
+ }
151
+ }
152
+
153
+ /*
154
+ ***************************************************************************
155
+ * Display per CPU statistics.
156
+ *
157
+ * IN:
158
+ * @st_ic Array for per-CPU statistics.
159
+ * @ic_nr Number of interrupts (hard or soft) per CPU.
160
+ * @dis TRUE if a header line must be printed.
161
+ * @itv Interval value.
162
+ * @prev Position in array where statistics used as reference are.
163
+ * Stats used as reference may be the previous ones read, or
164
+ * the very first ones when calculating the average.
165
+ * @curr Position in array where current statistics will be saved.
166
+ * @prev_string String displayed at the beginning of a header line. This is
167
+ * the timestamp of the previous sample, or "Average" when
168
+ * displaying average stats.
169
+ * @curr_string String displayed at the beginning of current sample stats.
170
+ * This is the timestamp of the current sample, or "Average"
171
+ * when displaying average stats.
172
+ ***************************************************************************
173
+ */
174
+ /* void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis, */
175
+ /* unsigned long long itv, int prev, int curr, */
176
+ /* char *prev_string, char *curr_string) */
177
+ /* { */
178
+ /* int j = 0, offset, cpu; */
179
+ /* struct stats_irqcpu *p, *q, *p0, *q0; */
180
+
181
+ /* /\* */
182
+ /* * Check if number of interrupts has changed. */
183
+ /* * NB: A null interval value indicates that we are */
184
+ /* * displaying statistics since system startup. */
185
+ /* *\/ */
186
+ /* if (!dis && interval) { */
187
+ /* do { */
188
+ /* p0 = st_ic[curr] + j; */
189
+ /* if (p0->irq_name[0] != '\0') { */
190
+ /* q0 = st_ic[prev] + j; */
191
+ /* if (strcmp(p0->irq_name, q0->irq_name)) { */
192
+ /* /\* These are two different irq *\/ */
193
+ /* j = -2; */
194
+ /* } */
195
+ /* } */
196
+ /* j++; */
197
+ /* } */
198
+ /* while ((j > 0) && (j <= ic_nr)); */
199
+ /* } */
200
+
201
+ /* if (dis || (j < 0)) { */
202
+ /* /\* Print header *\/ */
203
+ /* printf("\n%-11s CPU", prev_string); */
204
+ /* for (j = 0; j < ic_nr; j++) { */
205
+ /* p0 = st_ic[curr] + j; */
206
+ /* if (p0->irq_name[0] != '\0') { /\* Nb of irq per proc may have varied... *\/ */
207
+ /* printf(" %8s/s", p0->irq_name); */
208
+ /* } */
209
+ /* } */
210
+ /* printf("\n"); */
211
+ /* } */
212
+
213
+ /* for (cpu = 1; cpu <= cpu_nr; cpu++) { */
214
+
215
+ /* /\* */
216
+ /* * Check if we want stats about this CPU. */
217
+ /* * CPU must have been explicitly selected using option -P, */
218
+ /* * else we display every CPU. */
219
+ /* *\/ */
220
+ /* if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags)) */
221
+ /* continue; */
222
+
223
+ /* printf("%-11s %3d", curr_string, cpu - 1); */
224
+
225
+ /* for (j = 0; j < ic_nr; j++) { */
226
+ /* p0 = st_ic[curr] + j; /\* irq field set only for proc #0 *\/ */
227
+ /* /\* */
228
+ /* * An empty string for irq name means it is a remaining interrupt */
229
+ /* * which is no longer used, for example because the */
230
+ /* * number of interrupts has decreased in /proc/interrupts. */
231
+ /* *\/ */
232
+ /* if (p0->irq_name[0] != '\0') { */
233
+ /* q0 = st_ic[prev] + j; */
234
+ /* offset = j; */
235
+
236
+ /* /\* */
237
+ /* * If we want stats for the time since system startup, */
238
+ /* * we have p0->irq != q0->irq, since q0 structure is */
239
+ /* * completely set to zero. */
240
+ /* *\/ */
241
+ /* if (strcmp(p0->irq_name, q0->irq_name) && interval) { */
242
+ /* if (j) */
243
+ /* offset = j - 1; */
244
+ /* q0 = st_ic[prev] + offset; */
245
+ /* if (strcmp(p0->irq_name, q0->irq_name) && (j + 1 < ic_nr)) */
246
+ /* offset = j + 1; */
247
+ /* q0 = st_ic[prev] + offset; */
248
+ /* } */
249
+
250
+ /* if (!strcmp(p0->irq_name, q0->irq_name) || !interval) { */
251
+ /* p = st_ic[curr] + (cpu - 1) * ic_nr + j; */
252
+ /* q = st_ic[prev] + (cpu - 1) * ic_nr + offset; */
253
+ /* printf(" %10.2f", */
254
+ /* S_VALUE(q->interrupt, p->interrupt, itv)); */
255
+ /* } */
256
+ /* else */
257
+ /* printf(" N/A"); */
258
+ /* } */
259
+ /* } */
260
+ /* printf("\n"); */
261
+ /* } */
262
+ /* } */
263
+
264
+ /*
265
+ ***************************************************************************
266
+ * Core function used to display statistics
267
+ *
268
+ * IN:
269
+ * @prev Position in array where statistics used as reference are.
270
+ * Stats used as reference may be the previous ones read, or
271
+ * the very first ones when calculating the average.
272
+ * @curr Position in array where statistics for current sample are.
273
+ * @dis TRUE if a header line must be printed.
274
+ * @prev_string String displayed at the beginning of a header line. This is
275
+ * the timestamp of the previous sample, or "Average" when
276
+ * displaying average stats.
277
+ * @curr_string String displayed at the beginning of current sample stats.
278
+ * This is the timestamp of the current sample, or "Average"
279
+ * when displaying average stats.
280
+ ***************************************************************************
281
+ */
282
+ /* void write_stats_core(int prev, int curr, int dis, */
283
+ /* char *prev_string, char *curr_string) */
284
+ /* { */
285
+ /* struct stats_cpu *scc, *scp; */
286
+ /* unsigned long long itv, pc_itv, g_itv; */
287
+ /* int cpu; */
288
+
289
+ /* /\* Test stdout *\/ */
290
+ /* TEST_STDOUT(STDOUT_FILENO); */
291
+
292
+ /* /\* Compute time interval *\/ */
293
+ /* g_itv = get_interval(uptime[prev], uptime[curr]); */
294
+
295
+ /* /\* Reduce interval value to one processor *\/ */
296
+ /* if (cpu_nr > 1) { */
297
+ /* itv = get_interval(uptime0[prev], uptime0[curr]); */
298
+ /* } */
299
+ /* else { */
300
+ /* itv = g_itv; */
301
+ /* } */
302
+
303
+ /* /\* Print CPU stats *\/ */
304
+ /* if (DISPLAY_CPU(actflags)) { */
305
+ /* if (dis) { */
306
+ /* printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq " */
307
+ /* "%%soft %%steal %%guest %%idle\n", */
308
+ /* prev_string); */
309
+ /* } */
310
+
311
+ /* /\* Check if we want global stats among all proc *\/ */
312
+ /* if (*cpu_bitmap & 1) { */
313
+
314
+ /* printf("%-11s all", curr_string); */
315
+
316
+ /* printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", */
317
+ /* (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) < */
318
+ /* (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ? */
319
+ /* 0.0 : */
320
+ /* ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest, */
321
+ /* st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest, */
322
+ /* g_itv), */
323
+ /* ll_sp_value(st_cpu[prev]->cpu_nice, */
324
+ /* st_cpu[curr]->cpu_nice, */
325
+ /* g_itv), */
326
+ /* ll_sp_value(st_cpu[prev]->cpu_sys, */
327
+ /* st_cpu[curr]->cpu_sys, */
328
+ /* g_itv), */
329
+ /* ll_sp_value(st_cpu[prev]->cpu_iowait, */
330
+ /* st_cpu[curr]->cpu_iowait, */
331
+ /* g_itv), */
332
+ /* ll_sp_value(st_cpu[prev]->cpu_hardirq, */
333
+ /* st_cpu[curr]->cpu_hardirq, */
334
+ /* g_itv), */
335
+ /* ll_sp_value(st_cpu[prev]->cpu_softirq, */
336
+ /* st_cpu[curr]->cpu_softirq, */
337
+ /* g_itv), */
338
+ /* ll_sp_value(st_cpu[prev]->cpu_steal, */
339
+ /* st_cpu[curr]->cpu_steal, */
340
+ /* g_itv), */
341
+ /* ll_sp_value(st_cpu[prev]->cpu_guest, */
342
+ /* st_cpu[curr]->cpu_guest, */
343
+ /* g_itv), */
344
+ /* (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ? */
345
+ /* 0.0 : */
346
+ /* ll_sp_value(st_cpu[prev]->cpu_idle, */
347
+ /* st_cpu[curr]->cpu_idle, */
348
+ /* g_itv)); */
349
+ /* } */
350
+
351
+ /* for (cpu = 1; cpu <= cpu_nr; cpu++) { */
352
+
353
+ /* scc = st_cpu[curr] + cpu; */
354
+ /* scp = st_cpu[prev] + cpu; */
355
+
356
+ /* /\* Check if we want stats about this proc *\/ */
357
+ /* if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07)))) */
358
+ /* continue; */
359
+
360
+ /* printf("%-11s %4d", curr_string, cpu - 1); */
361
+
362
+ /* /\* */
363
+ /* * If the CPU is offline then it is omited from /proc/stat */
364
+ /* * and the sum of all values is zero. */
365
+ /* * (Remember that guest time is already included in user mode.) */
366
+ /* *\/ */
367
+ /* if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys + */
368
+ /* scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal + */
369
+ /* scc->cpu_hardirq + scc->cpu_softirq) == 0) { */
370
+ /* /\* */
371
+ /* * Set current struct fields (which have been set to zero) */
372
+ /* * to values from previous iteration. Hence their values won't */
373
+ /* * jump from zero when the CPU comes back online. */
374
+ /* *\/ */
375
+ /* *scc = *scp; */
376
+
377
+ /* printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f" */
378
+ /* " %6.2f %6.2f %6.2f\n", */
379
+ /* 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); */
380
+ /* continue; */
381
+ /* } */
382
+
383
+ /* /\* Recalculate itv for current proc *\/ */
384
+ /* pc_itv = get_per_cpu_interval(scc, scp); */
385
+
386
+ /* if (!pc_itv) { */
387
+ /* /\* */
388
+ /* * If the CPU is tickless then there is no change in CPU values */
389
+ /* * but the sum of values is not zero. */
390
+ /* *\/ */
391
+ /* printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f" */
392
+ /* " %6.2f %6.2f %6.2f\n", */
393
+ /* 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0); */
394
+ /* } */
395
+
396
+ /* else { */
397
+ /* printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f" */
398
+ /* " %6.2f %6.2f %6.2f\n", */
399
+ /* (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ? */
400
+ /* 0.0 : */
401
+ /* ll_sp_value(scp->cpu_user - scp->cpu_guest, */
402
+ /* scc->cpu_user - scc->cpu_guest, */
403
+ /* pc_itv), */
404
+ /* ll_sp_value(scp->cpu_nice, */
405
+ /* scc->cpu_nice, */
406
+ /* pc_itv), */
407
+ /* ll_sp_value(scp->cpu_sys, */
408
+ /* scc->cpu_sys, */
409
+ /* pc_itv), */
410
+ /* ll_sp_value(scp->cpu_iowait, */
411
+ /* scc->cpu_iowait, */
412
+ /* pc_itv), */
413
+ /* ll_sp_value(scp->cpu_hardirq, */
414
+ /* scc->cpu_hardirq, */
415
+ /* pc_itv), */
416
+ /* ll_sp_value(scp->cpu_softirq, */
417
+ /* scc->cpu_softirq, */
418
+ /* pc_itv), */
419
+ /* ll_sp_value(scp->cpu_steal, */
420
+ /* scc->cpu_steal, */
421
+ /* pc_itv), */
422
+ /* ll_sp_value(scp->cpu_guest, */
423
+ /* scc->cpu_guest, */
424
+ /* pc_itv), */
425
+ /* (scc->cpu_idle < scp->cpu_idle) ? */
426
+ /* 0.0 : */
427
+ /* ll_sp_value(scp->cpu_idle, */
428
+ /* scc->cpu_idle, */
429
+ /* pc_itv)); */
430
+ /* } */
431
+ /* } */
432
+ /* } */
433
+
434
+ /* /\* Print total number of interrupts per processor *\/ */
435
+ /* if (DISPLAY_IRQ_SUM(actflags)) { */
436
+ /* struct stats_irq *sic, *sip; */
437
+
438
+ /* if (dis) { */
439
+ /* printf("\n%-11s CPU intr/s\n", prev_string); */
440
+ /* } */
441
+
442
+ /* if (*cpu_bitmap & 1) { */
443
+ /* printf("%-11s all %9.2f\n", curr_string, */
444
+ /* ll_s_value(st_irq[prev]->irq_nr, st_irq[curr]->irq_nr, itv)); */
445
+ /* } */
446
+
447
+ /* for (cpu = 1; cpu <= cpu_nr; cpu++) { */
448
+
449
+ /* sic = st_irq[curr] + cpu; */
450
+ /* sip = st_irq[prev] + cpu; */
451
+
452
+ /* scc = st_cpu[curr] + cpu; */
453
+ /* scp = st_cpu[prev] + cpu; */
454
+
455
+ /* /\* Check if we want stats about this proc *\/ */
456
+ /* if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07)))) */
457
+ /* continue; */
458
+
459
+ /* printf("%-11s %4d", curr_string, cpu - 1); */
460
+
461
+ /* /\* Recalculate itv for current proc *\/ */
462
+ /* pc_itv = get_per_cpu_interval(scc, scp); */
463
+
464
+ /* if (!pc_itv) { */
465
+ /* /\* Current CPU is offline *\/ */
466
+ /* printf(" %9.2f\n", 0.0); */
467
+ /* } */
468
+ /* else { */
469
+ /* printf(" %9.2f\n", */
470
+ /* ll_s_value(sip->irq_nr, sic->irq_nr, itv)); */
471
+ /* } */
472
+ /* } */
473
+ /* } */
474
+
475
+ /* if (DISPLAY_IRQ_CPU(actflags)) { */
476
+ /* write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr, */
477
+ /* prev_string, curr_string); */
478
+ /* } */
479
+
480
+ /* if (DISPLAY_SOFTIRQS(actflags)) { */
481
+ /* write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr, */
482
+ /* prev_string, curr_string); */
483
+ /* } */
484
+ /* } */
485
+
486
+ /*
487
+ ***************************************************************************
488
+ * Print statistics average
489
+ *
490
+ * IN:
491
+ * @curr Position in array where statistics for current sample are.
492
+ * @dis TRUE if a header line must be printed.
493
+ ***************************************************************************
494
+ */
495
+ /* void write_stats_avg(int curr, int dis) */
496
+ /* { */
497
+ /* char string[16]; */
498
+
499
+ /* strncpy(string, _("Average:"), 16); */
500
+ /* string[15] = '\0'; */
501
+ /* write_stats_core(2, curr, dis, string, string); */
502
+ /* } */
503
+
504
+ /*
505
+ ***************************************************************************
506
+ * Print statistics
507
+ *
508
+ * IN:
509
+ * @curr Position in array where statistics for current sample are.
510
+ * @dis TRUE if a header line must be printed.
511
+ ***************************************************************************
512
+ */
513
+ /* void write_stats(int curr, int dis) */
514
+ /* { */
515
+ /* char cur_time[2][16]; */
516
+
517
+ /* /\* Get previous timestamp *\/ */
518
+ /* strftime(cur_time[!curr], 16, "%X", &(mp_tstamp[!curr])); */
519
+
520
+ /* /\* Get current timestamp *\/ */
521
+ /* strftime(cur_time[curr], 16, "%X", &(mp_tstamp[curr])); */
522
+
523
+ /* write_stats_core(!curr, curr, dis, cur_time[!curr], cur_time[curr]); */
524
+ /* } */
525
+
526
+ /*
527
+ ***************************************************************************
528
+ * Read stats from /proc/interrupts or /proc/softirqs.
529
+ *
530
+ * IN:
531
+ * @file /proc file to read (interrupts or softirqs).
532
+ * @ic_nr Number of interrupts (hard or soft) per CPU.
533
+ * @curr Position in array where current statistics will be saved.
534
+ *
535
+ * OUT:
536
+ * @st_ic Array for per-CPU statistics.
537
+ ***************************************************************************
538
+ */
539
+ void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, int curr)
540
+ {
541
+ FILE *fp;
542
+ struct stats_irq *st_irq_i;
543
+ struct stats_irqcpu *p;
544
+ char *line = NULL;
545
+ unsigned long irq = 0;
546
+ unsigned int cpu;
547
+ int cpu_index[cpu_nr], index = 0, dgt, len;
548
+ char *cp, *next;
549
+
550
+ for (cpu = 0; cpu < cpu_nr; cpu++) {
551
+ st_irq_i = st_irq[curr] + cpu + 1;
552
+ st_irq_i->irq_nr = 0;
553
+ }
554
+
555
+ if ((fp = fopen(file, "r")) != NULL) {
556
+
557
+ SREALLOC(line, char, INTERRUPTS_LINE + 11 * cpu_nr);
558
+
559
+ /*
560
+ * Parse header line to see which CPUs are online
561
+ */
562
+ while (fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) {
563
+ next = line;
564
+ while (((cp = strstr(next, "CPU")) != NULL) && (index < cpu_nr)) {
565
+ cpu = strtol(cp + 3, &next, 10);
566
+ cpu_index[index++] = cpu;
567
+ }
568
+ if (index)
569
+ /* Header line found */
570
+ break;
571
+ }
572
+
573
+ while ((fgets(line, INTERRUPTS_LINE + 11 * cpu_nr, fp) != NULL) &&
574
+ (irq < ic_nr)) {
575
+
576
+ /* Skip over "<irq>:" */
577
+ if ((cp = strchr(line, ':')) == NULL)
578
+ continue;
579
+ cp++;
580
+
581
+ p = st_ic[curr] + irq;
582
+ len = strcspn(line, ":");
583
+ if (len >= MAX_IRQ_LEN) {
584
+ len = MAX_IRQ_LEN - 1;
585
+ }
586
+ strncpy(p->irq_name, line, len);
587
+ p->irq_name[len] = '\0';
588
+ dgt = isdigit(line[len - 1]);
589
+
590
+ for (cpu = 0; cpu < index; cpu++) {
591
+ p = st_ic[curr] + cpu_index[cpu] * ic_nr + irq;
592
+ st_irq_i = st_irq[curr] + cpu_index[cpu] + 1;
593
+ /*
594
+ * No need to set (st_irqcpu + cpu * irqcpu_nr)->irq:
595
+ * This is the same as st_irqcpu->irq.
596
+ */
597
+ p->interrupt = strtoul(cp, &next, 10);
598
+ if (dgt) {
599
+ /* Sum only numerical irq (and not NMI, LOC, etc.) */
600
+ st_irq_i->irq_nr += p->interrupt;
601
+ }
602
+ cp = next;
603
+ }
604
+ irq++;
605
+ }
606
+
607
+ fclose(fp);
608
+
609
+ if (line) {
610
+ free(line);
611
+ }
612
+ }
613
+
614
+ while (irq < ic_nr) {
615
+ /* Nb of interrupts per processor has changed */
616
+ p = st_ic[curr] + irq;
617
+ p->irq_name[0] = '\0'; /* This value means this is a dummy interrupt */
618
+ irq++;
619
+ }
620
+ }
621
+
622
+ /*
623
+ ***************************************************************************
624
+ * Main loop: Read stats from the relevant sources, and display them.
625
+ *
626
+ * IN:
627
+ * @dis_hdr Set to TRUE if the header line must always be printed.
628
+ * @rows Number of rows of screen.
629
+ ***************************************************************************
630
+ */
631
+ void rw_mpstat_loop(int dis_hdr, int rows)
632
+ {
633
+ struct stats_cpu *scc;
634
+ int cpu;
635
+ int curr = 1, dis = 1;
636
+ unsigned long lines = rows;
637
+
638
+ /* Dont buffer data if redirected to a pipe */
639
+ setbuf(stdout, NULL);
640
+
641
+ /* Read stats */
642
+ if (cpu_nr > 1) {
643
+ /*
644
+ * Init uptime0. So if /proc/uptime cannot fill it,
645
+ * this will be done by /proc/stat.
646
+ */
647
+ uptime0[0] = 0;
648
+ read_uptime(&(uptime0[0]));
649
+ }
650
+ read_stat_cpu(st_cpu[0], cpu_nr + 1, &(uptime[0]), &(uptime0[0]));
651
+
652
+ if (DISPLAY_IRQ_SUM(actflags)) {
653
+ read_stat_irq(st_irq[0], 1);
654
+ }
655
+
656
+ if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
657
+ /* Read this file to display int per CPU or total nr of int per CPU */
658
+ read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, 0);
659
+ }
660
+
661
+ if (DISPLAY_SOFTIRQS(actflags)) {
662
+ read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
663
+ }
664
+
665
+ if (!interval) {
666
+ /* Display since boot time */
667
+ mp_tstamp[1] = mp_tstamp[0];
668
+ memset(st_cpu[1], 0, STATS_CPU_SIZE * (cpu_nr + 1));
669
+ memset(st_irq[1], 0, STATS_IRQ_SIZE * (cpu_nr + 1));
670
+ memset(st_irqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
671
+ if (DISPLAY_SOFTIRQS(actflags)) {
672
+ memset(st_softirqcpu[1], 0, STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
673
+ }
674
+ /* write_stats(0, DISP_HDR); */
675
+ exit(0);
676
+ }
677
+
678
+ /* Set a handler for SIGALRM */
679
+ /* alarm_handler(0); */
680
+
681
+ /* Save the first stats collected. Will be used to compute the average */
682
+ mp_tstamp[2] = mp_tstamp[0];
683
+ uptime[2] = uptime[0];
684
+ uptime0[2] = uptime0[0];
685
+ memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
686
+ memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
687
+ memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
688
+ if (DISPLAY_SOFTIRQS(actflags)) {
689
+ memcpy(st_softirqcpu[2], st_softirqcpu[0],
690
+ STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
691
+ }
692
+
693
+ pause();
694
+
695
+ do {
696
+ /*
697
+ * Resetting the structure not needed since every fields will be set.
698
+ * Exceptions are per-CPU structures: Some of them may not be filled
699
+ * if corresponding processor is disabled (offline). We set them to zero
700
+ * to be able to distinguish between offline and tickless CPUs.
701
+ */
702
+ for (cpu = 1; cpu <= cpu_nr; cpu++) {
703
+ scc = st_cpu[curr] + cpu;
704
+ memset(scc, 0, STATS_CPU_SIZE);
705
+ }
706
+
707
+ /* Get time */
708
+ get_localtime(&(mp_tstamp[curr]));
709
+
710
+ /* Read stats */
711
+ if (cpu_nr > 1) {
712
+ uptime0[curr] = 0;
713
+ read_uptime(&(uptime0[curr]));
714
+ }
715
+ read_stat_cpu(st_cpu[curr], cpu_nr + 1, &(uptime[curr]), &(uptime0[curr]));
716
+
717
+ if (DISPLAY_IRQ_SUM(actflags)) {
718
+ read_stat_irq(st_irq[curr], 1);
719
+ }
720
+
721
+ if (DISPLAY_IRQ_SUM(actflags) || DISPLAY_IRQ_CPU(actflags)) {
722
+ read_interrupts_stat(INTERRUPTS, st_irqcpu, irqcpu_nr, curr);
723
+ }
724
+
725
+ if (DISPLAY_SOFTIRQS(actflags)) {
726
+ read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, curr);
727
+ }
728
+
729
+ /* Write stats */
730
+ if (!dis_hdr) {
731
+ dis = lines / rows;
732
+ if (dis) {
733
+ lines %= rows;
734
+ }
735
+ lines++;
736
+ }
737
+ /* write_stats(curr, dis); */
738
+
739
+ if (count > 0) {
740
+ count--;
741
+ }
742
+ if (count) {
743
+ curr ^= 1;
744
+ pause();
745
+ }
746
+ }
747
+ while (count);
748
+
749
+ /* Write stats average */
750
+ /* write_stats_avg(curr, dis_hdr); */
751
+ }
752
+
753
+ /*
754
+ ***************************************************************************
755
+ * Main entry to the program
756
+ ***************************************************************************
757
+ */
758
+ /* int main(int argc, char **argv) */
759
+ /* { */
760
+ /* int opt = 0, i, actset = FALSE; */
761
+ /* struct utsname header; */
762
+ /* int dis_hdr = -1; */
763
+ /* int rows = 23; */
764
+ /* char *t; */
765
+
766
+ /* #ifdef USE_NLS */
767
+ /* /\* Init National Language Support *\/ */
768
+ /* init_nls(); */
769
+ /* #endif */
770
+
771
+ /* /\* Get HZ *\/ */
772
+ /* get_HZ(); */
773
+
774
+ /* /\* How many processors on this machine ? *\/ */
775
+ /* cpu_nr = get_cpu_nr(~0); */
776
+
777
+ /* /\* Calculate number of interrupts per processor *\/ */
778
+ /* irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) + */
779
+ /* NR_IRQCPU_PREALLOC; */
780
+ /* /\* Calculate number of soft interrupts per processor *\/ */
781
+ /* softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) + */
782
+ /* NR_IRQCPU_PREALLOC; */
783
+
784
+ /* /\* */
785
+ /* * cpu_nr: a value of 2 means there are 2 processors (0 and 1). */
786
+ /* * In this case, we have to allocate 3 structures: global, proc0 and proc1. */
787
+ /* *\/ */
788
+ /* salloc_mp_struct(cpu_nr + 1); */
789
+
790
+ /* while (++opt < argc) { */
791
+
792
+ /* if (!strcmp(argv[opt], "-I")) { */
793
+ /* if (argv[++opt]) { */
794
+ /* actset = TRUE; */
795
+ /* if (!strcmp(argv[opt], K_SUM)) { */
796
+ /* /\* Display total number of interrupts per CPU *\/ */
797
+ /* actflags |= M_D_IRQ_SUM; */
798
+ /* } */
799
+ /* else if (!strcmp(argv[opt], K_CPU)) { */
800
+ /* /\* Display interrupts per CPU *\/ */
801
+ /* actflags |= M_D_IRQ_CPU; */
802
+ /* } */
803
+ /* else if (!strcmp(argv[opt], K_SCPU)) { */
804
+ /* /\* Display soft interrupts per CPU *\/ */
805
+ /* actflags |= M_D_SOFTIRQS; */
806
+ /* } */
807
+ /* else if (!strcmp(argv[opt], K_ALL)) { */
808
+ /* actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS; */
809
+ /* } */
810
+ /* else { */
811
+ /* usage(argv[0]); */
812
+ /* } */
813
+ /* } */
814
+ /* else { */
815
+ /* usage(argv[0]); */
816
+ /* } */
817
+ /* } */
818
+
819
+ /* else if (!strcmp(argv[opt], "-P")) { */
820
+ /* /\* '-P ALL' can be used on UP machines *\/ */
821
+ /* if (argv[++opt]) { */
822
+ /* flags |= F_P_OPTION; */
823
+ /* dis_hdr++; */
824
+
825
+ /* for (t = strtok(argv[opt], ","); t; t = strtok(NULL, ",")) { */
826
+ /* if (!strcmp(t, K_ALL)) { */
827
+ /* if (cpu_nr) { */
828
+ /* dis_hdr = 9; */
829
+ /* } */
830
+ /* /\* */
831
+ /* * Set bit for every processor. */
832
+ /* * Also indicate to display stats for CPU 'all'. */
833
+ /* *\/ */
834
+ /* memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1); */
835
+ /* } */
836
+ /* else { */
837
+ /* if (strspn(t, DIGITS) != strlen(t)) { */
838
+ /* usage(argv[0]); */
839
+ /* } */
840
+ /* i = atoi(t); /\* Get cpu number *\/ */
841
+ /* if (i >= cpu_nr) { */
842
+ /* fprintf(stderr, _("Not that many processors!\n")); */
843
+ /* exit(1); */
844
+ /* } */
845
+ /* i++; */
846
+ /* *(cpu_bitmap + (i >> 3)) |= 1 << (i & 0x07); */
847
+ /* } */
848
+ /* } */
849
+ /* } */
850
+ /* else { */
851
+ /* usage(argv[0]); */
852
+ /* } */
853
+ /* } */
854
+
855
+ /* else if (!strncmp(argv[opt], "-", 1)) { */
856
+ /* for (i = 1; *(argv[opt] + i); i++) { */
857
+
858
+ /* switch (*(argv[opt] + i)) { */
859
+
860
+ /* case 'A': */
861
+ /* actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS; */
862
+ /* actset = TRUE; */
863
+ /* /\* Select all processors *\/ */
864
+ /* flags |= F_P_OPTION; */
865
+ /* memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1); */
866
+ /* break; */
867
+
868
+ /* case 'u': */
869
+ /* /\* Display CPU *\/ */
870
+ /* actflags |= M_D_CPU; */
871
+ /* break; */
872
+
873
+ /* case 'V': */
874
+ /* /\* Print version number *\/ */
875
+ /* print_version(); */
876
+ /* break; */
877
+
878
+ /* default: */
879
+ /* usage(argv[0]); */
880
+ /* } */
881
+ /* } */
882
+ /* } */
883
+
884
+ /* else if (interval < 0) { */
885
+ /* /\* Get interval *\/ */
886
+ /* if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) { */
887
+ /* usage(argv[0]); */
888
+ /* } */
889
+ /* interval = atol(argv[opt]); */
890
+ /* if (interval < 0) { */
891
+ /* usage(argv[0]); */
892
+ /* } */
893
+ /* count = -1; */
894
+ /* } */
895
+
896
+ /* else if (count <= 0) { */
897
+ /* /\* Get count value *\/ */
898
+ /* if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) || */
899
+ /* !interval) { */
900
+ /* usage(argv[0]); */
901
+ /* } */
902
+ /* count = atol(argv[opt]); */
903
+ /* if (count < 1) { */
904
+ /* usage(argv[0]); */
905
+ /* } */
906
+ /* } */
907
+
908
+ /* else { */
909
+ /* usage(argv[0]); */
910
+ /* } */
911
+ /* } */
912
+
913
+ /* /\* Default: Display CPU *\/ */
914
+ /* if (!actset) { */
915
+ /* actflags |= M_D_CPU; */
916
+ /* } */
917
+
918
+ /* if (count_bits(&actflags, sizeof(unsigned int)) > 1) { */
919
+ /* dis_hdr = 9; */
920
+ /* } */
921
+
922
+ /* if (!USE_P_OPTION(flags)) { */
923
+ /* /\* Option -P not used: Set bit 0 (global stats among all proc) *\/ */
924
+ /* *cpu_bitmap = 1; */
925
+ /* } */
926
+ /* if (dis_hdr < 0) { */
927
+ /* dis_hdr = 0; */
928
+ /* } */
929
+ /* if (!dis_hdr) { */
930
+ /* /\* Get window size *\/ */
931
+ /* rows = get_win_height(); */
932
+ /* } */
933
+ /* if (interval < 0) { */
934
+ /* /\* Interval not set => display stats since boot time *\/ */
935
+ /* interval = 0; */
936
+ /* } */
937
+
938
+ /* /\* Get time *\/ */
939
+ /* get_localtime(&(mp_tstamp[0])); */
940
+
941
+ /* /\* Get system name, release number and hostname *\/ */
942
+ /* uname(&header); */
943
+ /* print_gal_header(&(mp_tstamp[0]), header.sysname, header.release, */
944
+ /* header.nodename, header.machine, cpu_nr); */
945
+
946
+ /* /\* Main loop *\/ */
947
+ /* rw_mpstat_loop(dis_hdr, rows); */
948
+
949
+ /* /\* Free structures *\/ */
950
+ /* sfree_mp_struct(); */
951
+
952
+ /* return 0; */
953
+ /* } */