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 * osnoise_get_tracing_thresh - read and save the original "tracing_thresh" 660 */ 661 static long long 662 osnoise_get_tracing_thresh(struct osnoise_context *context) 663 { 664 long long tracing_thresh; 665 666 if (context->tracing_thresh != OSNOISE_OPTION_INIT_VAL) 667 return context->tracing_thresh; 668 669 if (context->orig_tracing_thresh != OSNOISE_OPTION_INIT_VAL) 670 return context->orig_tracing_thresh; 671 672 tracing_thresh = osnoise_read_ll_config("tracing_thresh"); 673 if (tracing_thresh < 0) 674 goto out_err; 675 676 context->orig_tracing_thresh = tracing_thresh; 677 return tracing_thresh; 678 679 out_err: 680 return OSNOISE_OPTION_INIT_VAL; 681 } 682 683 /* 684 * osnoise_set_tracing_thresh - set "tracing_thresh" 685 */ 686 int osnoise_set_tracing_thresh(struct osnoise_context *context, long long tracing_thresh) 687 { 688 long long curr_tracing_thresh = osnoise_get_tracing_thresh(context); 689 int retval; 690 691 if (curr_tracing_thresh == OSNOISE_OPTION_INIT_VAL) 692 return -1; 693 694 retval = osnoise_write_ll_config("tracing_thresh", tracing_thresh); 695 if (retval < 0) 696 return -1; 697 698 context->tracing_thresh = tracing_thresh; 699 700 return 0; 701 } 702 703 /* 704 * osnoise_restore_tracing_thresh - restore the original "tracing_thresh" 705 */ 706 void osnoise_restore_tracing_thresh(struct osnoise_context *context) 707 { 708 int retval; 709 710 if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL) 711 return; 712 713 if (context->orig_tracing_thresh == context->tracing_thresh) 714 goto out_done; 715 716 retval = osnoise_write_ll_config("tracing_thresh", context->orig_tracing_thresh); 717 if (retval < 0) 718 err_msg("Could not restore original tracing_thresh\n"); 719 720 out_done: 721 context->tracing_thresh = OSNOISE_OPTION_INIT_VAL; 722 } 723 724 /* 725 * osnoise_put_tracing_thresh - restore original values and cleanup data 726 */ 727 void osnoise_put_tracing_thresh(struct osnoise_context *context) 728 { 729 osnoise_restore_tracing_thresh(context); 730 731 if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL) 732 return; 733 734 context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL; 735 } 736 737 /* 738 * enable_osnoise - enable osnoise tracer in the trace_instance 739 */ 740 int enable_osnoise(struct trace_instance *trace) 741 { 742 return enable_tracer_by_name(trace->inst, "osnoise"); 743 } 744 745 /* 746 * enable_timerlat - enable timerlat tracer in the trace_instance 747 */ 748 int enable_timerlat(struct trace_instance *trace) 749 { 750 return enable_tracer_by_name(trace->inst, "timerlat"); 751 } 752 753 enum { 754 FLAG_CONTEXT_NEWLY_CREATED = (1 << 0), 755 FLAG_CONTEXT_DELETED = (1 << 1), 756 }; 757 758 /* 759 * osnoise_get_context - increase the usage of a context and return it 760 */ 761 int osnoise_get_context(struct osnoise_context *context) 762 { 763 int ret; 764 765 if (context->flags & FLAG_CONTEXT_DELETED) { 766 ret = -1; 767 } else { 768 context->ref++; 769 ret = 0; 770 } 771 772 return ret; 773 } 774 775 /* 776 * osnoise_context_alloc - alloc an osnoise_context 777 * 778 * The osnoise context contains the information of the "osnoise/" configs. 779 * It is used to set and restore the config. 780 */ 781 struct osnoise_context *osnoise_context_alloc(void) 782 { 783 struct osnoise_context *context; 784 785 context = calloc(1, sizeof(*context)); 786 if (!context) 787 return NULL; 788 789 context->orig_stop_us = OSNOISE_OPTION_INIT_VAL; 790 context->stop_us = OSNOISE_OPTION_INIT_VAL; 791 792 context->orig_stop_total_us = OSNOISE_OPTION_INIT_VAL; 793 context->stop_total_us = OSNOISE_OPTION_INIT_VAL; 794 795 context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; 796 context->print_stack = OSNOISE_OPTION_INIT_VAL; 797 798 context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL; 799 context->tracing_thresh = OSNOISE_OPTION_INIT_VAL; 800 801 osnoise_get_context(context); 802 803 return context; 804 } 805 806 /* 807 * osnoise_put_context - put the osnoise_put_context 808 * 809 * If there is no other user for the context, the original data 810 * is restored. 811 */ 812 void osnoise_put_context(struct osnoise_context *context) 813 { 814 if (--context->ref < 1) 815 context->flags |= FLAG_CONTEXT_DELETED; 816 817 if (!(context->flags & FLAG_CONTEXT_DELETED)) 818 return; 819 820 osnoise_put_cpus(context); 821 osnoise_put_runtime_period(context); 822 osnoise_put_stop_us(context); 823 osnoise_put_stop_total_us(context); 824 osnoise_put_timerlat_period_us(context); 825 osnoise_put_print_stack(context); 826 osnoise_put_tracing_thresh(context); 827 828 free(context); 829 } 830 831 /* 832 * osnoise_destroy_tool - disable trace, restore configs and free data 833 */ 834 void osnoise_destroy_tool(struct osnoise_tool *top) 835 { 836 if (!top) 837 return; 838 839 trace_instance_destroy(&top->trace); 840 841 if (top->context) 842 osnoise_put_context(top->context); 843 844 free(top); 845 } 846 847 /* 848 * osnoise_init_tool - init an osnoise tool 849 * 850 * It allocs data, create a context to store data and 851 * creates a new trace instance for the tool. 852 */ 853 struct osnoise_tool *osnoise_init_tool(char *tool_name) 854 { 855 struct osnoise_tool *top; 856 int retval; 857 858 top = calloc(1, sizeof(*top)); 859 if (!top) 860 return NULL; 861 862 top->context = osnoise_context_alloc(); 863 if (!top->context) 864 goto out_err; 865 866 retval = trace_instance_init(&top->trace, tool_name); 867 if (retval) 868 goto out_err; 869 870 return top; 871 out_err: 872 osnoise_destroy_tool(top); 873 return NULL; 874 } 875 876 /* 877 * osnoise_init_trace_tool - init a tracer instance to trace osnoise events 878 */ 879 struct osnoise_tool *osnoise_init_trace_tool(char *tracer) 880 { 881 struct osnoise_tool *trace; 882 int retval; 883 884 trace = osnoise_init_tool("osnoise_trace"); 885 if (!trace) 886 return NULL; 887 888 retval = tracefs_event_enable(trace->trace.inst, "osnoise", NULL); 889 if (retval < 0 && !errno) { 890 err_msg("Could not find osnoise events\n"); 891 goto out_err; 892 } 893 894 retval = enable_tracer_by_name(trace->trace.inst, tracer); 895 if (retval) { 896 err_msg("Could not enable %s tracer for tracing\n", tracer); 897 goto out_err; 898 } 899 900 return trace; 901 out_err: 902 osnoise_destroy_tool(trace); 903 return NULL; 904 } 905 906 static void osnoise_usage(int err) 907 { 908 int i; 909 910 static const char *msg[] = { 911 "", 912 "osnoise version " VERSION, 913 "", 914 " usage: [rtla] osnoise [MODE] ...", 915 "", 916 " modes:", 917 " top - prints the summary from osnoise tracer", 918 " hist - prints a histogram of osnoise samples", 919 "", 920 "if no MODE is given, the top mode is called, passing the arguments", 921 NULL, 922 }; 923 924 for (i = 0; msg[i]; i++) 925 fprintf(stderr, "%s\n", msg[i]); 926 exit(err); 927 } 928 929 int osnoise_main(int argc, char *argv[]) 930 { 931 if (argc == 0) 932 goto usage; 933 934 /* 935 * if osnoise was called without any argument, run the 936 * default cmdline. 937 */ 938 if (argc == 1) { 939 osnoise_top_main(argc, argv); 940 exit(0); 941 } 942 943 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) { 944 osnoise_usage(0); 945 } else if (strncmp(argv[1], "-", 1) == 0) { 946 /* the user skipped the tool, call the default one */ 947 osnoise_top_main(argc, argv); 948 exit(0); 949 } else if (strcmp(argv[1], "top") == 0) { 950 osnoise_top_main(argc-1, &argv[1]); 951 exit(0); 952 } else if (strcmp(argv[1], "hist") == 0) { 953 osnoise_hist_main(argc-1, &argv[1]); 954 exit(0); 955 } 956 957 usage: 958 osnoise_usage(1); 959 exit(1); 960 } 961