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