Linux Audio

Check our new training course

Loading...
v6.2
  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(int err)
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(err);
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(0);
945	} else if (strncmp(argv[1], "-", 1) == 0) {
946		/* the user skipped the tool, call the default one */
947		osnoise_top_main(argc, argv);
948		exit(0);
949	} else if (strcmp(argv[1], "top") == 0) {
950		osnoise_top_main(argc-1, &argv[1]);
951		exit(0);
952	} else if (strcmp(argv[1], "hist") == 0) {
953		osnoise_hist_main(argc-1, &argv[1]);
954		exit(0);
955	}
956
957usage:
958	osnoise_usage(1);
959	exit(1);
 
 
 
 
 
 
960}
v6.9.4
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
   4 */
   5
   6#include <sys/types.h>
   7#include <sys/stat.h>
   8#include <pthread.h>
   9#include <stdlib.h>
  10#include <string.h>
  11#include <unistd.h>
  12#include <errno.h>
  13#include <fcntl.h>
  14#include <stdio.h>
  15
  16#include "osnoise.h"
  17#include "utils.h"
  18
  19/*
  20 * osnoise_get_cpus - return the original "osnoise/cpus" content
  21 *
  22 * It also saves the value to be restored.
  23 */
  24char *osnoise_get_cpus(struct osnoise_context *context)
  25{
  26	if (context->curr_cpus)
  27		return context->curr_cpus;
  28
  29	if (context->orig_cpus)
  30		return context->orig_cpus;
  31
  32	context->orig_cpus = tracefs_instance_file_read(NULL, "osnoise/cpus", NULL);
  33
  34	/*
  35	 * The error value (NULL) is the same for tracefs_instance_file_read()
  36	 * and this functions, so:
  37	 */
  38	return context->orig_cpus;
  39}
  40
  41/*
  42 * osnoise_set_cpus - configure osnoise to run on *cpus
  43 *
  44 * "osnoise/cpus" file is used to set the cpus in which osnoise/timerlat
  45 * will run. This function opens this file, saves the current value,
  46 * and set the cpus passed as argument.
  47 */
  48int osnoise_set_cpus(struct osnoise_context *context, char *cpus)
  49{
  50	char *orig_cpus = osnoise_get_cpus(context);
  51	char buffer[1024];
  52	int retval;
  53
  54	if (!orig_cpus)
  55		return -1;
  56
  57	context->curr_cpus = strdup(cpus);
  58	if (!context->curr_cpus)
  59		return -1;
  60
  61	snprintf(buffer, 1024, "%s\n", cpus);
  62
  63	debug_msg("setting cpus to %s from %s", cpus, context->orig_cpus);
  64
  65	retval = tracefs_instance_file_write(NULL, "osnoise/cpus", buffer);
  66	if (retval < 0) {
  67		free(context->curr_cpus);
  68		context->curr_cpus = NULL;
  69		return -1;
  70	}
  71
  72	return 0;
  73}
  74
  75/*
  76 * osnoise_restore_cpus - restore the original "osnoise/cpus"
  77 *
  78 * osnoise_set_cpus() saves the original data for the "osnoise/cpus"
  79 * file. This function restore the original config it was previously
  80 * modified.
  81 */
  82void osnoise_restore_cpus(struct osnoise_context *context)
  83{
  84	int retval;
  85
  86	if (!context->orig_cpus)
  87		return;
  88
  89	if (!context->curr_cpus)
  90		return;
  91
  92	/* nothing to do? */
  93	if (!strcmp(context->orig_cpus, context->curr_cpus))
  94		goto out_done;
  95
  96	debug_msg("restoring cpus to %s", context->orig_cpus);
  97
  98	retval = tracefs_instance_file_write(NULL, "osnoise/cpus", context->orig_cpus);
  99	if (retval < 0)
 100		err_msg("could not restore original osnoise cpus\n");
 101
 102out_done:
 103	free(context->curr_cpus);
 104	context->curr_cpus = NULL;
 105}
 106
 107/*
 108 * osnoise_put_cpus - restore cpus config and cleanup data
 109 */
 110void osnoise_put_cpus(struct osnoise_context *context)
 111{
 112	osnoise_restore_cpus(context);
 113
 114	if (!context->orig_cpus)
 115		return;
 116
 117	free(context->orig_cpus);
 118	context->orig_cpus = NULL;
 119}
 120
 121/*
 122 * osnoise_read_ll_config - read a long long value from a config
 123 *
 124 * returns -1 on error.
 125 */
 126static long long osnoise_read_ll_config(char *rel_path)
 127{
 128	long long retval;
 129	char *buffer;
 130
 131	buffer = tracefs_instance_file_read(NULL, rel_path, NULL);
 132	if (!buffer)
 133		return -1;
 134
 135	/* get_llong_from_str returns -1 on error */
 136	retval = get_llong_from_str(buffer);
 137
 138	debug_msg("reading %s returned %lld\n", rel_path, retval);
 139
 140	free(buffer);
 141
 142	return retval;
 143}
 144
 145/*
 146 * osnoise_write_ll_config - write a long long value to a config in rel_path
 147 *
 148 * returns -1 on error.
 149 */
 150static long long osnoise_write_ll_config(char *rel_path, long long value)
 151{
 152	char buffer[BUFF_U64_STR_SIZE];
 153	long long retval;
 154
 155	snprintf(buffer, sizeof(buffer), "%lld\n", value);
 156
 157	debug_msg("setting %s to %lld\n", rel_path, value);
 158
 159	retval = tracefs_instance_file_write(NULL, rel_path, buffer);
 160	return retval;
 161}
 162
 163/*
 164 * osnoise_get_runtime - return the original "osnoise/runtime_us" value
 165 *
 166 * It also saves the value to be restored.
 167 */
 168unsigned long long osnoise_get_runtime(struct osnoise_context *context)
 169{
 170	long long runtime_us;
 171
 172	if (context->runtime_us != OSNOISE_TIME_INIT_VAL)
 173		return context->runtime_us;
 174
 175	if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL)
 176		return context->orig_runtime_us;
 177
 178	runtime_us = osnoise_read_ll_config("osnoise/runtime_us");
 179	if (runtime_us < 0)
 180		goto out_err;
 181
 182	context->orig_runtime_us = runtime_us;
 183	return runtime_us;
 184
 185out_err:
 186	return OSNOISE_TIME_INIT_VAL;
 187}
 188
 189/*
 190 * osnoise_get_period - return the original "osnoise/period_us" value
 191 *
 192 * It also saves the value to be restored.
 193 */
 194unsigned long long osnoise_get_period(struct osnoise_context *context)
 195{
 196	long long period_us;
 197
 198	if (context->period_us != OSNOISE_TIME_INIT_VAL)
 199		return context->period_us;
 200
 201	if (context->orig_period_us != OSNOISE_TIME_INIT_VAL)
 202		return context->orig_period_us;
 203
 204	period_us = osnoise_read_ll_config("osnoise/period_us");
 205	if (period_us < 0)
 206		goto out_err;
 207
 208	context->orig_period_us = period_us;
 209	return period_us;
 210
 211out_err:
 212	return OSNOISE_TIME_INIT_VAL;
 213}
 214
 215static int __osnoise_write_runtime(struct osnoise_context *context,
 216				   unsigned long long runtime)
 217{
 218	int retval;
 219
 220	if (context->orig_runtime_us == OSNOISE_TIME_INIT_VAL)
 221		return -1;
 222
 223	retval = osnoise_write_ll_config("osnoise/runtime_us", runtime);
 224	if (retval < 0)
 225		return -1;
 226
 227	context->runtime_us = runtime;
 228	return 0;
 229}
 230
 231static int __osnoise_write_period(struct osnoise_context *context,
 232				  unsigned long long period)
 233{
 234	int retval;
 235
 236	if (context->orig_period_us == OSNOISE_TIME_INIT_VAL)
 237		return -1;
 238
 239	retval = osnoise_write_ll_config("osnoise/period_us", period);
 240	if (retval < 0)
 241		return -1;
 242
 243	context->period_us = period;
 244	return 0;
 245}
 246
 247/*
 248 * osnoise_set_runtime_period - set osnoise runtime and period
 249 *
 250 * Osnoise's runtime and period are related as runtime <= period.
 251 * Thus, this function saves the original values, and then tries
 252 * to set the runtime and period if they are != 0.
 253 */
 254int osnoise_set_runtime_period(struct osnoise_context *context,
 255			       unsigned long long runtime,
 256			       unsigned long long period)
 257{
 258	unsigned long long curr_runtime_us;
 259	unsigned long long curr_period_us;
 260	int retval;
 261
 262	if (!period && !runtime)
 263		return 0;
 264
 265	curr_runtime_us = osnoise_get_runtime(context);
 266	curr_period_us = osnoise_get_period(context);
 267
 268	/* error getting any value? */
 269	if (curr_period_us == OSNOISE_TIME_INIT_VAL || curr_runtime_us == OSNOISE_TIME_INIT_VAL)
 270		return -1;
 271
 272	if (!period) {
 273		if (runtime > curr_period_us)
 274			return -1;
 275		return __osnoise_write_runtime(context, runtime);
 276	} else if (!runtime) {
 277		if (period < curr_runtime_us)
 278			return -1;
 279		return __osnoise_write_period(context, period);
 280	}
 281
 282	if (runtime > curr_period_us) {
 283		retval = __osnoise_write_period(context, period);
 284		if (retval)
 285			return -1;
 286		retval = __osnoise_write_runtime(context, runtime);
 287		if (retval)
 288			return -1;
 289	} else {
 290		retval = __osnoise_write_runtime(context, runtime);
 291		if (retval)
 292			return -1;
 293		retval = __osnoise_write_period(context, period);
 294		if (retval)
 295			return -1;
 296	}
 297
 298	return 0;
 299}
 300
 301/*
 302 * osnoise_restore_runtime_period - restore the original runtime and period
 303 */
 304void osnoise_restore_runtime_period(struct osnoise_context *context)
 305{
 306	unsigned long long orig_runtime = context->orig_runtime_us;
 307	unsigned long long orig_period = context->orig_period_us;
 308	unsigned long long curr_runtime = context->runtime_us;
 309	unsigned long long curr_period = context->period_us;
 310	int retval;
 311
 312	if ((orig_runtime == OSNOISE_TIME_INIT_VAL) && (orig_period == OSNOISE_TIME_INIT_VAL))
 313		return;
 314
 315	if ((orig_period == curr_period) && (orig_runtime == curr_runtime))
 316		goto out_done;
 317
 318	retval = osnoise_set_runtime_period(context, orig_runtime, orig_period);
 319	if (retval)
 320		err_msg("Could not restore original osnoise runtime/period\n");
 321
 322out_done:
 323	context->runtime_us = OSNOISE_TIME_INIT_VAL;
 324	context->period_us = OSNOISE_TIME_INIT_VAL;
 325}
 326
 327/*
 328 * osnoise_put_runtime_period - restore original values and cleanup data
 329 */
 330void osnoise_put_runtime_period(struct osnoise_context *context)
 331{
 332	osnoise_restore_runtime_period(context);
 333
 334	if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL)
 335		context->orig_runtime_us = OSNOISE_TIME_INIT_VAL;
 336
 337	if (context->orig_period_us != OSNOISE_TIME_INIT_VAL)
 338		context->orig_period_us = OSNOISE_TIME_INIT_VAL;
 339}
 340
 341/*
 342 * osnoise_get_timerlat_period_us - read and save the original "timerlat_period_us"
 343 */
 344static long long
 345osnoise_get_timerlat_period_us(struct osnoise_context *context)
 346{
 347	long long timerlat_period_us;
 348
 349	if (context->timerlat_period_us != OSNOISE_TIME_INIT_VAL)
 350		return context->timerlat_period_us;
 351
 352	if (context->orig_timerlat_period_us != OSNOISE_TIME_INIT_VAL)
 353		return context->orig_timerlat_period_us;
 354
 355	timerlat_period_us = osnoise_read_ll_config("osnoise/timerlat_period_us");
 356	if (timerlat_period_us < 0)
 357		goto out_err;
 358
 359	context->orig_timerlat_period_us = timerlat_period_us;
 360	return timerlat_period_us;
 361
 362out_err:
 363	return OSNOISE_TIME_INIT_VAL;
 364}
 365
 366/*
 367 * osnoise_set_timerlat_period_us - set "timerlat_period_us"
 368 */
 369int osnoise_set_timerlat_period_us(struct osnoise_context *context, long long timerlat_period_us)
 370{
 371	long long curr_timerlat_period_us = osnoise_get_timerlat_period_us(context);
 372	int retval;
 373
 374	if (curr_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
 375		return -1;
 376
 377	retval = osnoise_write_ll_config("osnoise/timerlat_period_us", timerlat_period_us);
 378	if (retval < 0)
 379		return -1;
 380
 381	context->timerlat_period_us = timerlat_period_us;
 382
 383	return 0;
 384}
 385
 386/*
 387 * osnoise_restore_timerlat_period_us - restore "timerlat_period_us"
 388 */
 389void osnoise_restore_timerlat_period_us(struct osnoise_context *context)
 390{
 391	int retval;
 392
 393	if (context->orig_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
 394		return;
 395
 396	if (context->orig_timerlat_period_us == context->timerlat_period_us)
 397		goto out_done;
 398
 399	retval = osnoise_write_ll_config("osnoise/timerlat_period_us", context->orig_timerlat_period_us);
 400	if (retval < 0)
 401		err_msg("Could not restore original osnoise timerlat_period_us\n");
 402
 403out_done:
 404	context->timerlat_period_us = OSNOISE_TIME_INIT_VAL;
 405}
 406
 407/*
 408 * osnoise_put_timerlat_period_us - restore original values and cleanup data
 409 */
 410void osnoise_put_timerlat_period_us(struct osnoise_context *context)
 411{
 412	osnoise_restore_timerlat_period_us(context);
 413
 414	if (context->orig_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
 415		return;
 416
 417	context->orig_timerlat_period_us = OSNOISE_TIME_INIT_VAL;
 418}
 419
 420/*
 421 * osnoise_get_stop_us - read and save the original "stop_tracing_us"
 422 */
 423static long long
 424osnoise_get_stop_us(struct osnoise_context *context)
 425{
 426	long long stop_us;
 427
 428	if (context->stop_us != OSNOISE_OPTION_INIT_VAL)
 429		return context->stop_us;
 430
 431	if (context->orig_stop_us != OSNOISE_OPTION_INIT_VAL)
 432		return context->orig_stop_us;
 433
 434	stop_us = osnoise_read_ll_config("osnoise/stop_tracing_us");
 435	if (stop_us < 0)
 436		goto out_err;
 437
 438	context->orig_stop_us = stop_us;
 439	return stop_us;
 440
 441out_err:
 442	return OSNOISE_OPTION_INIT_VAL;
 443}
 444
 445/*
 446 * osnoise_set_stop_us - set "stop_tracing_us"
 447 */
 448int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us)
 449{
 450	long long curr_stop_us = osnoise_get_stop_us(context);
 451	int retval;
 452
 453	if (curr_stop_us == OSNOISE_OPTION_INIT_VAL)
 454		return -1;
 455
 456	retval = osnoise_write_ll_config("osnoise/stop_tracing_us", stop_us);
 457	if (retval < 0)
 458		return -1;
 459
 460	context->stop_us = stop_us;
 461
 462	return 0;
 463}
 464
 465/*
 466 * osnoise_restore_stop_us - restore the original "stop_tracing_us"
 467 */
 468void osnoise_restore_stop_us(struct osnoise_context *context)
 469{
 470	int retval;
 471
 472	if (context->orig_stop_us == OSNOISE_OPTION_INIT_VAL)
 473		return;
 474
 475	if (context->orig_stop_us == context->stop_us)
 476		goto out_done;
 477
 478	retval = osnoise_write_ll_config("osnoise/stop_tracing_us", context->orig_stop_us);
 479	if (retval < 0)
 480		err_msg("Could not restore original osnoise stop_us\n");
 481
 482out_done:
 483	context->stop_us = OSNOISE_OPTION_INIT_VAL;
 484}
 485
 486/*
 487 * osnoise_put_stop_us - restore original values and cleanup data
 488 */
 489void osnoise_put_stop_us(struct osnoise_context *context)
 490{
 491	osnoise_restore_stop_us(context);
 492
 493	if (context->orig_stop_us == OSNOISE_OPTION_INIT_VAL)
 494		return;
 495
 496	context->orig_stop_us = OSNOISE_OPTION_INIT_VAL;
 497}
 498
 499/*
 500 * osnoise_get_stop_total_us - read and save the original "stop_tracing_total_us"
 501 */
 502static long long
 503osnoise_get_stop_total_us(struct osnoise_context *context)
 504{
 505	long long stop_total_us;
 506
 507	if (context->stop_total_us != OSNOISE_OPTION_INIT_VAL)
 508		return context->stop_total_us;
 509
 510	if (context->orig_stop_total_us != OSNOISE_OPTION_INIT_VAL)
 511		return context->orig_stop_total_us;
 512
 513	stop_total_us = osnoise_read_ll_config("osnoise/stop_tracing_total_us");
 514	if (stop_total_us < 0)
 515		goto out_err;
 516
 517	context->orig_stop_total_us = stop_total_us;
 518	return stop_total_us;
 519
 520out_err:
 521	return OSNOISE_OPTION_INIT_VAL;
 522}
 523
 524/*
 525 * osnoise_set_stop_total_us - set "stop_tracing_total_us"
 526 */
 527int osnoise_set_stop_total_us(struct osnoise_context *context, long long stop_total_us)
 528{
 529	long long curr_stop_total_us = osnoise_get_stop_total_us(context);
 530	int retval;
 531
 532	if (curr_stop_total_us == OSNOISE_OPTION_INIT_VAL)
 533		return -1;
 534
 535	retval = osnoise_write_ll_config("osnoise/stop_tracing_total_us", stop_total_us);
 536	if (retval < 0)
 537		return -1;
 538
 539	context->stop_total_us = stop_total_us;
 540
 541	return 0;
 542}
 543
 544/*
 545 * osnoise_restore_stop_total_us - restore the original "stop_tracing_total_us"
 546 */
 547void osnoise_restore_stop_total_us(struct osnoise_context *context)
 548{
 549	int retval;
 550
 551	if (context->orig_stop_total_us == OSNOISE_OPTION_INIT_VAL)
 552		return;
 553
 554	if (context->orig_stop_total_us == context->stop_total_us)
 555		goto out_done;
 556
 557	retval = osnoise_write_ll_config("osnoise/stop_tracing_total_us",
 558			context->orig_stop_total_us);
 559	if (retval < 0)
 560		err_msg("Could not restore original osnoise stop_total_us\n");
 561
 562out_done:
 563	context->stop_total_us = OSNOISE_OPTION_INIT_VAL;
 564}
 565
 566/*
 567 * osnoise_put_stop_total_us - restore original values and cleanup data
 568 */
 569void osnoise_put_stop_total_us(struct osnoise_context *context)
 570{
 571	osnoise_restore_stop_total_us(context);
 572
 573	if (context->orig_stop_total_us == OSNOISE_OPTION_INIT_VAL)
 574		return;
 575
 576	context->orig_stop_total_us = OSNOISE_OPTION_INIT_VAL;
 577}
 578
 579/*
 580 * osnoise_get_print_stack - read and save the original "print_stack"
 581 */
 582static long long
 583osnoise_get_print_stack(struct osnoise_context *context)
 584{
 585	long long print_stack;
 586
 587	if (context->print_stack != OSNOISE_OPTION_INIT_VAL)
 588		return context->print_stack;
 589
 590	if (context->orig_print_stack != OSNOISE_OPTION_INIT_VAL)
 591		return context->orig_print_stack;
 592
 593	print_stack = osnoise_read_ll_config("osnoise/print_stack");
 594	if (print_stack < 0)
 595		goto out_err;
 596
 597	context->orig_print_stack = print_stack;
 598	return print_stack;
 599
 600out_err:
 601	return OSNOISE_OPTION_INIT_VAL;
 602}
 603
 604/*
 605 * osnoise_set_print_stack - set "print_stack"
 606 */
 607int osnoise_set_print_stack(struct osnoise_context *context, long long print_stack)
 608{
 609	long long curr_print_stack = osnoise_get_print_stack(context);
 610	int retval;
 611
 612	if (curr_print_stack == OSNOISE_OPTION_INIT_VAL)
 613		return -1;
 614
 615	retval = osnoise_write_ll_config("osnoise/print_stack", print_stack);
 616	if (retval < 0)
 617		return -1;
 618
 619	context->print_stack = print_stack;
 620
 621	return 0;
 622}
 623
 624/*
 625 * osnoise_restore_print_stack - restore the original "print_stack"
 626 */
 627void osnoise_restore_print_stack(struct osnoise_context *context)
 628{
 629	int retval;
 630
 631	if (context->orig_print_stack == OSNOISE_OPTION_INIT_VAL)
 632		return;
 633
 634	if (context->orig_print_stack == context->print_stack)
 635		goto out_done;
 636
 637	retval = osnoise_write_ll_config("osnoise/print_stack", context->orig_print_stack);
 638	if (retval < 0)
 639		err_msg("Could not restore original osnoise print_stack\n");
 640
 641out_done:
 642	context->print_stack = OSNOISE_OPTION_INIT_VAL;
 643}
 644
 645/*
 646 * osnoise_put_print_stack - restore original values and cleanup data
 647 */
 648void osnoise_put_print_stack(struct osnoise_context *context)
 649{
 650	osnoise_restore_print_stack(context);
 651
 652	if (context->orig_print_stack == OSNOISE_OPTION_INIT_VAL)
 653		return;
 654
 655	context->orig_print_stack = OSNOISE_OPTION_INIT_VAL;
 656}
 657
 658/*
 659 * osnoise_get_tracing_thresh - read and save the original "tracing_thresh"
 660 */
 661static long long
 662osnoise_get_tracing_thresh(struct osnoise_context *context)
 663{
 664	long long tracing_thresh;
 665
 666	if (context->tracing_thresh != OSNOISE_OPTION_INIT_VAL)
 667		return context->tracing_thresh;
 668
 669	if (context->orig_tracing_thresh != OSNOISE_OPTION_INIT_VAL)
 670		return context->orig_tracing_thresh;
 671
 672	tracing_thresh = osnoise_read_ll_config("tracing_thresh");
 673	if (tracing_thresh < 0)
 674		goto out_err;
 675
 676	context->orig_tracing_thresh = tracing_thresh;
 677	return tracing_thresh;
 678
 679out_err:
 680	return OSNOISE_OPTION_INIT_VAL;
 681}
 682
 683/*
 684 * osnoise_set_tracing_thresh - set "tracing_thresh"
 685 */
 686int osnoise_set_tracing_thresh(struct osnoise_context *context, long long tracing_thresh)
 687{
 688	long long curr_tracing_thresh = osnoise_get_tracing_thresh(context);
 689	int retval;
 690
 691	if (curr_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
 692		return -1;
 693
 694	retval = osnoise_write_ll_config("tracing_thresh", tracing_thresh);
 695	if (retval < 0)
 696		return -1;
 697
 698	context->tracing_thresh = tracing_thresh;
 699
 700	return 0;
 701}
 702
 703/*
 704 * osnoise_restore_tracing_thresh - restore the original "tracing_thresh"
 705 */
 706void osnoise_restore_tracing_thresh(struct osnoise_context *context)
 707{
 708	int retval;
 709
 710	if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
 711		return;
 712
 713	if (context->orig_tracing_thresh == context->tracing_thresh)
 714		goto out_done;
 715
 716	retval = osnoise_write_ll_config("tracing_thresh", context->orig_tracing_thresh);
 717	if (retval < 0)
 718		err_msg("Could not restore original tracing_thresh\n");
 719
 720out_done:
 721	context->tracing_thresh = OSNOISE_OPTION_INIT_VAL;
 722}
 723
 724/*
 725 * osnoise_put_tracing_thresh - restore original values and cleanup data
 726 */
 727void osnoise_put_tracing_thresh(struct osnoise_context *context)
 728{
 729	osnoise_restore_tracing_thresh(context);
 730
 731	if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
 732		return;
 733
 734	context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL;
 735}
 736
 737static int osnoise_options_get_option(char *option)
 738{
 739	char *options = tracefs_instance_file_read(NULL, "osnoise/options", NULL);
 740	char no_option[128];
 741	int retval = 0;
 742	char *opt;
 743
 744	if (!options)
 745		return OSNOISE_OPTION_INIT_VAL;
 746
 747	/*
 748	 * Check first if the option is disabled.
 749	 */
 750	snprintf(no_option, sizeof(no_option), "NO_%s", option);
 751
 752	opt = strstr(options, no_option);
 753	if (opt)
 754		goto out_free;
 755
 756	/*
 757	 * Now that it is not disabled, if the string is there, it is
 758	 * enabled. If the string is not there, the option does not exist.
 759	 */
 760	opt = strstr(options, option);
 761	if (opt)
 762		retval = 1;
 763	else
 764		retval = OSNOISE_OPTION_INIT_VAL;
 765
 766out_free:
 767	free(options);
 768	return retval;
 769}
 770
 771static int osnoise_options_set_option(char *option, bool onoff)
 772{
 773	char no_option[128];
 774
 775	if (onoff)
 776		return tracefs_instance_file_write(NULL, "osnoise/options", option);
 777
 778	snprintf(no_option, sizeof(no_option), "NO_%s", option);
 779
 780	return tracefs_instance_file_write(NULL, "osnoise/options", no_option);
 781}
 782
 783static int osnoise_get_irq_disable(struct osnoise_context *context)
 784{
 785	if (context->opt_irq_disable != OSNOISE_OPTION_INIT_VAL)
 786		return context->opt_irq_disable;
 787
 788	if (context->orig_opt_irq_disable != OSNOISE_OPTION_INIT_VAL)
 789		return context->orig_opt_irq_disable;
 790
 791	context->orig_opt_irq_disable = osnoise_options_get_option("OSNOISE_IRQ_DISABLE");
 792
 793	return context->orig_opt_irq_disable;
 794}
 795
 796int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff)
 797{
 798	int opt_irq_disable = osnoise_get_irq_disable(context);
 799	int retval;
 800
 801	if (opt_irq_disable == OSNOISE_OPTION_INIT_VAL)
 802		return -1;
 803
 804	if (opt_irq_disable == onoff)
 805		return 0;
 806
 807	retval = osnoise_options_set_option("OSNOISE_IRQ_DISABLE", onoff);
 808	if (retval < 0)
 809		return -1;
 810
 811	context->opt_irq_disable = onoff;
 812
 813	return 0;
 814}
 815
 816static void osnoise_restore_irq_disable(struct osnoise_context *context)
 817{
 818	int retval;
 819
 820	if (context->orig_opt_irq_disable == OSNOISE_OPTION_INIT_VAL)
 821		return;
 822
 823	if (context->orig_opt_irq_disable == context->opt_irq_disable)
 824		goto out_done;
 825
 826	retval = osnoise_options_set_option("OSNOISE_IRQ_DISABLE", context->orig_opt_irq_disable);
 827	if (retval < 0)
 828		err_msg("Could not restore original OSNOISE_IRQ_DISABLE option\n");
 829
 830out_done:
 831	context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL;
 832}
 833
 834static void osnoise_put_irq_disable(struct osnoise_context *context)
 835{
 836	osnoise_restore_irq_disable(context);
 837
 838	if (context->orig_opt_irq_disable == OSNOISE_OPTION_INIT_VAL)
 839		return;
 840
 841	context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL;
 842}
 843
 844static int osnoise_get_workload(struct osnoise_context *context)
 845{
 846	if (context->opt_workload != OSNOISE_OPTION_INIT_VAL)
 847		return context->opt_workload;
 848
 849	if (context->orig_opt_workload != OSNOISE_OPTION_INIT_VAL)
 850		return context->orig_opt_workload;
 851
 852	context->orig_opt_workload = osnoise_options_get_option("OSNOISE_WORKLOAD");
 853
 854	return context->orig_opt_workload;
 855}
 856
 857int osnoise_set_workload(struct osnoise_context *context, bool onoff)
 858{
 859	int opt_workload = osnoise_get_workload(context);
 860	int retval;
 861
 862	if (opt_workload == OSNOISE_OPTION_INIT_VAL)
 863		return -1;
 864
 865	if (opt_workload == onoff)
 866		return 0;
 867
 868	retval = osnoise_options_set_option("OSNOISE_WORKLOAD", onoff);
 869	if (retval < 0)
 870		return -1;
 871
 872	context->opt_workload = onoff;
 873
 874	return 0;
 875}
 876
 877static void osnoise_restore_workload(struct osnoise_context *context)
 878{
 879	int retval;
 880
 881	if (context->orig_opt_workload == OSNOISE_OPTION_INIT_VAL)
 882		return;
 883
 884	if (context->orig_opt_workload == context->opt_workload)
 885		goto out_done;
 886
 887	retval = osnoise_options_set_option("OSNOISE_WORKLOAD", context->orig_opt_workload);
 888	if (retval < 0)
 889		err_msg("Could not restore original OSNOISE_WORKLOAD option\n");
 890
 891out_done:
 892	context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
 893}
 894
 895static void osnoise_put_workload(struct osnoise_context *context)
 896{
 897	osnoise_restore_workload(context);
 898
 899	if (context->orig_opt_workload == OSNOISE_OPTION_INIT_VAL)
 900		return;
 901
 902	context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
 903}
 904
 905/*
 906 * enable_osnoise - enable osnoise tracer in the trace_instance
 907 */
 908int enable_osnoise(struct trace_instance *trace)
 909{
 910	return enable_tracer_by_name(trace->inst, "osnoise");
 911}
 912
 913/*
 914 * enable_timerlat - enable timerlat tracer in the trace_instance
 915 */
 916int enable_timerlat(struct trace_instance *trace)
 917{
 918	return enable_tracer_by_name(trace->inst, "timerlat");
 919}
 920
 921enum {
 922	FLAG_CONTEXT_NEWLY_CREATED	= (1 << 0),
 923	FLAG_CONTEXT_DELETED		= (1 << 1),
 924};
 925
 926/*
 927 * osnoise_get_context - increase the usage of a context and return it
 928 */
 929int osnoise_get_context(struct osnoise_context *context)
 930{
 931	int ret;
 932
 933	if (context->flags & FLAG_CONTEXT_DELETED) {
 934		ret = -1;
 935	} else {
 936		context->ref++;
 937		ret = 0;
 938	}
 939
 940	return ret;
 941}
 942
 943/*
 944 * osnoise_context_alloc - alloc an osnoise_context
 945 *
 946 * The osnoise context contains the information of the "osnoise/" configs.
 947 * It is used to set and restore the config.
 948 */
 949struct osnoise_context *osnoise_context_alloc(void)
 950{
 951	struct osnoise_context *context;
 952
 953	context = calloc(1, sizeof(*context));
 954	if (!context)
 955		return NULL;
 956
 957	context->orig_stop_us		= OSNOISE_OPTION_INIT_VAL;
 958	context->stop_us		= OSNOISE_OPTION_INIT_VAL;
 959
 960	context->orig_stop_total_us	= OSNOISE_OPTION_INIT_VAL;
 961	context->stop_total_us		= OSNOISE_OPTION_INIT_VAL;
 962
 963	context->orig_print_stack	= OSNOISE_OPTION_INIT_VAL;
 964	context->print_stack		= OSNOISE_OPTION_INIT_VAL;
 965
 966	context->orig_tracing_thresh	= OSNOISE_OPTION_INIT_VAL;
 967	context->tracing_thresh		= OSNOISE_OPTION_INIT_VAL;
 968
 969	context->orig_opt_irq_disable	= OSNOISE_OPTION_INIT_VAL;
 970	context->opt_irq_disable	= OSNOISE_OPTION_INIT_VAL;
 971
 972	context->orig_opt_workload	= OSNOISE_OPTION_INIT_VAL;
 973	context->opt_workload		= OSNOISE_OPTION_INIT_VAL;
 974
 975	osnoise_get_context(context);
 976
 977	return context;
 978}
 979
 980/*
 981 * osnoise_put_context - put the osnoise_put_context
 982 *
 983 * If there is no other user for the context, the original data
 984 * is restored.
 985 */
 986void osnoise_put_context(struct osnoise_context *context)
 987{
 988	if (--context->ref < 1)
 989		context->flags |= FLAG_CONTEXT_DELETED;
 990
 991	if (!(context->flags & FLAG_CONTEXT_DELETED))
 992		return;
 993
 994	osnoise_put_cpus(context);
 995	osnoise_put_runtime_period(context);
 996	osnoise_put_stop_us(context);
 997	osnoise_put_stop_total_us(context);
 998	osnoise_put_timerlat_period_us(context);
 999	osnoise_put_print_stack(context);
1000	osnoise_put_tracing_thresh(context);
1001	osnoise_put_irq_disable(context);
1002	osnoise_put_workload(context);
1003
1004	free(context);
1005}
1006
1007/*
1008 * osnoise_destroy_tool - disable trace, restore configs and free data
1009 */
1010void osnoise_destroy_tool(struct osnoise_tool *top)
1011{
1012	if (!top)
1013		return;
1014
1015	trace_instance_destroy(&top->trace);
1016
1017	if (top->context)
1018		osnoise_put_context(top->context);
1019
1020	free(top);
1021}
1022
1023/*
1024 * osnoise_init_tool - init an osnoise tool
1025 *
1026 * It allocs data, create a context to store data and
1027 * creates a new trace instance for the tool.
1028 */
1029struct osnoise_tool *osnoise_init_tool(char *tool_name)
1030{
1031	struct osnoise_tool *top;
1032	int retval;
1033
1034	top = calloc(1, sizeof(*top));
1035	if (!top)
1036		return NULL;
1037
1038	top->context = osnoise_context_alloc();
1039	if (!top->context)
1040		goto out_err;
1041
1042	retval = trace_instance_init(&top->trace, tool_name);
1043	if (retval)
1044		goto out_err;
1045
1046	return top;
1047out_err:
1048	osnoise_destroy_tool(top);
1049	return NULL;
1050}
1051
1052/*
1053 * osnoise_init_trace_tool - init a tracer instance to trace osnoise events
1054 */
1055struct osnoise_tool *osnoise_init_trace_tool(char *tracer)
1056{
1057	struct osnoise_tool *trace;
1058	int retval;
1059
1060	trace = osnoise_init_tool("osnoise_trace");
1061	if (!trace)
1062		return NULL;
1063
1064	retval = tracefs_event_enable(trace->trace.inst, "osnoise", NULL);
1065	if (retval < 0 && !errno) {
1066		err_msg("Could not find osnoise events\n");
1067		goto out_err;
1068	}
1069
1070	retval = enable_tracer_by_name(trace->trace.inst, tracer);
1071	if (retval) {
1072		err_msg("Could not enable %s tracer for tracing\n", tracer);
1073		goto out_err;
1074	}
1075
1076	return trace;
1077out_err:
1078	osnoise_destroy_tool(trace);
1079	return NULL;
1080}
1081
1082static void osnoise_usage(int err)
1083{
1084	int i;
1085
1086	static const char *msg[] = {
1087		"",
1088		"osnoise version " VERSION,
1089		"",
1090		"  usage: [rtla] osnoise [MODE] ...",
1091		"",
1092		"  modes:",
1093		"     top   - prints the summary from osnoise tracer",
1094		"     hist  - prints a histogram of osnoise samples",
1095		"",
1096		"if no MODE is given, the top mode is called, passing the arguments",
1097		NULL,
1098	};
1099
1100	for (i = 0; msg[i]; i++)
1101		fprintf(stderr, "%s\n", msg[i]);
1102	exit(err);
1103}
1104
1105int osnoise_main(int argc, char *argv[])
1106{
1107	if (argc == 0)
1108		goto usage;
1109
1110	/*
1111	 * if osnoise was called without any argument, run the
1112	 * default cmdline.
1113	 */
1114	if (argc == 1) {
1115		osnoise_top_main(argc, argv);
1116		exit(0);
1117	}
1118
1119	if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
1120		osnoise_usage(0);
1121	} else if (strncmp(argv[1], "-", 1) == 0) {
1122		/* the user skipped the tool, call the default one */
1123		osnoise_top_main(argc, argv);
1124		exit(0);
1125	} else if (strcmp(argv[1], "top") == 0) {
1126		osnoise_top_main(argc-1, &argv[1]);
1127		exit(0);
1128	} else if (strcmp(argv[1], "hist") == 0) {
1129		osnoise_hist_main(argc-1, &argv[1]);
1130		exit(0);
1131	}
1132
1133usage:
1134	osnoise_usage(1);
1135	exit(1);
1136}
1137
1138int hwnoise_main(int argc, char *argv[])
1139{
1140	osnoise_top_main(argc, argv);
1141	exit(0);
1142}