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 */
osnoise_get_cpus(struct osnoise_context * context)24 char *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 */
osnoise_set_cpus(struct osnoise_context * context,char * cpus)48 int 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 */
osnoise_restore_cpus(struct osnoise_context * context)82 void 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
102 out_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 */
osnoise_put_cpus(struct osnoise_context * context)110 void 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 */
osnoise_read_ll_config(char * rel_path)126 static 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 */
osnoise_write_ll_config(char * rel_path,long long value)150 static 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 */
osnoise_get_runtime(struct osnoise_context * context)168 unsigned 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
185 out_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 */
osnoise_get_period(struct osnoise_context * context)194 unsigned 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
211 out_err:
212 return OSNOISE_TIME_INIT_VAL;
213 }
214
__osnoise_write_runtime(struct osnoise_context * context,unsigned long long runtime)215 static 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
__osnoise_write_period(struct osnoise_context * context,unsigned long long period)231 static 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 */
osnoise_set_runtime_period(struct osnoise_context * context,unsigned long long runtime,unsigned long long period)254 int 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 */
osnoise_restore_runtime_period(struct osnoise_context * context)304 void 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
322 out_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 */
osnoise_put_runtime_period(struct osnoise_context * context)330 void 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 */
344 static long long
osnoise_get_timerlat_period_us(struct osnoise_context * context)345 osnoise_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
362 out_err:
363 return OSNOISE_TIME_INIT_VAL;
364 }
365
366 /*
367 * osnoise_set_timerlat_period_us - set "timerlat_period_us"
368 */
osnoise_set_timerlat_period_us(struct osnoise_context * context,long long timerlat_period_us)369 int 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 */
osnoise_restore_timerlat_period_us(struct osnoise_context * context)389 void 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
403 out_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 */
osnoise_put_timerlat_period_us(struct osnoise_context * context)410 void 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 */
423 static long long
osnoise_get_stop_us(struct osnoise_context * context)424 osnoise_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
441 out_err:
442 return OSNOISE_OPTION_INIT_VAL;
443 }
444
445 /*
446 * osnoise_set_stop_us - set "stop_tracing_us"
447 */
osnoise_set_stop_us(struct osnoise_context * context,long long stop_us)448 int 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 */
osnoise_restore_stop_us(struct osnoise_context * context)468 void 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
482 out_done:
483 context->stop_us = OSNOISE_OPTION_INIT_VAL;
484 }
485
486 /*
487 * osnoise_put_stop_us - restore original values and cleanup data
488 */
osnoise_put_stop_us(struct osnoise_context * context)489 void 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 */
502 static long long
osnoise_get_stop_total_us(struct osnoise_context * context)503 osnoise_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
520 out_err:
521 return OSNOISE_OPTION_INIT_VAL;
522 }
523
524 /*
525 * osnoise_set_stop_total_us - set "stop_tracing_total_us"
526 */
osnoise_set_stop_total_us(struct osnoise_context * context,long long stop_total_us)527 int 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 */
osnoise_restore_stop_total_us(struct osnoise_context * context)547 void 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
562 out_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 */
osnoise_put_stop_total_us(struct osnoise_context * context)569 void 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 */
582 static long long
osnoise_get_print_stack(struct osnoise_context * context)583 osnoise_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
600 out_err:
601 return OSNOISE_OPTION_INIT_VAL;
602 }
603
604 /*
605 * osnoise_set_print_stack - set "print_stack"
606 */
osnoise_set_print_stack(struct osnoise_context * context,long long print_stack)607 int 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 */
osnoise_restore_print_stack(struct osnoise_context * context)627 void 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
641 out_done:
642 context->print_stack = OSNOISE_OPTION_INIT_VAL;
643 }
644
645 /*
646 * osnoise_put_print_stack - restore original values and cleanup data
647 */
osnoise_put_print_stack(struct osnoise_context * context)648 void 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 */
661 static long long
osnoise_get_tracing_thresh(struct osnoise_context * context)662 osnoise_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
679 out_err:
680 return OSNOISE_OPTION_INIT_VAL;
681 }
682
683 /*
684 * osnoise_set_tracing_thresh - set "tracing_thresh"
685 */
osnoise_set_tracing_thresh(struct osnoise_context * context,long long tracing_thresh)686 int 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 */
osnoise_restore_tracing_thresh(struct osnoise_context * context)706 void 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
720 out_done:
721 context->tracing_thresh = OSNOISE_OPTION_INIT_VAL;
722 }
723
724 /*
725 * osnoise_put_tracing_thresh - restore original values and cleanup data
726 */
osnoise_put_tracing_thresh(struct osnoise_context * context)727 void 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
osnoise_options_get_option(char * option)737 static 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
766 out_free:
767 free(options);
768 return retval;
769 }
770
osnoise_options_set_option(char * option,bool onoff)771 static 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
osnoise_get_irq_disable(struct osnoise_context * context)783 static 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
osnoise_set_irq_disable(struct osnoise_context * context,bool onoff)796 int 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
osnoise_restore_irq_disable(struct osnoise_context * context)816 static 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
830 out_done:
831 context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL;
832 }
833
osnoise_put_irq_disable(struct osnoise_context * context)834 static 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
osnoise_get_workload(struct osnoise_context * context)844 static 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
osnoise_set_workload(struct osnoise_context * context,bool onoff)857 int 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
osnoise_restore_workload(struct osnoise_context * context)877 static 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
891 out_done:
892 context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
893 }
894
osnoise_put_workload(struct osnoise_context * context)895 static 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 */
enable_osnoise(struct trace_instance * trace)908 int 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 */
enable_timerlat(struct trace_instance * trace)916 int enable_timerlat(struct trace_instance *trace)
917 {
918 return enable_tracer_by_name(trace->inst, "timerlat");
919 }
920
921 enum {
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 */
osnoise_get_context(struct osnoise_context * context)929 int 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 */
osnoise_context_alloc(void)949 struct 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 */
osnoise_put_context(struct osnoise_context * context)986 void 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 */
osnoise_destroy_tool(struct osnoise_tool * top)1010 void 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 */
osnoise_init_tool(char * tool_name)1029 struct 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;
1047 out_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 */
osnoise_init_trace_tool(char * tracer)1055 struct 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;
1077 out_err:
1078 osnoise_destroy_tool(trace);
1079 return NULL;
1080 }
1081
osnoise_usage(int err)1082 static 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
osnoise_main(int argc,char * argv[])1105 int 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
1133 usage:
1134 osnoise_usage(1);
1135 exit(1);
1136 }
1137
hwnoise_main(int argc,char * argv[])1138 int hwnoise_main(int argc, char *argv[])
1139 {
1140 osnoise_top_main(argc, argv);
1141 exit(0);
1142 }
1143