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.
- checksums.yaml +15 -0
- data/.dir-locals.el +2 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/COPYING +674 -0
- data/Gemfile +5 -0
- data/HOWTO.md +15 -0
- data/NEWS +115 -0
- data/README.md +61 -0
- data/Rakefile +8 -0
- data/bin/perfmonger +6 -0
- data/data/NOTICE +8 -0
- data/data/Twitter_Bootstrap_LICENSE.txt +176 -0
- data/data/assets/css/bootstrap-responsive.css +1109 -0
- data/data/assets/css/bootstrap.css +6167 -0
- data/data/assets/css/perfmonger.css +17 -0
- data/data/assets/dashboard.erb +319 -0
- data/data/assets/img/glyphicons-halflings-white.png +0 -0
- data/data/assets/img/glyphicons-halflings.png +0 -0
- data/data/assets/js/bootstrap.js +2280 -0
- data/data/assets/js/bootstrap.min.js +6 -0
- data/data/assets/js/canvasjs.js +9042 -0
- data/data/assets/js/canvasjs.min.js +271 -0
- data/data/sysstat.ioconf +268 -0
- data/ext/perfmonger/extconf.rb +19 -0
- data/ext/perfmonger/perfmonger.h +58 -0
- data/ext/perfmonger/perfmonger_record.c +754 -0
- data/ext/perfmonger/sysstat/common.c +627 -0
- data/ext/perfmonger/sysstat/common.h +207 -0
- data/ext/perfmonger/sysstat/ioconf.c +515 -0
- data/ext/perfmonger/sysstat/ioconf.h +84 -0
- data/ext/perfmonger/sysstat/iostat.c +1100 -0
- data/ext/perfmonger/sysstat/iostat.h +121 -0
- data/ext/perfmonger/sysstat/libsysstat.h +19 -0
- data/ext/perfmonger/sysstat/mpstat.c +953 -0
- data/ext/perfmonger/sysstat/mpstat.h +79 -0
- data/ext/perfmonger/sysstat/rd_stats.c +2388 -0
- data/ext/perfmonger/sysstat/rd_stats.h +651 -0
- data/ext/perfmonger/sysstat/sysconfig.h +13 -0
- data/lib/perfmonger/cli.rb +115 -0
- data/lib/perfmonger/command/base_command.rb +39 -0
- data/lib/perfmonger/command/fingerprint.rb +453 -0
- data/lib/perfmonger/command/plot.rb +429 -0
- data/lib/perfmonger/command/record.rb +32 -0
- data/lib/perfmonger/command/record_option.rb +149 -0
- data/lib/perfmonger/command/server.rb +294 -0
- data/lib/perfmonger/command/stat.rb +60 -0
- data/lib/perfmonger/command/stat_option.rb +29 -0
- data/lib/perfmonger/command/summary.rb +402 -0
- data/lib/perfmonger/config.rb +6 -0
- data/lib/perfmonger/version.rb +5 -0
- data/lib/perfmonger.rb +12 -0
- data/misc/release-howto.txt +17 -0
- data/misc/sample-cpu.png +0 -0
- data/misc/sample-read-iops.png +0 -0
- data/perfmonger.gemspec +44 -0
- data/test/run-test.sh +39 -0
- data/test/spec/bin_spec.rb +37 -0
- data/test/spec/data/2devices.expected +42 -0
- data/test/spec/data/2devices.output +42 -0
- data/test/spec/spec_helper.rb +20 -0
- data/test/spec/summary_spec.rb +193 -0
- data/test/test-perfmonger.c +145 -0
- data/test/test.h +9 -0
- 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
|
+
}
|