diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-06-29 05:34:41 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-06-29 05:34:41 -0400 |
commit | d905768c9e1addfa35d9731dbaa9242e8991f6ac (patch) | |
tree | f80cc76eaf80b553799fa93358054fbfb94907e3 | |
parent | d4cf1949f9689314aef962eea95df84a8288d097 (diff) | |
parent | ebccba3fe0a02f622f80e6be0e8ecb1a9a3ed983 (diff) |
Merge tag 'perf-core-for-mingo-20160628' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New features:
- Generate comm, fork and exit events when converting perf.data files to CTF (Wang Nan)
Infrastructure changes:
- Add libbabeltrace to build-test (Wang Nan)
- 'perf record' prep work to support multiple evlists (Wang Nan)
- Remove unused hist_entry__annotate function (Ravi Bangoria)
- Add more toolchain triplets (Ravi Bangoria)
- Update message for slang devel packages on Ubuntu (Neeraj Badlani)
- Generalize handling of 'ret' instructions in the annotate TUI (Naveen N. Rao)
- Use proper dso name for is_regular_file, fixing device file handling (Jiri Olsa)
Build Fixes:
- Add missing config.h include, fixing the build with libbabeltrace (Jiri Olsa)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/Documentation/perf-data.txt | 4 | ||||
-rw-r--r-- | tools/perf/arch/common.c | 17 | ||||
-rw-r--r-- | tools/perf/builtin-data.c | 11 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 105 | ||||
-rw-r--r-- | tools/perf/config/Makefile | 2 | ||||
-rw-r--r-- | tools/perf/tests/make | 2 | ||||
-rw-r--r-- | tools/perf/ui/browsers/annotate.c | 20 | ||||
-rw-r--r-- | tools/perf/util/annotate.c | 15 | ||||
-rw-r--r-- | tools/perf/util/annotate.h | 3 | ||||
-rw-r--r-- | tools/perf/util/data-convert-bt.c | 196 | ||||
-rw-r--r-- | tools/perf/util/data-convert-bt.h | 4 | ||||
-rw-r--r-- | tools/perf/util/data-convert.h | 9 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 2 |
13 files changed, 331 insertions, 59 deletions
diff --git a/tools/perf/Documentation/perf-data.txt b/tools/perf/Documentation/perf-data.txt index be8fa1a0a97e..f0796a47dfa3 100644 --- a/tools/perf/Documentation/perf-data.txt +++ b/tools/perf/Documentation/perf-data.txt | |||
@@ -34,6 +34,10 @@ OPTIONS for 'convert' | |||
34 | --verbose:: | 34 | --verbose:: |
35 | Be more verbose (show counter open errors, etc). | 35 | Be more verbose (show counter open errors, etc). |
36 | 36 | ||
37 | --all:: | ||
38 | Convert all events, including non-sample events (comm, fork, ...), to output. | ||
39 | Default is off, only convert samples. | ||
40 | |||
37 | SEE ALSO | 41 | SEE ALSO |
38 | -------- | 42 | -------- |
39 | linkperf:perf[1] | 43 | linkperf:perf[1] |
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index fa090a9eaa38..ee6966812a5a 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c | |||
@@ -9,34 +9,44 @@ const char *const arm_triplets[] = { | |||
9 | "arm-unknown-linux-", | 9 | "arm-unknown-linux-", |
10 | "arm-unknown-linux-gnu-", | 10 | "arm-unknown-linux-gnu-", |
11 | "arm-unknown-linux-gnueabi-", | 11 | "arm-unknown-linux-gnueabi-", |
12 | "arm-linux-gnu-", | ||
13 | "arm-linux-gnueabihf-", | ||
14 | "arm-none-eabi-", | ||
12 | NULL | 15 | NULL |
13 | }; | 16 | }; |
14 | 17 | ||
15 | const char *const arm64_triplets[] = { | 18 | const char *const arm64_triplets[] = { |
16 | "aarch64-linux-android-", | 19 | "aarch64-linux-android-", |
20 | "aarch64-linux-gnu-", | ||
17 | NULL | 21 | NULL |
18 | }; | 22 | }; |
19 | 23 | ||
20 | const char *const powerpc_triplets[] = { | 24 | const char *const powerpc_triplets[] = { |
21 | "powerpc-unknown-linux-gnu-", | 25 | "powerpc-unknown-linux-gnu-", |
22 | "powerpc64-unknown-linux-gnu-", | 26 | "powerpc64-unknown-linux-gnu-", |
27 | "powerpc64-linux-gnu-", | ||
28 | "powerpc64le-linux-gnu-", | ||
23 | NULL | 29 | NULL |
24 | }; | 30 | }; |
25 | 31 | ||
26 | const char *const s390_triplets[] = { | 32 | const char *const s390_triplets[] = { |
27 | "s390-ibm-linux-", | 33 | "s390-ibm-linux-", |
34 | "s390x-linux-gnu-", | ||
28 | NULL | 35 | NULL |
29 | }; | 36 | }; |
30 | 37 | ||
31 | const char *const sh_triplets[] = { | 38 | const char *const sh_triplets[] = { |
32 | "sh-unknown-linux-gnu-", | 39 | "sh-unknown-linux-gnu-", |
33 | "sh64-unknown-linux-gnu-", | 40 | "sh64-unknown-linux-gnu-", |
41 | "sh-linux-gnu-", | ||
42 | "sh64-linux-gnu-", | ||
34 | NULL | 43 | NULL |
35 | }; | 44 | }; |
36 | 45 | ||
37 | const char *const sparc_triplets[] = { | 46 | const char *const sparc_triplets[] = { |
38 | "sparc-unknown-linux-gnu-", | 47 | "sparc-unknown-linux-gnu-", |
39 | "sparc64-unknown-linux-gnu-", | 48 | "sparc64-unknown-linux-gnu-", |
49 | "sparc64-linux-gnu-", | ||
40 | NULL | 50 | NULL |
41 | }; | 51 | }; |
42 | 52 | ||
@@ -49,12 +59,19 @@ const char *const x86_triplets[] = { | |||
49 | "i386-pc-linux-gnu-", | 59 | "i386-pc-linux-gnu-", |
50 | "i686-linux-android-", | 60 | "i686-linux-android-", |
51 | "i686-android-linux-", | 61 | "i686-android-linux-", |
62 | "x86_64-linux-gnu-", | ||
63 | "i586-linux-gnu-", | ||
52 | NULL | 64 | NULL |
53 | }; | 65 | }; |
54 | 66 | ||
55 | const char *const mips_triplets[] = { | 67 | const char *const mips_triplets[] = { |
56 | "mips-unknown-linux-gnu-", | 68 | "mips-unknown-linux-gnu-", |
57 | "mipsel-linux-android-", | 69 | "mipsel-linux-android-", |
70 | "mips-linux-gnu-", | ||
71 | "mips64-linux-gnu-", | ||
72 | "mips64el-linux-gnuabi64-", | ||
73 | "mips64-linux-gnuabi64-", | ||
74 | "mipsel-linux-gnu-", | ||
58 | NULL | 75 | NULL |
59 | }; | 76 | }; |
60 | 77 | ||
diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c index b97bc1518b44..7ad6e17ac6b3 100644 --- a/tools/perf/builtin-data.c +++ b/tools/perf/builtin-data.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "perf.h" | 3 | #include "perf.h" |
4 | #include "debug.h" | 4 | #include "debug.h" |
5 | #include <subcmd/parse-options.h> | 5 | #include <subcmd/parse-options.h> |
6 | #include "data-convert.h" | ||
6 | #include "data-convert-bt.h" | 7 | #include "data-convert-bt.h" |
7 | 8 | ||
8 | typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); | 9 | typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); |
@@ -53,14 +54,18 @@ static int cmd_data_convert(int argc, const char **argv, | |||
53 | const char *prefix __maybe_unused) | 54 | const char *prefix __maybe_unused) |
54 | { | 55 | { |
55 | const char *to_ctf = NULL; | 56 | const char *to_ctf = NULL; |
56 | bool force = false; | 57 | struct perf_data_convert_opts opts = { |
58 | .force = false, | ||
59 | .all = false, | ||
60 | }; | ||
57 | const struct option options[] = { | 61 | const struct option options[] = { |
58 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | 62 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), |
59 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | 63 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
60 | #ifdef HAVE_LIBBABELTRACE_SUPPORT | 64 | #ifdef HAVE_LIBBABELTRACE_SUPPORT |
61 | OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"), | 65 | OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"), |
62 | #endif | 66 | #endif |
63 | OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), | 67 | OPT_BOOLEAN('f', "force", &opts.force, "don't complain, do it"), |
68 | OPT_BOOLEAN(0, "all", &opts.all, "Convert all events"), | ||
64 | OPT_END() | 69 | OPT_END() |
65 | }; | 70 | }; |
66 | 71 | ||
@@ -78,7 +83,7 @@ static int cmd_data_convert(int argc, const char **argv, | |||
78 | 83 | ||
79 | if (to_ctf) { | 84 | if (to_ctf) { |
80 | #ifdef HAVE_LIBBABELTRACE_SUPPORT | 85 | #ifdef HAVE_LIBBABELTRACE_SUPPORT |
81 | return bt_convert__perf2ctf(input_name, to_ctf, force); | 86 | return bt_convert__perf2ctf(input_name, to_ctf, &opts); |
82 | #else | 87 | #else |
83 | pr_err("The libbabeltrace support is not compiled in.\n"); | 88 | pr_err("The libbabeltrace support is not compiled in.\n"); |
84 | return -1; | 89 | return -1; |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 81411b14df4c..b2b3b600adf5 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -132,9 +132,9 @@ rb_find_range(struct perf_evlist *evlist, | |||
132 | return backward_rb_find_range(data, mask, head, start, end); | 132 | return backward_rb_find_range(data, mask, head, start, end); |
133 | } | 133 | } |
134 | 134 | ||
135 | static int record__mmap_read(struct record *rec, int idx) | 135 | static int record__mmap_read(struct record *rec, struct perf_evlist *evlist, int idx) |
136 | { | 136 | { |
137 | struct perf_mmap *md = &rec->evlist->mmap[idx]; | 137 | struct perf_mmap *md = &evlist->mmap[idx]; |
138 | u64 head = perf_mmap__read_head(md); | 138 | u64 head = perf_mmap__read_head(md); |
139 | u64 old = md->prev; | 139 | u64 old = md->prev; |
140 | u64 end = head, start = old; | 140 | u64 end = head, start = old; |
@@ -143,7 +143,7 @@ static int record__mmap_read(struct record *rec, int idx) | |||
143 | void *buf; | 143 | void *buf; |
144 | int rc = 0; | 144 | int rc = 0; |
145 | 145 | ||
146 | if (rb_find_range(rec->evlist, data, md->mask, head, | 146 | if (rb_find_range(evlist, data, md->mask, head, |
147 | old, &start, &end)) | 147 | old, &start, &end)) |
148 | return -1; | 148 | return -1; |
149 | 149 | ||
@@ -157,7 +157,7 @@ static int record__mmap_read(struct record *rec, int idx) | |||
157 | WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); | 157 | WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); |
158 | 158 | ||
159 | md->prev = head; | 159 | md->prev = head; |
160 | perf_evlist__mmap_consume(rec->evlist, idx); | 160 | perf_evlist__mmap_consume(evlist, idx); |
161 | return 0; | 161 | return 0; |
162 | } | 162 | } |
163 | 163 | ||
@@ -182,7 +182,7 @@ static int record__mmap_read(struct record *rec, int idx) | |||
182 | } | 182 | } |
183 | 183 | ||
184 | md->prev = head; | 184 | md->prev = head; |
185 | perf_evlist__mmap_consume(rec->evlist, idx); | 185 | perf_evlist__mmap_consume(evlist, idx); |
186 | out: | 186 | out: |
187 | return rc; | 187 | return rc; |
188 | } | 188 | } |
@@ -342,6 +342,40 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr __maybe_unused) | |||
342 | 342 | ||
343 | #endif | 343 | #endif |
344 | 344 | ||
345 | static int record__mmap_evlist(struct record *rec, | ||
346 | struct perf_evlist *evlist) | ||
347 | { | ||
348 | struct record_opts *opts = &rec->opts; | ||
349 | char msg[512]; | ||
350 | |||
351 | if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false, | ||
352 | opts->auxtrace_mmap_pages, | ||
353 | opts->auxtrace_snapshot_mode) < 0) { | ||
354 | if (errno == EPERM) { | ||
355 | pr_err("Permission error mapping pages.\n" | ||
356 | "Consider increasing " | ||
357 | "/proc/sys/kernel/perf_event_mlock_kb,\n" | ||
358 | "or try again with a smaller value of -m/--mmap_pages.\n" | ||
359 | "(current value: %u,%u)\n", | ||
360 | opts->mmap_pages, opts->auxtrace_mmap_pages); | ||
361 | return -errno; | ||
362 | } else { | ||
363 | pr_err("failed to mmap with %d (%s)\n", errno, | ||
364 | strerror_r(errno, msg, sizeof(msg))); | ||
365 | if (errno) | ||
366 | return -errno; | ||
367 | else | ||
368 | return -EINVAL; | ||
369 | } | ||
370 | } | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int record__mmap(struct record *rec) | ||
375 | { | ||
376 | return record__mmap_evlist(rec, rec->evlist); | ||
377 | } | ||
378 | |||
345 | static int record__open(struct record *rec) | 379 | static int record__open(struct record *rec) |
346 | { | 380 | { |
347 | char msg[512]; | 381 | char msg[512]; |
@@ -378,27 +412,9 @@ try_again: | |||
378 | goto out; | 412 | goto out; |
379 | } | 413 | } |
380 | 414 | ||
381 | if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false, | 415 | rc = record__mmap(rec); |
382 | opts->auxtrace_mmap_pages, | 416 | if (rc) |
383 | opts->auxtrace_snapshot_mode) < 0) { | ||
384 | if (errno == EPERM) { | ||
385 | pr_err("Permission error mapping pages.\n" | ||
386 | "Consider increasing " | ||
387 | "/proc/sys/kernel/perf_event_mlock_kb,\n" | ||
388 | "or try again with a smaller value of -m/--mmap_pages.\n" | ||
389 | "(current value: %u,%u)\n", | ||
390 | opts->mmap_pages, opts->auxtrace_mmap_pages); | ||
391 | rc = -errno; | ||
392 | } else { | ||
393 | pr_err("failed to mmap with %d (%s)\n", errno, | ||
394 | strerror_r(errno, msg, sizeof(msg))); | ||
395 | if (errno) | ||
396 | rc = -errno; | ||
397 | else | ||
398 | rc = -EINVAL; | ||
399 | } | ||
400 | goto out; | 417 | goto out; |
401 | } | ||
402 | 418 | ||
403 | session->evlist = evlist; | 419 | session->evlist = evlist; |
404 | perf_session__set_id_hdr_size(session); | 420 | perf_session__set_id_hdr_size(session); |
@@ -482,17 +498,20 @@ static struct perf_event_header finished_round_event = { | |||
482 | .type = PERF_RECORD_FINISHED_ROUND, | 498 | .type = PERF_RECORD_FINISHED_ROUND, |
483 | }; | 499 | }; |
484 | 500 | ||
485 | static int record__mmap_read_all(struct record *rec) | 501 | static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evlist) |
486 | { | 502 | { |
487 | u64 bytes_written = rec->bytes_written; | 503 | u64 bytes_written = rec->bytes_written; |
488 | int i; | 504 | int i; |
489 | int rc = 0; | 505 | int rc = 0; |
490 | 506 | ||
491 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { | 507 | if (!evlist) |
492 | struct auxtrace_mmap *mm = &rec->evlist->mmap[i].auxtrace_mmap; | 508 | return 0; |
493 | 509 | ||
494 | if (rec->evlist->mmap[i].base) { | 510 | for (i = 0; i < evlist->nr_mmaps; i++) { |
495 | if (record__mmap_read(rec, i) != 0) { | 511 | struct auxtrace_mmap *mm = &evlist->mmap[i].auxtrace_mmap; |
512 | |||
513 | if (evlist->mmap[i].base) { | ||
514 | if (record__mmap_read(rec, evlist, i) != 0) { | ||
496 | rc = -1; | 515 | rc = -1; |
497 | goto out; | 516 | goto out; |
498 | } | 517 | } |
@@ -516,6 +535,17 @@ out: | |||
516 | return rc; | 535 | return rc; |
517 | } | 536 | } |
518 | 537 | ||
538 | static int record__mmap_read_all(struct record *rec) | ||
539 | { | ||
540 | int err; | ||
541 | |||
542 | err = record__mmap_read_evlist(rec, rec->evlist); | ||
543 | if (err) | ||
544 | return err; | ||
545 | |||
546 | return err; | ||
547 | } | ||
548 | |||
519 | static void record__init_features(struct record *rec) | 549 | static void record__init_features(struct record *rec) |
520 | { | 550 | { |
521 | struct perf_session *session = rec->session; | 551 | struct perf_session *session = rec->session; |
@@ -656,10 +686,21 @@ perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused | |||
656 | return 0; | 686 | return 0; |
657 | } | 687 | } |
658 | 688 | ||
689 | static const struct perf_event_mmap_page * | ||
690 | perf_evlist__pick_pc(struct perf_evlist *evlist) | ||
691 | { | ||
692 | if (evlist && evlist->mmap && evlist->mmap[0].base) | ||
693 | return evlist->mmap[0].base; | ||
694 | return NULL; | ||
695 | } | ||
696 | |||
659 | static const struct perf_event_mmap_page *record__pick_pc(struct record *rec) | 697 | static const struct perf_event_mmap_page *record__pick_pc(struct record *rec) |
660 | { | 698 | { |
661 | if (rec->evlist && rec->evlist->mmap && rec->evlist->mmap[0].base) | 699 | const struct perf_event_mmap_page *pc; |
662 | return rec->evlist->mmap[0].base; | 700 | |
701 | pc = perf_evlist__pick_pc(rec->evlist); | ||
702 | if (pc) | ||
703 | return pc; | ||
663 | return NULL; | 704 | return NULL; |
664 | } | 705 | } |
665 | 706 | ||
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 534c81176f6c..bf1a0a0dd0ad 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -482,7 +482,7 @@ endif | |||
482 | 482 | ||
483 | ifndef NO_SLANG | 483 | ifndef NO_SLANG |
484 | ifneq ($(feature-libslang), 1) | 484 | ifneq ($(feature-libslang), 1) |
485 | msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); | 485 | msg := $(warning slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev); |
486 | NO_SLANG := 1 | 486 | NO_SLANG := 1 |
487 | else | 487 | else |
488 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h | 488 | # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h |
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index cac15d93aea6..51966d92fc82 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -81,6 +81,7 @@ make_no_libbionic := NO_LIBBIONIC=1 | |||
81 | make_no_auxtrace := NO_AUXTRACE=1 | 81 | make_no_auxtrace := NO_AUXTRACE=1 |
82 | make_no_libbpf := NO_LIBBPF=1 | 82 | make_no_libbpf := NO_LIBBPF=1 |
83 | make_no_libcrypto := NO_LIBCRYPTO=1 | 83 | make_no_libcrypto := NO_LIBCRYPTO=1 |
84 | make_with_babeltrace:= LIBBABELTRACE=1 | ||
84 | make_tags := tags | 85 | make_tags := tags |
85 | make_cscope := cscope | 86 | make_cscope := cscope |
86 | make_help := help | 87 | make_help := help |
@@ -136,6 +137,7 @@ run += make_no_libaudit | |||
136 | run += make_no_libbionic | 137 | run += make_no_libbionic |
137 | run += make_no_auxtrace | 138 | run += make_no_auxtrace |
138 | run += make_no_libbpf | 139 | run += make_no_libbpf |
140 | run += make_with_babeltrace | ||
139 | run += make_help | 141 | run += make_help |
140 | run += make_doc | 142 | run += make_doc |
141 | run += make_perf_o | 143 | run += make_perf_o |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 0e106bb97525..29dc6d20364e 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -223,16 +223,14 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
223 | } else if (ins__is_call(dl->ins)) { | 223 | } else if (ins__is_call(dl->ins)) { |
224 | ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); | 224 | ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); |
225 | SLsmg_write_char(' '); | 225 | SLsmg_write_char(' '); |
226 | } else if (ins__is_ret(dl->ins)) { | ||
227 | ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); | ||
228 | SLsmg_write_char(' '); | ||
226 | } else { | 229 | } else { |
227 | ui_browser__write_nstring(browser, " ", 2); | 230 | ui_browser__write_nstring(browser, " ", 2); |
228 | } | 231 | } |
229 | } else { | 232 | } else { |
230 | if (strcmp(dl->name, "retq")) { | 233 | ui_browser__write_nstring(browser, " ", 2); |
231 | ui_browser__write_nstring(browser, " ", 2); | ||
232 | } else { | ||
233 | ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); | ||
234 | SLsmg_write_char(' '); | ||
235 | } | ||
236 | } | 234 | } |
237 | 235 | ||
238 | disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); | 236 | disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); |
@@ -843,14 +841,14 @@ show_help: | |||
843 | ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); | 841 | ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); |
844 | else if (browser->selection->offset == -1) | 842 | else if (browser->selection->offset == -1) |
845 | ui_helpline__puts("Actions are only available for assembly lines."); | 843 | ui_helpline__puts("Actions are only available for assembly lines."); |
846 | else if (!browser->selection->ins) { | 844 | else if (!browser->selection->ins) |
847 | if (strcmp(browser->selection->name, "retq")) | 845 | goto show_sup_ins; |
848 | goto show_sup_ins; | 846 | else if (ins__is_ret(browser->selection->ins)) |
849 | goto out; | 847 | goto out; |
850 | } else if (!(annotate_browser__jump(browser) || | 848 | else if (!(annotate_browser__jump(browser) || |
851 | annotate_browser__callq(browser, evsel, hbt))) { | 849 | annotate_browser__callq(browser, evsel, hbt))) { |
852 | show_sup_ins: | 850 | show_sup_ins: |
853 | ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); | 851 | ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); |
854 | } | 852 | } |
855 | continue; | 853 | continue; |
856 | case 't': | 854 | case 't': |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7e5a1e8874ce..c385fecb9d32 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -354,6 +354,15 @@ static struct ins_ops nop_ops = { | |||
354 | .scnprintf = nop__scnprintf, | 354 | .scnprintf = nop__scnprintf, |
355 | }; | 355 | }; |
356 | 356 | ||
357 | static struct ins_ops ret_ops = { | ||
358 | .scnprintf = ins__raw_scnprintf, | ||
359 | }; | ||
360 | |||
361 | bool ins__is_ret(const struct ins *ins) | ||
362 | { | ||
363 | return ins->ops == &ret_ops; | ||
364 | } | ||
365 | |||
357 | static struct ins instructions[] = { | 366 | static struct ins instructions[] = { |
358 | { .name = "add", .ops = &mov_ops, }, | 367 | { .name = "add", .ops = &mov_ops, }, |
359 | { .name = "addl", .ops = &mov_ops, }, | 368 | { .name = "addl", .ops = &mov_ops, }, |
@@ -444,6 +453,7 @@ static struct ins instructions[] = { | |||
444 | { .name = "xadd", .ops = &mov_ops, }, | 453 | { .name = "xadd", .ops = &mov_ops, }, |
445 | { .name = "xbeginl", .ops = &jump_ops, }, | 454 | { .name = "xbeginl", .ops = &jump_ops, }, |
446 | { .name = "xbeginq", .ops = &jump_ops, }, | 455 | { .name = "xbeginq", .ops = &jump_ops, }, |
456 | { .name = "retq", .ops = &ret_ops, }, | ||
447 | }; | 457 | }; |
448 | 458 | ||
449 | static int ins__key_cmp(const void *name, const void *insp) | 459 | static int ins__key_cmp(const void *name, const void *insp) |
@@ -1676,11 +1686,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
1676 | return 0; | 1686 | return 0; |
1677 | } | 1687 | } |
1678 | 1688 | ||
1679 | int hist_entry__annotate(struct hist_entry *he, size_t privsize) | ||
1680 | { | ||
1681 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | ||
1682 | } | ||
1683 | |||
1684 | bool ui__has_annotation(void) | 1689 | bool ui__has_annotation(void) |
1685 | { | 1690 | { |
1686 | return use_browser == 1 && perf_hpp_list.sym; | 1691 | return use_browser == 1 && perf_hpp_list.sym; |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 9241f8c2b7e1..a23084f54128 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -48,6 +48,7 @@ struct ins { | |||
48 | 48 | ||
49 | bool ins__is_jump(const struct ins *ins); | 49 | bool ins__is_jump(const struct ins *ins); |
50 | bool ins__is_call(const struct ins *ins); | 50 | bool ins__is_call(const struct ins *ins); |
51 | bool ins__is_ret(const struct ins *ins); | ||
51 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); | 52 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); |
52 | 53 | ||
53 | struct annotation; | 54 | struct annotation; |
@@ -156,8 +157,6 @@ void symbol__annotate_zero_histograms(struct symbol *sym); | |||
156 | 157 | ||
157 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); | 158 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); |
158 | 159 | ||
159 | int hist_entry__annotate(struct hist_entry *he, size_t privsize); | ||
160 | |||
161 | int symbol__annotate_init(struct map *map, struct symbol *sym); | 160 | int symbol__annotate_init(struct map *map, struct symbol *sym); |
162 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 161 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
163 | struct perf_evsel *evsel, bool full_paths, | 162 | struct perf_evsel *evsel, bool full_paths, |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 4b59879391c0..4f979bb27b6c 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "evlist.h" | 26 | #include "evlist.h" |
27 | #include "evsel.h" | 27 | #include "evsel.h" |
28 | #include "machine.h" | 28 | #include "machine.h" |
29 | #include "config.h" | ||
29 | 30 | ||
30 | #define pr_N(n, fmt, ...) \ | 31 | #define pr_N(n, fmt, ...) \ |
31 | eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) | 32 | eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) |
@@ -68,6 +69,9 @@ struct ctf_writer { | |||
68 | }; | 69 | }; |
69 | struct bt_ctf_field_type *array[6]; | 70 | struct bt_ctf_field_type *array[6]; |
70 | } data; | 71 | } data; |
72 | struct bt_ctf_event_class *comm_class; | ||
73 | struct bt_ctf_event_class *exit_class; | ||
74 | struct bt_ctf_event_class *fork_class; | ||
71 | }; | 75 | }; |
72 | 76 | ||
73 | struct convert { | 77 | struct convert { |
@@ -76,6 +80,7 @@ struct convert { | |||
76 | 80 | ||
77 | u64 events_size; | 81 | u64 events_size; |
78 | u64 events_count; | 82 | u64 events_count; |
83 | u64 non_sample_count; | ||
79 | 84 | ||
80 | /* Ordered events configured queue size. */ | 85 | /* Ordered events configured queue size. */ |
81 | u64 queue_size; | 86 | u64 queue_size; |
@@ -140,6 +145,36 @@ FUNC_VALUE_SET(s64) | |||
140 | FUNC_VALUE_SET(u64) | 145 | FUNC_VALUE_SET(u64) |
141 | __FUNC_VALUE_SET(u64_hex, u64) | 146 | __FUNC_VALUE_SET(u64_hex, u64) |
142 | 147 | ||
148 | static int string_set_value(struct bt_ctf_field *field, const char *string); | ||
149 | static __maybe_unused int | ||
150 | value_set_string(struct ctf_writer *cw, struct bt_ctf_event *event, | ||
151 | const char *name, const char *string) | ||
152 | { | ||
153 | struct bt_ctf_field_type *type = cw->data.string; | ||
154 | struct bt_ctf_field *field; | ||
155 | int ret = 0; | ||
156 | |||
157 | field = bt_ctf_field_create(type); | ||
158 | if (!field) { | ||
159 | pr_err("failed to create a field %s\n", name); | ||
160 | return -1; | ||
161 | } | ||
162 | |||
163 | ret = string_set_value(field, string); | ||
164 | if (ret) { | ||
165 | pr_err("failed to set value %s\n", name); | ||
166 | goto err_put_field; | ||
167 | } | ||
168 | |||
169 | ret = bt_ctf_event_set_payload(event, name, field); | ||
170 | if (ret) | ||
171 | pr_err("failed to set payload %s\n", name); | ||
172 | |||
173 | err_put_field: | ||
174 | bt_ctf_field_put(field); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
143 | static struct bt_ctf_field_type* | 178 | static struct bt_ctf_field_type* |
144 | get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field) | 179 | get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field) |
145 | { | 180 | { |
@@ -731,6 +766,72 @@ static int process_sample_event(struct perf_tool *tool, | |||
731 | return cs ? 0 : -1; | 766 | return cs ? 0 : -1; |
732 | } | 767 | } |
733 | 768 | ||
769 | #define __NON_SAMPLE_SET_FIELD(_name, _type, _field) \ | ||
770 | do { \ | ||
771 | ret = value_set_##_type(cw, event, #_field, _event->_name._field);\ | ||
772 | if (ret) \ | ||
773 | return -1; \ | ||
774 | } while(0) | ||
775 | |||
776 | #define __FUNC_PROCESS_NON_SAMPLE(_name, body) \ | ||
777 | static int process_##_name##_event(struct perf_tool *tool, \ | ||
778 | union perf_event *_event, \ | ||
779 | struct perf_sample *sample, \ | ||
780 | struct machine *machine) \ | ||
781 | { \ | ||
782 | struct convert *c = container_of(tool, struct convert, tool);\ | ||
783 | struct ctf_writer *cw = &c->writer; \ | ||
784 | struct bt_ctf_event_class *event_class = cw->_name##_class;\ | ||
785 | struct bt_ctf_event *event; \ | ||
786 | struct ctf_stream *cs; \ | ||
787 | int ret; \ | ||
788 | \ | ||
789 | c->non_sample_count++; \ | ||
790 | c->events_size += _event->header.size; \ | ||
791 | event = bt_ctf_event_create(event_class); \ | ||
792 | if (!event) { \ | ||
793 | pr_err("Failed to create an CTF event\n"); \ | ||
794 | return -1; \ | ||
795 | } \ | ||
796 | \ | ||
797 | bt_ctf_clock_set_time(cw->clock, sample->time); \ | ||
798 | body \ | ||
799 | cs = ctf_stream(cw, 0); \ | ||
800 | if (cs) { \ | ||
801 | if (is_flush_needed(cs)) \ | ||
802 | ctf_stream__flush(cs); \ | ||
803 | \ | ||
804 | cs->count++; \ | ||
805 | bt_ctf_stream_append_event(cs->stream, event); \ | ||
806 | } \ | ||
807 | bt_ctf_event_put(event); \ | ||
808 | \ | ||
809 | return perf_event__process_##_name(tool, _event, sample, machine);\ | ||
810 | } | ||
811 | |||
812 | __FUNC_PROCESS_NON_SAMPLE(comm, | ||
813 | __NON_SAMPLE_SET_FIELD(comm, u32, pid); | ||
814 | __NON_SAMPLE_SET_FIELD(comm, u32, tid); | ||
815 | __NON_SAMPLE_SET_FIELD(comm, string, comm); | ||
816 | ) | ||
817 | __FUNC_PROCESS_NON_SAMPLE(fork, | ||
818 | __NON_SAMPLE_SET_FIELD(fork, u32, pid); | ||
819 | __NON_SAMPLE_SET_FIELD(fork, u32, ppid); | ||
820 | __NON_SAMPLE_SET_FIELD(fork, u32, tid); | ||
821 | __NON_SAMPLE_SET_FIELD(fork, u32, ptid); | ||
822 | __NON_SAMPLE_SET_FIELD(fork, u64, time); | ||
823 | ) | ||
824 | |||
825 | __FUNC_PROCESS_NON_SAMPLE(exit, | ||
826 | __NON_SAMPLE_SET_FIELD(fork, u32, pid); | ||
827 | __NON_SAMPLE_SET_FIELD(fork, u32, ppid); | ||
828 | __NON_SAMPLE_SET_FIELD(fork, u32, tid); | ||
829 | __NON_SAMPLE_SET_FIELD(fork, u32, ptid); | ||
830 | __NON_SAMPLE_SET_FIELD(fork, u64, time); | ||
831 | ) | ||
832 | #undef __NON_SAMPLE_SET_FIELD | ||
833 | #undef __FUNC_PROCESS_NON_SAMPLE | ||
834 | |||
734 | /* If dup < 0, add a prefix. Else, add _dupl_X suffix. */ | 835 | /* If dup < 0, add a prefix. Else, add _dupl_X suffix. */ |
735 | static char *change_name(char *name, char *orig_name, int dup) | 836 | static char *change_name(char *name, char *orig_name, int dup) |
736 | { | 837 | { |
@@ -1005,6 +1106,80 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session) | |||
1005 | return 0; | 1106 | return 0; |
1006 | } | 1107 | } |
1007 | 1108 | ||
1109 | #define __NON_SAMPLE_ADD_FIELD(t, n) \ | ||
1110 | do { \ | ||
1111 | pr2(" field '%s'\n", #n); \ | ||
1112 | if (bt_ctf_event_class_add_field(event_class, cw->data.t, #n)) {\ | ||
1113 | pr_err("Failed to add field '%s';\n", #n);\ | ||
1114 | return -1; \ | ||
1115 | } \ | ||
1116 | } while(0) | ||
1117 | |||
1118 | #define __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(_name, body) \ | ||
1119 | static int add_##_name##_event(struct ctf_writer *cw) \ | ||
1120 | { \ | ||
1121 | struct bt_ctf_event_class *event_class; \ | ||
1122 | int ret; \ | ||
1123 | \ | ||
1124 | pr("Adding "#_name" event\n"); \ | ||
1125 | event_class = bt_ctf_event_class_create("perf_" #_name);\ | ||
1126 | if (!event_class) \ | ||
1127 | return -1; \ | ||
1128 | body \ | ||
1129 | \ | ||
1130 | ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);\ | ||
1131 | if (ret) { \ | ||
1132 | pr("Failed to add event class '"#_name"' into stream.\n");\ | ||
1133 | return ret; \ | ||
1134 | } \ | ||
1135 | \ | ||
1136 | cw->_name##_class = event_class; \ | ||
1137 | bt_ctf_event_class_put(event_class); \ | ||
1138 | return 0; \ | ||
1139 | } | ||
1140 | |||
1141 | __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(comm, | ||
1142 | __NON_SAMPLE_ADD_FIELD(u32, pid); | ||
1143 | __NON_SAMPLE_ADD_FIELD(u32, tid); | ||
1144 | __NON_SAMPLE_ADD_FIELD(string, comm); | ||
1145 | ) | ||
1146 | |||
1147 | __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(fork, | ||
1148 | __NON_SAMPLE_ADD_FIELD(u32, pid); | ||
1149 | __NON_SAMPLE_ADD_FIELD(u32, ppid); | ||
1150 | __NON_SAMPLE_ADD_FIELD(u32, tid); | ||
1151 | __NON_SAMPLE_ADD_FIELD(u32, ptid); | ||
1152 | __NON_SAMPLE_ADD_FIELD(u64, time); | ||
1153 | ) | ||
1154 | |||
1155 | __FUNC_ADD_NON_SAMPLE_EVENT_CLASS(exit, | ||
1156 | __NON_SAMPLE_ADD_FIELD(u32, pid); | ||
1157 | __NON_SAMPLE_ADD_FIELD(u32, ppid); | ||
1158 | __NON_SAMPLE_ADD_FIELD(u32, tid); | ||
1159 | __NON_SAMPLE_ADD_FIELD(u32, ptid); | ||
1160 | __NON_SAMPLE_ADD_FIELD(u64, time); | ||
1161 | ) | ||
1162 | |||
1163 | #undef __NON_SAMPLE_ADD_FIELD | ||
1164 | #undef __FUNC_ADD_NON_SAMPLE_EVENT_CLASS | ||
1165 | |||
1166 | static int setup_non_sample_events(struct ctf_writer *cw, | ||
1167 | struct perf_session *session __maybe_unused) | ||
1168 | { | ||
1169 | int ret; | ||
1170 | |||
1171 | ret = add_comm_event(cw); | ||
1172 | if (ret) | ||
1173 | return ret; | ||
1174 | ret = add_exit_event(cw); | ||
1175 | if (ret) | ||
1176 | return ret; | ||
1177 | ret = add_fork_event(cw); | ||
1178 | if (ret) | ||
1179 | return ret; | ||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1008 | static void cleanup_events(struct perf_session *session) | 1183 | static void cleanup_events(struct perf_session *session) |
1009 | { | 1184 | { |
1010 | struct perf_evlist *evlist = session->evlist; | 1185 | struct perf_evlist *evlist = session->evlist; |
@@ -1273,13 +1448,14 @@ static int convert__config(const char *var, const char *value, void *cb) | |||
1273 | return 0; | 1448 | return 0; |
1274 | } | 1449 | } |
1275 | 1450 | ||
1276 | int bt_convert__perf2ctf(const char *input, const char *path, bool force) | 1451 | int bt_convert__perf2ctf(const char *input, const char *path, |
1452 | struct perf_data_convert_opts *opts) | ||
1277 | { | 1453 | { |
1278 | struct perf_session *session; | 1454 | struct perf_session *session; |
1279 | struct perf_data_file file = { | 1455 | struct perf_data_file file = { |
1280 | .path = input, | 1456 | .path = input, |
1281 | .mode = PERF_DATA_MODE_READ, | 1457 | .mode = PERF_DATA_MODE_READ, |
1282 | .force = force, | 1458 | .force = opts->force, |
1283 | }; | 1459 | }; |
1284 | struct convert c = { | 1460 | struct convert c = { |
1285 | .tool = { | 1461 | .tool = { |
@@ -1299,6 +1475,12 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) | |||
1299 | struct ctf_writer *cw = &c.writer; | 1475 | struct ctf_writer *cw = &c.writer; |
1300 | int err = -1; | 1476 | int err = -1; |
1301 | 1477 | ||
1478 | if (opts->all) { | ||
1479 | c.tool.comm = process_comm_event; | ||
1480 | c.tool.exit = process_exit_event; | ||
1481 | c.tool.fork = process_fork_event; | ||
1482 | } | ||
1483 | |||
1302 | perf_config(convert__config, &c); | 1484 | perf_config(convert__config, &c); |
1303 | 1485 | ||
1304 | /* CTF writer */ | 1486 | /* CTF writer */ |
@@ -1323,6 +1505,9 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) | |||
1323 | if (setup_events(cw, session)) | 1505 | if (setup_events(cw, session)) |
1324 | goto free_session; | 1506 | goto free_session; |
1325 | 1507 | ||
1508 | if (opts->all && setup_non_sample_events(cw, session)) | ||
1509 | goto free_session; | ||
1510 | |||
1326 | if (setup_streams(cw, session)) | 1511 | if (setup_streams(cw, session)) |
1327 | goto free_session; | 1512 | goto free_session; |
1328 | 1513 | ||
@@ -1337,10 +1522,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) | |||
1337 | file.path, path); | 1522 | file.path, path); |
1338 | 1523 | ||
1339 | fprintf(stderr, | 1524 | fprintf(stderr, |
1340 | "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n", | 1525 | "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples", |
1341 | (double) c.events_size / 1024.0 / 1024.0, | 1526 | (double) c.events_size / 1024.0 / 1024.0, |
1342 | c.events_count); | 1527 | c.events_count); |
1343 | 1528 | ||
1529 | if (!c.non_sample_count) | ||
1530 | fprintf(stderr, ") ]\n"); | ||
1531 | else | ||
1532 | fprintf(stderr, ", %" PRIu64 " non-samples) ]\n", c.non_sample_count); | ||
1533 | |||
1344 | cleanup_events(session); | 1534 | cleanup_events(session); |
1345 | perf_session__delete(session); | 1535 | perf_session__delete(session); |
1346 | ctf_writer__cleanup(cw); | 1536 | ctf_writer__cleanup(cw); |
diff --git a/tools/perf/util/data-convert-bt.h b/tools/perf/util/data-convert-bt.h index 4c204342a9d8..9a3b587f76c1 100644 --- a/tools/perf/util/data-convert-bt.h +++ b/tools/perf/util/data-convert-bt.h | |||
@@ -1,8 +1,10 @@ | |||
1 | #ifndef __DATA_CONVERT_BT_H | 1 | #ifndef __DATA_CONVERT_BT_H |
2 | #define __DATA_CONVERT_BT_H | 2 | #define __DATA_CONVERT_BT_H |
3 | #include "data-convert.h" | ||
3 | #ifdef HAVE_LIBBABELTRACE_SUPPORT | 4 | #ifdef HAVE_LIBBABELTRACE_SUPPORT |
4 | 5 | ||
5 | int bt_convert__perf2ctf(const char *input_name, const char *to_ctf, bool force); | 6 | int bt_convert__perf2ctf(const char *input_name, const char *to_ctf, |
7 | struct perf_data_convert_opts *opts); | ||
6 | 8 | ||
7 | #endif /* HAVE_LIBBABELTRACE_SUPPORT */ | 9 | #endif /* HAVE_LIBBABELTRACE_SUPPORT */ |
8 | #endif /* __DATA_CONVERT_BT_H */ | 10 | #endif /* __DATA_CONVERT_BT_H */ |
diff --git a/tools/perf/util/data-convert.h b/tools/perf/util/data-convert.h new file mode 100644 index 000000000000..5314962fe95b --- /dev/null +++ b/tools/perf/util/data-convert.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef __DATA_CONVERT_H | ||
2 | #define __DATA_CONVERT_H | ||
3 | |||
4 | struct perf_data_convert_opts { | ||
5 | bool force; | ||
6 | bool all; | ||
7 | }; | ||
8 | |||
9 | #endif /* __DATA_CONVERT_H */ | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b044f1a32d16..37e8d20ae03e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1430,7 +1430,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1430 | * Read the build id if possible. This is required for | 1430 | * Read the build id if possible. This is required for |
1431 | * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work | 1431 | * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work |
1432 | */ | 1432 | */ |
1433 | if (is_regular_file(name) && | 1433 | if (is_regular_file(dso->long_name) && |
1434 | filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) | 1434 | filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) |
1435 | dso__set_build_id(dso, build_id); | 1435 | dso__set_build_id(dso, build_id); |
1436 | 1436 | ||