cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

osnoise.c (22315B)


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