aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/annotate.c10
-rw-r--r--tools/perf/util/bitmap.c10
-rw-r--r--tools/perf/util/cache.h12
-rw-r--r--tools/perf/util/color.c9
-rw-r--r--tools/perf/util/cpumap.c11
-rw-r--r--tools/perf/util/cpumap.h4
-rw-r--r--tools/perf/util/ctype.c2
-rw-r--r--tools/perf/util/debugfs.c141
-rw-r--r--tools/perf/util/debugfs.h6
-rw-r--r--tools/perf/util/event.c1
-rw-r--r--tools/perf/util/event.h1
-rw-r--r--tools/perf/util/evlist.c27
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c30
-rw-r--r--tools/perf/util/evsel.h5
-rw-r--r--tools/perf/util/gtk/browser.c189
-rw-r--r--tools/perf/util/gtk/gtk.h8
-rw-r--r--tools/perf/util/header.c590
-rw-r--r--tools/perf/util/header.h3
-rw-r--r--tools/perf/util/hist.c344
-rw-r--r--tools/perf/util/hist.h32
-rw-r--r--tools/perf/util/include/asm/dwarf2.h4
-rw-r--r--tools/perf/util/include/asm/unistd_32.h1
-rw-r--r--tools/perf/util/include/asm/unistd_64.h1
-rw-r--r--tools/perf/util/include/linux/bitmap.h11
-rw-r--r--tools/perf/util/include/linux/bitops.h2
-rw-r--r--tools/perf/util/include/linux/export.h (renamed from tools/perf/util/include/linux/module.h)0
-rw-r--r--tools/perf/util/map.c15
-rw-r--r--tools/perf/util/map.h1
-rw-r--r--tools/perf/util/parse-events.c605
-rw-r--r--tools/perf/util/parse-events.h49
-rw-r--r--tools/perf/util/parse-events.l127
-rw-r--r--tools/perf/util/parse-events.y229
-rw-r--r--tools/perf/util/pmu.c469
-rw-r--r--tools/perf/util/pmu.h41
-rw-r--r--tools/perf/util/pmu.l43
-rw-r--r--tools/perf/util/pmu.y93
-rw-r--r--tools/perf/util/probe-event.c39
-rw-r--r--tools/perf/util/probe-finder.c17
-rw-r--r--tools/perf/util/python-ext-sources19
-rw-r--r--tools/perf/util/python.c10
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c127
-rw-r--r--tools/perf/util/session.h6
-rw-r--r--tools/perf/util/setup.py8
-rw-r--r--tools/perf/util/sort.c290
-rw-r--r--tools/perf/util/sort.h11
-rw-r--r--tools/perf/util/strbuf.c7
-rw-r--r--tools/perf/util/symbol.c27
-rw-r--r--tools/perf/util/symbol.h24
-rw-r--r--tools/perf/util/sysfs.c60
-rw-r--r--tools/perf/util/sysfs.h6
-rw-r--r--tools/perf/util/thread_map.c237
-rw-r--r--tools/perf/util/thread_map.h11
-rw-r--r--tools/perf/util/top.c13
-rw-r--r--tools/perf/util/top.h7
-rw-r--r--tools/perf/util/trace-event-parse.c23
-rw-r--r--tools/perf/util/trace-event-read.c1
-rw-r--r--tools/perf/util/trace-event-scripting.c1
-rw-r--r--tools/perf/util/ui/browser.h2
-rw-r--r--tools/perf/util/ui/browsers/annotate.c18
-rw-r--r--tools/perf/util/ui/browsers/hists.c131
-rw-r--r--tools/perf/util/ui/browsers/map.c2
-rw-r--r--tools/perf/util/ui/helpline.c2
-rw-r--r--tools/perf/util/ui/keysyms.h2
-rw-r--r--tools/perf/util/ui/util.c82
-rw-r--r--tools/perf/util/usage.c39
-rw-r--r--tools/perf/util/util.c4
-rw-r--r--tools/perf/util/util.h6
69 files changed, 3383 insertions, 985 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 011ed2676604..199f69ec656f 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -28,8 +28,8 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
28int symbol__alloc_hist(struct symbol *sym) 28int symbol__alloc_hist(struct symbol *sym)
29{ 29{
30 struct annotation *notes = symbol__annotation(sym); 30 struct annotation *notes = symbol__annotation(sym);
31 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + 31 const size_t size = sym->end - sym->start + 1;
32 (sym->end - sym->start) * sizeof(u64)); 32 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
33 33
34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
35 if (notes->src == NULL) 35 if (notes->src == NULL)
@@ -64,7 +64,7 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
64 64
65 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 65 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
66 66
67 if (addr >= sym->end) 67 if (addr > sym->end)
68 return 0; 68 return 0;
69 69
70 offset = addr - sym->start; 70 offset = addr - sym->start;
@@ -315,7 +315,7 @@ fallback:
315 "Please use:\n\n" 315 "Please use:\n\n"
316 " perf buildid-cache -av vmlinux\n\n" 316 " perf buildid-cache -av vmlinux\n\n"
317 "or:\n\n" 317 "or:\n\n"
318 " --vmlinux vmlinux", 318 " --vmlinux vmlinux\n",
319 sym->name, build_id_msg ?: ""); 319 sym->name, build_id_msg ?: "");
320 goto out_free_filename; 320 goto out_free_filename;
321 } 321 }
@@ -408,7 +408,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
408 if (!notes->src->lines) 408 if (!notes->src->lines)
409 return -1; 409 return -1;
410 410
411 start = map->unmap_ip(map, sym->start); 411 start = map__rip_2objdump(map, sym->start);
412 412
413 for (i = 0; i < len; i++) { 413 for (i = 0; i < len; i++) {
414 char *path = NULL; 414 char *path = NULL;
diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
index 5e230acae1e9..0a1adc1111fd 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/perf/util/bitmap.c
@@ -19,3 +19,13 @@ int __bitmap_weight(const unsigned long *bitmap, int bits)
19 19
20 return w; 20 return w;
21} 21}
22
23void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
24 const unsigned long *bitmap2, int bits)
25{
26 int k;
27 int nr = BITS_TO_LONGS(bits);
28
29 for (k = 0; k < nr; k++)
30 dst[k] = bitmap1[k] | bitmap2[k];
31}
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index fc5e5a09d5b9..8dd224df3e54 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -45,6 +45,18 @@ void setup_browser(bool fallback_to_pager);
45void exit_browser(bool wait_for_ok); 45void exit_browser(bool wait_for_ok);
46#endif 46#endif
47 47
48#ifdef NO_GTK2_SUPPORT
49static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager)
50{
51 if (fallback_to_pager)
52 setup_pager();
53}
54static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {}
55#else
56void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager);
57void perf_gtk_exit_browser(bool wait_for_ok);
58#endif
59
48char *alias_lookup(const char *alias); 60char *alias_lookup(const char *alias);
49int split_cmdline(char *cmdline, const char ***argv); 61int split_cmdline(char *cmdline, const char ***argv);
50 62
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 521c38a79190..11e46da17bbb 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -1,3 +1,4 @@
1#include <linux/kernel.h>
1#include "cache.h" 2#include "cache.h"
2#include "color.h" 3#include "color.h"
3 4
@@ -182,12 +183,12 @@ static int __color_vsnprintf(char *bf, size_t size, const char *color,
182 } 183 }
183 184
184 if (perf_use_color_default && *color) 185 if (perf_use_color_default && *color)
185 r += snprintf(bf, size, "%s", color); 186 r += scnprintf(bf, size, "%s", color);
186 r += vsnprintf(bf + r, size - r, fmt, args); 187 r += vscnprintf(bf + r, size - r, fmt, args);
187 if (perf_use_color_default && *color) 188 if (perf_use_color_default && *color)
188 r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET); 189 r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
189 if (trail) 190 if (trail)
190 r += snprintf(bf + r, size - r, "%s", trail); 191 r += scnprintf(bf + r, size - r, "%s", trail);
191 return r; 192 return r;
192} 193}
193 194
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 6893eec693ab..adc72f09914d 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -166,6 +166,17 @@ out:
166 return cpus; 166 return cpus;
167} 167}
168 168
169size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
170{
171 int i;
172 size_t printed = fprintf(fp, "%d cpu%s: ",
173 map->nr, map->nr > 1 ? "s" : "");
174 for (i = 0; i < map->nr; ++i)
175 printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
176
177 return printed + fprintf(fp, "\n");
178}
179
169struct cpu_map *cpu_map__dummy_new(void) 180struct cpu_map *cpu_map__dummy_new(void)
170{ 181{
171 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); 182 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 072c0a374794..c41518573c6a 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,6 +1,8 @@
1#ifndef __PERF_CPUMAP_H 1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H 2#define __PERF_CPUMAP_H
3 3
4#include <stdio.h>
5
4struct cpu_map { 6struct cpu_map {
5 int nr; 7 int nr;
6 int map[]; 8 int map[];
@@ -10,4 +12,6 @@ struct cpu_map *cpu_map__new(const char *cpu_list);
10struct cpu_map *cpu_map__dummy_new(void); 12struct cpu_map *cpu_map__dummy_new(void);
11void cpu_map__delete(struct cpu_map *map); 13void cpu_map__delete(struct cpu_map *map);
12 14
15size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
16
13#endif /* __PERF_CPUMAP_H */ 17#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index 35073621e5de..aada3ac5e891 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * No surprises, and works with signed and unsigned chars. 4 * No surprises, and works with signed and unsigned chars.
5 */ 5 */
6#include "cache.h" 6#include "util.h"
7 7
8enum { 8enum {
9 S = GIT_SPACE, 9 S = GIT_SPACE,
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index ffc35e748e89..dd8b19319c03 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -15,32 +15,6 @@ static const char *debugfs_known_mountpoints[] = {
15 0, 15 0,
16}; 16};
17 17
18/* use this to force a umount */
19void debugfs_force_cleanup(void)
20{
21 debugfs_find_mountpoint();
22 debugfs_premounted = 0;
23 debugfs_umount();
24}
25
26/* construct a full path to a debugfs element */
27int debugfs_make_path(const char *element, char *buffer, int size)
28{
29 int len;
30
31 if (strlen(debugfs_mountpoint) == 0) {
32 buffer[0] = '\0';
33 return -1;
34 }
35
36 len = strlen(debugfs_mountpoint) + strlen(element) + 1;
37 if (len >= size)
38 return len+1;
39
40 snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
41 return 0;
42}
43
44static int debugfs_found; 18static int debugfs_found;
45 19
46/* find the path to the mounted debugfs */ 20/* find the path to the mounted debugfs */
@@ -97,17 +71,6 @@ int debugfs_valid_mountpoint(const char *debugfs)
97 return 0; 71 return 0;
98} 72}
99 73
100
101int debugfs_valid_entry(const char *path)
102{
103 struct stat st;
104
105 if (stat(path, &st))
106 return -errno;
107
108 return 0;
109}
110
111static void debugfs_set_tracing_events_path(const char *mountpoint) 74static void debugfs_set_tracing_events_path(const char *mountpoint)
112{ 75{
113 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", 76 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -149,107 +112,3 @@ void debugfs_set_path(const char *mountpoint)
149 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); 112 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
150 debugfs_set_tracing_events_path(mountpoint); 113 debugfs_set_tracing_events_path(mountpoint);
151} 114}
152
153/* umount the debugfs */
154
155int debugfs_umount(void)
156{
157 char umountcmd[128];
158 int ret;
159
160 /* if it was already mounted, leave it */
161 if (debugfs_premounted)
162 return 0;
163
164 /* make sure it's a valid mount point */
165 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
166 if (ret)
167 return ret;
168
169 snprintf(umountcmd, sizeof(umountcmd),
170 "/bin/umount %s", debugfs_mountpoint);
171 return system(umountcmd);
172}
173
174int debugfs_write(const char *entry, const char *value)
175{
176 char path[PATH_MAX + 1];
177 int ret, count;
178 int fd;
179
180 /* construct the path */
181 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
182
183 /* verify that it exists */
184 ret = debugfs_valid_entry(path);
185 if (ret)
186 return ret;
187
188 /* get how many chars we're going to write */
189 count = strlen(value);
190
191 /* open the debugfs entry */
192 fd = open(path, O_RDWR);
193 if (fd < 0)
194 return -errno;
195
196 while (count > 0) {
197 /* write it */
198 ret = write(fd, value, count);
199 if (ret <= 0) {
200 if (ret == EAGAIN)
201 continue;
202 close(fd);
203 return -errno;
204 }
205 count -= ret;
206 }
207
208 /* close it */
209 close(fd);
210
211 /* return success */
212 return 0;
213}
214
215/*
216 * read a debugfs entry
217 * returns the number of chars read or a negative errno
218 */
219int debugfs_read(const char *entry, char *buffer, size_t size)
220{
221 char path[PATH_MAX + 1];
222 int ret;
223 int fd;
224
225 /* construct the path */
226 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
227
228 /* verify that it exists */
229 ret = debugfs_valid_entry(path);
230 if (ret)
231 return ret;
232
233 /* open the debugfs entry */
234 fd = open(path, O_RDONLY);
235 if (fd < 0)
236 return -errno;
237
238 do {
239 /* read it */
240 ret = read(fd, buffer, size);
241 if (ret == 0) {
242 close(fd);
243 return EOF;
244 }
245 } while (ret < 0 && errno == EAGAIN);
246
247 /* close it */
248 close(fd);
249
250 /* make *sure* there's a null character at the end */
251 buffer[ret] = '\0';
252
253 /* return the number of chars read */
254 return ret;
255}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 4a878f735eb0..68f3e87ec57f 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -3,14 +3,8 @@
3 3
4const char *debugfs_find_mountpoint(void); 4const char *debugfs_find_mountpoint(void);
5int debugfs_valid_mountpoint(const char *debugfs); 5int debugfs_valid_mountpoint(const char *debugfs);
6int debugfs_valid_entry(const char *path);
7char *debugfs_mount(const char *mountpoint); 6char *debugfs_mount(const char *mountpoint);
8int debugfs_umount(void);
9void debugfs_set_path(const char *mountpoint); 7void debugfs_set_path(const char *mountpoint);
10int debugfs_write(const char *entry, const char *value);
11int debugfs_read(const char *entry, char *buffer, size_t size);
12void debugfs_force_cleanup(void);
13int debugfs_make_path(const char *element, char *buffer, int size);
14 8
15extern char debugfs_mountpoint[]; 9extern char debugfs_mountpoint[];
16extern char tracing_events_path[]; 10extern char tracing_events_path[];
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 2044324b755a..2a6f33cd888c 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -74,6 +74,7 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
74 if (size >= len) 74 if (size >= len)
75 size = len - 1; 75 size = len - 1;
76 memcpy(comm, name, size); 76 memcpy(comm, name, size);
77 comm[size] = '\0';
77 78
78 } else if (memcmp(bf, "Tgid:", 5) == 0) { 79 } else if (memcmp(bf, "Tgid:", 5) == 0) {
79 char *tgids = bf + 5; 80 char *tgids = bf + 5;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index cbdeaad9c5e5..1b197280c621 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -81,6 +81,7 @@ struct perf_sample {
81 u32 raw_size; 81 u32 raw_size;
82 void *raw_data; 82 void *raw_data;
83 struct ip_callchain *callchain; 83 struct ip_callchain *callchain;
84 struct branch_stack *branch_stack;
84}; 85};
85 86
86#define BUILD_ID_SIZE 20 87#define BUILD_ID_SIZE 20
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3f16e08a5c8d..1986d8051bd1 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -51,13 +51,15 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
51void perf_evlist__config_attrs(struct perf_evlist *evlist, 51void perf_evlist__config_attrs(struct perf_evlist *evlist,
52 struct perf_record_opts *opts) 52 struct perf_record_opts *opts)
53{ 53{
54 struct perf_evsel *evsel; 54 struct perf_evsel *evsel, *first;
55 55
56 if (evlist->cpus->map[0] < 0) 56 if (evlist->cpus->map[0] < 0)
57 opts->no_inherit = true; 57 opts->no_inherit = true;
58 58
59 first = list_entry(evlist->entries.next, struct perf_evsel, node);
60
59 list_for_each_entry(evsel, &evlist->entries, node) { 61 list_for_each_entry(evsel, &evlist->entries, node) {
60 perf_evsel__config(evsel, opts); 62 perf_evsel__config(evsel, opts, first);
61 63
62 if (evlist->nr_entries > 1) 64 if (evlist->nr_entries > 1)
63 evsel->attr.sample_type |= PERF_SAMPLE_ID; 65 evsel->attr.sample_type |= PERF_SAMPLE_ID;
@@ -97,9 +99,9 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
97 ++evlist->nr_entries; 99 ++evlist->nr_entries;
98} 100}
99 101
100static void perf_evlist__splice_list_tail(struct perf_evlist *evlist, 102void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
101 struct list_head *list, 103 struct list_head *list,
102 int nr_entries) 104 int nr_entries)
103{ 105{
104 list_splice_tail(list, &evlist->entries); 106 list_splice_tail(list, &evlist->entries);
105 evlist->nr_entries += nr_entries; 107 evlist->nr_entries += nr_entries;
@@ -349,6 +351,10 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
349 hlist_for_each_entry(sid, pos, head, node) 351 hlist_for_each_entry(sid, pos, head, node)
350 if (sid->id == id) 352 if (sid->id == id)
351 return sid->evsel; 353 return sid->evsel;
354
355 if (!perf_evlist__sample_id_all(evlist))
356 return list_entry(evlist->entries.next, struct perf_evsel, node);
357
352 return NULL; 358 return NULL;
353} 359}
354 360
@@ -593,15 +599,15 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
593 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 599 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
594} 600}
595 601
596int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, 602int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
597 pid_t target_tid, const char *cpu_list) 603 const char *target_tid, uid_t uid, const char *cpu_list)
598{ 604{
599 evlist->threads = thread_map__new(target_pid, target_tid); 605 evlist->threads = thread_map__new_str(target_pid, target_tid, uid);
600 606
601 if (evlist->threads == NULL) 607 if (evlist->threads == NULL)
602 return -1; 608 return -1;
603 609
604 if (cpu_list == NULL && target_tid != -1) 610 if (uid != UINT_MAX || (cpu_list == NULL && target_tid))
605 evlist->cpus = cpu_map__dummy_new(); 611 evlist->cpus = cpu_map__dummy_new();
606 else 612 else
607 evlist->cpus = cpu_map__new(cpu_list); 613 evlist->cpus = cpu_map__new(cpu_list);
@@ -761,6 +767,7 @@ out_err:
761 list_for_each_entry_reverse(evsel, &evlist->entries, node) 767 list_for_each_entry_reverse(evsel, &evlist->entries, node)
762 perf_evsel__close(evsel, ncpus, nthreads); 768 perf_evsel__close(evsel, ncpus, nthreads);
763 769
770 errno = -err;
764 return err; 771 return err;
765} 772}
766 773
@@ -820,7 +827,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
820 exit(-1); 827 exit(-1);
821 } 828 }
822 829
823 if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) 830 if (!opts->system_wide && !opts->target_tid && !opts->target_pid)
824 evlist->threads->map[0] = evlist->workload.pid; 831 evlist->threads->map[0] = evlist->workload.pid;
825 832
826 close(child_ready_pipe[1]); 833 close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 8922aeed0467..21f1c9e57f13 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
106 evlist->threads = threads; 106 evlist->threads = threads;
107} 107}
108 108
109int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, 109int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
110 pid_t target_tid, const char *cpu_list); 110 const char *tid, uid_t uid, const char *cpu_list);
111void perf_evlist__delete_maps(struct perf_evlist *evlist); 111void perf_evlist__delete_maps(struct perf_evlist *evlist);
112int perf_evlist__set_filters(struct perf_evlist *evlist); 112int perf_evlist__set_filters(struct perf_evlist *evlist);
113 113
@@ -117,4 +117,9 @@ u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
117 117
118bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); 118bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
119bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); 119bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
120
121void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
122 struct list_head *list,
123 int nr_entries);
124
120#endif /* __PERF_EVLIST_H */ 125#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 7132ee834e0e..8c13dbcb84b9 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -34,7 +34,7 @@ int __perf_evsel__sample_size(u64 sample_type)
34 return size; 34 return size;
35} 35}
36 36
37static void hists__init(struct hists *hists) 37void hists__init(struct hists *hists)
38{ 38{
39 memset(hists, 0, sizeof(*hists)); 39 memset(hists, 0, sizeof(*hists));
40 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; 40 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
@@ -63,12 +63,13 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
63 return evsel; 63 return evsel;
64} 64}
65 65
66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) 66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
67 struct perf_evsel *first)
67{ 68{
68 struct perf_event_attr *attr = &evsel->attr; 69 struct perf_event_attr *attr = &evsel->attr;
69 int track = !evsel->idx; /* only the first counter needs these */ 70 int track = !evsel->idx; /* only the first counter needs these */
70 71
71 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; 72 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
72 attr->inherit = !opts->no_inherit; 73 attr->inherit = !opts->no_inherit;
73 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 74 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
74 PERF_FORMAT_TOTAL_TIME_RUNNING | 75 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -111,7 +112,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
111 if (opts->period) 112 if (opts->period)
112 attr->sample_type |= PERF_SAMPLE_PERIOD; 113 attr->sample_type |= PERF_SAMPLE_PERIOD;
113 114
114 if (opts->sample_id_all_avail && 115 if (!opts->sample_id_all_missing &&
115 (opts->sample_time || opts->system_wide || 116 (opts->sample_time || opts->system_wide ||
116 !opts->no_inherit || opts->cpu_list)) 117 !opts->no_inherit || opts->cpu_list))
117 attr->sample_type |= PERF_SAMPLE_TIME; 118 attr->sample_type |= PERF_SAMPLE_TIME;
@@ -126,11 +127,16 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
126 attr->watermark = 0; 127 attr->watermark = 0;
127 attr->wakeup_events = 1; 128 attr->wakeup_events = 1;
128 } 129 }
130 if (opts->branch_stack) {
131 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK;
132 attr->branch_sample_type = opts->branch_stack;
133 }
129 134
130 attr->mmap = track; 135 attr->mmap = track;
131 attr->comm = track; 136 attr->comm = track;
132 137
133 if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { 138 if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
139 (!opts->group || evsel == first)) {
134 attr->disabled = 1; 140 attr->disabled = 1;
135 attr->enable_on_exec = 1; 141 attr->enable_on_exec = 1;
136 } 142 }
@@ -536,7 +542,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
536 } 542 }
537 543
538 if (type & PERF_SAMPLE_READ) { 544 if (type & PERF_SAMPLE_READ) {
539 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n"); 545 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n");
540 return -1; 546 return -1;
541 } 547 }
542 548
@@ -574,8 +580,20 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
574 return -EFAULT; 580 return -EFAULT;
575 581
576 data->raw_data = (void *) pdata; 582 data->raw_data = (void *) pdata;
583
584 array = (void *)array + data->raw_size + sizeof(u32);
577 } 585 }
578 586
587 if (type & PERF_SAMPLE_BRANCH_STACK) {
588 u64 sz;
589
590 data->branch_stack = (struct branch_stack *)array;
591 array++; /* nr */
592
593 sz = data->branch_stack->nr * sizeof(struct branch_entry);
594 sz /= sizeof(u64);
595 array += sz;
596 }
579 return 0; 597 return 0;
580} 598}
581 599
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 326b8e4d5035..3d6b3e4cb66b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -80,7 +80,8 @@ void perf_evsel__exit(struct perf_evsel *evsel);
80void perf_evsel__delete(struct perf_evsel *evsel); 80void perf_evsel__delete(struct perf_evsel *evsel);
81 81
82void perf_evsel__config(struct perf_evsel *evsel, 82void perf_evsel__config(struct perf_evsel *evsel,
83 struct perf_record_opts *opts); 83 struct perf_record_opts *opts,
84 struct perf_evsel *first);
84 85
85int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 86int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
86int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 87int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
@@ -169,4 +170,6 @@ static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
169 return __perf_evsel__sample_size(evsel->attr.sample_type); 170 return __perf_evsel__sample_size(evsel->attr.sample_type);
170} 171}
171 172
173void hists__init(struct hists *hists);
174
172#endif /* __PERF_EVSEL_H */ 175#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/util/gtk/browser.c
new file mode 100644
index 000000000000..258352a2356c
--- /dev/null
+++ b/tools/perf/util/gtk/browser.c
@@ -0,0 +1,189 @@
1#include "../evlist.h"
2#include "../cache.h"
3#include "../evsel.h"
4#include "../sort.h"
5#include "../hist.h"
6#include "gtk.h"
7
8#include <signal.h>
9
10#define MAX_COLUMNS 32
11
12void perf_gtk_setup_browser(int argc, const char *argv[],
13 bool fallback_to_pager __used)
14{
15 gtk_init(&argc, (char ***)&argv);
16}
17
18void perf_gtk_exit_browser(bool wait_for_ok __used)
19{
20 gtk_main_quit();
21}
22
23static void perf_gtk_signal(int sig)
24{
25 psignal(sig, "perf");
26 gtk_main_quit();
27}
28
29static void perf_gtk_resize_window(GtkWidget *window)
30{
31 GdkRectangle rect;
32 GdkScreen *screen;
33 int monitor;
34 int height;
35 int width;
36
37 screen = gtk_widget_get_screen(window);
38
39 monitor = gdk_screen_get_monitor_at_window(screen, window->window);
40
41 gdk_screen_get_monitor_geometry(screen, monitor, &rect);
42
43 width = rect.width * 3 / 4;
44 height = rect.height * 3 / 4;
45
46 gtk_window_resize(GTK_WINDOW(window), width, height);
47}
48
49static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
50{
51 GType col_types[MAX_COLUMNS];
52 GtkCellRenderer *renderer;
53 struct sort_entry *se;
54 GtkListStore *store;
55 struct rb_node *nd;
56 u64 total_period;
57 GtkWidget *view;
58 int col_idx;
59 int nr_cols;
60
61 nr_cols = 0;
62
63 /* The percentage column */
64 col_types[nr_cols++] = G_TYPE_STRING;
65
66 list_for_each_entry(se, &hist_entry__sort_list, list) {
67 if (se->elide)
68 continue;
69
70 col_types[nr_cols++] = G_TYPE_STRING;
71 }
72
73 store = gtk_list_store_newv(nr_cols, col_types);
74
75 view = gtk_tree_view_new();
76
77 renderer = gtk_cell_renderer_text_new();
78
79 col_idx = 0;
80
81 /* The percentage column */
82 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
83 -1, "Overhead (%)",
84 renderer, "text",
85 col_idx++, NULL);
86
87 list_for_each_entry(se, &hist_entry__sort_list, list) {
88 if (se->elide)
89 continue;
90
91 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
92 -1, se->se_header,
93 renderer, "text",
94 col_idx++, NULL);
95 }
96
97 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
98
99 g_object_unref(GTK_TREE_MODEL(store));
100
101 total_period = hists->stats.total_period;
102
103 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
104 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
105 GtkTreeIter iter;
106 double percent;
107 char s[512];
108
109 if (h->filtered)
110 continue;
111
112 gtk_list_store_append(store, &iter);
113
114 col_idx = 0;
115
116 percent = (h->period * 100.0) / total_period;
117
118 snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
119
120 gtk_list_store_set(store, &iter, col_idx++, s, -1);
121
122 list_for_each_entry(se, &hist_entry__sort_list, list) {
123 if (se->elide)
124 continue;
125
126 se->se_snprintf(h, s, ARRAY_SIZE(s),
127 hists__col_len(hists, se->se_width_idx));
128
129 gtk_list_store_set(store, &iter, col_idx++, s, -1);
130 }
131 }
132
133 gtk_container_add(GTK_CONTAINER(window), view);
134}
135
136int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
137 const char *help __used,
138 void (*timer) (void *arg)__used,
139 void *arg __used, int delay_secs __used)
140{
141 struct perf_evsel *pos;
142 GtkWidget *notebook;
143 GtkWidget *window;
144
145 signal(SIGSEGV, perf_gtk_signal);
146 signal(SIGFPE, perf_gtk_signal);
147 signal(SIGINT, perf_gtk_signal);
148 signal(SIGQUIT, perf_gtk_signal);
149 signal(SIGTERM, perf_gtk_signal);
150
151 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
152
153 gtk_window_set_title(GTK_WINDOW(window), "perf report");
154
155 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
156
157 notebook = gtk_notebook_new();
158
159 list_for_each_entry(pos, &evlist->entries, node) {
160 struct hists *hists = &pos->hists;
161 const char *evname = event_name(pos);
162 GtkWidget *scrolled_window;
163 GtkWidget *tab_label;
164
165 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
166
167 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
168 GTK_POLICY_AUTOMATIC,
169 GTK_POLICY_AUTOMATIC);
170
171 perf_gtk_show_hists(scrolled_window, hists);
172
173 tab_label = gtk_label_new(evname);
174
175 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
176 }
177
178 gtk_container_add(GTK_CONTAINER(window), notebook);
179
180 gtk_widget_show_all(window);
181
182 perf_gtk_resize_window(window);
183
184 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
185
186 gtk_main();
187
188 return 0;
189}
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/util/gtk/gtk.h
new file mode 100644
index 000000000000..75177ee04032
--- /dev/null
+++ b/tools/perf/util/gtk/gtk.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_GTK_H_
2#define _PERF_GTK_H_ 1
3
4#pragma GCC diagnostic ignored "-Wstrict-prototypes"
5#include <gtk/gtk.h>
6#pragma GCC diagnostic error "-Wstrict-prototypes"
7
8#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index ecd7f4dd7eea..4c7c2d73251f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -63,9 +63,20 @@ char *perf_header__find_event(u64 id)
63 return NULL; 63 return NULL;
64} 64}
65 65
66static const char *__perf_magic = "PERFFILE"; 66/*
67 * magic2 = "PERFILE2"
68 * must be a numerical value to let the endianness
69 * determine the memory layout. That way we are able
70 * to detect endianness when reading the perf.data file
71 * back.
72 *
73 * we check for legacy (PERFFILE) format.
74 */
75static const char *__perf_magic1 = "PERFFILE";
76static const u64 __perf_magic2 = 0x32454c4946524550ULL;
77static const u64 __perf_magic2_sw = 0x50455246494c4532ULL;
67 78
68#define PERF_MAGIC (*(u64 *)__perf_magic) 79#define PERF_MAGIC __perf_magic2
69 80
70struct perf_file_attr { 81struct perf_file_attr {
71 struct perf_event_attr attr; 82 struct perf_event_attr attr;
@@ -280,7 +291,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
280 if (realname == NULL || filename == NULL || linkname == NULL) 291 if (realname == NULL || filename == NULL || linkname == NULL)
281 goto out_free; 292 goto out_free;
282 293
283 len = snprintf(filename, size, "%s%s%s", 294 len = scnprintf(filename, size, "%s%s%s",
284 debugdir, is_kallsyms ? "/" : "", realname); 295 debugdir, is_kallsyms ? "/" : "", realname);
285 if (mkdir_p(filename, 0755)) 296 if (mkdir_p(filename, 0755))
286 goto out_free; 297 goto out_free;
@@ -295,7 +306,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
295 goto out_free; 306 goto out_free;
296 } 307 }
297 308
298 len = snprintf(linkname, size, "%s/.build-id/%.2s", 309 len = scnprintf(linkname, size, "%s/.build-id/%.2s",
299 debugdir, sbuild_id); 310 debugdir, sbuild_id);
300 311
301 if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) 312 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
@@ -1012,6 +1023,12 @@ write_it:
1012 return do_write_string(fd, buffer); 1023 return do_write_string(fd, buffer);
1013} 1024}
1014 1025
1026static int write_branch_stack(int fd __used, struct perf_header *h __used,
1027 struct perf_evlist *evlist __used)
1028{
1029 return 0;
1030}
1031
1015static void print_hostname(struct perf_header *ph, int fd, FILE *fp) 1032static void print_hostname(struct perf_header *ph, int fd, FILE *fp)
1016{ 1033{
1017 char *str = do_read_string(fd, ph); 1034 char *str = do_read_string(fd, ph);
@@ -1133,8 +1150,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1133 uint64_t id; 1150 uint64_t id;
1134 void *buf = NULL; 1151 void *buf = NULL;
1135 char *str; 1152 char *str;
1136 u32 nre, sz, nr, i, j, msz; 1153 u32 nre, sz, nr, i, j;
1137 int ret; 1154 ssize_t ret;
1155 size_t msz;
1138 1156
1139 /* number of events */ 1157 /* number of events */
1140 ret = read(fd, &nre, sizeof(nre)); 1158 ret = read(fd, &nre, sizeof(nre));
@@ -1151,15 +1169,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1151 if (ph->needs_swap) 1169 if (ph->needs_swap)
1152 sz = bswap_32(sz); 1170 sz = bswap_32(sz);
1153 1171
1154 /*
1155 * ensure it is at least to our ABI rev
1156 */
1157 if (sz < (u32)sizeof(attr))
1158 goto error;
1159
1160 memset(&attr, 0, sizeof(attr)); 1172 memset(&attr, 0, sizeof(attr));
1161 1173
1162 /* read entire region to sync up to next field */ 1174 /* buffer to hold on file attr struct */
1163 buf = malloc(sz); 1175 buf = malloc(sz);
1164 if (!buf) 1176 if (!buf)
1165 goto error; 1177 goto error;
@@ -1170,6 +1182,10 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
1170 1182
1171 for (i = 0 ; i < nre; i++) { 1183 for (i = 0 ; i < nre; i++) {
1172 1184
1185 /*
1186 * must read entire on-file attr struct to
1187 * sync up with layout.
1188 */
1173 ret = read(fd, buf, sz); 1189 ret = read(fd, buf, sz);
1174 if (ret != (ssize_t)sz) 1190 if (ret != (ssize_t)sz)
1175 goto error; 1191 goto error;
@@ -1305,25 +1321,204 @@ static void print_cpuid(struct perf_header *ph, int fd, FILE *fp)
1305 free(str); 1321 free(str);
1306} 1322}
1307 1323
1324static void print_branch_stack(struct perf_header *ph __used, int fd __used,
1325 FILE *fp)
1326{
1327 fprintf(fp, "# contains samples with branch stack\n");
1328}
1329
1330static int __event_process_build_id(struct build_id_event *bev,
1331 char *filename,
1332 struct perf_session *session)
1333{
1334 int err = -1;
1335 struct list_head *head;
1336 struct machine *machine;
1337 u16 misc;
1338 struct dso *dso;
1339 enum dso_kernel_type dso_type;
1340
1341 machine = perf_session__findnew_machine(session, bev->pid);
1342 if (!machine)
1343 goto out;
1344
1345 misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1346
1347 switch (misc) {
1348 case PERF_RECORD_MISC_KERNEL:
1349 dso_type = DSO_TYPE_KERNEL;
1350 head = &machine->kernel_dsos;
1351 break;
1352 case PERF_RECORD_MISC_GUEST_KERNEL:
1353 dso_type = DSO_TYPE_GUEST_KERNEL;
1354 head = &machine->kernel_dsos;
1355 break;
1356 case PERF_RECORD_MISC_USER:
1357 case PERF_RECORD_MISC_GUEST_USER:
1358 dso_type = DSO_TYPE_USER;
1359 head = &machine->user_dsos;
1360 break;
1361 default:
1362 goto out;
1363 }
1364
1365 dso = __dsos__findnew(head, filename);
1366 if (dso != NULL) {
1367 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1368
1369 dso__set_build_id(dso, &bev->build_id);
1370
1371 if (filename[0] == '[')
1372 dso->kernel = dso_type;
1373
1374 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
1375 sbuild_id);
1376 pr_debug("build id event received for %s: %s\n",
1377 dso->long_name, sbuild_id);
1378 }
1379
1380 err = 0;
1381out:
1382 return err;
1383}
1384
1385static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1386 int input, u64 offset, u64 size)
1387{
1388 struct perf_session *session = container_of(header, struct perf_session, header);
1389 struct {
1390 struct perf_event_header header;
1391 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
1392 char filename[0];
1393 } old_bev;
1394 struct build_id_event bev;
1395 char filename[PATH_MAX];
1396 u64 limit = offset + size;
1397
1398 while (offset < limit) {
1399 ssize_t len;
1400
1401 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1402 return -1;
1403
1404 if (header->needs_swap)
1405 perf_event_header__bswap(&old_bev.header);
1406
1407 len = old_bev.header.size - sizeof(old_bev);
1408 if (read(input, filename, len) != len)
1409 return -1;
1410
1411 bev.header = old_bev.header;
1412
1413 /*
1414 * As the pid is the missing value, we need to fill
1415 * it properly. The header.misc value give us nice hint.
1416 */
1417 bev.pid = HOST_KERNEL_ID;
1418 if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
1419 bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
1420 bev.pid = DEFAULT_GUEST_KERNEL_ID;
1421
1422 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
1423 __event_process_build_id(&bev, filename, session);
1424
1425 offset += bev.header.size;
1426 }
1427
1428 return 0;
1429}
1430
1431static int perf_header__read_build_ids(struct perf_header *header,
1432 int input, u64 offset, u64 size)
1433{
1434 struct perf_session *session = container_of(header, struct perf_session, header);
1435 struct build_id_event bev;
1436 char filename[PATH_MAX];
1437 u64 limit = offset + size, orig_offset = offset;
1438 int err = -1;
1439
1440 while (offset < limit) {
1441 ssize_t len;
1442
1443 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
1444 goto out;
1445
1446 if (header->needs_swap)
1447 perf_event_header__bswap(&bev.header);
1448
1449 len = bev.header.size - sizeof(bev);
1450 if (read(input, filename, len) != len)
1451 goto out;
1452 /*
1453 * The a1645ce1 changeset:
1454 *
1455 * "perf: 'perf kvm' tool for monitoring guest performance from host"
1456 *
1457 * Added a field to struct build_id_event that broke the file
1458 * format.
1459 *
1460 * Since the kernel build-id is the first entry, process the
1461 * table using the old format if the well known
1462 * '[kernel.kallsyms]' string for the kernel build-id has the
1463 * first 4 characters chopped off (where the pid_t sits).
1464 */
1465 if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
1466 if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
1467 return -1;
1468 return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
1469 }
1470
1471 __event_process_build_id(&bev, filename, session);
1472
1473 offset += bev.header.size;
1474 }
1475 err = 0;
1476out:
1477 return err;
1478}
1479
1480static int process_trace_info(struct perf_file_section *section __unused,
1481 struct perf_header *ph __unused,
1482 int feat __unused, int fd)
1483{
1484 trace_report(fd, false);
1485 return 0;
1486}
1487
1488static int process_build_id(struct perf_file_section *section,
1489 struct perf_header *ph,
1490 int feat __unused, int fd)
1491{
1492 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
1493 pr_debug("Failed to read buildids, continuing...\n");
1494 return 0;
1495}
1496
1308struct feature_ops { 1497struct feature_ops {
1309 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 1498 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1310 void (*print)(struct perf_header *h, int fd, FILE *fp); 1499 void (*print)(struct perf_header *h, int fd, FILE *fp);
1500 int (*process)(struct perf_file_section *section,
1501 struct perf_header *h, int feat, int fd);
1311 const char *name; 1502 const char *name;
1312 bool full_only; 1503 bool full_only;
1313}; 1504};
1314 1505
1315#define FEAT_OPA(n, func) \ 1506#define FEAT_OPA(n, func) \
1316 [n] = { .name = #n, .write = write_##func, .print = print_##func } 1507 [n] = { .name = #n, .write = write_##func, .print = print_##func }
1508#define FEAT_OPP(n, func) \
1509 [n] = { .name = #n, .write = write_##func, .print = print_##func, \
1510 .process = process_##func }
1317#define FEAT_OPF(n, func) \ 1511#define FEAT_OPF(n, func) \
1318 [n] = { .name = #n, .write = write_##func, .print = print_##func, .full_only = true } 1512 [n] = { .name = #n, .write = write_##func, .print = print_##func, \
1513 .full_only = true }
1319 1514
1320/* feature_ops not implemented: */ 1515/* feature_ops not implemented: */
1321#define print_trace_info NULL 1516#define print_trace_info NULL
1322#define print_build_id NULL 1517#define print_build_id NULL
1323 1518
1324static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { 1519static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1325 FEAT_OPA(HEADER_TRACE_INFO, trace_info), 1520 FEAT_OPP(HEADER_TRACE_INFO, trace_info),
1326 FEAT_OPA(HEADER_BUILD_ID, build_id), 1521 FEAT_OPP(HEADER_BUILD_ID, build_id),
1327 FEAT_OPA(HEADER_HOSTNAME, hostname), 1522 FEAT_OPA(HEADER_HOSTNAME, hostname),
1328 FEAT_OPA(HEADER_OSRELEASE, osrelease), 1523 FEAT_OPA(HEADER_OSRELEASE, osrelease),
1329 FEAT_OPA(HEADER_VERSION, version), 1524 FEAT_OPA(HEADER_VERSION, version),
@@ -1336,6 +1531,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1336 FEAT_OPA(HEADER_CMDLINE, cmdline), 1531 FEAT_OPA(HEADER_CMDLINE, cmdline),
1337 FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology), 1532 FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
1338 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), 1533 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1534 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1339}; 1535};
1340 1536
1341struct header_print_data { 1537struct header_print_data {
@@ -1620,24 +1816,128 @@ out_free:
1620 return err; 1816 return err;
1621} 1817}
1622 1818
1819static const int attr_file_abi_sizes[] = {
1820 [0] = PERF_ATTR_SIZE_VER0,
1821 [1] = PERF_ATTR_SIZE_VER1,
1822 0,
1823};
1824
1825/*
1826 * In the legacy file format, the magic number is not used to encode endianness.
1827 * hdr_sz was used to encode endianness. But given that hdr_sz can vary based
1828 * on ABI revisions, we need to try all combinations for all endianness to
1829 * detect the endianness.
1830 */
1831static int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph)
1832{
1833 uint64_t ref_size, attr_size;
1834 int i;
1835
1836 for (i = 0 ; attr_file_abi_sizes[i]; i++) {
1837 ref_size = attr_file_abi_sizes[i]
1838 + sizeof(struct perf_file_section);
1839 if (hdr_sz != ref_size) {
1840 attr_size = bswap_64(hdr_sz);
1841 if (attr_size != ref_size)
1842 continue;
1843
1844 ph->needs_swap = true;
1845 }
1846 pr_debug("ABI%d perf.data file detected, need_swap=%d\n",
1847 i,
1848 ph->needs_swap);
1849 return 0;
1850 }
1851 /* could not determine endianness */
1852 return -1;
1853}
1854
1855#define PERF_PIPE_HDR_VER0 16
1856
1857static const size_t attr_pipe_abi_sizes[] = {
1858 [0] = PERF_PIPE_HDR_VER0,
1859 0,
1860};
1861
1862/*
1863 * In the legacy pipe format, there is an implicit assumption that endiannesss
1864 * between host recording the samples, and host parsing the samples is the
1865 * same. This is not always the case given that the pipe output may always be
1866 * redirected into a file and analyzed on a different machine with possibly a
1867 * different endianness and perf_event ABI revsions in the perf tool itself.
1868 */
1869static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
1870{
1871 u64 attr_size;
1872 int i;
1873
1874 for (i = 0 ; attr_pipe_abi_sizes[i]; i++) {
1875 if (hdr_sz != attr_pipe_abi_sizes[i]) {
1876 attr_size = bswap_64(hdr_sz);
1877 if (attr_size != hdr_sz)
1878 continue;
1879
1880 ph->needs_swap = true;
1881 }
1882 pr_debug("Pipe ABI%d perf.data file detected\n", i);
1883 return 0;
1884 }
1885 return -1;
1886}
1887
1888static int check_magic_endian(u64 magic, uint64_t hdr_sz,
1889 bool is_pipe, struct perf_header *ph)
1890{
1891 int ret;
1892
1893 /* check for legacy format */
1894 ret = memcmp(&magic, __perf_magic1, sizeof(magic));
1895 if (ret == 0) {
1896 pr_debug("legacy perf.data format\n");
1897 if (is_pipe)
1898 return try_all_pipe_abis(hdr_sz, ph);
1899
1900 return try_all_file_abis(hdr_sz, ph);
1901 }
1902 /*
1903 * the new magic number serves two purposes:
1904 * - unique number to identify actual perf.data files
1905 * - encode endianness of file
1906 */
1907
1908 /* check magic number with one endianness */
1909 if (magic == __perf_magic2)
1910 return 0;
1911
1912 /* check magic number with opposite endianness */
1913 if (magic != __perf_magic2_sw)
1914 return -1;
1915
1916 ph->needs_swap = true;
1917
1918 return 0;
1919}
1920
1623int perf_file_header__read(struct perf_file_header *header, 1921int perf_file_header__read(struct perf_file_header *header,
1624 struct perf_header *ph, int fd) 1922 struct perf_header *ph, int fd)
1625{ 1923{
1924 int ret;
1925
1626 lseek(fd, 0, SEEK_SET); 1926 lseek(fd, 0, SEEK_SET);
1627 1927
1628 if (readn(fd, header, sizeof(*header)) <= 0 || 1928 ret = readn(fd, header, sizeof(*header));
1629 memcmp(&header->magic, __perf_magic, sizeof(header->magic))) 1929 if (ret <= 0)
1630 return -1; 1930 return -1;
1631 1931
1632 if (header->attr_size != sizeof(struct perf_file_attr)) { 1932 if (check_magic_endian(header->magic,
1633 u64 attr_size = bswap_64(header->attr_size); 1933 header->attr_size, false, ph) < 0) {
1634 1934 pr_debug("magic/endian check failed\n");
1635 if (attr_size != sizeof(struct perf_file_attr)) 1935 return -1;
1636 return -1; 1936 }
1637 1937
1938 if (ph->needs_swap) {
1638 mem_bswap_64(header, offsetof(struct perf_file_header, 1939 mem_bswap_64(header, offsetof(struct perf_file_header,
1639 adds_features)); 1940 adds_features));
1640 ph->needs_swap = true;
1641 } 1941 }
1642 1942
1643 if (header->size != sizeof(*header)) { 1943 if (header->size != sizeof(*header)) {
@@ -1689,156 +1989,6 @@ int perf_file_header__read(struct perf_file_header *header,
1689 return 0; 1989 return 0;
1690} 1990}
1691 1991
1692static int __event_process_build_id(struct build_id_event *bev,
1693 char *filename,
1694 struct perf_session *session)
1695{
1696 int err = -1;
1697 struct list_head *head;
1698 struct machine *machine;
1699 u16 misc;
1700 struct dso *dso;
1701 enum dso_kernel_type dso_type;
1702
1703 machine = perf_session__findnew_machine(session, bev->pid);
1704 if (!machine)
1705 goto out;
1706
1707 misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1708
1709 switch (misc) {
1710 case PERF_RECORD_MISC_KERNEL:
1711 dso_type = DSO_TYPE_KERNEL;
1712 head = &machine->kernel_dsos;
1713 break;
1714 case PERF_RECORD_MISC_GUEST_KERNEL:
1715 dso_type = DSO_TYPE_GUEST_KERNEL;
1716 head = &machine->kernel_dsos;
1717 break;
1718 case PERF_RECORD_MISC_USER:
1719 case PERF_RECORD_MISC_GUEST_USER:
1720 dso_type = DSO_TYPE_USER;
1721 head = &machine->user_dsos;
1722 break;
1723 default:
1724 goto out;
1725 }
1726
1727 dso = __dsos__findnew(head, filename);
1728 if (dso != NULL) {
1729 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1730
1731 dso__set_build_id(dso, &bev->build_id);
1732
1733 if (filename[0] == '[')
1734 dso->kernel = dso_type;
1735
1736 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
1737 sbuild_id);
1738 pr_debug("build id event received for %s: %s\n",
1739 dso->long_name, sbuild_id);
1740 }
1741
1742 err = 0;
1743out:
1744 return err;
1745}
1746
1747static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1748 int input, u64 offset, u64 size)
1749{
1750 struct perf_session *session = container_of(header, struct perf_session, header);
1751 struct {
1752 struct perf_event_header header;
1753 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
1754 char filename[0];
1755 } old_bev;
1756 struct build_id_event bev;
1757 char filename[PATH_MAX];
1758 u64 limit = offset + size;
1759
1760 while (offset < limit) {
1761 ssize_t len;
1762
1763 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1764 return -1;
1765
1766 if (header->needs_swap)
1767 perf_event_header__bswap(&old_bev.header);
1768
1769 len = old_bev.header.size - sizeof(old_bev);
1770 if (read(input, filename, len) != len)
1771 return -1;
1772
1773 bev.header = old_bev.header;
1774
1775 /*
1776 * As the pid is the missing value, we need to fill
1777 * it properly. The header.misc value give us nice hint.
1778 */
1779 bev.pid = HOST_KERNEL_ID;
1780 if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
1781 bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
1782 bev.pid = DEFAULT_GUEST_KERNEL_ID;
1783
1784 memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
1785 __event_process_build_id(&bev, filename, session);
1786
1787 offset += bev.header.size;
1788 }
1789
1790 return 0;
1791}
1792
1793static int perf_header__read_build_ids(struct perf_header *header,
1794 int input, u64 offset, u64 size)
1795{
1796 struct perf_session *session = container_of(header, struct perf_session, header);
1797 struct build_id_event bev;
1798 char filename[PATH_MAX];
1799 u64 limit = offset + size, orig_offset = offset;
1800 int err = -1;
1801
1802 while (offset < limit) {
1803 ssize_t len;
1804
1805 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
1806 goto out;
1807
1808 if (header->needs_swap)
1809 perf_event_header__bswap(&bev.header);
1810
1811 len = bev.header.size - sizeof(bev);
1812 if (read(input, filename, len) != len)
1813 goto out;
1814 /*
1815 * The a1645ce1 changeset:
1816 *
1817 * "perf: 'perf kvm' tool for monitoring guest performance from host"
1818 *
1819 * Added a field to struct build_id_event that broke the file
1820 * format.
1821 *
1822 * Since the kernel build-id is the first entry, process the
1823 * table using the old format if the well known
1824 * '[kernel.kallsyms]' string for the kernel build-id has the
1825 * first 4 characters chopped off (where the pid_t sits).
1826 */
1827 if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
1828 if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
1829 return -1;
1830 return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
1831 }
1832
1833 __event_process_build_id(&bev, filename, session);
1834
1835 offset += bev.header.size;
1836 }
1837 err = 0;
1838out:
1839 return err;
1840}
1841
1842static int perf_file_section__process(struct perf_file_section *section, 1992static int perf_file_section__process(struct perf_file_section *section,
1843 struct perf_header *ph, 1993 struct perf_header *ph,
1844 int feat, int fd, void *data __used) 1994 int feat, int fd, void *data __used)
@@ -1854,40 +2004,32 @@ static int perf_file_section__process(struct perf_file_section *section,
1854 return 0; 2004 return 0;
1855 } 2005 }
1856 2006
1857 switch (feat) { 2007 if (!feat_ops[feat].process)
1858 case HEADER_TRACE_INFO: 2008 return 0;
1859 trace_report(fd, false);
1860 break;
1861 case HEADER_BUILD_ID:
1862 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
1863 pr_debug("Failed to read buildids, continuing...\n");
1864 break;
1865 default:
1866 break;
1867 }
1868 2009
1869 return 0; 2010 return feat_ops[feat].process(section, ph, feat, fd);
1870} 2011}
1871 2012
1872static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, 2013static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
1873 struct perf_header *ph, int fd, 2014 struct perf_header *ph, int fd,
1874 bool repipe) 2015 bool repipe)
1875{ 2016{
1876 if (readn(fd, header, sizeof(*header)) <= 0 || 2017 int ret;
1877 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
1878 return -1;
1879 2018
1880 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) 2019 ret = readn(fd, header, sizeof(*header));
2020 if (ret <= 0)
1881 return -1; 2021 return -1;
1882 2022
1883 if (header->size != sizeof(*header)) { 2023 if (check_magic_endian(header->magic, header->size, true, ph) < 0) {
1884 u64 size = bswap_64(header->size); 2024 pr_debug("endian/magic failed\n");
2025 return -1;
2026 }
1885 2027
1886 if (size != sizeof(*header)) 2028 if (ph->needs_swap)
1887 return -1; 2029 header->size = bswap_64(header->size);
1888 2030
1889 ph->needs_swap = true; 2031 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
1890 } 2032 return -1;
1891 2033
1892 return 0; 2034 return 0;
1893} 2035}
@@ -1908,6 +2050,52 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
1908 return 0; 2050 return 0;
1909} 2051}
1910 2052
2053static int read_attr(int fd, struct perf_header *ph,
2054 struct perf_file_attr *f_attr)
2055{
2056 struct perf_event_attr *attr = &f_attr->attr;
2057 size_t sz, left;
2058 size_t our_sz = sizeof(f_attr->attr);
2059 int ret;
2060
2061 memset(f_attr, 0, sizeof(*f_attr));
2062
2063 /* read minimal guaranteed structure */
2064 ret = readn(fd, attr, PERF_ATTR_SIZE_VER0);
2065 if (ret <= 0) {
2066 pr_debug("cannot read %d bytes of header attr\n",
2067 PERF_ATTR_SIZE_VER0);
2068 return -1;
2069 }
2070
2071 /* on file perf_event_attr size */
2072 sz = attr->size;
2073
2074 if (ph->needs_swap)
2075 sz = bswap_32(sz);
2076
2077 if (sz == 0) {
2078 /* assume ABI0 */
2079 sz = PERF_ATTR_SIZE_VER0;
2080 } else if (sz > our_sz) {
2081 pr_debug("file uses a more recent and unsupported ABI"
2082 " (%zu bytes extra)\n", sz - our_sz);
2083 return -1;
2084 }
2085 /* what we have not yet read and that we know about */
2086 left = sz - PERF_ATTR_SIZE_VER0;
2087 if (left) {
2088 void *ptr = attr;
2089 ptr += PERF_ATTR_SIZE_VER0;
2090
2091 ret = readn(fd, ptr, left);
2092 }
2093 /* read perf_file_section, ids are read in caller */
2094 ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids));
2095
2096 return ret <= 0 ? -1 : 0;
2097}
2098
1911int perf_session__read_header(struct perf_session *session, int fd) 2099int perf_session__read_header(struct perf_session *session, int fd)
1912{ 2100{
1913 struct perf_header *header = &session->header; 2101 struct perf_header *header = &session->header;
@@ -1923,19 +2111,17 @@ int perf_session__read_header(struct perf_session *session, int fd)
1923 if (session->fd_pipe) 2111 if (session->fd_pipe)
1924 return perf_header__read_pipe(session, fd); 2112 return perf_header__read_pipe(session, fd);
1925 2113
1926 if (perf_file_header__read(&f_header, header, fd) < 0) { 2114 if (perf_file_header__read(&f_header, header, fd) < 0)
1927 pr_debug("incompatible file format\n");
1928 return -EINVAL; 2115 return -EINVAL;
1929 }
1930 2116
1931 nr_attrs = f_header.attrs.size / sizeof(f_attr); 2117 nr_attrs = f_header.attrs.size / f_header.attr_size;
1932 lseek(fd, f_header.attrs.offset, SEEK_SET); 2118 lseek(fd, f_header.attrs.offset, SEEK_SET);
1933 2119
1934 for (i = 0; i < nr_attrs; i++) { 2120 for (i = 0; i < nr_attrs; i++) {
1935 struct perf_evsel *evsel; 2121 struct perf_evsel *evsel;
1936 off_t tmp; 2122 off_t tmp;
1937 2123
1938 if (readn(fd, &f_attr, sizeof(f_attr)) <= 0) 2124 if (read_attr(fd, header, &f_attr) < 0)
1939 goto out_errno; 2125 goto out_errno;
1940 2126
1941 if (header->needs_swap) 2127 if (header->needs_swap)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index ac4ec956024e..21a6be09c129 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -11,6 +11,7 @@
11 11
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_RESERVED = 0, /* always cleared */
14 HEADER_FIRST_FEATURE = 1,
14 HEADER_TRACE_INFO = 1, 15 HEADER_TRACE_INFO = 1,
15 HEADER_BUILD_ID, 16 HEADER_BUILD_ID,
16 17
@@ -26,7 +27,7 @@ enum {
26 HEADER_EVENT_DESC, 27 HEADER_EVENT_DESC,
27 HEADER_CPU_TOPOLOGY, 28 HEADER_CPU_TOPOLOGY,
28 HEADER_NUMA_TOPOLOGY, 29 HEADER_NUMA_TOPOLOGY,
29 30 HEADER_BRANCH_STACK,
30 HEADER_LAST_FEATURE, 31 HEADER_LAST_FEATURE,
31 HEADER_FEAT_BITS = 256, 32 HEADER_FEAT_BITS = 256,
32}; 33};
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 6f505d1abac7..2ec4b60aff6c 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -10,11 +10,14 @@ static bool hists__filter_entry_by_dso(struct hists *hists,
10 struct hist_entry *he); 10 struct hist_entry *he);
11static bool hists__filter_entry_by_thread(struct hists *hists, 11static bool hists__filter_entry_by_thread(struct hists *hists,
12 struct hist_entry *he); 12 struct hist_entry *he);
13static bool hists__filter_entry_by_symbol(struct hists *hists,
14 struct hist_entry *he);
13 15
14enum hist_filter { 16enum hist_filter {
15 HIST_FILTER__DSO, 17 HIST_FILTER__DSO,
16 HIST_FILTER__THREAD, 18 HIST_FILTER__THREAD,
17 HIST_FILTER__PARENT, 19 HIST_FILTER__PARENT,
20 HIST_FILTER__SYMBOL,
18}; 21};
19 22
20struct callchain_param callchain_param = { 23struct callchain_param callchain_param = {
@@ -50,21 +53,25 @@ static void hists__reset_col_len(struct hists *hists)
50 hists__set_col_len(hists, col, 0); 53 hists__set_col_len(hists, col, 0);
51} 54}
52 55
56static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
57{
58 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
59
60 if (hists__col_len(hists, dso) < unresolved_col_width &&
61 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
62 !symbol_conf.dso_list)
63 hists__set_col_len(hists, dso, unresolved_col_width);
64}
65
53static void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 66static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
54{ 67{
68 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
55 u16 len; 69 u16 len;
56 70
57 if (h->ms.sym) 71 if (h->ms.sym)
58 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen); 72 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
59 else { 73 else
60 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 74 hists__set_unres_dso_col_len(hists, HISTC_DSO);
61
62 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
63 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
64 !symbol_conf.dso_list)
65 hists__set_col_len(hists, HISTC_DSO,
66 unresolved_col_width);
67 }
68 75
69 len = thread__comm_len(h->thread); 76 len = thread__comm_len(h->thread);
70 if (hists__new_col_len(hists, HISTC_COMM, len)) 77 if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -74,6 +81,37 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
74 len = dso__name_len(h->ms.map->dso); 81 len = dso__name_len(h->ms.map->dso);
75 hists__new_col_len(hists, HISTC_DSO, len); 82 hists__new_col_len(hists, HISTC_DSO, len);
76 } 83 }
84
85 if (h->branch_info) {
86 int symlen;
87 /*
88 * +4 accounts for '[x] ' priv level info
89 * +2 account of 0x prefix on raw addresses
90 */
91 if (h->branch_info->from.sym) {
92 symlen = (int)h->branch_info->from.sym->namelen + 4;
93 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
94
95 symlen = dso__name_len(h->branch_info->from.map->dso);
96 hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
97 } else {
98 symlen = unresolved_col_width + 4 + 2;
99 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
100 hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
101 }
102
103 if (h->branch_info->to.sym) {
104 symlen = (int)h->branch_info->to.sym->namelen + 4;
105 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
106
107 symlen = dso__name_len(h->branch_info->to.map->dso);
108 hists__new_col_len(hists, HISTC_DSO_TO, symlen);
109 } else {
110 symlen = unresolved_col_width + 4 + 2;
111 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
112 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
113 }
114 }
77} 115}
78 116
79static void hist_entry__add_cpumode_period(struct hist_entry *he, 117static void hist_entry__add_cpumode_period(struct hist_entry *he,
@@ -195,26 +233,14 @@ static u8 symbol__parent_filter(const struct symbol *parent)
195 return 0; 233 return 0;
196} 234}
197 235
198struct hist_entry *__hists__add_entry(struct hists *hists, 236static struct hist_entry *add_hist_entry(struct hists *hists,
237 struct hist_entry *entry,
199 struct addr_location *al, 238 struct addr_location *al,
200 struct symbol *sym_parent, u64 period) 239 u64 period)
201{ 240{
202 struct rb_node **p; 241 struct rb_node **p;
203 struct rb_node *parent = NULL; 242 struct rb_node *parent = NULL;
204 struct hist_entry *he; 243 struct hist_entry *he;
205 struct hist_entry entry = {
206 .thread = al->thread,
207 .ms = {
208 .map = al->map,
209 .sym = al->sym,
210 },
211 .cpu = al->cpu,
212 .ip = al->addr,
213 .level = al->level,
214 .period = period,
215 .parent = sym_parent,
216 .filtered = symbol__parent_filter(sym_parent),
217 };
218 int cmp; 244 int cmp;
219 245
220 pthread_mutex_lock(&hists->lock); 246 pthread_mutex_lock(&hists->lock);
@@ -225,7 +251,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
225 parent = *p; 251 parent = *p;
226 he = rb_entry(parent, struct hist_entry, rb_node_in); 252 he = rb_entry(parent, struct hist_entry, rb_node_in);
227 253
228 cmp = hist_entry__cmp(&entry, he); 254 cmp = hist_entry__cmp(entry, he);
229 255
230 if (!cmp) { 256 if (!cmp) {
231 he->period += period; 257 he->period += period;
@@ -239,7 +265,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
239 p = &(*p)->rb_right; 265 p = &(*p)->rb_right;
240 } 266 }
241 267
242 he = hist_entry__new(&entry); 268 he = hist_entry__new(entry);
243 if (!he) 269 if (!he)
244 goto out_unlock; 270 goto out_unlock;
245 271
@@ -252,6 +278,51 @@ out_unlock:
252 return he; 278 return he;
253} 279}
254 280
281struct hist_entry *__hists__add_branch_entry(struct hists *self,
282 struct addr_location *al,
283 struct symbol *sym_parent,
284 struct branch_info *bi,
285 u64 period)
286{
287 struct hist_entry entry = {
288 .thread = al->thread,
289 .ms = {
290 .map = bi->to.map,
291 .sym = bi->to.sym,
292 },
293 .cpu = al->cpu,
294 .ip = bi->to.addr,
295 .level = al->level,
296 .period = period,
297 .parent = sym_parent,
298 .filtered = symbol__parent_filter(sym_parent),
299 .branch_info = bi,
300 };
301
302 return add_hist_entry(self, &entry, al, period);
303}
304
305struct hist_entry *__hists__add_entry(struct hists *self,
306 struct addr_location *al,
307 struct symbol *sym_parent, u64 period)
308{
309 struct hist_entry entry = {
310 .thread = al->thread,
311 .ms = {
312 .map = al->map,
313 .sym = al->sym,
314 },
315 .cpu = al->cpu,
316 .ip = al->addr,
317 .level = al->level,
318 .period = period,
319 .parent = sym_parent,
320 .filtered = symbol__parent_filter(sym_parent),
321 };
322
323 return add_hist_entry(self, &entry, al, period);
324}
325
255int64_t 326int64_t
256hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 327hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
257{ 328{
@@ -352,6 +423,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
352{ 423{
353 hists__filter_entry_by_dso(hists, he); 424 hists__filter_entry_by_dso(hists, he);
354 hists__filter_entry_by_thread(hists, he); 425 hists__filter_entry_by_thread(hists, he);
426 hists__filter_entry_by_symbol(hists, he);
355} 427}
356 428
357static void __hists__collapse_resort(struct hists *hists, bool threaded) 429static void __hists__collapse_resort(struct hists *hists, bool threaded)
@@ -535,7 +607,7 @@ static void init_rem_hits(void)
535 rem_hits.ms.sym = rem_sq_bracket; 607 rem_hits.ms.sym = rem_sq_bracket;
536} 608}
537 609
538static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 610static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
539 u64 total_samples, int depth, 611 u64 total_samples, int depth,
540 int depth_mask, int left_margin) 612 int depth_mask, int left_margin)
541{ 613{
@@ -543,21 +615,16 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
543 struct callchain_node *child; 615 struct callchain_node *child;
544 struct callchain_list *chain; 616 struct callchain_list *chain;
545 int new_depth_mask = depth_mask; 617 int new_depth_mask = depth_mask;
546 u64 new_total;
547 u64 remaining; 618 u64 remaining;
548 size_t ret = 0; 619 size_t ret = 0;
549 int i; 620 int i;
550 uint entries_printed = 0; 621 uint entries_printed = 0;
551 622
552 if (callchain_param.mode == CHAIN_GRAPH_REL) 623 remaining = total_samples;
553 new_total = self->children_hit;
554 else
555 new_total = total_samples;
556
557 remaining = new_total;
558 624
559 node = rb_first(&self->rb_root); 625 node = rb_first(root);
560 while (node) { 626 while (node) {
627 u64 new_total;
561 u64 cumul; 628 u64 cumul;
562 629
563 child = rb_entry(node, struct callchain_node, rb_node); 630 child = rb_entry(node, struct callchain_node, rb_node);
@@ -585,11 +652,17 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
585 list_for_each_entry(chain, &child->val, list) { 652 list_for_each_entry(chain, &child->val, list) {
586 ret += ipchain__fprintf_graph(fp, chain, depth, 653 ret += ipchain__fprintf_graph(fp, chain, depth,
587 new_depth_mask, i++, 654 new_depth_mask, i++,
588 new_total, 655 total_samples,
589 cumul, 656 cumul,
590 left_margin); 657 left_margin);
591 } 658 }
592 ret += __callchain__fprintf_graph(fp, child, new_total, 659
660 if (callchain_param.mode == CHAIN_GRAPH_REL)
661 new_total = child->children_hit;
662 else
663 new_total = total_samples;
664
665 ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
593 depth + 1, 666 depth + 1,
594 new_depth_mask | (1 << depth), 667 new_depth_mask | (1 << depth),
595 left_margin); 668 left_margin);
@@ -599,61 +672,75 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
599 } 672 }
600 673
601 if (callchain_param.mode == CHAIN_GRAPH_REL && 674 if (callchain_param.mode == CHAIN_GRAPH_REL &&
602 remaining && remaining != new_total) { 675 remaining && remaining != total_samples) {
603 676
604 if (!rem_sq_bracket) 677 if (!rem_sq_bracket)
605 return ret; 678 return ret;
606 679
607 new_depth_mask &= ~(1 << (depth - 1)); 680 new_depth_mask &= ~(1 << (depth - 1));
608
609 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 681 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
610 new_depth_mask, 0, new_total, 682 new_depth_mask, 0, total_samples,
611 remaining, left_margin); 683 remaining, left_margin);
612 } 684 }
613 685
614 return ret; 686 return ret;
615} 687}
616 688
617static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 689static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
618 u64 total_samples, int left_margin) 690 u64 total_samples, int left_margin)
619{ 691{
692 struct callchain_node *cnode;
620 struct callchain_list *chain; 693 struct callchain_list *chain;
694 u32 entries_printed = 0;
621 bool printed = false; 695 bool printed = false;
696 struct rb_node *node;
622 int i = 0; 697 int i = 0;
623 int ret = 0; 698 int ret;
624 u32 entries_printed = 0;
625
626 list_for_each_entry(chain, &self->val, list) {
627 if (!i++ && sort__first_dimension == SORT_SYM)
628 continue;
629
630 if (!printed) {
631 ret += callchain__fprintf_left_margin(fp, left_margin);
632 ret += fprintf(fp, "|\n");
633 ret += callchain__fprintf_left_margin(fp, left_margin);
634 ret += fprintf(fp, "---");
635
636 left_margin += 3;
637 printed = true;
638 } else
639 ret += callchain__fprintf_left_margin(fp, left_margin);
640 699
641 if (chain->ms.sym) 700 /*
642 ret += fprintf(fp, " %s\n", chain->ms.sym->name); 701 * If have one single callchain root, don't bother printing
643 else 702 * its percentage (100 % in fractal mode and the same percentage
644 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 703 * than the hist in graph mode). This also avoid one level of column.
704 */
705 node = rb_first(root);
706 if (node && !rb_next(node)) {
707 cnode = rb_entry(node, struct callchain_node, rb_node);
708 list_for_each_entry(chain, &cnode->val, list) {
709 /*
710 * If we sort by symbol, the first entry is the same than
711 * the symbol. No need to print it otherwise it appears as
712 * displayed twice.
713 */
714 if (!i++ && sort__first_dimension == SORT_SYM)
715 continue;
716 if (!printed) {
717 ret += callchain__fprintf_left_margin(fp, left_margin);
718 ret += fprintf(fp, "|\n");
719 ret += callchain__fprintf_left_margin(fp, left_margin);
720 ret += fprintf(fp, "---");
721 left_margin += 3;
722 printed = true;
723 } else
724 ret += callchain__fprintf_left_margin(fp, left_margin);
725
726 if (chain->ms.sym)
727 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
728 else
729 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
645 730
646 if (++entries_printed == callchain_param.print_limit) 731 if (++entries_printed == callchain_param.print_limit)
647 break; 732 break;
733 }
734 root = &cnode->rb_root;
648 } 735 }
649 736
650 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 737 return __callchain__fprintf_graph(fp, root, total_samples,
651 738 1, 1, left_margin);
652 return ret;
653} 739}
654 740
655static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self, 741static size_t __callchain__fprintf_flat(FILE *fp,
656 u64 total_samples) 742 struct callchain_node *self,
743 u64 total_samples)
657{ 744{
658 struct callchain_list *chain; 745 struct callchain_list *chain;
659 size_t ret = 0; 746 size_t ret = 0;
@@ -661,7 +748,7 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
661 if (!self) 748 if (!self)
662 return 0; 749 return 0;
663 750
664 ret += callchain__fprintf_flat(fp, self->parent, total_samples); 751 ret += __callchain__fprintf_flat(fp, self->parent, total_samples);
665 752
666 753
667 list_for_each_entry(chain, &self->val, list) { 754 list_for_each_entry(chain, &self->val, list) {
@@ -677,44 +764,58 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
677 return ret; 764 return ret;
678} 765}
679 766
680static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 767static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
681 u64 total_samples, int left_margin, 768 u64 total_samples)
682 FILE *fp)
683{ 769{
684 struct rb_node *rb_node;
685 struct callchain_node *chain;
686 size_t ret = 0; 770 size_t ret = 0;
687 u32 entries_printed = 0; 771 u32 entries_printed = 0;
772 struct rb_node *rb_node;
773 struct callchain_node *chain;
688 774
689 rb_node = rb_first(&he->sorted_chain); 775 rb_node = rb_first(self);
690 while (rb_node) { 776 while (rb_node) {
691 double percent; 777 double percent;
692 778
693 chain = rb_entry(rb_node, struct callchain_node, rb_node); 779 chain = rb_entry(rb_node, struct callchain_node, rb_node);
694 percent = chain->hit * 100.0 / total_samples; 780 percent = chain->hit * 100.0 / total_samples;
695 switch (callchain_param.mode) { 781
696 case CHAIN_FLAT: 782 ret = percent_color_fprintf(fp, " %6.2f%%\n", percent);
697 ret += percent_color_fprintf(fp, " %6.2f%%\n", 783 ret += __callchain__fprintf_flat(fp, chain, total_samples);
698 percent);
699 ret += callchain__fprintf_flat(fp, chain, total_samples);
700 break;
701 case CHAIN_GRAPH_ABS: /* Falldown */
702 case CHAIN_GRAPH_REL:
703 ret += callchain__fprintf_graph(fp, chain, total_samples,
704 left_margin);
705 case CHAIN_NONE:
706 default:
707 break;
708 }
709 ret += fprintf(fp, "\n"); 784 ret += fprintf(fp, "\n");
710 if (++entries_printed == callchain_param.print_limit) 785 if (++entries_printed == callchain_param.print_limit)
711 break; 786 break;
787
712 rb_node = rb_next(rb_node); 788 rb_node = rb_next(rb_node);
713 } 789 }
714 790
715 return ret; 791 return ret;
716} 792}
717 793
794static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
795 u64 total_samples, int left_margin,
796 FILE *fp)
797{
798 switch (callchain_param.mode) {
799 case CHAIN_GRAPH_REL:
800 return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
801 left_margin);
802 break;
803 case CHAIN_GRAPH_ABS:
804 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
805 left_margin);
806 break;
807 case CHAIN_FLAT:
808 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
809 break;
810 case CHAIN_NONE:
811 break;
812 default:
813 pr_err("Bad callchain mode\n");
814 }
815
816 return 0;
817}
818
718void hists__output_recalc_col_len(struct hists *hists, int max_rows) 819void hists__output_recalc_col_len(struct hists *hists, int max_rows)
719{ 820{
720 struct rb_node *next = rb_first(&hists->entries); 821 struct rb_node *next = rb_first(&hists->entries);
@@ -768,7 +869,7 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
768 sep ? "%.2f" : " %6.2f%%", 869 sep ? "%.2f" : " %6.2f%%",
769 (period * 100.0) / total); 870 (period * 100.0) / total);
770 else 871 else
771 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%", 872 ret = scnprintf(s, size, sep ? "%.2f" : " %6.2f%%",
772 (period * 100.0) / total); 873 (period * 100.0) / total);
773 if (symbol_conf.show_cpu_utilization) { 874 if (symbol_conf.show_cpu_utilization) {
774 ret += percent_color_snprintf(s + ret, size - ret, 875 ret += percent_color_snprintf(s + ret, size - ret,
@@ -791,20 +892,20 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
791 } 892 }
792 } 893 }
793 } else 894 } else
794 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period); 895 ret = scnprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
795 896
796 if (symbol_conf.show_nr_samples) { 897 if (symbol_conf.show_nr_samples) {
797 if (sep) 898 if (sep)
798 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events); 899 ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
799 else 900 else
800 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); 901 ret += scnprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
801 } 902 }
802 903
803 if (symbol_conf.show_total_period) { 904 if (symbol_conf.show_total_period) {
804 if (sep) 905 if (sep)
805 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period); 906 ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
806 else 907 else
807 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period); 908 ret += scnprintf(s + ret, size - ret, " %12" PRIu64, period);
808 } 909 }
809 910
810 if (pair_hists) { 911 if (pair_hists) {
@@ -819,25 +920,25 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
819 diff = new_percent - old_percent; 920 diff = new_percent - old_percent;
820 921
821 if (fabs(diff) >= 0.01) 922 if (fabs(diff) >= 0.01)
822 snprintf(bf, sizeof(bf), "%+4.2F%%", diff); 923 scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
823 else 924 else
824 snprintf(bf, sizeof(bf), " "); 925 scnprintf(bf, sizeof(bf), " ");
825 926
826 if (sep) 927 if (sep)
827 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf); 928 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
828 else 929 else
829 ret += snprintf(s + ret, size - ret, "%11.11s", bf); 930 ret += scnprintf(s + ret, size - ret, "%11.11s", bf);
830 931
831 if (show_displacement) { 932 if (show_displacement) {
832 if (displacement) 933 if (displacement)
833 snprintf(bf, sizeof(bf), "%+4ld", displacement); 934 scnprintf(bf, sizeof(bf), "%+4ld", displacement);
834 else 935 else
835 snprintf(bf, sizeof(bf), " "); 936 scnprintf(bf, sizeof(bf), " ");
836 937
837 if (sep) 938 if (sep)
838 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf); 939 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
839 else 940 else
840 ret += snprintf(s + ret, size - ret, "%6.6s", bf); 941 ret += scnprintf(s + ret, size - ret, "%6.6s", bf);
841 } 942 }
842 } 943 }
843 944
@@ -855,7 +956,7 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
855 if (se->elide) 956 if (se->elide)
856 continue; 957 continue;
857 958
858 ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); 959 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " ");
859 ret += se->se_snprintf(he, s + ret, size - ret, 960 ret += se->se_snprintf(he, s + ret, size - ret,
860 hists__col_len(hists, se->se_width_idx)); 961 hists__col_len(hists, se->se_width_idx));
861 } 962 }
@@ -1179,6 +1280,37 @@ void hists__filter_by_thread(struct hists *hists)
1179 } 1280 }
1180} 1281}
1181 1282
1283static bool hists__filter_entry_by_symbol(struct hists *hists,
1284 struct hist_entry *he)
1285{
1286 if (hists->symbol_filter_str != NULL &&
1287 (!he->ms.sym || strstr(he->ms.sym->name,
1288 hists->symbol_filter_str) == NULL)) {
1289 he->filtered |= (1 << HIST_FILTER__SYMBOL);
1290 return true;
1291 }
1292
1293 return false;
1294}
1295
1296void hists__filter_by_symbol(struct hists *hists)
1297{
1298 struct rb_node *nd;
1299
1300 hists->nr_entries = hists->stats.total_period = 0;
1301 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1302 hists__reset_col_len(hists);
1303
1304 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1305 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1306
1307 if (hists__filter_entry_by_symbol(hists, h))
1308 continue;
1309
1310 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL);
1311 }
1312}
1313
1182int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) 1314int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
1183{ 1315{
1184 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); 1316 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index f55f0a8d1f81..2cae9df40e04 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -32,6 +32,7 @@ struct events_stats {
32 u32 nr_unknown_events; 32 u32 nr_unknown_events;
33 u32 nr_invalid_chains; 33 u32 nr_invalid_chains;
34 u32 nr_unknown_id; 34 u32 nr_unknown_id;
35 u32 nr_unprocessable_samples;
35}; 36};
36 37
37enum hist_column { 38enum hist_column {
@@ -41,6 +42,11 @@ enum hist_column {
41 HISTC_COMM, 42 HISTC_COMM,
42 HISTC_PARENT, 43 HISTC_PARENT,
43 HISTC_CPU, 44 HISTC_CPU,
45 HISTC_MISPREDICT,
46 HISTC_SYMBOL_FROM,
47 HISTC_SYMBOL_TO,
48 HISTC_DSO_FROM,
49 HISTC_DSO_TO,
44 HISTC_NR_COLS, /* Last entry */ 50 HISTC_NR_COLS, /* Last entry */
45}; 51};
46 52
@@ -55,6 +61,8 @@ struct hists {
55 u64 nr_entries; 61 u64 nr_entries;
56 const struct thread *thread_filter; 62 const struct thread *thread_filter;
57 const struct dso *dso_filter; 63 const struct dso *dso_filter;
64 const char *uid_filter_str;
65 const char *symbol_filter_str;
58 pthread_mutex_t lock; 66 pthread_mutex_t lock;
59 struct events_stats stats; 67 struct events_stats stats;
60 u64 event_stream; 68 u64 event_stream;
@@ -72,6 +80,12 @@ int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
72 struct hists *hists); 80 struct hists *hists);
73void hist_entry__free(struct hist_entry *); 81void hist_entry__free(struct hist_entry *);
74 82
83struct hist_entry *__hists__add_branch_entry(struct hists *self,
84 struct addr_location *al,
85 struct symbol *sym_parent,
86 struct branch_info *bi,
87 u64 period);
88
75void hists__output_resort(struct hists *self); 89void hists__output_resort(struct hists *self);
76void hists__output_resort_threaded(struct hists *hists); 90void hists__output_resort_threaded(struct hists *hists);
77void hists__collapse_resort(struct hists *self); 91void hists__collapse_resort(struct hists *self);
@@ -94,6 +108,7 @@ int hist_entry__annotate(struct hist_entry *self, size_t privsize);
94 108
95void hists__filter_by_dso(struct hists *hists); 109void hists__filter_by_dso(struct hists *hists);
96void hists__filter_by_thread(struct hists *hists); 110void hists__filter_by_thread(struct hists *hists);
111void hists__filter_by_symbol(struct hists *hists);
97 112
98u16 hists__col_len(struct hists *self, enum hist_column col); 113u16 hists__col_len(struct hists *self, enum hist_column col);
99void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 114void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
@@ -132,6 +147,23 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
132 int refresh); 147 int refresh);
133#endif 148#endif
134 149
150#ifdef NO_GTK2_SUPPORT
151static inline
152int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __used,
153 const char *help __used,
154 void(*timer)(void *arg) __used,
155 void *arg __used,
156 int refresh __used)
157{
158 return 0;
159}
160
161#else
162int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
163 void(*timer)(void *arg), void *arg,
164 int refresh);
165#endif
166
135unsigned int hists__sort_list_width(struct hists *self); 167unsigned int hists__sort_list_width(struct hists *self);
136 168
137#endif /* __PERF_HIST_H */ 169#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/dwarf2.h b/tools/perf/util/include/asm/dwarf2.h
index bb4198e7837a..afe38199e922 100644
--- a/tools/perf/util/include/asm/dwarf2.h
+++ b/tools/perf/util/include/asm/dwarf2.h
@@ -2,10 +2,12 @@
2#ifndef PERF_DWARF2_H 2#ifndef PERF_DWARF2_H
3#define PERF_DWARF2_H 3#define PERF_DWARF2_H
4 4
5/* dwarf2.h ... dummy header file for including arch/x86/lib/memcpy_64.S */ 5/* dwarf2.h ... dummy header file for including arch/x86/lib/mem{cpy,set}_64.S */
6 6
7#define CFI_STARTPROC 7#define CFI_STARTPROC
8#define CFI_ENDPROC 8#define CFI_ENDPROC
9#define CFI_REMEMBER_STATE
10#define CFI_RESTORE_STATE
9 11
10#endif /* PERF_DWARF2_H */ 12#endif /* PERF_DWARF2_H */
11 13
diff --git a/tools/perf/util/include/asm/unistd_32.h b/tools/perf/util/include/asm/unistd_32.h
new file mode 100644
index 000000000000..8b137891791f
--- /dev/null
+++ b/tools/perf/util/include/asm/unistd_32.h
@@ -0,0 +1 @@
diff --git a/tools/perf/util/include/asm/unistd_64.h b/tools/perf/util/include/asm/unistd_64.h
new file mode 100644
index 000000000000..8b137891791f
--- /dev/null
+++ b/tools/perf/util/include/asm/unistd_64.h
@@ -0,0 +1 @@
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index eda4416efa0a..bb162e40c76c 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -5,6 +5,8 @@
5#include <linux/bitops.h> 5#include <linux/bitops.h>
6 6
7int __bitmap_weight(const unsigned long *bitmap, int bits); 7int __bitmap_weight(const unsigned long *bitmap, int bits);
8void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
9 const unsigned long *bitmap2, int bits);
8 10
9#define BITMAP_LAST_WORD_MASK(nbits) \ 11#define BITMAP_LAST_WORD_MASK(nbits) \
10( \ 12( \
@@ -32,4 +34,13 @@ static inline int bitmap_weight(const unsigned long *src, int nbits)
32 return __bitmap_weight(src, nbits); 34 return __bitmap_weight(src, nbits);
33} 35}
34 36
37static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
38 const unsigned long *src2, int nbits)
39{
40 if (small_const_nbits(nbits))
41 *dst = *src1 | *src2;
42 else
43 __bitmap_or(dst, src1, src2, nbits);
44}
45
35#endif /* _PERF_BITOPS_H */ 46#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 62cdee78db7b..f1584833bd22 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -15,7 +15,7 @@
15 (bit) = find_next_bit((addr), (size), (bit) + 1)) 15 (bit) = find_next_bit((addr), (size), (bit) + 1))
16 16
17/* same as for_each_set_bit() but use bit as value to start with */ 17/* same as for_each_set_bit() but use bit as value to start with */
18#define for_each_set_bit_cont(bit, addr, size) \ 18#define for_each_set_bit_from(bit, addr, size) \
19 for ((bit) = find_next_bit((addr), (size), (bit)); \ 19 for ((bit) = find_next_bit((addr), (size), (bit)); \
20 (bit) < (size); \ 20 (bit) < (size); \
21 (bit) = find_next_bit((addr), (size), (bit) + 1)) 21 (bit) = find_next_bit((addr), (size), (bit) + 1))
diff --git a/tools/perf/util/include/linux/module.h b/tools/perf/util/include/linux/export.h
index b43e2dc21e04..b43e2dc21e04 100644
--- a/tools/perf/util/include/linux/module.h
+++ b/tools/perf/util/include/linux/export.h
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 316aa0ab7122..dea6d1c1a954 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -212,6 +212,21 @@ size_t map__fprintf(struct map *self, FILE *fp)
212 self->start, self->end, self->pgoff, self->dso->name); 212 self->start, self->end, self->pgoff, self->dso->name);
213} 213}
214 214
215size_t map__fprintf_dsoname(struct map *map, FILE *fp)
216{
217 const char *dsoname;
218
219 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
220 if (symbol_conf.show_kernel_path && map->dso->long_name)
221 dsoname = map->dso->long_name;
222 else if (map->dso->name)
223 dsoname = map->dso->name;
224 } else
225 dsoname = "[unknown]";
226
227 return fprintf(fp, "%s", dsoname);
228}
229
215/* 230/*
216 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 231 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
217 * map->dso->adjust_symbols==1 for ET_EXEC-like cases. 232 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 2b8017f8a930..b100c20b7f94 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -118,6 +118,7 @@ void map__delete(struct map *self);
118struct map *map__clone(struct map *self); 118struct map *map__clone(struct map *self);
119int map__overlap(struct map *l, struct map *r); 119int map__overlap(struct map *l, struct map *r);
120size_t map__fprintf(struct map *self, FILE *fp); 120size_t map__fprintf(struct map *self, FILE *fp);
121size_t map__fprintf_dsoname(struct map *map, FILE *fp);
121 122
122int map__load(struct map *self, symbol_filter_t filter); 123int map__load(struct map *self, symbol_filter_t filter);
123struct symbol *map__find_symbol(struct map *self, 124struct symbol *map__find_symbol(struct map *self,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b029296d20d9..5b3a0ef4e232 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,10 @@
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
13#include "debugfs.h" 13#include "debugfs.h"
14#include "parse-events-flex.h"
15#include "pmu.h"
16
17#define MAX_NAME_LEN 100
14 18
15struct event_symbol { 19struct event_symbol {
16 u8 type; 20 u8 type;
@@ -19,11 +23,8 @@ struct event_symbol {
19 const char *alias; 23 const char *alias;
20}; 24};
21 25
22enum event_result { 26int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
23 EVT_FAILED, 27 int *idx);
24 EVT_HANDLED,
25 EVT_HANDLED_ALL
26};
27 28
28#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 29#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
29#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 30#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -165,7 +166,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
165 struct tracepoint_path *path = NULL; 166 struct tracepoint_path *path = NULL;
166 DIR *sys_dir, *evt_dir; 167 DIR *sys_dir, *evt_dir;
167 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 168 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
168 char id_buf[4]; 169 char id_buf[24];
169 int fd; 170 int fd;
170 u64 id; 171 u64 id;
171 char evt_path[MAXPATHLEN]; 172 char evt_path[MAXPATHLEN];
@@ -354,7 +355,24 @@ const char *__event_name(int type, u64 config)
354 return "unknown"; 355 return "unknown";
355} 356}
356 357
357static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size) 358static int add_event(struct list_head *list, int *idx,
359 struct perf_event_attr *attr, char *name)
360{
361 struct perf_evsel *evsel;
362
363 event_attr_init(attr);
364
365 evsel = perf_evsel__new(attr, (*idx)++);
366 if (!evsel)
367 return -ENOMEM;
368
369 list_add_tail(&evsel->node, list);
370
371 evsel->name = strdup(name);
372 return 0;
373}
374
375static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
358{ 376{
359 int i, j; 377 int i, j;
360 int n, longest = -1; 378 int n, longest = -1;
@@ -362,58 +380,57 @@ static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int
362 for (i = 0; i < size; i++) { 380 for (i = 0; i < size; i++) {
363 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { 381 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
364 n = strlen(names[i][j]); 382 n = strlen(names[i][j]);
365 if (n > longest && !strncasecmp(*str, names[i][j], n)) 383 if (n > longest && !strncasecmp(str, names[i][j], n))
366 longest = n; 384 longest = n;
367 } 385 }
368 if (longest > 0) { 386 if (longest > 0)
369 *str += longest;
370 return i; 387 return i;
371 }
372 } 388 }
373 389
374 return -1; 390 return -1;
375} 391}
376 392
377static enum event_result 393int parse_events_add_cache(struct list_head *list, int *idx,
378parse_generic_hw_event(const char **str, struct perf_event_attr *attr) 394 char *type, char *op_result1, char *op_result2)
379{ 395{
380 const char *s = *str; 396 struct perf_event_attr attr;
397 char name[MAX_NAME_LEN];
381 int cache_type = -1, cache_op = -1, cache_result = -1; 398 int cache_type = -1, cache_op = -1, cache_result = -1;
399 char *op_result[2] = { op_result1, op_result2 };
400 int i, n;
382 401
383 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
384 /* 402 /*
385 * No fallback - if we cannot get a clear cache type 403 * No fallback - if we cannot get a clear cache type
386 * then bail out: 404 * then bail out:
387 */ 405 */
406 cache_type = parse_aliases(type, hw_cache,
407 PERF_COUNT_HW_CACHE_MAX);
388 if (cache_type == -1) 408 if (cache_type == -1)
389 return EVT_FAILED; 409 return -EINVAL;
410
411 n = snprintf(name, MAX_NAME_LEN, "%s", type);
412
413 for (i = 0; (i < 2) && (op_result[i]); i++) {
414 char *str = op_result[i];
390 415
391 while ((cache_op == -1 || cache_result == -1) && *s == '-') { 416 snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
392 ++s;
393 417
394 if (cache_op == -1) { 418 if (cache_op == -1) {
395 cache_op = parse_aliases(&s, hw_cache_op, 419 cache_op = parse_aliases(str, hw_cache_op,
396 PERF_COUNT_HW_CACHE_OP_MAX); 420 PERF_COUNT_HW_CACHE_OP_MAX);
397 if (cache_op >= 0) { 421 if (cache_op >= 0) {
398 if (!is_cache_op_valid(cache_type, cache_op)) 422 if (!is_cache_op_valid(cache_type, cache_op))
399 return EVT_FAILED; 423 return -EINVAL;
400 continue; 424 continue;
401 } 425 }
402 } 426 }
403 427
404 if (cache_result == -1) { 428 if (cache_result == -1) {
405 cache_result = parse_aliases(&s, hw_cache_result, 429 cache_result = parse_aliases(str, hw_cache_result,
406 PERF_COUNT_HW_CACHE_RESULT_MAX); 430 PERF_COUNT_HW_CACHE_RESULT_MAX);
407 if (cache_result >= 0) 431 if (cache_result >= 0)
408 continue; 432 continue;
409 } 433 }
410
411 /*
412 * Can't parse this as a cache op or result, so back up
413 * to the '-'.
414 */
415 --s;
416 break;
417 } 434 }
418 435
419 /* 436 /*
@@ -428,20 +445,17 @@ parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
428 if (cache_result == -1) 445 if (cache_result == -1)
429 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; 446 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
430 447
431 attr->config = cache_type | (cache_op << 8) | (cache_result << 16); 448 memset(&attr, 0, sizeof(attr));
432 attr->type = PERF_TYPE_HW_CACHE; 449 attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
433 450 attr.type = PERF_TYPE_HW_CACHE;
434 *str = s; 451 return add_event(list, idx, &attr, name);
435 return EVT_HANDLED;
436} 452}
437 453
438static enum event_result 454static int add_tracepoint(struct list_head *list, int *idx,
439parse_single_tracepoint_event(char *sys_name, 455 char *sys_name, char *evt_name)
440 const char *evt_name,
441 unsigned int evt_length,
442 struct perf_event_attr *attr,
443 const char **strp)
444{ 456{
457 struct perf_event_attr attr;
458 char name[MAX_NAME_LEN];
445 char evt_path[MAXPATHLEN]; 459 char evt_path[MAXPATHLEN];
446 char id_buf[4]; 460 char id_buf[4];
447 u64 id; 461 u64 id;
@@ -452,130 +466,80 @@ parse_single_tracepoint_event(char *sys_name,
452 466
453 fd = open(evt_path, O_RDONLY); 467 fd = open(evt_path, O_RDONLY);
454 if (fd < 0) 468 if (fd < 0)
455 return EVT_FAILED; 469 return -1;
456 470
457 if (read(fd, id_buf, sizeof(id_buf)) < 0) { 471 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
458 close(fd); 472 close(fd);
459 return EVT_FAILED; 473 return -1;
460 } 474 }
461 475
462 close(fd); 476 close(fd);
463 id = atoll(id_buf); 477 id = atoll(id_buf);
464 attr->config = id;
465 attr->type = PERF_TYPE_TRACEPOINT;
466 *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
467
468 attr->sample_type |= PERF_SAMPLE_RAW;
469 attr->sample_type |= PERF_SAMPLE_TIME;
470 attr->sample_type |= PERF_SAMPLE_CPU;
471 478
472 attr->sample_period = 1; 479 memset(&attr, 0, sizeof(attr));
480 attr.config = id;
481 attr.type = PERF_TYPE_TRACEPOINT;
482 attr.sample_type |= PERF_SAMPLE_RAW;
483 attr.sample_type |= PERF_SAMPLE_TIME;
484 attr.sample_type |= PERF_SAMPLE_CPU;
485 attr.sample_period = 1;
473 486
474 487 snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
475 return EVT_HANDLED; 488 return add_event(list, idx, &attr, name);
476} 489}
477 490
478/* sys + ':' + event + ':' + flags*/ 491static int add_tracepoint_multi(struct list_head *list, int *idx,
479#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 492 char *sys_name, char *evt_name)
480static enum event_result
481parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
482 const char *evt_exp, char *flags)
483{ 493{
484 char evt_path[MAXPATHLEN]; 494 char evt_path[MAXPATHLEN];
485 struct dirent *evt_ent; 495 struct dirent *evt_ent;
486 DIR *evt_dir; 496 DIR *evt_dir;
497 int ret = 0;
487 498
488 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); 499 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
489 evt_dir = opendir(evt_path); 500 evt_dir = opendir(evt_path);
490
491 if (!evt_dir) { 501 if (!evt_dir) {
492 perror("Can't open event dir"); 502 perror("Can't open event dir");
493 return EVT_FAILED; 503 return -1;
494 } 504 }
495 505
496 while ((evt_ent = readdir(evt_dir))) { 506 while (!ret && (evt_ent = readdir(evt_dir))) {
497 char event_opt[MAX_EVOPT_LEN + 1];
498 int len;
499
500 if (!strcmp(evt_ent->d_name, ".") 507 if (!strcmp(evt_ent->d_name, ".")
501 || !strcmp(evt_ent->d_name, "..") 508 || !strcmp(evt_ent->d_name, "..")
502 || !strcmp(evt_ent->d_name, "enable") 509 || !strcmp(evt_ent->d_name, "enable")
503 || !strcmp(evt_ent->d_name, "filter")) 510 || !strcmp(evt_ent->d_name, "filter"))
504 continue; 511 continue;
505 512
506 if (!strglobmatch(evt_ent->d_name, evt_exp)) 513 if (!strglobmatch(evt_ent->d_name, evt_name))
507 continue; 514 continue;
508 515
509 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 516 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
510 evt_ent->d_name, flags ? ":" : "",
511 flags ?: "");
512 if (len < 0)
513 return EVT_FAILED;
514
515 if (parse_events(evlist, event_opt, 0))
516 return EVT_FAILED;
517 } 517 }
518 518
519 return EVT_HANDLED_ALL; 519 return ret;
520} 520}
521 521
522static enum event_result 522int parse_events_add_tracepoint(struct list_head *list, int *idx,
523parse_tracepoint_event(struct perf_evlist *evlist, const char **strp, 523 char *sys, char *event)
524 struct perf_event_attr *attr)
525{ 524{
526 const char *evt_name; 525 int ret;
527 char *flags = NULL, *comma_loc;
528 char sys_name[MAX_EVENT_LENGTH];
529 unsigned int sys_length, evt_length;
530
531 if (debugfs_valid_mountpoint(tracing_events_path))
532 return 0;
533
534 evt_name = strchr(*strp, ':');
535 if (!evt_name)
536 return EVT_FAILED;
537
538 sys_length = evt_name - *strp;
539 if (sys_length >= MAX_EVENT_LENGTH)
540 return 0;
541 526
542 strncpy(sys_name, *strp, sys_length); 527 ret = debugfs_valid_mountpoint(tracing_events_path);
543 sys_name[sys_length] = '\0'; 528 if (ret)
544 evt_name = evt_name + 1; 529 return ret;
545 530
546 comma_loc = strchr(evt_name, ','); 531 return strpbrk(event, "*?") ?
547 if (comma_loc) { 532 add_tracepoint_multi(list, idx, sys, event) :
548 /* take the event name up to the comma */ 533 add_tracepoint(list, idx, sys, event);
549 evt_name = strndup(evt_name, comma_loc - evt_name);
550 }
551 flags = strchr(evt_name, ':');
552 if (flags) {
553 /* split it out: */
554 evt_name = strndup(evt_name, flags - evt_name);
555 flags++;
556 }
557
558 evt_length = strlen(evt_name);
559 if (evt_length >= MAX_EVENT_LENGTH)
560 return EVT_FAILED;
561 if (strpbrk(evt_name, "*?")) {
562 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
563 return parse_multiple_tracepoint_event(evlist, sys_name,
564 evt_name, flags);
565 } else {
566 return parse_single_tracepoint_event(sys_name, evt_name,
567 evt_length, attr, strp);
568 }
569} 534}
570 535
571static enum event_result 536static int
572parse_breakpoint_type(const char *type, const char **strp, 537parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
573 struct perf_event_attr *attr)
574{ 538{
575 int i; 539 int i;
576 540
577 for (i = 0; i < 3; i++) { 541 for (i = 0; i < 3; i++) {
578 if (!type[i]) 542 if (!type || !type[i])
579 break; 543 break;
580 544
581 switch (type[i]) { 545 switch (type[i]) {
@@ -589,164 +553,146 @@ parse_breakpoint_type(const char *type, const char **strp,
589 attr->bp_type |= HW_BREAKPOINT_X; 553 attr->bp_type |= HW_BREAKPOINT_X;
590 break; 554 break;
591 default: 555 default:
592 return EVT_FAILED; 556 return -EINVAL;
593 } 557 }
594 } 558 }
559
595 if (!attr->bp_type) /* Default */ 560 if (!attr->bp_type) /* Default */
596 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; 561 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
597 562
598 *strp = type + i; 563 return 0;
599
600 return EVT_HANDLED;
601} 564}
602 565
603static enum event_result 566int parse_events_add_breakpoint(struct list_head *list, int *idx,
604parse_breakpoint_event(const char **strp, struct perf_event_attr *attr) 567 void *ptr, char *type)
605{ 568{
606 const char *target; 569 struct perf_event_attr attr;
607 const char *type; 570 char name[MAX_NAME_LEN];
608 char *endaddr;
609 u64 addr;
610 enum event_result err;
611
612 target = strchr(*strp, ':');
613 if (!target)
614 return EVT_FAILED;
615
616 if (strncmp(*strp, "mem", target - *strp) != 0)
617 return EVT_FAILED;
618
619 target++;
620
621 addr = strtoull(target, &endaddr, 0);
622 if (target == endaddr)
623 return EVT_FAILED;
624
625 attr->bp_addr = addr;
626 *strp = endaddr;
627 571
628 type = strchr(target, ':'); 572 memset(&attr, 0, sizeof(attr));
573 attr.bp_addr = (unsigned long) ptr;
629 574
630 /* If no type is defined, just rw as default */ 575 if (parse_breakpoint_type(type, &attr))
631 if (!type) { 576 return -EINVAL;
632 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
633 } else {
634 err = parse_breakpoint_type(++type, strp, attr);
635 if (err == EVT_FAILED)
636 return EVT_FAILED;
637 }
638 577
639 /* 578 /*
640 * We should find a nice way to override the access length 579 * We should find a nice way to override the access length
641 * Provide some defaults for now 580 * Provide some defaults for now
642 */ 581 */
643 if (attr->bp_type == HW_BREAKPOINT_X) 582 if (attr.bp_type == HW_BREAKPOINT_X)
644 attr->bp_len = sizeof(long); 583 attr.bp_len = sizeof(long);
645 else 584 else
646 attr->bp_len = HW_BREAKPOINT_LEN_4; 585 attr.bp_len = HW_BREAKPOINT_LEN_4;
647 586
648 attr->type = PERF_TYPE_BREAKPOINT; 587 attr.type = PERF_TYPE_BREAKPOINT;
649 588
650 return EVT_HANDLED; 589 snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
590 return add_event(list, idx, &attr, name);
651} 591}
652 592
653static int check_events(const char *str, unsigned int i) 593static int config_term(struct perf_event_attr *attr,
594 struct parse_events__term *term)
654{ 595{
655 int n; 596 switch (term->type) {
597 case PARSE_EVENTS__TERM_TYPE_CONFIG:
598 attr->config = term->val.num;
599 break;
600 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
601 attr->config1 = term->val.num;
602 break;
603 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
604 attr->config2 = term->val.num;
605 break;
606 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
607 attr->sample_period = term->val.num;
608 break;
609 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
610 /*
611 * TODO uncomment when the field is available
612 * attr->branch_sample_type = term->val.num;
613 */
614 break;
615 default:
616 return -EINVAL;
617 }
618 return 0;
619}
656 620
657 n = strlen(event_symbols[i].symbol); 621static int config_attr(struct perf_event_attr *attr,
658 if (!strncasecmp(str, event_symbols[i].symbol, n)) 622 struct list_head *head, int fail)
659 return n; 623{
624 struct parse_events__term *term;
660 625
661 n = strlen(event_symbols[i].alias); 626 list_for_each_entry(term, head, list)
662 if (n) { 627 if (config_term(attr, term) && fail)
663 if (!strncasecmp(str, event_symbols[i].alias, n)) 628 return -EINVAL;
664 return n;
665 }
666 629
667 return 0; 630 return 0;
668} 631}
669 632
670static enum event_result 633int parse_events_add_numeric(struct list_head *list, int *idx,
671parse_symbolic_event(const char **strp, struct perf_event_attr *attr) 634 unsigned long type, unsigned long config,
635 struct list_head *head_config)
672{ 636{
673 const char *str = *strp; 637 struct perf_event_attr attr;
674 unsigned int i; 638
675 int n; 639 memset(&attr, 0, sizeof(attr));
676 640 attr.type = type;
677 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { 641 attr.config = config;
678 n = check_events(str, i); 642
679 if (n > 0) { 643 if (head_config &&
680 attr->type = event_symbols[i].type; 644 config_attr(&attr, head_config, 1))
681 attr->config = event_symbols[i].config; 645 return -EINVAL;
682 *strp = str + n; 646
683 return EVT_HANDLED; 647 return add_event(list, idx, &attr,
684 } 648 (char *) __event_name(type, config));
685 }
686 return EVT_FAILED;
687} 649}
688 650
689static enum event_result 651int parse_events_add_pmu(struct list_head *list, int *idx,
690parse_raw_event(const char **strp, struct perf_event_attr *attr) 652 char *name, struct list_head *head_config)
691{ 653{
692 const char *str = *strp; 654 struct perf_event_attr attr;
693 u64 config; 655 struct perf_pmu *pmu;
694 int n; 656
695 657 pmu = perf_pmu__find(name);
696 if (*str != 'r') 658 if (!pmu)
697 return EVT_FAILED; 659 return -EINVAL;
698 n = hex2u64(str + 1, &config); 660
699 if (n > 0) { 661 memset(&attr, 0, sizeof(attr));
700 const char *end = str + n + 1; 662
701 if (*end != '\0' && *end != ',' && *end != ':') 663 /*
702 return EVT_FAILED; 664 * Configure hardcoded terms first, no need to check
703 665 * return value when called with fail == 0 ;)
704 *strp = end; 666 */
705 attr->type = PERF_TYPE_RAW; 667 config_attr(&attr, head_config, 0);
706 attr->config = config; 668
707 return EVT_HANDLED; 669 if (perf_pmu__config(pmu, &attr, head_config))
708 } 670 return -EINVAL;
709 return EVT_FAILED; 671
672 return add_event(list, idx, &attr, (char *) "pmu");
710} 673}
711 674
712static enum event_result 675void parse_events_update_lists(struct list_head *list_event,
713parse_numeric_event(const char **strp, struct perf_event_attr *attr) 676 struct list_head *list_all)
714{ 677{
715 const char *str = *strp; 678 /*
716 char *endp; 679 * Called for single event definition. Update the
717 unsigned long type; 680 * 'all event' list, and reinit the 'signle event'
718 u64 config; 681 * list, for next event definition.
719 682 */
720 type = strtoul(str, &endp, 0); 683 list_splice_tail(list_event, list_all);
721 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') { 684 INIT_LIST_HEAD(list_event);
722 str = endp + 1;
723 config = strtoul(str, &endp, 0);
724 if (endp > str) {
725 attr->type = type;
726 attr->config = config;
727 *strp = endp;
728 return EVT_HANDLED;
729 }
730 }
731 return EVT_FAILED;
732} 685}
733 686
734static int 687int parse_events_modifier(struct list_head *list, char *str)
735parse_event_modifier(const char **strp, struct perf_event_attr *attr)
736{ 688{
737 const char *str = *strp; 689 struct perf_evsel *evsel;
738 int exclude = 0, exclude_GH = 0; 690 int exclude = 0, exclude_GH = 0;
739 int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0; 691 int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
740 692
741 if (!*str) 693 if (str == NULL)
742 return 0; 694 return 0;
743 695
744 if (*str == ',')
745 return 0;
746
747 if (*str++ != ':')
748 return -1;
749
750 while (*str) { 696 while (*str) {
751 if (*str == 'u') { 697 if (*str == 'u') {
752 if (!exclude) 698 if (!exclude)
@@ -775,111 +721,62 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
775 721
776 ++str; 722 ++str;
777 } 723 }
778 if (str < *strp + 2)
779 return -1;
780 724
781 *strp = str; 725 /*
726 * precise ip:
727 *
728 * 0 - SAMPLE_IP can have arbitrary skid
729 * 1 - SAMPLE_IP must have constant skid
730 * 2 - SAMPLE_IP requested to have 0 skid
731 * 3 - SAMPLE_IP must have 0 skid
732 *
733 * See also PERF_RECORD_MISC_EXACT_IP
734 */
735 if (precise > 3)
736 return -EINVAL;
782 737
783 attr->exclude_user = eu; 738 list_for_each_entry(evsel, list, node) {
784 attr->exclude_kernel = ek; 739 evsel->attr.exclude_user = eu;
785 attr->exclude_hv = eh; 740 evsel->attr.exclude_kernel = ek;
786 attr->precise_ip = precise; 741 evsel->attr.exclude_hv = eh;
787 attr->exclude_host = eH; 742 evsel->attr.precise_ip = precise;
788 attr->exclude_guest = eG; 743 evsel->attr.exclude_host = eH;
744 evsel->attr.exclude_guest = eG;
745 }
789 746
790 return 0; 747 return 0;
791} 748}
792 749
793/* 750int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
794 * Each event can have multiple symbolic names.
795 * Symbolic names are (almost) exactly matched.
796 */
797static enum event_result
798parse_event_symbols(struct perf_evlist *evlist, const char **str,
799 struct perf_event_attr *attr)
800{ 751{
801 enum event_result ret; 752 LIST_HEAD(list);
802 753 LIST_HEAD(list_tmp);
803 ret = parse_tracepoint_event(evlist, str, attr); 754 YY_BUFFER_STATE buffer;
804 if (ret != EVT_FAILED) 755 int ret, idx = evlist->nr_entries;
805 goto modifier;
806
807 ret = parse_raw_event(str, attr);
808 if (ret != EVT_FAILED)
809 goto modifier;
810 756
811 ret = parse_numeric_event(str, attr); 757 buffer = parse_events__scan_string(str);
812 if (ret != EVT_FAILED)
813 goto modifier;
814 758
815 ret = parse_symbolic_event(str, attr); 759 ret = parse_events_parse(&list, &list_tmp, &idx);
816 if (ret != EVT_FAILED)
817 goto modifier;
818 760
819 ret = parse_generic_hw_event(str, attr); 761 parse_events__flush_buffer(buffer);
820 if (ret != EVT_FAILED) 762 parse_events__delete_buffer(buffer);
821 goto modifier;
822 763
823 ret = parse_breakpoint_event(str, attr); 764 if (!ret) {
824 if (ret != EVT_FAILED) 765 int entries = idx - evlist->nr_entries;
825 goto modifier; 766 perf_evlist__splice_list_tail(evlist, &list, entries);
826 767 return 0;
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 EVT_FAILED;
830
831modifier:
832 if (parse_event_modifier(str, attr) < 0) {
833 fprintf(stderr, "invalid event modifier: '%s'\n", *str);
834 fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
835
836 return EVT_FAILED;
837 } 768 }
838 769
770 /*
771 * There are 2 users - builtin-record and builtin-test objects.
772 * Both call perf_evlist__delete in case of error, so we dont
773 * need to bother.
774 */
775 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
776 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
839 return ret; 777 return ret;
840} 778}
841 779
842int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
843{
844 struct perf_event_attr attr;
845 enum event_result ret;
846 const char *ostr;
847
848 for (;;) {
849 ostr = str;
850 memset(&attr, 0, sizeof(attr));
851 event_attr_init(&attr);
852 ret = parse_event_symbols(evlist, &str, &attr);
853 if (ret == EVT_FAILED)
854 return -1;
855
856 if (!(*str == 0 || *str == ',' || isspace(*str)))
857 return -1;
858
859 if (ret != EVT_HANDLED_ALL) {
860 struct perf_evsel *evsel;
861 evsel = perf_evsel__new(&attr, evlist->nr_entries);
862 if (evsel == NULL)
863 return -1;
864 perf_evlist__add(evlist, evsel);
865
866 evsel->name = calloc(str - ostr + 1, 1);
867 if (!evsel->name)
868 return -1;
869 strncpy(evsel->name, ostr, str - ostr);
870 }
871
872 if (*str == 0)
873 break;
874 if (*str == ',')
875 ++str;
876 while (isspace(*str))
877 ++str;
878 }
879
880 return 0;
881}
882
883int parse_events_option(const struct option *opt, const char *str, 780int parse_events_option(const struct option *opt, const char *str,
884 int unset __used) 781 int unset __used)
885{ 782{
@@ -1052,8 +949,6 @@ int print_hwcache_events(const char *event_glob)
1052 return printed; 949 return printed;
1053} 950}
1054 951
1055#define MAX_NAME_LEN 100
1056
1057/* 952/*
1058 * Print the help text for the event symbols: 953 * Print the help text for the event symbols:
1059 */ 954 */
@@ -1102,8 +997,12 @@ void print_events(const char *event_glob)
1102 997
1103 printf("\n"); 998 printf("\n");
1104 printf(" %-50s [%s]\n", 999 printf(" %-50s [%s]\n",
1105 "rNNN (see 'perf list --help' on how to encode it)", 1000 "rNNN",
1106 event_type_descriptors[PERF_TYPE_RAW]); 1001 event_type_descriptors[PERF_TYPE_RAW]);
1002 printf(" %-50s [%s]\n",
1003 "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
1004 event_type_descriptors[PERF_TYPE_RAW]);
1005 printf(" (see 'perf list --help' on how to encode it)\n");
1107 printf("\n"); 1006 printf("\n");
1108 1007
1109 printf(" %-50s [%s]\n", 1008 printf(" %-50s [%s]\n",
@@ -1113,3 +1012,51 @@ void print_events(const char *event_glob)
1113 1012
1114 print_tracepoint_events(NULL, NULL); 1013 print_tracepoint_events(NULL, NULL);
1115} 1014}
1015
1016int parse_events__is_hardcoded_term(struct parse_events__term *term)
1017{
1018 return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
1019}
1020
1021int parse_events__new_term(struct parse_events__term **_term, int type,
1022 char *config, char *str, long num)
1023{
1024 struct parse_events__term *term;
1025
1026 term = zalloc(sizeof(*term));
1027 if (!term)
1028 return -ENOMEM;
1029
1030 INIT_LIST_HEAD(&term->list);
1031 term->type = type;
1032 term->config = config;
1033
1034 switch (type) {
1035 case PARSE_EVENTS__TERM_TYPE_CONFIG:
1036 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
1037 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
1038 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
1039 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
1040 case PARSE_EVENTS__TERM_TYPE_NUM:
1041 term->val.num = num;
1042 break;
1043 case PARSE_EVENTS__TERM_TYPE_STR:
1044 term->val.str = str;
1045 break;
1046 default:
1047 return -EINVAL;
1048 }
1049
1050 *_term = term;
1051 return 0;
1052}
1053
1054void parse_events__free_terms(struct list_head *terms)
1055{
1056 struct parse_events__term *term, *h;
1057
1058 list_for_each_entry_safe(term, h, terms, list)
1059 free(term);
1060
1061 free(terms);
1062}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 7e0cbe75d5f1..ca069f893381 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -33,6 +33,55 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
33 33
34#define EVENTS_HELP_MAX (128*1024) 34#define EVENTS_HELP_MAX (128*1024)
35 35
36enum {
37 PARSE_EVENTS__TERM_TYPE_CONFIG,
38 PARSE_EVENTS__TERM_TYPE_CONFIG1,
39 PARSE_EVENTS__TERM_TYPE_CONFIG2,
40 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
41 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
42 PARSE_EVENTS__TERM_TYPE_NUM,
43 PARSE_EVENTS__TERM_TYPE_STR,
44
45 PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
46 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
47};
48
49struct parse_events__term {
50 char *config;
51 union {
52 char *str;
53 long num;
54 } val;
55 int type;
56
57 struct list_head list;
58};
59
60int parse_events__is_hardcoded_term(struct parse_events__term *term);
61int parse_events__new_term(struct parse_events__term **term, int type,
62 char *config, char *str, long num);
63void parse_events__free_terms(struct list_head *terms);
64int parse_events_modifier(struct list_head *list __used, char *str __used);
65int parse_events_add_tracepoint(struct list_head *list, int *idx,
66 char *sys, char *event);
67int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
68 unsigned long config1, unsigned long config2,
69 char *mod);
70int parse_events_add_numeric(struct list_head *list, int *idx,
71 unsigned long type, unsigned long config,
72 struct list_head *head_config);
73int parse_events_add_cache(struct list_head *list, int *idx,
74 char *type, char *op_result1, char *op_result2);
75int parse_events_add_breakpoint(struct list_head *list, int *idx,
76 void *ptr, char *type);
77int parse_events_add_pmu(struct list_head *list, int *idx,
78 char *pmu , struct list_head *head_config);
79void parse_events_update_lists(struct list_head *list_event,
80 struct list_head *list_all);
81void parse_events_error(struct list_head *list_all,
82 struct list_head *list_event,
83 int *idx, char const *msg);
84
36void print_events(const char *event_glob); 85void print_events(const char *event_glob);
37void print_events_type(u8 type); 86void print_events_type(u8 type);
38void print_tracepoint_events(const char *subsys_glob, const char *event_glob); 87void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
new file mode 100644
index 000000000000..05d766e3ecb5
--- /dev/null
+++ b/tools/perf/util/parse-events.l
@@ -0,0 +1,127 @@
1
2%option prefix="parse_events_"
3
4%{
5#include <errno.h>
6#include "../perf.h"
7#include "parse-events-bison.h"
8#include "parse-events.h"
9
10static int __value(char *str, int base, int token)
11{
12 long num;
13
14 errno = 0;
15 num = strtoul(str, NULL, base);
16 if (errno)
17 return PE_ERROR;
18
19 parse_events_lval.num = num;
20 return token;
21}
22
23static int value(int base)
24{
25 return __value(parse_events_text, base, PE_VALUE);
26}
27
28static int raw(void)
29{
30 return __value(parse_events_text + 1, 16, PE_RAW);
31}
32
33static int str(int token)
34{
35 parse_events_lval.str = strdup(parse_events_text);
36 return token;
37}
38
39static int sym(int type, int config)
40{
41 parse_events_lval.num = (type << 16) + config;
42 return PE_VALUE_SYM;
43}
44
45static int term(int type)
46{
47 parse_events_lval.num = type;
48 return PE_TERM;
49}
50
51%}
52
53num_dec [0-9]+
54num_hex 0x[a-fA-F0-9]+
55num_raw_hex [a-fA-F0-9]+
56name [a-zA-Z_*?][a-zA-Z0-9_*?]*
57modifier_event [ukhp]{1,5}
58modifier_bp [rwx]
59
60%%
61cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
62stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
63stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
64instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
65cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
66cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
67branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
68branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
69bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
70ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
71cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
72task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
73page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
74minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
75major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
76context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
77cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
78alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
79emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
80
81L1-dcache|l1-d|l1d|L1-data |
82L1-icache|l1-i|l1i|L1-instruction |
83LLC|L2 |
84dTLB|d-tlb|Data-TLB |
85iTLB|i-tlb|Instruction-TLB |
86branch|branches|bpu|btb|bpc |
87node { return str(PE_NAME_CACHE_TYPE); }
88
89load|loads|read |
90store|stores|write |
91prefetch|prefetches |
92speculative-read|speculative-load |
93refs|Reference|ops|access |
94misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
95
96 /*
97 * These are event config hardcoded term names to be specified
98 * within xxx/.../ syntax. So far we dont clash with other names,
99 * so we can put them here directly. In case the we have a conflict
100 * in future, this needs to go into '//' condition block.
101 */
102config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
103config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
104config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
105period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
106branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
107
108mem: { return PE_PREFIX_MEM; }
109r{num_raw_hex} { return raw(); }
110{num_dec} { return value(10); }
111{num_hex} { return value(16); }
112
113{modifier_event} { return str(PE_MODIFIER_EVENT); }
114{modifier_bp} { return str(PE_MODIFIER_BP); }
115{name} { return str(PE_NAME); }
116"/" { return '/'; }
117- { return '-'; }
118, { return ','; }
119: { return ':'; }
120= { return '='; }
121
122%%
123
124int parse_events_wrap(void)
125{
126 return 1;
127}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
new file mode 100644
index 000000000000..d9637da7333c
--- /dev/null
+++ b/tools/perf/util/parse-events.y
@@ -0,0 +1,229 @@
1
2%name-prefix "parse_events_"
3%parse-param {struct list_head *list_all}
4%parse-param {struct list_head *list_event}
5%parse-param {int *idx}
6
7%{
8
9#define YYDEBUG 1
10
11#include <linux/compiler.h>
12#include <linux/list.h>
13#include "types.h"
14#include "util.h"
15#include "parse-events.h"
16
17extern int parse_events_lex (void);
18
19#define ABORT_ON(val) \
20do { \
21 if (val) \
22 YYABORT; \
23} while (0)
24
25%}
26
27%token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
28%token PE_NAME
29%token PE_MODIFIER_EVENT PE_MODIFIER_BP
30%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
31%token PE_PREFIX_MEM PE_PREFIX_RAW
32%token PE_ERROR
33%type <num> PE_VALUE
34%type <num> PE_VALUE_SYM
35%type <num> PE_RAW
36%type <num> PE_TERM
37%type <str> PE_NAME
38%type <str> PE_NAME_CACHE_TYPE
39%type <str> PE_NAME_CACHE_OP_RESULT
40%type <str> PE_MODIFIER_EVENT
41%type <str> PE_MODIFIER_BP
42%type <head> event_config
43%type <term> event_term
44
45%union
46{
47 char *str;
48 unsigned long num;
49 struct list_head *head;
50 struct parse_events__term *term;
51}
52%%
53
54events:
55events ',' event | event
56
57event:
58event_def PE_MODIFIER_EVENT
59{
60 /*
61 * Apply modifier on all events added by single event definition
62 * (there could be more events added for multiple tracepoint
63 * definitions via '*?'.
64 */
65 ABORT_ON(parse_events_modifier(list_event, $2));
66 parse_events_update_lists(list_event, list_all);
67}
68|
69event_def
70{
71 parse_events_update_lists(list_event, list_all);
72}
73
74event_def: event_pmu |
75 event_legacy_symbol |
76 event_legacy_cache sep_dc |
77 event_legacy_mem |
78 event_legacy_tracepoint sep_dc |
79 event_legacy_numeric sep_dc |
80 event_legacy_raw sep_dc
81
82event_pmu:
83PE_NAME '/' event_config '/'
84{
85 ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
86 parse_events__free_terms($3);
87}
88
89event_legacy_symbol:
90PE_VALUE_SYM '/' event_config '/'
91{
92 int type = $1 >> 16;
93 int config = $1 & 255;
94
95 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
96 parse_events__free_terms($3);
97}
98|
99PE_VALUE_SYM sep_slash_dc
100{
101 int type = $1 >> 16;
102 int config = $1 & 255;
103
104 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
105}
106
107event_legacy_cache:
108PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
109{
110 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
111}
112|
113PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
114{
115 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
116}
117|
118PE_NAME_CACHE_TYPE
119{
120 ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL));
121}
122
123event_legacy_mem:
124PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
125{
126 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
127}
128|
129PE_PREFIX_MEM PE_VALUE sep_dc
130{
131 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
132}
133
134event_legacy_tracepoint:
135PE_NAME ':' PE_NAME
136{
137 ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
138}
139
140event_legacy_numeric:
141PE_VALUE ':' PE_VALUE
142{
143 ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
144}
145
146event_legacy_raw:
147PE_RAW
148{
149 ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
150}
151
152event_config:
153event_config ',' event_term
154{
155 struct list_head *head = $1;
156 struct parse_events__term *term = $3;
157
158 ABORT_ON(!head);
159 list_add_tail(&term->list, head);
160 $$ = $1;
161}
162|
163event_term
164{
165 struct list_head *head = malloc(sizeof(*head));
166 struct parse_events__term *term = $1;
167
168 ABORT_ON(!head);
169 INIT_LIST_HEAD(head);
170 list_add_tail(&term->list, head);
171 $$ = head;
172}
173
174event_term:
175PE_NAME '=' PE_NAME
176{
177 struct parse_events__term *term;
178
179 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
180 $1, $3, 0));
181 $$ = term;
182}
183|
184PE_NAME '=' PE_VALUE
185{
186 struct parse_events__term *term;
187
188 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
189 $1, NULL, $3));
190 $$ = term;
191}
192|
193PE_NAME
194{
195 struct parse_events__term *term;
196
197 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
198 $1, NULL, 1));
199 $$ = term;
200}
201|
202PE_TERM '=' PE_VALUE
203{
204 struct parse_events__term *term;
205
206 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3));
207 $$ = term;
208}
209|
210PE_TERM
211{
212 struct parse_events__term *term;
213
214 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1));
215 $$ = term;
216}
217
218sep_dc: ':' |
219
220sep_slash_dc: '/' | ':' |
221
222%%
223
224void parse_events_error(struct list_head *list_all __used,
225 struct list_head *list_event __used,
226 int *idx __used,
227 char const *msg __used)
228{
229}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
new file mode 100644
index 000000000000..cb08a118e811
--- /dev/null
+++ b/tools/perf/util/pmu.c
@@ -0,0 +1,469 @@
1
2#include <linux/list.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <unistd.h>
6#include <stdio.h>
7#include <dirent.h>
8#include "sysfs.h"
9#include "util.h"
10#include "pmu.h"
11#include "parse-events.h"
12
13int perf_pmu_parse(struct list_head *list, char *name);
14extern FILE *perf_pmu_in;
15
16static LIST_HEAD(pmus);
17
18/*
19 * Parse & process all the sysfs attributes located under
20 * the directory specified in 'dir' parameter.
21 */
22static int pmu_format_parse(char *dir, struct list_head *head)
23{
24 struct dirent *evt_ent;
25 DIR *format_dir;
26 int ret = 0;
27
28 format_dir = opendir(dir);
29 if (!format_dir)
30 return -EINVAL;
31
32 while (!ret && (evt_ent = readdir(format_dir))) {
33 char path[PATH_MAX];
34 char *name = evt_ent->d_name;
35 FILE *file;
36
37 if (!strcmp(name, ".") || !strcmp(name, ".."))
38 continue;
39
40 snprintf(path, PATH_MAX, "%s/%s", dir, name);
41
42 ret = -EINVAL;
43 file = fopen(path, "r");
44 if (!file)
45 break;
46
47 perf_pmu_in = file;
48 ret = perf_pmu_parse(head, name);
49 fclose(file);
50 }
51
52 closedir(format_dir);
53 return ret;
54}
55
56/*
57 * Reading/parsing the default pmu format definition, which should be
58 * located at:
59 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
60 */
61static int pmu_format(char *name, struct list_head *format)
62{
63 struct stat st;
64 char path[PATH_MAX];
65 const char *sysfs;
66
67 sysfs = sysfs_find_mountpoint();
68 if (!sysfs)
69 return -1;
70
71 snprintf(path, PATH_MAX,
72 "%s/bus/event_source/devices/%s/format", sysfs, name);
73
74 if (stat(path, &st) < 0)
75 return -1;
76
77 if (pmu_format_parse(path, format))
78 return -1;
79
80 return 0;
81}
82
83/*
84 * Reading/parsing the default pmu type value, which should be
85 * located at:
86 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
87 */
88static int pmu_type(char *name, __u32 *type)
89{
90 struct stat st;
91 char path[PATH_MAX];
92 const char *sysfs;
93 FILE *file;
94 int ret = 0;
95
96 sysfs = sysfs_find_mountpoint();
97 if (!sysfs)
98 return -1;
99
100 snprintf(path, PATH_MAX,
101 "%s/bus/event_source/devices/%s/type", sysfs, name);
102
103 if (stat(path, &st) < 0)
104 return -1;
105
106 file = fopen(path, "r");
107 if (!file)
108 return -EINVAL;
109
110 if (1 != fscanf(file, "%u", type))
111 ret = -1;
112
113 fclose(file);
114 return ret;
115}
116
117static struct perf_pmu *pmu_lookup(char *name)
118{
119 struct perf_pmu *pmu;
120 LIST_HEAD(format);
121 __u32 type;
122
123 /*
124 * The pmu data we store & need consists of the pmu
125 * type value and format definitions. Load both right
126 * now.
127 */
128 if (pmu_format(name, &format))
129 return NULL;
130
131 if (pmu_type(name, &type))
132 return NULL;
133
134 pmu = zalloc(sizeof(*pmu));
135 if (!pmu)
136 return NULL;
137
138 INIT_LIST_HEAD(&pmu->format);
139 list_splice(&format, &pmu->format);
140 pmu->name = strdup(name);
141 pmu->type = type;
142 return pmu;
143}
144
145static struct perf_pmu *pmu_find(char *name)
146{
147 struct perf_pmu *pmu;
148
149 list_for_each_entry(pmu, &pmus, list)
150 if (!strcmp(pmu->name, name))
151 return pmu;
152
153 return NULL;
154}
155
156struct perf_pmu *perf_pmu__find(char *name)
157{
158 struct perf_pmu *pmu;
159
160 /*
161 * Once PMU is loaded it stays in the list,
162 * so we keep us from multiple reading/parsing
163 * the pmu format definitions.
164 */
165 pmu = pmu_find(name);
166 if (pmu)
167 return pmu;
168
169 return pmu_lookup(name);
170}
171
172static struct perf_pmu__format*
173pmu_find_format(struct list_head *formats, char *name)
174{
175 struct perf_pmu__format *format;
176
177 list_for_each_entry(format, formats, list)
178 if (!strcmp(format->name, name))
179 return format;
180
181 return NULL;
182}
183
184/*
185 * Returns value based on the format definition (format parameter)
186 * and unformated value (value parameter).
187 *
188 * TODO maybe optimize a little ;)
189 */
190static __u64 pmu_format_value(unsigned long *format, __u64 value)
191{
192 unsigned long fbit, vbit;
193 __u64 v = 0;
194
195 for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
196
197 if (!test_bit(fbit, format))
198 continue;
199
200 if (!(value & (1llu << vbit++)))
201 continue;
202
203 v |= (1llu << fbit);
204 }
205
206 return v;
207}
208
209/*
210 * Setup one of config[12] attr members based on the
211 * user input data - temr parameter.
212 */
213static int pmu_config_term(struct list_head *formats,
214 struct perf_event_attr *attr,
215 struct parse_events__term *term)
216{
217 struct perf_pmu__format *format;
218 __u64 *vp;
219
220 /*
221 * Support only for hardcoded and numnerial terms.
222 * Hardcoded terms should be already in, so nothing
223 * to be done for them.
224 */
225 if (parse_events__is_hardcoded_term(term))
226 return 0;
227
228 if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
229 return -EINVAL;
230
231 format = pmu_find_format(formats, term->config);
232 if (!format)
233 return -EINVAL;
234
235 switch (format->value) {
236 case PERF_PMU_FORMAT_VALUE_CONFIG:
237 vp = &attr->config;
238 break;
239 case PERF_PMU_FORMAT_VALUE_CONFIG1:
240 vp = &attr->config1;
241 break;
242 case PERF_PMU_FORMAT_VALUE_CONFIG2:
243 vp = &attr->config2;
244 break;
245 default:
246 return -EINVAL;
247 }
248
249 *vp |= pmu_format_value(format->bits, term->val.num);
250 return 0;
251}
252
253static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
254 struct list_head *head_terms)
255{
256 struct parse_events__term *term, *h;
257
258 list_for_each_entry_safe(term, h, head_terms, list)
259 if (pmu_config_term(formats, attr, term))
260 return -EINVAL;
261
262 return 0;
263}
264
265/*
266 * Configures event's 'attr' parameter based on the:
267 * 1) users input - specified in terms parameter
268 * 2) pmu format definitions - specified by pmu parameter
269 */
270int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
271 struct list_head *head_terms)
272{
273 attr->type = pmu->type;
274 return pmu_config(&pmu->format, attr, head_terms);
275}
276
277int perf_pmu__new_format(struct list_head *list, char *name,
278 int config, unsigned long *bits)
279{
280 struct perf_pmu__format *format;
281
282 format = zalloc(sizeof(*format));
283 if (!format)
284 return -ENOMEM;
285
286 format->name = strdup(name);
287 format->value = config;
288 memcpy(format->bits, bits, sizeof(format->bits));
289
290 list_add_tail(&format->list, list);
291 return 0;
292}
293
294void perf_pmu__set_format(unsigned long *bits, long from, long to)
295{
296 long b;
297
298 if (!to)
299 to = from;
300
301 memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
302 for (b = from; b <= to; b++)
303 set_bit(b, bits);
304}
305
306/* Simulated format definitions. */
307static struct test_format {
308 const char *name;
309 const char *value;
310} test_formats[] = {
311 { "krava01", "config:0-1,62-63\n", },
312 { "krava02", "config:10-17\n", },
313 { "krava03", "config:5\n", },
314 { "krava11", "config1:0,2,4,6,8,20-28\n", },
315 { "krava12", "config1:63\n", },
316 { "krava13", "config1:45-47\n", },
317 { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
318 { "krava22", "config2:8,18,48,58\n", },
319 { "krava23", "config2:28-29,38\n", },
320};
321
322#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
323
324/* Simulated users input. */
325static struct parse_events__term test_terms[] = {
326 {
327 .config = (char *) "krava01",
328 .val.num = 15,
329 .type = PARSE_EVENTS__TERM_TYPE_NUM,
330 },
331 {
332 .config = (char *) "krava02",
333 .val.num = 170,
334 .type = PARSE_EVENTS__TERM_TYPE_NUM,
335 },
336 {
337 .config = (char *) "krava03",
338 .val.num = 1,
339 .type = PARSE_EVENTS__TERM_TYPE_NUM,
340 },
341 {
342 .config = (char *) "krava11",
343 .val.num = 27,
344 .type = PARSE_EVENTS__TERM_TYPE_NUM,
345 },
346 {
347 .config = (char *) "krava12",
348 .val.num = 1,
349 .type = PARSE_EVENTS__TERM_TYPE_NUM,
350 },
351 {
352 .config = (char *) "krava13",
353 .val.num = 2,
354 .type = PARSE_EVENTS__TERM_TYPE_NUM,
355 },
356 {
357 .config = (char *) "krava21",
358 .val.num = 119,
359 .type = PARSE_EVENTS__TERM_TYPE_NUM,
360 },
361 {
362 .config = (char *) "krava22",
363 .val.num = 11,
364 .type = PARSE_EVENTS__TERM_TYPE_NUM,
365 },
366 {
367 .config = (char *) "krava23",
368 .val.num = 2,
369 .type = PARSE_EVENTS__TERM_TYPE_NUM,
370 },
371};
372#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
373
374/*
375 * Prepare format directory data, exported by kernel
376 * at /sys/bus/event_source/devices/<dev>/format.
377 */
378static char *test_format_dir_get(void)
379{
380 static char dir[PATH_MAX];
381 unsigned int i;
382
383 snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
384 if (!mkdtemp(dir))
385 return NULL;
386
387 for (i = 0; i < TEST_FORMATS_CNT; i++) {
388 static char name[PATH_MAX];
389 struct test_format *format = &test_formats[i];
390 FILE *file;
391
392 snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
393
394 file = fopen(name, "w");
395 if (!file)
396 return NULL;
397
398 if (1 != fwrite(format->value, strlen(format->value), 1, file))
399 break;
400
401 fclose(file);
402 }
403
404 return dir;
405}
406
407/* Cleanup format directory. */
408static int test_format_dir_put(char *dir)
409{
410 char buf[PATH_MAX];
411 snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
412 if (system(buf))
413 return -1;
414
415 snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
416 return system(buf);
417}
418
419static struct list_head *test_terms_list(void)
420{
421 static LIST_HEAD(terms);
422 unsigned int i;
423
424 for (i = 0; i < TERMS_CNT; i++)
425 list_add_tail(&test_terms[i].list, &terms);
426
427 return &terms;
428}
429
430#undef TERMS_CNT
431
432int perf_pmu__test(void)
433{
434 char *format = test_format_dir_get();
435 LIST_HEAD(formats);
436 struct list_head *terms = test_terms_list();
437 int ret;
438
439 if (!format)
440 return -EINVAL;
441
442 do {
443 struct perf_event_attr attr;
444
445 memset(&attr, 0, sizeof(attr));
446
447 ret = pmu_format_parse(format, &formats);
448 if (ret)
449 break;
450
451 ret = pmu_config(&formats, &attr, terms);
452 if (ret)
453 break;
454
455 ret = -EINVAL;
456
457 if (attr.config != 0xc00000000002a823)
458 break;
459 if (attr.config1 != 0x8000400000000145)
460 break;
461 if (attr.config2 != 0x0400000020041d07)
462 break;
463
464 ret = 0;
465 } while (0);
466
467 test_format_dir_put(format);
468 return ret;
469}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
new file mode 100644
index 000000000000..68c0db965e1f
--- /dev/null
+++ b/tools/perf/util/pmu.h
@@ -0,0 +1,41 @@
1#ifndef __PMU_H
2#define __PMU_H
3
4#include <linux/bitops.h>
5#include "../../../include/linux/perf_event.h"
6
7enum {
8 PERF_PMU_FORMAT_VALUE_CONFIG,
9 PERF_PMU_FORMAT_VALUE_CONFIG1,
10 PERF_PMU_FORMAT_VALUE_CONFIG2,
11};
12
13#define PERF_PMU_FORMAT_BITS 64
14
15struct perf_pmu__format {
16 char *name;
17 int value;
18 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
19 struct list_head list;
20};
21
22struct perf_pmu {
23 char *name;
24 __u32 type;
25 struct list_head format;
26 struct list_head list;
27};
28
29struct perf_pmu *perf_pmu__find(char *name);
30int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
31 struct list_head *head_terms);
32
33int perf_pmu_wrap(void);
34void perf_pmu_error(struct list_head *list, char *name, char const *msg);
35
36int perf_pmu__new_format(struct list_head *list, char *name,
37 int config, unsigned long *bits);
38void perf_pmu__set_format(unsigned long *bits, long from, long to);
39
40int perf_pmu__test(void);
41#endif /* __PMU_H */
diff --git a/tools/perf/util/pmu.l b/tools/perf/util/pmu.l
new file mode 100644
index 000000000000..a15d9fbd7c0e
--- /dev/null
+++ b/tools/perf/util/pmu.l
@@ -0,0 +1,43 @@
1%option prefix="perf_pmu_"
2
3%{
4#include <stdlib.h>
5#include <linux/bitops.h>
6#include "pmu.h"
7#include "pmu-bison.h"
8
9static int value(int base)
10{
11 long num;
12
13 errno = 0;
14 num = strtoul(perf_pmu_text, NULL, base);
15 if (errno)
16 return PP_ERROR;
17
18 perf_pmu_lval.num = num;
19 return PP_VALUE;
20}
21
22%}
23
24num_dec [0-9]+
25
26%%
27
28{num_dec} { return value(10); }
29config { return PP_CONFIG; }
30config1 { return PP_CONFIG1; }
31config2 { return PP_CONFIG2; }
32- { return '-'; }
33: { return ':'; }
34, { return ','; }
35. { ; }
36\n { ; }
37
38%%
39
40int perf_pmu_wrap(void)
41{
42 return 1;
43}
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
new file mode 100644
index 000000000000..20ea77e93169
--- /dev/null
+++ b/tools/perf/util/pmu.y
@@ -0,0 +1,93 @@
1
2%name-prefix "perf_pmu_"
3%parse-param {struct list_head *format}
4%parse-param {char *name}
5
6%{
7
8#include <linux/compiler.h>
9#include <linux/list.h>
10#include <linux/bitmap.h>
11#include <string.h>
12#include "pmu.h"
13
14extern int perf_pmu_lex (void);
15
16#define ABORT_ON(val) \
17do { \
18 if (val) \
19 YYABORT; \
20} while (0)
21
22%}
23
24%token PP_CONFIG PP_CONFIG1 PP_CONFIG2
25%token PP_VALUE PP_ERROR
26%type <num> PP_VALUE
27%type <bits> bit_term
28%type <bits> bits
29
30%union
31{
32 unsigned long num;
33 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
34}
35
36%%
37
38format:
39format format_term
40|
41format_term
42
43format_term:
44PP_CONFIG ':' bits
45{
46 ABORT_ON(perf_pmu__new_format(format, name,
47 PERF_PMU_FORMAT_VALUE_CONFIG,
48 $3));
49}
50|
51PP_CONFIG1 ':' bits
52{
53 ABORT_ON(perf_pmu__new_format(format, name,
54 PERF_PMU_FORMAT_VALUE_CONFIG1,
55 $3));
56}
57|
58PP_CONFIG2 ':' bits
59{
60 ABORT_ON(perf_pmu__new_format(format, name,
61 PERF_PMU_FORMAT_VALUE_CONFIG2,
62 $3));
63}
64
65bits:
66bits ',' bit_term
67{
68 bitmap_or($$, $1, $3, 64);
69}
70|
71bit_term
72{
73 memcpy($$, $1, sizeof($1));
74}
75
76bit_term:
77PP_VALUE '-' PP_VALUE
78{
79 perf_pmu__set_format($$, $1, $3);
80}
81|
82PP_VALUE
83{
84 perf_pmu__set_format($$, $1, 0);
85}
86
87%%
88
89void perf_pmu_error(struct list_head *list __used,
90 char *name __used,
91 char const *msg __used)
92{
93}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 29cb65459811..8a8ee64e72d1 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -34,7 +34,6 @@
34 34
35#include "util.h" 35#include "util.h"
36#include "event.h" 36#include "event.h"
37#include "string.h"
38#include "strlist.h" 37#include "strlist.h"
39#include "debug.h" 38#include "debug.h"
40#include "cache.h" 39#include "cache.h"
@@ -273,10 +272,10 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
273/* Try to find perf_probe_event with debuginfo */ 272/* Try to find perf_probe_event with debuginfo */
274static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 273static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
275 struct probe_trace_event **tevs, 274 struct probe_trace_event **tevs,
276 int max_tevs, const char *module) 275 int max_tevs, const char *target)
277{ 276{
278 bool need_dwarf = perf_probe_event_need_dwarf(pev); 277 bool need_dwarf = perf_probe_event_need_dwarf(pev);
279 struct debuginfo *dinfo = open_debuginfo(module); 278 struct debuginfo *dinfo = open_debuginfo(target);
280 int ntevs, ret = 0; 279 int ntevs, ret = 0;
281 280
282 if (!dinfo) { 281 if (!dinfo) {
@@ -295,9 +294,9 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
295 294
296 if (ntevs > 0) { /* Succeeded to find trace events */ 295 if (ntevs > 0) { /* Succeeded to find trace events */
297 pr_debug("find %d probe_trace_events.\n", ntevs); 296 pr_debug("find %d probe_trace_events.\n", ntevs);
298 if (module) 297 if (target)
299 ret = add_module_to_probe_trace_events(*tevs, ntevs, 298 ret = add_module_to_probe_trace_events(*tevs, ntevs,
300 module); 299 target);
301 return ret < 0 ? ret : ntevs; 300 return ret < 0 ? ret : ntevs;
302 } 301 }
303 302
@@ -1729,7 +1728,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1729 } 1728 }
1730 1729
1731 ret = 0; 1730 ret = 0;
1732 printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":"); 1731 printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
1733 for (i = 0; i < ntevs; i++) { 1732 for (i = 0; i < ntevs; i++) {
1734 tev = &tevs[i]; 1733 tev = &tevs[i];
1735 if (pev->event) 1734 if (pev->event)
@@ -1784,7 +1783,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1784 1783
1785 if (ret >= 0) { 1784 if (ret >= 0) {
1786 /* Show how to use the event. */ 1785 /* Show how to use the event. */
1787 printf("\nYou can now use it on all perf tools, such as:\n\n"); 1786 printf("\nYou can now use it in all perf tools, such as:\n\n");
1788 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 1787 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1789 tev->event); 1788 tev->event);
1790 } 1789 }
@@ -1796,14 +1795,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1796 1795
1797static int convert_to_probe_trace_events(struct perf_probe_event *pev, 1796static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1798 struct probe_trace_event **tevs, 1797 struct probe_trace_event **tevs,
1799 int max_tevs, const char *module) 1798 int max_tevs, const char *target)
1800{ 1799{
1801 struct symbol *sym; 1800 struct symbol *sym;
1802 int ret = 0, i; 1801 int ret = 0, i;
1803 struct probe_trace_event *tev; 1802 struct probe_trace_event *tev;
1804 1803
1805 /* Convert perf_probe_event with debuginfo */ 1804 /* Convert perf_probe_event with debuginfo */
1806 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); 1805 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
1807 if (ret != 0) 1806 if (ret != 0)
1808 return ret; /* Found in debuginfo or got an error */ 1807 return ret; /* Found in debuginfo or got an error */
1809 1808
@@ -1819,8 +1818,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1819 goto error; 1818 goto error;
1820 } 1819 }
1821 1820
1822 if (module) { 1821 if (target) {
1823 tev->point.module = strdup(module); 1822 tev->point.module = strdup(target);
1824 if (tev->point.module == NULL) { 1823 if (tev->point.module == NULL) {
1825 ret = -ENOMEM; 1824 ret = -ENOMEM;
1826 goto error; 1825 goto error;
@@ -1867,6 +1866,12 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1867 tev->point.symbol); 1866 tev->point.symbol);
1868 ret = -ENOENT; 1867 ret = -ENOENT;
1869 goto error; 1868 goto error;
1869 } else if (tev->point.offset > sym->end - sym->start) {
1870 pr_warning("Offset specified is greater than size of %s\n",
1871 tev->point.symbol);
1872 ret = -ENOENT;
1873 goto error;
1874
1870 } 1875 }
1871 1876
1872 return 1; 1877 return 1;
@@ -1884,7 +1889,7 @@ struct __event_package {
1884}; 1889};
1885 1890
1886int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1891int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1887 int max_tevs, const char *module, bool force_add) 1892 int max_tevs, const char *target, bool force_add)
1888{ 1893{
1889 int i, j, ret; 1894 int i, j, ret;
1890 struct __event_package *pkgs; 1895 struct __event_package *pkgs;
@@ -1907,7 +1912,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1907 ret = convert_to_probe_trace_events(pkgs[i].pev, 1912 ret = convert_to_probe_trace_events(pkgs[i].pev,
1908 &pkgs[i].tevs, 1913 &pkgs[i].tevs,
1909 max_tevs, 1914 max_tevs,
1910 module); 1915 target);
1911 if (ret < 0) 1916 if (ret < 0)
1912 goto end; 1917 goto end;
1913 pkgs[i].ntevs = ret; 1918 pkgs[i].ntevs = ret;
@@ -1959,7 +1964,7 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
1959 goto error; 1964 goto error;
1960 } 1965 }
1961 1966
1962 printf("Remove event: %s\n", ent->s); 1967 printf("Removed event: %s\n", ent->s);
1963 return 0; 1968 return 0;
1964error: 1969error:
1965 pr_warning("Failed to delete event: %s\n", strerror(-ret)); 1970 pr_warning("Failed to delete event: %s\n", strerror(-ret));
@@ -2063,7 +2068,7 @@ static int filter_available_functions(struct map *map __unused,
2063 return 1; 2068 return 1;
2064} 2069}
2065 2070
2066int show_available_funcs(const char *module, struct strfilter *_filter) 2071int show_available_funcs(const char *target, struct strfilter *_filter)
2067{ 2072{
2068 struct map *map; 2073 struct map *map;
2069 int ret; 2074 int ret;
@@ -2074,9 +2079,9 @@ int show_available_funcs(const char *module, struct strfilter *_filter)
2074 if (ret < 0) 2079 if (ret < 0)
2075 return ret; 2080 return ret;
2076 2081
2077 map = kernel_get_module_map(module); 2082 map = kernel_get_module_map(target);
2078 if (!map) { 2083 if (!map) {
2079 pr_err("Failed to find %s map.\n", (module) ? : "kernel"); 2084 pr_err("Failed to find %s map.\n", (target) ? : "kernel");
2080 return -EINVAL; 2085 return -EINVAL;
2081 } 2086 }
2082 available_func_filter = _filter; 2087 available_func_filter = _filter;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 5d732621a462..d448984ed789 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -30,7 +30,6 @@
30#include <stdlib.h> 30#include <stdlib.h>
31#include <string.h> 31#include <string.h>
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h>
34#include <dwarf-regs.h> 33#include <dwarf-regs.h>
35 34
36#include <linux/bitops.h> 35#include <linux/bitops.h>
@@ -672,7 +671,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
672static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 671static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
673 bool retprobe, struct probe_trace_point *tp) 672 bool retprobe, struct probe_trace_point *tp)
674{ 673{
675 Dwarf_Addr eaddr; 674 Dwarf_Addr eaddr, highaddr;
676 const char *name; 675 const char *name;
677 676
678 /* Copy the name of probe point */ 677 /* Copy the name of probe point */
@@ -683,6 +682,16 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
683 dwarf_diename(sp_die)); 682 dwarf_diename(sp_die));
684 return -ENOENT; 683 return -ENOENT;
685 } 684 }
685 if (dwarf_highpc(sp_die, &highaddr) != 0) {
686 pr_warning("Failed to get end address of %s\n",
687 dwarf_diename(sp_die));
688 return -ENOENT;
689 }
690 if (paddr > highaddr) {
691 pr_warning("Offset specified is greater than size of %s\n",
692 dwarf_diename(sp_die));
693 return -EINVAL;
694 }
686 tp->symbol = strdup(name); 695 tp->symbol = strdup(name);
687 if (tp->symbol == NULL) 696 if (tp->symbol == NULL)
688 return -ENOMEM; 697 return -ENOMEM;
@@ -963,10 +972,12 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
963 struct dwarf_callback_param *param = data; 972 struct dwarf_callback_param *param = data;
964 struct probe_finder *pf = param->data; 973 struct probe_finder *pf = param->data;
965 struct perf_probe_point *pp = &pf->pev->point; 974 struct perf_probe_point *pp = &pf->pev->point;
975 Dwarf_Attribute attr;
966 976
967 /* Check tag and diename */ 977 /* Check tag and diename */
968 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 978 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
969 !die_compare_name(sp_die, pp->function)) 979 !die_compare_name(sp_die, pp->function) ||
980 dwarf_attr(sp_die, DW_AT_declaration, &attr))
970 return DWARF_CB_OK; 981 return DWARF_CB_OK;
971 982
972 /* Check declared file */ 983 /* Check declared file */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
new file mode 100644
index 000000000000..2884e67ee625
--- /dev/null
+++ b/tools/perf/util/python-ext-sources
@@ -0,0 +1,19 @@
1#
2# List of files needed by perf python extention
3#
4# Each source file must be placed on its own line so that it can be
5# processed by Makefile and util/setup.py accordingly.
6#
7
8util/python.c
9util/ctype.c
10util/evlist.c
11util/evsel.c
12util/cpumap.c
13util/thread_map.c
14util/util.c
15util/xyarray.c
16util/cgroup.c
17util/debugfs.c
18util/strlist.c
19../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9dd47a4f2596..e03b58a48424 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -425,14 +425,14 @@ struct pyrf_thread_map {
425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, 425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
426 PyObject *args, PyObject *kwargs) 426 PyObject *args, PyObject *kwargs)
427{ 427{
428 static char *kwlist[] = { "pid", "tid", NULL }; 428 static char *kwlist[] = { "pid", "tid", "uid", NULL };
429 int pid = -1, tid = -1; 429 int pid = -1, tid = -1, uid = UINT_MAX;
430 430
431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", 431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii",
432 kwlist, &pid, &tid)) 432 kwlist, &pid, &tid, &uid))
433 return -1; 433 return -1;
434 434
435 pthreads->threads = thread_map__new(pid, tid); 435 pthreads->threads = thread_map__new(pid, tid, uid);
436 if (pthreads->threads == NULL) 436 if (pthreads->threads == NULL)
437 return -1; 437 return -1;
438 return 0; 438 return 0;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 0b2a48783172..c2623c6f9b51 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -24,7 +24,6 @@
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <string.h> 26#include <string.h>
27#include <ctype.h>
28#include <errno.h> 27#include <errno.h>
29 28
30#include "../../perf.h" 29#include "../../perf.h"
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index b5ca2558c7bb..9412e3b05f68 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force)
24 self->fd = STDIN_FILENO; 24 self->fd = STDIN_FILENO;
25 25
26 if (perf_session__read_header(self, self->fd) < 0) 26 if (perf_session__read_header(self, self->fd) < 0)
27 pr_err("incompatible file format"); 27 pr_err("incompatible file format (rerun with -v to learn more)");
28 28
29 return 0; 29 return 0;
30 } 30 }
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force)
56 } 56 }
57 57
58 if (perf_session__read_header(self, self->fd) < 0) { 58 if (perf_session__read_header(self, self->fd) < 0) {
59 pr_err("incompatible file format"); 59 pr_err("incompatible file format (rerun with -v to learn more)");
60 goto out_close; 60 goto out_close;
61 } 61 }
62 62
@@ -140,6 +140,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
140 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 140 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
141 INIT_LIST_HEAD(&self->ordered_samples.to_free); 141 INIT_LIST_HEAD(&self->ordered_samples.to_free);
142 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 142 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
143 hists__init(&self->hists);
143 144
144 if (mode == O_RDONLY) { 145 if (mode == O_RDONLY) {
145 if (perf_session__open(self, force) < 0) 146 if (perf_session__open(self, force) < 0)
@@ -229,6 +230,64 @@ static bool symbol__match_parent_regex(struct symbol *sym)
229 return 0; 230 return 0;
230} 231}
231 232
233static const u8 cpumodes[] = {
234 PERF_RECORD_MISC_USER,
235 PERF_RECORD_MISC_KERNEL,
236 PERF_RECORD_MISC_GUEST_USER,
237 PERF_RECORD_MISC_GUEST_KERNEL
238};
239#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
240
241static void ip__resolve_ams(struct machine *self, struct thread *thread,
242 struct addr_map_symbol *ams,
243 u64 ip)
244{
245 struct addr_location al;
246 size_t i;
247 u8 m;
248
249 memset(&al, 0, sizeof(al));
250
251 for (i = 0; i < NCPUMODES; i++) {
252 m = cpumodes[i];
253 /*
254 * We cannot use the header.misc hint to determine whether a
255 * branch stack address is user, kernel, guest, hypervisor.
256 * Branches may straddle the kernel/user/hypervisor boundaries.
257 * Thus, we have to try consecutively until we find a match
258 * or else, the symbol is unknown
259 */
260 thread__find_addr_location(thread, self, m, MAP__FUNCTION,
261 ip, &al, NULL);
262 if (al.sym)
263 goto found;
264 }
265found:
266 ams->addr = ip;
267 ams->al_addr = al.addr;
268 ams->sym = al.sym;
269 ams->map = al.map;
270}
271
272struct branch_info *machine__resolve_bstack(struct machine *self,
273 struct thread *thr,
274 struct branch_stack *bs)
275{
276 struct branch_info *bi;
277 unsigned int i;
278
279 bi = calloc(bs->nr, sizeof(struct branch_info));
280 if (!bi)
281 return NULL;
282
283 for (i = 0; i < bs->nr; i++) {
284 ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
285 ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
286 bi[i].flags = bs->entries[i].flags;
287 }
288 return bi;
289}
290
232int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, 291int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
233 struct thread *thread, 292 struct thread *thread,
234 struct ip_callchain *chain, 293 struct ip_callchain *chain,
@@ -697,6 +756,18 @@ static void callchain__printf(struct perf_sample *sample)
697 i, sample->callchain->ips[i]); 756 i, sample->callchain->ips[i]);
698} 757}
699 758
759static void branch_stack__printf(struct perf_sample *sample)
760{
761 uint64_t i;
762
763 printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr);
764
765 for (i = 0; i < sample->branch_stack->nr; i++)
766 printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 "\n",
767 i, sample->branch_stack->entries[i].from,
768 sample->branch_stack->entries[i].to);
769}
770
700static void perf_session__print_tstamp(struct perf_session *session, 771static void perf_session__print_tstamp(struct perf_session *session,
701 union perf_event *event, 772 union perf_event *event,
702 struct perf_sample *sample) 773 struct perf_sample *sample)
@@ -744,6 +815,9 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
744 815
745 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) 816 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
746 callchain__printf(sample); 817 callchain__printf(sample);
818
819 if (session->sample_type & PERF_SAMPLE_BRANCH_STACK)
820 branch_stack__printf(sample);
747} 821}
748 822
749static struct machine * 823static struct machine *
@@ -796,6 +870,10 @@ static int perf_session_deliver_event(struct perf_session *session,
796 ++session->hists.stats.nr_unknown_id; 870 ++session->hists.stats.nr_unknown_id;
797 return -1; 871 return -1;
798 } 872 }
873 if (machine == NULL) {
874 ++session->hists.stats.nr_unprocessable_samples;
875 return -1;
876 }
799 return tool->sample(tool, event, sample, evsel, machine); 877 return tool->sample(tool, event, sample, evsel, machine);
800 case PERF_RECORD_MMAP: 878 case PERF_RECORD_MMAP:
801 return tool->mmap(tool, event, sample, machine); 879 return tool->mmap(tool, event, sample, machine);
@@ -964,6 +1042,12 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
964 session->hists.stats.nr_invalid_chains, 1042 session->hists.stats.nr_invalid_chains,
965 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 1043 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
966 } 1044 }
1045
1046 if (session->hists.stats.nr_unprocessable_samples != 0) {
1047 ui__warning("%u unprocessable samples recorded.\n"
1048 "Do you have a KVM guest running and not using 'perf kvm'?\n",
1049 session->hists.stats.nr_unprocessable_samples);
1050 }
967} 1051}
968 1052
969#define session_done() (*(volatile int *)(&session_done)) 1053#define session_done() (*(volatile int *)(&session_done))
@@ -1293,10 +1377,9 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1293 1377
1294void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, 1378void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1295 struct machine *machine, struct perf_evsel *evsel, 1379 struct machine *machine, struct perf_evsel *evsel,
1296 int print_sym, int print_dso) 1380 int print_sym, int print_dso, int print_symoffset)
1297{ 1381{
1298 struct addr_location al; 1382 struct addr_location al;
1299 const char *symname, *dsoname;
1300 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; 1383 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
1301 struct callchain_cursor_node *node; 1384 struct callchain_cursor_node *node;
1302 1385
@@ -1324,20 +1407,13 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1324 1407
1325 printf("\t%16" PRIx64, node->ip); 1408 printf("\t%16" PRIx64, node->ip);
1326 if (print_sym) { 1409 if (print_sym) {
1327 if (node->sym && node->sym->name) 1410 printf(" ");
1328 symname = node->sym->name; 1411 symbol__fprintf_symname(node->sym, stdout);
1329 else
1330 symname = "";
1331
1332 printf(" %s", symname);
1333 } 1412 }
1334 if (print_dso) { 1413 if (print_dso) {
1335 if (node->map && node->map->dso && node->map->dso->name) 1414 printf(" (");
1336 dsoname = node->map->dso->name; 1415 map__fprintf_dsoname(al.map, stdout);
1337 else 1416 printf(")");
1338 dsoname = "";
1339
1340 printf(" (%s)", dsoname);
1341 } 1417 }
1342 printf("\n"); 1418 printf("\n");
1343 1419
@@ -1347,21 +1423,18 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1347 } else { 1423 } else {
1348 printf("%16" PRIx64, sample->ip); 1424 printf("%16" PRIx64, sample->ip);
1349 if (print_sym) { 1425 if (print_sym) {
1350 if (al.sym && al.sym->name) 1426 printf(" ");
1351 symname = al.sym->name; 1427 if (print_symoffset)
1428 symbol__fprintf_symname_offs(al.sym, &al,
1429 stdout);
1352 else 1430 else
1353 symname = ""; 1431 symbol__fprintf_symname(al.sym, stdout);
1354
1355 printf(" %s", symname);
1356 } 1432 }
1357 1433
1358 if (print_dso) { 1434 if (print_dso) {
1359 if (al.map && al.map->dso && al.map->dso->name) 1435 printf(" (");
1360 dsoname = al.map->dso->name; 1436 map__fprintf_dsoname(al.map, stdout);
1361 else 1437 printf(")");
1362 dsoname = "";
1363
1364 printf(" (%s)", dsoname);
1365 } 1438 }
1366 } 1439 }
1367} 1440}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 37bc38381fb6..7a5434c00565 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -73,6 +73,10 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel
73 struct ip_callchain *chain, 73 struct ip_callchain *chain,
74 struct symbol **parent); 74 struct symbol **parent);
75 75
76struct branch_info *machine__resolve_bstack(struct machine *self,
77 struct thread *thread,
78 struct branch_stack *bs);
79
76bool perf_session__has_traces(struct perf_session *self, const char *msg); 80bool perf_session__has_traces(struct perf_session *self, const char *msg);
77 81
78void mem_bswap_64(void *src, int byte_size); 82void mem_bswap_64(void *src, int byte_size);
@@ -147,7 +151,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
147 151
148void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, 152void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
149 struct machine *machine, struct perf_evsel *evsel, 153 struct machine *machine, struct perf_evsel *evsel,
150 int print_sym, int print_dso); 154 int print_sym, int print_dso, int print_symoffset);
151 155
152int perf_session__cpu_bitmap(struct perf_session *session, 156int perf_session__cpu_bitmap(struct perf_session *session,
153 const char *cpu_list, unsigned long *cpu_bitmap); 157 const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 36d4c5619575..d0f9f29cf181 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -24,11 +24,11 @@ cflags += getenv('CFLAGS', '').split()
24build_lib = getenv('PYTHON_EXTBUILD_LIB') 24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP') 25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26 26
27ext_sources = [f.strip() for f in file('util/python-ext-sources')
28 if len(f.strip()) > 0 and f[0] != '#']
29
27perf = Extension('perf', 30perf = Extension('perf',
28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 31 sources = ext_sources,
29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
30 'util/util.c', 'util/xyarray.c', 'util/cgroup.c',
31 'util/debugfs.c'],
32 include_dirs = ['util/include'], 32 include_dirs = ['util/include'],
33 extra_compile_args = cflags, 33 extra_compile_args = cflags,
34 ) 34 )
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 16da30d8d765..a27237430c5f 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -8,6 +8,7 @@ const char default_sort_order[] = "comm,dso,symbol";
8const char *sort_order = default_sort_order; 8const char *sort_order = default_sort_order;
9int sort__need_collapse = 0; 9int sort__need_collapse = 0;
10int sort__has_parent = 0; 10int sort__has_parent = 0;
11int sort__branch_mode = -1; /* -1 = means not set */
11 12
12enum sort_type sort__first_dimension; 13enum sort_type sort__first_dimension;
13 14
@@ -33,6 +34,9 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
33 } 34 }
34 } 35 }
35 va_end(ap); 36 va_end(ap);
37
38 if (n >= (int)size)
39 return size - 1;
36 return n; 40 return n;
37} 41}
38 42
@@ -94,6 +98,26 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
94 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 98 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
95} 99}
96 100
101static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
102{
103 struct dso *dso_l = map_l ? map_l->dso : NULL;
104 struct dso *dso_r = map_r ? map_r->dso : NULL;
105 const char *dso_name_l, *dso_name_r;
106
107 if (!dso_l || !dso_r)
108 return cmp_null(dso_l, dso_r);
109
110 if (verbose) {
111 dso_name_l = dso_l->long_name;
112 dso_name_r = dso_r->long_name;
113 } else {
114 dso_name_l = dso_l->short_name;
115 dso_name_r = dso_r->short_name;
116 }
117
118 return strcmp(dso_name_l, dso_name_r);
119}
120
97struct sort_entry sort_comm = { 121struct sort_entry sort_comm = {
98 .se_header = "Command", 122 .se_header = "Command",
99 .se_cmp = sort__comm_cmp, 123 .se_cmp = sort__comm_cmp,
@@ -107,36 +131,74 @@ struct sort_entry sort_comm = {
107static int64_t 131static int64_t
108sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
109{ 133{
110 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL; 134 return _sort__dso_cmp(left->ms.map, right->ms.map);
111 struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL; 135}
112 const char *dso_name_l, *dso_name_r;
113 136
114 if (!dso_l || !dso_r)
115 return cmp_null(dso_l, dso_r);
116 137
117 if (verbose) { 138static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
118 dso_name_l = dso_l->long_name; 139 u64 ip_l, u64 ip_r)
119 dso_name_r = dso_r->long_name; 140{
120 } else { 141 if (!sym_l || !sym_r)
121 dso_name_l = dso_l->short_name; 142 return cmp_null(sym_l, sym_r);
122 dso_name_r = dso_r->short_name; 143
144 if (sym_l == sym_r)
145 return 0;
146
147 if (sym_l)
148 ip_l = sym_l->start;
149 if (sym_r)
150 ip_r = sym_r->start;
151
152 return (int64_t)(ip_r - ip_l);
153}
154
155static int _hist_entry__dso_snprintf(struct map *map, char *bf,
156 size_t size, unsigned int width)
157{
158 if (map && map->dso) {
159 const char *dso_name = !verbose ? map->dso->short_name :
160 map->dso->long_name;
161 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
123 } 162 }
124 163
125 return strcmp(dso_name_l, dso_name_r); 164 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
126} 165}
127 166
128static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, 167static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
129 size_t size, unsigned int width) 168 size_t size, unsigned int width)
130{ 169{
131 if (self->ms.map && self->ms.map->dso) { 170 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
132 const char *dso_name = !verbose ? self->ms.map->dso->short_name : 171}
133 self->ms.map->dso->long_name; 172
134 return repsep_snprintf(bf, size, "%-*s", width, dso_name); 173static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
174 u64 ip, char level, char *bf, size_t size,
175 unsigned int width __used)
176{
177 size_t ret = 0;
178
179 if (verbose) {
180 char o = map ? dso__symtab_origin(map->dso) : '!';
181 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
182 BITS_PER_LONG / 4, ip, o);
135 } 183 }
136 184
137 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 185 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
186 if (sym)
187 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
188 width - ret,
189 sym->name);
190 else {
191 size_t len = BITS_PER_LONG / 4;
192 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
193 len, ip);
194 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
195 width - ret, "");
196 }
197
198 return ret;
138} 199}
139 200
201
140struct sort_entry sort_dso = { 202struct sort_entry sort_dso = {
141 .se_header = "Shared Object", 203 .se_header = "Shared Object",
142 .se_cmp = sort__dso_cmp, 204 .se_cmp = sort__dso_cmp,
@@ -144,8 +206,14 @@ struct sort_entry sort_dso = {
144 .se_width_idx = HISTC_DSO, 206 .se_width_idx = HISTC_DSO,
145}; 207};
146 208
147/* --sort symbol */ 209static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
210 size_t size, unsigned int width __used)
211{
212 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213 self->level, bf, size, width);
214}
148 215
216/* --sort symbol */
149static int64_t 217static int64_t
150sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
151{ 219{
@@ -163,31 +231,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
163 ip_l = left->ms.sym->start; 231 ip_l = left->ms.sym->start;
164 ip_r = right->ms.sym->start; 232 ip_r = right->ms.sym->start;
165 233
166 return (int64_t)(ip_r - ip_l); 234 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
167}
168
169static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
170 size_t size, unsigned int width __used)
171{
172 size_t ret = 0;
173
174 if (verbose) {
175 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
176 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
177 BITS_PER_LONG / 4, self->ip, o);
178 }
179
180 if (!sort_dso.elide)
181 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
182
183 if (self->ms.sym)
184 ret += repsep_snprintf(bf + ret, size - ret, "%s",
185 self->ms.sym->name);
186 else
187 ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
188 BITS_PER_LONG / 4, self->ip);
189
190 return ret;
191} 235}
192 236
193struct sort_entry sort_sym = { 237struct sort_entry sort_sym = {
@@ -246,19 +290,155 @@ struct sort_entry sort_cpu = {
246 .se_width_idx = HISTC_CPU, 290 .se_width_idx = HISTC_CPU,
247}; 291};
248 292
293static int64_t
294sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
295{
296 return _sort__dso_cmp(left->branch_info->from.map,
297 right->branch_info->from.map);
298}
299
300static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
301 size_t size, unsigned int width)
302{
303 return _hist_entry__dso_snprintf(self->branch_info->from.map,
304 bf, size, width);
305}
306
307struct sort_entry sort_dso_from = {
308 .se_header = "Source Shared Object",
309 .se_cmp = sort__dso_from_cmp,
310 .se_snprintf = hist_entry__dso_from_snprintf,
311 .se_width_idx = HISTC_DSO_FROM,
312};
313
314static int64_t
315sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
316{
317 return _sort__dso_cmp(left->branch_info->to.map,
318 right->branch_info->to.map);
319}
320
321static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
322 size_t size, unsigned int width)
323{
324 return _hist_entry__dso_snprintf(self->branch_info->to.map,
325 bf, size, width);
326}
327
328static int64_t
329sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
330{
331 struct addr_map_symbol *from_l = &left->branch_info->from;
332 struct addr_map_symbol *from_r = &right->branch_info->from;
333
334 if (!from_l->sym && !from_r->sym)
335 return right->level - left->level;
336
337 return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr,
338 from_r->addr);
339}
340
341static int64_t
342sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
343{
344 struct addr_map_symbol *to_l = &left->branch_info->to;
345 struct addr_map_symbol *to_r = &right->branch_info->to;
346
347 if (!to_l->sym && !to_r->sym)
348 return right->level - left->level;
349
350 return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr);
351}
352
353static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
354 size_t size, unsigned int width __used)
355{
356 struct addr_map_symbol *from = &self->branch_info->from;
357 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
358 self->level, bf, size, width);
359
360}
361
362static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
363 size_t size, unsigned int width __used)
364{
365 struct addr_map_symbol *to = &self->branch_info->to;
366 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
367 self->level, bf, size, width);
368
369}
370
371struct sort_entry sort_dso_to = {
372 .se_header = "Target Shared Object",
373 .se_cmp = sort__dso_to_cmp,
374 .se_snprintf = hist_entry__dso_to_snprintf,
375 .se_width_idx = HISTC_DSO_TO,
376};
377
378struct sort_entry sort_sym_from = {
379 .se_header = "Source Symbol",
380 .se_cmp = sort__sym_from_cmp,
381 .se_snprintf = hist_entry__sym_from_snprintf,
382 .se_width_idx = HISTC_SYMBOL_FROM,
383};
384
385struct sort_entry sort_sym_to = {
386 .se_header = "Target Symbol",
387 .se_cmp = sort__sym_to_cmp,
388 .se_snprintf = hist_entry__sym_to_snprintf,
389 .se_width_idx = HISTC_SYMBOL_TO,
390};
391
392static int64_t
393sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
394{
395 const unsigned char mp = left->branch_info->flags.mispred !=
396 right->branch_info->flags.mispred;
397 const unsigned char p = left->branch_info->flags.predicted !=
398 right->branch_info->flags.predicted;
399
400 return mp || p;
401}
402
403static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
404 size_t size, unsigned int width){
405 static const char *out = "N/A";
406
407 if (self->branch_info->flags.predicted)
408 out = "N";
409 else if (self->branch_info->flags.mispred)
410 out = "Y";
411
412 return repsep_snprintf(bf, size, "%-*s", width, out);
413}
414
415struct sort_entry sort_mispredict = {
416 .se_header = "Branch Mispredicted",
417 .se_cmp = sort__mispredict_cmp,
418 .se_snprintf = hist_entry__mispredict_snprintf,
419 .se_width_idx = HISTC_MISPREDICT,
420};
421
249struct sort_dimension { 422struct sort_dimension {
250 const char *name; 423 const char *name;
251 struct sort_entry *entry; 424 struct sort_entry *entry;
252 int taken; 425 int taken;
253}; 426};
254 427
428#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
429
255static struct sort_dimension sort_dimensions[] = { 430static struct sort_dimension sort_dimensions[] = {
256 { .name = "pid", .entry = &sort_thread, }, 431 DIM(SORT_PID, "pid", sort_thread),
257 { .name = "comm", .entry = &sort_comm, }, 432 DIM(SORT_COMM, "comm", sort_comm),
258 { .name = "dso", .entry = &sort_dso, }, 433 DIM(SORT_DSO, "dso", sort_dso),
259 { .name = "symbol", .entry = &sort_sym, }, 434 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
260 { .name = "parent", .entry = &sort_parent, }, 435 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
261 { .name = "cpu", .entry = &sort_cpu, }, 436 DIM(SORT_SYM, "symbol", sort_sym),
437 DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
438 DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
439 DIM(SORT_PARENT, "parent", sort_parent),
440 DIM(SORT_CPU, "cpu", sort_cpu),
441 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
262}; 442};
263 443
264int sort_dimension__add(const char *tok) 444int sort_dimension__add(const char *tok)
@@ -270,7 +450,6 @@ int sort_dimension__add(const char *tok)
270 450
271 if (strncasecmp(tok, sd->name, strlen(tok))) 451 if (strncasecmp(tok, sd->name, strlen(tok)))
272 continue; 452 continue;
273
274 if (sd->entry == &sort_parent) { 453 if (sd->entry == &sort_parent) {
275 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 454 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
276 if (ret) { 455 if (ret) {
@@ -302,6 +481,16 @@ int sort_dimension__add(const char *tok)
302 sort__first_dimension = SORT_PARENT; 481 sort__first_dimension = SORT_PARENT;
303 else if (!strcmp(sd->name, "cpu")) 482 else if (!strcmp(sd->name, "cpu"))
304 sort__first_dimension = SORT_CPU; 483 sort__first_dimension = SORT_CPU;
484 else if (!strcmp(sd->name, "symbol_from"))
485 sort__first_dimension = SORT_SYM_FROM;
486 else if (!strcmp(sd->name, "symbol_to"))
487 sort__first_dimension = SORT_SYM_TO;
488 else if (!strcmp(sd->name, "dso_from"))
489 sort__first_dimension = SORT_DSO_FROM;
490 else if (!strcmp(sd->name, "dso_to"))
491 sort__first_dimension = SORT_DSO_TO;
492 else if (!strcmp(sd->name, "mispredict"))
493 sort__first_dimension = SORT_MISPREDICT;
305 } 494 }
306 495
307 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 496 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
@@ -309,7 +498,6 @@ int sort_dimension__add(const char *tok)
309 498
310 return 0; 499 return 0;
311 } 500 }
312
313 return -ESRCH; 501 return -ESRCH;
314} 502}
315 503
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 3f67ae395752..472aa5a63a58 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -31,11 +31,16 @@ extern const char *parent_pattern;
31extern const char default_sort_order[]; 31extern const char default_sort_order[];
32extern int sort__need_collapse; 32extern int sort__need_collapse;
33extern int sort__has_parent; 33extern int sort__has_parent;
34extern int sort__branch_mode;
34extern char *field_sep; 35extern char *field_sep;
35extern struct sort_entry sort_comm; 36extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso; 37extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym; 38extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent; 39extern struct sort_entry sort_parent;
40extern struct sort_entry sort_dso_from;
41extern struct sort_entry sort_dso_to;
42extern struct sort_entry sort_sym_from;
43extern struct sort_entry sort_sym_to;
39extern enum sort_type sort__first_dimension; 44extern enum sort_type sort__first_dimension;
40 45
41/** 46/**
@@ -72,6 +77,7 @@ struct hist_entry {
72 struct hist_entry *pair; 77 struct hist_entry *pair;
73 struct rb_root sorted_chain; 78 struct rb_root sorted_chain;
74 }; 79 };
80 struct branch_info *branch_info;
75 struct callchain_root callchain[0]; 81 struct callchain_root callchain[0];
76}; 82};
77 83
@@ -82,6 +88,11 @@ enum sort_type {
82 SORT_SYM, 88 SORT_SYM,
83 SORT_PARENT, 89 SORT_PARENT,
84 SORT_CPU, 90 SORT_CPU,
91 SORT_DSO_FROM,
92 SORT_DSO_TO,
93 SORT_SYM_FROM,
94 SORT_SYM_TO,
95 SORT_MISPREDICT,
85}; 96};
86 97
87/* 98/*
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 92e068517c1a..2eeb51baf077 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -1,4 +1,5 @@
1#include "cache.h" 1#include "cache.h"
2#include <linux/kernel.h>
2 3
3int prefixcmp(const char *str, const char *prefix) 4int prefixcmp(const char *str, const char *prefix)
4{ 5{
@@ -89,14 +90,14 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
89 if (!strbuf_avail(sb)) 90 if (!strbuf_avail(sb))
90 strbuf_grow(sb, 64); 91 strbuf_grow(sb, 64);
91 va_start(ap, fmt); 92 va_start(ap, fmt);
92 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 93 len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
93 va_end(ap); 94 va_end(ap);
94 if (len < 0) 95 if (len < 0)
95 die("your vsnprintf is broken"); 96 die("your vscnprintf is broken");
96 if (len > strbuf_avail(sb)) { 97 if (len > strbuf_avail(sb)) {
97 strbuf_grow(sb, len); 98 strbuf_grow(sb, len);
98 va_start(ap, fmt); 99 va_start(ap, fmt);
99 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 100 len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
100 va_end(ap); 101 va_end(ap);
101 if (len > strbuf_avail(sb)) { 102 if (len > strbuf_avail(sb)) {
102 die("this should not happen, your snprintf is broken"); 103 die("this should not happen, your snprintf is broken");
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 0975438c3e72..c0a028c3ebaf 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,7 +1,5 @@
1#include <ctype.h>
2#include <dirent.h> 1#include <dirent.h>
3#include <errno.h> 2#include <errno.h>
4#include <libgen.h>
5#include <stdlib.h> 3#include <stdlib.h>
6#include <stdio.h> 4#include <stdio.h>
7#include <string.h> 5#include <string.h>
@@ -12,6 +10,7 @@
12#include <unistd.h> 10#include <unistd.h>
13#include <inttypes.h> 11#include <inttypes.h>
14#include "build-id.h" 12#include "build-id.h"
13#include "util.h"
15#include "debug.h" 14#include "debug.h"
16#include "symbol.h" 15#include "symbol.h"
17#include "strlist.h" 16#include "strlist.h"
@@ -51,6 +50,8 @@ struct symbol_conf symbol_conf = {
51 50
52int dso__name_len(const struct dso *dso) 51int dso__name_len(const struct dso *dso)
53{ 52{
53 if (!dso)
54 return strlen("[unknown]");
54 if (verbose) 55 if (verbose)
55 return dso->long_name_len; 56 return dso->long_name_len;
56 57
@@ -263,6 +264,28 @@ static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
263 sym->name); 264 sym->name);
264} 265}
265 266
267size_t symbol__fprintf_symname_offs(const struct symbol *sym,
268 const struct addr_location *al, FILE *fp)
269{
270 unsigned long offset;
271 size_t length;
272
273 if (sym && sym->name) {
274 length = fprintf(fp, "%s", sym->name);
275 if (al) {
276 offset = al->addr - sym->start;
277 length += fprintf(fp, "+0x%lx", offset);
278 }
279 return length;
280 } else
281 return fprintf(fp, "[unknown]");
282}
283
284size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
285{
286 return symbol__fprintf_symname_offs(sym, NULL, fp);
287}
288
266void dso__set_long_name(struct dso *dso, char *name) 289void dso__set_long_name(struct dso *dso, char *name)
267{ 290{
268 if (name == NULL) 291 if (name == NULL)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 123c2e14353e..ac49ef208a5f 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -5,6 +5,7 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include <stdint.h> 6#include <stdint.h>
7#include "map.h" 7#include "map.h"
8#include "../perf.h"
8#include <linux/list.h> 9#include <linux/list.h>
9#include <linux/rbtree.h> 10#include <linux/rbtree.h>
10#include <stdio.h> 11#include <stdio.h>
@@ -70,6 +71,7 @@ struct symbol_conf {
70 unsigned short priv_size; 71 unsigned short priv_size;
71 unsigned short nr_events; 72 unsigned short nr_events;
72 bool try_vmlinux_path, 73 bool try_vmlinux_path,
74 show_kernel_path,
73 use_modules, 75 use_modules,
74 sort_by_name, 76 sort_by_name,
75 show_nr_samples, 77 show_nr_samples,
@@ -95,7 +97,11 @@ struct symbol_conf {
95 *col_width_list_str; 97 *col_width_list_str;
96 struct strlist *dso_list, 98 struct strlist *dso_list,
97 *comm_list, 99 *comm_list,
98 *sym_list; 100 *sym_list,
101 *dso_from_list,
102 *dso_to_list,
103 *sym_from_list,
104 *sym_to_list;
99 const char *symfs; 105 const char *symfs;
100}; 106};
101 107
@@ -119,6 +125,19 @@ struct map_symbol {
119 bool has_children; 125 bool has_children;
120}; 126};
121 127
128struct addr_map_symbol {
129 struct map *map;
130 struct symbol *sym;
131 u64 addr;
132 u64 al_addr;
133};
134
135struct branch_info {
136 struct addr_map_symbol from;
137 struct addr_map_symbol to;
138 struct branch_flags flags;
139};
140
122struct addr_location { 141struct addr_location {
123 struct thread *thread; 142 struct thread *thread;
124 struct map *map; 143 struct map *map;
@@ -241,6 +260,9 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines);
241 260
242int symbol__init(void); 261int symbol__init(void);
243void symbol__exit(void); 262void symbol__exit(void);
263size_t symbol__fprintf_symname_offs(const struct symbol *sym,
264 const struct addr_location *al, FILE *fp);
265size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
244bool symbol_type__is_a(char symbol_type, enum map_type map_type); 266bool symbol_type__is_a(char symbol_type, enum map_type map_type);
245 267
246size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 268size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
new file mode 100644
index 000000000000..48c6902e749f
--- /dev/null
+++ b/tools/perf/util/sysfs.c
@@ -0,0 +1,60 @@
1
2#include "util.h"
3#include "sysfs.h"
4
5static const char * const sysfs_known_mountpoints[] = {
6 "/sys",
7 0,
8};
9
10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX];
12
13static int sysfs_valid_mountpoint(const char *sysfs)
14{
15 struct statfs st_fs;
16
17 if (statfs(sysfs, &st_fs) < 0)
18 return -ENOENT;
19 else if (st_fs.f_type != (long) SYSFS_MAGIC)
20 return -ENOENT;
21
22 return 0;
23}
24
25const char *sysfs_find_mountpoint(void)
26{
27 const char * const *ptr;
28 char type[100];
29 FILE *fp;
30
31 if (sysfs_found)
32 return (const char *) sysfs_mountpoint;
33
34 ptr = sysfs_known_mountpoints;
35 while (*ptr) {
36 if (sysfs_valid_mountpoint(*ptr) == 0) {
37 sysfs_found = 1;
38 strcpy(sysfs_mountpoint, *ptr);
39 return sysfs_mountpoint;
40 }
41 ptr++;
42 }
43
44 /* give up and parse /proc/mounts */
45 fp = fopen("/proc/mounts", "r");
46 if (fp == NULL)
47 return NULL;
48
49 while (!sysfs_found &&
50 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
51 sysfs_mountpoint, type) == 2) {
52
53 if (strcmp(type, "sysfs") == 0)
54 sysfs_found = 1;
55 }
56
57 fclose(fp);
58
59 return sysfs_found ? sysfs_mountpoint : NULL;
60}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
new file mode 100644
index 000000000000..a813b7203938
--- /dev/null
+++ b/tools/perf/util/sysfs.h
@@ -0,0 +1,6 @@
1#ifndef __SYSFS_H__
2#define __SYSFS_H__
3
4const char *sysfs_find_mountpoint(void);
5
6#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index a5df131b77c3..84d9bd782004 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -1,6 +1,13 @@
1#include <dirent.h> 1#include <dirent.h>
2#include <limits.h>
3#include <stdbool.h>
2#include <stdlib.h> 4#include <stdlib.h>
3#include <stdio.h> 5#include <stdio.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include "strlist.h"
10#include <string.h>
4#include "thread_map.h" 11#include "thread_map.h"
5 12
6/* Skip "." and ".." directories */ 13/* Skip "." and ".." directories */
@@ -23,7 +30,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
23 sprintf(name, "/proc/%d/task", pid); 30 sprintf(name, "/proc/%d/task", pid);
24 items = scandir(name, &namelist, filter, NULL); 31 items = scandir(name, &namelist, filter, NULL);
25 if (items <= 0) 32 if (items <= 0)
26 return NULL; 33 return NULL;
27 34
28 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); 35 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
29 if (threads != NULL) { 36 if (threads != NULL) {
@@ -51,14 +58,240 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
51 return threads; 58 return threads;
52} 59}
53 60
54struct thread_map *thread_map__new(pid_t pid, pid_t tid) 61struct thread_map *thread_map__new_by_uid(uid_t uid)
62{
63 DIR *proc;
64 int max_threads = 32, items, i;
65 char path[256];
66 struct dirent dirent, *next, **namelist = NULL;
67 struct thread_map *threads = malloc(sizeof(*threads) +
68 max_threads * sizeof(pid_t));
69 if (threads == NULL)
70 goto out;
71
72 proc = opendir("/proc");
73 if (proc == NULL)
74 goto out_free_threads;
75
76 threads->nr = 0;
77
78 while (!readdir_r(proc, &dirent, &next) && next) {
79 char *end;
80 bool grow = false;
81 struct stat st;
82 pid_t pid = strtol(dirent.d_name, &end, 10);
83
84 if (*end) /* only interested in proper numerical dirents */
85 continue;
86
87 snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
88
89 if (stat(path, &st) != 0)
90 continue;
91
92 if (st.st_uid != uid)
93 continue;
94
95 snprintf(path, sizeof(path), "/proc/%d/task", pid);
96 items = scandir(path, &namelist, filter, NULL);
97 if (items <= 0)
98 goto out_free_closedir;
99
100 while (threads->nr + items >= max_threads) {
101 max_threads *= 2;
102 grow = true;
103 }
104
105 if (grow) {
106 struct thread_map *tmp;
107
108 tmp = realloc(threads, (sizeof(*threads) +
109 max_threads * sizeof(pid_t)));
110 if (tmp == NULL)
111 goto out_free_namelist;
112
113 threads = tmp;
114 }
115
116 for (i = 0; i < items; i++)
117 threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
118
119 for (i = 0; i < items; i++)
120 free(namelist[i]);
121 free(namelist);
122
123 threads->nr += items;
124 }
125
126out_closedir:
127 closedir(proc);
128out:
129 return threads;
130
131out_free_threads:
132 free(threads);
133 return NULL;
134
135out_free_namelist:
136 for (i = 0; i < items; i++)
137 free(namelist[i]);
138 free(namelist);
139
140out_free_closedir:
141 free(threads);
142 threads = NULL;
143 goto out_closedir;
144}
145
146struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
55{ 147{
56 if (pid != -1) 148 if (pid != -1)
57 return thread_map__new_by_pid(pid); 149 return thread_map__new_by_pid(pid);
150
151 if (tid == -1 && uid != UINT_MAX)
152 return thread_map__new_by_uid(uid);
153
58 return thread_map__new_by_tid(tid); 154 return thread_map__new_by_tid(tid);
59} 155}
60 156
157static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
158{
159 struct thread_map *threads = NULL, *nt;
160 char name[256];
161 int items, total_tasks = 0;
162 struct dirent **namelist = NULL;
163 int i, j = 0;
164 pid_t pid, prev_pid = INT_MAX;
165 char *end_ptr;
166 struct str_node *pos;
167 struct strlist *slist = strlist__new(false, pid_str);
168
169 if (!slist)
170 return NULL;
171
172 strlist__for_each(pos, slist) {
173 pid = strtol(pos->s, &end_ptr, 10);
174
175 if (pid == INT_MIN || pid == INT_MAX ||
176 (*end_ptr != '\0' && *end_ptr != ','))
177 goto out_free_threads;
178
179 if (pid == prev_pid)
180 continue;
181
182 sprintf(name, "/proc/%d/task", pid);
183 items = scandir(name, &namelist, filter, NULL);
184 if (items <= 0)
185 goto out_free_threads;
186
187 total_tasks += items;
188 nt = realloc(threads, (sizeof(*threads) +
189 sizeof(pid_t) * total_tasks));
190 if (nt == NULL)
191 goto out_free_threads;
192
193 threads = nt;
194
195 if (threads) {
196 for (i = 0; i < items; i++)
197 threads->map[j++] = atoi(namelist[i]->d_name);
198 threads->nr = total_tasks;
199 }
200
201 for (i = 0; i < items; i++)
202 free(namelist[i]);
203 free(namelist);
204
205 if (!threads)
206 break;
207 }
208
209out:
210 strlist__delete(slist);
211 return threads;
212
213out_free_threads:
214 free(threads);
215 threads = NULL;
216 goto out;
217}
218
219static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
220{
221 struct thread_map *threads = NULL, *nt;
222 int ntasks = 0;
223 pid_t tid, prev_tid = INT_MAX;
224 char *end_ptr;
225 struct str_node *pos;
226 struct strlist *slist;
227
228 /* perf-stat expects threads to be generated even if tid not given */
229 if (!tid_str) {
230 threads = malloc(sizeof(*threads) + sizeof(pid_t));
231 if (threads != NULL) {
232 threads->map[0] = -1;
233 threads->nr = 1;
234 }
235 return threads;
236 }
237
238 slist = strlist__new(false, tid_str);
239 if (!slist)
240 return NULL;
241
242 strlist__for_each(pos, slist) {
243 tid = strtol(pos->s, &end_ptr, 10);
244
245 if (tid == INT_MIN || tid == INT_MAX ||
246 (*end_ptr != '\0' && *end_ptr != ','))
247 goto out_free_threads;
248
249 if (tid == prev_tid)
250 continue;
251
252 ntasks++;
253 nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks);
254
255 if (nt == NULL)
256 goto out_free_threads;
257
258 threads = nt;
259 threads->map[ntasks - 1] = tid;
260 threads->nr = ntasks;
261 }
262out:
263 return threads;
264
265out_free_threads:
266 free(threads);
267 threads = NULL;
268 goto out;
269}
270
271struct thread_map *thread_map__new_str(const char *pid, const char *tid,
272 uid_t uid)
273{
274 if (pid)
275 return thread_map__new_by_pid_str(pid);
276
277 if (!tid && uid != UINT_MAX)
278 return thread_map__new_by_uid(uid);
279
280 return thread_map__new_by_tid_str(tid);
281}
282
61void thread_map__delete(struct thread_map *threads) 283void thread_map__delete(struct thread_map *threads)
62{ 284{
63 free(threads); 285 free(threads);
64} 286}
287
288size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
289{
290 int i;
291 size_t printed = fprintf(fp, "%d thread%s: ",
292 threads->nr, threads->nr > 1 ? "s" : "");
293 for (i = 0; i < threads->nr; ++i)
294 printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
295
296 return printed + fprintf(fp, "\n");
297}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 3cb907311409..7da80f14418b 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -2,6 +2,7 @@
2#define __PERF_THREAD_MAP_H 2#define __PERF_THREAD_MAP_H
3 3
4#include <sys/types.h> 4#include <sys/types.h>
5#include <stdio.h>
5 6
6struct thread_map { 7struct thread_map {
7 int nr; 8 int nr;
@@ -10,6 +11,14 @@ struct thread_map {
10 11
11struct thread_map *thread_map__new_by_pid(pid_t pid); 12struct thread_map *thread_map__new_by_pid(pid_t pid);
12struct thread_map *thread_map__new_by_tid(pid_t tid); 13struct thread_map *thread_map__new_by_tid(pid_t tid);
13struct thread_map *thread_map__new(pid_t pid, pid_t tid); 14struct thread_map *thread_map__new_by_uid(uid_t uid);
15struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
16
17struct thread_map *thread_map__new_str(const char *pid,
18 const char *tid, uid_t uid);
19
14void thread_map__delete(struct thread_map *threads); 20void thread_map__delete(struct thread_map *threads);
21
22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
23
15#endif /* __PERF_THREAD_MAP_H */ 24#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 500471dffa4f..09fe579ccafb 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,12 +69,15 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
69 69
70 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
71 71
72 if (top->target_pid != -1) 72 if (top->target_pid)
73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d", 73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
74 top->target_pid); 74 top->target_pid);
75 else if (top->target_tid != -1) 75 else if (top->target_tid)
76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d", 76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
77 top->target_tid); 77 top->target_tid);
78 else if (top->uid_str != NULL)
79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
80 top->uid_str);
78 else 81 else
79 ret += SNPRINTF(bf + ret, size - ret, " (all"); 82 ret += SNPRINTF(bf + ret, size - ret, " (all");
80 83
@@ -82,7 +85,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
82 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
83 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); 86 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
84 else { 87 else {
85 if (top->target_tid != -1) 88 if (top->target_tid)
86 ret += SNPRINTF(bf + ret, size - ret, ")"); 89 ret += SNPRINTF(bf + ret, size - ret, ")");
87 else 90 else
88 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index a248f3c2c60d..ce61cb2d1acf 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -23,7 +23,8 @@ struct perf_top {
23 u64 guest_us_samples, guest_kernel_samples; 23 u64 guest_us_samples, guest_kernel_samples;
24 int print_entries, count_filter, delay_secs; 24 int print_entries, count_filter, delay_secs;
25 int freq; 25 int freq;
26 pid_t target_pid, target_tid; 26 const char *target_pid, *target_tid;
27 uid_t uid;
27 bool hide_kernel_symbols, hide_user_symbols, zero; 28 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool system_wide; 29 bool system_wide;
29 bool use_tui, use_stdio; 30 bool use_tui, use_stdio;
@@ -33,7 +34,8 @@ struct perf_top {
33 bool vmlinux_warned; 34 bool vmlinux_warned;
34 bool inherit; 35 bool inherit;
35 bool group; 36 bool group;
36 bool sample_id_all_avail; 37 bool sample_id_all_missing;
38 bool exclude_guest_missing;
37 bool dump_symtab; 39 bool dump_symtab;
38 const char *cpu_list; 40 const char *cpu_list;
39 struct hist_entry *sym_filter_entry; 41 struct hist_entry *sym_filter_entry;
@@ -45,6 +47,7 @@ struct perf_top {
45 int realtime_prio; 47 int realtime_prio;
46 int sym_pcnt_filter; 48 int sym_pcnt_filter;
47 const char *sym_filter; 49 const char *sym_filter;
50 const char *uid_str;
48}; 51};
49 52
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 53size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 1a8d4dc4f386..dfd1bd8371a4 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -25,7 +25,6 @@
25#include <stdio.h> 25#include <stdio.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <string.h> 27#include <string.h>
28#include <ctype.h>
29#include <errno.h> 28#include <errno.h>
30 29
31#include "../perf.h" 30#include "../perf.h"
@@ -723,7 +722,7 @@ static char *event_read_name(void)
723static int event_read_id(void) 722static int event_read_id(void)
724{ 723{
725 char *token; 724 char *token;
726 int id; 725 int id = -1;
727 726
728 if (read_expected_item(EVENT_ITEM, "ID") < 0) 727 if (read_expected_item(EVENT_ITEM, "ID") < 0)
729 return -1; 728 return -1;
@@ -732,15 +731,13 @@ static int event_read_id(void)
732 return -1; 731 return -1;
733 732
734 if (read_expect_type(EVENT_ITEM, &token) < 0) 733 if (read_expect_type(EVENT_ITEM, &token) < 0)
735 goto fail; 734 goto free;
736 735
737 id = strtoul(token, NULL, 0); 736 id = strtoul(token, NULL, 0);
738 free_token(token);
739 return id;
740 737
741 fail: 738 free:
742 free_token(token); 739 free_token(token);
743 return -1; 740 return id;
744} 741}
745 742
746static int field_is_string(struct format_field *field) 743static int field_is_string(struct format_field *field)
@@ -1424,6 +1421,11 @@ static long long arg_num_eval(struct print_arg *arg)
1424 die("unknown op '%s'", arg->op.op); 1421 die("unknown op '%s'", arg->op.op);
1425 } 1422 }
1426 break; 1423 break;
1424 case '+':
1425 left = arg_num_eval(arg->op.left);
1426 right = arg_num_eval(arg->op.right);
1427 val = left + right;
1428 break;
1427 default: 1429 default:
1428 die("unknown op '%s'", arg->op.op); 1430 die("unknown op '%s'", arg->op.op);
1429 } 1431 }
@@ -1484,6 +1486,13 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1484 1486
1485 free_token(token); 1487 free_token(token);
1486 type = process_arg(event, arg, &token); 1488 type = process_arg(event, arg, &token);
1489
1490 if (type == EVENT_OP)
1491 type = process_op(event, arg, &token);
1492
1493 if (type == EVENT_ERROR)
1494 goto out_free;
1495
1487 if (test_type_token(type, token, EVENT_DELIM, ",")) 1496 if (test_type_token(type, token, EVENT_DELIM, ","))
1488 goto out_free; 1497 goto out_free;
1489 1498
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index f55cc3a765a1..b9592e0de8d7 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -33,7 +33,6 @@
33#include <pthread.h> 33#include <pthread.h>
34#include <fcntl.h> 34#include <fcntl.h>
35#include <unistd.h> 35#include <unistd.h>
36#include <ctype.h>
37#include <errno.h> 36#include <errno.h>
38 37
39#include "../perf.h" 38#include "../perf.h"
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index a3fdf55f317b..18ae6c1831d3 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -22,7 +22,6 @@
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <ctype.h>
26#include <errno.h> 25#include <errno.h>
27 26
28#include "../perf.h" 27#include "../perf.h"
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 84d761b730c1..6ee82f60feaf 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -49,6 +49,8 @@ int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...); 49 const char *format, ...);
50int ui_browser__help_window(struct ui_browser *browser, const char *text); 50int ui_browser__help_window(struct ui_browser *browser, const char *text);
51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); 51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
52int ui_browser__input_window(const char *title, const char *text, char *input,
53 const char *exit_msg, int delay_sec);
52 54
53void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); 55void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
54unsigned int ui_browser__argv_refresh(struct ui_browser *browser); 56unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 295a9c93f945..57a4c6ef3fd2 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -69,14 +69,17 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
69 if (!self->navkeypressed) 69 if (!self->navkeypressed)
70 width += 1; 70 width += 1;
71 71
72 if (!ab->hide_src_code && ol->offset != -1)
73 if (!current_entry || (self->use_navkeypressed &&
74 !self->navkeypressed))
75 ui_browser__set_color(self, HE_COLORSET_CODE);
76
72 if (!*ol->line) 77 if (!*ol->line)
73 slsmg_write_nstring(" ", width - 18); 78 slsmg_write_nstring(" ", width - 18);
74 else 79 else
75 slsmg_write_nstring(ol->line, width - 18); 80 slsmg_write_nstring(ol->line, width - 18);
76 81
77 if (!current_entry) 82 if (current_entry)
78 ui_browser__set_color(self, HE_COLORSET_CODE);
79 else
80 ab->selection = ol; 83 ab->selection = ol;
81} 84}
82 85
@@ -230,9 +233,9 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
230 struct rb_node *nd = NULL; 233 struct rb_node *nd = NULL;
231 struct map_symbol *ms = self->b.priv; 234 struct map_symbol *ms = self->b.priv;
232 struct symbol *sym = ms->sym; 235 struct symbol *sym = ms->sym;
233 const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, " 236 const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
234 "H: Hottest, -> Line action, S -> Toggle source " 237 "H: Go to hottest line, ->/ENTER: Line action, "
235 "code view"; 238 "S: Toggle source code view";
236 int key; 239 int key;
237 240
238 if (ui_browser__show(&self->b, sym->name, help) < 0) 241 if (ui_browser__show(&self->b, sym->name, help) < 0)
@@ -284,9 +287,11 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
284 nd = self->curr_hot; 287 nd = self->curr_hot;
285 break; 288 break;
286 case 'H': 289 case 'H':
290 case 'h':
287 nd = self->curr_hot; 291 nd = self->curr_hot;
288 break; 292 break;
289 case 'S': 293 case 'S':
294 case 's':
290 if (annotate_browser__toggle_source(self)) 295 if (annotate_browser__toggle_source(self))
291 ui_helpline__puts(help); 296 ui_helpline__puts(help);
292 continue; 297 continue;
@@ -338,6 +343,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
338 pthread_mutex_unlock(&notes->lock); 343 pthread_mutex_unlock(&notes->lock);
339 symbol__tui_annotate(target, ms->map, evidx, 344 symbol__tui_annotate(target, ms->map, evidx,
340 timer, arg, delay_secs); 345 timer, arg, delay_secs);
346 ui_browser__show_title(&self->b, sym->name);
341 } 347 }
342 continue; 348 continue;
343 case K_LEFT: 349 case K_LEFT:
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index e81aef1f2569..d7a1c4afe28b 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -805,8 +805,11 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
805 self->hists = hists; 805 self->hists = hists;
806 self->b.refresh = hist_browser__refresh; 806 self->b.refresh = hist_browser__refresh;
807 self->b.seek = ui_browser__hists_seek; 807 self->b.seek = ui_browser__hists_seek;
808 self->b.use_navkeypressed = true, 808 self->b.use_navkeypressed = true;
809 self->has_symbols = sort_sym.list.next != NULL; 809 if (sort__branch_mode == 1)
810 self->has_symbols = sort_sym_from.list.next != NULL;
811 else
812 self->has_symbols = sort_sym.list.next != NULL;
810 } 813 }
811 814
812 return self; 815 return self;
@@ -837,19 +840,32 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
837 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE]; 840 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
838 841
839 nr_events = convert_unit(nr_events, &unit); 842 nr_events = convert_unit(nr_events, &unit);
840 printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name); 843 printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
841 844
842 if (thread) 845 if (self->uid_filter_str)
843 printed += snprintf(bf + printed, size - printed, 846 printed += snprintf(bf + printed, size - printed,
847 ", UID: %s", self->uid_filter_str);
848 if (thread)
849 printed += scnprintf(bf + printed, size - printed,
844 ", Thread: %s(%d)", 850 ", Thread: %s(%d)",
845 (thread->comm_set ? thread->comm : ""), 851 (thread->comm_set ? thread->comm : ""),
846 thread->pid); 852 thread->pid);
847 if (dso) 853 if (dso)
848 printed += snprintf(bf + printed, size - printed, 854 printed += scnprintf(bf + printed, size - printed,
849 ", DSO: %s", dso->short_name); 855 ", DSO: %s", dso->short_name);
850 return printed; 856 return printed;
851} 857}
852 858
859static inline void free_popup_options(char **options, int n)
860{
861 int i;
862
863 for (i = 0; i < n; ++i) {
864 free(options[i]);
865 options[i] = NULL;
866 }
867}
868
853static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 869static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
854 const char *helpline, const char *ev_name, 870 const char *helpline, const char *ev_name,
855 bool left_exits, 871 bool left_exits,
@@ -858,8 +874,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
858{ 874{
859 struct hists *self = &evsel->hists; 875 struct hists *self = &evsel->hists;
860 struct hist_browser *browser = hist_browser__new(self); 876 struct hist_browser *browser = hist_browser__new(self);
877 struct branch_info *bi;
861 struct pstack *fstack; 878 struct pstack *fstack;
879 char *options[16];
880 int nr_options = 0;
862 int key = -1; 881 int key = -1;
882 char buf[64];
863 883
864 if (browser == NULL) 884 if (browser == NULL)
865 return -1; 885 return -1;
@@ -870,13 +890,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
870 890
871 ui_helpline__push(helpline); 891 ui_helpline__push(helpline);
872 892
893 memset(options, 0, sizeof(options));
894
873 while (1) { 895 while (1) {
874 const struct thread *thread = NULL; 896 const struct thread *thread = NULL;
875 const struct dso *dso = NULL; 897 const struct dso *dso = NULL;
876 char *options[16]; 898 int choice = 0,
877 int nr_options = 0, choice = 0, i,
878 annotate = -2, zoom_dso = -2, zoom_thread = -2, 899 annotate = -2, zoom_dso = -2, zoom_thread = -2,
879 browse_map = -2; 900 annotate_f = -2, annotate_t = -2, browse_map = -2;
901
902 nr_options = 0;
880 903
881 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs); 904 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
882 905
@@ -884,7 +907,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
884 thread = hist_browser__selected_thread(browser); 907 thread = hist_browser__selected_thread(browser);
885 dso = browser->selection->map ? browser->selection->map->dso : NULL; 908 dso = browser->selection->map ? browser->selection->map->dso : NULL;
886 } 909 }
887
888 switch (key) { 910 switch (key) {
889 case K_TAB: 911 case K_TAB:
890 case K_UNTAB: 912 case K_UNTAB:
@@ -899,7 +921,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
899 if (!browser->has_symbols) { 921 if (!browser->has_symbols) {
900 ui_browser__warning(&browser->b, delay_secs * 2, 922 ui_browser__warning(&browser->b, delay_secs * 2,
901 "Annotation is only available for symbolic views, " 923 "Annotation is only available for symbolic views, "
902 "include \"sym\" in --sort to use it."); 924 "include \"sym*\" in --sort to use it.");
903 continue; 925 continue;
904 } 926 }
905 927
@@ -912,6 +934,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
912 goto zoom_dso; 934 goto zoom_dso;
913 case 't': 935 case 't':
914 goto zoom_thread; 936 goto zoom_thread;
937 case 's':
938 if (ui_browser__input_window("Symbol to show",
939 "Please enter the name of symbol you want to see",
940 buf, "ENTER: OK, ESC: Cancel",
941 delay_secs * 2) == K_ENTER) {
942 self->symbol_filter_str = *buf ? buf : NULL;
943 hists__filter_by_symbol(self);
944 hist_browser__reset(browser);
945 }
946 continue;
915 case K_F1: 947 case K_F1:
916 case 'h': 948 case 'h':
917 case '?': 949 case '?':
@@ -929,7 +961,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
929 "C Collapse all callchains\n" 961 "C Collapse all callchains\n"
930 "E Expand all callchains\n" 962 "E Expand all callchains\n"
931 "d Zoom into current DSO\n" 963 "d Zoom into current DSO\n"
932 "t Zoom into current Thread"); 964 "t Zoom into current Thread\n"
965 "s Filter symbol by name");
933 continue; 966 continue;
934 case K_ENTER: 967 case K_ENTER:
935 case K_RIGHT: 968 case K_RIGHT:
@@ -969,12 +1002,34 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
969 if (!browser->has_symbols) 1002 if (!browser->has_symbols)
970 goto add_exit_option; 1003 goto add_exit_option;
971 1004
972 if (browser->selection != NULL && 1005 if (sort__branch_mode == 1) {
973 browser->selection->sym != NULL && 1006 bi = browser->he_selection->branch_info;
974 !browser->selection->map->dso->annotate_warned && 1007 if (browser->selection != NULL &&
975 asprintf(&options[nr_options], "Annotate %s", 1008 bi &&
976 browser->selection->sym->name) > 0) 1009 bi->from.sym != NULL &&
977 annotate = nr_options++; 1010 !bi->from.map->dso->annotate_warned &&
1011 asprintf(&options[nr_options], "Annotate %s",
1012 bi->from.sym->name) > 0)
1013 annotate_f = nr_options++;
1014
1015 if (browser->selection != NULL &&
1016 bi &&
1017 bi->to.sym != NULL &&
1018 !bi->to.map->dso->annotate_warned &&
1019 (bi->to.sym != bi->from.sym ||
1020 bi->to.map->dso != bi->from.map->dso) &&
1021 asprintf(&options[nr_options], "Annotate %s",
1022 bi->to.sym->name) > 0)
1023 annotate_t = nr_options++;
1024 } else {
1025
1026 if (browser->selection != NULL &&
1027 browser->selection->sym != NULL &&
1028 !browser->selection->map->dso->annotate_warned &&
1029 asprintf(&options[nr_options], "Annotate %s",
1030 browser->selection->sym->name) > 0)
1031 annotate = nr_options++;
1032 }
978 1033
979 if (thread != NULL && 1034 if (thread != NULL &&
980 asprintf(&options[nr_options], "Zoom %s %s(%d) thread", 1035 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
@@ -995,25 +1050,39 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
995 browse_map = nr_options++; 1050 browse_map = nr_options++;
996add_exit_option: 1051add_exit_option:
997 options[nr_options++] = (char *)"Exit"; 1052 options[nr_options++] = (char *)"Exit";
998 1053retry_popup_menu:
999 choice = ui__popup_menu(nr_options, options); 1054 choice = ui__popup_menu(nr_options, options);
1000 1055
1001 for (i = 0; i < nr_options - 1; ++i)
1002 free(options[i]);
1003
1004 if (choice == nr_options - 1) 1056 if (choice == nr_options - 1)
1005 break; 1057 break;
1006 1058
1007 if (choice == -1) 1059 if (choice == -1) {
1060 free_popup_options(options, nr_options - 1);
1008 continue; 1061 continue;
1062 }
1009 1063
1010 if (choice == annotate) { 1064 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
1011 struct hist_entry *he; 1065 struct hist_entry *he;
1012 int err; 1066 int err;
1013do_annotate: 1067do_annotate:
1014 he = hist_browser__selected_entry(browser); 1068 he = hist_browser__selected_entry(browser);
1015 if (he == NULL) 1069 if (he == NULL)
1016 continue; 1070 continue;
1071
1072 /*
1073 * we stash the branch_info symbol + map into the
1074 * the ms so we don't have to rewrite all the annotation
1075 * code to use branch_info.
1076 * in branch mode, the ms struct is not used
1077 */
1078 if (choice == annotate_f) {
1079 he->ms.sym = he->branch_info->from.sym;
1080 he->ms.map = he->branch_info->from.map;
1081 } else if (choice == annotate_t) {
1082 he->ms.sym = he->branch_info->to.sym;
1083 he->ms.map = he->branch_info->to.map;
1084 }
1085
1017 /* 1086 /*
1018 * Don't let this be freed, say, by hists__decay_entry. 1087 * Don't let this be freed, say, by hists__decay_entry.
1019 */ 1088 */
@@ -1021,9 +1090,18 @@ do_annotate:
1021 err = hist_entry__tui_annotate(he, evsel->idx, 1090 err = hist_entry__tui_annotate(he, evsel->idx,
1022 timer, arg, delay_secs); 1091 timer, arg, delay_secs);
1023 he->used = false; 1092 he->used = false;
1093 /*
1094 * offer option to annotate the other branch source or target
1095 * (if they exists) when returning from annotate
1096 */
1097 if ((err == 'q' || err == CTRL('c'))
1098 && annotate_t != -2 && annotate_f != -2)
1099 goto retry_popup_menu;
1100
1024 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1101 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1025 if (err) 1102 if (err)
1026 ui_browser__handle_resize(&browser->b); 1103 ui_browser__handle_resize(&browser->b);
1104
1027 } else if (choice == browse_map) 1105 } else if (choice == browse_map)
1028 map__browse(browser->selection->map); 1106 map__browse(browser->selection->map);
1029 else if (choice == zoom_dso) { 1107 else if (choice == zoom_dso) {
@@ -1069,6 +1147,7 @@ out_free_stack:
1069 pstack__delete(fstack); 1147 pstack__delete(fstack);
1070out: 1148out:
1071 hist_browser__delete(browser); 1149 hist_browser__delete(browser);
1150 free_popup_options(options, nr_options - 1);
1072 return key; 1151 return key;
1073} 1152}
1074 1153
@@ -1095,7 +1174,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1095 HE_COLORSET_NORMAL); 1174 HE_COLORSET_NORMAL);
1096 1175
1097 nr_events = convert_unit(nr_events, &unit); 1176 nr_events = convert_unit(nr_events, &unit);
1098 printed = snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1177 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1099 unit, unit == ' ' ? "" : " ", ev_name); 1178 unit, unit == ' ' ? "" : " ", ev_name);
1100 slsmg_printf("%s", bf); 1179 slsmg_printf("%s", bf);
1101 1180
@@ -1105,8 +1184,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1105 if (!current_entry) 1184 if (!current_entry)
1106 ui_browser__set_color(browser, HE_COLORSET_TOP); 1185 ui_browser__set_color(browser, HE_COLORSET_TOP);
1107 nr_events = convert_unit(nr_events, &unit); 1186 nr_events = convert_unit(nr_events, &unit);
1108 snprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!", nr_events, 1187 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1109 unit, unit == ' ' ? "" : " "); 1188 nr_events, unit, unit == ' ' ? "" : " ");
1110 warn = bf; 1189 warn = bf;
1111 } 1190 }
1112 1191
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index 6905bcc8be2d..eca6575abfd0 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -3,9 +3,9 @@
3#include <newt.h> 3#include <newt.h>
4#include <inttypes.h> 4#include <inttypes.h>
5#include <sys/ttydefaults.h> 5#include <sys/ttydefaults.h>
6#include <ctype.h>
7#include <string.h> 6#include <string.h>
8#include <linux/bitops.h> 7#include <linux/bitops.h>
8#include "../../util.h"
9#include "../../debug.h" 9#include "../../debug.h"
10#include "../../symbol.h" 10#include "../../symbol.h"
11#include "../browser.h" 11#include "../browser.h"
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
index 4f48f5901b30..2f950c2641c8 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/util/ui/helpline.c
@@ -64,7 +64,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
64 static int backlog; 64 static int backlog;
65 65
66 pthread_mutex_lock(&ui__lock); 66 pthread_mutex_lock(&ui__lock);
67 ret = vsnprintf(ui_helpline__last_msg + backlog, 67 ret = vscnprintf(ui_helpline__last_msg + backlog,
68 sizeof(ui_helpline__last_msg) - backlog, format, ap); 68 sizeof(ui_helpline__last_msg) - backlog, format, ap);
69 backlog += ret; 69 backlog += ret;
70 70
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
index 3458b1985761..809eca5707fa 100644
--- a/tools/perf/util/ui/keysyms.h
+++ b/tools/perf/util/ui/keysyms.h
@@ -16,6 +16,8 @@
16#define K_TAB '\t' 16#define K_TAB '\t'
17#define K_UNTAB SL_KEY_UNTAB 17#define K_UNTAB SL_KEY_UNTAB
18#define K_UP SL_KEY_UP 18#define K_UP SL_KEY_UP
19#define K_BKSPC 0x7f
20#define K_DEL SL_KEY_DELETE
19 21
20/* Not really keys */ 22/* Not really keys */
21#define K_TIMER -1 23#define K_TIMER -1
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 45daa7c41dad..ad4374a16bb0 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -69,6 +69,88 @@ int ui__popup_menu(int argc, char * const argv[])
69 return popup_menu__run(&menu); 69 return popup_menu__run(&menu);
70} 70}
71 71
72int ui_browser__input_window(const char *title, const char *text, char *input,
73 const char *exit_msg, int delay_secs)
74{
75 int x, y, len, key;
76 int max_len = 60, nr_lines = 0;
77 static char buf[50];
78 const char *t;
79
80 t = text;
81 while (1) {
82 const char *sep = strchr(t, '\n');
83
84 if (sep == NULL)
85 sep = strchr(t, '\0');
86 len = sep - t;
87 if (max_len < len)
88 max_len = len;
89 ++nr_lines;
90 if (*sep == '\0')
91 break;
92 t = sep + 1;
93 }
94
95 max_len += 2;
96 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
98 x = SLtt_Screen_Cols / 2 - max_len / 2;
99
100 SLsmg_set_color(0);
101 SLsmg_draw_box(y, x++, nr_lines, max_len);
102 if (title) {
103 SLsmg_gotorc(y, x + 1);
104 SLsmg_write_string((char *)title);
105 }
106 SLsmg_gotorc(++y, x);
107 nr_lines -= 7;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 y += nr_lines;
112 len = 5;
113 while (len--) {
114 SLsmg_gotorc(y + len - 1, x);
115 SLsmg_write_nstring((char *)" ", max_len);
116 }
117 SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
118
119 SLsmg_gotorc(y + 3, x);
120 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh();
122
123 x += 2;
124 len = 0;
125 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
127 if (key == K_BKSPC) {
128 if (len == 0)
129 goto next_key;
130 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' ');
132 } else {
133 buf[len] = key;
134 SLsmg_gotorc(y, x + len++);
135 SLsmg_write_char(key);
136 }
137 SLsmg_refresh();
138
139 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!");
142 key = K_ENTER;
143 break;
144 }
145next_key:
146 key = ui__getch(delay_secs);
147 }
148
149 buf[len] = '\0';
150 strncpy(input, buf, len+1);
151 return key;
152}
153
72int ui__question_window(const char *title, const char *text, 154int ui__question_window(const char *title, const char *text,
73 const char *exit_msg, int delay_secs) 155 const char *exit_msg, int delay_secs)
74{ 156{
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index d76d1c0ff98f..52bb07c6442a 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -7,6 +7,7 @@
7 * Copyright (C) Linus Torvalds, 2005 7 * Copyright (C) Linus Torvalds, 2005
8 */ 8 */
9#include "util.h" 9#include "util.h"
10#include "debug.h"
10 11
11static void report(const char *prefix, const char *err, va_list params) 12static void report(const char *prefix, const char *err, va_list params)
12{ 13{
@@ -81,3 +82,41 @@ void warning(const char *warn, ...)
81 warn_routine(warn, params); 82 warn_routine(warn, params);
82 va_end(params); 83 va_end(params);
83} 84}
85
86uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
87{
88 struct passwd pwd, *result;
89 char buf[1024];
90
91 if (str == NULL)
92 return UINT_MAX;
93
94 /* UID and PID are mutually exclusive */
95 if (tid || pid) {
96 ui__warning("PID/TID switch overriding UID\n");
97 sleep(1);
98 return UINT_MAX;
99 }
100
101 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
102
103 if (result == NULL) {
104 char *endptr;
105 int uid = strtol(str, &endptr, 10);
106
107 if (*endptr != '\0') {
108 ui__error("Invalid user %s\n", str);
109 return UINT_MAX - 1;
110 }
111
112 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
113
114 if (result == NULL) {
115 ui__error("Problems obtaining information for user %s\n",
116 str);
117 return UINT_MAX - 1;
118 }
119 }
120
121 return result->pw_uid;
122}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 813141047fc2..8109a907841e 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -6,7 +6,7 @@
6 * XXX We need to find a better place for these things... 6 * XXX We need to find a better place for these things...
7 */ 7 */
8bool perf_host = true; 8bool perf_host = true;
9bool perf_guest = true; 9bool perf_guest = false;
10 10
11void event_attr_init(struct perf_event_attr *attr) 11void event_attr_init(struct perf_event_attr *attr)
12{ 12{
@@ -14,6 +14,8 @@ void event_attr_init(struct perf_event_attr *attr)
14 attr->exclude_host = 1; 14 attr->exclude_host = 1;
15 if (!perf_guest) 15 if (!perf_guest)
16 attr->exclude_guest = 1; 16 attr->exclude_guest = 1;
17 /* to capture ABI version */
18 attr->size = sizeof(*attr);
17} 19}
18 20
19int mkdir_p(char *path, mode_t mode) 21int mkdir_p(char *path, mode_t mode)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index ecf9898169c8..0f99f394d8e0 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -199,6 +199,8 @@ static inline int has_extension(const char *filename, const char *ext)
199#undef isalpha 199#undef isalpha
200#undef isprint 200#undef isprint
201#undef isalnum 201#undef isalnum
202#undef islower
203#undef isupper
202#undef tolower 204#undef tolower
203#undef toupper 205#undef toupper
204 206
@@ -219,6 +221,8 @@ extern unsigned char sane_ctype[256];
219#define isalpha(x) sane_istest(x,GIT_ALPHA) 221#define isalpha(x) sane_istest(x,GIT_ALPHA)
220#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 222#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
221#define isprint(x) sane_istest(x,GIT_PRINT) 223#define isprint(x) sane_istest(x,GIT_PRINT)
224#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20))
225#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20))
222#define tolower(x) sane_case((unsigned char)(x), 0x20) 226#define tolower(x) sane_case((unsigned char)(x), 0x20)
223#define toupper(x) sane_case((unsigned char)(x), 0) 227#define toupper(x) sane_case((unsigned char)(x), 0)
224 228
@@ -245,6 +249,8 @@ struct perf_event_attr;
245 249
246void event_attr_init(struct perf_event_attr *attr); 250void event_attr_init(struct perf_event_attr *attr);
247 251
252uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
253
248#define _STR(x) #x 254#define _STR(x) #x
249#define STR(x) _STR(x) 255#define STR(x) _STR(x)
250 256