brintos

brintos / linux-shallow public Read only

0
0
Text · 26.1 KiB · 245e934 Raw
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