Merge tag 'pidfd.v5.17-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner...
[linux-2.6-microblaze.git] / tools / tracing / rtla / src / timerlat_hist.c
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 <getopt.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <signal.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <time.h>
13
14 #include "utils.h"
15 #include "osnoise.h"
16 #include "timerlat.h"
17
18 struct timerlat_hist_params {
19         char                    *cpus;
20         char                    *monitored_cpus;
21         char                    *trace_output;
22         unsigned long long      runtime;
23         long long               stop_us;
24         long long               stop_total_us;
25         long long               timerlat_period_us;
26         long long               print_stack;
27         int                     sleep_time;
28         int                     output_divisor;
29         int                     duration;
30         int                     set_sched;
31         struct sched_attr       sched_param;
32
33         char                    no_irq;
34         char                    no_thread;
35         char                    no_header;
36         char                    no_summary;
37         char                    no_index;
38         char                    with_zeros;
39         int                     bucket_size;
40         int                     entries;
41 };
42
43 struct timerlat_hist_cpu {
44         int                     *irq;
45         int                     *thread;
46
47         int                     irq_count;
48         int                     thread_count;
49
50         unsigned long long      min_irq;
51         unsigned long long      sum_irq;
52         unsigned long long      max_irq;
53
54         unsigned long long      min_thread;
55         unsigned long long      sum_thread;
56         unsigned long long      max_thread;
57 };
58
59 struct timerlat_hist_data {
60         struct timerlat_hist_cpu        *hist;
61         int                             entries;
62         int                             bucket_size;
63         int                             nr_cpus;
64 };
65
66 /*
67  * timerlat_free_histogram - free runtime data
68  */
69 static void
70 timerlat_free_histogram(struct timerlat_hist_data *data)
71 {
72         int cpu;
73
74         /* one histogram for IRQ and one for thread, per CPU */
75         for (cpu = 0; cpu < data->nr_cpus; cpu++) {
76                 if (data->hist[cpu].irq)
77                         free(data->hist[cpu].irq);
78
79                 if (data->hist[cpu].thread)
80                         free(data->hist[cpu].thread);
81         }
82
83         /* one set of histograms per CPU */
84         if (data->hist)
85                 free(data->hist);
86
87         free(data);
88 }
89
90 /*
91  * timerlat_alloc_histogram - alloc runtime data
92  */
93 static struct timerlat_hist_data
94 *timerlat_alloc_histogram(int nr_cpus, int entries, int bucket_size)
95 {
96         struct timerlat_hist_data *data;
97         int cpu;
98
99         data = calloc(1, sizeof(*data));
100         if (!data)
101                 return NULL;
102
103         data->entries = entries;
104         data->bucket_size = bucket_size;
105         data->nr_cpus = nr_cpus;
106
107         /* one set of histograms per CPU */
108         data->hist = calloc(1, sizeof(*data->hist) * nr_cpus);
109         if (!data->hist)
110                 goto cleanup;
111
112         /* one histogram for IRQ and one for thread, per cpu */
113         for (cpu = 0; cpu < nr_cpus; cpu++) {
114                 data->hist[cpu].irq = calloc(1, sizeof(*data->hist->irq) * (entries + 1));
115                 if (!data->hist[cpu].irq)
116                         goto cleanup;
117                 data->hist[cpu].thread = calloc(1, sizeof(*data->hist->thread) * (entries + 1));
118                 if (!data->hist[cpu].thread)
119                         goto cleanup;
120         }
121
122         /* set the min to max */
123         for (cpu = 0; cpu < nr_cpus; cpu++) {
124                 data->hist[cpu].min_irq = ~0;
125                 data->hist[cpu].min_thread = ~0;
126         }
127
128         return data;
129
130 cleanup:
131         timerlat_free_histogram(data);
132         return NULL;
133 }
134
135 /*
136  * timerlat_hist_update - record a new timerlat occurent on cpu, updating data
137  */
138 static void
139 timerlat_hist_update(struct osnoise_tool *tool, int cpu,
140                      unsigned long long thread,
141                      unsigned long long latency)
142 {
143         struct timerlat_hist_params *params = tool->params;
144         struct timerlat_hist_data *data = tool->data;
145         int entries = data->entries;
146         int bucket;
147         int *hist;
148
149         if (params->output_divisor)
150                 latency = latency / params->output_divisor;
151
152         if (data->bucket_size)
153                 bucket = latency / data->bucket_size;
154
155         if (!thread) {
156                 hist = data->hist[cpu].irq;
157                 data->hist[cpu].irq_count++;
158                 update_min(&data->hist[cpu].min_irq, &latency);
159                 update_sum(&data->hist[cpu].sum_irq, &latency);
160                 update_max(&data->hist[cpu].max_irq, &latency);
161         } else {
162                 hist = data->hist[cpu].thread;
163                 data->hist[cpu].thread_count++;
164                 update_min(&data->hist[cpu].min_thread, &latency);
165                 update_sum(&data->hist[cpu].sum_thread, &latency);
166                 update_max(&data->hist[cpu].max_thread, &latency);
167         }
168
169         if (bucket < entries)
170                 hist[bucket]++;
171         else
172                 hist[entries]++;
173 }
174
175 /*
176  * timerlat_hist_handler - this is the handler for timerlat tracer events
177  */
178 static int
179 timerlat_hist_handler(struct trace_seq *s, struct tep_record *record,
180                      struct tep_event *event, void *data)
181 {
182         struct trace_instance *trace = data;
183         unsigned long long thread, latency;
184         struct osnoise_tool *tool;
185         int cpu = record->cpu;
186
187         tool = container_of(trace, struct osnoise_tool, trace);
188
189         tep_get_field_val(s, event, "context", record, &thread, 1);
190         tep_get_field_val(s, event, "timer_latency", record, &latency, 1);
191
192         timerlat_hist_update(tool, cpu, thread, latency);
193
194         return 0;
195 }
196
197 /*
198  * timerlat_hist_header - print the header of the tracer to the output
199  */
200 static void timerlat_hist_header(struct osnoise_tool *tool)
201 {
202         struct timerlat_hist_params *params = tool->params;
203         struct timerlat_hist_data *data = tool->data;
204         struct trace_seq *s = tool->trace.seq;
205         char duration[26];
206         int cpu;
207
208         if (params->no_header)
209                 return;
210
211         get_duration(tool->start_time, duration, sizeof(duration));
212         trace_seq_printf(s, "# RTLA timerlat histogram\n");
213         trace_seq_printf(s, "# Time unit is %s (%s)\n",
214                         params->output_divisor == 1 ? "nanoseconds" : "microseconds",
215                         params->output_divisor == 1 ? "ns" : "us");
216
217         trace_seq_printf(s, "# Duration: %s\n", duration);
218
219         if (!params->no_index)
220                 trace_seq_printf(s, "Index");
221
222         for (cpu = 0; cpu < data->nr_cpus; cpu++) {
223                 if (params->cpus && !params->monitored_cpus[cpu])
224                         continue;
225
226                 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
227                         continue;
228
229                 if (!params->no_irq)
230                         trace_seq_printf(s, "   IRQ-%03d", cpu);
231
232                 if (!params->no_thread)
233                         trace_seq_printf(s, "   Thr-%03d", cpu);
234         }
235         trace_seq_printf(s, "\n");
236
237
238         trace_seq_do_printf(s);
239         trace_seq_reset(s);
240 }
241
242 /*
243  * timerlat_print_summary - print the summary of the hist data to the output
244  */
245 static void
246 timerlat_print_summary(struct timerlat_hist_params *params,
247                        struct trace_instance *trace,
248                        struct timerlat_hist_data *data)
249 {
250         int cpu;
251
252         if (params->no_summary)
253                 return;
254
255         if (!params->no_index)
256                 trace_seq_printf(trace->seq, "count:");
257
258         for (cpu = 0; cpu < data->nr_cpus; cpu++) {
259                 if (params->cpus && !params->monitored_cpus[cpu])
260                         continue;
261
262                 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
263                         continue;
264
265                 if (!params->no_irq)
266                         trace_seq_printf(trace->seq, "%9d ",
267                                         data->hist[cpu].irq_count);
268
269                 if (!params->no_thread)
270                         trace_seq_printf(trace->seq, "%9d ",
271                                         data->hist[cpu].thread_count);
272         }
273         trace_seq_printf(trace->seq, "\n");
274
275         if (!params->no_index)
276                 trace_seq_printf(trace->seq, "min:  ");
277
278         for (cpu = 0; cpu < data->nr_cpus; cpu++) {
279                 if (params->cpus && !params->monitored_cpus[cpu])
280                         continue;
281
282                 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
283                         continue;
284
285                 if (!params->no_irq)
286                         trace_seq_printf(trace->seq, "%9llu ",
287                                         data->hist[cpu].min_irq);
288
289                 if (!params->no_thread)
290                         trace_seq_printf(trace->seq, "%9llu ",
291                                         data->hist[cpu].min_thread);
292         }
293         trace_seq_printf(trace->seq, "\n");
294
295         if (!params->no_index)
296                 trace_seq_printf(trace->seq, "avg:  ");
297
298         for (cpu = 0; cpu < data->nr_cpus; cpu++) {
299                 if (params->cpus && !params->monitored_cpus[cpu])
300                         continue;
301
302                 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
303                         continue;
304
305                 if (!params->no_irq) {
306                         if (data->hist[cpu].irq_count)
307                                 trace_seq_printf(trace->seq, "%9llu ",
308                                                  data->hist[cpu].sum_irq / data->hist[cpu].irq_count);
309                         else
310                                 trace_seq_printf(trace->seq, "        - ");
311                 }
312
313                 if (!params->no_thread) {
314                         if (data->hist[cpu].thread_count)
315                                 trace_seq_printf(trace->seq, "%9llu ",
316                                                 data->hist[cpu].sum_thread / data->hist[cpu].thread_count);
317                         else
318                                 trace_seq_printf(trace->seq, "        - ");
319                 }
320         }
321         trace_seq_printf(trace->seq, "\n");
322
323         if (!params->no_index)
324                 trace_seq_printf(trace->seq, "max:  ");
325
326         for (cpu = 0; cpu < data->nr_cpus; cpu++) {
327                 if (params->cpus && !params->monitored_cpus[cpu])
328                         continue;
329
330                 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
331                         continue;
332
333                 if (!params->no_irq)
334                         trace_seq_printf(trace->seq, "%9llu ",
335                                         data->hist[cpu].max_irq);
336
337                 if (!params->no_thread)
338                         trace_seq_printf(trace->seq, "%9llu ",
339                                         data->hist[cpu].max_thread);
340         }
341         trace_seq_printf(trace->seq, "\n");
342         trace_seq_do_printf(trace->seq);
343         trace_seq_reset(trace->seq);
344 }
345
346 /*
347  * timerlat_print_stats - print data for all CPUs
348  */
349 static void
350 timerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *tool)
351 {
352         struct timerlat_hist_data *data = tool->data;
353         struct trace_instance *trace = &tool->trace;
354         int bucket, cpu;
355         int total;
356
357         timerlat_hist_header(tool);
358
359         for (bucket = 0; bucket < data->entries; bucket++) {
360                 total = 0;
361
362                 if (!params->no_index)
363                         trace_seq_printf(trace->seq, "%-6d",
364                                          bucket * data->bucket_size);
365
366                 for (cpu = 0; cpu < data->nr_cpus; cpu++) {
367                         if (params->cpus && !params->monitored_cpus[cpu])
368                                 continue;
369
370                         if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
371                                 continue;
372
373                         if (!params->no_irq) {
374                                 total += data->hist[cpu].irq[bucket];
375                                 trace_seq_printf(trace->seq, "%9d ",
376                                                 data->hist[cpu].irq[bucket]);
377                         }
378
379                         if (!params->no_thread) {
380                                 total += data->hist[cpu].thread[bucket];
381                                 trace_seq_printf(trace->seq, "%9d ",
382                                                 data->hist[cpu].thread[bucket]);
383                         }
384
385                 }
386
387                 if (total == 0 && !params->with_zeros) {
388                         trace_seq_reset(trace->seq);
389                         continue;
390                 }
391
392                 trace_seq_printf(trace->seq, "\n");
393                 trace_seq_do_printf(trace->seq);
394                 trace_seq_reset(trace->seq);
395         }
396
397         if (!params->no_index)
398                 trace_seq_printf(trace->seq, "over: ");
399
400         for (cpu = 0; cpu < data->nr_cpus; cpu++) {
401                 if (params->cpus && !params->monitored_cpus[cpu])
402                         continue;
403
404                 if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count)
405                         continue;
406
407                 if (!params->no_irq)
408                         trace_seq_printf(trace->seq, "%9d ",
409                                          data->hist[cpu].irq[data->entries]);
410
411                 if (!params->no_thread)
412                         trace_seq_printf(trace->seq, "%9d ",
413                                          data->hist[cpu].thread[data->entries]);
414         }
415         trace_seq_printf(trace->seq, "\n");
416         trace_seq_do_printf(trace->seq);
417         trace_seq_reset(trace->seq);
418
419         timerlat_print_summary(params, trace, data);
420 }
421
422 /*
423  * timerlat_hist_usage - prints timerlat top usage message
424  */
425 static void timerlat_hist_usage(char *usage)
426 {
427         int i;
428
429         char *msg[] = {
430                 "",
431                 "  usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] [-t[=file]] \\",
432                 "         [-c cpu-list] [-P priority] [-e N] [-b N]  [--no-irq] [--no-thread] [--no-header] [--no-summary] \\",
433                 "         [--no-index] [--with-zeros]",
434                 "",
435                 "         -h/--help: print this menu",
436                 "         -p/--period us: timerlat period in us",
437                 "         -i/--irq us: stop trace if the irq latency is higher than the argument in us",
438                 "         -T/--thread us: stop trace if the thread latency is higher than the argument in us",
439                 "         -s/--stack us: save the stack trace at the IRQ if a thread latency is higher than the argument in us",
440                 "         -c/--cpus cpus: run the tracer only on the given cpus",
441                 "         -d/--duration time[m|h|d]: duration of the session in seconds",
442                 "         -D/--debug: print debug info",
443                 "         -T/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]",
444                 "         -n/--nano: display data in nanoseconds",
445                 "         -b/--bucket-size N: set the histogram bucket size (default 1)",
446                 "         -e/--entries N: set the number of entries of the histogram (default 256)",
447                 "            --no-irq: ignore IRQ latencies",
448                 "            --no-thread: ignore thread latencies",
449                 "            --no-header: do not print header",
450                 "            --no-summary: do not print summary",
451                 "            --no-index: do not print index",
452                 "            --with-zeros: print zero only entries",
453                 "         -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters",
454                 "               o:prio - use SCHED_OTHER with prio",
455                 "               r:prio - use SCHED_RR with prio",
456                 "               f:prio - use SCHED_FIFO with prio",
457                 "               d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period",
458                 "                                                      in nanoseconds",
459                 NULL,
460         };
461
462         if (usage)
463                 fprintf(stderr, "%s\n", usage);
464
465         fprintf(stderr, "rtla timerlat hist: a per-cpu histogram of the timer latency (version %s)\n",
466                         VERSION);
467
468         for (i = 0; msg[i]; i++)
469                 fprintf(stderr, "%s\n", msg[i]);
470         exit(1);
471 }
472
473 /*
474  * timerlat_hist_parse_args - allocs, parse and fill the cmd line parameters
475  */
476 static struct timerlat_hist_params
477 *timerlat_hist_parse_args(int argc, char *argv[])
478 {
479         struct timerlat_hist_params *params;
480         int retval;
481         int c;
482
483         params = calloc(1, sizeof(*params));
484         if (!params)
485                 exit(1);
486
487         /* display data in microseconds */
488         params->output_divisor = 1000;
489         params->bucket_size = 1;
490         params->entries = 256;
491
492         while (1) {
493                 static struct option long_options[] = {
494                         {"cpus",                required_argument,      0, 'c'},
495                         {"bucket-size",         required_argument,      0, 'b'},
496                         {"debug",               no_argument,            0, 'D'},
497                         {"entries",             required_argument,      0, 'e'},
498                         {"duration",            required_argument,      0, 'd'},
499                         {"help",                no_argument,            0, 'h'},
500                         {"irq",                 required_argument,      0, 'i'},
501                         {"nano",                no_argument,            0, 'n'},
502                         {"period",              required_argument,      0, 'p'},
503                         {"priority",            required_argument,      0, 'P'},
504                         {"stack",               required_argument,      0, 's'},
505                         {"thread",              required_argument,      0, 'T'},
506                         {"trace",               optional_argument,      0, 't'},
507                         {"no-irq",              no_argument,            0, '0'},
508                         {"no-thread",           no_argument,            0, '1'},
509                         {"no-header",           no_argument,            0, '2'},
510                         {"no-summary",          no_argument,            0, '3'},
511                         {"no-index",            no_argument,            0, '4'},
512                         {"with-zeros",          no_argument,            0, '5'},
513                         {0, 0, 0, 0}
514                 };
515
516                 /* getopt_long stores the option index here. */
517                 int option_index = 0;
518
519                 c = getopt_long(argc, argv, "c:b:d:e:Dhi:np:P:s:t::T:012345",
520                                  long_options, &option_index);
521
522                 /* detect the end of the options. */
523                 if (c == -1)
524                         break;
525
526                 switch (c) {
527                 case 'c':
528                         retval = parse_cpu_list(optarg, &params->monitored_cpus);
529                         if (retval)
530                                 timerlat_hist_usage("\nInvalid -c cpu list\n");
531                         params->cpus = optarg;
532                         break;
533                 case 'b':
534                         params->bucket_size = get_llong_from_str(optarg);
535                         if ((params->bucket_size == 0) || (params->bucket_size >= 1000000))
536                                 timerlat_hist_usage("Bucket size needs to be > 0 and <= 1000000\n");
537                         break;
538                 case 'D':
539                         config_debug = 1;
540                         break;
541                 case 'd':
542                         params->duration = parse_seconds_duration(optarg);
543                         if (!params->duration)
544                                 timerlat_hist_usage("Invalid -D duration\n");
545                         break;
546                 case 'e':
547                         params->entries = get_llong_from_str(optarg);
548                         if ((params->entries < 10) || (params->entries > 9999999))
549                                         timerlat_hist_usage("Entries must be > 10 and < 9999999\n");
550                         break;
551                 case 'h':
552                 case '?':
553                         timerlat_hist_usage(NULL);
554                         break;
555                 case 'i':
556                         params->stop_us = get_llong_from_str(optarg);
557                         break;
558                 case 'n':
559                         params->output_divisor = 1;
560                         break;
561                 case 'p':
562                         params->timerlat_period_us = get_llong_from_str(optarg);
563                         if (params->timerlat_period_us > 1000000)
564                                 timerlat_hist_usage("Period longer than 1 s\n");
565                         break;
566                 case 'P':
567                         retval = parse_prio(optarg, &params->sched_param);
568                         if (retval == -1)
569                                 timerlat_hist_usage("Invalid -P priority");
570                         params->set_sched = 1;
571                         break;
572                 case 's':
573                         params->print_stack = get_llong_from_str(optarg);
574                         break;
575                 case 'T':
576                         params->stop_total_us = get_llong_from_str(optarg);
577                         break;
578                 case 't':
579                         if (optarg)
580                                 /* skip = */
581                                 params->trace_output = &optarg[1];
582                         else
583                                 params->trace_output = "timerlat_trace.txt";
584                         break;
585                 case '0': /* no irq */
586                         params->no_irq = 1;
587                         break;
588                 case '1': /* no thread */
589                         params->no_thread = 1;
590                         break;
591                 case '2': /* no header */
592                         params->no_header = 1;
593                         break;
594                 case '3': /* no summary */
595                         params->no_summary = 1;
596                         break;
597                 case '4': /* no index */
598                         params->no_index = 1;
599                         break;
600                 case '5': /* with zeros */
601                         params->with_zeros = 1;
602                         break;
603                 default:
604                         timerlat_hist_usage("Invalid option");
605                 }
606         }
607
608         if (geteuid()) {
609                 err_msg("rtla needs root permission\n");
610                 exit(EXIT_FAILURE);
611         }
612
613         if (params->no_irq && params->no_thread)
614                 timerlat_hist_usage("no-irq and no-thread set, there is nothing to do here");
615
616         if (params->no_index && !params->with_zeros)
617                 timerlat_hist_usage("no-index set with with-zeros is not set - it does not make sense");
618
619         return params;
620 }
621
622 /*
623  * timerlat_hist_apply_config - apply the hist configs to the initialized tool
624  */
625 static int
626 timerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_params *params)
627 {
628         int retval;
629
630         if (!params->sleep_time)
631                 params->sleep_time = 1;
632
633         if (params->cpus) {
634                 retval = osnoise_set_cpus(tool->context, params->cpus);
635                 if (retval) {
636                         err_msg("Failed to apply CPUs config\n");
637                         goto out_err;
638                 }
639         }
640
641         if (params->stop_us) {
642                 retval = osnoise_set_stop_us(tool->context, params->stop_us);
643                 if (retval) {
644                         err_msg("Failed to set stop us\n");
645                         goto out_err;
646                 }
647         }
648
649         if (params->stop_total_us) {
650                 retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us);
651                 if (retval) {
652                         err_msg("Failed to set stop total us\n");
653                         goto out_err;
654                 }
655         }
656
657         if (params->timerlat_period_us) {
658                 retval = osnoise_set_timerlat_period_us(tool->context, params->timerlat_period_us);
659                 if (retval) {
660                         err_msg("Failed to set timerlat period\n");
661                         goto out_err;
662                 }
663         }
664
665         if (params->print_stack) {
666                 retval = osnoise_set_print_stack(tool->context, params->print_stack);
667                 if (retval) {
668                         err_msg("Failed to set print stack\n");
669                         goto out_err;
670                 }
671         }
672
673         return 0;
674
675 out_err:
676         return -1;
677 }
678
679 /*
680  * timerlat_init_hist - initialize a timerlat hist tool with parameters
681  */
682 static struct osnoise_tool
683 *timerlat_init_hist(struct timerlat_hist_params *params)
684 {
685         struct osnoise_tool *tool;
686         int nr_cpus;
687
688         nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
689
690         tool = osnoise_init_tool("timerlat_hist");
691         if (!tool)
692                 return NULL;
693
694         tool->data = timerlat_alloc_histogram(nr_cpus, params->entries, params->bucket_size);
695         if (!tool->data)
696                 goto out_err;
697
698         tool->params = params;
699
700         tep_register_event_handler(tool->trace.tep, -1, "ftrace", "timerlat",
701                                    timerlat_hist_handler, tool);
702
703         return tool;
704
705 out_err:
706         osnoise_destroy_tool(tool);
707         return NULL;
708 }
709
710 static int stop_tracing;
711 static void stop_hist(int sig)
712 {
713         stop_tracing = 1;
714 }
715
716 /*
717  * timerlat_hist_set_signals - handles the signal to stop the tool
718  */
719 static void
720 timerlat_hist_set_signals(struct timerlat_hist_params *params)
721 {
722         signal(SIGINT, stop_hist);
723         if (params->duration) {
724                 signal(SIGALRM, stop_hist);
725                 alarm(params->duration);
726         }
727 }
728
729 int timerlat_hist_main(int argc, char *argv[])
730 {
731         struct timerlat_hist_params *params;
732         struct osnoise_tool *record = NULL;
733         struct osnoise_tool *tool = NULL;
734         struct trace_instance *trace;
735         int return_value = 1;
736         int retval;
737
738         params = timerlat_hist_parse_args(argc, argv);
739         if (!params)
740                 exit(1);
741
742         tool = timerlat_init_hist(params);
743         if (!tool) {
744                 err_msg("Could not init osnoise hist\n");
745                 goto out_exit;
746         }
747
748         retval = timerlat_hist_apply_config(tool, params);
749         if (retval) {
750                 err_msg("Could not apply config\n");
751                 goto out_hist;
752         }
753
754         trace = &tool->trace;
755
756         retval = enable_timerlat(trace);
757         if (retval) {
758                 err_msg("Failed to enable timerlat tracer\n");
759                 goto out_hist;
760         }
761
762         if (params->set_sched) {
763                 retval = set_comm_sched_attr("timerlat/", &params->sched_param);
764                 if (retval) {
765                         err_msg("Failed to set sched parameters\n");
766                         goto out_hist;
767                 }
768         }
769
770         trace_instance_start(trace);
771
772         if (params->trace_output) {
773                 record = osnoise_init_trace_tool("timerlat");
774                 if (!record) {
775                         err_msg("Failed to enable the trace instance\n");
776                         goto out_hist;
777                 }
778                 trace_instance_start(&record->trace);
779         }
780
781         tool->start_time = time(NULL);
782         timerlat_hist_set_signals(params);
783
784         while (!stop_tracing) {
785                 sleep(params->sleep_time);
786
787                 retval = tracefs_iterate_raw_events(trace->tep,
788                                                     trace->inst,
789                                                     NULL,
790                                                     0,
791                                                     collect_registered_events,
792                                                     trace);
793                 if (retval < 0) {
794                         err_msg("Error iterating on events\n");
795                         goto out_hist;
796                 }
797
798                 if (!tracefs_trace_is_on(trace->inst))
799                         break;
800         };
801
802         timerlat_print_stats(params, tool);
803
804         return_value = 0;
805
806         if (!tracefs_trace_is_on(trace->inst)) {
807                 printf("rtla timelat hit stop tracing\n");
808                 if (params->trace_output) {
809                         printf("  Saving trace to %s\n", params->trace_output);
810                         save_trace_to_file(record->trace.inst, params->trace_output);
811                 }
812         }
813
814 out_hist:
815         timerlat_free_histogram(tool->data);
816         osnoise_destroy_tool(record);
817         osnoise_destroy_tool(tool);
818         free(params);
819 out_exit:
820         exit(return_value);
821 }