aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorMichal Marek <mmarek@suse.cz>2013-02-25 15:50:05 -0500
committerMichal Marek <mmarek@suse.cz>2013-02-25 15:51:57 -0500
commite3900e74f26fc924c8e9e2a922bd40369b0bb517 (patch)
tree6e868575d346032ba9408f350c6e5369e0e52b0d /tools/perf/util
parent62dc989921df2a98d1a73aacd085abe941cb9828 (diff)
parent02f3e53a131c8aa3fe3c954058f1add5beeae621 (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')
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN14
-rw-r--r--tools/perf/util/annotate.c72
-rw-r--r--tools/perf/util/annotate.h10
-rw-r--r--tools/perf/util/build-id.c27
-rw-r--r--tools/perf/util/build-id.h11
-rw-r--r--tools/perf/util/cache.h39
-rw-r--r--tools/perf/util/debug.h1
-rw-r--r--tools/perf/util/dso-test-data.c153
-rw-r--r--tools/perf/util/dso.c595
-rw-r--r--tools/perf/util/dso.h148
-rw-r--r--tools/perf/util/event.c302
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/evlist.c13
-rw-r--r--tools/perf/util/evsel.c56
-rw-r--r--tools/perf/util/evsel.h11
-rw-r--r--tools/perf/util/header.c13
-rw-r--r--tools/perf/util/header.h3
-rw-r--r--tools/perf/util/hist.c99
-rw-r--r--tools/perf/util/hist.h49
-rw-r--r--tools/perf/util/machine.c464
-rw-r--r--tools/perf/util/machine.h148
-rw-r--r--tools/perf/util/map.c182
-rw-r--r--tools/perf/util/map.h93
-rw-r--r--tools/perf/util/parse-events-test.c1044
-rw-r--r--tools/perf/util/parse-events.c59
-rw-r--r--tools/perf/util/parse-events.h5
-rw-r--r--tools/perf/util/parse-events.l4
-rw-r--r--tools/perf/util/parse-events.y18
-rw-r--r--tools/perf/util/pmu.c192
-rw-r--r--tools/perf/util/pmu.h6
-rw-r--r--tools/perf/util/pstack.c46
-rw-r--r--tools/perf/util/python.c2
-rw-r--r--tools/perf/util/rblist.c4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c5
-rw-r--r--tools/perf/util/session.h7
-rw-r--r--tools/perf/util/setup.py2
-rw-r--r--tools/perf/util/sort.c6
-rw-r--r--tools/perf/util/sort.h45
-rw-r--r--tools/perf/util/strbuf.c8
-rw-r--r--tools/perf/util/string.c18
-rw-r--r--tools/perf/util/symbol.c658
-rw-r--r--tools/perf/util/symbol.h162
-rw-r--r--tools/perf/util/thread.c42
-rw-r--r--tools/perf/util/thread.h2
-rw-r--r--tools/perf/util/trace-event-read.c2
-rw-r--r--tools/perf/util/util.c35
-rw-r--r--tools/perf/util/util.h8
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
9LF=' 9LF='
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#
14if test -d ../../.git -o -f ../../.git && 16if 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
23then 18then
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');
25else 21else
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
19const char *disassembler_style; 20const char *disassembler_style;
20const char *objdump_path; 21const 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
405static int ins__cmp(const void *name, const void *insp) 408static 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
885static 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
905static 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
873static void symbol__free_source_line(struct symbol *sym, int len) 923static 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 {
75struct source_line { 76struct 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
142int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 144int 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
145static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, 147static 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
156extern const char *disassembler_style; 157extern const char *disassembler_style;
157extern 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
19static int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 19int 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,
64struct perf_tool build_id__mark_dso_hit_ops = { 64struct 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
73int 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
73char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 88char *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
6extern struct perf_tool build_id__mark_dso_hit_ops; 9extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso;
7 11
12int build_id__sprintf(const u8 *build_id, int len, char *bf);
8char *dso__build_id_filename(struct dso *self, char *bf, size_t size); 13char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
9 14
15int 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;
31extern int pager_in_use(void); 32extern int pager_in_use(void);
32extern int pager_use_color; 33extern int pager_use_color;
33 34
34extern int use_browser;
35
36#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT)
37void setup_browser(bool fallback_to_pager);
38void exit_browser(bool wait_for_ok);
39
40#ifdef NEWT_SUPPORT
41int ui__init(void);
42void ui__exit(bool wait_for_ok);
43#else
44static inline int ui__init(void)
45{
46 return -1;
47}
48static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
49#endif
50
51#ifdef GTK2_SUPPORT
52int perf_gtk__init(void);
53void perf_gtk__exit(bool wait_for_ok);
54#else
55static inline int perf_gtk__init(void)
56{
57 return -1;
58}
59static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
60#endif
61
62#else /* NEWT_SUPPORT || GTK2_SUPPORT */
63
64static inline void setup_browser(bool fallback_to_pager)
65{
66 if (fallback_to_pager)
67 setup_pager();
68}
69static inline void exit_browser(bool wait_for_ok __maybe_unused) {}
70#endif /* NEWT_SUPPORT || GTK2_SUPPORT */
71
72char *alias_lookup(const char *alias); 35char *alias_lookup(const char *alias);
73int split_cmdline(char *cmdline, const char ***argv); 36int 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)));
26static inline void ui_progress__update(u64 curr __maybe_unused, 26static 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) {}
29static 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) \
12do { \
13 if (!(cond)) { \
14 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
15 return -1; \
16 } \
17} while (0)
18
19static 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
46struct test_data_offset {
47 off_t offset;
48 u8 data[10];
49 int size;
50};
51
52struct 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
97int 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
7char 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
30int 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
110static 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
134int 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
160static void
161dso_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
175static struct dso_cache*
176dso_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
199static void
200dso_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
224static ssize_t
225dso_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
235static ssize_t
236dso_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
281static 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
293ssize_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
322ssize_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
330struct 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
341struct 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
361void 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
369void 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
377static void dso__set_basename(struct dso *dso)
378{
379 dso__set_short_name(dso, basename(dso->long_name));
380}
381
382int 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
392bool dso__loaded(const struct dso *dso, enum map_type type)
393{
394 return dso->loaded & (1 << type);
395}
396
397bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
398{
399 return dso->sorted_by_name & (1 << type);
400}
401
402void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
403{
404 dso->sorted_by_name |= (1 << type);
405}
406
407struct 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
432void 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
445void 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
451bool 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
456void 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
468int 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
489bool __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
511void dsos__add(struct list_head *head, struct dso *dso)
512{
513 list_add_tail(&dso->node, head);
514}
515
516struct 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
526struct 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
541size_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
556size_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
570size_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
578size_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
9enum 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
26enum dso_kernel_type {
27 DSO_TYPE_USER = 0,
28 DSO_TYPE_KERNEL,
29 DSO_TYPE_GUEST_KERNEL
30};
31
32enum 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
63struct dso_cache {
64 struct rb_node rb_node;
65 u64 offset;
66 u64 size;
67 char data[0];
68};
69
70struct 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
95static inline void dso__set_loaded(struct dso *dso, enum map_type type)
96{
97 dso->loaded |= (1 << type);
98}
99
100struct dso *dso__new(const char *name);
101void dso__delete(struct dso *dso);
102
103void dso__set_short_name(struct dso *dso, const char *name);
104void dso__set_long_name(struct dso *dso, char *name);
105
106int dso__name_len(const struct dso *dso);
107
108bool dso__loaded(const struct dso *dso, enum map_type type);
109
110bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
111void dso__set_sorted_by_name(struct dso *dso, enum map_type type);
112void dso__sort_by_name(struct dso *dso, enum map_type type);
113
114void dso__set_build_id(struct dso *dso, void *build_id);
115bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
116void dso__read_running_kernel_build_id(struct dso *dso,
117 struct machine *machine);
118int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
119
120char dso__symtab_origin(const struct dso *dso);
121int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
122 char *root_dir, char *file, size_t size);
123
124int dso__data_fd(struct dso *dso, struct machine *machine);
125ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
126 u64 offset, u8 *data, ssize_t size);
127ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
128 struct machine *machine, u64 addr,
129 u8 *data, ssize_t size);
130
131struct map *dso__new_map(const char *name);
132struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
133 const char *short_name, int dso_type);
134
135void dsos__add(struct list_head *head, struct dso *dso);
136struct dso *dsos__find(struct list_head *head, const char *name);
137struct dso *__dsos__findnew(struct list_head *head, const char *name);
138bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
139
140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
141 bool with_hits);
142size_t __dsos__fprintf(struct list_head *head, FILE *fp);
143
144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
145size_t dso__fprintf_symbols_by_name(struct dso *dso,
146 enum map_type type, FILE *fp);
147size_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;
416out_closedir:
417 closedir(proc); 405 closedir(proc);
418out_free_mmap: 406out_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
535int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 513int 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
545static 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
558static 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;
648out_problem:
649 return -1;
650} 519}
651 520
652size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 521size_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
659int perf_event__process_mmap(struct perf_tool *tool, 528int 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
693out_problem:
694 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
695 return 0;
696} 534}
697 535
698size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 536size_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
705int perf_event__process_task(struct perf_tool *tool __maybe_unused, 543int 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; 551int 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
730size_t perf_event__fprintf(union perf_event *event, FILE *fp) 559size_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
753int perf_event__process(struct perf_tool *tool, union perf_event *event, 582int 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
776void thread__find_addr_map(struct thread *self, 590void 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
101struct build_id_event { 100struct 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);
194int perf_event__process_task(struct perf_tool *tool, 193int perf_event__process_fork(struct perf_tool *tool,
194 union perf_event *event,
195 struct perf_sample *sample,
196 struct machine *machine);
197int 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,
52void perf_evlist__config_attrs(struct perf_evlist *evlist, 52void 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
326union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 328union 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:
528int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 528int 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
407void 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 */
435void 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
495int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 533int 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);
92void perf_evsel__delete(struct perf_evsel *evsel); 93void perf_evsel__delete(struct perf_evsel *evsel);
93 94
94void perf_evsel__config(struct perf_evsel *evsel, 95void 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
98bool perf_evsel__is_cache_op_valid(u8 type, u8 op); 98bool 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
229static 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
27static bool no_buildid_cache = false; 28static 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;
1383error: 1386error:
@@ -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
2346bool 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
2343static int check_magic_endian(u64 magic, uint64_t hdr_sz, 2356static 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,
154int perf_event__process_build_id(struct perf_tool *tool, 154int 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);
157bool 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
411void hist_entry__free(struct hist_entry *he) 413void 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
720static 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 }
751out:
752 return he;
753}
754
755static 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 */
778void 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 */
797int 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
8extern struct callchain_param callchain_param; 9extern 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);
114void hists__reset_col_len(struct hists *hists); 115void hists__reset_col_len(struct hists *hists);
115void hists__calc_col_len(struct hists *hists, struct hist_entry *he); 116void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
116 117
118void hists__match(struct hists *leader, struct hists *other);
119int hists__link(struct hists *leader, struct hists *other);
120
117struct perf_hpp { 121struct 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
154struct perf_evlist; 162struct perf_evlist;
155 163
164struct 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"
158int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 172int 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
161int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 175int 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);
178int script_browse(const char *script_opt);
164#else 179#else
165static inline 180static inline
166int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, 181int 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,
175static inline int hist_entry__tui_annotate(struct hist_entry *self 189static 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
198static 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
190int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, 208int 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
194static inline 211static inline
195int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, 212int 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
205unsigned int hists__sort_list_width(struct hists *self); 220unsigned int hists__sort_list_width(struct hists *self);
206 221
222double perf_diff__compute_delta(struct hist_entry *he);
223double perf_diff__compute_ratio(struct hist_entry *he);
224s64 perf_diff__compute_wdiff(struct hist_entry *he);
225int 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
9int 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
41static 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
51void 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
60void machine__delete(struct machine *machine)
61{
62 machine__exit(machine);
63 free(machine);
64}
65
66struct 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
96struct 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
119struct 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);
149out:
150 return machine;
151}
152
153void 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
164char *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
178void 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
191static 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
234struct thread *machine__findnew_thread(struct machine *machine, pid_t pid)
235{
236 return __machine__findnew_thread(machine, pid, true);
237}
238
239struct thread *machine__find_thread(struct machine *machine, pid_t pid)
240{
241 return __machine__findnew_thread(machine, pid, false);
242}
243
244int 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
259int 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
267static 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
285static 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;
373out_problem:
374 return -1;
375}
376
377int 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
408out_problem:
409 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
410 return 0;
411}
412
413int 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
430int 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
443int 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
8struct branch_stack;
9struct perf_evsel;
10struct perf_sample;
11struct symbol;
12struct thread;
13union 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
19struct 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
33static inline
34struct map *machine__kernel_map(struct machine *machine, enum map_type type)
35{
36 return machine->vmlinux_maps[type];
37}
38
39struct thread *machine__find_thread(struct machine *machine, pid_t pid);
40
41int machine__process_comm_event(struct machine *machine, union perf_event *event);
42int machine__process_exit_event(struct machine *machine, union perf_event *event);
43int machine__process_fork_event(struct machine *machine, union perf_event *event);
44int machine__process_lost_event(struct machine *machine, union perf_event *event);
45int machine__process_mmap_event(struct machine *machine, union perf_event *event);
46int machine__process_event(struct machine *machine, union perf_event *event);
47
48typedef void (*machine__process_t)(struct machine *machine, void *data);
49
50void machines__process(struct rb_root *machines,
51 machine__process_t process, void *data);
52
53struct machine *machines__add(struct rb_root *machines, pid_t pid,
54 const char *root_dir);
55struct machine *machines__find_host(struct rb_root *machines);
56struct machine *machines__find(struct rb_root *machines, pid_t pid);
57struct machine *machines__findnew(struct rb_root *machines, pid_t pid);
58
59void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size);
60char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
61
62int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
63void machine__exit(struct machine *machine);
64void machine__delete(struct machine *machine);
65
66
67struct branch_info *machine__resolve_bstack(struct machine *machine,
68 struct thread *thread,
69 struct branch_stack *bs);
70int 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 */
80static inline bool machine__is_default_guest(struct machine *machine)
81{
82 return machine ? machine->pid == DEFAULT_GUEST_KERNEL_ID : false;
83}
84
85static inline bool machine__is_host(struct machine *machine)
86{
87 return machine ? machine->pid == HOST_KERNEL_ID : false;
88}
89
90struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
91void machine__remove_thread(struct machine *machine, struct thread *th);
92
93size_t machine__fprintf(struct machine *machine, FILE *fp);
94
95static inline
96struct 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
105static inline
106struct 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
114static inline
115struct 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
124struct map *machine__new_module(struct machine *machine, u64 start,
125 const char *filename);
126
127int machine__load_kallsyms(struct machine *machine, const char *filename,
128 enum map_type type, symbol_filter_t filter);
129int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
130 symbol_filter_t filter);
131
132size_t machine__fprintf_dsos_buildid(struct machine *machine,
133 FILE *fp, bool with_hits);
134size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
135size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
136 FILE *fp, bool with_hits);
137
138void machine__destroy_kernel_maps(struct machine *machine);
139int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
140int machine__create_kernel_maps(struct machine *machine);
141
142int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
143int machines__create_guest_kernel_maps(struct rb_root *machines);
144void machines__destroy_guest_kernel_maps(struct rb_root *machines);
145
146size_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
14const char *map_type__name[MAP__NR_TYPES] = { 15const 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
24static inline int is_no_dso_memory(const char *filename) 25static 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
593int 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
624static 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
634void 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
643void machine__delete(struct machine *self)
644{
645 machine__exit(self);
646 free(self);
647}
648
649struct 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
679struct 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
702struct 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
733out:
734 return machine;
735}
736
737void 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
747char *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
759void 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
64struct 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
78static inline
79struct map *machine__kernel_map(struct machine *self, enum map_type type)
80{
81 return self->vmlinux_maps[type];
82}
83
84static inline struct kmap *map__kmap(struct map *self) 60static 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,
143size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); 119size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp);
144size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); 120size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
145 121
146typedef void (*machine__process_t)(struct machine *self, void *data);
147
148void machines__process(struct rb_root *self, machine__process_t process, void *data);
149struct machine *machines__add(struct rb_root *self, pid_t pid,
150 const char *root_dir);
151struct machine *machines__find_host(struct rb_root *self);
152struct machine *machines__find(struct rb_root *self, pid_t pid);
153struct machine *machines__findnew(struct rb_root *self, pid_t pid);
154void machines__set_id_hdr_size(struct rb_root *self, u16 id_hdr_size);
155char *machine__mmap_name(struct machine *self, char *bf, size_t size);
156int machine__init(struct machine *self, const char *root_dir, pid_t pid);
157void machine__exit(struct machine *self);
158void machine__delete(struct machine *self);
159
160struct perf_evsel;
161struct perf_sample;
162int machine__resolve_callchain(struct machine *machine,
163 struct perf_evsel *evsel,
164 struct thread *thread,
165 struct perf_sample *sample,
166 struct symbol **parent);
167int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 122int 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 */
174static inline bool machine__is_default_guest(struct machine *self)
175{
176 return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false;
177}
178
179static inline bool machine__is_host(struct machine *self)
180{
181 return self ? self->pid == HOST_KERNEL_ID : false;
182}
183
184static inline void map_groups__insert(struct map_groups *mg, struct map *map) 125static 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
213struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
214void machine__remove_thread(struct machine *machine, struct thread *th);
215
216size_t machine__fprintf(struct machine *machine, FILE *fp);
217
218static inline
219struct 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
227static inline
228struct 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
235static inline 153static inline
236struct symbol *map_groups__find_function_by_name(struct map_groups *mg, 154struct 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
243static inline
244struct 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
253int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 161int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
254 int verbose, FILE *fp); 162 int verbose, FILE *fp);
255 163
256struct map *map_groups__find_by_name(struct map_groups *mg, 164struct 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);
258struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
259 166
260void map_groups__flush(struct map_groups *mg); 167void 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) \
9do { \
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
19static 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
31static 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
48static 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
58static 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
68static 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
79static 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
96static 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
107static 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
117static 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
131static 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
144static 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
159static 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
174static 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
189static 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
201static int
202test__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
220static 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
232static 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
244static 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
256static 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
266static 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
276static 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
288static 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
300static 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
315static 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
329static 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
343static 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
357static 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
371static 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
386static 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
425static 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
446static 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
489static 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
524static 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
572static 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
651static 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
687static 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
763struct test__event_st {
764 const char *name;
765 __u32 type;
766 int (*check)(struct perf_evlist *evlist);
767};
768
769static 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
904static 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
915struct test__term {
916 const char *str;
917 __u32 type;
918 int (*check)(struct list_head *terms);
919};
920
921static struct test__term test__terms[] = {
922 [0] = {
923 .str = "config=10,config1,config2=3,umask=1",
924 .check = test__checkterms_simple,
925 },
926};
927
928static 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
950static 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
967static 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
991static 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
1008static 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
1023int parse_events__test(void)
1024{
1025 int ret1, ret2 = 0;
1026
1027#define TEST_EVENTS(tests) \
1028do { \
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 */
729static 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
722int parse_events__modifier_event(struct list_head *list, char *str, bool add) 746int 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
839int parse_filter(const struct option *opt, const char *str, 870int 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
1173int 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
1142int parse_events__term_clone(struct parse_events__term **new, 1191int 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
13struct list_head; 13struct 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);
77int parse_events__term_str(struct parse_events__term **_term, 77int 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);
79int parse_events__term_sym_hw(struct parse_events__term **term,
80 char *config, unsigned idx);
79int parse_events__term_clone(struct parse_events__term **new, 81int parse_events__term_clone(struct parse_events__term **new,
80 struct parse_events__term *term); 82 struct parse_events__term *term);
81void parse_events__free_terms(struct list_head *terms); 83void parse_events__free_terms(struct list_head *terms);
@@ -97,7 +99,6 @@ void parse_events__set_leader(char *name, struct list_head *list);
97void parse_events_update_lists(struct list_head *list_event, 99void parse_events_update_lists(struct list_head *list_event,
98 struct list_head *list_all); 100 struct list_head *list_all);
99void parse_events_error(void *data, void *scanner, char const *msg); 101void parse_events_error(void *data, void *scanner, char const *msg);
100int parse_events__test(void);
101 102
102void print_events(const char *event_glob, bool name_only); 103void print_events(const char *event_glob, bool name_only);
103void print_events_type(u8 type); 104void 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]+
81num_hex 0x[a-fA-F0-9]+ 81num_hex 0x[a-fA-F0-9]+
82num_raw_hex [a-fA-F0-9]+ 82num_raw_hex [a-fA-F0-9]+
83name [a-zA-Z_*?][a-zA-Z0-9_*?]* 83name [a-zA-Z_*?][a-zA-Z0-9_*?]*
84modifier_event [ukhpGH]{1,8} 84name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]*
85modifier_event [ukhpGH]+
85modifier_bp [rwx]{1,3} 86modifier_bp [rwx]{1,3}
86 87
87%% 88%%
@@ -168,6 +169,7 @@ period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
168branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } 169branch_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
173mem: { BEGIN(mem); return PE_PREFIX_MEM; } 175mem: { 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|
355PE_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|
355PE_NAME 364PE_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|
373PE_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|
364PE_TERM '=' PE_NAME 382PE_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 */
25static int pmu_format_parse(char *dir, struct list_head *head) 25int 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
448static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, 449int 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
472static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, 474static 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. */
555static 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. */
573static 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 */
635static 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. */
665static 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
676static 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
689int 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
7enum { 7enum {
8 PERF_PMU_FORMAT_VALUE_CONFIG, 8 PERF_PMU_FORMAT_VALUE_CONFIG,
@@ -37,6 +37,9 @@ struct perf_pmu {
37struct perf_pmu *perf_pmu__find(char *name); 37struct perf_pmu *perf_pmu__find(char *name);
38int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 38int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
39 struct list_head *head_terms); 39 struct list_head *head_terms);
40int perf_pmu__config_terms(struct list_head *formats,
41 struct perf_event_attr *attr,
42 struct list_head *head_terms);
40int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); 43int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
41struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 44struct 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);
46int perf_pmu__new_format(struct list_head *list, char *name, 49int perf_pmu__new_format(struct list_head *list, char *name,
47 int config, unsigned long *bits); 50 int config, unsigned long *bits);
48void perf_pmu__set_format(unsigned long *bits, long from, long to); 51void perf_pmu__set_format(unsigned long *bits, long from, long to);
52int perf_pmu__format_parse(char *dir, struct list_head *head);
49 53
50struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 54struct 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
18struct pstack *pstack__new(unsigned short max_nr_entries) 18struct 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
27void pstack__delete(struct pstack *self) 27void pstack__delete(struct pstack *pstack)
28{ 28{
29 free(self); 29 free(pstack);
30} 30}
31 31
32bool pstack__empty(const struct pstack *self) 32bool pstack__empty(const struct pstack *pstack)
33{ 33{
34 return self->top == 0; 34 return pstack->top == 0;
35} 35}
36 36
37void pstack__remove(struct pstack *self, void *key) 37void 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
54void pstack__push(struct pstack *self, void *key) 54void 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
63void *pstack__pop(struct pstack *self) 63void *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)
44void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node) 44void 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
37PyMODINIT_FUNC initperf_trace_context(void); 36PyMODINIT_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);
1462out_err: 1460out_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
12struct sample_queue; 13struct sample_queue;
13struct ip_callchain; 14struct 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
71struct branch_info *machine__resolve_bstack(struct machine *self,
72 struct thread *thread,
73 struct branch_stack *bs);
74
75bool perf_session__has_traces(struct perf_session *self, const char *msg); 72bool perf_session__has_traces(struct perf_session *self, const char *msg);
76 73
77void mem_bswap_64(void *src, int byte_size); 74void 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
24build_lib = getenv('PYTHON_EXTBUILD_LIB') 24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP') 25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26libtraceevent = getenv('LIBTRACEEVENT')
26 27
27ext_sources = [f.strip() for f in file('util/python-ext-sources') 28ext_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
36setup(name='perf', 38setup(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
55struct 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 {
61struct hist_entry { 77struct 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
109static inline bool hist_entry__has_pairs(struct hist_entry *he)
110{
111 return !list_empty(&he->pairs.node);
112}
113
114static 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
121static 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
90enum sort_type { 127enum 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 */
324char *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
26static void dso_cache__free(struct rb_root *root);
27static int dso__load_kernel_sym(struct dso *dso, struct map *map, 27static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 28 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29static 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
59static 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
67int 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
77bool dso__loaded(const struct dso *dso, enum map_type type)
78{
79 return dso->loaded & (1 << type);
80}
81
82bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
83{
84 return dso->sorted_by_name & (1 << type);
85}
86
87static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
88{
89 dso->sorted_by_name |= (1 << type);
90}
91
92bool symbol_type__is_a(char symbol_type, enum map_type map_type) 59bool 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
273static size_t symbol__fprintf(struct symbol *sym, FILE *fp) 240size_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
304void dso__set_long_name(struct dso *dso, char *name) 271void 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
312static 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
320static void dso__set_basename(struct dso *dso)
321{
322 dso__set_short_name(dso, basename(dso->long_name));
323}
324
325struct 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
350static 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
363void 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
376void 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
382void symbols__insert(struct rb_root *symbols, struct symbol *sym) 284void 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
507int 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
522size_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
530size_t dso__fprintf_symbols_by_name(struct dso *dso, 409size_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
545size_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
564int kallsyms__parse(const char *filename, void *arg, 424int 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
895bool 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
900bool __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
922char 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
945int 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
1025int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 755int 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
1160static 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
1181static int map_groups__set_modules_path_dir(struct map_groups *mg, 890static 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
1594void dsos__add(struct list_head *head, struct dso *dso)
1595{
1596 list_add_tail(&dso->node, head);
1597}
1598
1599struct 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
1609struct 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
1624size_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
1638size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 1303size_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
1652static 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
1667size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 1317size_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
1687static struct dso*
1688dso__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
1708void 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
1720static struct dso *machine__get_kernel(struct machine *machine) 1337static 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
2068static 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 */
2083int 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
2101char *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
2111int machines__create_guest_kernel_maps(struct rb_root *machines) 1685int 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
2206struct 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
2217static 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
2241int 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
2262static void
2263dso_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
2277static struct dso_cache*
2278dso_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
2301static void
2302dso_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
2326static ssize_t
2327dso_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
2337static ssize_t
2338dso_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
2383static 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
2395ssize_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
2424ssize_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
22extern char *cplus_demangle(const char *, int); 25extern 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
42int hex2u64(const char *ptr, u64 *val);
43char *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
76void symbol__delete(struct symbol *sym); 74void symbol__delete(struct symbol *sym);
75void symbols__delete(struct rb_root *symbols);
77 76
78static inline size_t symbol__size(const struct symbol *sym) 77static 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
167enum 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
184enum dso_kernel_type {
185 DSO_TYPE_USER = 0,
186 DSO_TYPE_KERNEL,
187 DSO_TYPE_GUEST_KERNEL
188};
189
190enum 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
199struct dso_cache {
200 struct rb_node rb_node;
201 u64 offset;
202 u64 size;
203 char data[0];
204};
205
206struct 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
231struct symsrc { 166struct 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,
258bool symsrc__has_symtab(struct symsrc *ss); 193bool symsrc__has_symtab(struct symsrc *ss);
259bool symsrc__possibly_runtime(struct symsrc *ss); 194bool 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
283struct dso *dso__new(const char *name);
284void dso__delete(struct dso *dso);
285
286int dso__name_len(const struct dso *dso);
287
288bool dso__loaded(const struct dso *dso, enum map_type type);
289bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
290
291static inline void dso__set_loaded(struct dso *dso, enum map_type type)
292{
293 dso->loaded |= (1 << type);
294}
295
296void dso__sort_by_name(struct dso *dso, enum map_type type);
297
298void dsos__add(struct list_head *head, struct dso *dso);
299struct dso *dsos__find(struct list_head *head, const char *name);
300struct dso *__dsos__findnew(struct list_head *head, const char *name);
301
302int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); 196int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
303int dso__load_vmlinux(struct dso *dso, struct map *map, 197int 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);
307int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, 201int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
308 symbol_filter_t filter); 202 symbol_filter_t filter);
309int machine__load_kallsyms(struct machine *machine, const char *filename, 203
310 enum map_type type, symbol_filter_t filter);
311int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
312 symbol_filter_t filter);
313
314size_t __dsos__fprintf(struct list_head *head, FILE *fp);
315
316size_t machine__fprintf_dsos_buildid(struct machine *machine,
317 FILE *fp, bool with_hits);
318size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
319size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
320 FILE *fp, bool with_hits);
321size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
322size_t dso__fprintf_symbols_by_name(struct dso *dso,
323 enum map_type type, FILE *fp);
324size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
325
326char dso__symtab_origin(const struct dso *dso);
327void dso__set_long_name(struct dso *dso, char *name);
328void dso__set_build_id(struct dso *dso, void *build_id);
329bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
330void dso__read_running_kernel_build_id(struct dso *dso,
331 struct machine *machine);
332struct map *dso__new_map(const char *name);
333struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, 204struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
334 u64 addr); 205 u64 addr);
335struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 206struct 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
338int filename__read_build_id(const char *filename, void *bf, size_t size); 209int filename__read_build_id(const char *filename, void *bf, size_t size);
339int sysfs__read_build_id(const char *filename, void *bf, size_t size); 210int sysfs__read_build_id(const char *filename, void *bf, size_t size);
340bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
341int build_id__sprintf(const u8 *build_id, int len, char *bf);
342int kallsyms__parse(const char *filename, void *arg, 211int 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));
345int filename__read_debuglink(const char *filename, char *debuglink, 214int filename__read_debuglink(const char *filename, char *debuglink,
346 size_t size); 215 size_t size);
347 216
348void machine__destroy_kernel_maps(struct machine *machine);
349int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
350int machine__create_kernel_maps(struct machine *machine);
351
352int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
353int machines__create_guest_kernel_maps(struct rb_root *machines);
354void machines__destroy_guest_kernel_maps(struct rb_root *machines);
355
356int symbol__init(void); 217int symbol__init(void);
357void symbol__exit(void); 218void symbol__exit(void);
358void symbol__elf_init(void); 219void symbol__elf_init(void);
@@ -360,20 +221,9 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
360size_t symbol__fprintf_symname_offs(const struct symbol *sym, 221size_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);
362size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); 223size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
224size_t symbol__fprintf(struct symbol *sym, FILE *fp);
363bool symbol_type__is_a(char symbol_type, enum map_type map_type); 225bool symbol_type__is_a(char symbol_type, enum map_type map_type);
364 226
365size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
366
367int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
368 char *root_dir, char *file, size_t size);
369
370int dso__data_fd(struct dso *dso, struct machine *machine);
371ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
372 u64 offset, u8 *data, ssize_t size);
373ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
374 struct machine *machine, u64 addr,
375 u8 *data, ssize_t size);
376int dso__test_data(void);
377int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 227int 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
10static struct thread *thread__new(pid_t pid) 10struct 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
64struct 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
103void thread__insert_map(struct thread *self, struct map *map) 63void 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
8struct thread { 9struct thread {
@@ -22,6 +23,7 @@ struct thread {
22 23
23struct machine; 24struct machine;
24 25
26struct thread *thread__new(pid_t pid);
25void thread__delete(struct thread *self); 27void thread__delete(struct thread *self);
26 28
27int thread__set_comm(struct thread *self, const char *comm); 29int 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;
47int host_bigendian; 47int host_bigendian;
48static int long_size; 48static int long_size;
49 49
50static unsigned long page_size;
51
52static ssize_t calc_data_size; 50static ssize_t calc_data_size;
53static bool repipe; 51static 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 */
13unsigned int page_size;
14
13bool perf_host = true; 15bool perf_host = true;
14bool perf_guest = false; 16bool 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
169static 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 */
184int 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
169void dump_stack(void) 204void 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
201extern unsigned char sane_ctype[256]; 205extern 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);
236bool strglobmatch(const char *str, const char *pat); 240bool strglobmatch(const char *str, const char *pat);
237bool strlazymatch(const char *str, const char *pat); 241bool strlazymatch(const char *str, const char *pat);
238int strtailcmp(const char *s1, const char *s2); 242int strtailcmp(const char *s1, const char *s2);
243char *strxfrchar(char *s, char from, char to);
239unsigned long convert_unit(unsigned long value, char *unit); 244unsigned long convert_unit(unsigned long value, char *unit);
240int readn(int fd, void *buf, size_t size); 245int 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
260size_t hex_width(u64 v); 265size_t hex_width(u64 v);
266int hex2u64(const char *ptr, u64 *val);
261 267
262char *rtrim(char *s); 268char *rtrim(char *s);
263 269
264void dump_stack(void); 270void dump_stack(void);
265 271
272extern unsigned int page_size;
273
266#endif 274#endif