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,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
+ }