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