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 */ 24char *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 */ 48int 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 */ 82void 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 102out_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 */ 110void 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 */ 126static 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 */ 150static 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 */ 168unsigned 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 185out_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 */ 194unsigned 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 211out_err: 212 return OSNOISE_TIME_INIT_VAL; 213} 214 215static 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 231static 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 */ 254int 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 */ 304void 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 322out_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 */ 330void 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 */ 344static long long 345osnoise_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 362out_err: 363 return OSNOISE_TIME_INIT_VAL; 364} 365 366/* 367 * osnoise_set_timerlat_period_us - set "timerlat_period_us" 368 */ 369int 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 */ 389void 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 403out_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 */ 410void 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 */ 423static long long 424osnoise_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 441out_err: 442 return OSNOISE_OPTION_INIT_VAL; 443} 444 445/* 446 * osnoise_set_stop_us - set "stop_tracing_us" 447 */ 448int 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 */ 468void 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 482out_done: 483 context->stop_us = OSNOISE_OPTION_INIT_VAL; 484} 485 486/* 487 * osnoise_put_stop_us - restore original values and cleanup data 488 */ 489void 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 */ 502static long long 503osnoise_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 520out_err: 521 return OSNOISE_OPTION_INIT_VAL; 522} 523 524/* 525 * osnoise_set_stop_total_us - set "stop_tracing_total_us" 526 */ 527int 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 */ 547void 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 562out_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 */ 569void 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 */ 582static long long 583osnoise_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 600out_err: 601 return OSNOISE_OPTION_INIT_VAL; 602} 603 604/* 605 * osnoise_set_print_stack - set "print_stack" 606 */ 607int 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 */ 627void 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 641out_done: 642 context->print_stack = OSNOISE_OPTION_INIT_VAL; 643} 644 645/* 646 * osnoise_put_print_stack - restore original values and cleanup data 647 */ 648void 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 */ 661static long long 662osnoise_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 679out_err: 680 return OSNOISE_OPTION_INIT_VAL; 681} 682 683/* 684 * osnoise_set_tracing_thresh - set "tracing_thresh" 685 */ 686int 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 */ 706void 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 720out_done: 721 context->tracing_thresh = OSNOISE_OPTION_INIT_VAL; 722} 723 724/* 725 * osnoise_put_tracing_thresh - restore original values and cleanup data 726 */ 727void 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 737static 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 766out_free: 767 free(options); 768 return retval; 769} 770 771static 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 783static 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 796int 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 816static 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 830out_done: 831 context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL; 832} 833 834static 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 844static 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 857int 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 877static 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 891out_done: 892 context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL; 893} 894 895static 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 */ 908int 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 */ 916int enable_timerlat(struct trace_instance *trace) 917{ 918 return enable_tracer_by_name(trace->inst, "timerlat"); 919} 920 921enum { 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 */ 929int 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 */ 949struct 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 */ 986void 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 */ 1010void 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 */ 1029struct 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; 1047out_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 */ 1055struct 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; 1077out_err: 1078 osnoise_destroy_tool(trace); 1079 return NULL; 1080} 1081 1082static 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 1105int 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 1133usage: 1134 osnoise_usage(1); 1135 exit(1); 1136} 1137 1138int hwnoise_main(int argc, char *argv[]) 1139{ 1140 osnoise_top_main(argc, argv); 1141 exit(0); 1142} 1143