hc
2024-09-20 cf4ce59b3b70238352c7f1729f0f7223214828ad
kernel/tools/perf/builtin-ftrace.c
....@@ -1,34 +1,40 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * builtin-ftrace.c
34 *
45 * Copyright (c) 2013 LG Electronics, Namhyung Kim <namhyung@kernel.org>
5
- *
6
- * Released under the GPL v2.
6
+ * Copyright (c) 2020 Changbin Du <changbin.du@gmail.com>, significant enhancement.
77 */
88
99 #include "builtin.h"
10
-#include "perf.h"
1110
1211 #include <errno.h>
1312 #include <unistd.h>
1413 #include <signal.h>
14
+#include <stdlib.h>
1515 #include <fcntl.h>
1616 #include <poll.h>
17
+#include <linux/capability.h>
18
+#include <linux/string.h>
1719
1820 #include "debug.h"
21
+#include <subcmd/pager.h>
1922 #include <subcmd/parse-options.h>
2023 #include <api/fs/tracing_path.h>
2124 #include "evlist.h"
2225 #include "target.h"
2326 #include "cpumap.h"
2427 #include "thread_map.h"
28
+#include "strfilter.h"
29
+#include "util/cap.h"
2530 #include "util/config.h"
26
-
31
+#include "util/units.h"
32
+#include "util/parse-sublevel-options.h"
2733
2834 #define DEFAULT_TRACER "function_graph"
2935
3036 struct perf_ftrace {
31
- struct perf_evlist *evlist;
37
+ struct evlist *evlist;
3238 struct target target;
3339 const char *tracer;
3440 struct list_head filters;
....@@ -36,6 +42,15 @@
3642 struct list_head graph_funcs;
3743 struct list_head nograph_funcs;
3844 int graph_depth;
45
+ unsigned long percpu_buffer_size;
46
+ bool inherit;
47
+ int func_stack_trace;
48
+ int func_irq_info;
49
+ int graph_nosleep_time;
50
+ int graph_noirqs;
51
+ int graph_verbose;
52
+ int graph_thresh;
53
+ unsigned int initial_delay;
3954 };
4055
4156 struct filter_entry {
....@@ -43,6 +58,7 @@
4358 char name[];
4459 };
4560
61
+static volatile int workload_exec_errno;
4662 static bool done;
4763
4864 static void sig_handler(int sig __maybe_unused)
....@@ -61,7 +77,7 @@
6177 siginfo_t *info __maybe_unused,
6278 void *ucontext __maybe_unused)
6379 {
64
- /* workload_exec_errno = info->si_value.sival_int; */
80
+ workload_exec_errno = info->si_value.sival_int;
6581 done = true;
6682 }
6783
....@@ -125,8 +141,118 @@
125141 return __write_tracing_file(name, val, true);
126142 }
127143
144
+static int read_tracing_file_to_stdout(const char *name)
145
+{
146
+ char buf[4096];
147
+ char *file;
148
+ int fd;
149
+ int ret = -1;
150
+
151
+ file = get_tracing_file(name);
152
+ if (!file) {
153
+ pr_debug("cannot get tracing file: %s\n", name);
154
+ return -1;
155
+ }
156
+
157
+ fd = open(file, O_RDONLY);
158
+ if (fd < 0) {
159
+ pr_debug("cannot open tracing file: %s: %s\n",
160
+ name, str_error_r(errno, buf, sizeof(buf)));
161
+ goto out;
162
+ }
163
+
164
+ /* read contents to stdout */
165
+ while (true) {
166
+ int n = read(fd, buf, sizeof(buf));
167
+ if (n == 0)
168
+ break;
169
+ else if (n < 0)
170
+ goto out_close;
171
+
172
+ if (fwrite(buf, n, 1, stdout) != 1)
173
+ goto out_close;
174
+ }
175
+ ret = 0;
176
+
177
+out_close:
178
+ close(fd);
179
+out:
180
+ put_tracing_file(file);
181
+ return ret;
182
+}
183
+
184
+static int read_tracing_file_by_line(const char *name,
185
+ void (*cb)(char *str, void *arg),
186
+ void *cb_arg)
187
+{
188
+ char *line = NULL;
189
+ size_t len = 0;
190
+ char *file;
191
+ FILE *fp;
192
+
193
+ file = get_tracing_file(name);
194
+ if (!file) {
195
+ pr_debug("cannot get tracing file: %s\n", name);
196
+ return -1;
197
+ }
198
+
199
+ fp = fopen(file, "r");
200
+ if (fp == NULL) {
201
+ pr_debug("cannot open tracing file: %s\n", name);
202
+ put_tracing_file(file);
203
+ return -1;
204
+ }
205
+
206
+ while (getline(&line, &len, fp) != -1) {
207
+ cb(line, cb_arg);
208
+ }
209
+
210
+ if (line)
211
+ free(line);
212
+
213
+ fclose(fp);
214
+ put_tracing_file(file);
215
+ return 0;
216
+}
217
+
218
+static int write_tracing_file_int(const char *name, int value)
219
+{
220
+ char buf[16];
221
+
222
+ snprintf(buf, sizeof(buf), "%d", value);
223
+ if (write_tracing_file(name, buf) < 0)
224
+ return -1;
225
+
226
+ return 0;
227
+}
228
+
229
+static int write_tracing_option_file(const char *name, const char *val)
230
+{
231
+ char *file;
232
+ int ret;
233
+
234
+ if (asprintf(&file, "options/%s", name) < 0)
235
+ return -1;
236
+
237
+ ret = __write_tracing_file(file, val, false);
238
+ free(file);
239
+ return ret;
240
+}
241
+
128242 static int reset_tracing_cpu(void);
129243 static void reset_tracing_filters(void);
244
+
245
+static void reset_tracing_options(struct perf_ftrace *ftrace __maybe_unused)
246
+{
247
+ write_tracing_option_file("function-fork", "0");
248
+ write_tracing_option_file("func_stack_trace", "0");
249
+ write_tracing_option_file("sleep-time", "1");
250
+ write_tracing_option_file("funcgraph-irqs", "1");
251
+ write_tracing_option_file("funcgraph-proc", "0");
252
+ write_tracing_option_file("funcgraph-abstime", "0");
253
+ write_tracing_option_file("latency-format", "0");
254
+ write_tracing_option_file("irq-info", "0");
255
+}
130256
131257 static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
132258 {
....@@ -145,7 +271,11 @@
145271 if (write_tracing_file("max_graph_depth", "0") < 0)
146272 return -1;
147273
274
+ if (write_tracing_file("tracing_thresh", "0") < 0)
275
+ return -1;
276
+
148277 reset_tracing_filters();
278
+ reset_tracing_options(ftrace);
149279 return 0;
150280 }
151281
....@@ -157,16 +287,16 @@
157287 if (target__has_cpu(&ftrace->target))
158288 return 0;
159289
160
- for (i = 0; i < thread_map__nr(ftrace->evlist->threads); i++) {
290
+ for (i = 0; i < perf_thread_map__nr(ftrace->evlist->core.threads); i++) {
161291 scnprintf(buf, sizeof(buf), "%d",
162
- ftrace->evlist->threads->map[i]);
292
+ perf_thread_map__pid(ftrace->evlist->core.threads, i));
163293 if (append_tracing_file("set_ftrace_pid", buf) < 0)
164294 return -1;
165295 }
166296 return 0;
167297 }
168298
169
-static int set_tracing_cpumask(struct cpu_map *cpumap)
299
+static int set_tracing_cpumask(struct perf_cpu_map *cpumap)
170300 {
171301 char *cpumask;
172302 size_t mask_size;
....@@ -193,7 +323,7 @@
193323
194324 static int set_tracing_cpu(struct perf_ftrace *ftrace)
195325 {
196
- struct cpu_map *cpumap = ftrace->evlist->cpus;
326
+ struct perf_cpu_map *cpumap = ftrace->evlist->core.cpus;
197327
198328 if (!target__has_cpu(&ftrace->target))
199329 return 0;
....@@ -201,13 +331,35 @@
201331 return set_tracing_cpumask(cpumap);
202332 }
203333
334
+static int set_tracing_func_stack_trace(struct perf_ftrace *ftrace)
335
+{
336
+ if (!ftrace->func_stack_trace)
337
+ return 0;
338
+
339
+ if (write_tracing_option_file("func_stack_trace", "1") < 0)
340
+ return -1;
341
+
342
+ return 0;
343
+}
344
+
345
+static int set_tracing_func_irqinfo(struct perf_ftrace *ftrace)
346
+{
347
+ if (!ftrace->func_irq_info)
348
+ return 0;
349
+
350
+ if (write_tracing_option_file("irq-info", "1") < 0)
351
+ return -1;
352
+
353
+ return 0;
354
+}
355
+
204356 static int reset_tracing_cpu(void)
205357 {
206
- struct cpu_map *cpumap = cpu_map__new(NULL);
358
+ struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL);
207359 int ret;
208360
209361 ret = set_tracing_cpumask(cpumap);
210
- cpu_map__put(cpumap);
362
+ perf_cpu_map__put(cpumap);
211363 return ret;
212364 }
213365
....@@ -255,8 +407,6 @@
255407
256408 static int set_tracing_depth(struct perf_ftrace *ftrace)
257409 {
258
- char buf[16];
259
-
260410 if (ftrace->graph_depth == 0)
261411 return 0;
262412
....@@ -265,10 +415,152 @@
265415 return -1;
266416 }
267417
268
- snprintf(buf, sizeof(buf), "%d", ftrace->graph_depth);
269
-
270
- if (write_tracing_file("max_graph_depth", buf) < 0)
418
+ if (write_tracing_file_int("max_graph_depth", ftrace->graph_depth) < 0)
271419 return -1;
420
+
421
+ return 0;
422
+}
423
+
424
+static int set_tracing_percpu_buffer_size(struct perf_ftrace *ftrace)
425
+{
426
+ int ret;
427
+
428
+ if (ftrace->percpu_buffer_size == 0)
429
+ return 0;
430
+
431
+ ret = write_tracing_file_int("buffer_size_kb",
432
+ ftrace->percpu_buffer_size / 1024);
433
+ if (ret < 0)
434
+ return ret;
435
+
436
+ return 0;
437
+}
438
+
439
+static int set_tracing_trace_inherit(struct perf_ftrace *ftrace)
440
+{
441
+ if (!ftrace->inherit)
442
+ return 0;
443
+
444
+ if (write_tracing_option_file("function-fork", "1") < 0)
445
+ return -1;
446
+
447
+ return 0;
448
+}
449
+
450
+static int set_tracing_sleep_time(struct perf_ftrace *ftrace)
451
+{
452
+ if (!ftrace->graph_nosleep_time)
453
+ return 0;
454
+
455
+ if (write_tracing_option_file("sleep-time", "0") < 0)
456
+ return -1;
457
+
458
+ return 0;
459
+}
460
+
461
+static int set_tracing_funcgraph_irqs(struct perf_ftrace *ftrace)
462
+{
463
+ if (!ftrace->graph_noirqs)
464
+ return 0;
465
+
466
+ if (write_tracing_option_file("funcgraph-irqs", "0") < 0)
467
+ return -1;
468
+
469
+ return 0;
470
+}
471
+
472
+static int set_tracing_funcgraph_verbose(struct perf_ftrace *ftrace)
473
+{
474
+ if (!ftrace->graph_verbose)
475
+ return 0;
476
+
477
+ if (write_tracing_option_file("funcgraph-proc", "1") < 0)
478
+ return -1;
479
+
480
+ if (write_tracing_option_file("funcgraph-abstime", "1") < 0)
481
+ return -1;
482
+
483
+ if (write_tracing_option_file("latency-format", "1") < 0)
484
+ return -1;
485
+
486
+ return 0;
487
+}
488
+
489
+static int set_tracing_thresh(struct perf_ftrace *ftrace)
490
+{
491
+ int ret;
492
+
493
+ if (ftrace->graph_thresh == 0)
494
+ return 0;
495
+
496
+ ret = write_tracing_file_int("tracing_thresh", ftrace->graph_thresh);
497
+ if (ret < 0)
498
+ return ret;
499
+
500
+ return 0;
501
+}
502
+
503
+static int set_tracing_options(struct perf_ftrace *ftrace)
504
+{
505
+ if (set_tracing_pid(ftrace) < 0) {
506
+ pr_err("failed to set ftrace pid\n");
507
+ return -1;
508
+ }
509
+
510
+ if (set_tracing_cpu(ftrace) < 0) {
511
+ pr_err("failed to set tracing cpumask\n");
512
+ return -1;
513
+ }
514
+
515
+ if (set_tracing_func_stack_trace(ftrace) < 0) {
516
+ pr_err("failed to set tracing option func_stack_trace\n");
517
+ return -1;
518
+ }
519
+
520
+ if (set_tracing_func_irqinfo(ftrace) < 0) {
521
+ pr_err("failed to set tracing option irq-info\n");
522
+ return -1;
523
+ }
524
+
525
+ if (set_tracing_filters(ftrace) < 0) {
526
+ pr_err("failed to set tracing filters\n");
527
+ return -1;
528
+ }
529
+
530
+ if (set_tracing_depth(ftrace) < 0) {
531
+ pr_err("failed to set graph depth\n");
532
+ return -1;
533
+ }
534
+
535
+ if (set_tracing_percpu_buffer_size(ftrace) < 0) {
536
+ pr_err("failed to set tracing per-cpu buffer size\n");
537
+ return -1;
538
+ }
539
+
540
+ if (set_tracing_trace_inherit(ftrace) < 0) {
541
+ pr_err("failed to set tracing option function-fork\n");
542
+ return -1;
543
+ }
544
+
545
+ if (set_tracing_sleep_time(ftrace) < 0) {
546
+ pr_err("failed to set tracing option sleep-time\n");
547
+ return -1;
548
+ }
549
+
550
+ if (set_tracing_funcgraph_irqs(ftrace) < 0) {
551
+ pr_err("failed to set tracing option funcgraph-irqs\n");
552
+ return -1;
553
+ }
554
+
555
+ if (set_tracing_funcgraph_verbose(ftrace) < 0) {
556
+ pr_err("failed to set tracing option funcgraph-proc/funcgraph-abstime\n");
557
+ return -1;
558
+ }
559
+
560
+ if (set_tracing_thresh(ftrace) < 0) {
561
+ pr_err("failed to set tracing thresh\n");
562
+ return -1;
563
+ }
272564
273565 return 0;
274566 }
....@@ -282,8 +574,15 @@
282574 .events = POLLIN,
283575 };
284576
285
- if (geteuid() != 0) {
286
- pr_err("ftrace only works for root!\n");
577
+ if (!(perf_cap__capable(CAP_PERFMON) ||
578
+ perf_cap__capable(CAP_SYS_ADMIN))) {
579
+ pr_err("ftrace only works for %s!\n",
580
+#ifdef HAVE_LIBCAP_SUPPORT
581
+ "users with the CAP_PERFMON or CAP_SYS_ADMIN capability"
582
+#else
583
+ "root"
584
+#endif
585
+ );
287586 return -1;
288587 }
289588
....@@ -307,25 +606,8 @@
307606 goto out;
308607 }
309608
310
- if (set_tracing_pid(ftrace) < 0) {
311
- pr_err("failed to set ftrace pid\n");
609
+ if (set_tracing_options(ftrace) < 0)
312610 goto out_reset;
313
- }
314
-
315
- if (set_tracing_cpu(ftrace) < 0) {
316
- pr_err("failed to set tracing cpumask\n");
317
- goto out_reset;
318
- }
319
-
320
- if (set_tracing_filters(ftrace) < 0) {
321
- pr_err("failed to set tracing filters\n");
322
- goto out_reset;
323
- }
324
-
325
- if (set_tracing_depth(ftrace) < 0) {
326
- pr_err("failed to set graph depth\n");
327
- goto out_reset;
328
- }
329611
330612 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
331613 pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
....@@ -352,12 +634,25 @@
352634 fcntl(trace_fd, F_SETFL, O_NONBLOCK);
353635 pollfd.fd = trace_fd;
354636
355
- if (write_tracing_file("tracing_on", "1") < 0) {
356
- pr_err("can't enable tracing\n");
357
- goto out_close_fd;
637
+ /* display column headers */
638
+ read_tracing_file_to_stdout("trace");
639
+
640
+ if (!ftrace->initial_delay) {
641
+ if (write_tracing_file("tracing_on", "1") < 0) {
642
+ pr_err("can't enable tracing\n");
643
+ goto out_close_fd;
644
+ }
358645 }
359646
360647 perf_evlist__start_workload(ftrace->evlist);
648
+
649
+ if (ftrace->initial_delay) {
650
+ usleep(ftrace->initial_delay * 1000);
651
+ if (write_tracing_file("tracing_on", "1") < 0) {
652
+ pr_err("can't enable tracing\n");
653
+ goto out_close_fd;
654
+ }
655
+ }
361656
362657 while (!done) {
363658 if (poll(&pollfd, 1, -1) < 0)
....@@ -374,6 +669,14 @@
374669
375670 write_tracing_file("tracing_on", "0");
376671
672
+ if (workload_exec_errno) {
673
+ const char *emsg = str_error_r(workload_exec_errno, buf, sizeof(buf));
674
+ /* flush stdout first so below error msg appears at the end. */
675
+ fflush(stdout);
676
+ pr_err("workload failed: %s\n", emsg);
677
+ goto out_close_fd;
678
+ }
679
+
377680 /* read remaining buffer contents */
378681 while (true) {
379682 int n = read(trace_fd, buf, sizeof(buf));
....@@ -388,7 +691,7 @@
388691 out_reset:
389692 reset_tracing_files(ftrace);
390693 out:
391
- return done ? 0 : -1;
694
+ return (done && !workload_exec_errno) ? 0 : -1;
392695 }
393696
394697 static int perf_ftrace_config(const char *var, const char *value, void *cb)
....@@ -409,6 +712,46 @@
409712
410713 pr_err("Please select \"function_graph\" (default) or \"function\"\n");
411714 return -1;
715
+}
716
+
717
+static void list_function_cb(char *str, void *arg)
718
+{
719
+ struct strfilter *filter = (struct strfilter *)arg;
720
+
721
+ if (strfilter__compare(filter, str))
722
+ printf("%s", str);
723
+}
724
+
725
+static int opt_list_avail_functions(const struct option *opt __maybe_unused,
726
+ const char *str, int unset)
727
+{
728
+ struct strfilter *filter;
729
+ const char *err = NULL;
730
+ int ret;
731
+
732
+ if (unset || !str)
733
+ return -1;
734
+
735
+ filter = strfilter__new(str, &err);
736
+ if (!filter)
737
+ return err ? -EINVAL : -ENOMEM;
738
+
739
+ ret = strfilter__or(filter, str, &err);
740
+ if (ret == -EINVAL) {
741
+ pr_err("Filter parse error at %td.\n", err - str + 1);
742
+ pr_err("Source: \"%s\"\n", str);
743
+ pr_err(" %*c\n", (int)(err - str + 1), '^');
744
+ strfilter__delete(filter);
745
+ return ret;
746
+ }
747
+
748
+ ret = read_tracing_file_by_line("available_filter_functions",
749
+ list_function_cb, filter);
750
+ strfilter__delete(filter);
751
+ if (ret < 0)
752
+ return ret;
753
+
754
+ exit(0);
412755 }
413756
414757 static int parse_filter_func(const struct option *opt, const char *str,
....@@ -432,9 +775,102 @@
432775 struct filter_entry *pos, *tmp;
433776
434777 list_for_each_entry_safe(pos, tmp, head, list) {
435
- list_del(&pos->list);
778
+ list_del_init(&pos->list);
436779 free(pos);
437780 }
781
+}
782
+
783
+static int parse_buffer_size(const struct option *opt,
784
+ const char *str, int unset)
785
+{
786
+ unsigned long *s = (unsigned long *)opt->value;
787
+ static struct parse_tag tags_size[] = {
788
+ { .tag = 'B', .mult = 1 },
789
+ { .tag = 'K', .mult = 1 << 10 },
790
+ { .tag = 'M', .mult = 1 << 20 },
791
+ { .tag = 'G', .mult = 1 << 30 },
792
+ { .tag = 0 },
793
+ };
794
+ unsigned long val;
795
+
796
+ if (unset) {
797
+ *s = 0;
798
+ return 0;
799
+ }
800
+
801
+ val = parse_tag_value(str, tags_size);
802
+ if (val != (unsigned long) -1) {
803
+ if (val < 1024) {
804
+ pr_err("buffer size too small, must larger than 1KB.");
805
+ return -1;
806
+ }
807
+ *s = val;
808
+ return 0;
809
+ }
810
+
811
+ return -1;
812
+}
813
+
814
+static int parse_func_tracer_opts(const struct option *opt,
815
+ const char *str, int unset)
816
+{
817
+ int ret;
818
+ struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value;
819
+ struct sublevel_option func_tracer_opts[] = {
820
+ { .name = "call-graph", .value_ptr = &ftrace->func_stack_trace },
821
+ { .name = "irq-info", .value_ptr = &ftrace->func_irq_info },
822
+ { .name = NULL, }
823
+ };
824
+
825
+ if (unset)
826
+ return 0;
827
+
828
+ ret = perf_parse_sublevel_options(str, func_tracer_opts);
829
+ if (ret)
830
+ return ret;
831
+
832
+ return 0;
833
+}
834
+
835
+static int parse_graph_tracer_opts(const struct option *opt,
836
+ const char *str, int unset)
837
+{
838
+ int ret;
839
+ struct perf_ftrace *ftrace = (struct perf_ftrace *) opt->value;
840
+ struct sublevel_option graph_tracer_opts[] = {
841
+ { .name = "nosleep-time", .value_ptr = &ftrace->graph_nosleep_time },
842
+ { .name = "noirqs", .value_ptr = &ftrace->graph_noirqs },
843
+ { .name = "verbose", .value_ptr = &ftrace->graph_verbose },
844
+ { .name = "thresh", .value_ptr = &ftrace->graph_thresh },
845
+ { .name = "depth", .value_ptr = &ftrace->graph_depth },
846
+ { .name = NULL, }
847
+ };
848
+
849
+ if (unset)
850
+ return 0;
851
+
852
+ ret = perf_parse_sublevel_options(str, graph_tracer_opts);
853
+ if (ret)
854
+ return ret;
855
+
856
+ return 0;
857
+}
858
+
859
+static void select_tracer(struct perf_ftrace *ftrace)
860
+{
861
+ bool graph = !list_empty(&ftrace->graph_funcs) ||
862
+ !list_empty(&ftrace->nograph_funcs);
863
+ bool func = !list_empty(&ftrace->filters) ||
864
+ !list_empty(&ftrace->notrace);
865
+
866
+ /* The function_graph has priority over function tracer. */
867
+ if (graph)
868
+ ftrace->tracer = "function_graph";
869
+ else if (func)
870
+ ftrace->tracer = "function";
871
+ /* Otherwise, the default tracer is used. */
872
+
873
+ pr_debug("%s tracer is used\n", ftrace->tracer);
438874 }
439875
440876 int cmd_ftrace(int argc, const char **argv)
....@@ -451,25 +887,43 @@
451887 };
452888 const struct option ftrace_options[] = {
453889 OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
454
- "tracer to use: function_graph(default) or function"),
890
+ "Tracer to use: function_graph(default) or function"),
891
+ OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]",
892
+ "Show available functions to filter",
893
+ opt_list_avail_functions, "*"),
455894 OPT_STRING('p', "pid", &ftrace.target.pid, "pid",
456
- "trace on existing process id"),
895
+ "Trace on existing process id"),
896
+ /* TODO: Add short option -t after -t/--tracer can be removed. */
897
+ OPT_STRING(0, "tid", &ftrace.target.tid, "tid",
898
+ "Trace on existing thread id (exclusive to --pid)"),
457899 OPT_INCR('v', "verbose", &verbose,
458
- "be more verbose"),
900
+ "Be more verbose"),
459901 OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide,
460
- "system-wide collection from all CPUs"),
902
+ "System-wide collection from all CPUs"),
461903 OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu",
462
- "list of cpus to monitor"),
904
+ "List of cpus to monitor"),
463905 OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func",
464
- "trace given functions only", parse_filter_func),
906
+ "Trace given functions using function tracer",
907
+ parse_filter_func),
465908 OPT_CALLBACK('N', "notrace-funcs", &ftrace.notrace, "func",
466
- "do not trace given functions", parse_filter_func),
909
+ "Do not trace given functions", parse_filter_func),
910
+ OPT_CALLBACK(0, "func-opts", &ftrace, "options",
911
+ "Function tracer options, available options: call-graph,irq-info",
912
+ parse_func_tracer_opts),
467913 OPT_CALLBACK('G', "graph-funcs", &ftrace.graph_funcs, "func",
468
- "Set graph filter on given functions", parse_filter_func),
914
+ "Trace given functions using function_graph tracer",
915
+ parse_filter_func),
469916 OPT_CALLBACK('g', "nograph-funcs", &ftrace.nograph_funcs, "func",
470917 "Set nograph filter on given functions", parse_filter_func),
471
- OPT_INTEGER('D', "graph-depth", &ftrace.graph_depth,
472
- "Max depth for function graph tracer"),
918
+ OPT_CALLBACK(0, "graph-opts", &ftrace, "options",
919
+ "Graph tracer options, available options: nosleep-time,noirqs,verbose,thresh=<n>,depth=<n>",
920
+ parse_graph_tracer_opts),
921
+ OPT_CALLBACK('m', "buffer-size", &ftrace.percpu_buffer_size, "size",
922
+ "Size of per cpu buffer, needs to use a B, K, M or G suffix.", parse_buffer_size),
923
+ OPT_BOOLEAN(0, "inherit", &ftrace.inherit,
924
+ "Trace children processes"),
925
+ OPT_UINTEGER('D', "delay", &ftrace.initial_delay,
926
+ "Number of milliseconds to wait before starting tracing after program start"),
473927 OPT_END()
474928 };
475929
....@@ -485,7 +939,9 @@
485939 argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
486940 PARSE_OPT_STOP_AT_NON_OPTION);
487941 if (!argc && target__none(&ftrace.target))
488
- usage_with_options(ftrace_usage, ftrace_options);
942
+ ftrace.target.system_wide = true;
943
+
944
+ select_tracer(&ftrace);
489945
490946 ret = target__validate(&ftrace.target);
491947 if (ret) {
....@@ -496,7 +952,7 @@
496952 goto out_delete_filters;
497953 }
498954
499
- ftrace.evlist = perf_evlist__new();
955
+ ftrace.evlist = evlist__new();
500956 if (ftrace.evlist == NULL) {
501957 ret = -ENOMEM;
502958 goto out_delete_filters;
....@@ -509,7 +965,7 @@
509965 ret = __cmd_ftrace(&ftrace, argc, argv);
510966
511967 out_delete_evlist:
512
- perf_evlist__delete(ftrace.evlist);
968
+ evlist__delete(ftrace.evlist);
513969
514970 out_delete_filters:
515971 delete_filter_func(&ftrace.filters);