diff options
author | Michal Marek <mmarek@suse.cz> | 2013-02-25 15:50:05 -0500 |
---|---|---|
committer | Michal Marek <mmarek@suse.cz> | 2013-02-25 15:51:57 -0500 |
commit | e3900e74f26fc924c8e9e2a922bd40369b0bb517 (patch) | |
tree | 6e868575d346032ba9408f350c6e5369e0e52b0d /tools/perf/util | |
parent | 62dc989921df2a98d1a73aacd085abe941cb9828 (diff) | |
parent | 02f3e53a131c8aa3fe3c954058f1add5beeae621 (diff) |
Merge branch 'kbuild/rc-fixes' into kbuild/kconfig
There is one kconfig fix in the rc-fixes branch that I forgot to submit
for 3.8, so let's add it to the kconfig branch for 3.9-rc1.
Diffstat (limited to 'tools/perf/util')
48 files changed, 1985 insertions, 2908 deletions
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN index 95264f304179..6aa34e5afdcf 100755 --- a/tools/perf/util/PERF-VERSION-GEN +++ b/tools/perf/util/PERF-VERSION-GEN | |||
@@ -9,18 +9,14 @@ GVF=${OUTPUT}PERF-VERSION-FILE | |||
9 | LF=' | 9 | LF=' |
10 | ' | 10 | ' |
11 | 11 | ||
12 | # | ||
12 | # First check if there is a .git to get the version from git describe | 13 | # First check if there is a .git to get the version from git describe |
13 | # otherwise try to get the version from the kernel makefile | 14 | # otherwise try to get the version from the kernel Makefile |
15 | # | ||
14 | if test -d ../../.git -o -f ../../.git && | 16 | if test -d ../../.git -o -f ../../.git && |
15 | VN=$(git describe --match 'v[0-9].[0-9]*' --abbrev=4 HEAD 2>/dev/null) && | 17 | VN=$(git tag 2>/dev/null | tail -1 | grep -E "v[0-9].[0-9]*") |
16 | case "$VN" in | ||
17 | *$LF*) (exit 1) ;; | ||
18 | v[0-9]*) | ||
19 | git update-index -q --refresh | ||
20 | test -z "$(git diff-index --name-only HEAD --)" || | ||
21 | VN="$VN-dirty" ;; | ||
22 | esac | ||
23 | then | 18 | then |
19 | VN=$(echo $VN"-g"$(git log -1 --abbrev=4 --pretty=format:"%h" HEAD)) | ||
24 | VN=$(echo "$VN" | sed -e 's/-/./g'); | 20 | VN=$(echo "$VN" | sed -e 's/-/./g'); |
25 | else | 21 | else |
26 | VN=$(MAKEFLAGS= make -sC ../.. kernelversion) | 22 | VN=$(MAKEFLAGS= make -sC ../.. kernelversion) |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f0a910371377..07aaeea60000 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "debug.h" | 15 | #include "debug.h" |
16 | #include "annotate.h" | 16 | #include "annotate.h" |
17 | #include <pthread.h> | 17 | #include <pthread.h> |
18 | #include <linux/bitops.h> | ||
18 | 19 | ||
19 | const char *disassembler_style; | 20 | const char *disassembler_style; |
20 | const char *objdump_path; | 21 | const char *objdump_path; |
@@ -170,15 +171,15 @@ static int lock__parse(struct ins_operands *ops) | |||
170 | if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) | 171 | if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) |
171 | goto out_free_ops; | 172 | goto out_free_ops; |
172 | 173 | ||
173 | ops->locked.ins = ins__find(name); | 174 | ops->locked.ins = ins__find(name); |
174 | if (ops->locked.ins == NULL) | 175 | if (ops->locked.ins == NULL) |
175 | goto out_free_ops; | 176 | goto out_free_ops; |
176 | 177 | ||
177 | if (!ops->locked.ins->ops) | 178 | if (!ops->locked.ins->ops) |
178 | return 0; | 179 | return 0; |
179 | 180 | ||
180 | if (ops->locked.ins->ops->parse) | 181 | if (ops->locked.ins->ops->parse) |
181 | ops->locked.ins->ops->parse(ops->locked.ops); | 182 | ops->locked.ins->ops->parse(ops->locked.ops); |
182 | 183 | ||
183 | return 0; | 184 | return 0; |
184 | 185 | ||
@@ -400,6 +401,8 @@ static struct ins instructions[] = { | |||
400 | { .name = "testb", .ops = &mov_ops, }, | 401 | { .name = "testb", .ops = &mov_ops, }, |
401 | { .name = "testl", .ops = &mov_ops, }, | 402 | { .name = "testl", .ops = &mov_ops, }, |
402 | { .name = "xadd", .ops = &mov_ops, }, | 403 | { .name = "xadd", .ops = &mov_ops, }, |
404 | { .name = "xbeginl", .ops = &jump_ops, }, | ||
405 | { .name = "xbeginq", .ops = &jump_ops, }, | ||
403 | }; | 406 | }; |
404 | 407 | ||
405 | static int ins__cmp(const void *name, const void *insp) | 408 | static int ins__cmp(const void *name, const void *insp) |
@@ -855,21 +858,68 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
855 | struct source_line *iter; | 858 | struct source_line *iter; |
856 | struct rb_node **p = &root->rb_node; | 859 | struct rb_node **p = &root->rb_node; |
857 | struct rb_node *parent = NULL; | 860 | struct rb_node *parent = NULL; |
861 | int ret; | ||
858 | 862 | ||
859 | while (*p != NULL) { | 863 | while (*p != NULL) { |
860 | parent = *p; | 864 | parent = *p; |
861 | iter = rb_entry(parent, struct source_line, node); | 865 | iter = rb_entry(parent, struct source_line, node); |
862 | 866 | ||
863 | if (src_line->percent > iter->percent) | 867 | ret = strcmp(iter->path, src_line->path); |
868 | if (ret == 0) { | ||
869 | iter->percent_sum += src_line->percent; | ||
870 | return; | ||
871 | } | ||
872 | |||
873 | if (ret < 0) | ||
864 | p = &(*p)->rb_left; | 874 | p = &(*p)->rb_left; |
865 | else | 875 | else |
866 | p = &(*p)->rb_right; | 876 | p = &(*p)->rb_right; |
867 | } | 877 | } |
868 | 878 | ||
879 | src_line->percent_sum = src_line->percent; | ||
880 | |||
869 | rb_link_node(&src_line->node, parent, p); | 881 | rb_link_node(&src_line->node, parent, p); |
870 | rb_insert_color(&src_line->node, root); | 882 | rb_insert_color(&src_line->node, root); |
871 | } | 883 | } |
872 | 884 | ||
885 | static void __resort_source_line(struct rb_root *root, struct source_line *src_line) | ||
886 | { | ||
887 | struct source_line *iter; | ||
888 | struct rb_node **p = &root->rb_node; | ||
889 | struct rb_node *parent = NULL; | ||
890 | |||
891 | while (*p != NULL) { | ||
892 | parent = *p; | ||
893 | iter = rb_entry(parent, struct source_line, node); | ||
894 | |||
895 | if (src_line->percent_sum > iter->percent_sum) | ||
896 | p = &(*p)->rb_left; | ||
897 | else | ||
898 | p = &(*p)->rb_right; | ||
899 | } | ||
900 | |||
901 | rb_link_node(&src_line->node, parent, p); | ||
902 | rb_insert_color(&src_line->node, root); | ||
903 | } | ||
904 | |||
905 | static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root) | ||
906 | { | ||
907 | struct source_line *src_line; | ||
908 | struct rb_node *node; | ||
909 | |||
910 | node = rb_first(src_root); | ||
911 | while (node) { | ||
912 | struct rb_node *next; | ||
913 | |||
914 | src_line = rb_entry(node, struct source_line, node); | ||
915 | next = rb_next(node); | ||
916 | rb_erase(node, src_root); | ||
917 | |||
918 | __resort_source_line(dest_root, src_line); | ||
919 | node = next; | ||
920 | } | ||
921 | } | ||
922 | |||
873 | static void symbol__free_source_line(struct symbol *sym, int len) | 923 | static void symbol__free_source_line(struct symbol *sym, int len) |
874 | { | 924 | { |
875 | struct annotation *notes = symbol__annotation(sym); | 925 | struct annotation *notes = symbol__annotation(sym); |
@@ -894,6 +944,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
894 | struct source_line *src_line; | 944 | struct source_line *src_line; |
895 | struct annotation *notes = symbol__annotation(sym); | 945 | struct annotation *notes = symbol__annotation(sym); |
896 | struct sym_hist *h = annotation__histogram(notes, evidx); | 946 | struct sym_hist *h = annotation__histogram(notes, evidx); |
947 | struct rb_root tmp_root = RB_ROOT; | ||
897 | 948 | ||
898 | if (!h->sum) | 949 | if (!h->sum) |
899 | return 0; | 950 | return 0; |
@@ -928,12 +979,13 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
928 | goto next; | 979 | goto next; |
929 | 980 | ||
930 | strcpy(src_line[i].path, path); | 981 | strcpy(src_line[i].path, path); |
931 | insert_source_line(root, &src_line[i]); | 982 | insert_source_line(&tmp_root, &src_line[i]); |
932 | 983 | ||
933 | next: | 984 | next: |
934 | pclose(fp); | 985 | pclose(fp); |
935 | } | 986 | } |
936 | 987 | ||
988 | resort_source_line(root, &tmp_root); | ||
937 | return 0; | 989 | return 0; |
938 | } | 990 | } |
939 | 991 | ||
@@ -957,7 +1009,7 @@ static void print_summary(struct rb_root *root, const char *filename) | |||
957 | char *path; | 1009 | char *path; |
958 | 1010 | ||
959 | src_line = rb_entry(node, struct source_line, node); | 1011 | src_line = rb_entry(node, struct source_line, node); |
960 | percent = src_line->percent; | 1012 | percent = src_line->percent_sum; |
961 | color = get_percent_color(percent); | 1013 | color = get_percent_color(percent); |
962 | path = src_line->path; | 1014 | path = src_line->path; |
963 | 1015 | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 39242dcee8f2..8eec94358a4a 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <stdint.h> | 5 | #include <stdint.h> |
6 | #include "types.h" | 6 | #include "types.h" |
7 | #include "symbol.h" | 7 | #include "symbol.h" |
8 | #include "hist.h" | ||
8 | #include <linux/list.h> | 9 | #include <linux/list.h> |
9 | #include <linux/rbtree.h> | 10 | #include <linux/rbtree.h> |
10 | #include <pthread.h> | 11 | #include <pthread.h> |
@@ -75,6 +76,7 @@ struct sym_hist { | |||
75 | struct source_line { | 76 | struct source_line { |
76 | struct rb_node node; | 77 | struct rb_node node; |
77 | double percent; | 78 | double percent; |
79 | double percent_sum; | ||
78 | char *path; | 80 | char *path; |
79 | }; | 81 | }; |
80 | 82 | ||
@@ -140,20 +142,18 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
140 | 142 | ||
141 | #ifdef NEWT_SUPPORT | 143 | #ifdef NEWT_SUPPORT |
142 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 144 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, |
143 | void(*timer)(void *arg), void *arg, int delay_secs); | 145 | struct hist_browser_timer *hbt); |
144 | #else | 146 | #else |
145 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | 147 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, |
146 | struct map *map __maybe_unused, | 148 | struct map *map __maybe_unused, |
147 | int evidx __maybe_unused, | 149 | int evidx __maybe_unused, |
148 | void(*timer)(void *arg) __maybe_unused, | 150 | struct hist_browser_timer *hbt |
149 | void *arg __maybe_unused, | 151 | __maybe_unused) |
150 | int delay_secs __maybe_unused) | ||
151 | { | 152 | { |
152 | return 0; | 153 | return 0; |
153 | } | 154 | } |
154 | #endif | 155 | #endif |
155 | 156 | ||
156 | extern const char *disassembler_style; | 157 | extern const char *disassembler_style; |
157 | extern const char *objdump_path; | ||
158 | 158 | ||
159 | #endif /* __PERF_ANNOTATE_H */ | 159 | #endif /* __PERF_ANNOTATE_H */ |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 8e3a740ddbd4..5295625c0c00 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -16,11 +16,11 @@ | |||
16 | #include "session.h" | 16 | #include "session.h" |
17 | #include "tool.h" | 17 | #include "tool.h" |
18 | 18 | ||
19 | static int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, | 19 | int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, |
20 | union perf_event *event, | 20 | union perf_event *event, |
21 | struct perf_sample *sample __maybe_unused, | 21 | struct perf_sample *sample __maybe_unused, |
22 | struct perf_evsel *evsel __maybe_unused, | 22 | struct perf_evsel *evsel __maybe_unused, |
23 | struct machine *machine) | 23 | struct machine *machine) |
24 | { | 24 | { |
25 | struct addr_location al; | 25 | struct addr_location al; |
26 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 26 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
@@ -64,12 +64,27 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, | |||
64 | struct perf_tool build_id__mark_dso_hit_ops = { | 64 | struct perf_tool build_id__mark_dso_hit_ops = { |
65 | .sample = build_id__mark_dso_hit, | 65 | .sample = build_id__mark_dso_hit, |
66 | .mmap = perf_event__process_mmap, | 66 | .mmap = perf_event__process_mmap, |
67 | .fork = perf_event__process_task, | 67 | .fork = perf_event__process_fork, |
68 | .exit = perf_event__exit_del_thread, | 68 | .exit = perf_event__exit_del_thread, |
69 | .attr = perf_event__process_attr, | 69 | .attr = perf_event__process_attr, |
70 | .build_id = perf_event__process_build_id, | 70 | .build_id = perf_event__process_build_id, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | int build_id__sprintf(const u8 *build_id, int len, char *bf) | ||
74 | { | ||
75 | char *bid = bf; | ||
76 | const u8 *raw = build_id; | ||
77 | int i; | ||
78 | |||
79 | for (i = 0; i < len; ++i) { | ||
80 | sprintf(bid, "%02x", *raw); | ||
81 | ++raw; | ||
82 | bid += 2; | ||
83 | } | ||
84 | |||
85 | return raw - build_id; | ||
86 | } | ||
87 | |||
73 | char *dso__build_id_filename(struct dso *self, char *bf, size_t size) | 88 | char *dso__build_id_filename(struct dso *self, char *bf, size_t size) |
74 | { | 89 | { |
75 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 90 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index a993ba87d996..a811f5c62e18 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h | |||
@@ -1,10 +1,19 @@ | |||
1 | #ifndef PERF_BUILD_ID_H_ | 1 | #ifndef PERF_BUILD_ID_H_ |
2 | #define PERF_BUILD_ID_H_ 1 | 2 | #define PERF_BUILD_ID_H_ 1 |
3 | 3 | ||
4 | #include "session.h" | 4 | #define BUILD_ID_SIZE 20 |
5 | |||
6 | #include "tool.h" | ||
7 | #include "types.h" | ||
5 | 8 | ||
6 | extern struct perf_tool build_id__mark_dso_hit_ops; | 9 | extern struct perf_tool build_id__mark_dso_hit_ops; |
10 | struct dso; | ||
7 | 11 | ||
12 | int build_id__sprintf(const u8 *build_id, int len, char *bf); | ||
8 | char *dso__build_id_filename(struct dso *self, char *bf, size_t size); | 13 | char *dso__build_id_filename(struct dso *self, char *bf, size_t size); |
9 | 14 | ||
15 | int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, | ||
16 | struct perf_sample *sample, struct perf_evsel *evsel, | ||
17 | struct machine *machine); | ||
18 | |||
10 | #endif | 19 | #endif |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 2bd51370ad28..26e367239873 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "util.h" | 5 | #include "util.h" |
6 | #include "strbuf.h" | 6 | #include "strbuf.h" |
7 | #include "../perf.h" | 7 | #include "../perf.h" |
8 | #include "../ui/ui.h" | ||
8 | 9 | ||
9 | #define CMD_EXEC_PATH "--exec-path" | 10 | #define CMD_EXEC_PATH "--exec-path" |
10 | #define CMD_PERF_DIR "--perf-dir=" | 11 | #define CMD_PERF_DIR "--perf-dir=" |
@@ -31,44 +32,6 @@ extern const char *pager_program; | |||
31 | extern int pager_in_use(void); | 32 | extern int pager_in_use(void); |
32 | extern int pager_use_color; | 33 | extern int pager_use_color; |
33 | 34 | ||
34 | extern int use_browser; | ||
35 | |||
36 | #if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) | ||
37 | void setup_browser(bool fallback_to_pager); | ||
38 | void exit_browser(bool wait_for_ok); | ||
39 | |||
40 | #ifdef NEWT_SUPPORT | ||
41 | int ui__init(void); | ||
42 | void ui__exit(bool wait_for_ok); | ||
43 | #else | ||
44 | static inline int ui__init(void) | ||
45 | { | ||
46 | return -1; | ||
47 | } | ||
48 | static inline void ui__exit(bool wait_for_ok __maybe_unused) {} | ||
49 | #endif | ||
50 | |||
51 | #ifdef GTK2_SUPPORT | ||
52 | int perf_gtk__init(void); | ||
53 | void perf_gtk__exit(bool wait_for_ok); | ||
54 | #else | ||
55 | static inline int perf_gtk__init(void) | ||
56 | { | ||
57 | return -1; | ||
58 | } | ||
59 | static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {} | ||
60 | #endif | ||
61 | |||
62 | #else /* NEWT_SUPPORT || GTK2_SUPPORT */ | ||
63 | |||
64 | static inline void setup_browser(bool fallback_to_pager) | ||
65 | { | ||
66 | if (fallback_to_pager) | ||
67 | setup_pager(); | ||
68 | } | ||
69 | static inline void exit_browser(bool wait_for_ok __maybe_unused) {} | ||
70 | #endif /* NEWT_SUPPORT || GTK2_SUPPORT */ | ||
71 | |||
72 | char *alias_lookup(const char *alias); | 35 | char *alias_lookup(const char *alias); |
73 | int split_cmdline(char *cmdline, const char ***argv); | 36 | int split_cmdline(char *cmdline, const char ***argv); |
74 | 37 | ||
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index dec98750b484..83e8d234af6b 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -26,6 +26,7 @@ int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | |||
26 | static inline void ui_progress__update(u64 curr __maybe_unused, | 26 | static inline void ui_progress__update(u64 curr __maybe_unused, |
27 | u64 total __maybe_unused, | 27 | u64 total __maybe_unused, |
28 | const char *title __maybe_unused) {} | 28 | const char *title __maybe_unused) {} |
29 | static inline void ui_progress__finish(void) {} | ||
29 | 30 | ||
30 | #define ui__error(format, arg...) ui__warning(format, ##arg) | 31 | #define ui__error(format, arg...) ui__warning(format, ##arg) |
31 | 32 | ||
diff --git a/tools/perf/util/dso-test-data.c b/tools/perf/util/dso-test-data.c deleted file mode 100644 index c6caedeb1d6b..000000000000 --- a/tools/perf/util/dso-test-data.c +++ /dev/null | |||
@@ -1,153 +0,0 @@ | |||
1 | #include "util.h" | ||
2 | |||
3 | #include <stdlib.h> | ||
4 | #include <sys/types.h> | ||
5 | #include <sys/stat.h> | ||
6 | #include <fcntl.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #include "symbol.h" | ||
10 | |||
11 | #define TEST_ASSERT_VAL(text, cond) \ | ||
12 | do { \ | ||
13 | if (!(cond)) { \ | ||
14 | pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ | ||
15 | return -1; \ | ||
16 | } \ | ||
17 | } while (0) | ||
18 | |||
19 | static char *test_file(int size) | ||
20 | { | ||
21 | static char buf_templ[] = "/tmp/test-XXXXXX"; | ||
22 | char *templ = buf_templ; | ||
23 | int fd, i; | ||
24 | unsigned char *buf; | ||
25 | |||
26 | fd = mkstemp(templ); | ||
27 | |||
28 | buf = malloc(size); | ||
29 | if (!buf) { | ||
30 | close(fd); | ||
31 | return NULL; | ||
32 | } | ||
33 | |||
34 | for (i = 0; i < size; i++) | ||
35 | buf[i] = (unsigned char) ((int) i % 10); | ||
36 | |||
37 | if (size != write(fd, buf, size)) | ||
38 | templ = NULL; | ||
39 | |||
40 | close(fd); | ||
41 | return templ; | ||
42 | } | ||
43 | |||
44 | #define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20) | ||
45 | |||
46 | struct test_data_offset { | ||
47 | off_t offset; | ||
48 | u8 data[10]; | ||
49 | int size; | ||
50 | }; | ||
51 | |||
52 | struct test_data_offset offsets[] = { | ||
53 | /* Fill first cache page. */ | ||
54 | { | ||
55 | .offset = 10, | ||
56 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
57 | .size = 10, | ||
58 | }, | ||
59 | /* Read first cache page. */ | ||
60 | { | ||
61 | .offset = 10, | ||
62 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
63 | .size = 10, | ||
64 | }, | ||
65 | /* Fill cache boundary pages. */ | ||
66 | { | ||
67 | .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10, | ||
68 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
69 | .size = 10, | ||
70 | }, | ||
71 | /* Read cache boundary pages. */ | ||
72 | { | ||
73 | .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10, | ||
74 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
75 | .size = 10, | ||
76 | }, | ||
77 | /* Fill final cache page. */ | ||
78 | { | ||
79 | .offset = TEST_FILE_SIZE - 10, | ||
80 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
81 | .size = 10, | ||
82 | }, | ||
83 | /* Read final cache page. */ | ||
84 | { | ||
85 | .offset = TEST_FILE_SIZE - 10, | ||
86 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
87 | .size = 10, | ||
88 | }, | ||
89 | /* Read final cache page. */ | ||
90 | { | ||
91 | .offset = TEST_FILE_SIZE - 3, | ||
92 | .data = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 }, | ||
93 | .size = 3, | ||
94 | }, | ||
95 | }; | ||
96 | |||
97 | int dso__test_data(void) | ||
98 | { | ||
99 | struct machine machine; | ||
100 | struct dso *dso; | ||
101 | char *file = test_file(TEST_FILE_SIZE); | ||
102 | size_t i; | ||
103 | |||
104 | TEST_ASSERT_VAL("No test file", file); | ||
105 | |||
106 | memset(&machine, 0, sizeof(machine)); | ||
107 | |||
108 | dso = dso__new((const char *)file); | ||
109 | |||
110 | /* Basic 10 bytes tests. */ | ||
111 | for (i = 0; i < ARRAY_SIZE(offsets); i++) { | ||
112 | struct test_data_offset *data = &offsets[i]; | ||
113 | ssize_t size; | ||
114 | u8 buf[10]; | ||
115 | |||
116 | memset(buf, 0, 10); | ||
117 | size = dso__data_read_offset(dso, &machine, data->offset, | ||
118 | buf, 10); | ||
119 | |||
120 | TEST_ASSERT_VAL("Wrong size", size == data->size); | ||
121 | TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10)); | ||
122 | } | ||
123 | |||
124 | /* Read cross multiple cache pages. */ | ||
125 | { | ||
126 | ssize_t size; | ||
127 | int c; | ||
128 | u8 *buf; | ||
129 | |||
130 | buf = malloc(TEST_FILE_SIZE); | ||
131 | TEST_ASSERT_VAL("ENOMEM\n", buf); | ||
132 | |||
133 | /* First iteration to fill caches, second one to read them. */ | ||
134 | for (c = 0; c < 2; c++) { | ||
135 | memset(buf, 0, TEST_FILE_SIZE); | ||
136 | size = dso__data_read_offset(dso, &machine, 10, | ||
137 | buf, TEST_FILE_SIZE); | ||
138 | |||
139 | TEST_ASSERT_VAL("Wrong size", | ||
140 | size == (TEST_FILE_SIZE - 10)); | ||
141 | |||
142 | for (i = 0; i < (size_t)size; i++) | ||
143 | TEST_ASSERT_VAL("Wrong data", | ||
144 | buf[i] == (i % 10)); | ||
145 | } | ||
146 | |||
147 | free(buf); | ||
148 | } | ||
149 | |||
150 | dso__delete(dso); | ||
151 | unlink(file); | ||
152 | return 0; | ||
153 | } | ||
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c new file mode 100644 index 000000000000..d6d9a465acdb --- /dev/null +++ b/tools/perf/util/dso.c | |||
@@ -0,0 +1,595 @@ | |||
1 | #include "symbol.h" | ||
2 | #include "dso.h" | ||
3 | #include "machine.h" | ||
4 | #include "util.h" | ||
5 | #include "debug.h" | ||
6 | |||
7 | char dso__symtab_origin(const struct dso *dso) | ||
8 | { | ||
9 | static const char origin[] = { | ||
10 | [DSO_BINARY_TYPE__KALLSYMS] = 'k', | ||
11 | [DSO_BINARY_TYPE__VMLINUX] = 'v', | ||
12 | [DSO_BINARY_TYPE__JAVA_JIT] = 'j', | ||
13 | [DSO_BINARY_TYPE__DEBUGLINK] = 'l', | ||
14 | [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', | ||
15 | [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', | ||
16 | [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', | ||
17 | [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', | ||
18 | [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', | ||
19 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', | ||
20 | [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', | ||
21 | [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', | ||
22 | [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', | ||
23 | }; | ||
24 | |||
25 | if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) | ||
26 | return '!'; | ||
27 | return origin[dso->symtab_type]; | ||
28 | } | ||
29 | |||
30 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | ||
31 | char *root_dir, char *file, size_t size) | ||
32 | { | ||
33 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | ||
34 | int ret = 0; | ||
35 | |||
36 | switch (type) { | ||
37 | case DSO_BINARY_TYPE__DEBUGLINK: { | ||
38 | char *debuglink; | ||
39 | |||
40 | strncpy(file, dso->long_name, size); | ||
41 | debuglink = file + dso->long_name_len; | ||
42 | while (debuglink != file && *debuglink != '/') | ||
43 | debuglink--; | ||
44 | if (*debuglink == '/') | ||
45 | debuglink++; | ||
46 | filename__read_debuglink(dso->long_name, debuglink, | ||
47 | size - (debuglink - file)); | ||
48 | } | ||
49 | break; | ||
50 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | ||
51 | /* skip the locally configured cache if a symfs is given */ | ||
52 | if (symbol_conf.symfs[0] || | ||
53 | (dso__build_id_filename(dso, file, size) == NULL)) | ||
54 | ret = -1; | ||
55 | break; | ||
56 | |||
57 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | ||
58 | snprintf(file, size, "%s/usr/lib/debug%s.debug", | ||
59 | symbol_conf.symfs, dso->long_name); | ||
60 | break; | ||
61 | |||
62 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | ||
63 | snprintf(file, size, "%s/usr/lib/debug%s", | ||
64 | symbol_conf.symfs, dso->long_name); | ||
65 | break; | ||
66 | |||
67 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: | ||
68 | if (!dso->has_build_id) { | ||
69 | ret = -1; | ||
70 | break; | ||
71 | } | ||
72 | |||
73 | build_id__sprintf(dso->build_id, | ||
74 | sizeof(dso->build_id), | ||
75 | build_id_hex); | ||
76 | snprintf(file, size, | ||
77 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
78 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); | ||
79 | break; | ||
80 | |||
81 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: | ||
82 | snprintf(file, size, "%s%s", | ||
83 | symbol_conf.symfs, dso->long_name); | ||
84 | break; | ||
85 | |||
86 | case DSO_BINARY_TYPE__GUEST_KMODULE: | ||
87 | snprintf(file, size, "%s%s%s", symbol_conf.symfs, | ||
88 | root_dir, dso->long_name); | ||
89 | break; | ||
90 | |||
91 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | ||
92 | snprintf(file, size, "%s%s", symbol_conf.symfs, | ||
93 | dso->long_name); | ||
94 | break; | ||
95 | |||
96 | default: | ||
97 | case DSO_BINARY_TYPE__KALLSYMS: | ||
98 | case DSO_BINARY_TYPE__VMLINUX: | ||
99 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: | ||
100 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | ||
101 | case DSO_BINARY_TYPE__JAVA_JIT: | ||
102 | case DSO_BINARY_TYPE__NOT_FOUND: | ||
103 | ret = -1; | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | static int open_dso(struct dso *dso, struct machine *machine) | ||
111 | { | ||
112 | char *root_dir = (char *) ""; | ||
113 | char *name; | ||
114 | int fd; | ||
115 | |||
116 | name = malloc(PATH_MAX); | ||
117 | if (!name) | ||
118 | return -ENOMEM; | ||
119 | |||
120 | if (machine) | ||
121 | root_dir = machine->root_dir; | ||
122 | |||
123 | if (dso__binary_type_file(dso, dso->data_type, | ||
124 | root_dir, name, PATH_MAX)) { | ||
125 | free(name); | ||
126 | return -EINVAL; | ||
127 | } | ||
128 | |||
129 | fd = open(name, O_RDONLY); | ||
130 | free(name); | ||
131 | return fd; | ||
132 | } | ||
133 | |||
134 | int dso__data_fd(struct dso *dso, struct machine *machine) | ||
135 | { | ||
136 | static enum dso_binary_type binary_type_data[] = { | ||
137 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | ||
138 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | ||
139 | DSO_BINARY_TYPE__NOT_FOUND, | ||
140 | }; | ||
141 | int i = 0; | ||
142 | |||
143 | if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) | ||
144 | return open_dso(dso, machine); | ||
145 | |||
146 | do { | ||
147 | int fd; | ||
148 | |||
149 | dso->data_type = binary_type_data[i++]; | ||
150 | |||
151 | fd = open_dso(dso, machine); | ||
152 | if (fd >= 0) | ||
153 | return fd; | ||
154 | |||
155 | } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); | ||
156 | |||
157 | return -EINVAL; | ||
158 | } | ||
159 | |||
160 | static void | ||
161 | dso_cache__free(struct rb_root *root) | ||
162 | { | ||
163 | struct rb_node *next = rb_first(root); | ||
164 | |||
165 | while (next) { | ||
166 | struct dso_cache *cache; | ||
167 | |||
168 | cache = rb_entry(next, struct dso_cache, rb_node); | ||
169 | next = rb_next(&cache->rb_node); | ||
170 | rb_erase(&cache->rb_node, root); | ||
171 | free(cache); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | static struct dso_cache* | ||
176 | dso_cache__find(struct rb_root *root, u64 offset) | ||
177 | { | ||
178 | struct rb_node **p = &root->rb_node; | ||
179 | struct rb_node *parent = NULL; | ||
180 | struct dso_cache *cache; | ||
181 | |||
182 | while (*p != NULL) { | ||
183 | u64 end; | ||
184 | |||
185 | parent = *p; | ||
186 | cache = rb_entry(parent, struct dso_cache, rb_node); | ||
187 | end = cache->offset + DSO__DATA_CACHE_SIZE; | ||
188 | |||
189 | if (offset < cache->offset) | ||
190 | p = &(*p)->rb_left; | ||
191 | else if (offset >= end) | ||
192 | p = &(*p)->rb_right; | ||
193 | else | ||
194 | return cache; | ||
195 | } | ||
196 | return NULL; | ||
197 | } | ||
198 | |||
199 | static void | ||
200 | dso_cache__insert(struct rb_root *root, struct dso_cache *new) | ||
201 | { | ||
202 | struct rb_node **p = &root->rb_node; | ||
203 | struct rb_node *parent = NULL; | ||
204 | struct dso_cache *cache; | ||
205 | u64 offset = new->offset; | ||
206 | |||
207 | while (*p != NULL) { | ||
208 | u64 end; | ||
209 | |||
210 | parent = *p; | ||
211 | cache = rb_entry(parent, struct dso_cache, rb_node); | ||
212 | end = cache->offset + DSO__DATA_CACHE_SIZE; | ||
213 | |||
214 | if (offset < cache->offset) | ||
215 | p = &(*p)->rb_left; | ||
216 | else if (offset >= end) | ||
217 | p = &(*p)->rb_right; | ||
218 | } | ||
219 | |||
220 | rb_link_node(&new->rb_node, parent, p); | ||
221 | rb_insert_color(&new->rb_node, root); | ||
222 | } | ||
223 | |||
224 | static ssize_t | ||
225 | dso_cache__memcpy(struct dso_cache *cache, u64 offset, | ||
226 | u8 *data, u64 size) | ||
227 | { | ||
228 | u64 cache_offset = offset - cache->offset; | ||
229 | u64 cache_size = min(cache->size - cache_offset, size); | ||
230 | |||
231 | memcpy(data, cache->data + cache_offset, cache_size); | ||
232 | return cache_size; | ||
233 | } | ||
234 | |||
235 | static ssize_t | ||
236 | dso_cache__read(struct dso *dso, struct machine *machine, | ||
237 | u64 offset, u8 *data, ssize_t size) | ||
238 | { | ||
239 | struct dso_cache *cache; | ||
240 | ssize_t ret; | ||
241 | int fd; | ||
242 | |||
243 | fd = dso__data_fd(dso, machine); | ||
244 | if (fd < 0) | ||
245 | return -1; | ||
246 | |||
247 | do { | ||
248 | u64 cache_offset; | ||
249 | |||
250 | ret = -ENOMEM; | ||
251 | |||
252 | cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); | ||
253 | if (!cache) | ||
254 | break; | ||
255 | |||
256 | cache_offset = offset & DSO__DATA_CACHE_MASK; | ||
257 | ret = -EINVAL; | ||
258 | |||
259 | if (-1 == lseek(fd, cache_offset, SEEK_SET)) | ||
260 | break; | ||
261 | |||
262 | ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); | ||
263 | if (ret <= 0) | ||
264 | break; | ||
265 | |||
266 | cache->offset = cache_offset; | ||
267 | cache->size = ret; | ||
268 | dso_cache__insert(&dso->cache, cache); | ||
269 | |||
270 | ret = dso_cache__memcpy(cache, offset, data, size); | ||
271 | |||
272 | } while (0); | ||
273 | |||
274 | if (ret <= 0) | ||
275 | free(cache); | ||
276 | |||
277 | close(fd); | ||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, | ||
282 | u64 offset, u8 *data, ssize_t size) | ||
283 | { | ||
284 | struct dso_cache *cache; | ||
285 | |||
286 | cache = dso_cache__find(&dso->cache, offset); | ||
287 | if (cache) | ||
288 | return dso_cache__memcpy(cache, offset, data, size); | ||
289 | else | ||
290 | return dso_cache__read(dso, machine, offset, data, size); | ||
291 | } | ||
292 | |||
293 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | ||
294 | u64 offset, u8 *data, ssize_t size) | ||
295 | { | ||
296 | ssize_t r = 0; | ||
297 | u8 *p = data; | ||
298 | |||
299 | do { | ||
300 | ssize_t ret; | ||
301 | |||
302 | ret = dso_cache_read(dso, machine, offset, p, size); | ||
303 | if (ret < 0) | ||
304 | return ret; | ||
305 | |||
306 | /* Reached EOF, return what we have. */ | ||
307 | if (!ret) | ||
308 | break; | ||
309 | |||
310 | BUG_ON(ret > size); | ||
311 | |||
312 | r += ret; | ||
313 | p += ret; | ||
314 | offset += ret; | ||
315 | size -= ret; | ||
316 | |||
317 | } while (size); | ||
318 | |||
319 | return r; | ||
320 | } | ||
321 | |||
322 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | ||
323 | struct machine *machine, u64 addr, | ||
324 | u8 *data, ssize_t size) | ||
325 | { | ||
326 | u64 offset = map->map_ip(map, addr); | ||
327 | return dso__data_read_offset(dso, machine, offset, data, size); | ||
328 | } | ||
329 | |||
330 | struct map *dso__new_map(const char *name) | ||
331 | { | ||
332 | struct map *map = NULL; | ||
333 | struct dso *dso = dso__new(name); | ||
334 | |||
335 | if (dso) | ||
336 | map = map__new2(0, dso, MAP__FUNCTION); | ||
337 | |||
338 | return map; | ||
339 | } | ||
340 | |||
341 | struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | ||
342 | const char *short_name, int dso_type) | ||
343 | { | ||
344 | /* | ||
345 | * The kernel dso could be created by build_id processing. | ||
346 | */ | ||
347 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); | ||
348 | |||
349 | /* | ||
350 | * We need to run this in all cases, since during the build_id | ||
351 | * processing we had no idea this was the kernel dso. | ||
352 | */ | ||
353 | if (dso != NULL) { | ||
354 | dso__set_short_name(dso, short_name); | ||
355 | dso->kernel = dso_type; | ||
356 | } | ||
357 | |||
358 | return dso; | ||
359 | } | ||
360 | |||
361 | void dso__set_long_name(struct dso *dso, char *name) | ||
362 | { | ||
363 | if (name == NULL) | ||
364 | return; | ||
365 | dso->long_name = name; | ||
366 | dso->long_name_len = strlen(name); | ||
367 | } | ||
368 | |||
369 | void dso__set_short_name(struct dso *dso, const char *name) | ||
370 | { | ||
371 | if (name == NULL) | ||
372 | return; | ||
373 | dso->short_name = name; | ||
374 | dso->short_name_len = strlen(name); | ||
375 | } | ||
376 | |||
377 | static void dso__set_basename(struct dso *dso) | ||
378 | { | ||
379 | dso__set_short_name(dso, basename(dso->long_name)); | ||
380 | } | ||
381 | |||
382 | int dso__name_len(const struct dso *dso) | ||
383 | { | ||
384 | if (!dso) | ||
385 | return strlen("[unknown]"); | ||
386 | if (verbose) | ||
387 | return dso->long_name_len; | ||
388 | |||
389 | return dso->short_name_len; | ||
390 | } | ||
391 | |||
392 | bool dso__loaded(const struct dso *dso, enum map_type type) | ||
393 | { | ||
394 | return dso->loaded & (1 << type); | ||
395 | } | ||
396 | |||
397 | bool dso__sorted_by_name(const struct dso *dso, enum map_type type) | ||
398 | { | ||
399 | return dso->sorted_by_name & (1 << type); | ||
400 | } | ||
401 | |||
402 | void dso__set_sorted_by_name(struct dso *dso, enum map_type type) | ||
403 | { | ||
404 | dso->sorted_by_name |= (1 << type); | ||
405 | } | ||
406 | |||
407 | struct dso *dso__new(const char *name) | ||
408 | { | ||
409 | struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); | ||
410 | |||
411 | if (dso != NULL) { | ||
412 | int i; | ||
413 | strcpy(dso->name, name); | ||
414 | dso__set_long_name(dso, dso->name); | ||
415 | dso__set_short_name(dso, dso->name); | ||
416 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
417 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; | ||
418 | dso->cache = RB_ROOT; | ||
419 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | ||
420 | dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; | ||
421 | dso->loaded = 0; | ||
422 | dso->sorted_by_name = 0; | ||
423 | dso->has_build_id = 0; | ||
424 | dso->kernel = DSO_TYPE_USER; | ||
425 | dso->needs_swap = DSO_SWAP__UNSET; | ||
426 | INIT_LIST_HEAD(&dso->node); | ||
427 | } | ||
428 | |||
429 | return dso; | ||
430 | } | ||
431 | |||
432 | void dso__delete(struct dso *dso) | ||
433 | { | ||
434 | int i; | ||
435 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
436 | symbols__delete(&dso->symbols[i]); | ||
437 | if (dso->sname_alloc) | ||
438 | free((char *)dso->short_name); | ||
439 | if (dso->lname_alloc) | ||
440 | free(dso->long_name); | ||
441 | dso_cache__free(&dso->cache); | ||
442 | free(dso); | ||
443 | } | ||
444 | |||
445 | void dso__set_build_id(struct dso *dso, void *build_id) | ||
446 | { | ||
447 | memcpy(dso->build_id, build_id, sizeof(dso->build_id)); | ||
448 | dso->has_build_id = 1; | ||
449 | } | ||
450 | |||
451 | bool dso__build_id_equal(const struct dso *dso, u8 *build_id) | ||
452 | { | ||
453 | return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; | ||
454 | } | ||
455 | |||
456 | void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) | ||
457 | { | ||
458 | char path[PATH_MAX]; | ||
459 | |||
460 | if (machine__is_default_guest(machine)) | ||
461 | return; | ||
462 | sprintf(path, "%s/sys/kernel/notes", machine->root_dir); | ||
463 | if (sysfs__read_build_id(path, dso->build_id, | ||
464 | sizeof(dso->build_id)) == 0) | ||
465 | dso->has_build_id = true; | ||
466 | } | ||
467 | |||
468 | int dso__kernel_module_get_build_id(struct dso *dso, | ||
469 | const char *root_dir) | ||
470 | { | ||
471 | char filename[PATH_MAX]; | ||
472 | /* | ||
473 | * kernel module short names are of the form "[module]" and | ||
474 | * we need just "module" here. | ||
475 | */ | ||
476 | const char *name = dso->short_name + 1; | ||
477 | |||
478 | snprintf(filename, sizeof(filename), | ||
479 | "%s/sys/module/%.*s/notes/.note.gnu.build-id", | ||
480 | root_dir, (int)strlen(name) - 1, name); | ||
481 | |||
482 | if (sysfs__read_build_id(filename, dso->build_id, | ||
483 | sizeof(dso->build_id)) == 0) | ||
484 | dso->has_build_id = true; | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | ||
490 | { | ||
491 | bool have_build_id = false; | ||
492 | struct dso *pos; | ||
493 | |||
494 | list_for_each_entry(pos, head, node) { | ||
495 | if (with_hits && !pos->hit) | ||
496 | continue; | ||
497 | if (pos->has_build_id) { | ||
498 | have_build_id = true; | ||
499 | continue; | ||
500 | } | ||
501 | if (filename__read_build_id(pos->long_name, pos->build_id, | ||
502 | sizeof(pos->build_id)) > 0) { | ||
503 | have_build_id = true; | ||
504 | pos->has_build_id = true; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | return have_build_id; | ||
509 | } | ||
510 | |||
511 | void dsos__add(struct list_head *head, struct dso *dso) | ||
512 | { | ||
513 | list_add_tail(&dso->node, head); | ||
514 | } | ||
515 | |||
516 | struct dso *dsos__find(struct list_head *head, const char *name) | ||
517 | { | ||
518 | struct dso *pos; | ||
519 | |||
520 | list_for_each_entry(pos, head, node) | ||
521 | if (strcmp(pos->long_name, name) == 0) | ||
522 | return pos; | ||
523 | return NULL; | ||
524 | } | ||
525 | |||
526 | struct dso *__dsos__findnew(struct list_head *head, const char *name) | ||
527 | { | ||
528 | struct dso *dso = dsos__find(head, name); | ||
529 | |||
530 | if (!dso) { | ||
531 | dso = dso__new(name); | ||
532 | if (dso != NULL) { | ||
533 | dsos__add(head, dso); | ||
534 | dso__set_basename(dso); | ||
535 | } | ||
536 | } | ||
537 | |||
538 | return dso; | ||
539 | } | ||
540 | |||
541 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | ||
542 | bool with_hits) | ||
543 | { | ||
544 | struct dso *pos; | ||
545 | size_t ret = 0; | ||
546 | |||
547 | list_for_each_entry(pos, head, node) { | ||
548 | if (with_hits && !pos->hit) | ||
549 | continue; | ||
550 | ret += dso__fprintf_buildid(pos, fp); | ||
551 | ret += fprintf(fp, " %s\n", pos->long_name); | ||
552 | } | ||
553 | return ret; | ||
554 | } | ||
555 | |||
556 | size_t __dsos__fprintf(struct list_head *head, FILE *fp) | ||
557 | { | ||
558 | struct dso *pos; | ||
559 | size_t ret = 0; | ||
560 | |||
561 | list_for_each_entry(pos, head, node) { | ||
562 | int i; | ||
563 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
564 | ret += dso__fprintf(pos, i, fp); | ||
565 | } | ||
566 | |||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) | ||
571 | { | ||
572 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
573 | |||
574 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | ||
575 | return fprintf(fp, "%s", sbuild_id); | ||
576 | } | ||
577 | |||
578 | size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | ||
579 | { | ||
580 | struct rb_node *nd; | ||
581 | size_t ret = fprintf(fp, "dso: %s (", dso->short_name); | ||
582 | |||
583 | if (dso->short_name != dso->long_name) | ||
584 | ret += fprintf(fp, "%s, ", dso->long_name); | ||
585 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], | ||
586 | dso->loaded ? "" : "NOT "); | ||
587 | ret += dso__fprintf_buildid(dso, fp); | ||
588 | ret += fprintf(fp, ")\n"); | ||
589 | for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { | ||
590 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
591 | ret += symbol__fprintf(pos, fp); | ||
592 | } | ||
593 | |||
594 | return ret; | ||
595 | } | ||
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h new file mode 100644 index 000000000000..e03276940b99 --- /dev/null +++ b/tools/perf/util/dso.h | |||
@@ -0,0 +1,148 @@ | |||
1 | #ifndef __PERF_DSO | ||
2 | #define __PERF_DSO | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/rbtree.h> | ||
6 | #include "types.h" | ||
7 | #include "map.h" | ||
8 | |||
9 | enum dso_binary_type { | ||
10 | DSO_BINARY_TYPE__KALLSYMS = 0, | ||
11 | DSO_BINARY_TYPE__GUEST_KALLSYMS, | ||
12 | DSO_BINARY_TYPE__VMLINUX, | ||
13 | DSO_BINARY_TYPE__GUEST_VMLINUX, | ||
14 | DSO_BINARY_TYPE__JAVA_JIT, | ||
15 | DSO_BINARY_TYPE__DEBUGLINK, | ||
16 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | ||
17 | DSO_BINARY_TYPE__FEDORA_DEBUGINFO, | ||
18 | DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, | ||
19 | DSO_BINARY_TYPE__BUILDID_DEBUGINFO, | ||
20 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | ||
21 | DSO_BINARY_TYPE__GUEST_KMODULE, | ||
22 | DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, | ||
23 | DSO_BINARY_TYPE__NOT_FOUND, | ||
24 | }; | ||
25 | |||
26 | enum dso_kernel_type { | ||
27 | DSO_TYPE_USER = 0, | ||
28 | DSO_TYPE_KERNEL, | ||
29 | DSO_TYPE_GUEST_KERNEL | ||
30 | }; | ||
31 | |||
32 | enum dso_swap_type { | ||
33 | DSO_SWAP__UNSET, | ||
34 | DSO_SWAP__NO, | ||
35 | DSO_SWAP__YES, | ||
36 | }; | ||
37 | |||
38 | #define DSO__SWAP(dso, type, val) \ | ||
39 | ({ \ | ||
40 | type ____r = val; \ | ||
41 | BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \ | ||
42 | if (dso->needs_swap == DSO_SWAP__YES) { \ | ||
43 | switch (sizeof(____r)) { \ | ||
44 | case 2: \ | ||
45 | ____r = bswap_16(val); \ | ||
46 | break; \ | ||
47 | case 4: \ | ||
48 | ____r = bswap_32(val); \ | ||
49 | break; \ | ||
50 | case 8: \ | ||
51 | ____r = bswap_64(val); \ | ||
52 | break; \ | ||
53 | default: \ | ||
54 | BUG_ON(1); \ | ||
55 | } \ | ||
56 | } \ | ||
57 | ____r; \ | ||
58 | }) | ||
59 | |||
60 | #define DSO__DATA_CACHE_SIZE 4096 | ||
61 | #define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1) | ||
62 | |||
63 | struct dso_cache { | ||
64 | struct rb_node rb_node; | ||
65 | u64 offset; | ||
66 | u64 size; | ||
67 | char data[0]; | ||
68 | }; | ||
69 | |||
70 | struct dso { | ||
71 | struct list_head node; | ||
72 | struct rb_root symbols[MAP__NR_TYPES]; | ||
73 | struct rb_root symbol_names[MAP__NR_TYPES]; | ||
74 | struct rb_root cache; | ||
75 | enum dso_kernel_type kernel; | ||
76 | enum dso_swap_type needs_swap; | ||
77 | enum dso_binary_type symtab_type; | ||
78 | enum dso_binary_type data_type; | ||
79 | u8 adjust_symbols:1; | ||
80 | u8 has_build_id:1; | ||
81 | u8 hit:1; | ||
82 | u8 annotate_warned:1; | ||
83 | u8 sname_alloc:1; | ||
84 | u8 lname_alloc:1; | ||
85 | u8 sorted_by_name; | ||
86 | u8 loaded; | ||
87 | u8 build_id[BUILD_ID_SIZE]; | ||
88 | const char *short_name; | ||
89 | char *long_name; | ||
90 | u16 long_name_len; | ||
91 | u16 short_name_len; | ||
92 | char name[0]; | ||
93 | }; | ||
94 | |||
95 | static inline void dso__set_loaded(struct dso *dso, enum map_type type) | ||
96 | { | ||
97 | dso->loaded |= (1 << type); | ||
98 | } | ||
99 | |||
100 | struct dso *dso__new(const char *name); | ||
101 | void dso__delete(struct dso *dso); | ||
102 | |||
103 | void dso__set_short_name(struct dso *dso, const char *name); | ||
104 | void dso__set_long_name(struct dso *dso, char *name); | ||
105 | |||
106 | int dso__name_len(const struct dso *dso); | ||
107 | |||
108 | bool dso__loaded(const struct dso *dso, enum map_type type); | ||
109 | |||
110 | bool dso__sorted_by_name(const struct dso *dso, enum map_type type); | ||
111 | void dso__set_sorted_by_name(struct dso *dso, enum map_type type); | ||
112 | void dso__sort_by_name(struct dso *dso, enum map_type type); | ||
113 | |||
114 | void dso__set_build_id(struct dso *dso, void *build_id); | ||
115 | bool dso__build_id_equal(const struct dso *dso, u8 *build_id); | ||
116 | void dso__read_running_kernel_build_id(struct dso *dso, | ||
117 | struct machine *machine); | ||
118 | int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); | ||
119 | |||
120 | char dso__symtab_origin(const struct dso *dso); | ||
121 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | ||
122 | char *root_dir, char *file, size_t size); | ||
123 | |||
124 | int dso__data_fd(struct dso *dso, struct machine *machine); | ||
125 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | ||
126 | u64 offset, u8 *data, ssize_t size); | ||
127 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | ||
128 | struct machine *machine, u64 addr, | ||
129 | u8 *data, ssize_t size); | ||
130 | |||
131 | struct map *dso__new_map(const char *name); | ||
132 | struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | ||
133 | const char *short_name, int dso_type); | ||
134 | |||
135 | void dsos__add(struct list_head *head, struct dso *dso); | ||
136 | struct dso *dsos__find(struct list_head *head, const char *name); | ||
137 | struct dso *__dsos__findnew(struct list_head *head, const char *name); | ||
138 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); | ||
139 | |||
140 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | ||
141 | bool with_hits); | ||
142 | size_t __dsos__fprintf(struct list_head *head, FILE *fp); | ||
143 | |||
144 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); | ||
145 | size_t dso__fprintf_symbols_by_name(struct dso *dso, | ||
146 | enum map_type type, FILE *fp); | ||
147 | size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); | ||
148 | #endif /* __PERF_DSO */ | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6715b1938725..3cf2c3e0605f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <linux/types.h> | 1 | #include <linux/types.h> |
2 | #include "event.h" | 2 | #include "event.h" |
3 | #include "debug.h" | 3 | #include "debug.h" |
4 | #include "machine.h" | ||
4 | #include "sort.h" | 5 | #include "sort.h" |
5 | #include "string.h" | 6 | #include "string.h" |
6 | #include "strlist.h" | 7 | #include "strlist.h" |
@@ -192,55 +193,43 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
192 | event->header.misc = PERF_RECORD_MISC_USER; | 193 | event->header.misc = PERF_RECORD_MISC_USER; |
193 | 194 | ||
194 | while (1) { | 195 | while (1) { |
195 | char bf[BUFSIZ], *pbf = bf; | 196 | char bf[BUFSIZ]; |
196 | int n; | 197 | char prot[5]; |
198 | char execname[PATH_MAX]; | ||
199 | char anonstr[] = "//anon"; | ||
197 | size_t size; | 200 | size_t size; |
201 | |||
198 | if (fgets(bf, sizeof(bf), fp) == NULL) | 202 | if (fgets(bf, sizeof(bf), fp) == NULL) |
199 | break; | 203 | break; |
200 | 204 | ||
205 | /* ensure null termination since stack will be reused. */ | ||
206 | strcpy(execname, ""); | ||
207 | |||
201 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ | 208 | /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ |
202 | n = hex2u64(pbf, &event->mmap.start); | 209 | sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", |
203 | if (n < 0) | 210 | &event->mmap.start, &event->mmap.len, prot, |
204 | continue; | 211 | &event->mmap.pgoff, execname); |
205 | pbf += n + 1; | 212 | |
206 | n = hex2u64(pbf, &event->mmap.len); | 213 | if (prot[2] != 'x') |
207 | if (n < 0) | ||
208 | continue; | 214 | continue; |
209 | pbf += n + 3; | 215 | |
210 | if (*pbf == 'x') { /* vm_exec */ | 216 | if (!strcmp(execname, "")) |
211 | char anonstr[] = "//anon\n"; | 217 | strcpy(execname, anonstr); |
212 | char *execname = strchr(bf, '/'); | 218 | |
213 | 219 | size = strlen(execname) + 1; | |
214 | /* Catch VDSO */ | 220 | memcpy(event->mmap.filename, execname, size); |
215 | if (execname == NULL) | 221 | size = PERF_ALIGN(size, sizeof(u64)); |
216 | execname = strstr(bf, "[vdso]"); | 222 | event->mmap.len -= event->mmap.start; |
217 | 223 | event->mmap.header.size = (sizeof(event->mmap) - | |
218 | /* Catch anonymous mmaps */ | 224 | (sizeof(event->mmap.filename) - size)); |
219 | if ((execname == NULL) && !strstr(bf, "[")) | 225 | memset(event->mmap.filename + size, 0, machine->id_hdr_size); |
220 | execname = anonstr; | 226 | event->mmap.header.size += machine->id_hdr_size; |
221 | 227 | event->mmap.pid = tgid; | |
222 | if (execname == NULL) | 228 | event->mmap.tid = pid; |
223 | continue; | 229 | |
224 | 230 | if (process(tool, event, &synth_sample, machine) != 0) { | |
225 | pbf += 3; | 231 | rc = -1; |
226 | n = hex2u64(pbf, &event->mmap.pgoff); | 232 | break; |
227 | |||
228 | size = strlen(execname); | ||
229 | execname[size - 1] = '\0'; /* Remove \n */ | ||
230 | memcpy(event->mmap.filename, execname, size); | ||
231 | size = PERF_ALIGN(size, sizeof(u64)); | ||
232 | event->mmap.len -= event->mmap.start; | ||
233 | event->mmap.header.size = (sizeof(event->mmap) - | ||
234 | (sizeof(event->mmap.filename) - size)); | ||
235 | memset(event->mmap.filename + size, 0, machine->id_hdr_size); | ||
236 | event->mmap.header.size += machine->id_hdr_size; | ||
237 | event->mmap.pid = tgid; | ||
238 | event->mmap.tid = pid; | ||
239 | |||
240 | if (process(tool, event, &synth_sample, machine) != 0) { | ||
241 | rc = -1; | ||
242 | break; | ||
243 | } | ||
244 | } | 233 | } |
245 | } | 234 | } |
246 | 235 | ||
@@ -404,16 +393,15 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
404 | 393 | ||
405 | if (*end) /* only interested in proper numerical dirents */ | 394 | if (*end) /* only interested in proper numerical dirents */ |
406 | continue; | 395 | continue; |
407 | 396 | /* | |
408 | if (__event__synthesize_thread(comm_event, mmap_event, pid, 1, | 397 | * We may race with exiting thread, so don't stop just because |
409 | process, tool, machine) != 0) { | 398 | * one thread couldn't be synthesized. |
410 | err = -1; | 399 | */ |
411 | goto out_closedir; | 400 | __event__synthesize_thread(comm_event, mmap_event, pid, 1, |
412 | } | 401 | process, tool, machine); |
413 | } | 402 | } |
414 | 403 | ||
415 | err = 0; | 404 | err = 0; |
416 | out_closedir: | ||
417 | closedir(proc); | 405 | closedir(proc); |
418 | out_free_mmap: | 406 | out_free_mmap: |
419 | free(mmap_event); | 407 | free(mmap_event); |
@@ -519,134 +507,15 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused, | |||
519 | struct perf_sample *sample __maybe_unused, | 507 | struct perf_sample *sample __maybe_unused, |
520 | struct machine *machine) | 508 | struct machine *machine) |
521 | { | 509 | { |
522 | struct thread *thread = machine__findnew_thread(machine, event->comm.tid); | 510 | return machine__process_comm_event(machine, event); |
523 | |||
524 | if (dump_trace) | ||
525 | perf_event__fprintf_comm(event, stdout); | ||
526 | |||
527 | if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { | ||
528 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); | ||
529 | return -1; | ||
530 | } | ||
531 | |||
532 | return 0; | ||
533 | } | 511 | } |
534 | 512 | ||
535 | int perf_event__process_lost(struct perf_tool *tool __maybe_unused, | 513 | int perf_event__process_lost(struct perf_tool *tool __maybe_unused, |
536 | union perf_event *event, | 514 | union perf_event *event, |
537 | struct perf_sample *sample __maybe_unused, | 515 | struct perf_sample *sample __maybe_unused, |
538 | struct machine *machine __maybe_unused) | 516 | struct machine *machine) |
539 | { | ||
540 | dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", | ||
541 | event->lost.id, event->lost.lost); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static void perf_event__set_kernel_mmap_len(union perf_event *event, | ||
546 | struct map **maps) | ||
547 | { | ||
548 | maps[MAP__FUNCTION]->start = event->mmap.start; | ||
549 | maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len; | ||
550 | /* | ||
551 | * Be a bit paranoid here, some perf.data file came with | ||
552 | * a zero sized synthesized MMAP event for the kernel. | ||
553 | */ | ||
554 | if (maps[MAP__FUNCTION]->end == 0) | ||
555 | maps[MAP__FUNCTION]->end = ~0ULL; | ||
556 | } | ||
557 | |||
558 | static int perf_event__process_kernel_mmap(struct perf_tool *tool | ||
559 | __maybe_unused, | ||
560 | union perf_event *event, | ||
561 | struct machine *machine) | ||
562 | { | 517 | { |
563 | struct map *map; | 518 | return machine__process_lost_event(machine, event); |
564 | char kmmap_prefix[PATH_MAX]; | ||
565 | enum dso_kernel_type kernel_type; | ||
566 | bool is_kernel_mmap; | ||
567 | |||
568 | machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); | ||
569 | if (machine__is_host(machine)) | ||
570 | kernel_type = DSO_TYPE_KERNEL; | ||
571 | else | ||
572 | kernel_type = DSO_TYPE_GUEST_KERNEL; | ||
573 | |||
574 | is_kernel_mmap = memcmp(event->mmap.filename, | ||
575 | kmmap_prefix, | ||
576 | strlen(kmmap_prefix) - 1) == 0; | ||
577 | if (event->mmap.filename[0] == '/' || | ||
578 | (!is_kernel_mmap && event->mmap.filename[0] == '[')) { | ||
579 | |||
580 | char short_module_name[1024]; | ||
581 | char *name, *dot; | ||
582 | |||
583 | if (event->mmap.filename[0] == '/') { | ||
584 | name = strrchr(event->mmap.filename, '/'); | ||
585 | if (name == NULL) | ||
586 | goto out_problem; | ||
587 | |||
588 | ++name; /* skip / */ | ||
589 | dot = strrchr(name, '.'); | ||
590 | if (dot == NULL) | ||
591 | goto out_problem; | ||
592 | snprintf(short_module_name, sizeof(short_module_name), | ||
593 | "[%.*s]", (int)(dot - name), name); | ||
594 | strxfrchar(short_module_name, '-', '_'); | ||
595 | } else | ||
596 | strcpy(short_module_name, event->mmap.filename); | ||
597 | |||
598 | map = machine__new_module(machine, event->mmap.start, | ||
599 | event->mmap.filename); | ||
600 | if (map == NULL) | ||
601 | goto out_problem; | ||
602 | |||
603 | name = strdup(short_module_name); | ||
604 | if (name == NULL) | ||
605 | goto out_problem; | ||
606 | |||
607 | map->dso->short_name = name; | ||
608 | map->dso->sname_alloc = 1; | ||
609 | map->end = map->start + event->mmap.len; | ||
610 | } else if (is_kernel_mmap) { | ||
611 | const char *symbol_name = (event->mmap.filename + | ||
612 | strlen(kmmap_prefix)); | ||
613 | /* | ||
614 | * Should be there already, from the build-id table in | ||
615 | * the header. | ||
616 | */ | ||
617 | struct dso *kernel = __dsos__findnew(&machine->kernel_dsos, | ||
618 | kmmap_prefix); | ||
619 | if (kernel == NULL) | ||
620 | goto out_problem; | ||
621 | |||
622 | kernel->kernel = kernel_type; | ||
623 | if (__machine__create_kernel_maps(machine, kernel) < 0) | ||
624 | goto out_problem; | ||
625 | |||
626 | perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps); | ||
627 | |||
628 | /* | ||
629 | * Avoid using a zero address (kptr_restrict) for the ref reloc | ||
630 | * symbol. Effectively having zero here means that at record | ||
631 | * time /proc/sys/kernel/kptr_restrict was non zero. | ||
632 | */ | ||
633 | if (event->mmap.pgoff != 0) { | ||
634 | maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, | ||
635 | symbol_name, | ||
636 | event->mmap.pgoff); | ||
637 | } | ||
638 | |||
639 | if (machine__is_default_guest(machine)) { | ||
640 | /* | ||
641 | * preload dso of guest kernel and modules | ||
642 | */ | ||
643 | dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION], | ||
644 | NULL); | ||
645 | } | ||
646 | } | ||
647 | return 0; | ||
648 | out_problem: | ||
649 | return -1; | ||
650 | } | 519 | } |
651 | 520 | ||
652 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) | 521 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) |
@@ -656,43 +525,12 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) | |||
656 | event->mmap.len, event->mmap.pgoff, event->mmap.filename); | 525 | event->mmap.len, event->mmap.pgoff, event->mmap.filename); |
657 | } | 526 | } |
658 | 527 | ||
659 | int perf_event__process_mmap(struct perf_tool *tool, | 528 | int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, |
660 | union perf_event *event, | 529 | union perf_event *event, |
661 | struct perf_sample *sample __maybe_unused, | 530 | struct perf_sample *sample __maybe_unused, |
662 | struct machine *machine) | 531 | struct machine *machine) |
663 | { | 532 | { |
664 | struct thread *thread; | 533 | return machine__process_mmap_event(machine, event); |
665 | struct map *map; | ||
666 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
667 | int ret = 0; | ||
668 | |||
669 | if (dump_trace) | ||
670 | perf_event__fprintf_mmap(event, stdout); | ||
671 | |||
672 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || | ||
673 | cpumode == PERF_RECORD_MISC_KERNEL) { | ||
674 | ret = perf_event__process_kernel_mmap(tool, event, machine); | ||
675 | if (ret < 0) | ||
676 | goto out_problem; | ||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | thread = machine__findnew_thread(machine, event->mmap.pid); | ||
681 | if (thread == NULL) | ||
682 | goto out_problem; | ||
683 | map = map__new(&machine->user_dsos, event->mmap.start, | ||
684 | event->mmap.len, event->mmap.pgoff, | ||
685 | event->mmap.pid, event->mmap.filename, | ||
686 | MAP__FUNCTION); | ||
687 | if (map == NULL) | ||
688 | goto out_problem; | ||
689 | |||
690 | thread__insert_map(thread, map); | ||
691 | return 0; | ||
692 | |||
693 | out_problem: | ||
694 | dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); | ||
695 | return 0; | ||
696 | } | 534 | } |
697 | 535 | ||
698 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) | 536 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) |
@@ -702,29 +540,20 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) | |||
702 | event->fork.ppid, event->fork.ptid); | 540 | event->fork.ppid, event->fork.ptid); |
703 | } | 541 | } |
704 | 542 | ||
705 | int perf_event__process_task(struct perf_tool *tool __maybe_unused, | 543 | int perf_event__process_fork(struct perf_tool *tool __maybe_unused, |
706 | union perf_event *event, | 544 | union perf_event *event, |
707 | struct perf_sample *sample __maybe_unused, | 545 | struct perf_sample *sample __maybe_unused, |
708 | struct machine *machine) | 546 | struct machine *machine) |
709 | { | 547 | { |
710 | struct thread *thread = machine__findnew_thread(machine, event->fork.tid); | 548 | return machine__process_fork_event(machine, event); |
711 | struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); | 549 | } |
712 | |||
713 | if (dump_trace) | ||
714 | perf_event__fprintf_task(event, stdout); | ||
715 | |||
716 | if (event->header.type == PERF_RECORD_EXIT) { | ||
717 | machine__remove_thread(machine, thread); | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | if (thread == NULL || parent == NULL || | ||
722 | thread__fork(thread, parent) < 0) { | ||
723 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); | ||
724 | return -1; | ||
725 | } | ||
726 | 550 | ||
727 | return 0; | 551 | int perf_event__process_exit(struct perf_tool *tool __maybe_unused, |
552 | union perf_event *event, | ||
553 | struct perf_sample *sample __maybe_unused, | ||
554 | struct machine *machine) | ||
555 | { | ||
556 | return machine__process_exit_event(machine, event); | ||
728 | } | 557 | } |
729 | 558 | ||
730 | size_t perf_event__fprintf(union perf_event *event, FILE *fp) | 559 | size_t perf_event__fprintf(union perf_event *event, FILE *fp) |
@@ -750,27 +579,12 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) | |||
750 | return ret; | 579 | return ret; |
751 | } | 580 | } |
752 | 581 | ||
753 | int perf_event__process(struct perf_tool *tool, union perf_event *event, | 582 | int perf_event__process(struct perf_tool *tool __maybe_unused, |
754 | struct perf_sample *sample, struct machine *machine) | 583 | union perf_event *event, |
584 | struct perf_sample *sample __maybe_unused, | ||
585 | struct machine *machine) | ||
755 | { | 586 | { |
756 | switch (event->header.type) { | 587 | return machine__process_event(machine, event); |
757 | case PERF_RECORD_COMM: | ||
758 | perf_event__process_comm(tool, event, sample, machine); | ||
759 | break; | ||
760 | case PERF_RECORD_MMAP: | ||
761 | perf_event__process_mmap(tool, event, sample, machine); | ||
762 | break; | ||
763 | case PERF_RECORD_FORK: | ||
764 | case PERF_RECORD_EXIT: | ||
765 | perf_event__process_task(tool, event, sample, machine); | ||
766 | break; | ||
767 | case PERF_RECORD_LOST: | ||
768 | perf_event__process_lost(tool, event, sample, machine); | ||
769 | default: | ||
770 | break; | ||
771 | } | ||
772 | |||
773 | return 0; | ||
774 | } | 588 | } |
775 | 589 | ||
776 | void thread__find_addr_map(struct thread *self, | 590 | void thread__find_addr_map(struct thread *self, |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 21b99e741a87..0d573ff4771a 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | #include "../perf.h" | 7 | #include "../perf.h" |
8 | #include "map.h" | 8 | #include "map.h" |
9 | #include "build-id.h" | ||
9 | 10 | ||
10 | /* | 11 | /* |
11 | * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * | 12 | * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * |
@@ -96,8 +97,6 @@ struct perf_sample { | |||
96 | struct stack_dump user_stack; | 97 | struct stack_dump user_stack; |
97 | }; | 98 | }; |
98 | 99 | ||
99 | #define BUILD_ID_SIZE 20 | ||
100 | |||
101 | struct build_id_event { | 100 | struct build_id_event { |
102 | struct perf_event_header header; | 101 | struct perf_event_header header; |
103 | pid_t pid; | 102 | pid_t pid; |
@@ -191,7 +190,11 @@ int perf_event__process_mmap(struct perf_tool *tool, | |||
191 | union perf_event *event, | 190 | union perf_event *event, |
192 | struct perf_sample *sample, | 191 | struct perf_sample *sample, |
193 | struct machine *machine); | 192 | struct machine *machine); |
194 | int perf_event__process_task(struct perf_tool *tool, | 193 | int perf_event__process_fork(struct perf_tool *tool, |
194 | union perf_event *event, | ||
195 | struct perf_sample *sample, | ||
196 | struct machine *machine); | ||
197 | int perf_event__process_exit(struct perf_tool *tool, | ||
195 | union perf_event *event, | 198 | union perf_event *event, |
196 | struct perf_sample *sample, | 199 | struct perf_sample *sample, |
197 | struct machine *machine); | 200 | struct machine *machine); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 186b87730396..705293489e3c 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -52,15 +52,13 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | |||
52 | void perf_evlist__config_attrs(struct perf_evlist *evlist, | 52 | void perf_evlist__config_attrs(struct perf_evlist *evlist, |
53 | struct perf_record_opts *opts) | 53 | struct perf_record_opts *opts) |
54 | { | 54 | { |
55 | struct perf_evsel *evsel, *first; | 55 | struct perf_evsel *evsel; |
56 | 56 | ||
57 | if (evlist->cpus->map[0] < 0) | 57 | if (evlist->cpus->map[0] < 0) |
58 | opts->no_inherit = true; | 58 | opts->no_inherit = true; |
59 | 59 | ||
60 | first = perf_evlist__first(evlist); | ||
61 | |||
62 | list_for_each_entry(evsel, &evlist->entries, node) { | 60 | list_for_each_entry(evsel, &evlist->entries, node) { |
63 | perf_evsel__config(evsel, opts, first); | 61 | perf_evsel__config(evsel, opts); |
64 | 62 | ||
65 | if (evlist->nr_entries > 1) | 63 | if (evlist->nr_entries > 1) |
66 | evsel->attr.sample_type |= PERF_SAMPLE_ID; | 64 | evsel->attr.sample_type |= PERF_SAMPLE_ID; |
@@ -224,6 +222,8 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
224 | 222 | ||
225 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 223 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { |
226 | list_for_each_entry(pos, &evlist->entries, node) { | 224 | list_for_each_entry(pos, &evlist->entries, node) { |
225 | if (perf_evsel__is_group_member(pos)) | ||
226 | continue; | ||
227 | for (thread = 0; thread < evlist->threads->nr; thread++) | 227 | for (thread = 0; thread < evlist->threads->nr; thread++) |
228 | ioctl(FD(pos, cpu, thread), | 228 | ioctl(FD(pos, cpu, thread), |
229 | PERF_EVENT_IOC_DISABLE, 0); | 229 | PERF_EVENT_IOC_DISABLE, 0); |
@@ -238,6 +238,8 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
238 | 238 | ||
239 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { | 239 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { |
240 | list_for_each_entry(pos, &evlist->entries, node) { | 240 | list_for_each_entry(pos, &evlist->entries, node) { |
241 | if (perf_evsel__is_group_member(pos)) | ||
242 | continue; | ||
241 | for (thread = 0; thread < evlist->threads->nr; thread++) | 243 | for (thread = 0; thread < evlist->threads->nr; thread++) |
242 | ioctl(FD(pos, cpu, thread), | 244 | ioctl(FD(pos, cpu, thread), |
243 | PERF_EVENT_IOC_ENABLE, 0); | 245 | PERF_EVENT_IOC_ENABLE, 0); |
@@ -325,8 +327,6 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) | |||
325 | 327 | ||
326 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | 328 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) |
327 | { | 329 | { |
328 | /* XXX Move this to perf.c, making it generally available */ | ||
329 | unsigned int page_size = sysconf(_SC_PAGE_SIZE); | ||
330 | struct perf_mmap *md = &evlist->mmap[idx]; | 330 | struct perf_mmap *md = &evlist->mmap[idx]; |
331 | unsigned int head = perf_mmap__read_head(md); | 331 | unsigned int head = perf_mmap__read_head(md); |
332 | unsigned int old = md->prev; | 332 | unsigned int old = md->prev; |
@@ -528,7 +528,6 @@ out_unmap: | |||
528 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | 528 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, |
529 | bool overwrite) | 529 | bool overwrite) |
530 | { | 530 | { |
531 | unsigned int page_size = sysconf(_SC_PAGE_SIZE); | ||
532 | struct perf_evsel *evsel; | 531 | struct perf_evsel *evsel; |
533 | const struct cpu_map *cpus = evlist->cpus; | 532 | const struct cpu_map *cpus = evlist->cpus; |
534 | const struct thread_map *threads = evlist->threads; | 533 | const struct thread_map *threads = evlist->threads; |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 618d41140abd..1b16dd1edc8e 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -18,8 +18,8 @@ | |||
18 | #include "cpumap.h" | 18 | #include "cpumap.h" |
19 | #include "thread_map.h" | 19 | #include "thread_map.h" |
20 | #include "target.h" | 20 | #include "target.h" |
21 | #include "../../../include/linux/hw_breakpoint.h" | 21 | #include <linux/hw_breakpoint.h> |
22 | #include "../../../include/uapi/linux/perf_event.h" | 22 | #include <linux/perf_event.h> |
23 | #include "perf_regs.h" | 23 | #include "perf_regs.h" |
24 | 24 | ||
25 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 25 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
@@ -404,13 +404,40 @@ const char *perf_evsel__name(struct perf_evsel *evsel) | |||
404 | return evsel->name ?: "unknown"; | 404 | return evsel->name ?: "unknown"; |
405 | } | 405 | } |
406 | 406 | ||
407 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, | 407 | /* |
408 | struct perf_evsel *first) | 408 | * The enable_on_exec/disabled value strategy: |
409 | * | ||
410 | * 1) For any type of traced program: | ||
411 | * - all independent events and group leaders are disabled | ||
412 | * - all group members are enabled | ||
413 | * | ||
414 | * Group members are ruled by group leaders. They need to | ||
415 | * be enabled, because the group scheduling relies on that. | ||
416 | * | ||
417 | * 2) For traced programs executed by perf: | ||
418 | * - all independent events and group leaders have | ||
419 | * enable_on_exec set | ||
420 | * - we don't specifically enable or disable any event during | ||
421 | * the record command | ||
422 | * | ||
423 | * Independent events and group leaders are initially disabled | ||
424 | * and get enabled by exec. Group members are ruled by group | ||
425 | * leaders as stated in 1). | ||
426 | * | ||
427 | * 3) For traced programs attached by perf (pid/tid): | ||
428 | * - we specifically enable or disable all events during | ||
429 | * the record command | ||
430 | * | ||
431 | * When attaching events to already running traced we | ||
432 | * enable/disable events specifically, as there's no | ||
433 | * initial traced exec call. | ||
434 | */ | ||
435 | void perf_evsel__config(struct perf_evsel *evsel, | ||
436 | struct perf_record_opts *opts) | ||
409 | { | 437 | { |
410 | struct perf_event_attr *attr = &evsel->attr; | 438 | struct perf_event_attr *attr = &evsel->attr; |
411 | int track = !evsel->idx; /* only the first counter needs these */ | 439 | int track = !evsel->idx; /* only the first counter needs these */ |
412 | 440 | ||
413 | attr->disabled = 1; | ||
414 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; | 441 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; |
415 | attr->inherit = !opts->no_inherit; | 442 | attr->inherit = !opts->no_inherit; |
416 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 443 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
@@ -486,10 +513,21 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, | |||
486 | attr->mmap = track; | 513 | attr->mmap = track; |
487 | attr->comm = track; | 514 | attr->comm = track; |
488 | 515 | ||
489 | if (perf_target__none(&opts->target) && | 516 | /* |
490 | (!opts->group || evsel == first)) { | 517 | * XXX see the function comment above |
518 | * | ||
519 | * Disabling only independent events or group leaders, | ||
520 | * keeping group members enabled. | ||
521 | */ | ||
522 | if (!perf_evsel__is_group_member(evsel)) | ||
523 | attr->disabled = 1; | ||
524 | |||
525 | /* | ||
526 | * Setting enable_on_exec for independent events and | ||
527 | * group leaders for traced executed by perf. | ||
528 | */ | ||
529 | if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel)) | ||
491 | attr->enable_on_exec = 1; | 530 | attr->enable_on_exec = 1; |
492 | } | ||
493 | } | 531 | } |
494 | 532 | ||
495 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 533 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
@@ -669,7 +707,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) | |||
669 | struct perf_evsel *leader = evsel->leader; | 707 | struct perf_evsel *leader = evsel->leader; |
670 | int fd; | 708 | int fd; |
671 | 709 | ||
672 | if (!leader) | 710 | if (!perf_evsel__is_group_member(evsel)) |
673 | return -1; | 711 | return -1; |
674 | 712 | ||
675 | /* | 713 | /* |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6f94d6dea00f..3d2b8017438c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -3,7 +3,8 @@ | |||
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include "../../../include/uapi/linux/perf_event.h" | 6 | #include <stddef.h> |
7 | #include <linux/perf_event.h> | ||
7 | #include "types.h" | 8 | #include "types.h" |
8 | #include "xyarray.h" | 9 | #include "xyarray.h" |
9 | #include "cgroup.h" | 10 | #include "cgroup.h" |
@@ -92,8 +93,7 @@ void perf_evsel__exit(struct perf_evsel *evsel); | |||
92 | void perf_evsel__delete(struct perf_evsel *evsel); | 93 | void perf_evsel__delete(struct perf_evsel *evsel); |
93 | 94 | ||
94 | void perf_evsel__config(struct perf_evsel *evsel, | 95 | void perf_evsel__config(struct perf_evsel *evsel, |
95 | struct perf_record_opts *opts, | 96 | struct perf_record_opts *opts); |
96 | struct perf_evsel *first); | ||
97 | 97 | ||
98 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); | 98 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); |
99 | 99 | ||
@@ -225,4 +225,9 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) | |||
225 | { | 225 | { |
226 | return list_entry(evsel->node.next, struct perf_evsel, node); | 226 | return list_entry(evsel->node.next, struct perf_evsel, node); |
227 | } | 227 | } |
228 | |||
229 | static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel) | ||
230 | { | ||
231 | return evsel->leader != NULL; | ||
232 | } | ||
228 | #endif /* __PERF_EVSEL_H */ | 233 | #endif /* __PERF_EVSEL_H */ |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 7daad237dea5..b7da4634a047 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "pmu.h" | 23 | #include "pmu.h" |
24 | #include "vdso.h" | 24 | #include "vdso.h" |
25 | #include "strbuf.h" | 25 | #include "strbuf.h" |
26 | #include "build-id.h" | ||
26 | 27 | ||
27 | static bool no_buildid_cache = false; | 28 | static bool no_buildid_cache = false; |
28 | 29 | ||
@@ -1378,6 +1379,8 @@ static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused, | |||
1378 | 1379 | ||
1379 | str = tmp + 1; | 1380 | str = tmp + 1; |
1380 | fprintf(fp, "# node%u cpu list : %s\n", c, str); | 1381 | fprintf(fp, "# node%u cpu list : %s\n", c, str); |
1382 | |||
1383 | str += strlen(str) + 1; | ||
1381 | } | 1384 | } |
1382 | return; | 1385 | return; |
1383 | error: | 1386 | error: |
@@ -2340,6 +2343,16 @@ static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph) | |||
2340 | return -1; | 2343 | return -1; |
2341 | } | 2344 | } |
2342 | 2345 | ||
2346 | bool is_perf_magic(u64 magic) | ||
2347 | { | ||
2348 | if (!memcmp(&magic, __perf_magic1, sizeof(magic)) | ||
2349 | || magic == __perf_magic2 | ||
2350 | || magic == __perf_magic2_sw) | ||
2351 | return true; | ||
2352 | |||
2353 | return false; | ||
2354 | } | ||
2355 | |||
2343 | static int check_magic_endian(u64 magic, uint64_t hdr_sz, | 2356 | static int check_magic_endian(u64 magic, uint64_t hdr_sz, |
2344 | bool is_pipe, struct perf_header *ph) | 2357 | bool is_pipe, struct perf_header *ph) |
2345 | { | 2358 | { |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 879d215cdac9..20f0344accb1 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __PERF_HEADER_H | 1 | #ifndef __PERF_HEADER_H |
2 | #define __PERF_HEADER_H | 2 | #define __PERF_HEADER_H |
3 | 3 | ||
4 | #include "../../../include/uapi/linux/perf_event.h" | 4 | #include <linux/perf_event.h> |
5 | #include <sys/types.h> | 5 | #include <sys/types.h> |
6 | #include <stdbool.h> | 6 | #include <stdbool.h> |
7 | #include "types.h" | 7 | #include "types.h" |
@@ -154,6 +154,7 @@ int perf_event__synthesize_build_id(struct perf_tool *tool, | |||
154 | int perf_event__process_build_id(struct perf_tool *tool, | 154 | int perf_event__process_build_id(struct perf_tool *tool, |
155 | union perf_event *event, | 155 | union perf_event *event, |
156 | struct perf_session *session); | 156 | struct perf_session *session); |
157 | bool is_perf_magic(u64 magic); | ||
157 | 158 | ||
158 | /* | 159 | /* |
159 | * arch specific callback | 160 | * arch specific callback |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 277947a669b2..cb17e2a8c6ed 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -244,6 +244,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
244 | he->ms.map->referenced = true; | 244 | he->ms.map->referenced = true; |
245 | if (symbol_conf.use_callchain) | 245 | if (symbol_conf.use_callchain) |
246 | callchain_init(he->callchain); | 246 | callchain_init(he->callchain); |
247 | |||
248 | INIT_LIST_HEAD(&he->pairs.node); | ||
247 | } | 249 | } |
248 | 250 | ||
249 | return he; | 251 | return he; |
@@ -410,6 +412,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
410 | 412 | ||
411 | void hist_entry__free(struct hist_entry *he) | 413 | void hist_entry__free(struct hist_entry *he) |
412 | { | 414 | { |
415 | free(he->branch_info); | ||
413 | free(he); | 416 | free(he); |
414 | } | 417 | } |
415 | 418 | ||
@@ -713,3 +716,99 @@ void hists__inc_nr_events(struct hists *hists, u32 type) | |||
713 | ++hists->stats.nr_events[0]; | 716 | ++hists->stats.nr_events[0]; |
714 | ++hists->stats.nr_events[type]; | 717 | ++hists->stats.nr_events[type]; |
715 | } | 718 | } |
719 | |||
720 | static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | ||
721 | struct hist_entry *pair) | ||
722 | { | ||
723 | struct rb_node **p = &hists->entries.rb_node; | ||
724 | struct rb_node *parent = NULL; | ||
725 | struct hist_entry *he; | ||
726 | int cmp; | ||
727 | |||
728 | while (*p != NULL) { | ||
729 | parent = *p; | ||
730 | he = rb_entry(parent, struct hist_entry, rb_node); | ||
731 | |||
732 | cmp = hist_entry__cmp(pair, he); | ||
733 | |||
734 | if (!cmp) | ||
735 | goto out; | ||
736 | |||
737 | if (cmp < 0) | ||
738 | p = &(*p)->rb_left; | ||
739 | else | ||
740 | p = &(*p)->rb_right; | ||
741 | } | ||
742 | |||
743 | he = hist_entry__new(pair); | ||
744 | if (he) { | ||
745 | memset(&he->stat, 0, sizeof(he->stat)); | ||
746 | he->hists = hists; | ||
747 | rb_link_node(&he->rb_node, parent, p); | ||
748 | rb_insert_color(&he->rb_node, &hists->entries); | ||
749 | hists__inc_nr_entries(hists, he); | ||
750 | } | ||
751 | out: | ||
752 | return he; | ||
753 | } | ||
754 | |||
755 | static struct hist_entry *hists__find_entry(struct hists *hists, | ||
756 | struct hist_entry *he) | ||
757 | { | ||
758 | struct rb_node *n = hists->entries.rb_node; | ||
759 | |||
760 | while (n) { | ||
761 | struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); | ||
762 | int64_t cmp = hist_entry__cmp(he, iter); | ||
763 | |||
764 | if (cmp < 0) | ||
765 | n = n->rb_left; | ||
766 | else if (cmp > 0) | ||
767 | n = n->rb_right; | ||
768 | else | ||
769 | return iter; | ||
770 | } | ||
771 | |||
772 | return NULL; | ||
773 | } | ||
774 | |||
775 | /* | ||
776 | * Look for pairs to link to the leader buckets (hist_entries): | ||
777 | */ | ||
778 | void hists__match(struct hists *leader, struct hists *other) | ||
779 | { | ||
780 | struct rb_node *nd; | ||
781 | struct hist_entry *pos, *pair; | ||
782 | |||
783 | for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { | ||
784 | pos = rb_entry(nd, struct hist_entry, rb_node); | ||
785 | pair = hists__find_entry(other, pos); | ||
786 | |||
787 | if (pair) | ||
788 | hist__entry_add_pair(pos, pair); | ||
789 | } | ||
790 | } | ||
791 | |||
792 | /* | ||
793 | * Look for entries in the other hists that are not present in the leader, if | ||
794 | * we find them, just add a dummy entry on the leader hists, with period=0, | ||
795 | * nr_events=0, to serve as the list header. | ||
796 | */ | ||
797 | int hists__link(struct hists *leader, struct hists *other) | ||
798 | { | ||
799 | struct rb_node *nd; | ||
800 | struct hist_entry *pos, *pair; | ||
801 | |||
802 | for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { | ||
803 | pos = rb_entry(nd, struct hist_entry, rb_node); | ||
804 | |||
805 | if (!hist_entry__has_pairs(pos)) { | ||
806 | pair = hists__add_dummy_entry(leader, pos); | ||
807 | if (pair == NULL) | ||
808 | return -1; | ||
809 | hist__entry_add_pair(pair, pos); | ||
810 | } | ||
811 | } | ||
812 | |||
813 | return 0; | ||
814 | } | ||
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 66cb31fe81d2..8b091a51e4a2 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <pthread.h> | 5 | #include <pthread.h> |
6 | #include "callchain.h" | 6 | #include "callchain.h" |
7 | #include "header.h" | ||
7 | 8 | ||
8 | extern struct callchain_param callchain_param; | 9 | extern struct callchain_param callchain_param; |
9 | 10 | ||
@@ -114,6 +115,9 @@ bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); | |||
114 | void hists__reset_col_len(struct hists *hists); | 115 | void hists__reset_col_len(struct hists *hists); |
115 | void hists__calc_col_len(struct hists *hists, struct hist_entry *he); | 116 | void hists__calc_col_len(struct hists *hists, struct hist_entry *he); |
116 | 117 | ||
118 | void hists__match(struct hists *leader, struct hists *other); | ||
119 | int hists__link(struct hists *leader, struct hists *other); | ||
120 | |||
117 | struct perf_hpp { | 121 | struct perf_hpp { |
118 | char *buf; | 122 | char *buf; |
119 | size_t size; | 123 | size_t size; |
@@ -140,8 +144,12 @@ enum { | |||
140 | PERF_HPP__OVERHEAD_GUEST_US, | 144 | PERF_HPP__OVERHEAD_GUEST_US, |
141 | PERF_HPP__SAMPLES, | 145 | PERF_HPP__SAMPLES, |
142 | PERF_HPP__PERIOD, | 146 | PERF_HPP__PERIOD, |
147 | PERF_HPP__PERIOD_BASELINE, | ||
143 | PERF_HPP__DELTA, | 148 | PERF_HPP__DELTA, |
149 | PERF_HPP__RATIO, | ||
150 | PERF_HPP__WEIGHTED_DIFF, | ||
144 | PERF_HPP__DISPL, | 151 | PERF_HPP__DISPL, |
152 | PERF_HPP__FORMULA, | ||
145 | 153 | ||
146 | PERF_HPP__MAX_INDEX | 154 | PERF_HPP__MAX_INDEX |
147 | }; | 155 | }; |
@@ -153,21 +161,27 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
153 | 161 | ||
154 | struct perf_evlist; | 162 | struct perf_evlist; |
155 | 163 | ||
164 | struct hist_browser_timer { | ||
165 | void (*timer)(void *arg); | ||
166 | void *arg; | ||
167 | int refresh; | ||
168 | }; | ||
169 | |||
156 | #ifdef NEWT_SUPPORT | 170 | #ifdef NEWT_SUPPORT |
157 | #include "../ui/keysyms.h" | 171 | #include "../ui/keysyms.h" |
158 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | 172 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, |
159 | void(*timer)(void *arg), void *arg, int delay_secs); | 173 | struct hist_browser_timer *hbt); |
160 | 174 | ||
161 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 175 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
162 | void(*timer)(void *arg), void *arg, | 176 | struct hist_browser_timer *hbt, |
163 | int refresh); | 177 | struct perf_session_env *env); |
178 | int script_browse(const char *script_opt); | ||
164 | #else | 179 | #else |
165 | static inline | 180 | static inline |
166 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, | 181 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, |
167 | const char *help __maybe_unused, | 182 | const char *help __maybe_unused, |
168 | void(*timer)(void *arg) __maybe_unused, | 183 | struct hist_browser_timer *hbt __maybe_unused, |
169 | void *arg __maybe_unused, | 184 | struct perf_session_env *env __maybe_unused) |
170 | int refresh __maybe_unused) | ||
171 | { | 185 | { |
172 | return 0; | 186 | return 0; |
173 | } | 187 | } |
@@ -175,28 +189,29 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
175 | static inline int hist_entry__tui_annotate(struct hist_entry *self | 189 | static inline int hist_entry__tui_annotate(struct hist_entry *self |
176 | __maybe_unused, | 190 | __maybe_unused, |
177 | int evidx __maybe_unused, | 191 | int evidx __maybe_unused, |
178 | void(*timer)(void *arg) | 192 | struct hist_browser_timer *hbt |
179 | __maybe_unused, | 193 | __maybe_unused) |
180 | void *arg __maybe_unused, | ||
181 | int delay_secs __maybe_unused) | ||
182 | { | 194 | { |
183 | return 0; | 195 | return 0; |
184 | } | 196 | } |
197 | |||
198 | static inline int script_browse(const char *script_opt __maybe_unused) | ||
199 | { | ||
200 | return 0; | ||
201 | } | ||
202 | |||
185 | #define K_LEFT -1 | 203 | #define K_LEFT -1 |
186 | #define K_RIGHT -2 | 204 | #define K_RIGHT -2 |
187 | #endif | 205 | #endif |
188 | 206 | ||
189 | #ifdef GTK2_SUPPORT | 207 | #ifdef GTK2_SUPPORT |
190 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, | 208 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, |
191 | void(*timer)(void *arg), void *arg, | 209 | struct hist_browser_timer *hbt __maybe_unused); |
192 | int refresh); | ||
193 | #else | 210 | #else |
194 | static inline | 211 | static inline |
195 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | 212 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, |
196 | const char *help __maybe_unused, | 213 | const char *help __maybe_unused, |
197 | void(*timer)(void *arg) __maybe_unused, | 214 | struct hist_browser_timer *hbt __maybe_unused) |
198 | void *arg __maybe_unused, | ||
199 | int refresh __maybe_unused) | ||
200 | { | 215 | { |
201 | return 0; | 216 | return 0; |
202 | } | 217 | } |
@@ -204,4 +219,8 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
204 | 219 | ||
205 | unsigned int hists__sort_list_width(struct hists *self); | 220 | unsigned int hists__sort_list_width(struct hists *self); |
206 | 221 | ||
222 | double perf_diff__compute_delta(struct hist_entry *he); | ||
223 | double perf_diff__compute_ratio(struct hist_entry *he); | ||
224 | s64 perf_diff__compute_wdiff(struct hist_entry *he); | ||
225 | int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); | ||
207 | #endif /* __PERF_HIST_H */ | 226 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c new file mode 100644 index 000000000000..1f09d0581e6b --- /dev/null +++ b/tools/perf/util/machine.c | |||
@@ -0,0 +1,464 @@ | |||
1 | #include "debug.h" | ||
2 | #include "event.h" | ||
3 | #include "machine.h" | ||
4 | #include "map.h" | ||
5 | #include "strlist.h" | ||
6 | #include "thread.h" | ||
7 | #include <stdbool.h> | ||
8 | |||
9 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | ||
10 | { | ||
11 | map_groups__init(&machine->kmaps); | ||
12 | RB_CLEAR_NODE(&machine->rb_node); | ||
13 | INIT_LIST_HEAD(&machine->user_dsos); | ||
14 | INIT_LIST_HEAD(&machine->kernel_dsos); | ||
15 | |||
16 | machine->threads = RB_ROOT; | ||
17 | INIT_LIST_HEAD(&machine->dead_threads); | ||
18 | machine->last_match = NULL; | ||
19 | |||
20 | machine->kmaps.machine = machine; | ||
21 | machine->pid = pid; | ||
22 | |||
23 | machine->root_dir = strdup(root_dir); | ||
24 | if (machine->root_dir == NULL) | ||
25 | return -ENOMEM; | ||
26 | |||
27 | if (pid != HOST_KERNEL_ID) { | ||
28 | struct thread *thread = machine__findnew_thread(machine, pid); | ||
29 | char comm[64]; | ||
30 | |||
31 | if (thread == NULL) | ||
32 | return -ENOMEM; | ||
33 | |||
34 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); | ||
35 | thread__set_comm(thread, comm); | ||
36 | } | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void dsos__delete(struct list_head *dsos) | ||
42 | { | ||
43 | struct dso *pos, *n; | ||
44 | |||
45 | list_for_each_entry_safe(pos, n, dsos, node) { | ||
46 | list_del(&pos->node); | ||
47 | dso__delete(pos); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | void machine__exit(struct machine *machine) | ||
52 | { | ||
53 | map_groups__exit(&machine->kmaps); | ||
54 | dsos__delete(&machine->user_dsos); | ||
55 | dsos__delete(&machine->kernel_dsos); | ||
56 | free(machine->root_dir); | ||
57 | machine->root_dir = NULL; | ||
58 | } | ||
59 | |||
60 | void machine__delete(struct machine *machine) | ||
61 | { | ||
62 | machine__exit(machine); | ||
63 | free(machine); | ||
64 | } | ||
65 | |||
66 | struct machine *machines__add(struct rb_root *machines, pid_t pid, | ||
67 | const char *root_dir) | ||
68 | { | ||
69 | struct rb_node **p = &machines->rb_node; | ||
70 | struct rb_node *parent = NULL; | ||
71 | struct machine *pos, *machine = malloc(sizeof(*machine)); | ||
72 | |||
73 | if (machine == NULL) | ||
74 | return NULL; | ||
75 | |||
76 | if (machine__init(machine, root_dir, pid) != 0) { | ||
77 | free(machine); | ||
78 | return NULL; | ||
79 | } | ||
80 | |||
81 | while (*p != NULL) { | ||
82 | parent = *p; | ||
83 | pos = rb_entry(parent, struct machine, rb_node); | ||
84 | if (pid < pos->pid) | ||
85 | p = &(*p)->rb_left; | ||
86 | else | ||
87 | p = &(*p)->rb_right; | ||
88 | } | ||
89 | |||
90 | rb_link_node(&machine->rb_node, parent, p); | ||
91 | rb_insert_color(&machine->rb_node, machines); | ||
92 | |||
93 | return machine; | ||
94 | } | ||
95 | |||
96 | struct machine *machines__find(struct rb_root *machines, pid_t pid) | ||
97 | { | ||
98 | struct rb_node **p = &machines->rb_node; | ||
99 | struct rb_node *parent = NULL; | ||
100 | struct machine *machine; | ||
101 | struct machine *default_machine = NULL; | ||
102 | |||
103 | while (*p != NULL) { | ||
104 | parent = *p; | ||
105 | machine = rb_entry(parent, struct machine, rb_node); | ||
106 | if (pid < machine->pid) | ||
107 | p = &(*p)->rb_left; | ||
108 | else if (pid > machine->pid) | ||
109 | p = &(*p)->rb_right; | ||
110 | else | ||
111 | return machine; | ||
112 | if (!machine->pid) | ||
113 | default_machine = machine; | ||
114 | } | ||
115 | |||
116 | return default_machine; | ||
117 | } | ||
118 | |||
119 | struct machine *machines__findnew(struct rb_root *machines, pid_t pid) | ||
120 | { | ||
121 | char path[PATH_MAX]; | ||
122 | const char *root_dir = ""; | ||
123 | struct machine *machine = machines__find(machines, pid); | ||
124 | |||
125 | if (machine && (machine->pid == pid)) | ||
126 | goto out; | ||
127 | |||
128 | if ((pid != HOST_KERNEL_ID) && | ||
129 | (pid != DEFAULT_GUEST_KERNEL_ID) && | ||
130 | (symbol_conf.guestmount)) { | ||
131 | sprintf(path, "%s/%d", symbol_conf.guestmount, pid); | ||
132 | if (access(path, R_OK)) { | ||
133 | static struct strlist *seen; | ||
134 | |||
135 | if (!seen) | ||
136 | seen = strlist__new(true, NULL); | ||
137 | |||
138 | if (!strlist__has_entry(seen, path)) { | ||
139 | pr_err("Can't access file %s\n", path); | ||
140 | strlist__add(seen, path); | ||
141 | } | ||
142 | machine = NULL; | ||
143 | goto out; | ||
144 | } | ||
145 | root_dir = path; | ||
146 | } | ||
147 | |||
148 | machine = machines__add(machines, pid, root_dir); | ||
149 | out: | ||
150 | return machine; | ||
151 | } | ||
152 | |||
153 | void machines__process(struct rb_root *machines, | ||
154 | machine__process_t process, void *data) | ||
155 | { | ||
156 | struct rb_node *nd; | ||
157 | |||
158 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { | ||
159 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
160 | process(pos, data); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | char *machine__mmap_name(struct machine *machine, char *bf, size_t size) | ||
165 | { | ||
166 | if (machine__is_host(machine)) | ||
167 | snprintf(bf, size, "[%s]", "kernel.kallsyms"); | ||
168 | else if (machine__is_default_guest(machine)) | ||
169 | snprintf(bf, size, "[%s]", "guest.kernel.kallsyms"); | ||
170 | else { | ||
171 | snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", | ||
172 | machine->pid); | ||
173 | } | ||
174 | |||
175 | return bf; | ||
176 | } | ||
177 | |||
178 | void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) | ||
179 | { | ||
180 | struct rb_node *node; | ||
181 | struct machine *machine; | ||
182 | |||
183 | for (node = rb_first(machines); node; node = rb_next(node)) { | ||
184 | machine = rb_entry(node, struct machine, rb_node); | ||
185 | machine->id_hdr_size = id_hdr_size; | ||
186 | } | ||
187 | |||
188 | return; | ||
189 | } | ||
190 | |||
191 | static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, | ||
192 | bool create) | ||
193 | { | ||
194 | struct rb_node **p = &machine->threads.rb_node; | ||
195 | struct rb_node *parent = NULL; | ||
196 | struct thread *th; | ||
197 | |||
198 | /* | ||
199 | * Font-end cache - PID lookups come in blocks, | ||
200 | * so most of the time we dont have to look up | ||
201 | * the full rbtree: | ||
202 | */ | ||
203 | if (machine->last_match && machine->last_match->pid == pid) | ||
204 | return machine->last_match; | ||
205 | |||
206 | while (*p != NULL) { | ||
207 | parent = *p; | ||
208 | th = rb_entry(parent, struct thread, rb_node); | ||
209 | |||
210 | if (th->pid == pid) { | ||
211 | machine->last_match = th; | ||
212 | return th; | ||
213 | } | ||
214 | |||
215 | if (pid < th->pid) | ||
216 | p = &(*p)->rb_left; | ||
217 | else | ||
218 | p = &(*p)->rb_right; | ||
219 | } | ||
220 | |||
221 | if (!create) | ||
222 | return NULL; | ||
223 | |||
224 | th = thread__new(pid); | ||
225 | if (th != NULL) { | ||
226 | rb_link_node(&th->rb_node, parent, p); | ||
227 | rb_insert_color(&th->rb_node, &machine->threads); | ||
228 | machine->last_match = th; | ||
229 | } | ||
230 | |||
231 | return th; | ||
232 | } | ||
233 | |||
234 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) | ||
235 | { | ||
236 | return __machine__findnew_thread(machine, pid, true); | ||
237 | } | ||
238 | |||
239 | struct thread *machine__find_thread(struct machine *machine, pid_t pid) | ||
240 | { | ||
241 | return __machine__findnew_thread(machine, pid, false); | ||
242 | } | ||
243 | |||
244 | int machine__process_comm_event(struct machine *machine, union perf_event *event) | ||
245 | { | ||
246 | struct thread *thread = machine__findnew_thread(machine, event->comm.tid); | ||
247 | |||
248 | if (dump_trace) | ||
249 | perf_event__fprintf_comm(event, stdout); | ||
250 | |||
251 | if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { | ||
252 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); | ||
253 | return -1; | ||
254 | } | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | int machine__process_lost_event(struct machine *machine __maybe_unused, | ||
260 | union perf_event *event) | ||
261 | { | ||
262 | dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", | ||
263 | event->lost.id, event->lost.lost); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static void machine__set_kernel_mmap_len(struct machine *machine, | ||
268 | union perf_event *event) | ||
269 | { | ||
270 | int i; | ||
271 | |||
272 | for (i = 0; i < MAP__NR_TYPES; i++) { | ||
273 | machine->vmlinux_maps[i]->start = event->mmap.start; | ||
274 | machine->vmlinux_maps[i]->end = (event->mmap.start + | ||
275 | event->mmap.len); | ||
276 | /* | ||
277 | * Be a bit paranoid here, some perf.data file came with | ||
278 | * a zero sized synthesized MMAP event for the kernel. | ||
279 | */ | ||
280 | if (machine->vmlinux_maps[i]->end == 0) | ||
281 | machine->vmlinux_maps[i]->end = ~0ULL; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static int machine__process_kernel_mmap_event(struct machine *machine, | ||
286 | union perf_event *event) | ||
287 | { | ||
288 | struct map *map; | ||
289 | char kmmap_prefix[PATH_MAX]; | ||
290 | enum dso_kernel_type kernel_type; | ||
291 | bool is_kernel_mmap; | ||
292 | |||
293 | machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); | ||
294 | if (machine__is_host(machine)) | ||
295 | kernel_type = DSO_TYPE_KERNEL; | ||
296 | else | ||
297 | kernel_type = DSO_TYPE_GUEST_KERNEL; | ||
298 | |||
299 | is_kernel_mmap = memcmp(event->mmap.filename, | ||
300 | kmmap_prefix, | ||
301 | strlen(kmmap_prefix) - 1) == 0; | ||
302 | if (event->mmap.filename[0] == '/' || | ||
303 | (!is_kernel_mmap && event->mmap.filename[0] == '[')) { | ||
304 | |||
305 | char short_module_name[1024]; | ||
306 | char *name, *dot; | ||
307 | |||
308 | if (event->mmap.filename[0] == '/') { | ||
309 | name = strrchr(event->mmap.filename, '/'); | ||
310 | if (name == NULL) | ||
311 | goto out_problem; | ||
312 | |||
313 | ++name; /* skip / */ | ||
314 | dot = strrchr(name, '.'); | ||
315 | if (dot == NULL) | ||
316 | goto out_problem; | ||
317 | snprintf(short_module_name, sizeof(short_module_name), | ||
318 | "[%.*s]", (int)(dot - name), name); | ||
319 | strxfrchar(short_module_name, '-', '_'); | ||
320 | } else | ||
321 | strcpy(short_module_name, event->mmap.filename); | ||
322 | |||
323 | map = machine__new_module(machine, event->mmap.start, | ||
324 | event->mmap.filename); | ||
325 | if (map == NULL) | ||
326 | goto out_problem; | ||
327 | |||
328 | name = strdup(short_module_name); | ||
329 | if (name == NULL) | ||
330 | goto out_problem; | ||
331 | |||
332 | map->dso->short_name = name; | ||
333 | map->dso->sname_alloc = 1; | ||
334 | map->end = map->start + event->mmap.len; | ||
335 | } else if (is_kernel_mmap) { | ||
336 | const char *symbol_name = (event->mmap.filename + | ||
337 | strlen(kmmap_prefix)); | ||
338 | /* | ||
339 | * Should be there already, from the build-id table in | ||
340 | * the header. | ||
341 | */ | ||
342 | struct dso *kernel = __dsos__findnew(&machine->kernel_dsos, | ||
343 | kmmap_prefix); | ||
344 | if (kernel == NULL) | ||
345 | goto out_problem; | ||
346 | |||
347 | kernel->kernel = kernel_type; | ||
348 | if (__machine__create_kernel_maps(machine, kernel) < 0) | ||
349 | goto out_problem; | ||
350 | |||
351 | machine__set_kernel_mmap_len(machine, event); | ||
352 | |||
353 | /* | ||
354 | * Avoid using a zero address (kptr_restrict) for the ref reloc | ||
355 | * symbol. Effectively having zero here means that at record | ||
356 | * time /proc/sys/kernel/kptr_restrict was non zero. | ||
357 | */ | ||
358 | if (event->mmap.pgoff != 0) { | ||
359 | maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, | ||
360 | symbol_name, | ||
361 | event->mmap.pgoff); | ||
362 | } | ||
363 | |||
364 | if (machine__is_default_guest(machine)) { | ||
365 | /* | ||
366 | * preload dso of guest kernel and modules | ||
367 | */ | ||
368 | dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION], | ||
369 | NULL); | ||
370 | } | ||
371 | } | ||
372 | return 0; | ||
373 | out_problem: | ||
374 | return -1; | ||
375 | } | ||
376 | |||
377 | int machine__process_mmap_event(struct machine *machine, union perf_event *event) | ||
378 | { | ||
379 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | ||
380 | struct thread *thread; | ||
381 | struct map *map; | ||
382 | int ret = 0; | ||
383 | |||
384 | if (dump_trace) | ||
385 | perf_event__fprintf_mmap(event, stdout); | ||
386 | |||
387 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || | ||
388 | cpumode == PERF_RECORD_MISC_KERNEL) { | ||
389 | ret = machine__process_kernel_mmap_event(machine, event); | ||
390 | if (ret < 0) | ||
391 | goto out_problem; | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | thread = machine__findnew_thread(machine, event->mmap.pid); | ||
396 | if (thread == NULL) | ||
397 | goto out_problem; | ||
398 | map = map__new(&machine->user_dsos, event->mmap.start, | ||
399 | event->mmap.len, event->mmap.pgoff, | ||
400 | event->mmap.pid, event->mmap.filename, | ||
401 | MAP__FUNCTION); | ||
402 | if (map == NULL) | ||
403 | goto out_problem; | ||
404 | |||
405 | thread__insert_map(thread, map); | ||
406 | return 0; | ||
407 | |||
408 | out_problem: | ||
409 | dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | int machine__process_fork_event(struct machine *machine, union perf_event *event) | ||
414 | { | ||
415 | struct thread *thread = machine__findnew_thread(machine, event->fork.tid); | ||
416 | struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); | ||
417 | |||
418 | if (dump_trace) | ||
419 | perf_event__fprintf_task(event, stdout); | ||
420 | |||
421 | if (thread == NULL || parent == NULL || | ||
422 | thread__fork(thread, parent) < 0) { | ||
423 | dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); | ||
424 | return -1; | ||
425 | } | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | int machine__process_exit_event(struct machine *machine, union perf_event *event) | ||
431 | { | ||
432 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | ||
433 | |||
434 | if (dump_trace) | ||
435 | perf_event__fprintf_task(event, stdout); | ||
436 | |||
437 | if (thread != NULL) | ||
438 | machine__remove_thread(machine, thread); | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | int machine__process_event(struct machine *machine, union perf_event *event) | ||
444 | { | ||
445 | int ret; | ||
446 | |||
447 | switch (event->header.type) { | ||
448 | case PERF_RECORD_COMM: | ||
449 | ret = machine__process_comm_event(machine, event); break; | ||
450 | case PERF_RECORD_MMAP: | ||
451 | ret = machine__process_mmap_event(machine, event); break; | ||
452 | case PERF_RECORD_FORK: | ||
453 | ret = machine__process_fork_event(machine, event); break; | ||
454 | case PERF_RECORD_EXIT: | ||
455 | ret = machine__process_exit_event(machine, event); break; | ||
456 | case PERF_RECORD_LOST: | ||
457 | ret = machine__process_lost_event(machine, event); break; | ||
458 | default: | ||
459 | ret = -1; | ||
460 | break; | ||
461 | } | ||
462 | |||
463 | return ret; | ||
464 | } | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h new file mode 100644 index 000000000000..b7cde7467d55 --- /dev/null +++ b/tools/perf/util/machine.h | |||
@@ -0,0 +1,148 @@ | |||
1 | #ifndef __PERF_MACHINE_H | ||
2 | #define __PERF_MACHINE_H | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | #include <linux/rbtree.h> | ||
6 | #include "map.h" | ||
7 | |||
8 | struct branch_stack; | ||
9 | struct perf_evsel; | ||
10 | struct perf_sample; | ||
11 | struct symbol; | ||
12 | struct thread; | ||
13 | union perf_event; | ||
14 | |||
15 | /* Native host kernel uses -1 as pid index in machine */ | ||
16 | #define HOST_KERNEL_ID (-1) | ||
17 | #define DEFAULT_GUEST_KERNEL_ID (0) | ||
18 | |||
19 | struct machine { | ||
20 | struct rb_node rb_node; | ||
21 | pid_t pid; | ||
22 | u16 id_hdr_size; | ||
23 | char *root_dir; | ||
24 | struct rb_root threads; | ||
25 | struct list_head dead_threads; | ||
26 | struct thread *last_match; | ||
27 | struct list_head user_dsos; | ||
28 | struct list_head kernel_dsos; | ||
29 | struct map_groups kmaps; | ||
30 | struct map *vmlinux_maps[MAP__NR_TYPES]; | ||
31 | }; | ||
32 | |||
33 | static inline | ||
34 | struct map *machine__kernel_map(struct machine *machine, enum map_type type) | ||
35 | { | ||
36 | return machine->vmlinux_maps[type]; | ||
37 | } | ||
38 | |||
39 | struct thread *machine__find_thread(struct machine *machine, pid_t pid); | ||
40 | |||
41 | int machine__process_comm_event(struct machine *machine, union perf_event *event); | ||
42 | int machine__process_exit_event(struct machine *machine, union perf_event *event); | ||
43 | int machine__process_fork_event(struct machine *machine, union perf_event *event); | ||
44 | int machine__process_lost_event(struct machine *machine, union perf_event *event); | ||
45 | int machine__process_mmap_event(struct machine *machine, union perf_event *event); | ||
46 | int machine__process_event(struct machine *machine, union perf_event *event); | ||
47 | |||
48 | typedef void (*machine__process_t)(struct machine *machine, void *data); | ||
49 | |||
50 | void machines__process(struct rb_root *machines, | ||
51 | machine__process_t process, void *data); | ||
52 | |||
53 | struct machine *machines__add(struct rb_root *machines, pid_t pid, | ||
54 | const char *root_dir); | ||
55 | struct machine *machines__find_host(struct rb_root *machines); | ||
56 | struct machine *machines__find(struct rb_root *machines, pid_t pid); | ||
57 | struct machine *machines__findnew(struct rb_root *machines, pid_t pid); | ||
58 | |||
59 | void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size); | ||
60 | char *machine__mmap_name(struct machine *machine, char *bf, size_t size); | ||
61 | |||
62 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); | ||
63 | void machine__exit(struct machine *machine); | ||
64 | void machine__delete(struct machine *machine); | ||
65 | |||
66 | |||
67 | struct branch_info *machine__resolve_bstack(struct machine *machine, | ||
68 | struct thread *thread, | ||
69 | struct branch_stack *bs); | ||
70 | int machine__resolve_callchain(struct machine *machine, | ||
71 | struct perf_evsel *evsel, | ||
72 | struct thread *thread, | ||
73 | struct perf_sample *sample, | ||
74 | struct symbol **parent); | ||
75 | |||
76 | /* | ||
77 | * Default guest kernel is defined by parameter --guestkallsyms | ||
78 | * and --guestmodules | ||
79 | */ | ||
80 | static inline bool machine__is_default_guest(struct machine *machine) | ||
81 | { | ||
82 | return machine ? machine->pid == DEFAULT_GUEST_KERNEL_ID : false; | ||
83 | } | ||
84 | |||
85 | static inline bool machine__is_host(struct machine *machine) | ||
86 | { | ||
87 | return machine ? machine->pid == HOST_KERNEL_ID : false; | ||
88 | } | ||
89 | |||
90 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); | ||
91 | void machine__remove_thread(struct machine *machine, struct thread *th); | ||
92 | |||
93 | size_t machine__fprintf(struct machine *machine, FILE *fp); | ||
94 | |||
95 | static inline | ||
96 | struct symbol *machine__find_kernel_symbol(struct machine *machine, | ||
97 | enum map_type type, u64 addr, | ||
98 | struct map **mapp, | ||
99 | symbol_filter_t filter) | ||
100 | { | ||
101 | return map_groups__find_symbol(&machine->kmaps, type, addr, | ||
102 | mapp, filter); | ||
103 | } | ||
104 | |||
105 | static inline | ||
106 | struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr, | ||
107 | struct map **mapp, | ||
108 | symbol_filter_t filter) | ||
109 | { | ||
110 | return machine__find_kernel_symbol(machine, MAP__FUNCTION, addr, | ||
111 | mapp, filter); | ||
112 | } | ||
113 | |||
114 | static inline | ||
115 | struct symbol *machine__find_kernel_function_by_name(struct machine *machine, | ||
116 | const char *name, | ||
117 | struct map **mapp, | ||
118 | symbol_filter_t filter) | ||
119 | { | ||
120 | return map_groups__find_function_by_name(&machine->kmaps, name, mapp, | ||
121 | filter); | ||
122 | } | ||
123 | |||
124 | struct map *machine__new_module(struct machine *machine, u64 start, | ||
125 | const char *filename); | ||
126 | |||
127 | int machine__load_kallsyms(struct machine *machine, const char *filename, | ||
128 | enum map_type type, symbol_filter_t filter); | ||
129 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | ||
130 | symbol_filter_t filter); | ||
131 | |||
132 | size_t machine__fprintf_dsos_buildid(struct machine *machine, | ||
133 | FILE *fp, bool with_hits); | ||
134 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); | ||
135 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | ||
136 | FILE *fp, bool with_hits); | ||
137 | |||
138 | void machine__destroy_kernel_maps(struct machine *machine); | ||
139 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); | ||
140 | int machine__create_kernel_maps(struct machine *machine); | ||
141 | |||
142 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); | ||
143 | int machines__create_guest_kernel_maps(struct rb_root *machines); | ||
144 | void machines__destroy_guest_kernel_maps(struct rb_root *machines); | ||
145 | |||
146 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); | ||
147 | |||
148 | #endif /* __PERF_MACHINE_H */ | ||
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 6109fa4d14cd..0328d45c4f2a 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "thread.h" | 10 | #include "thread.h" |
11 | #include "strlist.h" | 11 | #include "strlist.h" |
12 | #include "vdso.h" | 12 | #include "vdso.h" |
13 | #include "build-id.h" | ||
13 | 14 | ||
14 | const char *map_type__name[MAP__NR_TYPES] = { | 15 | const char *map_type__name[MAP__NR_TYPES] = { |
15 | [MAP__FUNCTION] = "Functions", | 16 | [MAP__FUNCTION] = "Functions", |
@@ -23,7 +24,7 @@ static inline int is_anon_memory(const char *filename) | |||
23 | 24 | ||
24 | static inline int is_no_dso_memory(const char *filename) | 25 | static inline int is_no_dso_memory(const char *filename) |
25 | { | 26 | { |
26 | return !strcmp(filename, "[stack]") || | 27 | return !strncmp(filename, "[stack", 6) || |
27 | !strcmp(filename, "[heap]"); | 28 | !strcmp(filename, "[heap]"); |
28 | } | 29 | } |
29 | 30 | ||
@@ -589,182 +590,3 @@ struct map *maps__find(struct rb_root *maps, u64 ip) | |||
589 | 590 | ||
590 | return NULL; | 591 | return NULL; |
591 | } | 592 | } |
592 | |||
593 | int machine__init(struct machine *self, const char *root_dir, pid_t pid) | ||
594 | { | ||
595 | map_groups__init(&self->kmaps); | ||
596 | RB_CLEAR_NODE(&self->rb_node); | ||
597 | INIT_LIST_HEAD(&self->user_dsos); | ||
598 | INIT_LIST_HEAD(&self->kernel_dsos); | ||
599 | |||
600 | self->threads = RB_ROOT; | ||
601 | INIT_LIST_HEAD(&self->dead_threads); | ||
602 | self->last_match = NULL; | ||
603 | |||
604 | self->kmaps.machine = self; | ||
605 | self->pid = pid; | ||
606 | self->root_dir = strdup(root_dir); | ||
607 | if (self->root_dir == NULL) | ||
608 | return -ENOMEM; | ||
609 | |||
610 | if (pid != HOST_KERNEL_ID) { | ||
611 | struct thread *thread = machine__findnew_thread(self, pid); | ||
612 | char comm[64]; | ||
613 | |||
614 | if (thread == NULL) | ||
615 | return -ENOMEM; | ||
616 | |||
617 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); | ||
618 | thread__set_comm(thread, comm); | ||
619 | } | ||
620 | |||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | static void dsos__delete(struct list_head *self) | ||
625 | { | ||
626 | struct dso *pos, *n; | ||
627 | |||
628 | list_for_each_entry_safe(pos, n, self, node) { | ||
629 | list_del(&pos->node); | ||
630 | dso__delete(pos); | ||
631 | } | ||
632 | } | ||
633 | |||
634 | void machine__exit(struct machine *self) | ||
635 | { | ||
636 | map_groups__exit(&self->kmaps); | ||
637 | dsos__delete(&self->user_dsos); | ||
638 | dsos__delete(&self->kernel_dsos); | ||
639 | free(self->root_dir); | ||
640 | self->root_dir = NULL; | ||
641 | } | ||
642 | |||
643 | void machine__delete(struct machine *self) | ||
644 | { | ||
645 | machine__exit(self); | ||
646 | free(self); | ||
647 | } | ||
648 | |||
649 | struct machine *machines__add(struct rb_root *self, pid_t pid, | ||
650 | const char *root_dir) | ||
651 | { | ||
652 | struct rb_node **p = &self->rb_node; | ||
653 | struct rb_node *parent = NULL; | ||
654 | struct machine *pos, *machine = malloc(sizeof(*machine)); | ||
655 | |||
656 | if (!machine) | ||
657 | return NULL; | ||
658 | |||
659 | if (machine__init(machine, root_dir, pid) != 0) { | ||
660 | free(machine); | ||
661 | return NULL; | ||
662 | } | ||
663 | |||
664 | while (*p != NULL) { | ||
665 | parent = *p; | ||
666 | pos = rb_entry(parent, struct machine, rb_node); | ||
667 | if (pid < pos->pid) | ||
668 | p = &(*p)->rb_left; | ||
669 | else | ||
670 | p = &(*p)->rb_right; | ||
671 | } | ||
672 | |||
673 | rb_link_node(&machine->rb_node, parent, p); | ||
674 | rb_insert_color(&machine->rb_node, self); | ||
675 | |||
676 | return machine; | ||
677 | } | ||
678 | |||
679 | struct machine *machines__find(struct rb_root *self, pid_t pid) | ||
680 | { | ||
681 | struct rb_node **p = &self->rb_node; | ||
682 | struct rb_node *parent = NULL; | ||
683 | struct machine *machine; | ||
684 | struct machine *default_machine = NULL; | ||
685 | |||
686 | while (*p != NULL) { | ||
687 | parent = *p; | ||
688 | machine = rb_entry(parent, struct machine, rb_node); | ||
689 | if (pid < machine->pid) | ||
690 | p = &(*p)->rb_left; | ||
691 | else if (pid > machine->pid) | ||
692 | p = &(*p)->rb_right; | ||
693 | else | ||
694 | return machine; | ||
695 | if (!machine->pid) | ||
696 | default_machine = machine; | ||
697 | } | ||
698 | |||
699 | return default_machine; | ||
700 | } | ||
701 | |||
702 | struct machine *machines__findnew(struct rb_root *self, pid_t pid) | ||
703 | { | ||
704 | char path[PATH_MAX]; | ||
705 | const char *root_dir = ""; | ||
706 | struct machine *machine = machines__find(self, pid); | ||
707 | |||
708 | if (machine && (machine->pid == pid)) | ||
709 | goto out; | ||
710 | |||
711 | if ((pid != HOST_KERNEL_ID) && | ||
712 | (pid != DEFAULT_GUEST_KERNEL_ID) && | ||
713 | (symbol_conf.guestmount)) { | ||
714 | sprintf(path, "%s/%d", symbol_conf.guestmount, pid); | ||
715 | if (access(path, R_OK)) { | ||
716 | static struct strlist *seen; | ||
717 | |||
718 | if (!seen) | ||
719 | seen = strlist__new(true, NULL); | ||
720 | |||
721 | if (!strlist__has_entry(seen, path)) { | ||
722 | pr_err("Can't access file %s\n", path); | ||
723 | strlist__add(seen, path); | ||
724 | } | ||
725 | machine = NULL; | ||
726 | goto out; | ||
727 | } | ||
728 | root_dir = path; | ||
729 | } | ||
730 | |||
731 | machine = machines__add(self, pid, root_dir); | ||
732 | |||
733 | out: | ||
734 | return machine; | ||
735 | } | ||
736 | |||
737 | void machines__process(struct rb_root *self, machine__process_t process, void *data) | ||
738 | { | ||
739 | struct rb_node *nd; | ||
740 | |||
741 | for (nd = rb_first(self); nd; nd = rb_next(nd)) { | ||
742 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | ||
743 | process(pos, data); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | char *machine__mmap_name(struct machine *self, char *bf, size_t size) | ||
748 | { | ||
749 | if (machine__is_host(self)) | ||
750 | snprintf(bf, size, "[%s]", "kernel.kallsyms"); | ||
751 | else if (machine__is_default_guest(self)) | ||
752 | snprintf(bf, size, "[%s]", "guest.kernel.kallsyms"); | ||
753 | else | ||
754 | snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid); | ||
755 | |||
756 | return bf; | ||
757 | } | ||
758 | |||
759 | void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) | ||
760 | { | ||
761 | struct rb_node *node; | ||
762 | struct machine *machine; | ||
763 | |||
764 | for (node = rb_first(machines); node; node = rb_next(node)) { | ||
765 | machine = rb_entry(node, struct machine, rb_node); | ||
766 | machine->id_hdr_size = id_hdr_size; | ||
767 | } | ||
768 | |||
769 | return; | ||
770 | } | ||
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index d2250fc97e25..bcb39e2a6965 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -57,30 +57,6 @@ struct map_groups { | |||
57 | struct machine *machine; | 57 | struct machine *machine; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | /* Native host kernel uses -1 as pid index in machine */ | ||
61 | #define HOST_KERNEL_ID (-1) | ||
62 | #define DEFAULT_GUEST_KERNEL_ID (0) | ||
63 | |||
64 | struct machine { | ||
65 | struct rb_node rb_node; | ||
66 | pid_t pid; | ||
67 | u16 id_hdr_size; | ||
68 | char *root_dir; | ||
69 | struct rb_root threads; | ||
70 | struct list_head dead_threads; | ||
71 | struct thread *last_match; | ||
72 | struct list_head user_dsos; | ||
73 | struct list_head kernel_dsos; | ||
74 | struct map_groups kmaps; | ||
75 | struct map *vmlinux_maps[MAP__NR_TYPES]; | ||
76 | }; | ||
77 | |||
78 | static inline | ||
79 | struct map *machine__kernel_map(struct machine *self, enum map_type type) | ||
80 | { | ||
81 | return self->vmlinux_maps[type]; | ||
82 | } | ||
83 | |||
84 | static inline struct kmap *map__kmap(struct map *self) | 60 | static inline struct kmap *map__kmap(struct map *self) |
85 | { | 61 | { |
86 | return (struct kmap *)(self + 1); | 62 | return (struct kmap *)(self + 1); |
@@ -143,44 +119,9 @@ int map_groups__clone(struct map_groups *mg, | |||
143 | size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); | 119 | size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); |
144 | size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); | 120 | size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); |
145 | 121 | ||
146 | typedef void (*machine__process_t)(struct machine *self, void *data); | ||
147 | |||
148 | void machines__process(struct rb_root *self, machine__process_t process, void *data); | ||
149 | struct machine *machines__add(struct rb_root *self, pid_t pid, | ||
150 | const char *root_dir); | ||
151 | struct machine *machines__find_host(struct rb_root *self); | ||
152 | struct machine *machines__find(struct rb_root *self, pid_t pid); | ||
153 | struct machine *machines__findnew(struct rb_root *self, pid_t pid); | ||
154 | void machines__set_id_hdr_size(struct rb_root *self, u16 id_hdr_size); | ||
155 | char *machine__mmap_name(struct machine *self, char *bf, size_t size); | ||
156 | int machine__init(struct machine *self, const char *root_dir, pid_t pid); | ||
157 | void machine__exit(struct machine *self); | ||
158 | void machine__delete(struct machine *self); | ||
159 | |||
160 | struct perf_evsel; | ||
161 | struct perf_sample; | ||
162 | int machine__resolve_callchain(struct machine *machine, | ||
163 | struct perf_evsel *evsel, | ||
164 | struct thread *thread, | ||
165 | struct perf_sample *sample, | ||
166 | struct symbol **parent); | ||
167 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, | 122 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, |
168 | u64 addr); | 123 | u64 addr); |
169 | 124 | ||
170 | /* | ||
171 | * Default guest kernel is defined by parameter --guestkallsyms | ||
172 | * and --guestmodules | ||
173 | */ | ||
174 | static inline bool machine__is_default_guest(struct machine *self) | ||
175 | { | ||
176 | return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false; | ||
177 | } | ||
178 | |||
179 | static inline bool machine__is_host(struct machine *self) | ||
180 | { | ||
181 | return self ? self->pid == HOST_KERNEL_ID : false; | ||
182 | } | ||
183 | |||
184 | static inline void map_groups__insert(struct map_groups *mg, struct map *map) | 125 | static inline void map_groups__insert(struct map_groups *mg, struct map *map) |
185 | { | 126 | { |
186 | maps__insert(&mg->maps[map->type], map); | 127 | maps__insert(&mg->maps[map->type], map); |
@@ -209,29 +150,6 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, | |||
209 | struct map **mapp, | 150 | struct map **mapp, |
210 | symbol_filter_t filter); | 151 | symbol_filter_t filter); |
211 | 152 | ||
212 | |||
213 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); | ||
214 | void machine__remove_thread(struct machine *machine, struct thread *th); | ||
215 | |||
216 | size_t machine__fprintf(struct machine *machine, FILE *fp); | ||
217 | |||
218 | static inline | ||
219 | struct symbol *machine__find_kernel_symbol(struct machine *self, | ||
220 | enum map_type type, u64 addr, | ||
221 | struct map **mapp, | ||
222 | symbol_filter_t filter) | ||
223 | { | ||
224 | return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter); | ||
225 | } | ||
226 | |||
227 | static inline | ||
228 | struct symbol *machine__find_kernel_function(struct machine *self, u64 addr, | ||
229 | struct map **mapp, | ||
230 | symbol_filter_t filter) | ||
231 | { | ||
232 | return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter); | ||
233 | } | ||
234 | |||
235 | static inline | 153 | static inline |
236 | struct symbol *map_groups__find_function_by_name(struct map_groups *mg, | 154 | struct symbol *map_groups__find_function_by_name(struct map_groups *mg, |
237 | const char *name, struct map **mapp, | 155 | const char *name, struct map **mapp, |
@@ -240,22 +158,11 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *mg, | |||
240 | return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter); | 158 | return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter); |
241 | } | 159 | } |
242 | 160 | ||
243 | static inline | ||
244 | struct symbol *machine__find_kernel_function_by_name(struct machine *self, | ||
245 | const char *name, | ||
246 | struct map **mapp, | ||
247 | symbol_filter_t filter) | ||
248 | { | ||
249 | return map_groups__find_function_by_name(&self->kmaps, name, mapp, | ||
250 | filter); | ||
251 | } | ||
252 | |||
253 | int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, | 161 | int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, |
254 | int verbose, FILE *fp); | 162 | int verbose, FILE *fp); |
255 | 163 | ||
256 | struct map *map_groups__find_by_name(struct map_groups *mg, | 164 | struct map *map_groups__find_by_name(struct map_groups *mg, |
257 | enum map_type type, const char *name); | 165 | enum map_type type, const char *name); |
258 | struct map *machine__new_module(struct machine *self, u64 start, const char *filename); | ||
259 | 166 | ||
260 | void map_groups__flush(struct map_groups *mg); | 167 | void map_groups__flush(struct map_groups *mg); |
261 | 168 | ||
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c deleted file mode 100644 index 28c18d1d52c3..000000000000 --- a/tools/perf/util/parse-events-test.c +++ /dev/null | |||
@@ -1,1044 +0,0 @@ | |||
1 | |||
2 | #include "parse-events.h" | ||
3 | #include "evsel.h" | ||
4 | #include "evlist.h" | ||
5 | #include "sysfs.h" | ||
6 | #include "../../../include/linux/hw_breakpoint.h" | ||
7 | |||
8 | #define TEST_ASSERT_VAL(text, cond) \ | ||
9 | do { \ | ||
10 | if (!(cond)) { \ | ||
11 | pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ | ||
12 | return -1; \ | ||
13 | } \ | ||
14 | } while (0) | ||
15 | |||
16 | #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ | ||
17 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) | ||
18 | |||
19 | static int test__checkevent_tracepoint(struct perf_evlist *evlist) | ||
20 | { | ||
21 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
22 | |||
23 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
24 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); | ||
25 | TEST_ASSERT_VAL("wrong sample_type", | ||
26 | PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); | ||
27 | TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); | ||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) | ||
32 | { | ||
33 | struct perf_evsel *evsel; | ||
34 | |||
35 | TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); | ||
36 | |||
37 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
38 | TEST_ASSERT_VAL("wrong type", | ||
39 | PERF_TYPE_TRACEPOINT == evsel->attr.type); | ||
40 | TEST_ASSERT_VAL("wrong sample_type", | ||
41 | PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); | ||
42 | TEST_ASSERT_VAL("wrong sample_period", | ||
43 | 1 == evsel->attr.sample_period); | ||
44 | } | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static int test__checkevent_raw(struct perf_evlist *evlist) | ||
49 | { | ||
50 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
51 | |||
52 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
53 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); | ||
54 | TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config); | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int test__checkevent_numeric(struct perf_evlist *evlist) | ||
59 | { | ||
60 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
61 | |||
62 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
63 | TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); | ||
64 | TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int test__checkevent_symbolic_name(struct perf_evlist *evlist) | ||
69 | { | ||
70 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
71 | |||
72 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
73 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
74 | TEST_ASSERT_VAL("wrong config", | ||
75 | PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist) | ||
80 | { | ||
81 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
82 | |||
83 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
84 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
85 | TEST_ASSERT_VAL("wrong config", | ||
86 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
87 | TEST_ASSERT_VAL("wrong period", | ||
88 | 100000 == evsel->attr.sample_period); | ||
89 | TEST_ASSERT_VAL("wrong config1", | ||
90 | 0 == evsel->attr.config1); | ||
91 | TEST_ASSERT_VAL("wrong config2", | ||
92 | 1 == evsel->attr.config2); | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int test__checkevent_symbolic_alias(struct perf_evlist *evlist) | ||
97 | { | ||
98 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
99 | |||
100 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
101 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type); | ||
102 | TEST_ASSERT_VAL("wrong config", | ||
103 | PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int test__checkevent_genhw(struct perf_evlist *evlist) | ||
108 | { | ||
109 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
110 | |||
111 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
112 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type); | ||
113 | TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int test__checkevent_breakpoint(struct perf_evlist *evlist) | ||
118 | { | ||
119 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
120 | |||
121 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
122 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); | ||
123 | TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); | ||
124 | TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) == | ||
125 | evsel->attr.bp_type); | ||
126 | TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 == | ||
127 | evsel->attr.bp_len); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int test__checkevent_breakpoint_x(struct perf_evlist *evlist) | ||
132 | { | ||
133 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
134 | |||
135 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
136 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type); | ||
137 | TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); | ||
138 | TEST_ASSERT_VAL("wrong bp_type", | ||
139 | HW_BREAKPOINT_X == evsel->attr.bp_type); | ||
140 | TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int test__checkevent_breakpoint_r(struct perf_evlist *evlist) | ||
145 | { | ||
146 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
147 | |||
148 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
149 | TEST_ASSERT_VAL("wrong type", | ||
150 | PERF_TYPE_BREAKPOINT == evsel->attr.type); | ||
151 | TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); | ||
152 | TEST_ASSERT_VAL("wrong bp_type", | ||
153 | HW_BREAKPOINT_R == evsel->attr.bp_type); | ||
154 | TEST_ASSERT_VAL("wrong bp_len", | ||
155 | HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int test__checkevent_breakpoint_w(struct perf_evlist *evlist) | ||
160 | { | ||
161 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
162 | |||
163 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
164 | TEST_ASSERT_VAL("wrong type", | ||
165 | PERF_TYPE_BREAKPOINT == evsel->attr.type); | ||
166 | TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); | ||
167 | TEST_ASSERT_VAL("wrong bp_type", | ||
168 | HW_BREAKPOINT_W == evsel->attr.bp_type); | ||
169 | TEST_ASSERT_VAL("wrong bp_len", | ||
170 | HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int test__checkevent_breakpoint_rw(struct perf_evlist *evlist) | ||
175 | { | ||
176 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
177 | |||
178 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
179 | TEST_ASSERT_VAL("wrong type", | ||
180 | PERF_TYPE_BREAKPOINT == evsel->attr.type); | ||
181 | TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); | ||
182 | TEST_ASSERT_VAL("wrong bp_type", | ||
183 | (HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->attr.bp_type); | ||
184 | TEST_ASSERT_VAL("wrong bp_len", | ||
185 | HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) | ||
190 | { | ||
191 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
192 | |||
193 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
194 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
195 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
196 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
197 | |||
198 | return test__checkevent_tracepoint(evlist); | ||
199 | } | ||
200 | |||
201 | static int | ||
202 | test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) | ||
203 | { | ||
204 | struct perf_evsel *evsel; | ||
205 | |||
206 | TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); | ||
207 | |||
208 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
209 | TEST_ASSERT_VAL("wrong exclude_user", | ||
210 | !evsel->attr.exclude_user); | ||
211 | TEST_ASSERT_VAL("wrong exclude_kernel", | ||
212 | evsel->attr.exclude_kernel); | ||
213 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
214 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
215 | } | ||
216 | |||
217 | return test__checkevent_tracepoint_multi(evlist); | ||
218 | } | ||
219 | |||
220 | static int test__checkevent_raw_modifier(struct perf_evlist *evlist) | ||
221 | { | ||
222 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
223 | |||
224 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
225 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
226 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
227 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | ||
228 | |||
229 | return test__checkevent_raw(evlist); | ||
230 | } | ||
231 | |||
232 | static int test__checkevent_numeric_modifier(struct perf_evlist *evlist) | ||
233 | { | ||
234 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
235 | |||
236 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
237 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
238 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
239 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | ||
240 | |||
241 | return test__checkevent_numeric(evlist); | ||
242 | } | ||
243 | |||
244 | static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist) | ||
245 | { | ||
246 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
247 | |||
248 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
249 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
250 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
251 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
252 | |||
253 | return test__checkevent_symbolic_name(evlist); | ||
254 | } | ||
255 | |||
256 | static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist) | ||
257 | { | ||
258 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
259 | |||
260 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
261 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
262 | |||
263 | return test__checkevent_symbolic_name(evlist); | ||
264 | } | ||
265 | |||
266 | static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist) | ||
267 | { | ||
268 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
269 | |||
270 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
271 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
272 | |||
273 | return test__checkevent_symbolic_name(evlist); | ||
274 | } | ||
275 | |||
276 | static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist) | ||
277 | { | ||
278 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
279 | |||
280 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
281 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
282 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
283 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
284 | |||
285 | return test__checkevent_symbolic_alias(evlist); | ||
286 | } | ||
287 | |||
288 | static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) | ||
289 | { | ||
290 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
291 | |||
292 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
293 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
294 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
295 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | ||
296 | |||
297 | return test__checkevent_genhw(evlist); | ||
298 | } | ||
299 | |||
300 | static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) | ||
301 | { | ||
302 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
303 | |||
304 | |||
305 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
306 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
307 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
308 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
309 | TEST_ASSERT_VAL("wrong name", | ||
310 | !strcmp(perf_evsel__name(evsel), "mem:0:u")); | ||
311 | |||
312 | return test__checkevent_breakpoint(evlist); | ||
313 | } | ||
314 | |||
315 | static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) | ||
316 | { | ||
317 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
318 | |||
319 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
320 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
321 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
322 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
323 | TEST_ASSERT_VAL("wrong name", | ||
324 | !strcmp(perf_evsel__name(evsel), "mem:0:x:k")); | ||
325 | |||
326 | return test__checkevent_breakpoint_x(evlist); | ||
327 | } | ||
328 | |||
329 | static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) | ||
330 | { | ||
331 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
332 | |||
333 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
334 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
335 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
336 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | ||
337 | TEST_ASSERT_VAL("wrong name", | ||
338 | !strcmp(perf_evsel__name(evsel), "mem:0:r:hp")); | ||
339 | |||
340 | return test__checkevent_breakpoint_r(evlist); | ||
341 | } | ||
342 | |||
343 | static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) | ||
344 | { | ||
345 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
346 | |||
347 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
348 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
349 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
350 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | ||
351 | TEST_ASSERT_VAL("wrong name", | ||
352 | !strcmp(perf_evsel__name(evsel), "mem:0:w:up")); | ||
353 | |||
354 | return test__checkevent_breakpoint_w(evlist); | ||
355 | } | ||
356 | |||
357 | static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist) | ||
358 | { | ||
359 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
360 | |||
361 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
362 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
363 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
364 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | ||
365 | TEST_ASSERT_VAL("wrong name", | ||
366 | !strcmp(perf_evsel__name(evsel), "mem:0:rw:kp")); | ||
367 | |||
368 | return test__checkevent_breakpoint_rw(evlist); | ||
369 | } | ||
370 | |||
371 | static int test__checkevent_pmu(struct perf_evlist *evlist) | ||
372 | { | ||
373 | |||
374 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
375 | |||
376 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
377 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); | ||
378 | TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config); | ||
379 | TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1); | ||
380 | TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2); | ||
381 | TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static int test__checkevent_list(struct perf_evlist *evlist) | ||
387 | { | ||
388 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
389 | |||
390 | TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); | ||
391 | |||
392 | /* r1 */ | ||
393 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); | ||
394 | TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); | ||
395 | TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1); | ||
396 | TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2); | ||
397 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
398 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
399 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
400 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
401 | |||
402 | /* syscalls:sys_enter_open:k */ | ||
403 | evsel = perf_evsel__next(evsel); | ||
404 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); | ||
405 | TEST_ASSERT_VAL("wrong sample_type", | ||
406 | PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); | ||
407 | TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); | ||
408 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
409 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
410 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
411 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
412 | |||
413 | /* 1:1:hp */ | ||
414 | evsel = perf_evsel__next(evsel); | ||
415 | TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); | ||
416 | TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); | ||
417 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
418 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
419 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
420 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int test__checkevent_pmu_name(struct perf_evlist *evlist) | ||
426 | { | ||
427 | struct perf_evsel *evsel = perf_evlist__first(evlist); | ||
428 | |||
429 | /* cpu/config=1,name=krava/u */ | ||
430 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
431 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); | ||
432 | TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); | ||
433 | TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava")); | ||
434 | |||
435 | /* cpu/config=2/u" */ | ||
436 | evsel = perf_evsel__next(evsel); | ||
437 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
438 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); | ||
439 | TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); | ||
440 | TEST_ASSERT_VAL("wrong name", | ||
441 | !strcmp(perf_evsel__name(evsel), "cpu/config=2/u")); | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static int test__checkterms_simple(struct list_head *terms) | ||
447 | { | ||
448 | struct parse_events__term *term; | ||
449 | |||
450 | /* config=10 */ | ||
451 | term = list_entry(terms->next, struct parse_events__term, list); | ||
452 | TEST_ASSERT_VAL("wrong type term", | ||
453 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); | ||
454 | TEST_ASSERT_VAL("wrong type val", | ||
455 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
456 | TEST_ASSERT_VAL("wrong val", term->val.num == 10); | ||
457 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
458 | |||
459 | /* config1 */ | ||
460 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
461 | TEST_ASSERT_VAL("wrong type term", | ||
462 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); | ||
463 | TEST_ASSERT_VAL("wrong type val", | ||
464 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
465 | TEST_ASSERT_VAL("wrong val", term->val.num == 1); | ||
466 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
467 | |||
468 | /* config2=3 */ | ||
469 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
470 | TEST_ASSERT_VAL("wrong type term", | ||
471 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); | ||
472 | TEST_ASSERT_VAL("wrong type val", | ||
473 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
474 | TEST_ASSERT_VAL("wrong val", term->val.num == 3); | ||
475 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
476 | |||
477 | /* umask=1*/ | ||
478 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
479 | TEST_ASSERT_VAL("wrong type term", | ||
480 | term->type_term == PARSE_EVENTS__TERM_TYPE_USER); | ||
481 | TEST_ASSERT_VAL("wrong type val", | ||
482 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
483 | TEST_ASSERT_VAL("wrong val", term->val.num == 1); | ||
484 | TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "umask")); | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int test__group1(struct perf_evlist *evlist) | ||
490 | { | ||
491 | struct perf_evsel *evsel, *leader; | ||
492 | |||
493 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
494 | |||
495 | /* instructions:k */ | ||
496 | evsel = leader = perf_evlist__first(evlist); | ||
497 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
498 | TEST_ASSERT_VAL("wrong config", | ||
499 | PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); | ||
500 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
501 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
502 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
503 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
504 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
505 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
506 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
507 | |||
508 | /* cycles:upp */ | ||
509 | evsel = perf_evsel__next(evsel); | ||
510 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
511 | TEST_ASSERT_VAL("wrong config", | ||
512 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
513 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
514 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
515 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
516 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
517 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
518 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); | ||
519 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int test__group2(struct perf_evlist *evlist) | ||
525 | { | ||
526 | struct perf_evsel *evsel, *leader; | ||
527 | |||
528 | TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); | ||
529 | |||
530 | /* faults + :ku modifier */ | ||
531 | evsel = leader = perf_evlist__first(evlist); | ||
532 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type); | ||
533 | TEST_ASSERT_VAL("wrong config", | ||
534 | PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config); | ||
535 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
536 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
537 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
538 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
539 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
540 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
541 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
542 | |||
543 | /* cache-references + :u modifier */ | ||
544 | evsel = perf_evsel__next(evsel); | ||
545 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
546 | TEST_ASSERT_VAL("wrong config", | ||
547 | PERF_COUNT_HW_CACHE_REFERENCES == evsel->attr.config); | ||
548 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
549 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
550 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
551 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
552 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
553 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
554 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
555 | |||
556 | /* cycles:k */ | ||
557 | evsel = perf_evsel__next(evsel); | ||
558 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
559 | TEST_ASSERT_VAL("wrong config", | ||
560 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
561 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
562 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
563 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
564 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
565 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
566 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
567 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static int test__group3(struct perf_evlist *evlist __maybe_unused) | ||
573 | { | ||
574 | struct perf_evsel *evsel, *leader; | ||
575 | |||
576 | TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); | ||
577 | |||
578 | /* group1 syscalls:sys_enter_open:H */ | ||
579 | evsel = leader = perf_evlist__first(evlist); | ||
580 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); | ||
581 | TEST_ASSERT_VAL("wrong sample_type", | ||
582 | PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); | ||
583 | TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period); | ||
584 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
585 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
586 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
587 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
588 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
589 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
590 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
591 | TEST_ASSERT_VAL("wrong group name", | ||
592 | !strcmp(leader->group_name, "group1")); | ||
593 | |||
594 | /* group1 cycles:kppp */ | ||
595 | evsel = perf_evsel__next(evsel); | ||
596 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
597 | TEST_ASSERT_VAL("wrong config", | ||
598 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
599 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
600 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
601 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
602 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
603 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
604 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); | ||
605 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
606 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
607 | |||
608 | /* group2 cycles + G modifier */ | ||
609 | evsel = leader = perf_evsel__next(evsel); | ||
610 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
611 | TEST_ASSERT_VAL("wrong config", | ||
612 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
613 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
614 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
615 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
616 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
617 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
618 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
619 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
620 | TEST_ASSERT_VAL("wrong group name", | ||
621 | !strcmp(leader->group_name, "group2")); | ||
622 | |||
623 | /* group2 1:3 + G modifier */ | ||
624 | evsel = perf_evsel__next(evsel); | ||
625 | TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); | ||
626 | TEST_ASSERT_VAL("wrong config", 3 == evsel->attr.config); | ||
627 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
628 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
629 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
630 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
631 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
632 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
633 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
634 | |||
635 | /* instructions:u */ | ||
636 | evsel = perf_evsel__next(evsel); | ||
637 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
638 | TEST_ASSERT_VAL("wrong config", | ||
639 | PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); | ||
640 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
641 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
642 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
643 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
644 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
645 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
646 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | static int test__group4(struct perf_evlist *evlist __maybe_unused) | ||
652 | { | ||
653 | struct perf_evsel *evsel, *leader; | ||
654 | |||
655 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
656 | |||
657 | /* cycles:u + p */ | ||
658 | evsel = leader = perf_evlist__first(evlist); | ||
659 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
660 | TEST_ASSERT_VAL("wrong config", | ||
661 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
662 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
663 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
664 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
665 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
666 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
667 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); | ||
668 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
669 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
670 | |||
671 | /* instructions:kp + p */ | ||
672 | evsel = perf_evsel__next(evsel); | ||
673 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
674 | TEST_ASSERT_VAL("wrong config", | ||
675 | PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); | ||
676 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
677 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
678 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
679 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
680 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
681 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); | ||
682 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static int test__group5(struct perf_evlist *evlist __maybe_unused) | ||
688 | { | ||
689 | struct perf_evsel *evsel, *leader; | ||
690 | |||
691 | TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); | ||
692 | |||
693 | /* cycles + G */ | ||
694 | evsel = leader = perf_evlist__first(evlist); | ||
695 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
696 | TEST_ASSERT_VAL("wrong config", | ||
697 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
698 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
699 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
700 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
701 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
702 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
703 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
704 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
705 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
706 | |||
707 | /* instructions + G */ | ||
708 | evsel = perf_evsel__next(evsel); | ||
709 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
710 | TEST_ASSERT_VAL("wrong config", | ||
711 | PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); | ||
712 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
713 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
714 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
715 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
716 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
717 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
718 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
719 | |||
720 | /* cycles:G */ | ||
721 | evsel = leader = perf_evsel__next(evsel); | ||
722 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
723 | TEST_ASSERT_VAL("wrong config", | ||
724 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
725 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
726 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
727 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
728 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
729 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
730 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
731 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
732 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
733 | |||
734 | /* instructions:G */ | ||
735 | evsel = perf_evsel__next(evsel); | ||
736 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
737 | TEST_ASSERT_VAL("wrong config", | ||
738 | PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config); | ||
739 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
740 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
741 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
742 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
743 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
744 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
745 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
746 | |||
747 | /* cycles */ | ||
748 | evsel = perf_evsel__next(evsel); | ||
749 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
750 | TEST_ASSERT_VAL("wrong config", | ||
751 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
752 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
753 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
754 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
755 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
756 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
757 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
758 | TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); | ||
759 | |||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | struct test__event_st { | ||
764 | const char *name; | ||
765 | __u32 type; | ||
766 | int (*check)(struct perf_evlist *evlist); | ||
767 | }; | ||
768 | |||
769 | static struct test__event_st test__events[] = { | ||
770 | [0] = { | ||
771 | .name = "syscalls:sys_enter_open", | ||
772 | .check = test__checkevent_tracepoint, | ||
773 | }, | ||
774 | [1] = { | ||
775 | .name = "syscalls:*", | ||
776 | .check = test__checkevent_tracepoint_multi, | ||
777 | }, | ||
778 | [2] = { | ||
779 | .name = "r1a", | ||
780 | .check = test__checkevent_raw, | ||
781 | }, | ||
782 | [3] = { | ||
783 | .name = "1:1", | ||
784 | .check = test__checkevent_numeric, | ||
785 | }, | ||
786 | [4] = { | ||
787 | .name = "instructions", | ||
788 | .check = test__checkevent_symbolic_name, | ||
789 | }, | ||
790 | [5] = { | ||
791 | .name = "cycles/period=100000,config2/", | ||
792 | .check = test__checkevent_symbolic_name_config, | ||
793 | }, | ||
794 | [6] = { | ||
795 | .name = "faults", | ||
796 | .check = test__checkevent_symbolic_alias, | ||
797 | }, | ||
798 | [7] = { | ||
799 | .name = "L1-dcache-load-miss", | ||
800 | .check = test__checkevent_genhw, | ||
801 | }, | ||
802 | [8] = { | ||
803 | .name = "mem:0", | ||
804 | .check = test__checkevent_breakpoint, | ||
805 | }, | ||
806 | [9] = { | ||
807 | .name = "mem:0:x", | ||
808 | .check = test__checkevent_breakpoint_x, | ||
809 | }, | ||
810 | [10] = { | ||
811 | .name = "mem:0:r", | ||
812 | .check = test__checkevent_breakpoint_r, | ||
813 | }, | ||
814 | [11] = { | ||
815 | .name = "mem:0:w", | ||
816 | .check = test__checkevent_breakpoint_w, | ||
817 | }, | ||
818 | [12] = { | ||
819 | .name = "syscalls:sys_enter_open:k", | ||
820 | .check = test__checkevent_tracepoint_modifier, | ||
821 | }, | ||
822 | [13] = { | ||
823 | .name = "syscalls:*:u", | ||
824 | .check = test__checkevent_tracepoint_multi_modifier, | ||
825 | }, | ||
826 | [14] = { | ||
827 | .name = "r1a:kp", | ||
828 | .check = test__checkevent_raw_modifier, | ||
829 | }, | ||
830 | [15] = { | ||
831 | .name = "1:1:hp", | ||
832 | .check = test__checkevent_numeric_modifier, | ||
833 | }, | ||
834 | [16] = { | ||
835 | .name = "instructions:h", | ||
836 | .check = test__checkevent_symbolic_name_modifier, | ||
837 | }, | ||
838 | [17] = { | ||
839 | .name = "faults:u", | ||
840 | .check = test__checkevent_symbolic_alias_modifier, | ||
841 | }, | ||
842 | [18] = { | ||
843 | .name = "L1-dcache-load-miss:kp", | ||
844 | .check = test__checkevent_genhw_modifier, | ||
845 | }, | ||
846 | [19] = { | ||
847 | .name = "mem:0:u", | ||
848 | .check = test__checkevent_breakpoint_modifier, | ||
849 | }, | ||
850 | [20] = { | ||
851 | .name = "mem:0:x:k", | ||
852 | .check = test__checkevent_breakpoint_x_modifier, | ||
853 | }, | ||
854 | [21] = { | ||
855 | .name = "mem:0:r:hp", | ||
856 | .check = test__checkevent_breakpoint_r_modifier, | ||
857 | }, | ||
858 | [22] = { | ||
859 | .name = "mem:0:w:up", | ||
860 | .check = test__checkevent_breakpoint_w_modifier, | ||
861 | }, | ||
862 | [23] = { | ||
863 | .name = "r1,syscalls:sys_enter_open:k,1:1:hp", | ||
864 | .check = test__checkevent_list, | ||
865 | }, | ||
866 | [24] = { | ||
867 | .name = "instructions:G", | ||
868 | .check = test__checkevent_exclude_host_modifier, | ||
869 | }, | ||
870 | [25] = { | ||
871 | .name = "instructions:H", | ||
872 | .check = test__checkevent_exclude_guest_modifier, | ||
873 | }, | ||
874 | [26] = { | ||
875 | .name = "mem:0:rw", | ||
876 | .check = test__checkevent_breakpoint_rw, | ||
877 | }, | ||
878 | [27] = { | ||
879 | .name = "mem:0:rw:kp", | ||
880 | .check = test__checkevent_breakpoint_rw_modifier, | ||
881 | }, | ||
882 | [28] = { | ||
883 | .name = "{instructions:k,cycles:upp}", | ||
884 | .check = test__group1, | ||
885 | }, | ||
886 | [29] = { | ||
887 | .name = "{faults:k,cache-references}:u,cycles:k", | ||
888 | .check = test__group2, | ||
889 | }, | ||
890 | [30] = { | ||
891 | .name = "group1{syscalls:sys_enter_open:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u", | ||
892 | .check = test__group3, | ||
893 | }, | ||
894 | [31] = { | ||
895 | .name = "{cycles:u,instructions:kp}:p", | ||
896 | .check = test__group4, | ||
897 | }, | ||
898 | [32] = { | ||
899 | .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", | ||
900 | .check = test__group5, | ||
901 | }, | ||
902 | }; | ||
903 | |||
904 | static struct test__event_st test__events_pmu[] = { | ||
905 | [0] = { | ||
906 | .name = "cpu/config=10,config1,config2=3,period=1000/u", | ||
907 | .check = test__checkevent_pmu, | ||
908 | }, | ||
909 | [1] = { | ||
910 | .name = "cpu/config=1,name=krava/u,cpu/config=2/u", | ||
911 | .check = test__checkevent_pmu_name, | ||
912 | }, | ||
913 | }; | ||
914 | |||
915 | struct test__term { | ||
916 | const char *str; | ||
917 | __u32 type; | ||
918 | int (*check)(struct list_head *terms); | ||
919 | }; | ||
920 | |||
921 | static struct test__term test__terms[] = { | ||
922 | [0] = { | ||
923 | .str = "config=10,config1,config2=3,umask=1", | ||
924 | .check = test__checkterms_simple, | ||
925 | }, | ||
926 | }; | ||
927 | |||
928 | static int test_event(struct test__event_st *e) | ||
929 | { | ||
930 | struct perf_evlist *evlist; | ||
931 | int ret; | ||
932 | |||
933 | evlist = perf_evlist__new(NULL, NULL); | ||
934 | if (evlist == NULL) | ||
935 | return -ENOMEM; | ||
936 | |||
937 | ret = parse_events(evlist, e->name, 0); | ||
938 | if (ret) { | ||
939 | pr_debug("failed to parse event '%s', err %d\n", | ||
940 | e->name, ret); | ||
941 | return ret; | ||
942 | } | ||
943 | |||
944 | ret = e->check(evlist); | ||
945 | perf_evlist__delete(evlist); | ||
946 | |||
947 | return ret; | ||
948 | } | ||
949 | |||
950 | static int test_events(struct test__event_st *events, unsigned cnt) | ||
951 | { | ||
952 | int ret1, ret2 = 0; | ||
953 | unsigned i; | ||
954 | |||
955 | for (i = 0; i < cnt; i++) { | ||
956 | struct test__event_st *e = &events[i]; | ||
957 | |||
958 | pr_debug("running test %d '%s'\n", i, e->name); | ||
959 | ret1 = test_event(e); | ||
960 | if (ret1) | ||
961 | ret2 = ret1; | ||
962 | } | ||
963 | |||
964 | return ret2; | ||
965 | } | ||
966 | |||
967 | static int test_term(struct test__term *t) | ||
968 | { | ||
969 | struct list_head *terms; | ||
970 | int ret; | ||
971 | |||
972 | terms = malloc(sizeof(*terms)); | ||
973 | if (!terms) | ||
974 | return -ENOMEM; | ||
975 | |||
976 | INIT_LIST_HEAD(terms); | ||
977 | |||
978 | ret = parse_events_terms(terms, t->str); | ||
979 | if (ret) { | ||
980 | pr_debug("failed to parse terms '%s', err %d\n", | ||
981 | t->str , ret); | ||
982 | return ret; | ||
983 | } | ||
984 | |||
985 | ret = t->check(terms); | ||
986 | parse_events__free_terms(terms); | ||
987 | |||
988 | return ret; | ||
989 | } | ||
990 | |||
991 | static int test_terms(struct test__term *terms, unsigned cnt) | ||
992 | { | ||
993 | int ret = 0; | ||
994 | unsigned i; | ||
995 | |||
996 | for (i = 0; i < cnt; i++) { | ||
997 | struct test__term *t = &terms[i]; | ||
998 | |||
999 | pr_debug("running test %d '%s'\n", i, t->str); | ||
1000 | ret = test_term(t); | ||
1001 | if (ret) | ||
1002 | break; | ||
1003 | } | ||
1004 | |||
1005 | return ret; | ||
1006 | } | ||
1007 | |||
1008 | static int test_pmu(void) | ||
1009 | { | ||
1010 | struct stat st; | ||
1011 | char path[PATH_MAX]; | ||
1012 | int ret; | ||
1013 | |||
1014 | snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/", | ||
1015 | sysfs_find_mountpoint()); | ||
1016 | |||
1017 | ret = stat(path, &st); | ||
1018 | if (ret) | ||
1019 | pr_debug("omitting PMU cpu tests\n"); | ||
1020 | return !ret; | ||
1021 | } | ||
1022 | |||
1023 | int parse_events__test(void) | ||
1024 | { | ||
1025 | int ret1, ret2 = 0; | ||
1026 | |||
1027 | #define TEST_EVENTS(tests) \ | ||
1028 | do { \ | ||
1029 | ret1 = test_events(tests, ARRAY_SIZE(tests)); \ | ||
1030 | if (!ret2) \ | ||
1031 | ret2 = ret1; \ | ||
1032 | } while (0) | ||
1033 | |||
1034 | TEST_EVENTS(test__events); | ||
1035 | |||
1036 | if (test_pmu()) | ||
1037 | TEST_EVENTS(test__events_pmu); | ||
1038 | |||
1039 | ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms)); | ||
1040 | if (!ret2) | ||
1041 | ret2 = ret1; | ||
1042 | |||
1043 | return ret2; | ||
1044 | } | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index aed38e4b9dfa..2d8d53bec17e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -1,4 +1,4 @@ | |||
1 | #include "../../../include/linux/hw_breakpoint.h" | 1 | #include <linux/hw_breakpoint.h> |
2 | #include "util.h" | 2 | #include "util.h" |
3 | #include "../perf.h" | 3 | #include "../perf.h" |
4 | #include "evlist.h" | 4 | #include "evlist.h" |
@@ -690,6 +690,9 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
690 | eH = 0; | 690 | eH = 0; |
691 | } else if (*str == 'p') { | 691 | } else if (*str == 'p') { |
692 | precise++; | 692 | precise++; |
693 | /* use of precise requires exclude_guest */ | ||
694 | if (!exclude_GH) | ||
695 | eG = 1; | ||
693 | } else | 696 | } else |
694 | break; | 697 | break; |
695 | 698 | ||
@@ -719,6 +722,27 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
719 | return 0; | 722 | return 0; |
720 | } | 723 | } |
721 | 724 | ||
725 | /* | ||
726 | * Basic modifier sanity check to validate it contains only one | ||
727 | * instance of any modifier (apart from 'p') present. | ||
728 | */ | ||
729 | static int check_modifier(char *str) | ||
730 | { | ||
731 | char *p = str; | ||
732 | |||
733 | /* The sizeof includes 0 byte as well. */ | ||
734 | if (strlen(str) > (sizeof("ukhGHppp") - 1)) | ||
735 | return -1; | ||
736 | |||
737 | while (*p) { | ||
738 | if (*p != 'p' && strchr(p + 1, *p)) | ||
739 | return -1; | ||
740 | p++; | ||
741 | } | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
722 | int parse_events__modifier_event(struct list_head *list, char *str, bool add) | 746 | int parse_events__modifier_event(struct list_head *list, char *str, bool add) |
723 | { | 747 | { |
724 | struct perf_evsel *evsel; | 748 | struct perf_evsel *evsel; |
@@ -727,6 +751,9 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) | |||
727 | if (str == NULL) | 751 | if (str == NULL) |
728 | return 0; | 752 | return 0; |
729 | 753 | ||
754 | if (check_modifier(str)) | ||
755 | return -EINVAL; | ||
756 | |||
730 | if (!add && get_event_modifier(&mod, str, NULL)) | 757 | if (!add && get_event_modifier(&mod, str, NULL)) |
731 | return -EINVAL; | 758 | return -EINVAL; |
732 | 759 | ||
@@ -824,8 +851,6 @@ int parse_events(struct perf_evlist *evlist, const char *str, | |||
824 | * Both call perf_evlist__delete in case of error, so we dont | 851 | * Both call perf_evlist__delete in case of error, so we dont |
825 | * need to bother. | 852 | * need to bother. |
826 | */ | 853 | */ |
827 | fprintf(stderr, "invalid or unsupported event: '%s'\n", str); | ||
828 | fprintf(stderr, "Run 'perf list' for a list of valid events\n"); | ||
829 | return ret; | 854 | return ret; |
830 | } | 855 | } |
831 | 856 | ||
@@ -833,7 +858,13 @@ int parse_events_option(const struct option *opt, const char *str, | |||
833 | int unset __maybe_unused) | 858 | int unset __maybe_unused) |
834 | { | 859 | { |
835 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; | 860 | struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; |
836 | return parse_events(evlist, str, unset); | 861 | int ret = parse_events(evlist, str, unset); |
862 | |||
863 | if (ret) { | ||
864 | fprintf(stderr, "invalid or unsupported event: '%s'\n", str); | ||
865 | fprintf(stderr, "Run 'perf list' for a list of valid events\n"); | ||
866 | } | ||
867 | return ret; | ||
837 | } | 868 | } |
838 | 869 | ||
839 | int parse_filter(const struct option *opt, const char *str, | 870 | int parse_filter(const struct option *opt, const char *str, |
@@ -1078,7 +1109,7 @@ void print_events(const char *event_glob, bool name_only) | |||
1078 | printf(" %-50s [%s]\n", | 1109 | printf(" %-50s [%s]\n", |
1079 | "cpu/t1=v1[,t2=v2,t3 ...]/modifier", | 1110 | "cpu/t1=v1[,t2=v2,t3 ...]/modifier", |
1080 | event_type_descriptors[PERF_TYPE_RAW]); | 1111 | event_type_descriptors[PERF_TYPE_RAW]); |
1081 | printf(" (see 'perf list --help' on how to encode it)\n"); | 1112 | printf(" (see 'man perf-list' on how to encode it)\n"); |
1082 | printf("\n"); | 1113 | printf("\n"); |
1083 | 1114 | ||
1084 | printf(" %-50s [%s]\n", | 1115 | printf(" %-50s [%s]\n", |
@@ -1139,6 +1170,24 @@ int parse_events__term_str(struct parse_events__term **term, | |||
1139 | config, str, 0); | 1170 | config, str, 0); |
1140 | } | 1171 | } |
1141 | 1172 | ||
1173 | int parse_events__term_sym_hw(struct parse_events__term **term, | ||
1174 | char *config, unsigned idx) | ||
1175 | { | ||
1176 | struct event_symbol *sym; | ||
1177 | |||
1178 | BUG_ON(idx >= PERF_COUNT_HW_MAX); | ||
1179 | sym = &event_symbols_hw[idx]; | ||
1180 | |||
1181 | if (config) | ||
1182 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, | ||
1183 | PARSE_EVENTS__TERM_TYPE_USER, config, | ||
1184 | (char *) sym->symbol, 0); | ||
1185 | else | ||
1186 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, | ||
1187 | PARSE_EVENTS__TERM_TYPE_USER, | ||
1188 | (char *) "event", (char *) sym->symbol, 0); | ||
1189 | } | ||
1190 | |||
1142 | int parse_events__term_clone(struct parse_events__term **new, | 1191 | int parse_events__term_clone(struct parse_events__term **new, |
1143 | struct parse_events__term *term) | 1192 | struct parse_events__term *term) |
1144 | { | 1193 | { |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 839230ceb18b..b7af80b8bdda 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #include <linux/list.h> | 7 | #include <linux/list.h> |
8 | #include <stdbool.h> | 8 | #include <stdbool.h> |
9 | #include "types.h" | 9 | #include "types.h" |
10 | #include "../../../include/uapi/linux/perf_event.h" | 10 | #include <linux/perf_event.h> |
11 | #include "types.h" | 11 | #include "types.h" |
12 | 12 | ||
13 | struct list_head; | 13 | struct list_head; |
@@ -76,6 +76,8 @@ int parse_events__term_num(struct parse_events__term **_term, | |||
76 | int type_term, char *config, u64 num); | 76 | int type_term, char *config, u64 num); |
77 | int parse_events__term_str(struct parse_events__term **_term, | 77 | int parse_events__term_str(struct parse_events__term **_term, |
78 | int type_term, char *config, char *str); | 78 | int type_term, char *config, char *str); |
79 | int parse_events__term_sym_hw(struct parse_events__term **term, | ||
80 | char *config, unsigned idx); | ||
79 | int parse_events__term_clone(struct parse_events__term **new, | 81 | int parse_events__term_clone(struct parse_events__term **new, |
80 | struct parse_events__term *term); | 82 | struct parse_events__term *term); |
81 | void parse_events__free_terms(struct list_head *terms); | 83 | void parse_events__free_terms(struct list_head *terms); |
@@ -97,7 +99,6 @@ void parse_events__set_leader(char *name, struct list_head *list); | |||
97 | void parse_events_update_lists(struct list_head *list_event, | 99 | void parse_events_update_lists(struct list_head *list_event, |
98 | struct list_head *list_all); | 100 | struct list_head *list_all); |
99 | void parse_events_error(void *data, void *scanner, char const *msg); | 101 | void parse_events_error(void *data, void *scanner, char const *msg); |
100 | int parse_events__test(void); | ||
101 | 102 | ||
102 | void print_events(const char *event_glob, bool name_only); | 103 | void print_events(const char *event_glob, bool name_only); |
103 | void print_events_type(u8 type); | 104 | void print_events_type(u8 type); |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index c87efc12579d..e9d1134c2c68 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -81,7 +81,8 @@ num_dec [0-9]+ | |||
81 | num_hex 0x[a-fA-F0-9]+ | 81 | num_hex 0x[a-fA-F0-9]+ |
82 | num_raw_hex [a-fA-F0-9]+ | 82 | num_raw_hex [a-fA-F0-9]+ |
83 | name [a-zA-Z_*?][a-zA-Z0-9_*?]* | 83 | name [a-zA-Z_*?][a-zA-Z0-9_*?]* |
84 | modifier_event [ukhpGH]{1,8} | 84 | name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]* |
85 | modifier_event [ukhpGH]+ | ||
85 | modifier_bp [rwx]{1,3} | 86 | modifier_bp [rwx]{1,3} |
86 | 87 | ||
87 | %% | 88 | %% |
@@ -168,6 +169,7 @@ period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } | |||
168 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } | 169 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } |
169 | , { return ','; } | 170 | , { return ','; } |
170 | "/" { BEGIN(INITIAL); return '/'; } | 171 | "/" { BEGIN(INITIAL); return '/'; } |
172 | {name_minus} { return str(yyscanner, PE_NAME); } | ||
171 | } | 173 | } |
172 | 174 | ||
173 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } | 175 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index cd88209e3c58..0f9914ae6bac 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -352,6 +352,15 @@ PE_NAME '=' PE_VALUE | |||
352 | $$ = term; | 352 | $$ = term; |
353 | } | 353 | } |
354 | | | 354 | | |
355 | PE_NAME '=' PE_VALUE_SYM_HW | ||
356 | { | ||
357 | struct parse_events__term *term; | ||
358 | int config = $3 & 255; | ||
359 | |||
360 | ABORT_ON(parse_events__term_sym_hw(&term, $1, config)); | ||
361 | $$ = term; | ||
362 | } | ||
363 | | | ||
355 | PE_NAME | 364 | PE_NAME |
356 | { | 365 | { |
357 | struct parse_events__term *term; | 366 | struct parse_events__term *term; |
@@ -361,6 +370,15 @@ PE_NAME | |||
361 | $$ = term; | 370 | $$ = term; |
362 | } | 371 | } |
363 | | | 372 | | |
373 | PE_VALUE_SYM_HW | ||
374 | { | ||
375 | struct parse_events__term *term; | ||
376 | int config = $1 & 255; | ||
377 | |||
378 | ABORT_ON(parse_events__term_sym_hw(&term, NULL, config)); | ||
379 | $$ = term; | ||
380 | } | ||
381 | | | ||
364 | PE_TERM '=' PE_NAME | 382 | PE_TERM '=' PE_NAME |
365 | { | 383 | { |
366 | struct parse_events__term *term; | 384 | struct parse_events__term *term; |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 8a2229da594f..9bdc60c6f138 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -22,7 +22,7 @@ static LIST_HEAD(pmus); | |||
22 | * Parse & process all the sysfs attributes located under | 22 | * Parse & process all the sysfs attributes located under |
23 | * the directory specified in 'dir' parameter. | 23 | * the directory specified in 'dir' parameter. |
24 | */ | 24 | */ |
25 | static int pmu_format_parse(char *dir, struct list_head *head) | 25 | int perf_pmu__format_parse(char *dir, struct list_head *head) |
26 | { | 26 | { |
27 | struct dirent *evt_ent; | 27 | struct dirent *evt_ent; |
28 | DIR *format_dir; | 28 | DIR *format_dir; |
@@ -77,7 +77,7 @@ static int pmu_format(char *name, struct list_head *format) | |||
77 | if (stat(path, &st) < 0) | 77 | if (stat(path, &st) < 0) |
78 | return 0; /* no error if format does not exist */ | 78 | return 0; /* no error if format does not exist */ |
79 | 79 | ||
80 | if (pmu_format_parse(path, format)) | 80 | if (perf_pmu__format_parse(path, format)) |
81 | return -1; | 81 | return -1; |
82 | 82 | ||
83 | return 0; | 83 | return 0; |
@@ -164,7 +164,7 @@ static int pmu_aliases(char *name, struct list_head *head) | |||
164 | "%s/bus/event_source/devices/%s/events", sysfs, name); | 164 | "%s/bus/event_source/devices/%s/events", sysfs, name); |
165 | 165 | ||
166 | if (stat(path, &st) < 0) | 166 | if (stat(path, &st) < 0) |
167 | return -1; | 167 | return 0; /* no error if 'events' does not exist */ |
168 | 168 | ||
169 | if (pmu_aliases_parse(path, head)) | 169 | if (pmu_aliases_parse(path, head)) |
170 | return -1; | 170 | return -1; |
@@ -296,6 +296,9 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
296 | if (pmu_format(name, &format)) | 296 | if (pmu_format(name, &format)) |
297 | return NULL; | 297 | return NULL; |
298 | 298 | ||
299 | if (pmu_aliases(name, &aliases)) | ||
300 | return NULL; | ||
301 | |||
299 | if (pmu_type(name, &type)) | 302 | if (pmu_type(name, &type)) |
300 | return NULL; | 303 | return NULL; |
301 | 304 | ||
@@ -305,8 +308,6 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
305 | 308 | ||
306 | pmu->cpus = pmu_cpumask(name); | 309 | pmu->cpus = pmu_cpumask(name); |
307 | 310 | ||
308 | pmu_aliases(name, &aliases); | ||
309 | |||
310 | INIT_LIST_HEAD(&pmu->format); | 311 | INIT_LIST_HEAD(&pmu->format); |
311 | INIT_LIST_HEAD(&pmu->aliases); | 312 | INIT_LIST_HEAD(&pmu->aliases); |
312 | list_splice(&format, &pmu->format); | 313 | list_splice(&format, &pmu->format); |
@@ -445,8 +446,9 @@ static int pmu_config_term(struct list_head *formats, | |||
445 | return 0; | 446 | return 0; |
446 | } | 447 | } |
447 | 448 | ||
448 | static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, | 449 | int perf_pmu__config_terms(struct list_head *formats, |
449 | struct list_head *head_terms) | 450 | struct perf_event_attr *attr, |
451 | struct list_head *head_terms) | ||
450 | { | 452 | { |
451 | struct parse_events__term *term; | 453 | struct parse_events__term *term; |
452 | 454 | ||
@@ -466,7 +468,7 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
466 | struct list_head *head_terms) | 468 | struct list_head *head_terms) |
467 | { | 469 | { |
468 | attr->type = pmu->type; | 470 | attr->type = pmu->type; |
469 | return pmu_config(&pmu->format, attr, head_terms); | 471 | return perf_pmu__config_terms(&pmu->format, attr, head_terms); |
470 | } | 472 | } |
471 | 473 | ||
472 | static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, | 474 | static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, |
@@ -550,177 +552,3 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to) | |||
550 | for (b = from; b <= to; b++) | 552 | for (b = from; b <= to; b++) |
551 | set_bit(b, bits); | 553 | set_bit(b, bits); |
552 | } | 554 | } |
553 | |||
554 | /* Simulated format definitions. */ | ||
555 | static struct test_format { | ||
556 | const char *name; | ||
557 | const char *value; | ||
558 | } test_formats[] = { | ||
559 | { "krava01", "config:0-1,62-63\n", }, | ||
560 | { "krava02", "config:10-17\n", }, | ||
561 | { "krava03", "config:5\n", }, | ||
562 | { "krava11", "config1:0,2,4,6,8,20-28\n", }, | ||
563 | { "krava12", "config1:63\n", }, | ||
564 | { "krava13", "config1:45-47\n", }, | ||
565 | { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", }, | ||
566 | { "krava22", "config2:8,18,48,58\n", }, | ||
567 | { "krava23", "config2:28-29,38\n", }, | ||
568 | }; | ||
569 | |||
570 | #define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format)) | ||
571 | |||
572 | /* Simulated users input. */ | ||
573 | static struct parse_events__term test_terms[] = { | ||
574 | { | ||
575 | .config = (char *) "krava01", | ||
576 | .val.num = 15, | ||
577 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
578 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
579 | }, | ||
580 | { | ||
581 | .config = (char *) "krava02", | ||
582 | .val.num = 170, | ||
583 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
584 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
585 | }, | ||
586 | { | ||
587 | .config = (char *) "krava03", | ||
588 | .val.num = 1, | ||
589 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
590 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
591 | }, | ||
592 | { | ||
593 | .config = (char *) "krava11", | ||
594 | .val.num = 27, | ||
595 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
596 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
597 | }, | ||
598 | { | ||
599 | .config = (char *) "krava12", | ||
600 | .val.num = 1, | ||
601 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
602 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
603 | }, | ||
604 | { | ||
605 | .config = (char *) "krava13", | ||
606 | .val.num = 2, | ||
607 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
608 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
609 | }, | ||
610 | { | ||
611 | .config = (char *) "krava21", | ||
612 | .val.num = 119, | ||
613 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
614 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
615 | }, | ||
616 | { | ||
617 | .config = (char *) "krava22", | ||
618 | .val.num = 11, | ||
619 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
620 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
621 | }, | ||
622 | { | ||
623 | .config = (char *) "krava23", | ||
624 | .val.num = 2, | ||
625 | .type_val = PARSE_EVENTS__TERM_TYPE_NUM, | ||
626 | .type_term = PARSE_EVENTS__TERM_TYPE_USER, | ||
627 | }, | ||
628 | }; | ||
629 | #define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) | ||
630 | |||
631 | /* | ||
632 | * Prepare format directory data, exported by kernel | ||
633 | * at /sys/bus/event_source/devices/<dev>/format. | ||
634 | */ | ||
635 | static char *test_format_dir_get(void) | ||
636 | { | ||
637 | static char dir[PATH_MAX]; | ||
638 | unsigned int i; | ||
639 | |||
640 | snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX"); | ||
641 | if (!mkdtemp(dir)) | ||
642 | return NULL; | ||
643 | |||
644 | for (i = 0; i < TEST_FORMATS_CNT; i++) { | ||
645 | static char name[PATH_MAX]; | ||
646 | struct test_format *format = &test_formats[i]; | ||
647 | FILE *file; | ||
648 | |||
649 | snprintf(name, PATH_MAX, "%s/%s", dir, format->name); | ||
650 | |||
651 | file = fopen(name, "w"); | ||
652 | if (!file) | ||
653 | return NULL; | ||
654 | |||
655 | if (1 != fwrite(format->value, strlen(format->value), 1, file)) | ||
656 | break; | ||
657 | |||
658 | fclose(file); | ||
659 | } | ||
660 | |||
661 | return dir; | ||
662 | } | ||
663 | |||
664 | /* Cleanup format directory. */ | ||
665 | static int test_format_dir_put(char *dir) | ||
666 | { | ||
667 | char buf[PATH_MAX]; | ||
668 | snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir); | ||
669 | if (system(buf)) | ||
670 | return -1; | ||
671 | |||
672 | snprintf(buf, PATH_MAX, "rmdir %s\n", dir); | ||
673 | return system(buf); | ||
674 | } | ||
675 | |||
676 | static struct list_head *test_terms_list(void) | ||
677 | { | ||
678 | static LIST_HEAD(terms); | ||
679 | unsigned int i; | ||
680 | |||
681 | for (i = 0; i < TERMS_CNT; i++) | ||
682 | list_add_tail(&test_terms[i].list, &terms); | ||
683 | |||
684 | return &terms; | ||
685 | } | ||
686 | |||
687 | #undef TERMS_CNT | ||
688 | |||
689 | int perf_pmu__test(void) | ||
690 | { | ||
691 | char *format = test_format_dir_get(); | ||
692 | LIST_HEAD(formats); | ||
693 | struct list_head *terms = test_terms_list(); | ||
694 | int ret; | ||
695 | |||
696 | if (!format) | ||
697 | return -EINVAL; | ||
698 | |||
699 | do { | ||
700 | struct perf_event_attr attr; | ||
701 | |||
702 | memset(&attr, 0, sizeof(attr)); | ||
703 | |||
704 | ret = pmu_format_parse(format, &formats); | ||
705 | if (ret) | ||
706 | break; | ||
707 | |||
708 | ret = pmu_config(&formats, &attr, terms); | ||
709 | if (ret) | ||
710 | break; | ||
711 | |||
712 | ret = -EINVAL; | ||
713 | |||
714 | if (attr.config != 0xc00000000002a823) | ||
715 | break; | ||
716 | if (attr.config1 != 0x8000400000000145) | ||
717 | break; | ||
718 | if (attr.config2 != 0x0400000020041d07) | ||
719 | break; | ||
720 | |||
721 | ret = 0; | ||
722 | } while (0); | ||
723 | |||
724 | test_format_dir_put(format); | ||
725 | return ret; | ||
726 | } | ||
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 39f3abac7744..a313ed76a49a 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define __PMU_H | 2 | #define __PMU_H |
3 | 3 | ||
4 | #include <linux/bitops.h> | 4 | #include <linux/bitops.h> |
5 | #include "../../../include/uapi/linux/perf_event.h" | 5 | #include <linux/perf_event.h> |
6 | 6 | ||
7 | enum { | 7 | enum { |
8 | PERF_PMU_FORMAT_VALUE_CONFIG, | 8 | PERF_PMU_FORMAT_VALUE_CONFIG, |
@@ -37,6 +37,9 @@ struct perf_pmu { | |||
37 | struct perf_pmu *perf_pmu__find(char *name); | 37 | struct perf_pmu *perf_pmu__find(char *name); |
38 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | 38 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, |
39 | struct list_head *head_terms); | 39 | struct list_head *head_terms); |
40 | int perf_pmu__config_terms(struct list_head *formats, | ||
41 | struct perf_event_attr *attr, | ||
42 | struct list_head *head_terms); | ||
40 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); | 43 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); |
41 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | 44 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, |
42 | struct list_head *head_terms); | 45 | struct list_head *head_terms); |
@@ -46,6 +49,7 @@ void perf_pmu_error(struct list_head *list, char *name, char const *msg); | |||
46 | int perf_pmu__new_format(struct list_head *list, char *name, | 49 | int perf_pmu__new_format(struct list_head *list, char *name, |
47 | int config, unsigned long *bits); | 50 | int config, unsigned long *bits); |
48 | void perf_pmu__set_format(unsigned long *bits, long from, long to); | 51 | void perf_pmu__set_format(unsigned long *bits, long from, long to); |
52 | int perf_pmu__format_parse(char *dir, struct list_head *head); | ||
49 | 53 | ||
50 | struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); | 54 | struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); |
51 | 55 | ||
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c index 13d36faf64eb..daa17aeb6c63 100644 --- a/tools/perf/util/pstack.c +++ b/tools/perf/util/pstack.c | |||
@@ -17,59 +17,59 @@ struct pstack { | |||
17 | 17 | ||
18 | struct pstack *pstack__new(unsigned short max_nr_entries) | 18 | struct pstack *pstack__new(unsigned short max_nr_entries) |
19 | { | 19 | { |
20 | struct pstack *self = zalloc((sizeof(*self) + | 20 | struct pstack *pstack = zalloc((sizeof(*pstack) + |
21 | max_nr_entries * sizeof(void *))); | 21 | max_nr_entries * sizeof(void *))); |
22 | if (self != NULL) | 22 | if (pstack != NULL) |
23 | self->max_nr_entries = max_nr_entries; | 23 | pstack->max_nr_entries = max_nr_entries; |
24 | return self; | 24 | return pstack; |
25 | } | 25 | } |
26 | 26 | ||
27 | void pstack__delete(struct pstack *self) | 27 | void pstack__delete(struct pstack *pstack) |
28 | { | 28 | { |
29 | free(self); | 29 | free(pstack); |
30 | } | 30 | } |
31 | 31 | ||
32 | bool pstack__empty(const struct pstack *self) | 32 | bool pstack__empty(const struct pstack *pstack) |
33 | { | 33 | { |
34 | return self->top == 0; | 34 | return pstack->top == 0; |
35 | } | 35 | } |
36 | 36 | ||
37 | void pstack__remove(struct pstack *self, void *key) | 37 | void pstack__remove(struct pstack *pstack, void *key) |
38 | { | 38 | { |
39 | unsigned short i = self->top, last_index = self->top - 1; | 39 | unsigned short i = pstack->top, last_index = pstack->top - 1; |
40 | 40 | ||
41 | while (i-- != 0) { | 41 | while (i-- != 0) { |
42 | if (self->entries[i] == key) { | 42 | if (pstack->entries[i] == key) { |
43 | if (i < last_index) | 43 | if (i < last_index) |
44 | memmove(self->entries + i, | 44 | memmove(pstack->entries + i, |
45 | self->entries + i + 1, | 45 | pstack->entries + i + 1, |
46 | (last_index - i) * sizeof(void *)); | 46 | (last_index - i) * sizeof(void *)); |
47 | --self->top; | 47 | --pstack->top; |
48 | return; | 48 | return; |
49 | } | 49 | } |
50 | } | 50 | } |
51 | pr_err("%s: %p not on the pstack!\n", __func__, key); | 51 | pr_err("%s: %p not on the pstack!\n", __func__, key); |
52 | } | 52 | } |
53 | 53 | ||
54 | void pstack__push(struct pstack *self, void *key) | 54 | void pstack__push(struct pstack *pstack, void *key) |
55 | { | 55 | { |
56 | if (self->top == self->max_nr_entries) { | 56 | if (pstack->top == pstack->max_nr_entries) { |
57 | pr_err("%s: top=%d, overflow!\n", __func__, self->top); | 57 | pr_err("%s: top=%d, overflow!\n", __func__, pstack->top); |
58 | return; | 58 | return; |
59 | } | 59 | } |
60 | self->entries[self->top++] = key; | 60 | pstack->entries[pstack->top++] = key; |
61 | } | 61 | } |
62 | 62 | ||
63 | void *pstack__pop(struct pstack *self) | 63 | void *pstack__pop(struct pstack *pstack) |
64 | { | 64 | { |
65 | void *ret; | 65 | void *ret; |
66 | 66 | ||
67 | if (self->top == 0) { | 67 | if (pstack->top == 0) { |
68 | pr_err("%s: underflow!\n", __func__); | 68 | pr_err("%s: underflow!\n", __func__); |
69 | return NULL; | 69 | return NULL; |
70 | } | 70 | } |
71 | 71 | ||
72 | ret = self->entries[--self->top]; | 72 | ret = pstack->entries[--pstack->top]; |
73 | self->entries[self->top] = NULL; | 73 | pstack->entries[pstack->top] = NULL; |
74 | return ret; | 74 | return ret; |
75 | } | 75 | } |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 9181bf212fb9..a2657fd96837 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -1015,6 +1015,8 @@ PyMODINIT_FUNC initperf(void) | |||
1015 | pyrf_cpu_map__setup_types() < 0) | 1015 | pyrf_cpu_map__setup_types() < 0) |
1016 | return; | 1016 | return; |
1017 | 1017 | ||
1018 | page_size = sysconf(_SC_PAGE_SIZE); | ||
1019 | |||
1018 | Py_INCREF(&pyrf_evlist__type); | 1020 | Py_INCREF(&pyrf_evlist__type); |
1019 | PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type); | 1021 | PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type); |
1020 | 1022 | ||
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c index 0171fb611004..a16cdd2625ad 100644 --- a/tools/perf/util/rblist.c +++ b/tools/perf/util/rblist.c | |||
@@ -44,6 +44,7 @@ int rblist__add_node(struct rblist *rblist, const void *new_entry) | |||
44 | void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node) | 44 | void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node) |
45 | { | 45 | { |
46 | rb_erase(rb_node, &rblist->entries); | 46 | rb_erase(rb_node, &rblist->entries); |
47 | --rblist->nr_entries; | ||
47 | rblist->node_delete(rblist, rb_node); | 48 | rblist->node_delete(rblist, rb_node); |
48 | } | 49 | } |
49 | 50 | ||
@@ -87,8 +88,7 @@ void rblist__delete(struct rblist *rblist) | |||
87 | while (next) { | 88 | while (next) { |
88 | pos = next; | 89 | pos = next; |
89 | next = rb_next(pos); | 90 | next = rb_next(pos); |
90 | rb_erase(pos, &rblist->entries); | 91 | rblist__remove_node(rblist, pos); |
91 | rblist->node_delete(rblist, pos); | ||
92 | } | 92 | } |
93 | free(rblist); | 93 | free(rblist); |
94 | } | 94 | } |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 730c6630cba5..14683dfca2ee 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include "../event.h" | 32 | #include "../event.h" |
33 | #include "../thread.h" | 33 | #include "../thread.h" |
34 | #include "../trace-event.h" | 34 | #include "../trace-event.h" |
35 | #include "../evsel.h" | ||
36 | 35 | ||
37 | PyMODINIT_FUNC initperf_trace_context(void); | 36 | PyMODINIT_FUNC initperf_trace_context(void); |
38 | 37 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8cdd23239c90..ce6f51162386 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1375,15 +1375,13 @@ int __perf_session__process_events(struct perf_session *session, | |||
1375 | { | 1375 | { |
1376 | u64 head, page_offset, file_offset, file_pos, progress_next; | 1376 | u64 head, page_offset, file_offset, file_pos, progress_next; |
1377 | int err, mmap_prot, mmap_flags, map_idx = 0; | 1377 | int err, mmap_prot, mmap_flags, map_idx = 0; |
1378 | size_t page_size, mmap_size; | 1378 | size_t mmap_size; |
1379 | char *buf, *mmaps[8]; | 1379 | char *buf, *mmaps[8]; |
1380 | union perf_event *event; | 1380 | union perf_event *event; |
1381 | uint32_t size; | 1381 | uint32_t size; |
1382 | 1382 | ||
1383 | perf_tool__fill_defaults(tool); | 1383 | perf_tool__fill_defaults(tool); |
1384 | 1384 | ||
1385 | page_size = sysconf(_SC_PAGESIZE); | ||
1386 | |||
1387 | page_offset = page_size * (data_offset / page_size); | 1385 | page_offset = page_size * (data_offset / page_size); |
1388 | file_offset = page_offset; | 1386 | file_offset = page_offset; |
1389 | head = data_offset - page_offset; | 1387 | head = data_offset - page_offset; |
@@ -1460,6 +1458,7 @@ more: | |||
1460 | session->ordered_samples.next_flush = ULLONG_MAX; | 1458 | session->ordered_samples.next_flush = ULLONG_MAX; |
1461 | err = flush_sample_queue(session, tool); | 1459 | err = flush_sample_queue(session, tool); |
1462 | out_err: | 1460 | out_err: |
1461 | ui_progress__finish(); | ||
1463 | perf_session__warn_about_errors(session, tool); | 1462 | perf_session__warn_about_errors(session, tool); |
1464 | perf_session_free_sample_buffers(session); | 1463 | perf_session_free_sample_buffers(session); |
1465 | return err; | 1464 | return err; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index dd6426163ba6..cea133a6bdf1 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -4,10 +4,11 @@ | |||
4 | #include "hist.h" | 4 | #include "hist.h" |
5 | #include "event.h" | 5 | #include "event.h" |
6 | #include "header.h" | 6 | #include "header.h" |
7 | #include "machine.h" | ||
7 | #include "symbol.h" | 8 | #include "symbol.h" |
8 | #include "thread.h" | 9 | #include "thread.h" |
9 | #include <linux/rbtree.h> | 10 | #include <linux/rbtree.h> |
10 | #include "../../../include/uapi/linux/perf_event.h" | 11 | #include <linux/perf_event.h> |
11 | 12 | ||
12 | struct sample_queue; | 13 | struct sample_queue; |
13 | struct ip_callchain; | 14 | struct ip_callchain; |
@@ -68,10 +69,6 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel | |||
68 | struct ip_callchain *chain, | 69 | struct ip_callchain *chain, |
69 | struct symbol **parent); | 70 | struct symbol **parent); |
70 | 71 | ||
71 | struct branch_info *machine__resolve_bstack(struct machine *self, | ||
72 | struct thread *thread, | ||
73 | struct branch_stack *bs); | ||
74 | |||
75 | bool perf_session__has_traces(struct perf_session *self, const char *msg); | 72 | bool perf_session__has_traces(struct perf_session *self, const char *msg); |
76 | 73 | ||
77 | void mem_bswap_64(void *src, int byte_size); | 74 | void mem_bswap_64(void *src, int byte_size); |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index d0f9f29cf181..73d510269784 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -23,6 +23,7 @@ cflags += getenv('CFLAGS', '').split() | |||
23 | 23 | ||
24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | 24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | 25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
26 | libtraceevent = getenv('LIBTRACEEVENT') | ||
26 | 27 | ||
27 | ext_sources = [f.strip() for f in file('util/python-ext-sources') | 28 | ext_sources = [f.strip() for f in file('util/python-ext-sources') |
28 | if len(f.strip()) > 0 and f[0] != '#'] | 29 | if len(f.strip()) > 0 and f[0] != '#'] |
@@ -31,6 +32,7 @@ perf = Extension('perf', | |||
31 | sources = ext_sources, | 32 | sources = ext_sources, |
32 | include_dirs = ['util/include'], | 33 | include_dirs = ['util/include'], |
33 | extra_compile_args = cflags, | 34 | extra_compile_args = cflags, |
35 | extra_objects = [libtraceevent], | ||
34 | ) | 36 | ) |
35 | 37 | ||
36 | setup(name='perf', | 38 | setup(name='perf', |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index b5b1b9211960..cfd1c0feb32d 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -260,6 +260,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, | |||
260 | if (path != NULL) | 260 | if (path != NULL) |
261 | goto out_path; | 261 | goto out_path; |
262 | 262 | ||
263 | if (!self->ms.map) | ||
264 | goto out_ip; | ||
265 | |||
266 | if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10)) | ||
267 | goto out_ip; | ||
268 | |||
263 | snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64, | 269 | snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64, |
264 | self->ms.map->dso->long_name, self->ip); | 270 | self->ms.map->dso->long_name, self->ip); |
265 | fp = popen(cmd, "r"); | 271 | fp = popen(cmd, "r"); |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 5786f323b597..b4e8c3ba559d 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -52,6 +52,22 @@ struct he_stat { | |||
52 | u32 nr_events; | 52 | u32 nr_events; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | struct hist_entry_diff { | ||
56 | bool computed; | ||
57 | |||
58 | /* PERF_HPP__DISPL */ | ||
59 | int displacement; | ||
60 | |||
61 | /* PERF_HPP__DELTA */ | ||
62 | double period_ratio_delta; | ||
63 | |||
64 | /* PERF_HPP__RATIO */ | ||
65 | double period_ratio; | ||
66 | |||
67 | /* HISTC_WEIGHTED_DIFF */ | ||
68 | s64 wdiff; | ||
69 | }; | ||
70 | |||
55 | /** | 71 | /** |
56 | * struct hist_entry - histogram entry | 72 | * struct hist_entry - histogram entry |
57 | * | 73 | * |
@@ -61,12 +77,18 @@ struct he_stat { | |||
61 | struct hist_entry { | 77 | struct hist_entry { |
62 | struct rb_node rb_node_in; | 78 | struct rb_node rb_node_in; |
63 | struct rb_node rb_node; | 79 | struct rb_node rb_node; |
80 | union { | ||
81 | struct list_head node; | ||
82 | struct list_head head; | ||
83 | } pairs; | ||
64 | struct he_stat stat; | 84 | struct he_stat stat; |
65 | struct map_symbol ms; | 85 | struct map_symbol ms; |
66 | struct thread *thread; | 86 | struct thread *thread; |
67 | u64 ip; | 87 | u64 ip; |
68 | s32 cpu; | 88 | s32 cpu; |
69 | 89 | ||
90 | struct hist_entry_diff diff; | ||
91 | |||
70 | /* XXX These two should move to some tree widget lib */ | 92 | /* XXX These two should move to some tree widget lib */ |
71 | u16 row_offset; | 93 | u16 row_offset; |
72 | u16 nr_rows; | 94 | u16 nr_rows; |
@@ -78,15 +100,30 @@ struct hist_entry { | |||
78 | char *srcline; | 100 | char *srcline; |
79 | struct symbol *parent; | 101 | struct symbol *parent; |
80 | unsigned long position; | 102 | unsigned long position; |
81 | union { | 103 | struct rb_root sorted_chain; |
82 | struct hist_entry *pair; | ||
83 | struct rb_root sorted_chain; | ||
84 | }; | ||
85 | struct branch_info *branch_info; | 104 | struct branch_info *branch_info; |
86 | struct hists *hists; | 105 | struct hists *hists; |
87 | struct callchain_root callchain[0]; | 106 | struct callchain_root callchain[0]; |
88 | }; | 107 | }; |
89 | 108 | ||
109 | static inline bool hist_entry__has_pairs(struct hist_entry *he) | ||
110 | { | ||
111 | return !list_empty(&he->pairs.node); | ||
112 | } | ||
113 | |||
114 | static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he) | ||
115 | { | ||
116 | if (hist_entry__has_pairs(he)) | ||
117 | return list_entry(he->pairs.node.next, struct hist_entry, pairs.node); | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | static inline void hist__entry_add_pair(struct hist_entry *he, | ||
122 | struct hist_entry *pair) | ||
123 | { | ||
124 | list_add_tail(&he->pairs.head, &pair->pairs.node); | ||
125 | } | ||
126 | |||
90 | enum sort_type { | 127 | enum sort_type { |
91 | SORT_PID, | 128 | SORT_PID, |
92 | SORT_COMM, | 129 | SORT_COMM, |
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 2eeb51baf077..cfa906882e2c 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c | |||
@@ -90,17 +90,17 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) | |||
90 | if (!strbuf_avail(sb)) | 90 | if (!strbuf_avail(sb)) |
91 | strbuf_grow(sb, 64); | 91 | strbuf_grow(sb, 64); |
92 | va_start(ap, fmt); | 92 | va_start(ap, fmt); |
93 | len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); | 93 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); |
94 | va_end(ap); | 94 | va_end(ap); |
95 | if (len < 0) | 95 | if (len < 0) |
96 | die("your vscnprintf is broken"); | 96 | die("your vsnprintf is broken"); |
97 | if (len > strbuf_avail(sb)) { | 97 | if (len > strbuf_avail(sb)) { |
98 | strbuf_grow(sb, len); | 98 | strbuf_grow(sb, len); |
99 | va_start(ap, fmt); | 99 | va_start(ap, fmt); |
100 | len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); | 100 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); |
101 | va_end(ap); | 101 | va_end(ap); |
102 | if (len > strbuf_avail(sb)) { | 102 | if (len > strbuf_avail(sb)) { |
103 | die("this should not happen, your snprintf is broken"); | 103 | die("this should not happen, your vsnprintf is broken"); |
104 | } | 104 | } |
105 | } | 105 | } |
106 | strbuf_setlen(sb, sb->len + len); | 106 | strbuf_setlen(sb, sb->len + len); |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 32170590892d..346707df04b9 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -314,6 +314,24 @@ int strtailcmp(const char *s1, const char *s2) | |||
314 | } | 314 | } |
315 | 315 | ||
316 | /** | 316 | /** |
317 | * strxfrchar - Locate and replace character in @s | ||
318 | * @s: The string to be searched/changed. | ||
319 | * @from: Source character to be replaced. | ||
320 | * @to: Destination character. | ||
321 | * | ||
322 | * Return pointer to the changed string. | ||
323 | */ | ||
324 | char *strxfrchar(char *s, char from, char to) | ||
325 | { | ||
326 | char *p = s; | ||
327 | |||
328 | while ((p = strchr(p, from)) != NULL) | ||
329 | *p++ = to; | ||
330 | |||
331 | return s; | ||
332 | } | ||
333 | |||
334 | /** | ||
317 | * rtrim - Removes trailing whitespace from @s. | 335 | * rtrim - Removes trailing whitespace from @s. |
318 | * @s: The string to be stripped. | 336 | * @s: The string to be stripped. |
319 | * | 337 | * |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e2e8c697cffe..295f8d4feedf 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "build-id.h" | 12 | #include "build-id.h" |
13 | #include "util.h" | 13 | #include "util.h" |
14 | #include "debug.h" | 14 | #include "debug.h" |
15 | #include "machine.h" | ||
15 | #include "symbol.h" | 16 | #include "symbol.h" |
16 | #include "strlist.h" | 17 | #include "strlist.h" |
17 | 18 | ||
@@ -23,7 +24,6 @@ | |||
23 | #define KSYM_NAME_LEN 256 | 24 | #define KSYM_NAME_LEN 256 |
24 | #endif | 25 | #endif |
25 | 26 | ||
26 | static void dso_cache__free(struct rb_root *root); | ||
27 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, | 27 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
28 | symbol_filter_t filter); | 28 | symbol_filter_t filter); |
29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | 29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
@@ -56,39 +56,6 @@ static enum dso_binary_type binary_type_symtab[] = { | |||
56 | 56 | ||
57 | #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) | 57 | #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) |
58 | 58 | ||
59 | static enum dso_binary_type binary_type_data[] = { | ||
60 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | ||
61 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | ||
62 | DSO_BINARY_TYPE__NOT_FOUND, | ||
63 | }; | ||
64 | |||
65 | #define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data) | ||
66 | |||
67 | int dso__name_len(const struct dso *dso) | ||
68 | { | ||
69 | if (!dso) | ||
70 | return strlen("[unknown]"); | ||
71 | if (verbose) | ||
72 | return dso->long_name_len; | ||
73 | |||
74 | return dso->short_name_len; | ||
75 | } | ||
76 | |||
77 | bool dso__loaded(const struct dso *dso, enum map_type type) | ||
78 | { | ||
79 | return dso->loaded & (1 << type); | ||
80 | } | ||
81 | |||
82 | bool dso__sorted_by_name(const struct dso *dso, enum map_type type) | ||
83 | { | ||
84 | return dso->sorted_by_name & (1 << type); | ||
85 | } | ||
86 | |||
87 | static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) | ||
88 | { | ||
89 | dso->sorted_by_name |= (1 << type); | ||
90 | } | ||
91 | |||
92 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) | 59 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) |
93 | { | 60 | { |
94 | symbol_type = toupper(symbol_type); | 61 | symbol_type = toupper(symbol_type); |
@@ -270,7 +237,7 @@ void symbol__delete(struct symbol *sym) | |||
270 | free(((void *)sym) - symbol_conf.priv_size); | 237 | free(((void *)sym) - symbol_conf.priv_size); |
271 | } | 238 | } |
272 | 239 | ||
273 | static size_t symbol__fprintf(struct symbol *sym, FILE *fp) | 240 | size_t symbol__fprintf(struct symbol *sym, FILE *fp) |
274 | { | 241 | { |
275 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", | 242 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", |
276 | sym->start, sym->end, | 243 | sym->start, sym->end, |
@@ -301,53 +268,7 @@ size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) | |||
301 | return symbol__fprintf_symname_offs(sym, NULL, fp); | 268 | return symbol__fprintf_symname_offs(sym, NULL, fp); |
302 | } | 269 | } |
303 | 270 | ||
304 | void dso__set_long_name(struct dso *dso, char *name) | 271 | void symbols__delete(struct rb_root *symbols) |
305 | { | ||
306 | if (name == NULL) | ||
307 | return; | ||
308 | dso->long_name = name; | ||
309 | dso->long_name_len = strlen(name); | ||
310 | } | ||
311 | |||
312 | static void dso__set_short_name(struct dso *dso, const char *name) | ||
313 | { | ||
314 | if (name == NULL) | ||
315 | return; | ||
316 | dso->short_name = name; | ||
317 | dso->short_name_len = strlen(name); | ||
318 | } | ||
319 | |||
320 | static void dso__set_basename(struct dso *dso) | ||
321 | { | ||
322 | dso__set_short_name(dso, basename(dso->long_name)); | ||
323 | } | ||
324 | |||
325 | struct dso *dso__new(const char *name) | ||
326 | { | ||
327 | struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); | ||
328 | |||
329 | if (dso != NULL) { | ||
330 | int i; | ||
331 | strcpy(dso->name, name); | ||
332 | dso__set_long_name(dso, dso->name); | ||
333 | dso__set_short_name(dso, dso->name); | ||
334 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
335 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; | ||
336 | dso->cache = RB_ROOT; | ||
337 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | ||
338 | dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; | ||
339 | dso->loaded = 0; | ||
340 | dso->sorted_by_name = 0; | ||
341 | dso->has_build_id = 0; | ||
342 | dso->kernel = DSO_TYPE_USER; | ||
343 | dso->needs_swap = DSO_SWAP__UNSET; | ||
344 | INIT_LIST_HEAD(&dso->node); | ||
345 | } | ||
346 | |||
347 | return dso; | ||
348 | } | ||
349 | |||
350 | static void symbols__delete(struct rb_root *symbols) | ||
351 | { | 272 | { |
352 | struct symbol *pos; | 273 | struct symbol *pos; |
353 | struct rb_node *next = rb_first(symbols); | 274 | struct rb_node *next = rb_first(symbols); |
@@ -360,25 +281,6 @@ static void symbols__delete(struct rb_root *symbols) | |||
360 | } | 281 | } |
361 | } | 282 | } |
362 | 283 | ||
363 | void dso__delete(struct dso *dso) | ||
364 | { | ||
365 | int i; | ||
366 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
367 | symbols__delete(&dso->symbols[i]); | ||
368 | if (dso->sname_alloc) | ||
369 | free((char *)dso->short_name); | ||
370 | if (dso->lname_alloc) | ||
371 | free(dso->long_name); | ||
372 | dso_cache__free(&dso->cache); | ||
373 | free(dso); | ||
374 | } | ||
375 | |||
376 | void dso__set_build_id(struct dso *dso, void *build_id) | ||
377 | { | ||
378 | memcpy(dso->build_id, build_id, sizeof(dso->build_id)); | ||
379 | dso->has_build_id = 1; | ||
380 | } | ||
381 | |||
382 | void symbols__insert(struct rb_root *symbols, struct symbol *sym) | 284 | void symbols__insert(struct rb_root *symbols, struct symbol *sym) |
383 | { | 285 | { |
384 | struct rb_node **p = &symbols->rb_node; | 286 | struct rb_node **p = &symbols->rb_node; |
@@ -504,29 +406,6 @@ void dso__sort_by_name(struct dso *dso, enum map_type type) | |||
504 | &dso->symbols[type]); | 406 | &dso->symbols[type]); |
505 | } | 407 | } |
506 | 408 | ||
507 | int build_id__sprintf(const u8 *build_id, int len, char *bf) | ||
508 | { | ||
509 | char *bid = bf; | ||
510 | const u8 *raw = build_id; | ||
511 | int i; | ||
512 | |||
513 | for (i = 0; i < len; ++i) { | ||
514 | sprintf(bid, "%02x", *raw); | ||
515 | ++raw; | ||
516 | bid += 2; | ||
517 | } | ||
518 | |||
519 | return raw - build_id; | ||
520 | } | ||
521 | |||
522 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) | ||
523 | { | ||
524 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
525 | |||
526 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | ||
527 | return fprintf(fp, "%s", sbuild_id); | ||
528 | } | ||
529 | |||
530 | size_t dso__fprintf_symbols_by_name(struct dso *dso, | 409 | size_t dso__fprintf_symbols_by_name(struct dso *dso, |
531 | enum map_type type, FILE *fp) | 410 | enum map_type type, FILE *fp) |
532 | { | 411 | { |
@@ -542,25 +421,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso, | |||
542 | return ret; | 421 | return ret; |
543 | } | 422 | } |
544 | 423 | ||
545 | size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | ||
546 | { | ||
547 | struct rb_node *nd; | ||
548 | size_t ret = fprintf(fp, "dso: %s (", dso->short_name); | ||
549 | |||
550 | if (dso->short_name != dso->long_name) | ||
551 | ret += fprintf(fp, "%s, ", dso->long_name); | ||
552 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], | ||
553 | dso->loaded ? "" : "NOT "); | ||
554 | ret += dso__fprintf_buildid(dso, fp); | ||
555 | ret += fprintf(fp, ")\n"); | ||
556 | for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { | ||
557 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
558 | ret += symbol__fprintf(pos, fp); | ||
559 | } | ||
560 | |||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | int kallsyms__parse(const char *filename, void *arg, | 424 | int kallsyms__parse(const char *filename, void *arg, |
565 | int (*process_symbol)(void *arg, const char *name, | 425 | int (*process_symbol)(void *arg, const char *name, |
566 | char type, u64 start)) | 426 | char type, u64 start)) |
@@ -892,136 +752,6 @@ out_failure: | |||
892 | return -1; | 752 | return -1; |
893 | } | 753 | } |
894 | 754 | ||
895 | bool dso__build_id_equal(const struct dso *dso, u8 *build_id) | ||
896 | { | ||
897 | return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; | ||
898 | } | ||
899 | |||
900 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | ||
901 | { | ||
902 | bool have_build_id = false; | ||
903 | struct dso *pos; | ||
904 | |||
905 | list_for_each_entry(pos, head, node) { | ||
906 | if (with_hits && !pos->hit) | ||
907 | continue; | ||
908 | if (pos->has_build_id) { | ||
909 | have_build_id = true; | ||
910 | continue; | ||
911 | } | ||
912 | if (filename__read_build_id(pos->long_name, pos->build_id, | ||
913 | sizeof(pos->build_id)) > 0) { | ||
914 | have_build_id = true; | ||
915 | pos->has_build_id = true; | ||
916 | } | ||
917 | } | ||
918 | |||
919 | return have_build_id; | ||
920 | } | ||
921 | |||
922 | char dso__symtab_origin(const struct dso *dso) | ||
923 | { | ||
924 | static const char origin[] = { | ||
925 | [DSO_BINARY_TYPE__KALLSYMS] = 'k', | ||
926 | [DSO_BINARY_TYPE__VMLINUX] = 'v', | ||
927 | [DSO_BINARY_TYPE__JAVA_JIT] = 'j', | ||
928 | [DSO_BINARY_TYPE__DEBUGLINK] = 'l', | ||
929 | [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', | ||
930 | [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', | ||
931 | [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', | ||
932 | [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', | ||
933 | [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', | ||
934 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', | ||
935 | [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', | ||
936 | [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', | ||
937 | [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', | ||
938 | }; | ||
939 | |||
940 | if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) | ||
941 | return '!'; | ||
942 | return origin[dso->symtab_type]; | ||
943 | } | ||
944 | |||
945 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | ||
946 | char *root_dir, char *file, size_t size) | ||
947 | { | ||
948 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | ||
949 | int ret = 0; | ||
950 | |||
951 | switch (type) { | ||
952 | case DSO_BINARY_TYPE__DEBUGLINK: { | ||
953 | char *debuglink; | ||
954 | |||
955 | strncpy(file, dso->long_name, size); | ||
956 | debuglink = file + dso->long_name_len; | ||
957 | while (debuglink != file && *debuglink != '/') | ||
958 | debuglink--; | ||
959 | if (*debuglink == '/') | ||
960 | debuglink++; | ||
961 | filename__read_debuglink(dso->long_name, debuglink, | ||
962 | size - (debuglink - file)); | ||
963 | } | ||
964 | break; | ||
965 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | ||
966 | /* skip the locally configured cache if a symfs is given */ | ||
967 | if (symbol_conf.symfs[0] || | ||
968 | (dso__build_id_filename(dso, file, size) == NULL)) | ||
969 | ret = -1; | ||
970 | break; | ||
971 | |||
972 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | ||
973 | snprintf(file, size, "%s/usr/lib/debug%s.debug", | ||
974 | symbol_conf.symfs, dso->long_name); | ||
975 | break; | ||
976 | |||
977 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | ||
978 | snprintf(file, size, "%s/usr/lib/debug%s", | ||
979 | symbol_conf.symfs, dso->long_name); | ||
980 | break; | ||
981 | |||
982 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: | ||
983 | if (!dso->has_build_id) { | ||
984 | ret = -1; | ||
985 | break; | ||
986 | } | ||
987 | |||
988 | build_id__sprintf(dso->build_id, | ||
989 | sizeof(dso->build_id), | ||
990 | build_id_hex); | ||
991 | snprintf(file, size, | ||
992 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
993 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); | ||
994 | break; | ||
995 | |||
996 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: | ||
997 | snprintf(file, size, "%s%s", | ||
998 | symbol_conf.symfs, dso->long_name); | ||
999 | break; | ||
1000 | |||
1001 | case DSO_BINARY_TYPE__GUEST_KMODULE: | ||
1002 | snprintf(file, size, "%s%s%s", symbol_conf.symfs, | ||
1003 | root_dir, dso->long_name); | ||
1004 | break; | ||
1005 | |||
1006 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | ||
1007 | snprintf(file, size, "%s%s", symbol_conf.symfs, | ||
1008 | dso->long_name); | ||
1009 | break; | ||
1010 | |||
1011 | default: | ||
1012 | case DSO_BINARY_TYPE__KALLSYMS: | ||
1013 | case DSO_BINARY_TYPE__VMLINUX: | ||
1014 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: | ||
1015 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | ||
1016 | case DSO_BINARY_TYPE__JAVA_JIT: | ||
1017 | case DSO_BINARY_TYPE__NOT_FOUND: | ||
1018 | ret = -1; | ||
1019 | break; | ||
1020 | } | ||
1021 | |||
1022 | return ret; | ||
1023 | } | ||
1024 | |||
1025 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | 755 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) |
1026 | { | 756 | { |
1027 | char *name; | 757 | char *name; |
@@ -1157,27 +887,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg, | |||
1157 | return NULL; | 887 | return NULL; |
1158 | } | 888 | } |
1159 | 889 | ||
1160 | static int dso__kernel_module_get_build_id(struct dso *dso, | ||
1161 | const char *root_dir) | ||
1162 | { | ||
1163 | char filename[PATH_MAX]; | ||
1164 | /* | ||
1165 | * kernel module short names are of the form "[module]" and | ||
1166 | * we need just "module" here. | ||
1167 | */ | ||
1168 | const char *name = dso->short_name + 1; | ||
1169 | |||
1170 | snprintf(filename, sizeof(filename), | ||
1171 | "%s/sys/module/%.*s/notes/.note.gnu.build-id", | ||
1172 | root_dir, (int)strlen(name) - 1, name); | ||
1173 | |||
1174 | if (sysfs__read_build_id(filename, dso->build_id, | ||
1175 | sizeof(dso->build_id)) == 0) | ||
1176 | dso->has_build_id = true; | ||
1177 | |||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | static int map_groups__set_modules_path_dir(struct map_groups *mg, | 890 | static int map_groups__set_modules_path_dir(struct map_groups *mg, |
1182 | const char *dir_name) | 891 | const char *dir_name) |
1183 | { | 892 | { |
@@ -1591,50 +1300,6 @@ out_try_fixup: | |||
1591 | return err; | 1300 | return err; |
1592 | } | 1301 | } |
1593 | 1302 | ||
1594 | void dsos__add(struct list_head *head, struct dso *dso) | ||
1595 | { | ||
1596 | list_add_tail(&dso->node, head); | ||
1597 | } | ||
1598 | |||
1599 | struct dso *dsos__find(struct list_head *head, const char *name) | ||
1600 | { | ||
1601 | struct dso *pos; | ||
1602 | |||
1603 | list_for_each_entry(pos, head, node) | ||
1604 | if (strcmp(pos->long_name, name) == 0) | ||
1605 | return pos; | ||
1606 | return NULL; | ||
1607 | } | ||
1608 | |||
1609 | struct dso *__dsos__findnew(struct list_head *head, const char *name) | ||
1610 | { | ||
1611 | struct dso *dso = dsos__find(head, name); | ||
1612 | |||
1613 | if (!dso) { | ||
1614 | dso = dso__new(name); | ||
1615 | if (dso != NULL) { | ||
1616 | dsos__add(head, dso); | ||
1617 | dso__set_basename(dso); | ||
1618 | } | ||
1619 | } | ||
1620 | |||
1621 | return dso; | ||
1622 | } | ||
1623 | |||
1624 | size_t __dsos__fprintf(struct list_head *head, FILE *fp) | ||
1625 | { | ||
1626 | struct dso *pos; | ||
1627 | size_t ret = 0; | ||
1628 | |||
1629 | list_for_each_entry(pos, head, node) { | ||
1630 | int i; | ||
1631 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
1632 | ret += dso__fprintf(pos, i, fp); | ||
1633 | } | ||
1634 | |||
1635 | return ret; | ||
1636 | } | ||
1637 | |||
1638 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) | 1303 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) |
1639 | { | 1304 | { |
1640 | struct rb_node *nd; | 1305 | struct rb_node *nd; |
@@ -1649,21 +1314,6 @@ size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) | |||
1649 | return ret; | 1314 | return ret; |
1650 | } | 1315 | } |
1651 | 1316 | ||
1652 | static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | ||
1653 | bool with_hits) | ||
1654 | { | ||
1655 | struct dso *pos; | ||
1656 | size_t ret = 0; | ||
1657 | |||
1658 | list_for_each_entry(pos, head, node) { | ||
1659 | if (with_hits && !pos->hit) | ||
1660 | continue; | ||
1661 | ret += dso__fprintf_buildid(pos, fp); | ||
1662 | ret += fprintf(fp, " %s\n", pos->long_name); | ||
1663 | } | ||
1664 | return ret; | ||
1665 | } | ||
1666 | |||
1667 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | 1317 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, |
1668 | bool with_hits) | 1318 | bool with_hits) |
1669 | { | 1319 | { |
@@ -1684,39 +1334,6 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | |||
1684 | return ret; | 1334 | return ret; |
1685 | } | 1335 | } |
1686 | 1336 | ||
1687 | static struct dso* | ||
1688 | dso__kernel_findnew(struct machine *machine, const char *name, | ||
1689 | const char *short_name, int dso_type) | ||
1690 | { | ||
1691 | /* | ||
1692 | * The kernel dso could be created by build_id processing. | ||
1693 | */ | ||
1694 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); | ||
1695 | |||
1696 | /* | ||
1697 | * We need to run this in all cases, since during the build_id | ||
1698 | * processing we had no idea this was the kernel dso. | ||
1699 | */ | ||
1700 | if (dso != NULL) { | ||
1701 | dso__set_short_name(dso, short_name); | ||
1702 | dso->kernel = dso_type; | ||
1703 | } | ||
1704 | |||
1705 | return dso; | ||
1706 | } | ||
1707 | |||
1708 | void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) | ||
1709 | { | ||
1710 | char path[PATH_MAX]; | ||
1711 | |||
1712 | if (machine__is_default_guest(machine)) | ||
1713 | return; | ||
1714 | sprintf(path, "%s/sys/kernel/notes", machine->root_dir); | ||
1715 | if (sysfs__read_build_id(path, dso->build_id, | ||
1716 | sizeof(dso->build_id)) == 0) | ||
1717 | dso->has_build_id = true; | ||
1718 | } | ||
1719 | |||
1720 | static struct dso *machine__get_kernel(struct machine *machine) | 1337 | static struct dso *machine__get_kernel(struct machine *machine) |
1721 | { | 1338 | { |
1722 | const char *vmlinux_name = NULL; | 1339 | const char *vmlinux_name = NULL; |
@@ -2065,49 +1682,6 @@ int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) | |||
2065 | return machine__create_kernel_maps(machine); | 1682 | return machine__create_kernel_maps(machine); |
2066 | } | 1683 | } |
2067 | 1684 | ||
2068 | static int hex(char ch) | ||
2069 | { | ||
2070 | if ((ch >= '0') && (ch <= '9')) | ||
2071 | return ch - '0'; | ||
2072 | if ((ch >= 'a') && (ch <= 'f')) | ||
2073 | return ch - 'a' + 10; | ||
2074 | if ((ch >= 'A') && (ch <= 'F')) | ||
2075 | return ch - 'A' + 10; | ||
2076 | return -1; | ||
2077 | } | ||
2078 | |||
2079 | /* | ||
2080 | * While we find nice hex chars, build a long_val. | ||
2081 | * Return number of chars processed. | ||
2082 | */ | ||
2083 | int hex2u64(const char *ptr, u64 *long_val) | ||
2084 | { | ||
2085 | const char *p = ptr; | ||
2086 | *long_val = 0; | ||
2087 | |||
2088 | while (*p) { | ||
2089 | const int hex_val = hex(*p); | ||
2090 | |||
2091 | if (hex_val < 0) | ||
2092 | break; | ||
2093 | |||
2094 | *long_val = (*long_val << 4) | hex_val; | ||
2095 | p++; | ||
2096 | } | ||
2097 | |||
2098 | return p - ptr; | ||
2099 | } | ||
2100 | |||
2101 | char *strxfrchar(char *s, char from, char to) | ||
2102 | { | ||
2103 | char *p = s; | ||
2104 | |||
2105 | while ((p = strchr(p, from)) != NULL) | ||
2106 | *p++ = to; | ||
2107 | |||
2108 | return s; | ||
2109 | } | ||
2110 | |||
2111 | int machines__create_guest_kernel_maps(struct rb_root *machines) | 1685 | int machines__create_guest_kernel_maps(struct rb_root *machines) |
2112 | { | 1686 | { |
2113 | int ret = 0; | 1687 | int ret = 0; |
@@ -2202,229 +1776,3 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | |||
2202 | 1776 | ||
2203 | return ret; | 1777 | return ret; |
2204 | } | 1778 | } |
2205 | |||
2206 | struct map *dso__new_map(const char *name) | ||
2207 | { | ||
2208 | struct map *map = NULL; | ||
2209 | struct dso *dso = dso__new(name); | ||
2210 | |||
2211 | if (dso) | ||
2212 | map = map__new2(0, dso, MAP__FUNCTION); | ||
2213 | |||
2214 | return map; | ||
2215 | } | ||
2216 | |||
2217 | static int open_dso(struct dso *dso, struct machine *machine) | ||
2218 | { | ||
2219 | char *root_dir = (char *) ""; | ||
2220 | char *name; | ||
2221 | int fd; | ||
2222 | |||
2223 | name = malloc(PATH_MAX); | ||
2224 | if (!name) | ||
2225 | return -ENOMEM; | ||
2226 | |||
2227 | if (machine) | ||
2228 | root_dir = machine->root_dir; | ||
2229 | |||
2230 | if (dso__binary_type_file(dso, dso->data_type, | ||
2231 | root_dir, name, PATH_MAX)) { | ||
2232 | free(name); | ||
2233 | return -EINVAL; | ||
2234 | } | ||
2235 | |||
2236 | fd = open(name, O_RDONLY); | ||
2237 | free(name); | ||
2238 | return fd; | ||
2239 | } | ||
2240 | |||
2241 | int dso__data_fd(struct dso *dso, struct machine *machine) | ||
2242 | { | ||
2243 | int i = 0; | ||
2244 | |||
2245 | if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) | ||
2246 | return open_dso(dso, machine); | ||
2247 | |||
2248 | do { | ||
2249 | int fd; | ||
2250 | |||
2251 | dso->data_type = binary_type_data[i++]; | ||
2252 | |||
2253 | fd = open_dso(dso, machine); | ||
2254 | if (fd >= 0) | ||
2255 | return fd; | ||
2256 | |||
2257 | } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); | ||
2258 | |||
2259 | return -EINVAL; | ||
2260 | } | ||
2261 | |||
2262 | static void | ||
2263 | dso_cache__free(struct rb_root *root) | ||
2264 | { | ||
2265 | struct rb_node *next = rb_first(root); | ||
2266 | |||
2267 | while (next) { | ||
2268 | struct dso_cache *cache; | ||
2269 | |||
2270 | cache = rb_entry(next, struct dso_cache, rb_node); | ||
2271 | next = rb_next(&cache->rb_node); | ||
2272 | rb_erase(&cache->rb_node, root); | ||
2273 | free(cache); | ||
2274 | } | ||
2275 | } | ||
2276 | |||
2277 | static struct dso_cache* | ||
2278 | dso_cache__find(struct rb_root *root, u64 offset) | ||
2279 | { | ||
2280 | struct rb_node **p = &root->rb_node; | ||
2281 | struct rb_node *parent = NULL; | ||
2282 | struct dso_cache *cache; | ||
2283 | |||
2284 | while (*p != NULL) { | ||
2285 | u64 end; | ||
2286 | |||
2287 | parent = *p; | ||
2288 | cache = rb_entry(parent, struct dso_cache, rb_node); | ||
2289 | end = cache->offset + DSO__DATA_CACHE_SIZE; | ||
2290 | |||
2291 | if (offset < cache->offset) | ||
2292 | p = &(*p)->rb_left; | ||
2293 | else if (offset >= end) | ||
2294 | p = &(*p)->rb_right; | ||
2295 | else | ||
2296 | return cache; | ||
2297 | } | ||
2298 | return NULL; | ||
2299 | } | ||
2300 | |||
2301 | static void | ||
2302 | dso_cache__insert(struct rb_root *root, struct dso_cache *new) | ||
2303 | { | ||
2304 | struct rb_node **p = &root->rb_node; | ||
2305 | struct rb_node *parent = NULL; | ||
2306 | struct dso_cache *cache; | ||
2307 | u64 offset = new->offset; | ||
2308 | |||
2309 | while (*p != NULL) { | ||
2310 | u64 end; | ||
2311 | |||
2312 | parent = *p; | ||
2313 | cache = rb_entry(parent, struct dso_cache, rb_node); | ||
2314 | end = cache->offset + DSO__DATA_CACHE_SIZE; | ||
2315 | |||
2316 | if (offset < cache->offset) | ||
2317 | p = &(*p)->rb_left; | ||
2318 | else if (offset >= end) | ||
2319 | p = &(*p)->rb_right; | ||
2320 | } | ||
2321 | |||
2322 | rb_link_node(&new->rb_node, parent, p); | ||
2323 | rb_insert_color(&new->rb_node, root); | ||
2324 | } | ||
2325 | |||
2326 | static ssize_t | ||
2327 | dso_cache__memcpy(struct dso_cache *cache, u64 offset, | ||
2328 | u8 *data, u64 size) | ||
2329 | { | ||
2330 | u64 cache_offset = offset - cache->offset; | ||
2331 | u64 cache_size = min(cache->size - cache_offset, size); | ||
2332 | |||
2333 | memcpy(data, cache->data + cache_offset, cache_size); | ||
2334 | return cache_size; | ||
2335 | } | ||
2336 | |||
2337 | static ssize_t | ||
2338 | dso_cache__read(struct dso *dso, struct machine *machine, | ||
2339 | u64 offset, u8 *data, ssize_t size) | ||
2340 | { | ||
2341 | struct dso_cache *cache; | ||
2342 | ssize_t ret; | ||
2343 | int fd; | ||
2344 | |||
2345 | fd = dso__data_fd(dso, machine); | ||
2346 | if (fd < 0) | ||
2347 | return -1; | ||
2348 | |||
2349 | do { | ||
2350 | u64 cache_offset; | ||
2351 | |||
2352 | ret = -ENOMEM; | ||
2353 | |||
2354 | cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); | ||
2355 | if (!cache) | ||
2356 | break; | ||
2357 | |||
2358 | cache_offset = offset & DSO__DATA_CACHE_MASK; | ||
2359 | ret = -EINVAL; | ||
2360 | |||
2361 | if (-1 == lseek(fd, cache_offset, SEEK_SET)) | ||
2362 | break; | ||
2363 | |||
2364 | ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); | ||
2365 | if (ret <= 0) | ||
2366 | break; | ||
2367 | |||
2368 | cache->offset = cache_offset; | ||
2369 | cache->size = ret; | ||
2370 | dso_cache__insert(&dso->cache, cache); | ||
2371 | |||
2372 | ret = dso_cache__memcpy(cache, offset, data, size); | ||
2373 | |||
2374 | } while (0); | ||
2375 | |||
2376 | if (ret <= 0) | ||
2377 | free(cache); | ||
2378 | |||
2379 | close(fd); | ||
2380 | return ret; | ||
2381 | } | ||
2382 | |||
2383 | static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, | ||
2384 | u64 offset, u8 *data, ssize_t size) | ||
2385 | { | ||
2386 | struct dso_cache *cache; | ||
2387 | |||
2388 | cache = dso_cache__find(&dso->cache, offset); | ||
2389 | if (cache) | ||
2390 | return dso_cache__memcpy(cache, offset, data, size); | ||
2391 | else | ||
2392 | return dso_cache__read(dso, machine, offset, data, size); | ||
2393 | } | ||
2394 | |||
2395 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | ||
2396 | u64 offset, u8 *data, ssize_t size) | ||
2397 | { | ||
2398 | ssize_t r = 0; | ||
2399 | u8 *p = data; | ||
2400 | |||
2401 | do { | ||
2402 | ssize_t ret; | ||
2403 | |||
2404 | ret = dso_cache_read(dso, machine, offset, p, size); | ||
2405 | if (ret < 0) | ||
2406 | return ret; | ||
2407 | |||
2408 | /* Reached EOF, return what we have. */ | ||
2409 | if (!ret) | ||
2410 | break; | ||
2411 | |||
2412 | BUG_ON(ret > size); | ||
2413 | |||
2414 | r += ret; | ||
2415 | p += ret; | ||
2416 | offset += ret; | ||
2417 | size -= ret; | ||
2418 | |||
2419 | } while (size); | ||
2420 | |||
2421 | return r; | ||
2422 | } | ||
2423 | |||
2424 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | ||
2425 | struct machine *machine, u64 addr, | ||
2426 | u8 *data, ssize_t size) | ||
2427 | { | ||
2428 | u64 offset = map->map_ip(map, addr); | ||
2429 | return dso__data_read_offset(dso, machine, offset, data, size); | ||
2430 | } | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 8b6ef7fac745..de68f98b236d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <stdio.h> | 11 | #include <stdio.h> |
12 | #include <byteswap.h> | 12 | #include <byteswap.h> |
13 | #include <libgen.h> | 13 | #include <libgen.h> |
14 | #include "build-id.h" | ||
14 | 15 | ||
15 | #ifdef LIBELF_SUPPORT | 16 | #ifdef LIBELF_SUPPORT |
16 | #include <libelf.h> | 17 | #include <libelf.h> |
@@ -18,6 +19,8 @@ | |||
18 | #include <elf.h> | 19 | #include <elf.h> |
19 | #endif | 20 | #endif |
20 | 21 | ||
22 | #include "dso.h" | ||
23 | |||
21 | #ifdef HAVE_CPLUS_DEMANGLE | 24 | #ifdef HAVE_CPLUS_DEMANGLE |
22 | extern char *cplus_demangle(const char *, int); | 25 | extern char *cplus_demangle(const char *, int); |
23 | 26 | ||
@@ -39,9 +42,6 @@ static inline char *bfd_demangle(void __maybe_unused *v, | |||
39 | #endif | 42 | #endif |
40 | #endif | 43 | #endif |
41 | 44 | ||
42 | int hex2u64(const char *ptr, u64 *val); | ||
43 | char *strxfrchar(char *s, char from, char to); | ||
44 | |||
45 | /* | 45 | /* |
46 | * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; | 46 | * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; |
47 | * for newer versions we can use mmap to reduce memory usage: | 47 | * for newer versions we can use mmap to reduce memory usage: |
@@ -57,8 +57,6 @@ char *strxfrchar(char *s, char from, char to); | |||
57 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ | 57 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ |
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | #define BUILD_ID_SIZE 20 | ||
61 | |||
62 | /** struct symbol - symtab entry | 60 | /** struct symbol - symtab entry |
63 | * | 61 | * |
64 | * @ignore - resolvable but tools ignore it (e.g. idle routines) | 62 | * @ignore - resolvable but tools ignore it (e.g. idle routines) |
@@ -74,6 +72,7 @@ struct symbol { | |||
74 | }; | 72 | }; |
75 | 73 | ||
76 | void symbol__delete(struct symbol *sym); | 74 | void symbol__delete(struct symbol *sym); |
75 | void symbols__delete(struct rb_root *symbols); | ||
77 | 76 | ||
78 | static inline size_t symbol__size(const struct symbol *sym) | 77 | static inline size_t symbol__size(const struct symbol *sym) |
79 | { | 78 | { |
@@ -164,70 +163,6 @@ struct addr_location { | |||
164 | s32 cpu; | 163 | s32 cpu; |
165 | }; | 164 | }; |
166 | 165 | ||
167 | enum dso_binary_type { | ||
168 | DSO_BINARY_TYPE__KALLSYMS = 0, | ||
169 | DSO_BINARY_TYPE__GUEST_KALLSYMS, | ||
170 | DSO_BINARY_TYPE__VMLINUX, | ||
171 | DSO_BINARY_TYPE__GUEST_VMLINUX, | ||
172 | DSO_BINARY_TYPE__JAVA_JIT, | ||
173 | DSO_BINARY_TYPE__DEBUGLINK, | ||
174 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | ||
175 | DSO_BINARY_TYPE__FEDORA_DEBUGINFO, | ||
176 | DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, | ||
177 | DSO_BINARY_TYPE__BUILDID_DEBUGINFO, | ||
178 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | ||
179 | DSO_BINARY_TYPE__GUEST_KMODULE, | ||
180 | DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, | ||
181 | DSO_BINARY_TYPE__NOT_FOUND, | ||
182 | }; | ||
183 | |||
184 | enum dso_kernel_type { | ||
185 | DSO_TYPE_USER = 0, | ||
186 | DSO_TYPE_KERNEL, | ||
187 | DSO_TYPE_GUEST_KERNEL | ||
188 | }; | ||
189 | |||
190 | enum dso_swap_type { | ||
191 | DSO_SWAP__UNSET, | ||
192 | DSO_SWAP__NO, | ||
193 | DSO_SWAP__YES, | ||
194 | }; | ||
195 | |||
196 | #define DSO__DATA_CACHE_SIZE 4096 | ||
197 | #define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1) | ||
198 | |||
199 | struct dso_cache { | ||
200 | struct rb_node rb_node; | ||
201 | u64 offset; | ||
202 | u64 size; | ||
203 | char data[0]; | ||
204 | }; | ||
205 | |||
206 | struct dso { | ||
207 | struct list_head node; | ||
208 | struct rb_root symbols[MAP__NR_TYPES]; | ||
209 | struct rb_root symbol_names[MAP__NR_TYPES]; | ||
210 | struct rb_root cache; | ||
211 | enum dso_kernel_type kernel; | ||
212 | enum dso_swap_type needs_swap; | ||
213 | enum dso_binary_type symtab_type; | ||
214 | enum dso_binary_type data_type; | ||
215 | u8 adjust_symbols:1; | ||
216 | u8 has_build_id:1; | ||
217 | u8 hit:1; | ||
218 | u8 annotate_warned:1; | ||
219 | u8 sname_alloc:1; | ||
220 | u8 lname_alloc:1; | ||
221 | u8 sorted_by_name; | ||
222 | u8 loaded; | ||
223 | u8 build_id[BUILD_ID_SIZE]; | ||
224 | const char *short_name; | ||
225 | char *long_name; | ||
226 | u16 long_name_len; | ||
227 | u16 short_name_len; | ||
228 | char name[0]; | ||
229 | }; | ||
230 | |||
231 | struct symsrc { | 166 | struct symsrc { |
232 | char *name; | 167 | char *name; |
233 | int fd; | 168 | int fd; |
@@ -258,47 +193,6 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, | |||
258 | bool symsrc__has_symtab(struct symsrc *ss); | 193 | bool symsrc__has_symtab(struct symsrc *ss); |
259 | bool symsrc__possibly_runtime(struct symsrc *ss); | 194 | bool symsrc__possibly_runtime(struct symsrc *ss); |
260 | 195 | ||
261 | #define DSO__SWAP(dso, type, val) \ | ||
262 | ({ \ | ||
263 | type ____r = val; \ | ||
264 | BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \ | ||
265 | if (dso->needs_swap == DSO_SWAP__YES) { \ | ||
266 | switch (sizeof(____r)) { \ | ||
267 | case 2: \ | ||
268 | ____r = bswap_16(val); \ | ||
269 | break; \ | ||
270 | case 4: \ | ||
271 | ____r = bswap_32(val); \ | ||
272 | break; \ | ||
273 | case 8: \ | ||
274 | ____r = bswap_64(val); \ | ||
275 | break; \ | ||
276 | default: \ | ||
277 | BUG_ON(1); \ | ||
278 | } \ | ||
279 | } \ | ||
280 | ____r; \ | ||
281 | }) | ||
282 | |||
283 | struct dso *dso__new(const char *name); | ||
284 | void dso__delete(struct dso *dso); | ||
285 | |||
286 | int dso__name_len(const struct dso *dso); | ||
287 | |||
288 | bool dso__loaded(const struct dso *dso, enum map_type type); | ||
289 | bool dso__sorted_by_name(const struct dso *dso, enum map_type type); | ||
290 | |||
291 | static inline void dso__set_loaded(struct dso *dso, enum map_type type) | ||
292 | { | ||
293 | dso->loaded |= (1 << type); | ||
294 | } | ||
295 | |||
296 | void dso__sort_by_name(struct dso *dso, enum map_type type); | ||
297 | |||
298 | void dsos__add(struct list_head *head, struct dso *dso); | ||
299 | struct dso *dsos__find(struct list_head *head, const char *name); | ||
300 | struct dso *__dsos__findnew(struct list_head *head, const char *name); | ||
301 | |||
302 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); | 196 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); |
303 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 197 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
304 | const char *vmlinux, symbol_filter_t filter); | 198 | const char *vmlinux, symbol_filter_t filter); |
@@ -306,30 +200,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
306 | symbol_filter_t filter); | 200 | symbol_filter_t filter); |
307 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, | 201 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, |
308 | symbol_filter_t filter); | 202 | symbol_filter_t filter); |
309 | int machine__load_kallsyms(struct machine *machine, const char *filename, | 203 | |
310 | enum map_type type, symbol_filter_t filter); | ||
311 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | ||
312 | symbol_filter_t filter); | ||
313 | |||
314 | size_t __dsos__fprintf(struct list_head *head, FILE *fp); | ||
315 | |||
316 | size_t machine__fprintf_dsos_buildid(struct machine *machine, | ||
317 | FILE *fp, bool with_hits); | ||
318 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); | ||
319 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | ||
320 | FILE *fp, bool with_hits); | ||
321 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); | ||
322 | size_t dso__fprintf_symbols_by_name(struct dso *dso, | ||
323 | enum map_type type, FILE *fp); | ||
324 | size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); | ||
325 | |||
326 | char dso__symtab_origin(const struct dso *dso); | ||
327 | void dso__set_long_name(struct dso *dso, char *name); | ||
328 | void dso__set_build_id(struct dso *dso, void *build_id); | ||
329 | bool dso__build_id_equal(const struct dso *dso, u8 *build_id); | ||
330 | void dso__read_running_kernel_build_id(struct dso *dso, | ||
331 | struct machine *machine); | ||
332 | struct map *dso__new_map(const char *name); | ||
333 | struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, | 204 | struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, |
334 | u64 addr); | 205 | u64 addr); |
335 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 206 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
@@ -337,22 +208,12 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | |||
337 | 208 | ||
338 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 209 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
339 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 210 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
340 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); | ||
341 | int build_id__sprintf(const u8 *build_id, int len, char *bf); | ||
342 | int kallsyms__parse(const char *filename, void *arg, | 211 | int kallsyms__parse(const char *filename, void *arg, |
343 | int (*process_symbol)(void *arg, const char *name, | 212 | int (*process_symbol)(void *arg, const char *name, |
344 | char type, u64 start)); | 213 | char type, u64 start)); |
345 | int filename__read_debuglink(const char *filename, char *debuglink, | 214 | int filename__read_debuglink(const char *filename, char *debuglink, |
346 | size_t size); | 215 | size_t size); |
347 | 216 | ||
348 | void machine__destroy_kernel_maps(struct machine *machine); | ||
349 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); | ||
350 | int machine__create_kernel_maps(struct machine *machine); | ||
351 | |||
352 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); | ||
353 | int machines__create_guest_kernel_maps(struct rb_root *machines); | ||
354 | void machines__destroy_guest_kernel_maps(struct rb_root *machines); | ||
355 | |||
356 | int symbol__init(void); | 217 | int symbol__init(void); |
357 | void symbol__exit(void); | 218 | void symbol__exit(void); |
358 | void symbol__elf_init(void); | 219 | void symbol__elf_init(void); |
@@ -360,20 +221,9 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); | |||
360 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | 221 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, |
361 | const struct addr_location *al, FILE *fp); | 222 | const struct addr_location *al, FILE *fp); |
362 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); | 223 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); |
224 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); | ||
363 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 225 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
364 | 226 | ||
365 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); | ||
366 | |||
367 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | ||
368 | char *root_dir, char *file, size_t size); | ||
369 | |||
370 | int dso__data_fd(struct dso *dso, struct machine *machine); | ||
371 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | ||
372 | u64 offset, u8 *data, ssize_t size); | ||
373 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | ||
374 | struct machine *machine, u64 addr, | ||
375 | u8 *data, ssize_t size); | ||
376 | int dso__test_data(void); | ||
377 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | 227 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, |
378 | struct symsrc *runtime_ss, symbol_filter_t filter, | 228 | struct symsrc *runtime_ss, symbol_filter_t filter, |
379 | int kmodule); | 229 | int kmodule); |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index fb4b7ea6752f..df59623ac763 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -7,7 +7,7 @@ | |||
7 | #include "util.h" | 7 | #include "util.h" |
8 | #include "debug.h" | 8 | #include "debug.h" |
9 | 9 | ||
10 | static struct thread *thread__new(pid_t pid) | 10 | struct thread *thread__new(pid_t pid) |
11 | { | 11 | { |
12 | struct thread *self = zalloc(sizeof(*self)); | 12 | struct thread *self = zalloc(sizeof(*self)); |
13 | 13 | ||
@@ -39,7 +39,6 @@ int thread__set_comm(struct thread *self, const char *comm) | |||
39 | err = self->comm == NULL ? -ENOMEM : 0; | 39 | err = self->comm == NULL ? -ENOMEM : 0; |
40 | if (!err) { | 40 | if (!err) { |
41 | self->comm_set = true; | 41 | self->comm_set = true; |
42 | map_groups__flush(&self->mg); | ||
43 | } | 42 | } |
44 | return err; | 43 | return err; |
45 | } | 44 | } |
@@ -61,45 +60,6 @@ static size_t thread__fprintf(struct thread *self, FILE *fp) | |||
61 | map_groups__fprintf(&self->mg, verbose, fp); | 60 | map_groups__fprintf(&self->mg, verbose, fp); |
62 | } | 61 | } |
63 | 62 | ||
64 | struct thread *machine__findnew_thread(struct machine *self, pid_t pid) | ||
65 | { | ||
66 | struct rb_node **p = &self->threads.rb_node; | ||
67 | struct rb_node *parent = NULL; | ||
68 | struct thread *th; | ||
69 | |||
70 | /* | ||
71 | * Font-end cache - PID lookups come in blocks, | ||
72 | * so most of the time we dont have to look up | ||
73 | * the full rbtree: | ||
74 | */ | ||
75 | if (self->last_match && self->last_match->pid == pid) | ||
76 | return self->last_match; | ||
77 | |||
78 | while (*p != NULL) { | ||
79 | parent = *p; | ||
80 | th = rb_entry(parent, struct thread, rb_node); | ||
81 | |||
82 | if (th->pid == pid) { | ||
83 | self->last_match = th; | ||
84 | return th; | ||
85 | } | ||
86 | |||
87 | if (pid < th->pid) | ||
88 | p = &(*p)->rb_left; | ||
89 | else | ||
90 | p = &(*p)->rb_right; | ||
91 | } | ||
92 | |||
93 | th = thread__new(pid); | ||
94 | if (th != NULL) { | ||
95 | rb_link_node(&th->rb_node, parent, p); | ||
96 | rb_insert_color(&th->rb_node, &self->threads); | ||
97 | self->last_match = th; | ||
98 | } | ||
99 | |||
100 | return th; | ||
101 | } | ||
102 | |||
103 | void thread__insert_map(struct thread *self, struct map *map) | 63 | void thread__insert_map(struct thread *self, struct map *map) |
104 | { | 64 | { |
105 | map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); | 65 | map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index f66610b7bacf..f2fa17caa7d5 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/rbtree.h> | 4 | #include <linux/rbtree.h> |
5 | #include <unistd.h> | 5 | #include <unistd.h> |
6 | #include <sys/types.h> | ||
6 | #include "symbol.h" | 7 | #include "symbol.h" |
7 | 8 | ||
8 | struct thread { | 9 | struct thread { |
@@ -22,6 +23,7 @@ struct thread { | |||
22 | 23 | ||
23 | struct machine; | 24 | struct machine; |
24 | 25 | ||
26 | struct thread *thread__new(pid_t pid); | ||
25 | void thread__delete(struct thread *self); | 27 | void thread__delete(struct thread *self); |
26 | 28 | ||
27 | int thread__set_comm(struct thread *self, const char *comm); | 29 | int thread__set_comm(struct thread *self, const char *comm); |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 719ed74a8565..3741572696af 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -47,8 +47,6 @@ int file_bigendian; | |||
47 | int host_bigendian; | 47 | int host_bigendian; |
48 | static int long_size; | 48 | static int long_size; |
49 | 49 | ||
50 | static unsigned long page_size; | ||
51 | |||
52 | static ssize_t calc_data_size; | 50 | static ssize_t calc_data_size; |
53 | static bool repipe; | 51 | static bool repipe; |
54 | 52 | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 99664598bc1a..5906e8426cc7 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -10,6 +10,8 @@ | |||
10 | /* | 10 | /* |
11 | * XXX We need to find a better place for these things... | 11 | * XXX We need to find a better place for these things... |
12 | */ | 12 | */ |
13 | unsigned int page_size; | ||
14 | |||
13 | bool perf_host = true; | 15 | bool perf_host = true; |
14 | bool perf_guest = false; | 16 | bool perf_guest = false; |
15 | 17 | ||
@@ -164,6 +166,39 @@ size_t hex_width(u64 v) | |||
164 | return n; | 166 | return n; |
165 | } | 167 | } |
166 | 168 | ||
169 | static int hex(char ch) | ||
170 | { | ||
171 | if ((ch >= '0') && (ch <= '9')) | ||
172 | return ch - '0'; | ||
173 | if ((ch >= 'a') && (ch <= 'f')) | ||
174 | return ch - 'a' + 10; | ||
175 | if ((ch >= 'A') && (ch <= 'F')) | ||
176 | return ch - 'A' + 10; | ||
177 | return -1; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * While we find nice hex chars, build a long_val. | ||
182 | * Return number of chars processed. | ||
183 | */ | ||
184 | int hex2u64(const char *ptr, u64 *long_val) | ||
185 | { | ||
186 | const char *p = ptr; | ||
187 | *long_val = 0; | ||
188 | |||
189 | while (*p) { | ||
190 | const int hex_val = hex(*p); | ||
191 | |||
192 | if (hex_val < 0) | ||
193 | break; | ||
194 | |||
195 | *long_val = (*long_val << 4) | hex_val; | ||
196 | p++; | ||
197 | } | ||
198 | |||
199 | return p - ptr; | ||
200 | } | ||
201 | |||
167 | /* Obtain a backtrace and print it to stdout. */ | 202 | /* Obtain a backtrace and print it to stdout. */ |
168 | #ifdef BACKTRACE_SUPPORT | 203 | #ifdef BACKTRACE_SUPPORT |
169 | void dump_stack(void) | 204 | void dump_stack(void) |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 70fa70b535b2..c2330918110c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -198,6 +198,10 @@ static inline int has_extension(const char *filename, const char *ext) | |||
198 | #undef tolower | 198 | #undef tolower |
199 | #undef toupper | 199 | #undef toupper |
200 | 200 | ||
201 | #ifndef NSEC_PER_MSEC | ||
202 | #define NSEC_PER_MSEC 1000000L | ||
203 | #endif | ||
204 | |||
201 | extern unsigned char sane_ctype[256]; | 205 | extern unsigned char sane_ctype[256]; |
202 | #define GIT_SPACE 0x01 | 206 | #define GIT_SPACE 0x01 |
203 | #define GIT_DIGIT 0x02 | 207 | #define GIT_DIGIT 0x02 |
@@ -236,6 +240,7 @@ void argv_free(char **argv); | |||
236 | bool strglobmatch(const char *str, const char *pat); | 240 | bool strglobmatch(const char *str, const char *pat); |
237 | bool strlazymatch(const char *str, const char *pat); | 241 | bool strlazymatch(const char *str, const char *pat); |
238 | int strtailcmp(const char *s1, const char *s2); | 242 | int strtailcmp(const char *s1, const char *s2); |
243 | char *strxfrchar(char *s, char from, char to); | ||
239 | unsigned long convert_unit(unsigned long value, char *unit); | 244 | unsigned long convert_unit(unsigned long value, char *unit); |
240 | int readn(int fd, void *buf, size_t size); | 245 | int readn(int fd, void *buf, size_t size); |
241 | 246 | ||
@@ -258,9 +263,12 @@ bool is_power_of_2(unsigned long n) | |||
258 | } | 263 | } |
259 | 264 | ||
260 | size_t hex_width(u64 v); | 265 | size_t hex_width(u64 v); |
266 | int hex2u64(const char *ptr, u64 *val); | ||
261 | 267 | ||
262 | char *rtrim(char *s); | 268 | char *rtrim(char *s); |
263 | 269 | ||
264 | void dump_stack(void); | 270 | void dump_stack(void); |
265 | 271 | ||
272 | extern unsigned int page_size; | ||
273 | |||
266 | #endif | 274 | #endif |