1143 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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" content21 *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 *cpus43 *44 * "osnoise/cpus" file is used to set the cpus in which osnoise/timerlat45 * 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 previously80 * 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 data109 */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 config123 *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_path147 *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" value165 *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" value191 *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 period249 *250 * Osnoise's runtime and period are related as runtime <= period.251 * Thus, this function saves the original values, and then tries252 * 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 period303 */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 data329 */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 long345osnoise_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 data409 */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 long424osnoise_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 data488 */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 long503osnoise_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 data568 */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 long583osnoise_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 data647 */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 long662osnoise_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 data726 */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 is758 * 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 else764 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_instance907 */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_instance915 */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 it928 */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_context945 *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_context982 *983 * If there is no other user for the context, the original data984 * 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 data1009 */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 tool1025 *1026 * It allocs data, create a context to store data and1027 * 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 events1054 */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 the1112 * 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