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