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,754 @@
1
+ /* -*- indent-tabs-mode: nil -*- */
2
+
3
+ #include "perfmonger.h"
4
+
5
+ typedef struct {
6
+ char *buffer;
7
+ char *cursor;
8
+ size_t size;
9
+ size_t len;
10
+ } strbuf_t;
11
+
12
+ /*
13
+ * Private functions
14
+ */
15
+ static void sigint_handler(int signum, siginfo_t *info, void *handler);
16
+ static void sigterm_handler(int signum, siginfo_t *info, void *handler);
17
+
18
+ static strbuf_t *strbuf_new(void);
19
+ static void strbuf_free(strbuf_t *strbuf);
20
+ static int strbuf_append(strbuf_t *strbuf, const char *format, ...);
21
+
22
+ static void output_io_stat (strbuf_t *output, int curr);
23
+ static void output_cpu_stat (strbuf_t *output, int curr);
24
+ static void output_ctxsw_stat(strbuf_t *output, int curr);
25
+
26
+
27
+ /*
28
+ * Global variables
29
+ */
30
+
31
+ /*
32
+ * Variables in sysstat/iostat.c
33
+ */
34
+
35
+ extern struct io_stats *st_iodev[2];
36
+ extern struct io_hdr_stats *st_hdr_iodev;
37
+ extern struct io_dlist *st_dev_list;
38
+
39
+ extern int iodev_nr; /* Nb of devices and partitions found */
40
+ extern int cpu_nr; /* Nb of processors on the machine */
41
+ extern int dlist_idx; /* Nb of devices entered on the command line */
42
+ extern unsigned int dm_major; /* Device-mapper major number */
43
+
44
+ /* Variables in sysstat/mpstat.c */
45
+ extern unsigned long long uptime[3];
46
+ extern unsigned long long uptime0[3];
47
+
48
+ extern unsigned char *cpu_bitmap; /* Bit 0: Global; Bit 1: 1st proc; etc. */
49
+
50
+ extern struct stats_cpu *st_cpu[3];
51
+ extern struct stats_irq *st_irq[3];
52
+ extern struct tm mp_tstamp[3];
53
+ extern struct stats_irqcpu *st_irqcpu[3];
54
+ extern struct stats_irqcpu *st_softirqcpu[3];
55
+ extern struct tm mp_tstamp[3];
56
+ /* Nb of interrupts per processor */
57
+ extern int irqcpu_nr;
58
+ /* Nb of soft interrupts per processor */
59
+ extern int softirqcpu_nr;
60
+ extern unsigned int actflags;
61
+
62
+ /* Variables for pcsw */
63
+ struct stats_pcsw st_pcsw[3];
64
+
65
+ /* Variables for handling signals */
66
+ static volatile sig_atomic_t sigint_sent = 0;
67
+ static volatile sig_atomic_t sigterm_sent = 0;
68
+
69
+
70
+ /* TODO: long options */
71
+ int
72
+ parse_args(int argc, char **argv, option_t *opt)
73
+ {
74
+ int optval;
75
+
76
+ optind = 1;
77
+
78
+ opt->nr_dev = 0;
79
+ opt->dev_list = NULL;
80
+ opt->all_devices = false;
81
+ opt->interval = 1.0;
82
+ opt->interval_backoff = false;
83
+ opt->start_delay = 0.0;
84
+ opt->timeout = -1.0; /* negative means no timeout */
85
+ opt->verbose = false;
86
+ opt->report_cpu = false;
87
+ opt->report_io = false;
88
+ opt->report_ctxsw = false;
89
+ opt->output = stdout;
90
+
91
+ while((optval = getopt(argc, argv, "d:Di:bs:t:vhCSl:")) != -1) {
92
+ switch(optval) {
93
+ case 'd': // device
94
+ opt->nr_dev ++;
95
+ opt->dev_list = realloc(opt->dev_list, opt->nr_dev * sizeof(char *));
96
+ opt->dev_list[opt->nr_dev - 1] = strdup(optarg);
97
+ opt->report_io = true;
98
+ break;
99
+ case 'D': // show all devices
100
+ opt->report_io = true;
101
+ opt->all_devices = true;
102
+ break;
103
+ case 'i': // interval
104
+ opt->interval = strtod(optarg, NULL);
105
+ break;
106
+ case 'b': // interval backoff
107
+ opt->interval_backoff = true;
108
+ break;
109
+ case 's': // start delay
110
+ opt->start_delay = strtod(optarg, NULL);
111
+ break;
112
+ case 't': // timeout
113
+ opt->timeout = strtod(optarg, NULL);
114
+ break;
115
+ case 'v': // verbose
116
+ opt->verbose = true;
117
+ break;
118
+ case 'h': // help
119
+ print_help();
120
+ goto error;
121
+ break;
122
+ case 'C': // show CPU
123
+ opt->report_cpu = true;
124
+ break;
125
+ case 'S': // show context switch per second
126
+ opt->report_ctxsw = true;
127
+ break;
128
+ case 'l': // show context switch per second
129
+ opt->output = fopen(optarg, "w");
130
+ if (opt->output == NULL)
131
+ {
132
+ perror("log file open failed");
133
+ goto error;
134
+ }
135
+ break;
136
+ default:
137
+ print_help();
138
+ goto error;
139
+ }
140
+ }
141
+
142
+ if (! (opt->report_io || opt->report_ctxsw))
143
+ opt->report_cpu = true;
144
+
145
+ return 0;
146
+ error:
147
+ return -1;
148
+ }
149
+
150
+ /*
151
+ * print_help:
152
+ *
153
+ * Prints usage of PerfMonger in the standard output and call exit(2)
154
+ * with @exit_status. If @exit_status < 0, do not invoke exit(2).
155
+ */
156
+ void
157
+ print_help(void)
158
+ {
159
+ printf("Usage: perfmonger [options]\n");
160
+ }
161
+
162
+ /*
163
+ * signal handlers
164
+ */
165
+ static void
166
+ sigint_handler(int signum, siginfo_t *info, void *handler)
167
+ {
168
+ sigint_sent = 1;
169
+ }
170
+
171
+ static void
172
+ sigterm_handler(int signum, siginfo_t *info, void *handler)
173
+ {
174
+ sigterm_sent = 1;
175
+ }
176
+
177
+
178
+ void
179
+ init_subsystem(option_t *opt)
180
+ {
181
+ int i;
182
+ struct io_dlist *st_dev_list_i;
183
+ struct sigaction sigint_act;
184
+ struct sigaction sigterm_act;
185
+
186
+ get_HZ();
187
+ salloc_dev_list(opt->nr_dev);
188
+ io_sys_init();
189
+
190
+ if (! opt->all_devices)
191
+ {
192
+ for (i = 0; i < opt->nr_dev; i++) {
193
+ update_dev_list(&dlist_idx, opt->dev_list[i]);
194
+ st_dev_list_i = st_dev_list + i;
195
+ st_dev_list_i->disp_part = TRUE;
196
+ }
197
+ }
198
+
199
+ /* ----------------------------------------- */
200
+ /* initialization for mpstat functionalities */
201
+ /* ----------------------------------------- */
202
+
203
+ cpu_nr = get_cpu_nr(~0);
204
+ irqcpu_nr = get_irqcpu_nr(INTERRUPTS, NR_IRQS, cpu_nr) +
205
+ NR_IRQCPU_PREALLOC;
206
+ softirqcpu_nr = get_irqcpu_nr(SOFTIRQS, NR_IRQS, cpu_nr) +
207
+ NR_IRQCPU_PREALLOC;
208
+
209
+ salloc_mp_struct(cpu_nr + 1);
210
+
211
+ /* Enable all activity flags */
212
+ actflags |= M_D_CPU;
213
+ actflags |= M_D_IRQ_SUM;
214
+ actflags |= M_D_IRQ_CPU;
215
+ actflags |= M_D_SOFTIRQS;
216
+ actflags |= M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
217
+
218
+ /* set bit for every processor */
219
+ memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
220
+
221
+ // init uptime
222
+ if (cpu_nr > 1) {
223
+ uptime0[0] = 0;
224
+ read_uptime(&(uptime0[0]));
225
+ }
226
+ // init st_cpu
227
+ read_stat_cpu(st_cpu[0], cpu_nr + 1, &(uptime[0]), &(uptime0[0]));
228
+ // init st_irq
229
+ read_stat_irq(st_irq[0], 1);
230
+ // init st_interrupts_stat
231
+ read_interrupts_stat(SOFTIRQS, st_softirqcpu, softirqcpu_nr, 0);
232
+ // init st_pcsw
233
+ read_stat_pcsw(&st_pcsw[0]);
234
+ // init st_iodev
235
+ read_diskstats_stat(0);
236
+
237
+ /* Save the first stats collected. Will be used to compute the average */
238
+ mp_tstamp[2] = mp_tstamp[0];
239
+ uptime[2] = uptime[0];
240
+ uptime0[2] = uptime0[0];
241
+ st_pcsw[2] = st_pcsw[0];
242
+ memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
243
+ memcpy(st_irq[2], st_irq[0], STATS_IRQ_SIZE * (cpu_nr + 1));
244
+ memcpy(st_irqcpu[2], st_irqcpu[0], STATS_IRQCPU_SIZE * (cpu_nr + 1) * irqcpu_nr);
245
+ if (DISPLAY_SOFTIRQS(actflags)) {
246
+ memcpy(st_softirqcpu[2], st_softirqcpu[0],
247
+ STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
248
+ }
249
+
250
+ /* setup signal handlers */
251
+
252
+ bzero(&sigint_act, sizeof(struct sigaction));
253
+ sigint_act.sa_sigaction = sigint_handler;
254
+ sigint_act.sa_flags = SA_SIGINFO | SA_RESTART;
255
+ if (sigaction(SIGINT, &sigint_act, NULL) != 0) {
256
+ perror("failed to set SIGINT handler");
257
+ exit(EXIT_FAILURE);
258
+ }
259
+
260
+ bzero(&sigterm_act, sizeof(struct sigaction));
261
+ sigterm_act.sa_sigaction = sigterm_handler;
262
+ sigterm_act.sa_flags = SA_SIGINFO | SA_RESTART;
263
+ if (sigaction(SIGTERM, &sigterm_act, NULL) != 0) {
264
+ perror("failed to set SIGTERM handler");
265
+ exit(EXIT_FAILURE);
266
+ }
267
+ }
268
+
269
+ void
270
+ destroy_subsystem(option_t *opt)
271
+ {
272
+ io_sys_free();
273
+ sfree_dev_list();
274
+ }
275
+
276
+ void
277
+ collector_loop(option_t *opt)
278
+ {
279
+ int curr;
280
+ struct timeval tv;
281
+ double interval;
282
+ long wait_until;
283
+ long sleeptime;
284
+ long timeout_when;
285
+ int backoff_counter;
286
+ bool running;
287
+
288
+ if (opt->start_delay > 0.0) {
289
+ usleep(opt->start_delay * 1000000L);
290
+ }
291
+
292
+ curr = 1;
293
+ setbuf(stdout, NULL);
294
+
295
+ gettimeofday(&tv, NULL);
296
+ wait_until = tv.tv_sec * 1000000L + tv.tv_usec;
297
+
298
+ if (opt->timeout > 0) {
299
+ timeout_when = wait_until + opt->timeout * 1000000L; /* in usec */
300
+ } else {
301
+ timeout_when = LONG_MAX;
302
+ }
303
+
304
+ interval = opt->interval;
305
+
306
+ backoff_counter = 0;
307
+
308
+ running = true;
309
+ while(running) {
310
+ if (sigint_sent || sigterm_sent) {
311
+ /* Do not break loop here. For capturing execution time
312
+ * accurate as possible, it is necessary to outputing 1
313
+ * line just after SIGINT was handled */
314
+ running = false;
315
+ }
316
+
317
+ if (wait_until >= timeout_when) {
318
+ running = false;
319
+ }
320
+
321
+ #define BACKOFF_THRESH (2000)
322
+ #define BACKOFF_RATIO (2.0)
323
+ /* Minimum resolution: BACKOFF_RATIO / BACKOFF_THRESH */
324
+ if (opt->interval_backoff && backoff_counter++ >= BACKOFF_THRESH) {
325
+ backoff_counter -= BACKOFF_THRESH;
326
+ interval *= BACKOFF_RATIO;
327
+ if (interval > 3600.0) {
328
+ interval = 3600.0;
329
+ }
330
+ }
331
+
332
+ wait_until += interval * 1000000L;
333
+
334
+ uptime0[curr] = 0;
335
+ read_uptime(&(uptime0[curr]));
336
+
337
+ if (opt->report_cpu)
338
+ read_stat_cpu(st_cpu[curr], cpu_nr + 1, &(uptime[curr]), &(uptime0[curr]));
339
+ if (opt->report_io)
340
+ read_diskstats_stat(curr);
341
+ if (opt->report_ctxsw)
342
+ read_stat_pcsw(&st_pcsw[curr]);
343
+
344
+ output_stat(opt, curr);
345
+
346
+ if (! running) break;
347
+
348
+ if (wait_until > timeout_when) {
349
+ wait_until = timeout_when;
350
+ }
351
+
352
+ curr ^= 1;
353
+ gettimeofday(&tv, NULL);
354
+
355
+ sleeptime = wait_until - (tv.tv_sec * 1000000L + tv.tv_usec);
356
+
357
+ if (sleeptime < 0){
358
+ if (opt->verbose)
359
+ fprintf(stderr, "panic!: %ld\n", sleeptime);
360
+ } else {
361
+ usleep(sleeptime);
362
+ }
363
+ }
364
+
365
+ fflush(opt->output);
366
+ fclose(opt->output);
367
+ }
368
+
369
+
370
+ void
371
+ output_stat(option_t *opt, int curr)
372
+ {
373
+ struct timeval tv;
374
+ strbuf_t *output;
375
+
376
+ output = strbuf_new();
377
+
378
+ gettimeofday(&tv, NULL);
379
+ strbuf_append(output,
380
+ "{\"time\": %.4lf", tv.tv_sec + ((double) tv.tv_usec) / 1000000.0);
381
+
382
+ if (opt->report_cpu) output_cpu_stat(output, curr);
383
+ if (opt->report_io) output_io_stat(output, curr);
384
+ if (opt->report_ctxsw) output_ctxsw_stat(output, curr);
385
+
386
+ strbuf_append(output, "}");
387
+ fprintf(opt->output, "%s\n", output->buffer);
388
+ strbuf_free(output);
389
+ }
390
+
391
+ static strbuf_t *
392
+ strbuf_new(void)
393
+ {
394
+ strbuf_t *strbuf;
395
+
396
+ strbuf = malloc(sizeof(strbuf_t));
397
+ if (strbuf == NULL)
398
+ {
399
+ return NULL;
400
+ }
401
+
402
+ #define INIT_STRBUF_SIZE 1024
403
+ strbuf->buffer = malloc(sizeof(char) * INIT_STRBUF_SIZE);
404
+ bzero(strbuf->buffer, sizeof(char) * INIT_STRBUF_SIZE);
405
+ strbuf->cursor = strbuf->buffer;
406
+ strbuf->size = INIT_STRBUF_SIZE;
407
+ strbuf->len = 0;
408
+
409
+ return strbuf;
410
+ }
411
+
412
+ static void
413
+ strbuf_free(strbuf_t *strbuf)
414
+ {
415
+ free(strbuf->buffer);
416
+ free(strbuf);
417
+ }
418
+
419
+ static int
420
+ strbuf_append(strbuf_t *strbuf, const char *format, ...)
421
+ {
422
+ va_list ap;
423
+ int n;
424
+ size_t size;
425
+
426
+ for (;;)
427
+ {
428
+ va_start(ap, format);
429
+
430
+ size = strbuf->size - strbuf->len;
431
+ n = vsnprintf(strbuf->cursor, size, format, ap);
432
+ if (n < 0)
433
+ {
434
+ return n; // error
435
+ }
436
+ else if (n < size)
437
+ {
438
+ strbuf->cursor += n;
439
+ strbuf->len += n;
440
+
441
+ va_end(ap);
442
+ break;
443
+ }
444
+ else
445
+ {
446
+ int cursor_ofst = strbuf->cursor - strbuf->buffer;
447
+
448
+ strbuf->size *= 2;
449
+ strbuf->buffer = realloc(strbuf->buffer, strbuf->size);
450
+ strbuf->cursor = strbuf->buffer + cursor_ofst;
451
+ }
452
+
453
+ va_end(ap);
454
+ }
455
+
456
+ return n;
457
+ }
458
+
459
+ static void
460
+ output_io_stat (strbuf_t *output, int curr)
461
+ {
462
+ unsigned long long interval;
463
+ struct io_hdr_stats *shi;
464
+ int dev_idx;
465
+ int i;
466
+ struct io_stats *ioi, *ioj;
467
+ int nr_dev;
468
+ struct stats_disk sdc, sdp;
469
+ struct ext_disk_stats xds;
470
+ struct timeval tv;
471
+
472
+ double r_iops, w_iops;
473
+ double r_await, w_await;
474
+ double r_sectors, w_sectors;
475
+
476
+ double reqsz;
477
+
478
+ interval = get_interval(uptime[!curr], uptime[curr]);
479
+ gettimeofday(&tv, NULL);
480
+
481
+ strbuf_append(output, ", \"ioinfo\": {\"devices\": [");
482
+
483
+ int nr_dev_printed = 0;
484
+ for (i = 0, shi = st_hdr_iodev; i < iodev_nr; i++, shi++) {
485
+ if (! shi->used) {
486
+ continue;
487
+ }
488
+ if (dlist_idx) {
489
+ for (dev_idx = 0; dev_idx < dlist_idx; dev_idx++) {
490
+ if (! strcmp(shi->name, st_dev_list[dev_idx].dev_name)) {
491
+ break;
492
+ }
493
+ }
494
+ if (dev_idx == dlist_idx) {
495
+ continue;
496
+ }
497
+ }
498
+
499
+ ioi = st_iodev[curr] + i;
500
+ if (!ioi->rd_ios && !ioi->wr_ios) continue;
501
+
502
+ if (nr_dev_printed > 0) {
503
+ strbuf_append(output, ", ");
504
+ }
505
+ strbuf_append(output, "\"%s\"", shi->name);
506
+
507
+ nr_dev_printed++;
508
+ }
509
+ strbuf_append(output, "], ");
510
+
511
+
512
+ interval = get_interval(uptime0[!curr], uptime0[curr]);
513
+
514
+ r_await = 0;
515
+ w_await = 0;
516
+ r_iops = 0;
517
+ w_iops = 0;
518
+ r_sectors = 0;
519
+ w_sectors = 0;
520
+ reqsz = 0;
521
+ nr_dev = 0;
522
+
523
+ for (i = 0, shi = st_hdr_iodev; i < iodev_nr; i++, shi++) {
524
+ if (! shi->used) {
525
+ continue;
526
+ }
527
+
528
+ if (dlist_idx) {
529
+ for (dev_idx = 0; dev_idx < dlist_idx; dev_idx++) {
530
+ if (! strcmp(shi->name, st_dev_list[dev_idx].dev_name)) {
531
+ break;
532
+ }
533
+ }
534
+ if (dev_idx == dlist_idx) {
535
+ continue;
536
+ }
537
+ }
538
+
539
+ ioi = st_iodev[curr] + i;
540
+ ioj = st_iodev[!curr] + i;
541
+
542
+ ioi = st_iodev[curr] + i;
543
+ if (!ioi->rd_ios && !ioi->wr_ios) continue;
544
+
545
+ sdc.nr_ios = ioi->rd_ios + ioi->wr_ios;
546
+ sdp.nr_ios = ioj->rd_ios + ioj->wr_ios;
547
+
548
+ sdc.tot_ticks = ioi->tot_ticks;
549
+ sdp.tot_ticks = ioj->tot_ticks;
550
+
551
+ sdc.rd_ticks = ioi->rd_ticks;
552
+ sdp.rd_ticks = ioj->rd_ticks;
553
+ sdc.wr_ticks = ioi->wr_ticks;
554
+ sdp.wr_ticks = ioj->wr_ticks;
555
+
556
+ sdc.rd_sect = ioi->rd_sectors;
557
+ sdp.rd_sect = ioj->rd_sectors;
558
+ sdc.wr_sect = ioi->wr_sectors;
559
+ sdp.wr_sect = ioj->wr_sectors;
560
+
561
+ compute_ext_disk_stats(&sdc, &sdp, interval, &xds);
562
+
563
+ r_await += (ioi->rd_ios - ioj->rd_ios) ?
564
+ (ioi->rd_ticks - ioj->rd_ticks) /
565
+ ((double) (ioi->rd_ios - ioj->rd_ios)) : 0.0;
566
+ w_await += (ioi->wr_ios - ioj->wr_ios) ?
567
+ (ioi->wr_ticks - ioj->wr_ticks) /
568
+ ((double) (ioi->wr_ios - ioj->wr_ios)) : 0.0;
569
+ r_iops += S_VALUE(ioj->rd_ios, ioi->rd_ios, interval);
570
+ w_iops += S_VALUE(ioj->wr_ios, ioi->wr_ios, interval);
571
+ r_sectors += ll_s_value(ioj->rd_sectors, ioi->rd_sectors, interval);
572
+ w_sectors += ll_s_value(ioj->wr_sectors, ioi->wr_sectors, interval);
573
+
574
+ reqsz += xds.arqsz;
575
+ nr_dev ++;
576
+
577
+ strbuf_append(output,
578
+ "\"%s\": {\"riops\": %.4lf, \"wiops\": %.4lf, "
579
+ "\"rsecps\": %.4lf, \"wsecps\": %.4lf, "
580
+ "\"r_await\": %.4lf, \"w_await\": %.4lf, "
581
+ "\"avgrq-sz\": %.4lf, \"avgqu-sz\": %.4lf}, ",
582
+ shi->name,
583
+ S_VALUE(ioj->rd_ios, ioi->rd_ios, interval),
584
+ S_VALUE(ioj->wr_ios, ioi->wr_ios, interval),
585
+ ll_s_value(ioj->rd_sectors, ioi->rd_sectors, interval),
586
+ ll_s_value(ioj->wr_sectors, ioi->wr_sectors, interval),
587
+ (ioi->rd_ios - ioj->rd_ios) ?
588
+ (ioi->rd_ticks - ioj->rd_ticks) /
589
+ ((double) (ioi->rd_ios - ioj->rd_ios)) : 0.0,
590
+ (ioi->wr_ios - ioj->wr_ios) ?
591
+ (ioi->wr_ticks - ioj->wr_ticks) /
592
+ ((double) (ioi->wr_ios - ioj->wr_ios)) : 0.0,
593
+ (double) xds.arqsz,
594
+ (double) S_VALUE(ioj->rq_ticks, ioi->rq_ticks, interval) / 1000.0
595
+ );
596
+ }
597
+ r_await /= nr_dev;
598
+ w_await /= nr_dev;
599
+ reqsz /= nr_dev;
600
+
601
+ strbuf_append(output,
602
+ "\"total\": {\"riops\": %.4lf, \"wiops\": %.4lf, "
603
+ "\"rsecps\": %.4lf, \"wsecps\": %.4lf, "
604
+ "\"r_await\": %.4lf, \"w_await\": %.4lf}}",
605
+ r_iops, w_iops,
606
+ r_sectors, w_sectors,
607
+ r_await, w_await
608
+ );
609
+ }
610
+
611
+ static void
612
+ output_cpu_stat(strbuf_t *output, int curr)
613
+ {
614
+ struct stats_cpu *scc, *scp;
615
+ unsigned long long pc_itv, g_itv;
616
+ int cpu;
617
+ int nr_cpu_printed = 0;
618
+
619
+ g_itv = get_interval(uptime[!curr], uptime[curr]);
620
+
621
+ strbuf_append(output, ", \"cpuinfo\": {\"nr_cpu\": %d", cpu_nr);
622
+ strbuf_append(output, ", \"all\": {\"usr\": %.2f, \"nice\": %.2f, "
623
+ "\"sys\": %.2f, \"iowait\": %.2f, "
624
+ "\"irq\": %.2f, \"soft\": %.2f, "
625
+ "\"steal\": %.2f, \"guest\": %.2f, "
626
+ "\"idle\": %.2f}",
627
+ (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
628
+ (st_cpu[!curr]->cpu_user - st_cpu[!curr]->cpu_guest) ?
629
+ 0.0 :
630
+ ll_sp_value(st_cpu[!curr]->cpu_user - st_cpu[!curr]->cpu_guest,
631
+ st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
632
+ g_itv),
633
+ ll_sp_value(st_cpu[!curr]->cpu_nice,
634
+ st_cpu[curr]->cpu_nice,
635
+ g_itv),
636
+ ll_sp_value(st_cpu[!curr]->cpu_sys,
637
+ st_cpu[curr]->cpu_sys,
638
+ g_itv),
639
+ ll_sp_value(st_cpu[!curr]->cpu_iowait,
640
+ st_cpu[curr]->cpu_iowait,
641
+ g_itv),
642
+ ll_sp_value(st_cpu[!curr]->cpu_hardirq,
643
+ st_cpu[curr]->cpu_hardirq,
644
+ g_itv),
645
+ ll_sp_value(st_cpu[!curr]->cpu_softirq,
646
+ st_cpu[curr]->cpu_softirq,
647
+ g_itv),
648
+ ll_sp_value(st_cpu[!curr]->cpu_steal,
649
+ st_cpu[curr]->cpu_steal,
650
+ g_itv),
651
+ ll_sp_value(st_cpu[!curr]->cpu_guest,
652
+ st_cpu[curr]->cpu_guest,
653
+ g_itv),
654
+ (st_cpu[curr]->cpu_idle < st_cpu[!curr]->cpu_idle) ?
655
+ 0.0 :
656
+ ll_sp_value(st_cpu[!curr]->cpu_idle,
657
+ st_cpu[curr]->cpu_idle,
658
+ g_itv));
659
+
660
+ strbuf_append(output, ", \"cpus\": [");
661
+ for (cpu = 1; cpu <= cpu_nr; cpu++) {
662
+ scc = st_cpu[curr] + cpu;
663
+ scp = st_cpu[!curr] + cpu;
664
+
665
+ if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
666
+ continue;
667
+
668
+ strbuf_append(output, (nr_cpu_printed > 0 ? ", " : ""));
669
+
670
+ nr_cpu_printed++;
671
+
672
+ /* Recalculate itv for current proc */
673
+ pc_itv = get_per_cpu_interval(scc, scp);
674
+ if (!pc_itv) {
675
+ /*
676
+ * If the CPU is tickless then there is no change in CPU values
677
+ * but the sum of values is not zero.
678
+ */
679
+ strbuf_append(output, "{\"usr\": %.2f, \"nice\": %.2f, "
680
+ "\"sys\": %.2f, \"iowait\": %.2f, "
681
+ "\"irq\": %.2f, \"soft\": %.2f, "
682
+ "\"steal\": %.2f, \"guest\": %.2f, "
683
+ "\"idle\": %.2f}",
684
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
685
+ }
686
+ else
687
+ {
688
+ strbuf_append(output, "{\"usr\": %.2f, \"nice\": %.2f, "
689
+ "\"sys\": %.2f, \"iowait\": %.2f, "
690
+ "\"irq\": %.2f, \"soft\": %.2f, "
691
+ "\"steal\": %.2f, \"guest\": %.2f, "
692
+ "\"idle\": %.2f}",
693
+ (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
694
+ 0.0 :
695
+ ll_sp_value(scp->cpu_user - scp->cpu_guest,
696
+ scc->cpu_user - scc->cpu_guest,
697
+ pc_itv),
698
+ ll_sp_value(scp->cpu_nice,
699
+ scc->cpu_nice,
700
+ pc_itv),
701
+ ll_sp_value(scp->cpu_sys,
702
+ scc->cpu_sys,
703
+ pc_itv),
704
+ ll_sp_value(scp->cpu_iowait,
705
+ scc->cpu_iowait,
706
+ pc_itv),
707
+ ll_sp_value(scp->cpu_hardirq,
708
+ scc->cpu_hardirq,
709
+ pc_itv),
710
+ ll_sp_value(scp->cpu_softirq,
711
+ scc->cpu_softirq,
712
+ pc_itv),
713
+ ll_sp_value(scp->cpu_steal,
714
+ scc->cpu_steal,
715
+ pc_itv),
716
+ ll_sp_value(scp->cpu_guest,
717
+ scc->cpu_guest,
718
+ pc_itv),
719
+ (scc->cpu_idle < scp->cpu_idle) ?
720
+ 0.0 :
721
+ ll_sp_value(scp->cpu_idle,
722
+ scc->cpu_idle,
723
+ pc_itv));
724
+ }
725
+ }
726
+ strbuf_append(output, "]}");
727
+ }
728
+
729
+ static void
730
+ output_ctxsw_stat(strbuf_t *output, int curr)
731
+ {
732
+ unsigned long long itv;
733
+ itv = get_interval(uptime0[!curr], uptime0[curr]);
734
+ strbuf_append(output, ", \"ctxsw\": %.2f",
735
+ ll_s_value(st_pcsw[!curr].context_switch, st_pcsw[curr].context_switch, itv));
736
+ }
737
+
738
+ int nr_thargs = 0;
739
+
740
+ int
741
+ main(int argc, char **argv)
742
+ {
743
+ option_t opt;
744
+ if (parse_args(argc, argv, &opt) != 0){
745
+ fprintf(stderr, "Argument error. Exit.\n");
746
+ exit(EXIT_FAILURE);
747
+ }
748
+
749
+ init_subsystem(&opt);
750
+ collector_loop(&opt);
751
+ destroy_subsystem(&opt);
752
+
753
+ return 0;
754
+ }