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 <sys/types.h> 7 #include <sys/stat.h> 8 #include <pthread.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <unistd.h> 12 #include <errno.h> 13 #include <fcntl.h> 14 #include <stdio.h> 15 16 #include "osnoise.h" 17 #include "utils.h" 18 19 /* 20 * osnoise_get_cpus - return the original "osnoise/cpus" content 21 * 22 * It also saves the value to be restored. 23 */ 24 char *osnoise_get_cpus(struct osnoise_context *context) 25 { 26 if (context->curr_cpus) 27 return context->curr_cpus; 28 29 if (context->orig_cpus) 30 return context->orig_cpus; 31 32 context->orig_cpus = tracefs_instance_file_read(NULL, "osnoise/cpus", NULL); 33 34 /* 35 * The error value (NULL) is the same for tracefs_instance_file_read() 36 * and this functions, so: 37 */ 38 return context->orig_cpus; 39 } 40 41 /* 42 * osnoise_set_cpus - configure osnoise to run on *cpus 43 * 44 * "osnoise/cpus" file is used to set the cpus in which osnoise/timerlat 45 * will run. This function opens this file, saves the current value, 46 * and set the cpus passed as argument. 47 */ 48 int osnoise_set_cpus(struct osnoise_context *context, char *cpus) 49 { 50 char *orig_cpus = osnoise_get_cpus(context); 51 char buffer[1024]; 52 int retval; 53 54 if (!orig_cpus) 55 return -1; 56 57 context->curr_cpus = strdup(cpus); 58 if (!context->curr_cpus) 59 return -1; 60 61 snprintf(buffer, 1024, "%s\n", cpus); 62 63 debug_msg("setting cpus to %s from %s", cpus, context->orig_cpus); 64 65 retval = tracefs_instance_file_write(NULL, "osnoise/cpus", buffer); 66 if (retval < 0) { 67 free(context->curr_cpus); 68 context->curr_cpus = NULL; 69 return -1; 70 } 71 72 return 0; 73 } 74 75 /* 76 * osnoise_restore_cpus - restore the original "osnoise/cpus" 77 * 78 * osnoise_set_cpus() saves the original data for the "osnoise/cpus" 79 * file. This function restore the original config it was previously 80 * modified. 81 */ 82 void osnoise_restore_cpus(struct osnoise_context *context) 83 { 84 int retval; 85 86 if (!context->orig_cpus) 87 return; 88 89 if (!context->curr_cpus) 90 return; 91 92 /* nothing to do? */ 93 if (!strcmp(context->orig_cpus, context->curr_cpus)) 94 goto out_done; 95 96 debug_msg("restoring cpus to %s", context->orig_cpus); 97 98 retval = tracefs_instance_file_write(NULL, "osnoise/cpus", context->orig_cpus); 99 if (retval < 0) 100 err_msg("could not restore original osnoise cpus\n"); 101 102 out_done: 103 free(context->curr_cpus); 104 context->curr_cpus = NULL; 105 } 106 107 /* 108 * osnoise_put_cpus - restore cpus config and cleanup data 109 */ 110 void osnoise_put_cpus(struct osnoise_context *context) 111 { 112 osnoise_restore_cpus(context); 113 114 if (!context->orig_cpus) 115 return; 116 117 free(context->orig_cpus); 118 context->orig_cpus = NULL; 119 } 120 121 /* 122 * osnoise_read_ll_config - read a long long value from a config 123 * 124 * returns -1 on error. 125 */ 126 static long long osnoise_read_ll_config(char *rel_path) 127 { 128 long long retval; 129 char *buffer; 130 131 buffer = tracefs_instance_file_read(NULL, rel_path, NULL); 132 if (!buffer) 133 return -1; 134 135 /* get_llong_from_str returns -1 on error */ 136 retval = get_llong_from_str(buffer); 137 138 debug_msg("reading %s returned %lld\n", rel_path, retval); 139 140 free(buffer); 141 142 return retval; 143 } 144 145 /* 146 * osnoise_write_ll_config - write a long long value to a config in rel_path 147 * 148 * returns -1 on error. 149 */ 150 static long long osnoise_write_ll_config(char *rel_path, long long value) 151 { 152 char buffer[BUFF_U64_STR_SIZE]; 153 long long retval; 154 155 snprintf(buffer, sizeof(buffer), "%lld\n", value); 156 157 debug_msg("setting %s to %lld\n", rel_path, value); 158 159 retval = tracefs_instance_file_write(NULL, rel_path, buffer); 160 return retval; 161 } 162 163 /* 164 * osnoise_get_runtime - return the original "osnoise/runtime_us" value 165 * 166 * It also saves the value to be restored. 167 */ 168 unsigned long long osnoise_get_runtime(struct osnoise_context *context) 169 { 170 long long runtime_us; 171 172 if (context->runtime_us != OSNOISE_TIME_INIT_VAL) 173 return context->runtime_us; 174 175 if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL) 176 return context->orig_runtime_us; 177 178 runtime_us = osnoise_read_ll_config("osnoise/runtime_us"); 179 if (runtime_us < 0) 180 goto out_err; 181 182 context->orig_runtime_us = runtime_us; 183 return runtime_us; 184 185 out_err: 186 return OSNOISE_TIME_INIT_VAL; 187 } 188 189 /* 190 * osnoise_get_period - return the original "osnoise/period_us" value 191 * 192 * It also saves the value to be restored. 193 */ 194 unsigned long long osnoise_get_period(struct osnoise_context *context) 195 { 196 long long period_us; 197 198 if (context->period_us != OSNOISE_TIME_INIT_VAL) 199 return context->period_us; 200 201 if (context->orig_period_us != OSNOISE_TIME_INIT_VAL) 202 return context->orig_period_us; 203 204 period_us = osnoise_read_ll_config("osnoise/period_us"); 205 if (period_us < 0) 206 goto out_err; 207 208 context->orig_period_us = period_us; 209 return period_us; 210 211 out_err: 212 return OSNOISE_TIME_INIT_VAL; 213 } 214 215 static int __osnoise_write_runtime(struct osnoise_context *context, 216 unsigned long long runtime) 217 { 218 int retval; 219 220 if (context->orig_runtime_us == OSNOISE_TIME_INIT_VAL) 221 return -1; 222 223 retval = osnoise_write_ll_config("osnoise/runtime_us", runtime); 224 if (retval < 0) 225 return -1; 226 227 context->runtime_us = runtime; 228 return 0; 229 } 230 231 static int __osnoise_write_period(struct osnoise_context *context, 232 unsigned long long period) 233 { 234 int retval; 235 236 if (context->orig_period_us == OSNOISE_TIME_INIT_VAL) 237 return -1; 238 239 retval = osnoise_write_ll_config("osnoise/period_us", period); 240 if (retval < 0) 241 return -1; 242 243 context->period_us = period; 244 return 0; 245 } 246 247 /* 248 * osnoise_set_runtime_period - set osnoise runtime and period 249 * 250 * Osnoise's runtime and period are related as runtime <= period. 251 * Thus, this function saves the original values, and then tries 252 * to set the runtime and period if they are != 0. 253 */ 254 int osnoise_set_runtime_period(struct osnoise_context *context, 255 unsigned long long runtime, 256 unsigned long long period) 257 { 258 unsigned long long curr_runtime_us; 259 unsigned long long curr_period_us; 260 int retval; 261 262 if (!period && !runtime) 263 return 0; 264 265 curr_runtime_us = osnoise_get_runtime(context); 266 curr_period_us = osnoise_get_period(context); 267 268 /* error getting any value? */ 269 if (curr_period_us == OSNOISE_TIME_INIT_VAL || curr_runtime_us == OSNOISE_TIME_INIT_VAL) 270 return -1; 271 272 if (!period) { 273 if (runtime > curr_period_us) 274 return -1; 275 return __osnoise_write_runtime(context, runtime); 276 } else if (!runtime) { 277 if (period < curr_runtime_us) 278 return -1; 279 return __osnoise_write_period(context, period); 280 } 281 282 if (runtime > curr_period_us) { 283 retval = __osnoise_write_period(context, period); 284 if (retval) 285 return -1; 286 retval = __osnoise_write_runtime(context, runtime); 287 if (retval) 288 return -1; 289 } else { 290 retval = __osnoise_write_runtime(context, runtime); 291 if (retval) 292 return -1; 293 retval = __osnoise_write_period(context, period); 294 if (retval) 295 return -1; 296 } 297 298 return 0; 299 } 300 301 /* 302 * osnoise_restore_runtime_period - restore the original runtime and period 303 */ 304 void osnoise_restore_runtime_period(struct osnoise_context *context) 305 { 306 unsigned long long orig_runtime = context->orig_runtime_us; 307 unsigned long long orig_period = context->orig_period_us; 308 unsigned long long curr_runtime = context->runtime_us; 309 unsigned long long curr_period = context->period_us; 310 int retval; 311 312 if ((orig_runtime == OSNOISE_TIME_INIT_VAL) && (orig_period == OSNOISE_TIME_INIT_VAL)) 313 return; 314 315 if ((orig_period == curr_period) && (orig_runtime == curr_runtime)) 316 goto out_done; 317 318 retval = osnoise_set_runtime_period(context, orig_runtime, orig_period); 319 if (retval) 320 err_msg("Could not restore original osnoise runtime/period\n"); 321 322 out_done: 323 context->runtime_us = OSNOISE_TIME_INIT_VAL; 324 context->period_us = OSNOISE_TIME_INIT_VAL; 325 } 326 327 /* 328 * osnoise_put_runtime_period - restore original values and cleanup data 329 */ 330 void osnoise_put_runtime_period(struct osnoise_context *context) 331 { 332 osnoise_restore_runtime_period(context); 333 334 if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL) 335 context->orig_runtime_us = OSNOISE_TIME_INIT_VAL; 336 337 if (context->orig_period_us != OSNOISE_TIME_INIT_VAL) 338 context->orig_period_us = OSNOISE_TIME_INIT_VAL; 339 } 340 341 /* 342 * osnoise_get_timerlat_period_us - read and save the original "timerlat_period_us" 343 */ 344 static long long 345 osnoise_get_timerlat_period_us(struct osnoise_context *context) 346 { 347 long long timerlat_period_us; 348 349 if (context->timerlat_period_us != OSNOISE_TIME_INIT_VAL) 350 return context->timerlat_period_us; 351 352 if (context->orig_timerlat_period_us != OSNOISE_TIME_INIT_VAL) 353 return context->orig_timerlat_period_us; 354 355 timerlat_period_us = osnoise_read_ll_config("osnoise/timerlat_period_us"); 356 if (timerlat_period_us < 0) 357 goto out_err; 358 359 context->orig_timerlat_period_us = timerlat_period_us; 360 return timerlat_period_us; 361 362 out_err: 363 return OSNOISE_TIME_INIT_VAL; 364 } 365 366 /* 367 * osnoise_set_timerlat_period_us - set "timerlat_period_us" 368 */ 369 int osnoise_set_timerlat_period_us(struct osnoise_context *context, long long timerlat_period_us) 370 { 371 long long curr_timerlat_period_us = osnoise_get_timerlat_period_us(context); 372 int retval; 373 374 if (curr_timerlat_period_us == OSNOISE_TIME_INIT_VAL) 375 return -1; 376 377 retval = osnoise_write_ll_config("osnoise/timerlat_period_us", timerlat_period_us); 378 if (retval < 0) 379 return -1; 380 381 context->timerlat_period_us = timerlat_period_us; 382 383 return 0; 384 } 385 386 /* 387 * osnoise_restore_timerlat_period_us - restore "timerlat_period_us" 388 */ 389 void osnoise_restore_timerlat_period_us(struct osnoise_context *context) 390 { 391 int retval; 392 393 if (context->orig_timerlat_period_us == OSNOISE_TIME_INIT_VAL) 394 return; 395 396 if (context->orig_timerlat_period_us == context->timerlat_period_us) 397 goto out_done; 398 399 retval = osnoise_write_ll_config("osnoise/timerlat_period_us", context->orig_timerlat_period_us); 400 if (retval < 0) 401 err_msg("Could not restore original osnoise timerlat_period_us\n"); 402 403 out_done: 404 context->timerlat_period_us = OSNOISE_TIME_INIT_VAL; 405 } 406 407 /* 408 * osnoise_put_timerlat_period_us - restore original values and cleanup data 409 */ 410 void osnoise_put_timerlat_period_us(struct osnoise_context *context) 411 { 412 osnoise_restore_timerlat_period_us(context); 413 414 if (context->orig_timerlat_period_us == OSNOISE_TIME_INIT_VAL) 415 return; 416 417 context->orig_timerlat_period_us = OSNOISE_TIME_INIT_VAL; 418 } 419 420 /* 421 * osnoise_get_stop_us - read and save the original "stop_tracing_us" 422 */ 423 static long long 424 osnoise_get_stop_us(struct osnoise_context *context) 425 { 426 long long stop_us; 427 428 if (context->stop_us != OSNOISE_OPTION_INIT_VAL) 429 return context->stop_us; 430 431 if (context->orig_stop_us != OSNOISE_OPTION_INIT_VAL) 432 return context->orig_stop_us; 433 434 stop_us = osnoise_read_ll_config("osnoise/stop_tracing_us"); 435 if (stop_us < 0) 436 goto out_err; 437 438 context->orig_stop_us = stop_us; 439 return stop_us; 440 441 out_err: 442 return OSNOISE_OPTION_INIT_VAL; 443 } 444 445 /* 446 * osnoise_set_stop_us - set "stop_tracing_us" 447 */ 448 int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us) 449 { 450 long long curr_stop_us = osnoise_get_stop_us(context); 451 int retval; 452 453 if (curr_stop_us == OSNOISE_OPTION_INIT_VAL) 454 return -1; 455 456 retval = osnoise_write_ll_config("osnoise/stop_tracing_us", stop_us); 457 if (retval < 0) 458 return -1; 459 460 context->stop_us = stop_us; 461 462 return 0; 463 } 464 465 /* 466 * osnoise_restore_stop_us - restore the original "stop_tracing_us" 467 */ 468 void osnoise_restore_stop_us(struct osnoise_context *context) 469 { 470 int retval; 471 472 if (context->orig_stop_us == OSNOISE_OPTION_INIT_VAL) 473 return; 474 475 if (context->orig_stop_us == context->stop_us) 476 goto out_done; 477 478 retval = osnoise_write_ll_config("osnoise/stop_tracing_us", context->orig_stop_us); 479 if (retval < 0) 480 err_msg("Could not restore original osnoise stop_us\n"); 481 482 out_done: 483 context->stop_us = OSNOISE_OPTION_INIT_VAL; 484 } 485 486 /* 487 * osnoise_put_stop_us - restore original values and cleanup data 488 */ 489 void osnoise_put_stop_us(struct osnoise_context *context) 490 { 491 osnoise_restore_stop_us(context); 492 493 if (context->orig_stop_us == OSNOISE_OPTION_INIT_VAL) 494 return; 495 496 context->orig_stop_us = OSNOISE_OPTION_INIT_VAL; 497 } 498 499 /* 500 * osnoise_get_stop_total_us - read and save the original "stop_tracing_total_us" 501 */ 502 static long long 503 osnoise_get_stop_total_us(struct osnoise_context *context) 504 { 505 long long stop_total_us; 506 507 if (context->stop_total_us != OSNOISE_OPTION_INIT_VAL) 508 return context->stop_total_us; 509 510 if (context->orig_stop_total_us != OSNOISE_OPTION_INIT_VAL) 511 return context->orig_stop_total_us; 512 513 stop_total_us = osnoise_read_ll_config("osnoise/stop_tracing_total_us"); 514 if (stop_total_us < 0) 515 goto out_err; 516 517 context->orig_stop_total_us = stop_total_us; 518 return stop_total_us; 519 520 out_err: 521 return OSNOISE_OPTION_INIT_VAL; 522 } 523 524 /* 525 * osnoise_set_stop_total_us - set "stop_tracing_total_us" 526 */ 527 int osnoise_set_stop_total_us(struct osnoise_context *context, long long stop_total_us) 528 { 529 long long curr_stop_total_us = osnoise_get_stop_total_us(context); 530 int retval; 531 532 if (curr_stop_total_us == OSNOISE_OPTION_INIT_VAL) 533 return -1; 534 535 retval = osnoise_write_ll_config("osnoise/stop_tracing_total_us", stop_total_us); 536 if (retval < 0) 537 return -1; 538 539 context->stop_total_us = stop_total_us; 540 541 return 0; 542 } 543 544 /* 545 * osnoise_restore_stop_total_us - restore the original "stop_tracing_total_us" 546 */ 547 void osnoise_restore_stop_total_us(struct osnoise_context *context) 548 { 549 int retval; 550 551 if (context->orig_stop_total_us == OSNOISE_OPTION_INIT_VAL) 552 return; 553 554 if (context->orig_stop_total_us == context->stop_total_us) 555 goto out_done; 556 557 retval = osnoise_write_ll_config("osnoise/stop_tracing_total_us", 558 context->orig_stop_total_us); 559 if (retval < 0) 560 err_msg("Could not restore original osnoise stop_total_us\n"); 561 562 out_done: 563 context->stop_total_us = OSNOISE_OPTION_INIT_VAL; 564 } 565 566 /* 567 * osnoise_put_stop_total_us - restore original values and cleanup data 568 */ 569 void osnoise_put_stop_total_us(struct osnoise_context *context) 570 { 571 osnoise_restore_stop_total_us(context); 572 573 if (context->orig_stop_total_us == OSNOISE_OPTION_INIT_VAL) 574 return; 575 576 context->orig_stop_total_us = OSNOISE_OPTION_INIT_VAL; 577 } 578 579 /* 580 * osnoise_get_print_stack - read and save the original "print_stack" 581 */ 582 static long long 583 osnoise_get_print_stack(struct osnoise_context *context) 584 { 585 long long print_stack; 586 587 if (context->print_stack != OSNOISE_OPTION_INIT_VAL) 588 return context->print_stack; 589 590 if (context->orig_print_stack != OSNOISE_OPTION_INIT_VAL) 591 return context->orig_print_stack; 592 593 print_stack = osnoise_read_ll_config("osnoise/print_stack"); 594 if (print_stack < 0) 595 goto out_err; 596 597 context->orig_print_stack = print_stack; 598 return print_stack; 599 600 out_err: 601 return OSNOISE_OPTION_INIT_VAL; 602 } 603 604 /* 605 * osnoise_set_print_stack - set "print_stack" 606 */ 607 int osnoise_set_print_stack(struct osnoise_context *context, long long print_stack) 608 { 609 long long curr_print_stack = osnoise_get_print_stack(context); 610 int retval; 611 612 if (curr_print_stack == OSNOISE_OPTION_INIT_VAL) 613 return -1; 614 615 retval = osnoise_write_ll_config("osnoise/print_stack", print_stack); 616 if (retval < 0) 617 return -1; 618 619 context->print_stack = print_stack; 620 621 return 0; 622 } 623 624 /* 625 * osnoise_restore_print_stack - restore the original "print_stack" 626 */ 627 void osnoise_restore_print_stack(struct osnoise_context *context) 628 { 629 int retval; 630 631 if (context->orig_print_stack == OSNOISE_OPTION_INIT_VAL) 632 return; 633 634 if (context->orig_print_stack == context->print_stack) 635 goto out_done; 636 637 retval = osnoise_write_ll_config("osnoise/print_stack", context->orig_print_stack); 638 if (retval < 0) 639 err_msg("Could not restore original osnoise print_stack\n"); 640 641 out_done: 642 context->print_stack = OSNOISE_OPTION_INIT_VAL; 643 } 644 645 /* 646 * osnoise_put_print_stack - restore original values and cleanup data 647 */ 648 void osnoise_put_print_stack(struct osnoise_context *context) 649 { 650 osnoise_restore_print_stack(context); 651 652 if (context->orig_print_stack == OSNOISE_OPTION_INIT_VAL) 653 return; 654 655 context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; 656 } 657 658 /* 659 * enable_osnoise - enable osnoise tracer in the trace_instance 660 */ 661 int enable_osnoise(struct trace_instance *trace) 662 { 663 return enable_tracer_by_name(trace->inst, "osnoise"); 664 } 665 666 /* 667 * enable_timerlat - enable timerlat tracer in the trace_instance 668 */ 669 int enable_timerlat(struct trace_instance *trace) 670 { 671 return enable_tracer_by_name(trace->inst, "timerlat"); 672 } 673 674 enum { 675 FLAG_CONTEXT_NEWLY_CREATED = (1 << 0), 676 FLAG_CONTEXT_DELETED = (1 << 1), 677 }; 678 679 /* 680 * osnoise_get_context - increase the usage of a context and return it 681 */ 682 int osnoise_get_context(struct osnoise_context *context) 683 { 684 int ret; 685 686 if (context->flags & FLAG_CONTEXT_DELETED) { 687 ret = -1; 688 } else { 689 context->ref++; 690 ret = 0; 691 } 692 693 return ret; 694 } 695 696 /* 697 * osnoise_context_alloc - alloc an osnoise_context 698 * 699 * The osnoise context contains the information of the "osnoise/" configs. 700 * It is used to set and restore the config. 701 */ 702 struct osnoise_context *osnoise_context_alloc(void) 703 { 704 struct osnoise_context *context; 705 706 context = calloc(1, sizeof(*context)); 707 if (!context) 708 return NULL; 709 710 context->orig_stop_us = OSNOISE_OPTION_INIT_VAL; 711 context->stop_us = OSNOISE_OPTION_INIT_VAL; 712 713 context->orig_stop_total_us = OSNOISE_OPTION_INIT_VAL; 714 context->stop_total_us = OSNOISE_OPTION_INIT_VAL; 715 716 context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; 717 context->print_stack = OSNOISE_OPTION_INIT_VAL; 718 719 osnoise_get_context(context); 720 721 return context; 722 } 723 724 /* 725 * osnoise_put_context - put the osnoise_put_context 726 * 727 * If there is no other user for the context, the original data 728 * is restored. 729 */ 730 void osnoise_put_context(struct osnoise_context *context) 731 { 732 if (--context->ref < 1) 733 context->flags |= FLAG_CONTEXT_DELETED; 734 735 if (!(context->flags & FLAG_CONTEXT_DELETED)) 736 return; 737 738 osnoise_put_cpus(context); 739 osnoise_put_runtime_period(context); 740 osnoise_put_stop_us(context); 741 osnoise_put_stop_total_us(context); 742 osnoise_put_timerlat_period_us(context); 743 osnoise_put_print_stack(context); 744 745 free(context); 746 } 747 748 /* 749 * osnoise_destroy_tool - disable trace, restore configs and free data 750 */ 751 void osnoise_destroy_tool(struct osnoise_tool *top) 752 { 753 if (!top) 754 return; 755 756 trace_instance_destroy(&top->trace); 757 758 if (top->context) 759 osnoise_put_context(top->context); 760 761 free(top); 762 } 763 764 /* 765 * osnoise_init_tool - init an osnoise tool 766 * 767 * It allocs data, create a context to store data and 768 * creates a new trace instance for the tool. 769 */ 770 struct osnoise_tool *osnoise_init_tool(char *tool_name) 771 { 772 struct osnoise_tool *top; 773 int retval; 774 775 top = calloc(1, sizeof(*top)); 776 if (!top) 777 return NULL; 778 779 top->context = osnoise_context_alloc(); 780 if (!top->context) 781 goto out_err; 782 783 retval = trace_instance_init(&top->trace, tool_name); 784 if (retval) 785 goto out_err; 786 787 return top; 788 out_err: 789 osnoise_destroy_tool(top); 790 return NULL; 791 } 792 793 /* 794 * osnoise_init_trace_tool - init a tracer instance to trace osnoise events 795 */ 796 struct osnoise_tool *osnoise_init_trace_tool(char *tracer) 797 { 798 struct osnoise_tool *trace; 799 int retval; 800 801 trace = osnoise_init_tool("osnoise_trace"); 802 if (!trace) 803 return NULL; 804 805 retval = tracefs_event_enable(trace->trace.inst, "osnoise", NULL); 806 if (retval < 0 && !errno) { 807 err_msg("Could not find osnoise events\n"); 808 goto out_err; 809 } 810 811 retval = enable_tracer_by_name(trace->trace.inst, tracer); 812 if (retval) { 813 err_msg("Could not enable %s tracer for tracing\n", tracer); 814 goto out_err; 815 } 816 817 return trace; 818 out_err: 819 osnoise_destroy_tool(trace); 820 return NULL; 821 } 822 823 static void osnoise_usage(void) 824 { 825 int i; 826 827 static const char *msg[] = { 828 "", 829 "osnoise version " VERSION, 830 "", 831 " usage: [rtla] osnoise [MODE] ...", 832 "", 833 " modes:", 834 " top - prints the summary from osnoise tracer", 835 " hist - prints a histogram of osnoise samples", 836 "", 837 "if no MODE is given, the top mode is called, passing the arguments", 838 NULL, 839 }; 840 841 for (i = 0; msg[i]; i++) 842 fprintf(stderr, "%s\n", msg[i]); 843 exit(1); 844 } 845 846 int osnoise_main(int argc, char *argv[]) 847 { 848 if (argc == 0) 849 goto usage; 850 851 /* 852 * if osnoise was called without any argument, run the 853 * default cmdline. 854 */ 855 if (argc == 1) { 856 osnoise_top_main(argc, argv); 857 exit(0); 858 } 859 860 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) { 861 osnoise_usage(); 862 exit(0); 863 } else if (strncmp(argv[1], "-", 1) == 0) { 864 /* the user skipped the tool, call the default one */ 865 osnoise_top_main(argc, argv); 866 exit(0); 867 } else if (strcmp(argv[1], "top") == 0) { 868 osnoise_top_main(argc-1, &argv[1]); 869 exit(0); 870 } else if (strcmp(argv[1], "hist") == 0) { 871 osnoise_hist_main(argc-1, &argv[1]); 872 exit(0); 873 } 874 875 usage: 876 osnoise_usage(); 877 exit(1); 878 } 879