0001
0002
0003
0004
0005
0006 #include <getopt.h>
0007 #include <stdlib.h>
0008 #include <string.h>
0009 #include <signal.h>
0010 #include <unistd.h>
0011 #include <errno.h>
0012 #include <stdio.h>
0013 #include <time.h>
0014
0015 #include "utils.h"
0016 #include "osnoise.h"
0017
0018 struct osnoise_hist_params {
0019 char *cpus;
0020 char *monitored_cpus;
0021 char *trace_output;
0022 unsigned long long runtime;
0023 unsigned long long period;
0024 long long threshold;
0025 long long stop_us;
0026 long long stop_total_us;
0027 int sleep_time;
0028 int duration;
0029 int set_sched;
0030 int output_divisor;
0031 struct sched_attr sched_param;
0032 struct trace_events *events;
0033
0034 char no_header;
0035 char no_summary;
0036 char no_index;
0037 char with_zeros;
0038 int bucket_size;
0039 int entries;
0040 };
0041
0042 struct osnoise_hist_cpu {
0043 int *samples;
0044 int count;
0045
0046 unsigned long long min_sample;
0047 unsigned long long sum_sample;
0048 unsigned long long max_sample;
0049
0050 };
0051
0052 struct osnoise_hist_data {
0053 struct tracefs_hist *trace_hist;
0054 struct osnoise_hist_cpu *hist;
0055 int entries;
0056 int bucket_size;
0057 int nr_cpus;
0058 };
0059
0060
0061
0062
0063 static void
0064 osnoise_free_histogram(struct osnoise_hist_data *data)
0065 {
0066 int cpu;
0067
0068
0069 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
0070 if (data->hist[cpu].samples)
0071 free(data->hist[cpu].samples);
0072 }
0073
0074
0075 if (data->hist)
0076 free(data->hist);
0077
0078 free(data);
0079 }
0080
0081
0082
0083
0084 static struct osnoise_hist_data
0085 *osnoise_alloc_histogram(int nr_cpus, int entries, int bucket_size)
0086 {
0087 struct osnoise_hist_data *data;
0088 int cpu;
0089
0090 data = calloc(1, sizeof(*data));
0091 if (!data)
0092 return NULL;
0093
0094 data->entries = entries;
0095 data->bucket_size = bucket_size;
0096 data->nr_cpus = nr_cpus;
0097
0098 data->hist = calloc(1, sizeof(*data->hist) * nr_cpus);
0099 if (!data->hist)
0100 goto cleanup;
0101
0102 for (cpu = 0; cpu < nr_cpus; cpu++) {
0103 data->hist[cpu].samples = calloc(1, sizeof(*data->hist->samples) * (entries + 1));
0104 if (!data->hist[cpu].samples)
0105 goto cleanup;
0106 }
0107
0108
0109 for (cpu = 0; cpu < nr_cpus; cpu++)
0110 data->hist[cpu].min_sample = ~0;
0111
0112 return data;
0113
0114 cleanup:
0115 osnoise_free_histogram(data);
0116 return NULL;
0117 }
0118
0119 static void osnoise_hist_update_multiple(struct osnoise_tool *tool, int cpu,
0120 unsigned long long duration, int count)
0121 {
0122 struct osnoise_hist_params *params = tool->params;
0123 struct osnoise_hist_data *data = tool->data;
0124 int entries = data->entries;
0125 int bucket;
0126 int *hist;
0127
0128 if (params->output_divisor)
0129 duration = duration / params->output_divisor;
0130
0131 if (data->bucket_size)
0132 bucket = duration / data->bucket_size;
0133
0134 hist = data->hist[cpu].samples;
0135 data->hist[cpu].count += count;
0136 update_min(&data->hist[cpu].min_sample, &duration);
0137 update_sum(&data->hist[cpu].sum_sample, &duration);
0138 update_max(&data->hist[cpu].max_sample, &duration);
0139
0140 if (bucket < entries)
0141 hist[bucket] += count;
0142 else
0143 hist[entries] += count;
0144 }
0145
0146
0147
0148
0149 static void osnoise_destroy_trace_hist(struct osnoise_tool *tool)
0150 {
0151 struct osnoise_hist_data *data = tool->data;
0152
0153 tracefs_hist_pause(tool->trace.inst, data->trace_hist);
0154 tracefs_hist_destroy(tool->trace.inst, data->trace_hist);
0155 }
0156
0157
0158
0159
0160 static int osnoise_init_trace_hist(struct osnoise_tool *tool)
0161 {
0162 struct osnoise_hist_params *params = tool->params;
0163 struct osnoise_hist_data *data = tool->data;
0164 int bucket_size;
0165 char buff[128];
0166 int retval = 0;
0167
0168
0169
0170
0171 bucket_size = params->output_divisor * params->bucket_size;
0172 snprintf(buff, sizeof(buff), "duration.buckets=%d", bucket_size);
0173
0174 data->trace_hist = tracefs_hist_alloc(tool->trace.tep, "osnoise", "sample_threshold",
0175 buff, TRACEFS_HIST_KEY_NORMAL);
0176 if (!data->trace_hist)
0177 return 1;
0178
0179 retval = tracefs_hist_add_key(data->trace_hist, "cpu", 0);
0180 if (retval)
0181 goto out_err;
0182
0183 retval = tracefs_hist_start(tool->trace.inst, data->trace_hist);
0184 if (retval)
0185 goto out_err;
0186
0187 return 0;
0188
0189 out_err:
0190 osnoise_destroy_trace_hist(tool);
0191 return 1;
0192 }
0193
0194
0195
0196
0197 static void osnoise_read_trace_hist(struct osnoise_tool *tool)
0198 {
0199 struct osnoise_hist_data *data = tool->data;
0200 long long cpu, counter, duration;
0201 char *content, *position;
0202
0203 tracefs_hist_pause(tool->trace.inst, data->trace_hist);
0204
0205 content = tracefs_event_file_read(tool->trace.inst, "osnoise",
0206 "sample_threshold",
0207 "hist", NULL);
0208 if (!content)
0209 return;
0210
0211 position = content;
0212 while (true) {
0213 position = strstr(position, "duration: ~");
0214 if (!position)
0215 break;
0216 position += strlen("duration: ~");
0217 duration = get_llong_from_str(position);
0218 if (duration == -1)
0219 err_msg("error reading duration from histogram\n");
0220
0221 position = strstr(position, "cpu:");
0222 if (!position)
0223 break;
0224 position += strlen("cpu: ");
0225 cpu = get_llong_from_str(position);
0226 if (cpu == -1)
0227 err_msg("error reading cpu from histogram\n");
0228
0229 position = strstr(position, "hitcount:");
0230 if (!position)
0231 break;
0232 position += strlen("hitcount: ");
0233 counter = get_llong_from_str(position);
0234 if (counter == -1)
0235 err_msg("error reading counter from histogram\n");
0236
0237 osnoise_hist_update_multiple(tool, cpu, duration, counter);
0238 }
0239 free(content);
0240 }
0241
0242
0243
0244
0245 static void osnoise_hist_header(struct osnoise_tool *tool)
0246 {
0247 struct osnoise_hist_params *params = tool->params;
0248 struct osnoise_hist_data *data = tool->data;
0249 struct trace_seq *s = tool->trace.seq;
0250 char duration[26];
0251 int cpu;
0252
0253 if (params->no_header)
0254 return;
0255
0256 get_duration(tool->start_time, duration, sizeof(duration));
0257 trace_seq_printf(s, "# RTLA osnoise histogram\n");
0258 trace_seq_printf(s, "# Time unit is %s (%s)\n",
0259 params->output_divisor == 1 ? "nanoseconds" : "microseconds",
0260 params->output_divisor == 1 ? "ns" : "us");
0261
0262 trace_seq_printf(s, "# Duration: %s\n", duration);
0263
0264 if (!params->no_index)
0265 trace_seq_printf(s, "Index");
0266
0267 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
0268 if (params->cpus && !params->monitored_cpus[cpu])
0269 continue;
0270
0271 if (!data->hist[cpu].count)
0272 continue;
0273
0274 trace_seq_printf(s, " CPU-%03d", cpu);
0275 }
0276 trace_seq_printf(s, "\n");
0277
0278 trace_seq_do_printf(s);
0279 trace_seq_reset(s);
0280 }
0281
0282
0283
0284
0285 static void
0286 osnoise_print_summary(struct osnoise_hist_params *params,
0287 struct trace_instance *trace,
0288 struct osnoise_hist_data *data)
0289 {
0290 int cpu;
0291
0292 if (params->no_summary)
0293 return;
0294
0295 if (!params->no_index)
0296 trace_seq_printf(trace->seq, "count:");
0297
0298 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
0299 if (params->cpus && !params->monitored_cpus[cpu])
0300 continue;
0301
0302 if (!data->hist[cpu].count)
0303 continue;
0304
0305 trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].count);
0306 }
0307 trace_seq_printf(trace->seq, "\n");
0308
0309 if (!params->no_index)
0310 trace_seq_printf(trace->seq, "min: ");
0311
0312 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
0313 if (params->cpus && !params->monitored_cpus[cpu])
0314 continue;
0315
0316 if (!data->hist[cpu].count)
0317 continue;
0318
0319 trace_seq_printf(trace->seq, "%9llu ", data->hist[cpu].min_sample);
0320
0321 }
0322 trace_seq_printf(trace->seq, "\n");
0323
0324 if (!params->no_index)
0325 trace_seq_printf(trace->seq, "avg: ");
0326
0327 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
0328 if (params->cpus && !params->monitored_cpus[cpu])
0329 continue;
0330
0331 if (!data->hist[cpu].count)
0332 continue;
0333
0334 if (data->hist[cpu].count)
0335 trace_seq_printf(trace->seq, "%9llu ",
0336 data->hist[cpu].sum_sample / data->hist[cpu].count);
0337 else
0338 trace_seq_printf(trace->seq, " - ");
0339 }
0340 trace_seq_printf(trace->seq, "\n");
0341
0342 if (!params->no_index)
0343 trace_seq_printf(trace->seq, "max: ");
0344
0345 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
0346 if (params->cpus && !params->monitored_cpus[cpu])
0347 continue;
0348
0349 if (!data->hist[cpu].count)
0350 continue;
0351
0352 trace_seq_printf(trace->seq, "%9llu ", data->hist[cpu].max_sample);
0353
0354 }
0355 trace_seq_printf(trace->seq, "\n");
0356 trace_seq_do_printf(trace->seq);
0357 trace_seq_reset(trace->seq);
0358 }
0359
0360
0361
0362
0363 static void
0364 osnoise_print_stats(struct osnoise_hist_params *params, struct osnoise_tool *tool)
0365 {
0366 struct osnoise_hist_data *data = tool->data;
0367 struct trace_instance *trace = &tool->trace;
0368 int bucket, cpu;
0369 int total;
0370
0371 osnoise_hist_header(tool);
0372
0373 for (bucket = 0; bucket < data->entries; bucket++) {
0374 total = 0;
0375
0376 if (!params->no_index)
0377 trace_seq_printf(trace->seq, "%-6d",
0378 bucket * data->bucket_size);
0379
0380 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
0381 if (params->cpus && !params->monitored_cpus[cpu])
0382 continue;
0383
0384 if (!data->hist[cpu].count)
0385 continue;
0386
0387 total += data->hist[cpu].samples[bucket];
0388 trace_seq_printf(trace->seq, "%9d ", data->hist[cpu].samples[bucket]);
0389 }
0390
0391 if (total == 0 && !params->with_zeros) {
0392 trace_seq_reset(trace->seq);
0393 continue;
0394 }
0395
0396 trace_seq_printf(trace->seq, "\n");
0397 trace_seq_do_printf(trace->seq);
0398 trace_seq_reset(trace->seq);
0399 }
0400
0401 if (!params->no_index)
0402 trace_seq_printf(trace->seq, "over: ");
0403
0404 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
0405 if (params->cpus && !params->monitored_cpus[cpu])
0406 continue;
0407
0408 if (!data->hist[cpu].count)
0409 continue;
0410
0411 trace_seq_printf(trace->seq, "%9d ",
0412 data->hist[cpu].samples[data->entries]);
0413 }
0414 trace_seq_printf(trace->seq, "\n");
0415 trace_seq_do_printf(trace->seq);
0416 trace_seq_reset(trace->seq);
0417
0418 osnoise_print_summary(params, trace, data);
0419 }
0420
0421
0422
0423
0424 static void osnoise_hist_usage(char *usage)
0425 {
0426 int i;
0427
0428 static const char * const msg[] = {
0429 "",
0430 " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\",
0431 " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\",
0432 " [-c cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] [--no-index] \\",
0433 " [--with-zeros]",
0434 "",
0435 " -h/--help: print this menu",
0436 " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit",
0437 " -p/--period us: osnoise period in us",
0438 " -r/--runtime us: osnoise runtime in us",
0439 " -s/--stop us: stop trace if a single sample is higher than the argument in us",
0440 " -S/--stop-total us: stop trace if the total sample is higher than the argument in us",
0441 " -T/--threshold us: the minimum delta to be considered a noise",
0442 " -c/--cpus cpu-list: list of cpus to run osnoise threads",
0443 " -d/--duration time[s|m|h|d]: duration of the session",
0444 " -D/--debug: print debug info",
0445 " -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]",
0446 " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed",
0447 " --filter <filter>: enable a trace event filter to the previous -e event",
0448 " --trigger <trigger>: enable a trace event trigger to the previous -e event",
0449 " -b/--bucket-size N: set the histogram bucket size (default 1)",
0450 " -E/--entries N: set the number of entries of the histogram (default 256)",
0451 " --no-header: do not print header",
0452 " --no-summary: do not print summary",
0453 " --no-index: do not print index",
0454 " --with-zeros: print zero only entries",
0455 " -P/--priority o:prio|r:prio|f:prio|d:runtime:period: set scheduling parameters",
0456 " o:prio - use SCHED_OTHER with prio",
0457 " r:prio - use SCHED_RR with prio",
0458 " f:prio - use SCHED_FIFO with prio",
0459 " d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
0460 " in nanoseconds",
0461 NULL,
0462 };
0463
0464 if (usage)
0465 fprintf(stderr, "%s\n", usage);
0466
0467 fprintf(stderr, "rtla osnoise hist: a per-cpu histogram of the OS noise (version %s)\n",
0468 VERSION);
0469
0470 for (i = 0; msg[i]; i++)
0471 fprintf(stderr, "%s\n", msg[i]);
0472 exit(1);
0473 }
0474
0475
0476
0477
0478 static struct osnoise_hist_params
0479 *osnoise_hist_parse_args(int argc, char *argv[])
0480 {
0481 struct osnoise_hist_params *params;
0482 struct trace_events *tevent;
0483 int retval;
0484 int c;
0485
0486 params = calloc(1, sizeof(*params));
0487 if (!params)
0488 exit(1);
0489
0490
0491 params->output_divisor = 1000;
0492 params->bucket_size = 1;
0493 params->entries = 256;
0494
0495 while (1) {
0496 static struct option long_options[] = {
0497 {"auto", required_argument, 0, 'a'},
0498 {"bucket-size", required_argument, 0, 'b'},
0499 {"entries", required_argument, 0, 'E'},
0500 {"cpus", required_argument, 0, 'c'},
0501 {"debug", no_argument, 0, 'D'},
0502 {"duration", required_argument, 0, 'd'},
0503 {"help", no_argument, 0, 'h'},
0504 {"period", required_argument, 0, 'p'},
0505 {"priority", required_argument, 0, 'P'},
0506 {"runtime", required_argument, 0, 'r'},
0507 {"stop", required_argument, 0, 's'},
0508 {"stop-total", required_argument, 0, 'S'},
0509 {"trace", optional_argument, 0, 't'},
0510 {"event", required_argument, 0, 'e'},
0511 {"threshold", required_argument, 0, 'T'},
0512 {"no-header", no_argument, 0, '0'},
0513 {"no-summary", no_argument, 0, '1'},
0514 {"no-index", no_argument, 0, '2'},
0515 {"with-zeros", no_argument, 0, '3'},
0516 {"trigger", required_argument, 0, '4'},
0517 {"filter", required_argument, 0, '5'},
0518 {0, 0, 0, 0}
0519 };
0520
0521
0522 int option_index = 0;
0523
0524 c = getopt_long(argc, argv, "a:c:b:d:e:E:Dhp:P:r:s:S:t::T:01234:5:",
0525 long_options, &option_index);
0526
0527
0528 if (c == -1)
0529 break;
0530
0531 switch (c) {
0532 case 'a':
0533
0534 params->stop_us = get_llong_from_str(optarg);
0535
0536
0537 params->threshold = 1;
0538
0539
0540 params->trace_output = "osnoise_trace.txt";
0541
0542 break;
0543 case 'b':
0544 params->bucket_size = get_llong_from_str(optarg);
0545 if ((params->bucket_size == 0) || (params->bucket_size >= 1000000))
0546 osnoise_hist_usage("Bucket size needs to be > 0 and <= 1000000\n");
0547 break;
0548 case 'c':
0549 retval = parse_cpu_list(optarg, ¶ms->monitored_cpus);
0550 if (retval)
0551 osnoise_hist_usage("\nInvalid -c cpu list\n");
0552 params->cpus = optarg;
0553 break;
0554 case 'D':
0555 config_debug = 1;
0556 break;
0557 case 'd':
0558 params->duration = parse_seconds_duration(optarg);
0559 if (!params->duration)
0560 osnoise_hist_usage("Invalid -D duration\n");
0561 break;
0562 case 'e':
0563 tevent = trace_event_alloc(optarg);
0564 if (!tevent) {
0565 err_msg("Error alloc trace event");
0566 exit(EXIT_FAILURE);
0567 }
0568
0569 if (params->events)
0570 tevent->next = params->events;
0571
0572 params->events = tevent;
0573 break;
0574 case 'E':
0575 params->entries = get_llong_from_str(optarg);
0576 if ((params->entries < 10) || (params->entries > 9999999))
0577 osnoise_hist_usage("Entries must be > 10 and < 9999999\n");
0578 break;
0579 case 'h':
0580 case '?':
0581 osnoise_hist_usage(NULL);
0582 break;
0583 case 'p':
0584 params->period = get_llong_from_str(optarg);
0585 if (params->period > 10000000)
0586 osnoise_hist_usage("Period longer than 10 s\n");
0587 break;
0588 case 'P':
0589 retval = parse_prio(optarg, ¶ms->sched_param);
0590 if (retval == -1)
0591 osnoise_hist_usage("Invalid -P priority");
0592 params->set_sched = 1;
0593 break;
0594 case 'r':
0595 params->runtime = get_llong_from_str(optarg);
0596 if (params->runtime < 100)
0597 osnoise_hist_usage("Runtime shorter than 100 us\n");
0598 break;
0599 case 's':
0600 params->stop_us = get_llong_from_str(optarg);
0601 break;
0602 case 'S':
0603 params->stop_total_us = get_llong_from_str(optarg);
0604 break;
0605 case 'T':
0606 params->threshold = get_llong_from_str(optarg);
0607 break;
0608 case 't':
0609 if (optarg)
0610
0611 params->trace_output = &optarg[1];
0612 else
0613 params->trace_output = "osnoise_trace.txt";
0614 break;
0615 case '0':
0616 params->no_header = 1;
0617 break;
0618 case '1':
0619 params->no_summary = 1;
0620 break;
0621 case '2':
0622 params->no_index = 1;
0623 break;
0624 case '3':
0625 params->with_zeros = 1;
0626 break;
0627 case '4':
0628 if (params->events) {
0629 retval = trace_event_add_trigger(params->events, optarg);
0630 if (retval) {
0631 err_msg("Error adding trigger %s\n", optarg);
0632 exit(EXIT_FAILURE);
0633 }
0634 } else {
0635 osnoise_hist_usage("--trigger requires a previous -e\n");
0636 }
0637 break;
0638 case '5':
0639 if (params->events) {
0640 retval = trace_event_add_filter(params->events, optarg);
0641 if (retval) {
0642 err_msg("Error adding filter %s\n", optarg);
0643 exit(EXIT_FAILURE);
0644 }
0645 } else {
0646 osnoise_hist_usage("--filter requires a previous -e\n");
0647 }
0648 break;
0649 default:
0650 osnoise_hist_usage("Invalid option");
0651 }
0652 }
0653
0654 if (geteuid()) {
0655 err_msg("rtla needs root permission\n");
0656 exit(EXIT_FAILURE);
0657 }
0658
0659 if (params->no_index && !params->with_zeros)
0660 osnoise_hist_usage("no-index set and with-zeros not set - it does not make sense");
0661
0662 return params;
0663 }
0664
0665
0666
0667
0668 static int
0669 osnoise_hist_apply_config(struct osnoise_tool *tool, struct osnoise_hist_params *params)
0670 {
0671 int retval;
0672
0673 if (!params->sleep_time)
0674 params->sleep_time = 1;
0675
0676 if (params->cpus) {
0677 retval = osnoise_set_cpus(tool->context, params->cpus);
0678 if (retval) {
0679 err_msg("Failed to apply CPUs config\n");
0680 goto out_err;
0681 }
0682 }
0683
0684 if (params->runtime || params->period) {
0685 retval = osnoise_set_runtime_period(tool->context,
0686 params->runtime,
0687 params->period);
0688 if (retval) {
0689 err_msg("Failed to set runtime and/or period\n");
0690 goto out_err;
0691 }
0692 }
0693
0694 if (params->stop_us) {
0695 retval = osnoise_set_stop_us(tool->context, params->stop_us);
0696 if (retval) {
0697 err_msg("Failed to set stop us\n");
0698 goto out_err;
0699 }
0700 }
0701
0702 if (params->stop_total_us) {
0703 retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us);
0704 if (retval) {
0705 err_msg("Failed to set stop total us\n");
0706 goto out_err;
0707 }
0708 }
0709
0710 if (params->threshold) {
0711 retval = osnoise_set_tracing_thresh(tool->context, params->threshold);
0712 if (retval) {
0713 err_msg("Failed to set tracing_thresh\n");
0714 goto out_err;
0715 }
0716 }
0717
0718 return 0;
0719
0720 out_err:
0721 return -1;
0722 }
0723
0724
0725
0726
0727 static struct osnoise_tool
0728 *osnoise_init_hist(struct osnoise_hist_params *params)
0729 {
0730 struct osnoise_tool *tool;
0731 int nr_cpus;
0732
0733 nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
0734
0735 tool = osnoise_init_tool("osnoise_hist");
0736 if (!tool)
0737 return NULL;
0738
0739 tool->data = osnoise_alloc_histogram(nr_cpus, params->entries, params->bucket_size);
0740 if (!tool->data)
0741 goto out_err;
0742
0743 tool->params = params;
0744
0745 return tool;
0746
0747 out_err:
0748 osnoise_destroy_tool(tool);
0749 return NULL;
0750 }
0751
0752 static int stop_tracing;
0753 static void stop_hist(int sig)
0754 {
0755 stop_tracing = 1;
0756 }
0757
0758
0759
0760
0761 static void
0762 osnoise_hist_set_signals(struct osnoise_hist_params *params)
0763 {
0764 signal(SIGINT, stop_hist);
0765 if (params->duration) {
0766 signal(SIGALRM, stop_hist);
0767 alarm(params->duration);
0768 }
0769 }
0770
0771 int osnoise_hist_main(int argc, char *argv[])
0772 {
0773 struct osnoise_hist_params *params;
0774 struct osnoise_tool *record = NULL;
0775 struct osnoise_tool *tool = NULL;
0776 struct trace_instance *trace;
0777 int return_value = 1;
0778 int retval;
0779
0780 params = osnoise_hist_parse_args(argc, argv);
0781 if (!params)
0782 exit(1);
0783
0784 tool = osnoise_init_hist(params);
0785 if (!tool) {
0786 err_msg("Could not init osnoise hist\n");
0787 goto out_exit;
0788 }
0789
0790 retval = osnoise_hist_apply_config(tool, params);
0791 if (retval) {
0792 err_msg("Could not apply config\n");
0793 goto out_destroy;
0794 }
0795
0796 trace = &tool->trace;
0797
0798 retval = enable_osnoise(trace);
0799 if (retval) {
0800 err_msg("Failed to enable osnoise tracer\n");
0801 goto out_destroy;
0802 }
0803
0804 retval = osnoise_init_trace_hist(tool);
0805 if (retval)
0806 goto out_destroy;
0807
0808 if (params->set_sched) {
0809 retval = set_comm_sched_attr("osnoise/", ¶ms->sched_param);
0810 if (retval) {
0811 err_msg("Failed to set sched parameters\n");
0812 goto out_free;
0813 }
0814 }
0815
0816 trace_instance_start(trace);
0817
0818 if (params->trace_output) {
0819 record = osnoise_init_trace_tool("osnoise");
0820 if (!record) {
0821 err_msg("Failed to enable the trace instance\n");
0822 goto out_free;
0823 }
0824
0825 if (params->events) {
0826 retval = trace_events_enable(&record->trace, params->events);
0827 if (retval)
0828 goto out_hist;
0829 }
0830
0831 trace_instance_start(&record->trace);
0832 }
0833
0834 tool->start_time = time(NULL);
0835 osnoise_hist_set_signals(params);
0836
0837 while (!stop_tracing) {
0838 sleep(params->sleep_time);
0839
0840 retval = tracefs_iterate_raw_events(trace->tep,
0841 trace->inst,
0842 NULL,
0843 0,
0844 collect_registered_events,
0845 trace);
0846 if (retval < 0) {
0847 err_msg("Error iterating on events\n");
0848 goto out_hist;
0849 }
0850
0851 if (trace_is_off(&tool->trace, &record->trace))
0852 break;
0853 }
0854
0855 osnoise_read_trace_hist(tool);
0856
0857 osnoise_print_stats(params, tool);
0858
0859 return_value = 0;
0860
0861 if (trace_is_off(&tool->trace, &record->trace)) {
0862 printf("rtla osnoise hit stop tracing\n");
0863 if (params->trace_output) {
0864 printf(" Saving trace to %s\n", params->trace_output);
0865 save_trace_to_file(record->trace.inst, params->trace_output);
0866 }
0867 }
0868
0869 out_hist:
0870 trace_events_destroy(&record->trace, params->events);
0871 params->events = NULL;
0872 out_free:
0873 osnoise_free_histogram(tool->data);
0874 out_destroy:
0875 osnoise_destroy_tool(record);
0876 osnoise_destroy_tool(tool);
0877 free(params);
0878 out_exit:
0879 exit(return_value);
0880 }