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