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 static int osnoise_options_get_option(char *option) 738 { 739 char *options = tracefs_instance_file_read(NULL, "osnoise/options", NULL); 740 char no_option[128]; 741 int retval = 0; 742 char *opt; 743 744 if (!options) 745 return OSNOISE_OPTION_INIT_VAL; 746 747 /* 748 * Check first if the option is disabled. 749 */ 750 snprintf(no_option, sizeof(no_option), "NO_%s", option); 751 752 opt = strstr(options, no_option); 753 if (opt) 754 goto out_free; 755 756 /* 757 * Now that it is not disabled, if the string is there, it is 758 * enabled. If the string is not there, the option does not exist. 759 */ 760 opt = strstr(options, option); 761 if (opt) 762 retval = 1; 763 else 764 retval = OSNOISE_OPTION_INIT_VAL; 765 766 out_free: 767 free(options); 768 return retval; 769 } 770 771 static int osnoise_options_set_option(char *option, bool onoff) 772 { 773 char no_option[128]; 774 775 if (onoff) 776 return tracefs_instance_file_write(NULL, "osnoise/options", option); 777 778 snprintf(no_option, sizeof(no_option), "NO_%s", option); 779 780 return tracefs_instance_file_write(NULL, "osnoise/options", no_option); 781 } 782 783 static int osnoise_get_irq_disable(struct osnoise_context *context) 784 { 785 if (context->opt_irq_disable != OSNOISE_OPTION_INIT_VAL) 786 return context->opt_irq_disable; 787 788 if (context->orig_opt_irq_disable != OSNOISE_OPTION_INIT_VAL) 789 return context->orig_opt_irq_disable; 790 791 context->orig_opt_irq_disable = osnoise_options_get_option("OSNOISE_IRQ_DISABLE"); 792 793 return context->orig_opt_irq_disable; 794 } 795 796 int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff) 797 { 798 int opt_irq_disable = osnoise_get_irq_disable(context); 799 int retval; 800 801 if (opt_irq_disable == OSNOISE_OPTION_INIT_VAL) 802 return -1; 803 804 if (opt_irq_disable == onoff) 805 return 0; 806 807 retval = osnoise_options_set_option("OSNOISE_IRQ_DISABLE", onoff); 808 if (retval < 0) 809 return -1; 810 811 context->opt_irq_disable = onoff; 812 813 return 0; 814 } 815 816 static void osnoise_restore_irq_disable(struct osnoise_context *context) 817 { 818 int retval; 819 820 if (context->orig_opt_irq_disable == OSNOISE_OPTION_INIT_VAL) 821 return; 822 823 if (context->orig_opt_irq_disable == context->opt_irq_disable) 824 goto out_done; 825 826 retval = osnoise_options_set_option("OSNOISE_IRQ_DISABLE", context->orig_opt_irq_disable); 827 if (retval < 0) 828 err_msg("Could not restore original OSNOISE_IRQ_DISABLE option\n"); 829 830 out_done: 831 context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 832 } 833 834 static void osnoise_put_irq_disable(struct osnoise_context *context) 835 { 836 osnoise_restore_irq_disable(context); 837 838 if (context->orig_opt_irq_disable == OSNOISE_OPTION_INIT_VAL) 839 return; 840 841 context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 842 } 843 844 static int osnoise_get_workload(struct osnoise_context *context) 845 { 846 if (context->opt_workload != OSNOISE_OPTION_INIT_VAL) 847 return context->opt_workload; 848 849 if (context->orig_opt_workload != OSNOISE_OPTION_INIT_VAL) 850 return context->orig_opt_workload; 851 852 context->orig_opt_workload = osnoise_options_get_option("OSNOISE_WORKLOAD"); 853 854 return context->orig_opt_workload; 855 } 856 857 int osnoise_set_workload(struct osnoise_context *context, bool onoff) 858 { 859 int opt_workload = osnoise_get_workload(context); 860 int retval; 861 862 if (opt_workload == OSNOISE_OPTION_INIT_VAL) 863 return -1; 864 865 if (opt_workload == onoff) 866 return 0; 867 868 retval = osnoise_options_set_option("OSNOISE_WORKLOAD", onoff); 869 if (retval < 0) 870 return -1; 871 872 context->opt_workload = onoff; 873 874 return 0; 875 } 876 877 static void osnoise_restore_workload(struct osnoise_context *context) 878 { 879 int retval; 880 881 if (context->orig_opt_workload == OSNOISE_OPTION_INIT_VAL) 882 return; 883 884 if (context->orig_opt_workload == context->opt_workload) 885 goto out_done; 886 887 retval = osnoise_options_set_option("OSNOISE_WORKLOAD", context->orig_opt_workload); 888 if (retval < 0) 889 err_msg("Could not restore original OSNOISE_WORKLOAD option\n"); 890 891 out_done: 892 context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL; 893 } 894 895 static void osnoise_put_workload(struct osnoise_context *context) 896 { 897 osnoise_restore_workload(context); 898 899 if (context->orig_opt_workload == OSNOISE_OPTION_INIT_VAL) 900 return; 901 902 context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL; 903 } 904 905 /* 906 * enable_osnoise - enable osnoise tracer in the trace_instance 907 */ 908 int enable_osnoise(struct trace_instance *trace) 909 { 910 return enable_tracer_by_name(trace->inst, "osnoise"); 911 } 912 913 /* 914 * enable_timerlat - enable timerlat tracer in the trace_instance 915 */ 916 int enable_timerlat(struct trace_instance *trace) 917 { 918 return enable_tracer_by_name(trace->inst, "timerlat"); 919 } 920 921 enum { 922 FLAG_CONTEXT_NEWLY_CREATED = (1 << 0), 923 FLAG_CONTEXT_DELETED = (1 << 1), 924 }; 925 926 /* 927 * osnoise_get_context - increase the usage of a context and return it 928 */ 929 int osnoise_get_context(struct osnoise_context *context) 930 { 931 int ret; 932 933 if (context->flags & FLAG_CONTEXT_DELETED) { 934 ret = -1; 935 } else { 936 context->ref++; 937 ret = 0; 938 } 939 940 return ret; 941 } 942 943 /* 944 * osnoise_context_alloc - alloc an osnoise_context 945 * 946 * The osnoise context contains the information of the "osnoise/" configs. 947 * It is used to set and restore the config. 948 */ 949 struct osnoise_context *osnoise_context_alloc(void) 950 { 951 struct osnoise_context *context; 952 953 context = calloc(1, sizeof(*context)); 954 if (!context) 955 return NULL; 956 957 context->orig_stop_us = OSNOISE_OPTION_INIT_VAL; 958 context->stop_us = OSNOISE_OPTION_INIT_VAL; 959 960 context->orig_stop_total_us = OSNOISE_OPTION_INIT_VAL; 961 context->stop_total_us = OSNOISE_OPTION_INIT_VAL; 962 963 context->orig_print_stack = OSNOISE_OPTION_INIT_VAL; 964 context->print_stack = OSNOISE_OPTION_INIT_VAL; 965 966 context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL; 967 context->tracing_thresh = OSNOISE_OPTION_INIT_VAL; 968 969 context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 970 context->opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 971 972 context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL; 973 context->opt_workload = OSNOISE_OPTION_INIT_VAL; 974 975 osnoise_get_context(context); 976 977 return context; 978 } 979 980 /* 981 * osnoise_put_context - put the osnoise_put_context 982 * 983 * If there is no other user for the context, the original data 984 * is restored. 985 */ 986 void osnoise_put_context(struct osnoise_context *context) 987 { 988 if (--context->ref < 1) 989 context->flags |= FLAG_CONTEXT_DELETED; 990 991 if (!(context->flags & FLAG_CONTEXT_DELETED)) 992 return; 993 994 osnoise_put_cpus(context); 995 osnoise_put_runtime_period(context); 996 osnoise_put_stop_us(context); 997 osnoise_put_stop_total_us(context); 998 osnoise_put_timerlat_period_us(context); 999 osnoise_put_print_stack(context); 1000 osnoise_put_tracing_thresh(context); 1001 osnoise_put_irq_disable(context); 1002 osnoise_put_workload(context); 1003 1004 free(context); 1005 } 1006 1007 /* 1008 * osnoise_destroy_tool - disable trace, restore configs and free data 1009 */ 1010 void osnoise_destroy_tool(struct osnoise_tool *top) 1011 { 1012 if (!top) 1013 return; 1014 1015 trace_instance_destroy(&top->trace); 1016 1017 if (top->context) 1018 osnoise_put_context(top->context); 1019 1020 free(top); 1021 } 1022 1023 /* 1024 * osnoise_init_tool - init an osnoise tool 1025 * 1026 * It allocs data, create a context to store data and 1027 * creates a new trace instance for the tool. 1028 */ 1029 struct osnoise_tool *osnoise_init_tool(char *tool_name) 1030 { 1031 struct osnoise_tool *top; 1032 int retval; 1033 1034 top = calloc(1, sizeof(*top)); 1035 if (!top) 1036 return NULL; 1037 1038 top->context = osnoise_context_alloc(); 1039 if (!top->context) 1040 goto out_err; 1041 1042 retval = trace_instance_init(&top->trace, tool_name); 1043 if (retval) 1044 goto out_err; 1045 1046 return top; 1047 out_err: 1048 osnoise_destroy_tool(top); 1049 return NULL; 1050 } 1051 1052 /* 1053 * osnoise_init_trace_tool - init a tracer instance to trace osnoise events 1054 */ 1055 struct osnoise_tool *osnoise_init_trace_tool(char *tracer) 1056 { 1057 struct osnoise_tool *trace; 1058 int retval; 1059 1060 trace = osnoise_init_tool("osnoise_trace"); 1061 if (!trace) 1062 return NULL; 1063 1064 retval = tracefs_event_enable(trace->trace.inst, "osnoise", NULL); 1065 if (retval < 0 && !errno) { 1066 err_msg("Could not find osnoise events\n"); 1067 goto out_err; 1068 } 1069 1070 retval = enable_tracer_by_name(trace->trace.inst, tracer); 1071 if (retval) { 1072 err_msg("Could not enable %s tracer for tracing\n", tracer); 1073 goto out_err; 1074 } 1075 1076 return trace; 1077 out_err: 1078 osnoise_destroy_tool(trace); 1079 return NULL; 1080 } 1081 1082 static void osnoise_usage(int err) 1083 { 1084 int i; 1085 1086 static const char *msg[] = { 1087 "", 1088 "osnoise version " VERSION, 1089 "", 1090 " usage: [rtla] osnoise [MODE] ...", 1091 "", 1092 " modes:", 1093 " top - prints the summary from osnoise tracer", 1094 " hist - prints a histogram of osnoise samples", 1095 "", 1096 "if no MODE is given, the top mode is called, passing the arguments", 1097 NULL, 1098 }; 1099 1100 for (i = 0; msg[i]; i++) 1101 fprintf(stderr, "%s\n", msg[i]); 1102 exit(err); 1103 } 1104 1105 int osnoise_main(int argc, char *argv[]) 1106 { 1107 if (argc == 0) 1108 goto usage; 1109 1110 /* 1111 * if osnoise was called without any argument, run the 1112 * default cmdline. 1113 */ 1114 if (argc == 1) { 1115 osnoise_top_main(argc, argv); 1116 exit(0); 1117 } 1118 1119 if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) { 1120 osnoise_usage(0); 1121 } else if (strncmp(argv[1], "-", 1) == 0) { 1122 /* the user skipped the tool, call the default one */ 1123 osnoise_top_main(argc, argv); 1124 exit(0); 1125 } else if (strcmp(argv[1], "top") == 0) { 1126 osnoise_top_main(argc-1, &argv[1]); 1127 exit(0); 1128 } else if (strcmp(argv[1], "hist") == 0) { 1129 osnoise_hist_main(argc-1, &argv[1]); 1130 exit(0); 1131 } 1132 1133 usage: 1134 osnoise_usage(1); 1135 exit(1); 1136 } 1137 1138 int hwnoise_main(int argc, char *argv[]) 1139 { 1140 osnoise_top_main(argc, argv); 1141 exit(0); 1142 } 1143