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