Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/tracing/rtla/src/osnoise_hist.c
29524 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <[email protected]>
4
*/
5
6
#define _GNU_SOURCE
7
#include <getopt.h>
8
#include <stdlib.h>
9
#include <string.h>
10
#include <signal.h>
11
#include <unistd.h>
12
#include <errno.h>
13
#include <stdio.h>
14
#include <time.h>
15
16
#include "osnoise.h"
17
18
struct osnoise_hist_cpu {
19
int *samples;
20
int count;
21
22
unsigned long long min_sample;
23
unsigned long long sum_sample;
24
unsigned long long max_sample;
25
26
};
27
28
struct osnoise_hist_data {
29
struct tracefs_hist *trace_hist;
30
struct osnoise_hist_cpu *hist;
31
int entries;
32
int bucket_size;
33
int nr_cpus;
34
};
35
36
/*
37
* osnoise_free_histogram - free runtime data
38
*/
39
static void
40
osnoise_free_histogram(struct osnoise_hist_data *data)
41
{
42
int cpu;
43
44
/* one histogram for IRQ and one for thread, per CPU */
45
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
46
if (data->hist[cpu].samples)
47
free(data->hist[cpu].samples);
48
}
49
50
/* one set of histograms per CPU */
51
if (data->hist)
52
free(data->hist);
53
54
free(data);
55
}
56
57
static void osnoise_free_hist_tool(struct osnoise_tool *tool)
58
{
59
osnoise_free_histogram(tool->data);
60
}
61
62
/*
63
* osnoise_alloc_histogram - alloc runtime data
64
*/
65
static struct osnoise_hist_data
66
*osnoise_alloc_histogram(int nr_cpus, int entries, int bucket_size)
67
{
68
struct osnoise_hist_data *data;
69
int cpu;
70
71
data = calloc(1, sizeof(*data));
72
if (!data)
73
return NULL;
74
75
data->entries = entries;
76
data->bucket_size = bucket_size;
77
data->nr_cpus = nr_cpus;
78
79
data->hist = calloc(1, sizeof(*data->hist) * nr_cpus);
80
if (!data->hist)
81
goto cleanup;
82
83
for (cpu = 0; cpu < nr_cpus; cpu++) {
84
data->hist[cpu].samples = calloc(1, sizeof(*data->hist->samples) * (entries + 1));
85
if (!data->hist[cpu].samples)
86
goto cleanup;
87
}
88
89
/* set the min to max */
90
for (cpu = 0; cpu < nr_cpus; cpu++)
91
data->hist[cpu].min_sample = ~0;
92
93
return data;
94
95
cleanup:
96
osnoise_free_histogram(data);
97
return NULL;
98
}
99
100
static void osnoise_hist_update_multiple(struct osnoise_tool *tool, int cpu,
101
unsigned long long duration, int count)
102
{
103
struct osnoise_params *params = to_osnoise_params(tool->params);
104
struct osnoise_hist_data *data = tool->data;
105
unsigned long long total_duration;
106
int entries = data->entries;
107
int bucket;
108
int *hist;
109
110
if (params->common.output_divisor)
111
duration = duration / params->common.output_divisor;
112
113
bucket = duration / data->bucket_size;
114
115
total_duration = duration * count;
116
117
hist = data->hist[cpu].samples;
118
data->hist[cpu].count += count;
119
update_min(&data->hist[cpu].min_sample, &duration);
120
update_sum(&data->hist[cpu].sum_sample, &total_duration);
121
update_max(&data->hist[cpu].max_sample, &duration);
122
123
if (bucket < entries)
124
hist[bucket] += count;
125
else
126
hist[entries] += count;
127
}
128
129
/*
130
* osnoise_destroy_trace_hist - disable events used to collect histogram
131
*/
132
static void osnoise_destroy_trace_hist(struct osnoise_tool *tool)
133
{
134
struct osnoise_hist_data *data = tool->data;
135
136
tracefs_hist_pause(tool->trace.inst, data->trace_hist);
137
tracefs_hist_destroy(tool->trace.inst, data->trace_hist);
138
}
139
140
/*
141
* osnoise_init_trace_hist - enable events used to collect histogram
142
*/
143
static int osnoise_init_trace_hist(struct osnoise_tool *tool)
144
{
145
struct osnoise_params *params = to_osnoise_params(tool->params);
146
struct osnoise_hist_data *data = tool->data;
147
int bucket_size;
148
char buff[128];
149
int retval = 0;
150
151
/*
152
* Set the size of the bucket.
153
*/
154
bucket_size = params->common.output_divisor * params->common.hist.bucket_size;
155
snprintf(buff, sizeof(buff), "duration.buckets=%d", bucket_size);
156
157
data->trace_hist = tracefs_hist_alloc(tool->trace.tep, "osnoise", "sample_threshold",
158
buff, TRACEFS_HIST_KEY_NORMAL);
159
if (!data->trace_hist)
160
return 1;
161
162
retval = tracefs_hist_add_key(data->trace_hist, "cpu", 0);
163
if (retval)
164
goto out_err;
165
166
retval = tracefs_hist_start(tool->trace.inst, data->trace_hist);
167
if (retval)
168
goto out_err;
169
170
return 0;
171
172
out_err:
173
osnoise_destroy_trace_hist(tool);
174
return 1;
175
}
176
177
/*
178
* osnoise_read_trace_hist - parse histogram file and file osnoise histogram
179
*/
180
static void osnoise_read_trace_hist(struct osnoise_tool *tool)
181
{
182
struct osnoise_hist_data *data = tool->data;
183
long long cpu, counter, duration;
184
char *content, *position;
185
186
tracefs_hist_pause(tool->trace.inst, data->trace_hist);
187
188
content = tracefs_event_file_read(tool->trace.inst, "osnoise",
189
"sample_threshold",
190
"hist", NULL);
191
if (!content)
192
return;
193
194
position = content;
195
while (true) {
196
position = strstr(position, "duration: ~");
197
if (!position)
198
break;
199
position += strlen("duration: ~");
200
duration = get_llong_from_str(position);
201
if (duration == -1)
202
err_msg("error reading duration from histogram\n");
203
204
position = strstr(position, "cpu:");
205
if (!position)
206
break;
207
position += strlen("cpu: ");
208
cpu = get_llong_from_str(position);
209
if (cpu == -1)
210
err_msg("error reading cpu from histogram\n");
211
212
position = strstr(position, "hitcount:");
213
if (!position)
214
break;
215
position += strlen("hitcount: ");
216
counter = get_llong_from_str(position);
217
if (counter == -1)
218
err_msg("error reading counter from histogram\n");
219
220
osnoise_hist_update_multiple(tool, cpu, duration, counter);
221
}
222
free(content);
223
}
224
225
/*
226
* osnoise_hist_header - print the header of the tracer to the output
227
*/
228
static void osnoise_hist_header(struct osnoise_tool *tool)
229
{
230
struct osnoise_params *params = to_osnoise_params(tool->params);
231
struct osnoise_hist_data *data = tool->data;
232
struct trace_seq *s = tool->trace.seq;
233
char duration[26];
234
int cpu;
235
236
if (params->common.hist.no_header)
237
return;
238
239
get_duration(tool->start_time, duration, sizeof(duration));
240
trace_seq_printf(s, "# RTLA osnoise histogram\n");
241
trace_seq_printf(s, "# Time unit is %s (%s)\n",
242
params->common.output_divisor == 1 ? "nanoseconds" : "microseconds",
243
params->common.output_divisor == 1 ? "ns" : "us");
244
245
trace_seq_printf(s, "# Duration: %s\n", duration);
246
247
if (!params->common.hist.no_index)
248
trace_seq_printf(s, "Index");
249
250
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
251
if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus))
252
continue;
253
254
if (!data->hist[cpu].count)
255
continue;
256
257
trace_seq_printf(s, " CPU-%03d", cpu);
258
}
259
trace_seq_printf(s, "\n");
260
261
trace_seq_do_printf(s);
262
trace_seq_reset(s);
263
}
264
265
/*
266
* osnoise_print_summary - print the summary of the hist data to the output
267
*/
268
static void
269
osnoise_print_summary(struct osnoise_params *params,
270
struct trace_instance *trace,
271
struct osnoise_hist_data *data)
272
{
273
int cpu;
274
275
if (params->common.hist.no_summary)
276
return;
277
278
if (!params->common.hist.no_index)
279
trace_seq_printf(trace->seq, "count:");
280
281
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
282
if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus))
283
continue;
284
285
if (!data->hist[cpu].count)
286
continue;
287
288
trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].count);
289
}
290
trace_seq_printf(trace->seq, "\n");
291
292
if (!params->common.hist.no_index)
293
trace_seq_printf(trace->seq, "min: ");
294
295
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
296
if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus))
297
continue;
298
299
if (!data->hist[cpu].count)
300
continue;
301
302
trace_seq_printf(trace->seq, "%9llu ", data->hist[cpu].min_sample);
303
304
}
305
trace_seq_printf(trace->seq, "\n");
306
307
if (!params->common.hist.no_index)
308
trace_seq_printf(trace->seq, "avg: ");
309
310
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
311
if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus))
312
continue;
313
314
if (!data->hist[cpu].count)
315
continue;
316
317
if (data->hist[cpu].count)
318
trace_seq_printf(trace->seq, "%9.2f ",
319
((double) data->hist[cpu].sum_sample) / data->hist[cpu].count);
320
else
321
trace_seq_printf(trace->seq, " - ");
322
}
323
trace_seq_printf(trace->seq, "\n");
324
325
if (!params->common.hist.no_index)
326
trace_seq_printf(trace->seq, "max: ");
327
328
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
329
if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus))
330
continue;
331
332
if (!data->hist[cpu].count)
333
continue;
334
335
trace_seq_printf(trace->seq, "%9llu ", data->hist[cpu].max_sample);
336
337
}
338
trace_seq_printf(trace->seq, "\n");
339
trace_seq_do_printf(trace->seq);
340
trace_seq_reset(trace->seq);
341
}
342
343
/*
344
* osnoise_print_stats - print data for all CPUs
345
*/
346
static void
347
osnoise_print_stats(struct osnoise_tool *tool)
348
{
349
struct osnoise_params *params = to_osnoise_params(tool->params);
350
struct osnoise_hist_data *data = tool->data;
351
struct trace_instance *trace = &tool->trace;
352
int has_samples = 0;
353
int bucket, cpu;
354
int total;
355
356
osnoise_hist_header(tool);
357
358
for (bucket = 0; bucket < data->entries; bucket++) {
359
total = 0;
360
361
if (!params->common.hist.no_index)
362
trace_seq_printf(trace->seq, "%-6d",
363
bucket * data->bucket_size);
364
365
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
366
if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus))
367
continue;
368
369
if (!data->hist[cpu].count)
370
continue;
371
372
total += data->hist[cpu].samples[bucket];
373
trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].samples[bucket]);
374
}
375
376
if (total == 0 && !params->common.hist.with_zeros) {
377
trace_seq_reset(trace->seq);
378
continue;
379
}
380
381
/* There are samples above the threshold */
382
has_samples = 1;
383
trace_seq_printf(trace->seq, "\n");
384
trace_seq_do_printf(trace->seq);
385
trace_seq_reset(trace->seq);
386
}
387
388
/*
389
* If no samples were recorded, skip calculations, print zeroed statistics
390
* and return.
391
*/
392
if (!has_samples) {
393
trace_seq_reset(trace->seq);
394
trace_seq_printf(trace->seq, "over: 0\ncount: 0\nmin: 0\navg: 0\nmax: 0\n");
395
trace_seq_do_printf(trace->seq);
396
trace_seq_reset(trace->seq);
397
return;
398
}
399
400
if (!params->common.hist.no_index)
401
trace_seq_printf(trace->seq, "over: ");
402
403
for (cpu = 0; cpu < data->nr_cpus; cpu++) {
404
if (params->common.cpus && !CPU_ISSET(cpu, &params->common.monitored_cpus))
405
continue;
406
407
if (!data->hist[cpu].count)
408
continue;
409
410
trace_seq_printf(trace->seq, "%9d ",
411
data->hist[cpu].samples[data->entries]);
412
}
413
trace_seq_printf(trace->seq, "\n");
414
trace_seq_do_printf(trace->seq);
415
trace_seq_reset(trace->seq);
416
417
osnoise_print_summary(params, trace, data);
418
osnoise_report_missed_events(tool);
419
}
420
421
/*
422
* osnoise_hist_usage - prints osnoise hist usage message
423
*/
424
static void osnoise_hist_usage(char *usage)
425
{
426
int i;
427
428
static const char * const msg[] = {
429
"",
430
" usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
431
" [-T us] [-t[file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
432
" [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\",
433
" [--no-index] [--with-zeros] [-C[=cgroup_name]] [--warm-up]",
434
"",
435
" -h/--help: print this menu",
436
" -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
437
" -p/--period us: osnoise period in us",
438
" -r/--runtime us: osnoise runtime in us",
439
" -s/--stop us: stop trace if a single sample is higher than the argument in us",
440
" -S/--stop-total us: stop trace if the total sample is higher than the argument in us",
441
" -T/--threshold us: the minimum delta to be considered a noise",
442
" -c/--cpus cpu-list: list of cpus to run osnoise threads",
443
" -H/--house-keeping cpus: run rtla control threads only on the given cpus",
444
" -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited",
445
" -d/--duration time[s|m|h|d]: duration of the session",
446
" -D/--debug: print debug info",
447
" -t/--trace[file]: save the stopped trace to [file|osnoise_trace.txt]",
448
" -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
449
" --filter <filter>: enable a trace event filter to the previous -e event",
450
" --trigger <trigger>: enable a trace event trigger to the previous -e event",
451
" -b/--bucket-size N: set the histogram bucket size (default 1)",
452
" -E/--entries N: set the number of entries of the histogram (default 256)",
453
" --no-header: do not print header",
454
" --no-summary: do not print summary",
455
" --no-index: do not print index",
456
" --with-zeros: print zero only entries",
457
" -P/--priority o:prio|r:prio|f:prio|d:runtime:period: set scheduling parameters",
458
" o:prio - use SCHED_OTHER with prio",
459
" r:prio - use SCHED_RR with prio",
460
" f:prio - use SCHED_FIFO with prio",
461
" d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
462
" in nanoseconds",
463
" --warm-up: let the workload run for s seconds before collecting data",
464
" --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
465
" --on-threshold <action>: define action to be executed at stop-total threshold, multiple are allowed",
466
" --on-end <action>: define action to be executed at measurement end, multiple are allowed",
467
NULL,
468
};
469
470
if (usage)
471
fprintf(stderr, "%s\n", usage);
472
473
fprintf(stderr, "rtla osnoise hist: a per-cpu histogram of the OS noise (version %s)\n",
474
VERSION);
475
476
for (i = 0; msg[i]; i++)
477
fprintf(stderr, "%s\n", msg[i]);
478
479
if (usage)
480
exit(EXIT_FAILURE);
481
482
exit(EXIT_SUCCESS);
483
}
484
485
/*
486
* osnoise_hist_parse_args - allocs, parse and fill the cmd line parameters
487
*/
488
static struct common_params
489
*osnoise_hist_parse_args(int argc, char *argv[])
490
{
491
struct osnoise_params *params;
492
struct trace_events *tevent;
493
int retval;
494
int c;
495
char *trace_output = NULL;
496
497
params = calloc(1, sizeof(*params));
498
if (!params)
499
exit(1);
500
501
actions_init(&params->common.threshold_actions);
502
actions_init(&params->common.end_actions);
503
504
/* display data in microseconds */
505
params->common.output_divisor = 1000;
506
params->common.hist.bucket_size = 1;
507
params->common.hist.entries = 256;
508
509
while (1) {
510
static struct option long_options[] = {
511
{"auto", required_argument, 0, 'a'},
512
{"bucket-size", required_argument, 0, 'b'},
513
{"entries", required_argument, 0, 'E'},
514
{"cpus", required_argument, 0, 'c'},
515
{"cgroup", optional_argument, 0, 'C'},
516
{"debug", no_argument, 0, 'D'},
517
{"duration", required_argument, 0, 'd'},
518
{"house-keeping", required_argument, 0, 'H'},
519
{"help", no_argument, 0, 'h'},
520
{"period", required_argument, 0, 'p'},
521
{"priority", required_argument, 0, 'P'},
522
{"runtime", required_argument, 0, 'r'},
523
{"stop", required_argument, 0, 's'},
524
{"stop-total", required_argument, 0, 'S'},
525
{"trace", optional_argument, 0, 't'},
526
{"event", required_argument, 0, 'e'},
527
{"threshold", required_argument, 0, 'T'},
528
{"no-header", no_argument, 0, '0'},
529
{"no-summary", no_argument, 0, '1'},
530
{"no-index", no_argument, 0, '2'},
531
{"with-zeros", no_argument, 0, '3'},
532
{"trigger", required_argument, 0, '4'},
533
{"filter", required_argument, 0, '5'},
534
{"warm-up", required_argument, 0, '6'},
535
{"trace-buffer-size", required_argument, 0, '7'},
536
{"on-threshold", required_argument, 0, '8'},
537
{"on-end", required_argument, 0, '9'},
538
{0, 0, 0, 0}
539
};
540
541
/* getopt_long stores the option index here. */
542
int option_index = 0;
543
544
c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:",
545
long_options, &option_index);
546
547
/* detect the end of the options. */
548
if (c == -1)
549
break;
550
551
switch (c) {
552
case 'a':
553
/* set sample stop to auto_thresh */
554
params->common.stop_us = get_llong_from_str(optarg);
555
556
/* set sample threshold to 1 */
557
params->threshold = 1;
558
559
/* set trace */
560
trace_output = "osnoise_trace.txt";
561
562
break;
563
case 'b':
564
params->common.hist.bucket_size = get_llong_from_str(optarg);
565
if (params->common.hist.bucket_size == 0 ||
566
params->common.hist.bucket_size >= 1000000)
567
osnoise_hist_usage("Bucket size needs to be > 0 and <= 1000000\n");
568
break;
569
case 'c':
570
retval = parse_cpu_set(optarg, &params->common.monitored_cpus);
571
if (retval)
572
osnoise_hist_usage("\nInvalid -c cpu list\n");
573
params->common.cpus = optarg;
574
break;
575
case 'C':
576
params->common.cgroup = 1;
577
if (!optarg) {
578
/* will inherit this cgroup */
579
params->common.cgroup_name = NULL;
580
} else if (*optarg == '=') {
581
/* skip the = */
582
params->common.cgroup_name = ++optarg;
583
}
584
break;
585
case 'D':
586
config_debug = 1;
587
break;
588
case 'd':
589
params->common.duration = parse_seconds_duration(optarg);
590
if (!params->common.duration)
591
osnoise_hist_usage("Invalid -D duration\n");
592
break;
593
case 'e':
594
tevent = trace_event_alloc(optarg);
595
if (!tevent) {
596
err_msg("Error alloc trace event");
597
exit(EXIT_FAILURE);
598
}
599
600
if (params->common.events)
601
tevent->next = params->common.events;
602
603
params->common.events = tevent;
604
break;
605
case 'E':
606
params->common.hist.entries = get_llong_from_str(optarg);
607
if (params->common.hist.entries < 10 ||
608
params->common.hist.entries > 9999999)
609
osnoise_hist_usage("Entries must be > 10 and < 9999999\n");
610
break;
611
case 'h':
612
case '?':
613
osnoise_hist_usage(NULL);
614
break;
615
case 'H':
616
params->common.hk_cpus = 1;
617
retval = parse_cpu_set(optarg, &params->common.hk_cpu_set);
618
if (retval) {
619
err_msg("Error parsing house keeping CPUs\n");
620
exit(EXIT_FAILURE);
621
}
622
break;
623
case 'p':
624
params->period = get_llong_from_str(optarg);
625
if (params->period > 10000000)
626
osnoise_hist_usage("Period longer than 10 s\n");
627
break;
628
case 'P':
629
retval = parse_prio(optarg, &params->common.sched_param);
630
if (retval == -1)
631
osnoise_hist_usage("Invalid -P priority");
632
params->common.set_sched = 1;
633
break;
634
case 'r':
635
params->runtime = get_llong_from_str(optarg);
636
if (params->runtime < 100)
637
osnoise_hist_usage("Runtime shorter than 100 us\n");
638
break;
639
case 's':
640
params->common.stop_us = get_llong_from_str(optarg);
641
break;
642
case 'S':
643
params->common.stop_total_us = get_llong_from_str(optarg);
644
break;
645
case 'T':
646
params->threshold = get_llong_from_str(optarg);
647
break;
648
case 't':
649
if (optarg) {
650
if (optarg[0] == '=')
651
trace_output = &optarg[1];
652
else
653
trace_output = &optarg[0];
654
} else if (optind < argc && argv[optind][0] != '0')
655
trace_output = argv[optind];
656
else
657
trace_output = "osnoise_trace.txt";
658
break;
659
case '0': /* no header */
660
params->common.hist.no_header = 1;
661
break;
662
case '1': /* no summary */
663
params->common.hist.no_summary = 1;
664
break;
665
case '2': /* no index */
666
params->common.hist.no_index = 1;
667
break;
668
case '3': /* with zeros */
669
params->common.hist.with_zeros = 1;
670
break;
671
case '4': /* trigger */
672
if (params->common.events) {
673
retval = trace_event_add_trigger(params->common.events, optarg);
674
if (retval) {
675
err_msg("Error adding trigger %s\n", optarg);
676
exit(EXIT_FAILURE);
677
}
678
} else {
679
osnoise_hist_usage("--trigger requires a previous -e\n");
680
}
681
break;
682
case '5': /* filter */
683
if (params->common.events) {
684
retval = trace_event_add_filter(params->common.events, optarg);
685
if (retval) {
686
err_msg("Error adding filter %s\n", optarg);
687
exit(EXIT_FAILURE);
688
}
689
} else {
690
osnoise_hist_usage("--filter requires a previous -e\n");
691
}
692
break;
693
case '6':
694
params->common.warmup = get_llong_from_str(optarg);
695
break;
696
case '7':
697
params->common.buffer_size = get_llong_from_str(optarg);
698
break;
699
case '8':
700
retval = actions_parse(&params->common.threshold_actions, optarg,
701
"osnoise_trace.txt");
702
if (retval) {
703
err_msg("Invalid action %s\n", optarg);
704
exit(EXIT_FAILURE);
705
}
706
break;
707
case '9':
708
retval = actions_parse(&params->common.end_actions, optarg,
709
"osnoise_trace.txt");
710
if (retval) {
711
err_msg("Invalid action %s\n", optarg);
712
exit(EXIT_FAILURE);
713
}
714
break;
715
default:
716
osnoise_hist_usage("Invalid option");
717
}
718
}
719
720
if (trace_output)
721
actions_add_trace_output(&params->common.threshold_actions, trace_output);
722
723
if (geteuid()) {
724
err_msg("rtla needs root permission\n");
725
exit(EXIT_FAILURE);
726
}
727
728
if (params->common.hist.no_index && !params->common.hist.with_zeros)
729
osnoise_hist_usage("no-index set and with-zeros not set - it does not make sense");
730
731
return &params->common;
732
}
733
734
/*
735
* osnoise_hist_apply_config - apply the hist configs to the initialized tool
736
*/
737
static int
738
osnoise_hist_apply_config(struct osnoise_tool *tool)
739
{
740
return osnoise_apply_config(tool, to_osnoise_params(tool->params));
741
}
742
743
/*
744
* osnoise_init_hist - initialize a osnoise hist tool with parameters
745
*/
746
static struct osnoise_tool
747
*osnoise_init_hist(struct common_params *params)
748
{
749
struct osnoise_tool *tool;
750
int nr_cpus;
751
752
nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
753
754
tool = osnoise_init_tool("osnoise_hist");
755
if (!tool)
756
return NULL;
757
758
tool->data = osnoise_alloc_histogram(nr_cpus, params->hist.entries,
759
params->hist.bucket_size);
760
if (!tool->data)
761
goto out_err;
762
763
return tool;
764
765
out_err:
766
osnoise_destroy_tool(tool);
767
return NULL;
768
}
769
770
static int osnoise_hist_enable(struct osnoise_tool *tool)
771
{
772
int retval;
773
774
retval = osnoise_init_trace_hist(tool);
775
if (retval)
776
return retval;
777
778
return osnoise_enable(tool);
779
}
780
781
static int osnoise_hist_main_loop(struct osnoise_tool *tool)
782
{
783
int retval;
784
785
retval = hist_main_loop(tool);
786
osnoise_read_trace_hist(tool);
787
788
return retval;
789
}
790
791
struct tool_ops osnoise_hist_ops = {
792
.tracer = "osnoise",
793
.comm_prefix = "osnoise/",
794
.parse_args = osnoise_hist_parse_args,
795
.init_tool = osnoise_init_hist,
796
.apply_config = osnoise_hist_apply_config,
797
.enable = osnoise_hist_enable,
798
.main = osnoise_hist_main_loop,
799
.print_stats = osnoise_print_stats,
800
.free = osnoise_free_hist_tool,
801
};
802
803