Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
0004  */
0005 
0006 #include <sys/types.h>
0007 #include <sys/stat.h>
0008 #include <pthread.h>
0009 #include <stdlib.h>
0010 #include <string.h>
0011 #include <unistd.h>
0012 #include <errno.h>
0013 #include <fcntl.h>
0014 #include <stdio.h>
0015 
0016 #include "osnoise.h"
0017 #include "utils.h"
0018 
0019 /*
0020  * osnoise_get_cpus - return the original "osnoise/cpus" content
0021  *
0022  * It also saves the value to be restored.
0023  */
0024 char *osnoise_get_cpus(struct osnoise_context *context)
0025 {
0026     if (context->curr_cpus)
0027         return context->curr_cpus;
0028 
0029     if (context->orig_cpus)
0030         return context->orig_cpus;
0031 
0032     context->orig_cpus = tracefs_instance_file_read(NULL, "osnoise/cpus", NULL);
0033 
0034     /*
0035      * The error value (NULL) is the same for tracefs_instance_file_read()
0036      * and this functions, so:
0037      */
0038     return context->orig_cpus;
0039 }
0040 
0041 /*
0042  * osnoise_set_cpus - configure osnoise to run on *cpus
0043  *
0044  * "osnoise/cpus" file is used to set the cpus in which osnoise/timerlat
0045  * will run. This function opens this file, saves the current value,
0046  * and set the cpus passed as argument.
0047  */
0048 int osnoise_set_cpus(struct osnoise_context *context, char *cpus)
0049 {
0050     char *orig_cpus = osnoise_get_cpus(context);
0051     char buffer[1024];
0052     int retval;
0053 
0054     if (!orig_cpus)
0055         return -1;
0056 
0057     context->curr_cpus = strdup(cpus);
0058     if (!context->curr_cpus)
0059         return -1;
0060 
0061     snprintf(buffer, 1024, "%s\n", cpus);
0062 
0063     debug_msg("setting cpus to %s from %s", cpus, context->orig_cpus);
0064 
0065     retval = tracefs_instance_file_write(NULL, "osnoise/cpus", buffer);
0066     if (retval < 0) {
0067         free(context->curr_cpus);
0068         context->curr_cpus = NULL;
0069         return -1;
0070     }
0071 
0072     return 0;
0073 }
0074 
0075 /*
0076  * osnoise_restore_cpus - restore the original "osnoise/cpus"
0077  *
0078  * osnoise_set_cpus() saves the original data for the "osnoise/cpus"
0079  * file. This function restore the original config it was previously
0080  * modified.
0081  */
0082 void osnoise_restore_cpus(struct osnoise_context *context)
0083 {
0084     int retval;
0085 
0086     if (!context->orig_cpus)
0087         return;
0088 
0089     if (!context->curr_cpus)
0090         return;
0091 
0092     /* nothing to do? */
0093     if (!strcmp(context->orig_cpus, context->curr_cpus))
0094         goto out_done;
0095 
0096     debug_msg("restoring cpus to %s", context->orig_cpus);
0097 
0098     retval = tracefs_instance_file_write(NULL, "osnoise/cpus", context->orig_cpus);
0099     if (retval < 0)
0100         err_msg("could not restore original osnoise cpus\n");
0101 
0102 out_done:
0103     free(context->curr_cpus);
0104     context->curr_cpus = NULL;
0105 }
0106 
0107 /*
0108  * osnoise_put_cpus - restore cpus config and cleanup data
0109  */
0110 void osnoise_put_cpus(struct osnoise_context *context)
0111 {
0112     osnoise_restore_cpus(context);
0113 
0114     if (!context->orig_cpus)
0115         return;
0116 
0117     free(context->orig_cpus);
0118     context->orig_cpus = NULL;
0119 }
0120 
0121 /*
0122  * osnoise_read_ll_config - read a long long value from a config
0123  *
0124  * returns -1 on error.
0125  */
0126 static long long osnoise_read_ll_config(char *rel_path)
0127 {
0128     long long retval;
0129     char *buffer;
0130 
0131     buffer = tracefs_instance_file_read(NULL, rel_path, NULL);
0132     if (!buffer)
0133         return -1;
0134 
0135     /* get_llong_from_str returns -1 on error */
0136     retval = get_llong_from_str(buffer);
0137 
0138     debug_msg("reading %s returned %lld\n", rel_path, retval);
0139 
0140     free(buffer);
0141 
0142     return retval;
0143 }
0144 
0145 /*
0146  * osnoise_write_ll_config - write a long long value to a config in rel_path
0147  *
0148  * returns -1 on error.
0149  */
0150 static long long osnoise_write_ll_config(char *rel_path, long long value)
0151 {
0152     char buffer[BUFF_U64_STR_SIZE];
0153     long long retval;
0154 
0155     snprintf(buffer, sizeof(buffer), "%lld\n", value);
0156 
0157     debug_msg("setting %s to %lld\n", rel_path, value);
0158 
0159     retval = tracefs_instance_file_write(NULL, rel_path, buffer);
0160     return retval;
0161 }
0162 
0163 /*
0164  * osnoise_get_runtime - return the original "osnoise/runtime_us" value
0165  *
0166  * It also saves the value to be restored.
0167  */
0168 unsigned long long osnoise_get_runtime(struct osnoise_context *context)
0169 {
0170     long long runtime_us;
0171 
0172     if (context->runtime_us != OSNOISE_TIME_INIT_VAL)
0173         return context->runtime_us;
0174 
0175     if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL)
0176         return context->orig_runtime_us;
0177 
0178     runtime_us = osnoise_read_ll_config("osnoise/runtime_us");
0179     if (runtime_us < 0)
0180         goto out_err;
0181 
0182     context->orig_runtime_us = runtime_us;
0183     return runtime_us;
0184 
0185 out_err:
0186     return OSNOISE_TIME_INIT_VAL;
0187 }
0188 
0189 /*
0190  * osnoise_get_period - return the original "osnoise/period_us" value
0191  *
0192  * It also saves the value to be restored.
0193  */
0194 unsigned long long osnoise_get_period(struct osnoise_context *context)
0195 {
0196     long long period_us;
0197 
0198     if (context->period_us != OSNOISE_TIME_INIT_VAL)
0199         return context->period_us;
0200 
0201     if (context->orig_period_us != OSNOISE_TIME_INIT_VAL)
0202         return context->orig_period_us;
0203 
0204     period_us = osnoise_read_ll_config("osnoise/period_us");
0205     if (period_us < 0)
0206         goto out_err;
0207 
0208     context->orig_period_us = period_us;
0209     return period_us;
0210 
0211 out_err:
0212     return OSNOISE_TIME_INIT_VAL;
0213 }
0214 
0215 static int __osnoise_write_runtime(struct osnoise_context *context,
0216                    unsigned long long runtime)
0217 {
0218     int retval;
0219 
0220     if (context->orig_runtime_us == OSNOISE_TIME_INIT_VAL)
0221         return -1;
0222 
0223     retval = osnoise_write_ll_config("osnoise/runtime_us", runtime);
0224     if (retval < 0)
0225         return -1;
0226 
0227     context->runtime_us = runtime;
0228     return 0;
0229 }
0230 
0231 static int __osnoise_write_period(struct osnoise_context *context,
0232                   unsigned long long period)
0233 {
0234     int retval;
0235 
0236     if (context->orig_period_us == OSNOISE_TIME_INIT_VAL)
0237         return -1;
0238 
0239     retval = osnoise_write_ll_config("osnoise/period_us", period);
0240     if (retval < 0)
0241         return -1;
0242 
0243     context->period_us = period;
0244     return 0;
0245 }
0246 
0247 /*
0248  * osnoise_set_runtime_period - set osnoise runtime and period
0249  *
0250  * Osnoise's runtime and period are related as runtime <= period.
0251  * Thus, this function saves the original values, and then tries
0252  * to set the runtime and period if they are != 0.
0253  */
0254 int osnoise_set_runtime_period(struct osnoise_context *context,
0255                    unsigned long long runtime,
0256                    unsigned long long period)
0257 {
0258     unsigned long long curr_runtime_us;
0259     unsigned long long curr_period_us;
0260     int retval;
0261 
0262     if (!period && !runtime)
0263         return 0;
0264 
0265     curr_runtime_us = osnoise_get_runtime(context);
0266     curr_period_us = osnoise_get_period(context);
0267 
0268     /* error getting any value? */
0269     if (curr_period_us == OSNOISE_TIME_INIT_VAL || curr_runtime_us == OSNOISE_TIME_INIT_VAL)
0270         return -1;
0271 
0272     if (!period) {
0273         if (runtime > curr_period_us)
0274             return -1;
0275         return __osnoise_write_runtime(context, runtime);
0276     } else if (!runtime) {
0277         if (period < curr_runtime_us)
0278             return -1;
0279         return __osnoise_write_period(context, period);
0280     }
0281 
0282     if (runtime > curr_period_us) {
0283         retval = __osnoise_write_period(context, period);
0284         if (retval)
0285             return -1;
0286         retval = __osnoise_write_runtime(context, runtime);
0287         if (retval)
0288             return -1;
0289     } else {
0290         retval = __osnoise_write_runtime(context, runtime);
0291         if (retval)
0292             return -1;
0293         retval = __osnoise_write_period(context, period);
0294         if (retval)
0295             return -1;
0296     }
0297 
0298     return 0;
0299 }
0300 
0301 /*
0302  * osnoise_restore_runtime_period - restore the original runtime and period
0303  */
0304 void osnoise_restore_runtime_period(struct osnoise_context *context)
0305 {
0306     unsigned long long orig_runtime = context->orig_runtime_us;
0307     unsigned long long orig_period = context->orig_period_us;
0308     unsigned long long curr_runtime = context->runtime_us;
0309     unsigned long long curr_period = context->period_us;
0310     int retval;
0311 
0312     if ((orig_runtime == OSNOISE_TIME_INIT_VAL) && (orig_period == OSNOISE_TIME_INIT_VAL))
0313         return;
0314 
0315     if ((orig_period == curr_period) && (orig_runtime == curr_runtime))
0316         goto out_done;
0317 
0318     retval = osnoise_set_runtime_period(context, orig_runtime, orig_period);
0319     if (retval)
0320         err_msg("Could not restore original osnoise runtime/period\n");
0321 
0322 out_done:
0323     context->runtime_us = OSNOISE_TIME_INIT_VAL;
0324     context->period_us = OSNOISE_TIME_INIT_VAL;
0325 }
0326 
0327 /*
0328  * osnoise_put_runtime_period - restore original values and cleanup data
0329  */
0330 void osnoise_put_runtime_period(struct osnoise_context *context)
0331 {
0332     osnoise_restore_runtime_period(context);
0333 
0334     if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL)
0335         context->orig_runtime_us = OSNOISE_TIME_INIT_VAL;
0336 
0337     if (context->orig_period_us != OSNOISE_TIME_INIT_VAL)
0338         context->orig_period_us = OSNOISE_TIME_INIT_VAL;
0339 }
0340 
0341 /*
0342  * osnoise_get_timerlat_period_us - read and save the original "timerlat_period_us"
0343  */
0344 static long long
0345 osnoise_get_timerlat_period_us(struct osnoise_context *context)
0346 {
0347     long long timerlat_period_us;
0348 
0349     if (context->timerlat_period_us != OSNOISE_TIME_INIT_VAL)
0350         return context->timerlat_period_us;
0351 
0352     if (context->orig_timerlat_period_us != OSNOISE_TIME_INIT_VAL)
0353         return context->orig_timerlat_period_us;
0354 
0355     timerlat_period_us = osnoise_read_ll_config("osnoise/timerlat_period_us");
0356     if (timerlat_period_us < 0)
0357         goto out_err;
0358 
0359     context->orig_timerlat_period_us = timerlat_period_us;
0360     return timerlat_period_us;
0361 
0362 out_err:
0363     return OSNOISE_TIME_INIT_VAL;
0364 }
0365 
0366 /*
0367  * osnoise_set_timerlat_period_us - set "timerlat_period_us"
0368  */
0369 int osnoise_set_timerlat_period_us(struct osnoise_context *context, long long timerlat_period_us)
0370 {
0371     long long curr_timerlat_period_us = osnoise_get_timerlat_period_us(context);
0372     int retval;
0373 
0374     if (curr_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
0375         return -1;
0376 
0377     retval = osnoise_write_ll_config("osnoise/timerlat_period_us", timerlat_period_us);
0378     if (retval < 0)
0379         return -1;
0380 
0381     context->timerlat_period_us = timerlat_period_us;
0382 
0383     return 0;
0384 }
0385 
0386 /*
0387  * osnoise_restore_timerlat_period_us - restore "timerlat_period_us"
0388  */
0389 void osnoise_restore_timerlat_period_us(struct osnoise_context *context)
0390 {
0391     int retval;
0392 
0393     if (context->orig_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
0394         return;
0395 
0396     if (context->orig_timerlat_period_us == context->timerlat_period_us)
0397         goto out_done;
0398 
0399     retval = osnoise_write_ll_config("osnoise/timerlat_period_us", context->orig_timerlat_period_us);
0400     if (retval < 0)
0401         err_msg("Could not restore original osnoise timerlat_period_us\n");
0402 
0403 out_done:
0404     context->timerlat_period_us = OSNOISE_TIME_INIT_VAL;
0405 }
0406 
0407 /*
0408  * osnoise_put_timerlat_period_us - restore original values and cleanup data
0409  */
0410 void osnoise_put_timerlat_period_us(struct osnoise_context *context)
0411 {
0412     osnoise_restore_timerlat_period_us(context);
0413 
0414     if (context->orig_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
0415         return;
0416 
0417     context->orig_timerlat_period_us = OSNOISE_TIME_INIT_VAL;
0418 }
0419 
0420 /*
0421  * osnoise_get_stop_us - read and save the original "stop_tracing_us"
0422  */
0423 static long long
0424 osnoise_get_stop_us(struct osnoise_context *context)
0425 {
0426     long long stop_us;
0427 
0428     if (context->stop_us != OSNOISE_OPTION_INIT_VAL)
0429         return context->stop_us;
0430 
0431     if (context->orig_stop_us != OSNOISE_OPTION_INIT_VAL)
0432         return context->orig_stop_us;
0433 
0434     stop_us = osnoise_read_ll_config("osnoise/stop_tracing_us");
0435     if (stop_us < 0)
0436         goto out_err;
0437 
0438     context->orig_stop_us = stop_us;
0439     return stop_us;
0440 
0441 out_err:
0442     return OSNOISE_OPTION_INIT_VAL;
0443 }
0444 
0445 /*
0446  * osnoise_set_stop_us - set "stop_tracing_us"
0447  */
0448 int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us)
0449 {
0450     long long curr_stop_us = osnoise_get_stop_us(context);
0451     int retval;
0452 
0453     if (curr_stop_us == OSNOISE_OPTION_INIT_VAL)
0454         return -1;
0455 
0456     retval = osnoise_write_ll_config("osnoise/stop_tracing_us", stop_us);
0457     if (retval < 0)
0458         return -1;
0459 
0460     context->stop_us = stop_us;
0461 
0462     return 0;
0463 }
0464 
0465 /*
0466  * osnoise_restore_stop_us - restore the original "stop_tracing_us"
0467  */
0468 void osnoise_restore_stop_us(struct osnoise_context *context)
0469 {
0470     int retval;
0471 
0472     if (context->orig_stop_us == OSNOISE_OPTION_INIT_VAL)
0473         return;
0474 
0475     if (context->orig_stop_us == context->stop_us)
0476         goto out_done;
0477 
0478     retval = osnoise_write_ll_config("osnoise/stop_tracing_us", context->orig_stop_us);
0479     if (retval < 0)
0480         err_msg("Could not restore original osnoise stop_us\n");
0481 
0482 out_done:
0483     context->stop_us = OSNOISE_OPTION_INIT_VAL;
0484 }
0485 
0486 /*
0487  * osnoise_put_stop_us - restore original values and cleanup data
0488  */
0489 void osnoise_put_stop_us(struct osnoise_context *context)
0490 {
0491     osnoise_restore_stop_us(context);
0492 
0493     if (context->orig_stop_us == OSNOISE_OPTION_INIT_VAL)
0494         return;
0495 
0496     context->orig_stop_us = OSNOISE_OPTION_INIT_VAL;
0497 }
0498 
0499 /*
0500  * osnoise_get_stop_total_us - read and save the original "stop_tracing_total_us"
0501  */
0502 static long long
0503 osnoise_get_stop_total_us(struct osnoise_context *context)
0504 {
0505     long long stop_total_us;
0506 
0507     if (context->stop_total_us != OSNOISE_OPTION_INIT_VAL)
0508         return context->stop_total_us;
0509 
0510     if (context->orig_stop_total_us != OSNOISE_OPTION_INIT_VAL)
0511         return context->orig_stop_total_us;
0512 
0513     stop_total_us = osnoise_read_ll_config("osnoise/stop_tracing_total_us");
0514     if (stop_total_us < 0)
0515         goto out_err;
0516 
0517     context->orig_stop_total_us = stop_total_us;
0518     return stop_total_us;
0519 
0520 out_err:
0521     return OSNOISE_OPTION_INIT_VAL;
0522 }
0523 
0524 /*
0525  * osnoise_set_stop_total_us - set "stop_tracing_total_us"
0526  */
0527 int osnoise_set_stop_total_us(struct osnoise_context *context, long long stop_total_us)
0528 {
0529     long long curr_stop_total_us = osnoise_get_stop_total_us(context);
0530     int retval;
0531 
0532     if (curr_stop_total_us == OSNOISE_OPTION_INIT_VAL)
0533         return -1;
0534 
0535     retval = osnoise_write_ll_config("osnoise/stop_tracing_total_us", stop_total_us);
0536     if (retval < 0)
0537         return -1;
0538 
0539     context->stop_total_us = stop_total_us;
0540 
0541     return 0;
0542 }
0543 
0544 /*
0545  * osnoise_restore_stop_total_us - restore the original "stop_tracing_total_us"
0546  */
0547 void osnoise_restore_stop_total_us(struct osnoise_context *context)
0548 {
0549     int retval;
0550 
0551     if (context->orig_stop_total_us == OSNOISE_OPTION_INIT_VAL)
0552         return;
0553 
0554     if (context->orig_stop_total_us == context->stop_total_us)
0555         goto out_done;
0556 
0557     retval = osnoise_write_ll_config("osnoise/stop_tracing_total_us",
0558             context->orig_stop_total_us);
0559     if (retval < 0)
0560         err_msg("Could not restore original osnoise stop_total_us\n");
0561 
0562 out_done:
0563     context->stop_total_us = OSNOISE_OPTION_INIT_VAL;
0564 }
0565 
0566 /*
0567  * osnoise_put_stop_total_us - restore original values and cleanup data
0568  */
0569 void osnoise_put_stop_total_us(struct osnoise_context *context)
0570 {
0571     osnoise_restore_stop_total_us(context);
0572 
0573     if (context->orig_stop_total_us == OSNOISE_OPTION_INIT_VAL)
0574         return;
0575 
0576     context->orig_stop_total_us = OSNOISE_OPTION_INIT_VAL;
0577 }
0578 
0579 /*
0580  * osnoise_get_print_stack - read and save the original "print_stack"
0581  */
0582 static long long
0583 osnoise_get_print_stack(struct osnoise_context *context)
0584 {
0585     long long print_stack;
0586 
0587     if (context->print_stack != OSNOISE_OPTION_INIT_VAL)
0588         return context->print_stack;
0589 
0590     if (context->orig_print_stack != OSNOISE_OPTION_INIT_VAL)
0591         return context->orig_print_stack;
0592 
0593     print_stack = osnoise_read_ll_config("osnoise/print_stack");
0594     if (print_stack < 0)
0595         goto out_err;
0596 
0597     context->orig_print_stack = print_stack;
0598     return print_stack;
0599 
0600 out_err:
0601     return OSNOISE_OPTION_INIT_VAL;
0602 }
0603 
0604 /*
0605  * osnoise_set_print_stack - set "print_stack"
0606  */
0607 int osnoise_set_print_stack(struct osnoise_context *context, long long print_stack)
0608 {
0609     long long curr_print_stack = osnoise_get_print_stack(context);
0610     int retval;
0611 
0612     if (curr_print_stack == OSNOISE_OPTION_INIT_VAL)
0613         return -1;
0614 
0615     retval = osnoise_write_ll_config("osnoise/print_stack", print_stack);
0616     if (retval < 0)
0617         return -1;
0618 
0619     context->print_stack = print_stack;
0620 
0621     return 0;
0622 }
0623 
0624 /*
0625  * osnoise_restore_print_stack - restore the original "print_stack"
0626  */
0627 void osnoise_restore_print_stack(struct osnoise_context *context)
0628 {
0629     int retval;
0630 
0631     if (context->orig_print_stack == OSNOISE_OPTION_INIT_VAL)
0632         return;
0633 
0634     if (context->orig_print_stack == context->print_stack)
0635         goto out_done;
0636 
0637     retval = osnoise_write_ll_config("osnoise/print_stack", context->orig_print_stack);
0638     if (retval < 0)
0639         err_msg("Could not restore original osnoise print_stack\n");
0640 
0641 out_done:
0642     context->print_stack = OSNOISE_OPTION_INIT_VAL;
0643 }
0644 
0645 /*
0646  * osnoise_put_print_stack - restore original values and cleanup data
0647  */
0648 void osnoise_put_print_stack(struct osnoise_context *context)
0649 {
0650     osnoise_restore_print_stack(context);
0651 
0652     if (context->orig_print_stack == OSNOISE_OPTION_INIT_VAL)
0653         return;
0654 
0655     context->orig_print_stack = OSNOISE_OPTION_INIT_VAL;
0656 }
0657 
0658 /*
0659  * osnoise_get_tracing_thresh - read and save the original "tracing_thresh"
0660  */
0661 static long long
0662 osnoise_get_tracing_thresh(struct osnoise_context *context)
0663 {
0664     long long tracing_thresh;
0665 
0666     if (context->tracing_thresh != OSNOISE_OPTION_INIT_VAL)
0667         return context->tracing_thresh;
0668 
0669     if (context->orig_tracing_thresh != OSNOISE_OPTION_INIT_VAL)
0670         return context->orig_tracing_thresh;
0671 
0672     tracing_thresh = osnoise_read_ll_config("tracing_thresh");
0673     if (tracing_thresh < 0)
0674         goto out_err;
0675 
0676     context->orig_tracing_thresh = tracing_thresh;
0677     return tracing_thresh;
0678 
0679 out_err:
0680     return OSNOISE_OPTION_INIT_VAL;
0681 }
0682 
0683 /*
0684  * osnoise_set_tracing_thresh - set "tracing_thresh"
0685  */
0686 int osnoise_set_tracing_thresh(struct osnoise_context *context, long long tracing_thresh)
0687 {
0688     long long curr_tracing_thresh = osnoise_get_tracing_thresh(context);
0689     int retval;
0690 
0691     if (curr_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
0692         return -1;
0693 
0694     retval = osnoise_write_ll_config("tracing_thresh", tracing_thresh);
0695     if (retval < 0)
0696         return -1;
0697 
0698     context->tracing_thresh = tracing_thresh;
0699 
0700     return 0;
0701 }
0702 
0703 /*
0704  * osnoise_restore_tracing_thresh - restore the original "tracing_thresh"
0705  */
0706 void osnoise_restore_tracing_thresh(struct osnoise_context *context)
0707 {
0708     int retval;
0709 
0710     if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
0711         return;
0712 
0713     if (context->orig_tracing_thresh == context->tracing_thresh)
0714         goto out_done;
0715 
0716     retval = osnoise_write_ll_config("tracing_thresh", context->orig_tracing_thresh);
0717     if (retval < 0)
0718         err_msg("Could not restore original tracing_thresh\n");
0719 
0720 out_done:
0721     context->tracing_thresh = OSNOISE_OPTION_INIT_VAL;
0722 }
0723 
0724 /*
0725  * osnoise_put_tracing_thresh - restore original values and cleanup data
0726  */
0727 void osnoise_put_tracing_thresh(struct osnoise_context *context)
0728 {
0729     osnoise_restore_tracing_thresh(context);
0730 
0731     if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
0732         return;
0733 
0734     context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL;
0735 }
0736 
0737 /*
0738  * enable_osnoise - enable osnoise tracer in the trace_instance
0739  */
0740 int enable_osnoise(struct trace_instance *trace)
0741 {
0742     return enable_tracer_by_name(trace->inst, "osnoise");
0743 }
0744 
0745 /*
0746  * enable_timerlat - enable timerlat tracer in the trace_instance
0747  */
0748 int enable_timerlat(struct trace_instance *trace)
0749 {
0750     return enable_tracer_by_name(trace->inst, "timerlat");
0751 }
0752 
0753 enum {
0754     FLAG_CONTEXT_NEWLY_CREATED  = (1 << 0),
0755     FLAG_CONTEXT_DELETED        = (1 << 1),
0756 };
0757 
0758 /*
0759  * osnoise_get_context - increase the usage of a context and return it
0760  */
0761 int osnoise_get_context(struct osnoise_context *context)
0762 {
0763     int ret;
0764 
0765     if (context->flags & FLAG_CONTEXT_DELETED) {
0766         ret = -1;
0767     } else {
0768         context->ref++;
0769         ret = 0;
0770     }
0771 
0772     return ret;
0773 }
0774 
0775 /*
0776  * osnoise_context_alloc - alloc an osnoise_context
0777  *
0778  * The osnoise context contains the information of the "osnoise/" configs.
0779  * It is used to set and restore the config.
0780  */
0781 struct osnoise_context *osnoise_context_alloc(void)
0782 {
0783     struct osnoise_context *context;
0784 
0785     context = calloc(1, sizeof(*context));
0786     if (!context)
0787         return NULL;
0788 
0789     context->orig_stop_us       = OSNOISE_OPTION_INIT_VAL;
0790     context->stop_us        = OSNOISE_OPTION_INIT_VAL;
0791 
0792     context->orig_stop_total_us = OSNOISE_OPTION_INIT_VAL;
0793     context->stop_total_us      = OSNOISE_OPTION_INIT_VAL;
0794 
0795     context->orig_print_stack   = OSNOISE_OPTION_INIT_VAL;
0796     context->print_stack        = OSNOISE_OPTION_INIT_VAL;
0797 
0798     context->orig_tracing_thresh    = OSNOISE_OPTION_INIT_VAL;
0799     context->tracing_thresh     = OSNOISE_OPTION_INIT_VAL;
0800 
0801     osnoise_get_context(context);
0802 
0803     return context;
0804 }
0805 
0806 /*
0807  * osnoise_put_context - put the osnoise_put_context
0808  *
0809  * If there is no other user for the context, the original data
0810  * is restored.
0811  */
0812 void osnoise_put_context(struct osnoise_context *context)
0813 {
0814     if (--context->ref < 1)
0815         context->flags |= FLAG_CONTEXT_DELETED;
0816 
0817     if (!(context->flags & FLAG_CONTEXT_DELETED))
0818         return;
0819 
0820     osnoise_put_cpus(context);
0821     osnoise_put_runtime_period(context);
0822     osnoise_put_stop_us(context);
0823     osnoise_put_stop_total_us(context);
0824     osnoise_put_timerlat_period_us(context);
0825     osnoise_put_print_stack(context);
0826     osnoise_put_tracing_thresh(context);
0827 
0828     free(context);
0829 }
0830 
0831 /*
0832  * osnoise_destroy_tool - disable trace, restore configs and free data
0833  */
0834 void osnoise_destroy_tool(struct osnoise_tool *top)
0835 {
0836     if (!top)
0837         return;
0838 
0839     trace_instance_destroy(&top->trace);
0840 
0841     if (top->context)
0842         osnoise_put_context(top->context);
0843 
0844     free(top);
0845 }
0846 
0847 /*
0848  * osnoise_init_tool - init an osnoise tool
0849  *
0850  * It allocs data, create a context to store data and
0851  * creates a new trace instance for the tool.
0852  */
0853 struct osnoise_tool *osnoise_init_tool(char *tool_name)
0854 {
0855     struct osnoise_tool *top;
0856     int retval;
0857 
0858     top = calloc(1, sizeof(*top));
0859     if (!top)
0860         return NULL;
0861 
0862     top->context = osnoise_context_alloc();
0863     if (!top->context)
0864         goto out_err;
0865 
0866     retval = trace_instance_init(&top->trace, tool_name);
0867     if (retval)
0868         goto out_err;
0869 
0870     return top;
0871 out_err:
0872     osnoise_destroy_tool(top);
0873     return NULL;
0874 }
0875 
0876 /*
0877  * osnoise_init_trace_tool - init a tracer instance to trace osnoise events
0878  */
0879 struct osnoise_tool *osnoise_init_trace_tool(char *tracer)
0880 {
0881     struct osnoise_tool *trace;
0882     int retval;
0883 
0884     trace = osnoise_init_tool("osnoise_trace");
0885     if (!trace)
0886         return NULL;
0887 
0888     retval = tracefs_event_enable(trace->trace.inst, "osnoise", NULL);
0889     if (retval < 0 && !errno) {
0890         err_msg("Could not find osnoise events\n");
0891         goto out_err;
0892     }
0893 
0894     retval = enable_tracer_by_name(trace->trace.inst, tracer);
0895     if (retval) {
0896         err_msg("Could not enable %s tracer for tracing\n", tracer);
0897         goto out_err;
0898     }
0899 
0900     return trace;
0901 out_err:
0902     osnoise_destroy_tool(trace);
0903     return NULL;
0904 }
0905 
0906 static void osnoise_usage(void)
0907 {
0908     int i;
0909 
0910     static const char *msg[] = {
0911         "",
0912         "osnoise version " VERSION,
0913         "",
0914         "  usage: [rtla] osnoise [MODE] ...",
0915         "",
0916         "  modes:",
0917         "     top   - prints the summary from osnoise tracer",
0918         "     hist  - prints a histogram of osnoise samples",
0919         "",
0920         "if no MODE is given, the top mode is called, passing the arguments",
0921         NULL,
0922     };
0923 
0924     for (i = 0; msg[i]; i++)
0925         fprintf(stderr, "%s\n", msg[i]);
0926     exit(1);
0927 }
0928 
0929 int osnoise_main(int argc, char *argv[])
0930 {
0931     if (argc == 0)
0932         goto usage;
0933 
0934     /*
0935      * if osnoise was called without any argument, run the
0936      * default cmdline.
0937      */
0938     if (argc == 1) {
0939         osnoise_top_main(argc, argv);
0940         exit(0);
0941     }
0942 
0943     if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
0944         osnoise_usage();
0945         exit(0);
0946     } else if (strncmp(argv[1], "-", 1) == 0) {
0947         /* the user skipped the tool, call the default one */
0948         osnoise_top_main(argc, argv);
0949         exit(0);
0950     } else if (strcmp(argv[1], "top") == 0) {
0951         osnoise_top_main(argc-1, &argv[1]);
0952         exit(0);
0953     } else if (strcmp(argv[1], "hist") == 0) {
0954         osnoise_hist_main(argc-1, &argv[1]);
0955         exit(0);
0956     }
0957 
0958 usage:
0959     osnoise_usage();
0960     exit(1);
0961 }