perfmonger 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ /* } */