aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2013-03-18 05:57:32 -0400
committerJiri Kosina <jkosina@suse.cz>2013-03-18 05:57:57 -0400
commitaa1262b3876ec5249ff464618a7dcd46b3ca54e2 (patch)
treeb150bb2c83c073e1f0e298ba7899148f7d991ef7 /tools/perf/util
parent806b2139db236e0cbd0b5833ab0ce139f0196bcd (diff)
parent6dbe51c251a327e012439c4772097a13df43c5b8 (diff)
Merge branch 'master' into for-next
Sync with Linus' tree to be able to apply patch to the newly added ITG-3200 driver.
Diffstat (limited to 'tools/perf/util')
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN4
-rw-r--r--tools/perf/util/annotate.c2
-rw-r--r--tools/perf/util/annotate.h24
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h5
-rw-r--r--tools/perf/util/cpumap.c54
-rw-r--r--tools/perf/util/cpumap.h9
-rw-r--r--tools/perf/util/debug.c28
-rw-r--r--tools/perf/util/debug.h34
-rw-r--r--tools/perf/util/dso.c6
-rw-r--r--tools/perf/util/dso.h2
-rw-r--r--tools/perf/util/event.c4
-rw-r--r--tools/perf/util/evlist.c34
-rw-r--r--tools/perf/util/evlist.h34
-rw-r--r--tools/perf/util/evsel.c370
-rw-r--r--tools/perf/util/evsel.h50
-rw-r--r--tools/perf/util/header.c266
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c142
-rw-r--r--tools/perf/util/hist.h26
-rw-r--r--tools/perf/util/include/linux/bitops.h1
-rw-r--r--tools/perf/util/intlist.c36
-rw-r--r--tools/perf/util/intlist.h2
-rw-r--r--tools/perf/util/machine.c784
-rw-r--r--tools/perf/util/machine.h41
-rw-r--r--tools/perf/util/map.c121
-rw-r--r--tools/perf/util/map.h24
-rw-r--r--tools/perf/util/parse-events.c96
-rw-r--r--tools/perf/util/parse-events.h22
-rw-r--r--tools/perf/util/parse-events.y75
-rw-r--r--tools/perf/util/pmu.c46
-rw-r--r--tools/perf/util/pmu.h15
-rw-r--r--tools/perf/util/pmu.y1
-rw-r--r--tools/perf/util/probe-finder.c10
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/python.c9
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c325
-rw-r--r--tools/perf/util/session.h35
-rw-r--r--tools/perf/util/sort.c245
-rw-r--r--tools/perf/util/sort.h15
-rw-r--r--tools/perf/util/string.c18
-rw-r--r--tools/perf/util/strlist.c54
-rw-r--r--tools/perf/util/strlist.h42
-rw-r--r--tools/perf/util/symbol-elf.c14
-rw-r--r--tools/perf/util/symbol-minimal.c1
-rw-r--r--tools/perf/util/symbol.c536
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/sysfs.c2
-rw-r--r--tools/perf/util/thread.c20
-rw-r--r--tools/perf/util/thread.h1
-rw-r--r--tools/perf/util/top.c22
-rw-r--r--tools/perf/util/top.h10
-rw-r--r--tools/perf/util/util.c24
-rw-r--r--tools/perf/util/util.h4
56 files changed, 2339 insertions, 1422 deletions
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 6aa34e5afdcf..055fef34b6f6 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -26,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)')
26 26
27if test -r $GVF 27if test -r $GVF
28then 28then
29 VC=$(sed -e 's/^PERF_VERSION = //' <$GVF) 29 VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF)
30else 30else
31 VC=unset 31 VC=unset
32fi 32fi
33test "$VN" = "$VC" || { 33test "$VN" = "$VC" || {
34 echo >&2 "PERF_VERSION = $VN" 34 echo >&2 "PERF_VERSION = $VN"
35 echo "PERF_VERSION = $VN" >$GVF 35 echo "#define PERF_VERSION \"$VN\"" >$GVF
36} 36}
37 37
38 38
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 07aaeea60000..d33fe937e6f1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -809,7 +809,7 @@ fallback:
809 pr_err("Can't annotate %s:\n\n" 809 pr_err("Can't annotate %s:\n\n"
810 "No vmlinux file%s\nwas found in the path.\n\n" 810 "No vmlinux file%s\nwas found in the path.\n\n"
811 "Please use:\n\n" 811 "Please use:\n\n"
812 " perf buildid-cache -av vmlinux\n\n" 812 " perf buildid-cache -vu vmlinux\n\n"
813 "or:\n\n" 813 "or:\n\n"
814 " --vmlinux vmlinux\n", 814 " --vmlinux vmlinux\n",
815 sym->name, build_id_msg ?: ""); 815 sym->name, build_id_msg ?: "");
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 8eec94358a4a..c422440fe611 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -6,6 +6,7 @@
6#include "types.h" 6#include "types.h"
7#include "symbol.h" 7#include "symbol.h"
8#include "hist.h" 8#include "hist.h"
9#include "sort.h"
9#include <linux/list.h> 10#include <linux/list.h>
10#include <linux/rbtree.h> 11#include <linux/rbtree.h>
11#include <pthread.h> 12#include <pthread.h>
@@ -154,6 +155,29 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
154} 155}
155#endif 156#endif
156 157
158#ifdef GTK2_SUPPORT
159int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
160 struct hist_browser_timer *hbt);
161
162static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx,
163 struct hist_browser_timer *hbt)
164{
165 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt);
166}
167
168void perf_gtk__show_annotations(void);
169#else
170static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
171 int evidx __maybe_unused,
172 struct hist_browser_timer *hbt
173 __maybe_unused)
174{
175 return 0;
176}
177
178static inline void perf_gtk__show_annotations(void) {}
179#endif
180
157extern const char *disassembler_style; 181extern const char *disassembler_style;
158 182
159#endif /* __PERF_ANNOTATE_H */ 183#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index d3b3f5d82137..42b6a632fe7b 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
444 struct callchain_cursor_node *node = *cursor->last; 444 struct callchain_cursor_node *node = *cursor->last;
445 445
446 if (!node) { 446 if (!node) {
447 node = calloc(sizeof(*node), 1); 447 node = calloc(1, sizeof(*node));
448 if (!node) 448 if (!node)
449 return -ENOMEM; 449 return -ENOMEM;
450 450
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index eb340571e7d6..3ee9f67d5af0 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
143 cursor->curr = cursor->curr->next; 143 cursor->curr = cursor->curr->next;
144 cursor->pos++; 144 cursor->pos++;
145} 145}
146
147struct option;
148
149int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
150extern const char record_callchain_help[];
146#endif /* __PERF_CALLCHAIN_H */ 151#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 2b32ffa9ebdb..f817046e22b1 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -1,4 +1,5 @@
1#include "util.h" 1#include "util.h"
2#include "sysfs.h"
2#include "../perf.h" 3#include "../perf.h"
3#include "cpumap.h" 4#include "cpumap.h"
4#include <assert.h> 5#include <assert.h>
@@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map)
201{ 202{
202 free(map); 203 free(map);
203} 204}
205
206int cpu_map__get_socket(struct cpu_map *map, int idx)
207{
208 FILE *fp;
209 const char *mnt;
210 char path[PATH_MAX];
211 int cpu, ret;
212
213 if (idx > map->nr)
214 return -1;
215
216 cpu = map->map[idx];
217
218 mnt = sysfs_find_mountpoint();
219 if (!mnt)
220 return -1;
221
222 sprintf(path,
223 "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
224 mnt, cpu);
225
226 fp = fopen(path, "r");
227 if (!fp)
228 return -1;
229 ret = fscanf(fp, "%d", &cpu);
230 fclose(fp);
231 return ret == 1 ? cpu : -1;
232}
233
234int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
235{
236 struct cpu_map *sock;
237 int nr = cpus->nr;
238 int cpu, s1, s2;
239
240 sock = calloc(1, sizeof(*sock) + nr * sizeof(int));
241 if (!sock)
242 return -1;
243
244 for (cpu = 0; cpu < nr; cpu++) {
245 s1 = cpu_map__get_socket(cpus, cpu);
246 for (s2 = 0; s2 < sock->nr; s2++) {
247 if (s1 == sock->map[s2])
248 break;
249 }
250 if (s2 == sock->nr) {
251 sock->map[sock->nr] = s1;
252 sock->nr++;
253 }
254 }
255 *sockp = sock;
256 return 0;
257}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 2f68a3b8c285..161b00756a12 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -14,6 +14,15 @@ struct cpu_map *cpu_map__dummy_new(void);
14void cpu_map__delete(struct cpu_map *map); 14void cpu_map__delete(struct cpu_map *map);
15struct cpu_map *cpu_map__read(FILE *file); 15struct cpu_map *cpu_map__read(FILE *file);
16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
17int cpu_map__get_socket(struct cpu_map *map, int idx);
18int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
19
20static inline int cpu_map__socket(struct cpu_map *sock, int s)
21{
22 if (!sock || s > sock->nr || s < 0)
23 return 0;
24 return sock->map[s];
25}
17 26
18static inline int cpu_map__nr(const struct cpu_map *map) 27static inline int cpu_map__nr(const struct cpu_map *map)
19{ 28{
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 03f830b48148..399e74c34c1a 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -23,10 +23,8 @@ int eprintf(int level, const char *fmt, ...)
23 23
24 if (verbose >= level) { 24 if (verbose >= level) {
25 va_start(args, fmt); 25 va_start(args, fmt);
26 if (use_browser == 1) 26 if (use_browser >= 1)
27 ret = ui_helpline__show_help(fmt, args); 27 ui_helpline__vshow(fmt, args);
28 else if (use_browser == 2)
29 ret = perf_gtk__show_helpline(fmt, args);
30 else 28 else
31 ret = vfprintf(stderr, fmt, args); 29 ret = vfprintf(stderr, fmt, args);
32 va_end(args); 30 va_end(args);
@@ -49,28 +47,6 @@ int dump_printf(const char *fmt, ...)
49 return ret; 47 return ret;
50} 48}
51 49
52#if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT)
53int ui__warning(const char *format, ...)
54{
55 va_list args;
56
57 va_start(args, format);
58 vfprintf(stderr, format, args);
59 va_end(args);
60 return 0;
61}
62#endif
63
64int ui__error_paranoid(void)
65{
66 return ui__error("Permission error - are you root?\n"
67 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
68 " -1 - Not paranoid at all\n"
69 " 0 - Disallow raw tracepoint access for unpriv\n"
70 " 1 - Disallow cpu events for unpriv\n"
71 " 2 - Disallow kernel profiling for unpriv\n");
72}
73
74void trace_event(union perf_event *event) 50void trace_event(union perf_event *event)
75{ 51{
76 unsigned char *raw_event = (void *)event; 52 unsigned char *raw_event = (void *)event;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 83e8d234af6b..efbd98805ad0 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -5,6 +5,8 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include "event.h" 6#include "event.h"
7#include "../ui/helpline.h" 7#include "../ui/helpline.h"
8#include "../ui/progress.h"
9#include "../ui/util.h"
8 10
9extern int verbose; 11extern int verbose;
10extern bool quiet, dump_trace; 12extern bool quiet, dump_trace;
@@ -12,39 +14,7 @@ extern bool quiet, dump_trace;
12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 14int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(union perf_event *event); 15void trace_event(union perf_event *event);
14 16
15struct ui_progress;
16struct perf_error_ops;
17
18#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT)
19
20#include "../ui/progress.h"
21int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
22#include "../ui/util.h"
23
24#else
25
26static inline void ui_progress__update(u64 curr __maybe_unused,
27 u64 total __maybe_unused,
28 const char *title __maybe_unused) {}
29static inline void ui_progress__finish(void) {}
30
31#define ui__error(format, arg...) ui__warning(format, ##arg)
32
33static inline int
34perf_error__register(struct perf_error_ops *eops __maybe_unused)
35{
36 return 0;
37}
38
39static inline int
40perf_error__unregister(struct perf_error_ops *eops __maybe_unused)
41{
42 return 0;
43}
44
45#endif /* NEWT_SUPPORT || GTK2_SUPPORT */
46
47int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
48int ui__error_paranoid(void);
49 19
50#endif /* __PERF_DEBUG_H */ 20#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index d6d9a465acdb..6f7d5a9d6b05 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -539,13 +539,13 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name)
539} 539}
540 540
541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
542 bool with_hits) 542 bool (skip)(struct dso *dso, int parm), int parm)
543{ 543{
544 struct dso *pos; 544 struct dso *pos;
545 size_t ret = 0; 545 size_t ret = 0;
546 546
547 list_for_each_entry(pos, head, node) { 547 list_for_each_entry(pos, head, node) {
548 if (with_hits && !pos->hit) 548 if (skip && skip(pos, parm))
549 continue; 549 continue;
550 ret += dso__fprintf_buildid(pos, fp); 550 ret += dso__fprintf_buildid(pos, fp);
551 ret += fprintf(fp, " %s\n", pos->long_name); 551 ret += fprintf(fp, " %s\n", pos->long_name);
@@ -583,7 +583,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
583 if (dso->short_name != dso->long_name) 583 if (dso->short_name != dso->long_name)
584 ret += fprintf(fp, "%s, ", dso->long_name); 584 ret += fprintf(fp, "%s, ", dso->long_name);
585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
586 dso->loaded ? "" : "NOT "); 586 dso__loaded(dso, type) ? "" : "NOT ");
587 ret += dso__fprintf_buildid(dso, fp); 587 ret += dso__fprintf_buildid(dso, fp);
588 ret += fprintf(fp, ")\n"); 588 ret += fprintf(fp, ")\n");
589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { 589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index e03276940b99..450199ab51b5 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -138,7 +138,7 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name);
138bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 138bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
139 139
140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
141 bool with_hits); 141 bool (skip)(struct dso *dso, int parm), int parm);
142size_t __dsos__fprintf(struct list_head *head, FILE *fp); 142size_t __dsos__fprintf(struct list_head *head, FILE *fp);
143 143
144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); 144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 3cf2c3e0605f..5cd13d768cec 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -476,8 +476,10 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
476 } 476 }
477 } 477 }
478 478
479 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) 479 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) {
480 free(event);
480 return -ENOENT; 481 return -ENOENT;
482 }
481 483
482 map = machine->vmlinux_maps[MAP__FUNCTION]; 484 map = machine->vmlinux_maps[MAP__FUNCTION];
483 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 485 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 705293489e3c..c8be0fbc5145 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -49,10 +49,16 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
49 return evlist; 49 return evlist;
50} 50}
51 51
52void perf_evlist__config_attrs(struct perf_evlist *evlist, 52void perf_evlist__config(struct perf_evlist *evlist,
53 struct perf_record_opts *opts) 53 struct perf_record_opts *opts)
54{ 54{
55 struct perf_evsel *evsel; 55 struct perf_evsel *evsel;
56 /*
57 * Set the evsel leader links before we configure attributes,
58 * since some might depend on this info.
59 */
60 if (opts->group)
61 perf_evlist__set_leader(evlist);
56 62
57 if (evlist->cpus->map[0] < 0) 63 if (evlist->cpus->map[0] < 0)
58 opts->no_inherit = true; 64 opts->no_inherit = true;
@@ -61,7 +67,7 @@ void perf_evlist__config_attrs(struct perf_evlist *evlist,
61 perf_evsel__config(evsel, opts); 67 perf_evsel__config(evsel, opts);
62 68
63 if (evlist->nr_entries > 1) 69 if (evlist->nr_entries > 1)
64 evsel->attr.sample_type |= PERF_SAMPLE_ID; 70 perf_evsel__set_sample_id(evsel);
65 } 71 }
66} 72}
67 73
@@ -111,18 +117,21 @@ void __perf_evlist__set_leader(struct list_head *list)
111 struct perf_evsel *evsel, *leader; 117 struct perf_evsel *evsel, *leader;
112 118
113 leader = list_entry(list->next, struct perf_evsel, node); 119 leader = list_entry(list->next, struct perf_evsel, node);
114 leader->leader = NULL; 120 evsel = list_entry(list->prev, struct perf_evsel, node);
121
122 leader->nr_members = evsel->idx - leader->idx + 1;
115 123
116 list_for_each_entry(evsel, list, node) { 124 list_for_each_entry(evsel, list, node) {
117 if (evsel != leader) 125 evsel->leader = leader;
118 evsel->leader = leader;
119 } 126 }
120} 127}
121 128
122void perf_evlist__set_leader(struct perf_evlist *evlist) 129void perf_evlist__set_leader(struct perf_evlist *evlist)
123{ 130{
124 if (evlist->nr_entries) 131 if (evlist->nr_entries) {
132 evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0;
125 __perf_evlist__set_leader(&evlist->entries); 133 __perf_evlist__set_leader(&evlist->entries);
134 }
126} 135}
127 136
128int perf_evlist__add_default(struct perf_evlist *evlist) 137int perf_evlist__add_default(struct perf_evlist *evlist)
@@ -222,7 +231,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
222 231
223 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 232 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
224 list_for_each_entry(pos, &evlist->entries, node) { 233 list_for_each_entry(pos, &evlist->entries, node) {
225 if (perf_evsel__is_group_member(pos)) 234 if (!perf_evsel__is_group_leader(pos))
226 continue; 235 continue;
227 for (thread = 0; thread < evlist->threads->nr; thread++) 236 for (thread = 0; thread < evlist->threads->nr; thread++)
228 ioctl(FD(pos, cpu, thread), 237 ioctl(FD(pos, cpu, thread),
@@ -238,7 +247,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
238 247
239 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { 248 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
240 list_for_each_entry(pos, &evlist->entries, node) { 249 list_for_each_entry(pos, &evlist->entries, node) {
241 if (perf_evsel__is_group_member(pos)) 250 if (!perf_evsel__is_group_leader(pos))
242 continue; 251 continue;
243 for (thread = 0; thread < evlist->threads->nr; thread++) 252 for (thread = 0; thread < evlist->threads->nr; thread++)
244 ioctl(FD(pos, cpu, thread), 253 ioctl(FD(pos, cpu, thread),
@@ -305,7 +314,6 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
305struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) 314struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
306{ 315{
307 struct hlist_head *head; 316 struct hlist_head *head;
308 struct hlist_node *pos;
309 struct perf_sample_id *sid; 317 struct perf_sample_id *sid;
310 int hash; 318 int hash;
311 319
@@ -315,7 +323,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
315 hash = hash_64(id, PERF_EVLIST__HLIST_BITS); 323 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
316 head = &evlist->heads[hash]; 324 head = &evlist->heads[hash];
317 325
318 hlist_for_each_entry(sid, pos, head, node) 326 hlist_for_each_entry(sid, head, node)
319 if (sid->id == id) 327 if (sid->id == id)
320 return sid->evsel; 328 return sid->evsel;
321 329
@@ -366,7 +374,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
366 if ((old & md->mask) + size != ((old + size) & md->mask)) { 374 if ((old & md->mask) + size != ((old + size) & md->mask)) {
367 unsigned int offset = old; 375 unsigned int offset = old;
368 unsigned int len = min(sizeof(*event), size), cpy; 376 unsigned int len = min(sizeof(*event), size), cpy;
369 void *dst = &evlist->event_copy; 377 void *dst = &md->event_copy;
370 378
371 do { 379 do {
372 cpy = min(md->mask + 1 - (offset & md->mask), len); 380 cpy = min(md->mask + 1 - (offset & md->mask), len);
@@ -376,7 +384,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
376 len -= cpy; 384 len -= cpy;
377 } while (len); 385 } while (len);
378 386
379 event = &evlist->event_copy; 387 event = &md->event_copy;
380 } 388 }
381 389
382 old += size; 390 old += size;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 56003f779e60..2dd07bd60b4f 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -17,10 +17,18 @@ struct perf_record_opts;
17#define PERF_EVLIST__HLIST_BITS 8 17#define PERF_EVLIST__HLIST_BITS 8
18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
19 19
20struct perf_mmap {
21 void *base;
22 int mask;
23 unsigned int prev;
24 union perf_event event_copy;
25};
26
20struct perf_evlist { 27struct perf_evlist {
21 struct list_head entries; 28 struct list_head entries;
22 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; 29 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
23 int nr_entries; 30 int nr_entries;
31 int nr_groups;
24 int nr_fds; 32 int nr_fds;
25 int nr_mmaps; 33 int nr_mmaps;
26 int mmap_len; 34 int mmap_len;
@@ -29,7 +37,6 @@ struct perf_evlist {
29 pid_t pid; 37 pid_t pid;
30 } workload; 38 } workload;
31 bool overwrite; 39 bool overwrite;
32 union perf_event event_copy;
33 struct perf_mmap *mmap; 40 struct perf_mmap *mmap;
34 struct pollfd *pollfd; 41 struct pollfd *pollfd;
35 struct thread_map *threads; 42 struct thread_map *threads;
@@ -76,8 +83,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
76 83
77int perf_evlist__open(struct perf_evlist *evlist); 84int perf_evlist__open(struct perf_evlist *evlist);
78 85
79void perf_evlist__config_attrs(struct perf_evlist *evlist, 86void perf_evlist__config(struct perf_evlist *evlist,
80 struct perf_record_opts *opts); 87 struct perf_record_opts *opts);
81 88
82int perf_evlist__prepare_workload(struct perf_evlist *evlist, 89int perf_evlist__prepare_workload(struct perf_evlist *evlist,
83 struct perf_record_opts *opts, 90 struct perf_record_opts *opts,
@@ -135,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
135} 142}
136 143
137size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 144size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
145
146static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
147{
148 struct perf_event_mmap_page *pc = mm->base;
149 int head = pc->data_head;
150 rmb();
151 return head;
152}
153
154static inline void perf_mmap__write_tail(struct perf_mmap *md,
155 unsigned long tail)
156{
157 struct perf_event_mmap_page *pc = md->base;
158
159 /*
160 * ensure all reads are done before we write the tail out.
161 */
162 /* mb(); */
163 pc->data_tail = tail;
164}
165
138#endif /* __PERF_EVLIST_H */ 166#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1b16dd1edc8e..9c82f98f26de 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -22,6 +22,11 @@
22#include <linux/perf_event.h> 22#include <linux/perf_event.h>
23#include "perf_regs.h" 23#include "perf_regs.h"
24 24
25static struct {
26 bool sample_id_all;
27 bool exclude_guest;
28} perf_missing_features;
29
25#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 30#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
26 31
27static int __perf_evsel__sample_size(u64 sample_type) 32static int __perf_evsel__sample_size(u64 sample_type)
@@ -50,11 +55,36 @@ void hists__init(struct hists *hists)
50 pthread_mutex_init(&hists->lock, NULL); 55 pthread_mutex_init(&hists->lock, NULL);
51} 56}
52 57
58void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
59 enum perf_event_sample_format bit)
60{
61 if (!(evsel->attr.sample_type & bit)) {
62 evsel->attr.sample_type |= bit;
63 evsel->sample_size += sizeof(u64);
64 }
65}
66
67void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
68 enum perf_event_sample_format bit)
69{
70 if (evsel->attr.sample_type & bit) {
71 evsel->attr.sample_type &= ~bit;
72 evsel->sample_size -= sizeof(u64);
73 }
74}
75
76void perf_evsel__set_sample_id(struct perf_evsel *evsel)
77{
78 perf_evsel__set_sample_bit(evsel, ID);
79 evsel->attr.read_format |= PERF_FORMAT_ID;
80}
81
53void perf_evsel__init(struct perf_evsel *evsel, 82void perf_evsel__init(struct perf_evsel *evsel,
54 struct perf_event_attr *attr, int idx) 83 struct perf_event_attr *attr, int idx)
55{ 84{
56 evsel->idx = idx; 85 evsel->idx = idx;
57 evsel->attr = *attr; 86 evsel->attr = *attr;
87 evsel->leader = evsel;
58 INIT_LIST_HEAD(&evsel->node); 88 INIT_LIST_HEAD(&evsel->node);
59 hists__init(&evsel->hists); 89 hists__init(&evsel->hists);
60 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 90 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
@@ -404,6 +434,31 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
404 return evsel->name ?: "unknown"; 434 return evsel->name ?: "unknown";
405} 435}
406 436
437const char *perf_evsel__group_name(struct perf_evsel *evsel)
438{
439 return evsel->group_name ?: "anon group";
440}
441
442int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
443{
444 int ret;
445 struct perf_evsel *pos;
446 const char *group_name = perf_evsel__group_name(evsel);
447
448 ret = scnprintf(buf, size, "%s", group_name);
449
450 ret += scnprintf(buf + ret, size - ret, " { %s",
451 perf_evsel__name(evsel));
452
453 for_each_group_member(pos, evsel)
454 ret += scnprintf(buf + ret, size - ret, ", %s",
455 perf_evsel__name(pos));
456
457 ret += scnprintf(buf + ret, size - ret, " }");
458
459 return ret;
460}
461
407/* 462/*
408 * The enable_on_exec/disabled value strategy: 463 * The enable_on_exec/disabled value strategy:
409 * 464 *
@@ -438,13 +493,11 @@ void perf_evsel__config(struct perf_evsel *evsel,
438 struct perf_event_attr *attr = &evsel->attr; 493 struct perf_event_attr *attr = &evsel->attr;
439 int track = !evsel->idx; /* only the first counter needs these */ 494 int track = !evsel->idx; /* only the first counter needs these */
440 495
441 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 496 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
442 attr->inherit = !opts->no_inherit; 497 attr->inherit = !opts->no_inherit;
443 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
444 PERF_FORMAT_TOTAL_TIME_RUNNING |
445 PERF_FORMAT_ID;
446 498
447 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 499 perf_evsel__set_sample_bit(evsel, IP);
500 perf_evsel__set_sample_bit(evsel, TID);
448 501
449 /* 502 /*
450 * We default some events to a 1 default interval. But keep 503 * We default some events to a 1 default interval. But keep
@@ -453,7 +506,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
453 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 506 if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
454 opts->user_interval != ULLONG_MAX)) { 507 opts->user_interval != ULLONG_MAX)) {
455 if (opts->freq) { 508 if (opts->freq) {
456 attr->sample_type |= PERF_SAMPLE_PERIOD; 509 perf_evsel__set_sample_bit(evsel, PERIOD);
457 attr->freq = 1; 510 attr->freq = 1;
458 attr->sample_freq = opts->freq; 511 attr->sample_freq = opts->freq;
459 } else { 512 } else {
@@ -468,16 +521,16 @@ void perf_evsel__config(struct perf_evsel *evsel,
468 attr->inherit_stat = 1; 521 attr->inherit_stat = 1;
469 522
470 if (opts->sample_address) { 523 if (opts->sample_address) {
471 attr->sample_type |= PERF_SAMPLE_ADDR; 524 perf_evsel__set_sample_bit(evsel, ADDR);
472 attr->mmap_data = track; 525 attr->mmap_data = track;
473 } 526 }
474 527
475 if (opts->call_graph) { 528 if (opts->call_graph) {
476 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 529 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
477 530
478 if (opts->call_graph == CALLCHAIN_DWARF) { 531 if (opts->call_graph == CALLCHAIN_DWARF) {
479 attr->sample_type |= PERF_SAMPLE_REGS_USER | 532 perf_evsel__set_sample_bit(evsel, REGS_USER);
480 PERF_SAMPLE_STACK_USER; 533 perf_evsel__set_sample_bit(evsel, STACK_USER);
481 attr->sample_regs_user = PERF_REGS_MASK; 534 attr->sample_regs_user = PERF_REGS_MASK;
482 attr->sample_stack_user = opts->stack_dump_size; 535 attr->sample_stack_user = opts->stack_dump_size;
483 attr->exclude_callchain_user = 1; 536 attr->exclude_callchain_user = 1;
@@ -485,20 +538,20 @@ void perf_evsel__config(struct perf_evsel *evsel,
485 } 538 }
486 539
487 if (perf_target__has_cpu(&opts->target)) 540 if (perf_target__has_cpu(&opts->target))
488 attr->sample_type |= PERF_SAMPLE_CPU; 541 perf_evsel__set_sample_bit(evsel, CPU);
489 542
490 if (opts->period) 543 if (opts->period)
491 attr->sample_type |= PERF_SAMPLE_PERIOD; 544 perf_evsel__set_sample_bit(evsel, PERIOD);
492 545
493 if (!opts->sample_id_all_missing && 546 if (!perf_missing_features.sample_id_all &&
494 (opts->sample_time || !opts->no_inherit || 547 (opts->sample_time || !opts->no_inherit ||
495 perf_target__has_cpu(&opts->target))) 548 perf_target__has_cpu(&opts->target)))
496 attr->sample_type |= PERF_SAMPLE_TIME; 549 perf_evsel__set_sample_bit(evsel, TIME);
497 550
498 if (opts->raw_samples) { 551 if (opts->raw_samples) {
499 attr->sample_type |= PERF_SAMPLE_TIME; 552 perf_evsel__set_sample_bit(evsel, TIME);
500 attr->sample_type |= PERF_SAMPLE_RAW; 553 perf_evsel__set_sample_bit(evsel, RAW);
501 attr->sample_type |= PERF_SAMPLE_CPU; 554 perf_evsel__set_sample_bit(evsel, CPU);
502 } 555 }
503 556
504 if (opts->no_delay) { 557 if (opts->no_delay) {
@@ -506,7 +559,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
506 attr->wakeup_events = 1; 559 attr->wakeup_events = 1;
507 } 560 }
508 if (opts->branch_stack) { 561 if (opts->branch_stack) {
509 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; 562 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
510 attr->branch_sample_type = opts->branch_stack; 563 attr->branch_sample_type = opts->branch_stack;
511 } 564 }
512 565
@@ -519,14 +572,14 @@ void perf_evsel__config(struct perf_evsel *evsel,
519 * Disabling only independent events or group leaders, 572 * Disabling only independent events or group leaders,
520 * keeping group members enabled. 573 * keeping group members enabled.
521 */ 574 */
522 if (!perf_evsel__is_group_member(evsel)) 575 if (perf_evsel__is_group_leader(evsel))
523 attr->disabled = 1; 576 attr->disabled = 1;
524 577
525 /* 578 /*
526 * Setting enable_on_exec for independent events and 579 * Setting enable_on_exec for independent events and
527 * group leaders for traced executed by perf. 580 * group leaders for traced executed by perf.
528 */ 581 */
529 if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel)) 582 if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel))
530 attr->enable_on_exec = 1; 583 attr->enable_on_exec = 1;
531} 584}
532 585
@@ -612,6 +665,11 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
612 } 665 }
613} 666}
614 667
668void perf_evsel__free_counts(struct perf_evsel *evsel)
669{
670 free(evsel->counts);
671}
672
615void perf_evsel__exit(struct perf_evsel *evsel) 673void perf_evsel__exit(struct perf_evsel *evsel)
616{ 674{
617 assert(list_empty(&evsel->node)); 675 assert(list_empty(&evsel->node));
@@ -631,6 +689,28 @@ void perf_evsel__delete(struct perf_evsel *evsel)
631 free(evsel); 689 free(evsel);
632} 690}
633 691
692static inline void compute_deltas(struct perf_evsel *evsel,
693 int cpu,
694 struct perf_counts_values *count)
695{
696 struct perf_counts_values tmp;
697
698 if (!evsel->prev_raw_counts)
699 return;
700
701 if (cpu == -1) {
702 tmp = evsel->prev_raw_counts->aggr;
703 evsel->prev_raw_counts->aggr = *count;
704 } else {
705 tmp = evsel->prev_raw_counts->cpu[cpu];
706 evsel->prev_raw_counts->cpu[cpu] = *count;
707 }
708
709 count->val = count->val - tmp.val;
710 count->ena = count->ena - tmp.ena;
711 count->run = count->run - tmp.run;
712}
713
634int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 714int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
635 int cpu, int thread, bool scale) 715 int cpu, int thread, bool scale)
636{ 716{
@@ -646,6 +726,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
646 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) 726 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
647 return -errno; 727 return -errno;
648 728
729 compute_deltas(evsel, cpu, &count);
730
649 if (scale) { 731 if (scale) {
650 if (count.run == 0) 732 if (count.run == 0)
651 count.val = 0; 733 count.val = 0;
@@ -684,6 +766,8 @@ int __perf_evsel__read(struct perf_evsel *evsel,
684 } 766 }
685 } 767 }
686 768
769 compute_deltas(evsel, -1, aggr);
770
687 evsel->counts->scaled = 0; 771 evsel->counts->scaled = 0;
688 if (scale) { 772 if (scale) {
689 if (aggr->run == 0) { 773 if (aggr->run == 0) {
@@ -707,7 +791,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
707 struct perf_evsel *leader = evsel->leader; 791 struct perf_evsel *leader = evsel->leader;
708 int fd; 792 int fd;
709 793
710 if (!perf_evsel__is_group_member(evsel)) 794 if (perf_evsel__is_group_leader(evsel))
711 return -1; 795 return -1;
712 796
713 /* 797 /*
@@ -738,6 +822,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
738 pid = evsel->cgrp->fd; 822 pid = evsel->cgrp->fd;
739 } 823 }
740 824
825fallback_missing_features:
826 if (perf_missing_features.exclude_guest)
827 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
828retry_sample_id:
829 if (perf_missing_features.sample_id_all)
830 evsel->attr.sample_id_all = 0;
831
741 for (cpu = 0; cpu < cpus->nr; cpu++) { 832 for (cpu = 0; cpu < cpus->nr; cpu++) {
742 833
743 for (thread = 0; thread < threads->nr; thread++) { 834 for (thread = 0; thread < threads->nr; thread++) {
@@ -754,13 +845,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
754 group_fd, flags); 845 group_fd, flags);
755 if (FD(evsel, cpu, thread) < 0) { 846 if (FD(evsel, cpu, thread) < 0) {
756 err = -errno; 847 err = -errno;
757 goto out_close; 848 goto try_fallback;
758 } 849 }
759 } 850 }
760 } 851 }
761 852
762 return 0; 853 return 0;
763 854
855try_fallback:
856 if (err != -EINVAL || cpu > 0 || thread > 0)
857 goto out_close;
858
859 if (!perf_missing_features.exclude_guest &&
860 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
861 perf_missing_features.exclude_guest = true;
862 goto fallback_missing_features;
863 } else if (!perf_missing_features.sample_id_all) {
864 perf_missing_features.sample_id_all = true;
865 goto retry_sample_id;
866 }
867
764out_close: 868out_close:
765 do { 869 do {
766 while (--thread >= 0) { 870 while (--thread >= 0) {
@@ -1205,3 +1309,225 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
1205 1309
1206 return 0; 1310 return 0;
1207} 1311}
1312
1313static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
1314{
1315 va_list args;
1316 int ret = 0;
1317
1318 if (!*first) {
1319 ret += fprintf(fp, ",");
1320 } else {
1321 ret += fprintf(fp, ":");
1322 *first = false;
1323 }
1324
1325 va_start(args, fmt);
1326 ret += vfprintf(fp, fmt, args);
1327 va_end(args);
1328 return ret;
1329}
1330
1331static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value)
1332{
1333 if (value == 0)
1334 return 0;
1335
1336 return comma_fprintf(fp, first, " %s: %" PRIu64, field, value);
1337}
1338
1339#define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field)
1340
1341struct bit_names {
1342 int bit;
1343 const char *name;
1344};
1345
1346static int bits__fprintf(FILE *fp, const char *field, u64 value,
1347 struct bit_names *bits, bool *first)
1348{
1349 int i = 0, printed = comma_fprintf(fp, first, " %s: ", field);
1350 bool first_bit = true;
1351
1352 do {
1353 if (value & bits[i].bit) {
1354 printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name);
1355 first_bit = false;
1356 }
1357 } while (bits[++i].name != NULL);
1358
1359 return printed;
1360}
1361
1362static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
1363{
1364#define bit_name(n) { PERF_SAMPLE_##n, #n }
1365 struct bit_names bits[] = {
1366 bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR),
1367 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
1368 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1369 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1370 { .name = NULL, }
1371 };
1372#undef bit_name
1373 return bits__fprintf(fp, "sample_type", value, bits, first);
1374}
1375
1376static int read_format__fprintf(FILE *fp, bool *first, u64 value)
1377{
1378#define bit_name(n) { PERF_FORMAT_##n, #n }
1379 struct bit_names bits[] = {
1380 bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING),
1381 bit_name(ID), bit_name(GROUP),
1382 { .name = NULL, }
1383 };
1384#undef bit_name
1385 return bits__fprintf(fp, "read_format", value, bits, first);
1386}
1387
1388int perf_evsel__fprintf(struct perf_evsel *evsel,
1389 struct perf_attr_details *details, FILE *fp)
1390{
1391 bool first = true;
1392 int printed = 0;
1393
1394 if (details->event_group) {
1395 struct perf_evsel *pos;
1396
1397 if (!perf_evsel__is_group_leader(evsel))
1398 return 0;
1399
1400 if (evsel->nr_members > 1)
1401 printed += fprintf(fp, "%s{", evsel->group_name ?: "");
1402
1403 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
1404 for_each_group_member(pos, evsel)
1405 printed += fprintf(fp, ",%s", perf_evsel__name(pos));
1406
1407 if (evsel->nr_members > 1)
1408 printed += fprintf(fp, "}");
1409 goto out;
1410 }
1411
1412 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
1413
1414 if (details->verbose || details->freq) {
1415 printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64,
1416 (u64)evsel->attr.sample_freq);
1417 }
1418
1419 if (details->verbose) {
1420 if_print(type);
1421 if_print(config);
1422 if_print(config1);
1423 if_print(config2);
1424 if_print(size);
1425 printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type);
1426 if (evsel->attr.read_format)
1427 printed += read_format__fprintf(fp, &first, evsel->attr.read_format);
1428 if_print(disabled);
1429 if_print(inherit);
1430 if_print(pinned);
1431 if_print(exclusive);
1432 if_print(exclude_user);
1433 if_print(exclude_kernel);
1434 if_print(exclude_hv);
1435 if_print(exclude_idle);
1436 if_print(mmap);
1437 if_print(comm);
1438 if_print(freq);
1439 if_print(inherit_stat);
1440 if_print(enable_on_exec);
1441 if_print(task);
1442 if_print(watermark);
1443 if_print(precise_ip);
1444 if_print(mmap_data);
1445 if_print(sample_id_all);
1446 if_print(exclude_host);
1447 if_print(exclude_guest);
1448 if_print(__reserved_1);
1449 if_print(wakeup_events);
1450 if_print(bp_type);
1451 if_print(branch_sample_type);
1452 }
1453out:
1454 fputc('\n', fp);
1455 return ++printed;
1456}
1457
1458bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1459 char *msg, size_t msgsize)
1460{
1461 if ((err == ENOENT || err == ENXIO) &&
1462 evsel->attr.type == PERF_TYPE_HARDWARE &&
1463 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
1464 /*
1465 * If it's cycles then fall back to hrtimer based
1466 * cpu-clock-tick sw counter, which is always available even if
1467 * no PMU support.
1468 *
1469 * PPC returns ENXIO until 2.6.37 (behavior changed with commit
1470 * b0a873e).
1471 */
1472 scnprintf(msg, msgsize, "%s",
1473"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
1474
1475 evsel->attr.type = PERF_TYPE_SOFTWARE;
1476 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
1477
1478 free(evsel->name);
1479 evsel->name = NULL;
1480 return true;
1481 }
1482
1483 return false;
1484}
1485
1486int perf_evsel__open_strerror(struct perf_evsel *evsel,
1487 struct perf_target *target,
1488 int err, char *msg, size_t size)
1489{
1490 switch (err) {
1491 case EPERM:
1492 case EACCES:
1493 return scnprintf(msg, size, "%s",
1494 "You may not have permission to collect %sstats.\n"
1495 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
1496 " -1 - Not paranoid at all\n"
1497 " 0 - Disallow raw tracepoint access for unpriv\n"
1498 " 1 - Disallow cpu events for unpriv\n"
1499 " 2 - Disallow kernel profiling for unpriv",
1500 target->system_wide ? "system-wide " : "");
1501 case ENOENT:
1502 return scnprintf(msg, size, "The %s event is not supported.",
1503 perf_evsel__name(evsel));
1504 case EMFILE:
1505 return scnprintf(msg, size, "%s",
1506 "Too many events are opened.\n"
1507 "Try again after reducing the number of events.");
1508 case ENODEV:
1509 if (target->cpu_list)
1510 return scnprintf(msg, size, "%s",
1511 "No such device - did you specify an out-of-range profile CPU?\n");
1512 break;
1513 case EOPNOTSUPP:
1514 if (evsel->attr.precise_ip)
1515 return scnprintf(msg, size, "%s",
1516 "\'precise\' request may not be supported. Try removing 'p' modifier.");
1517#if defined(__i386__) || defined(__x86_64__)
1518 if (evsel->attr.type == PERF_TYPE_HARDWARE)
1519 return scnprintf(msg, size, "%s",
1520 "No hardware sampling interrupt available.\n"
1521 "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
1522#endif
1523 break;
1524 default:
1525 break;
1526 }
1527
1528 return scnprintf(msg, size,
1529 "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n"
1530 "/bin/dmesg may provide additional information.\n"
1531 "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
1532 err, strerror(err), perf_evsel__name(evsel));
1533}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3d2b8017438c..52021c3087df 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -53,6 +53,7 @@ struct perf_evsel {
53 struct xyarray *sample_id; 53 struct xyarray *sample_id;
54 u64 *id; 54 u64 *id;
55 struct perf_counts *counts; 55 struct perf_counts *counts;
56 struct perf_counts *prev_raw_counts;
56 int idx; 57 int idx;
57 u32 ids; 58 u32 ids;
58 struct hists hists; 59 struct hists hists;
@@ -73,10 +74,13 @@ struct perf_evsel {
73 bool needs_swap; 74 bool needs_swap;
74 /* parse modifier helper */ 75 /* parse modifier helper */
75 int exclude_GH; 76 int exclude_GH;
77 int nr_members;
76 struct perf_evsel *leader; 78 struct perf_evsel *leader;
77 char *group_name; 79 char *group_name;
78}; 80};
79 81
82#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
83
80struct cpu_map; 84struct cpu_map;
81struct thread_map; 85struct thread_map;
82struct perf_evlist; 86struct perf_evlist;
@@ -110,14 +114,30 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
110int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, 114int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
111 char *bf, size_t size); 115 char *bf, size_t size);
112const char *perf_evsel__name(struct perf_evsel *evsel); 116const char *perf_evsel__name(struct perf_evsel *evsel);
117const char *perf_evsel__group_name(struct perf_evsel *evsel);
118int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
113 119
114int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 120int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
115int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 121int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
116int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 122int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
117void perf_evsel__free_fd(struct perf_evsel *evsel); 123void perf_evsel__free_fd(struct perf_evsel *evsel);
118void perf_evsel__free_id(struct perf_evsel *evsel); 124void perf_evsel__free_id(struct perf_evsel *evsel);
125void perf_evsel__free_counts(struct perf_evsel *evsel);
119void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 126void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
120 127
128void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
129 enum perf_event_sample_format bit);
130void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
131 enum perf_event_sample_format bit);
132
133#define perf_evsel__set_sample_bit(evsel, bit) \
134 __perf_evsel__set_sample_bit(evsel, PERF_SAMPLE_##bit)
135
136#define perf_evsel__reset_sample_bit(evsel, bit) \
137 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
138
139void perf_evsel__set_sample_id(struct perf_evsel *evsel);
140
121int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 141int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
122 const char *filter); 142 const char *filter);
123 143
@@ -226,8 +246,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
226 return list_entry(evsel->node.next, struct perf_evsel, node); 246 return list_entry(evsel->node.next, struct perf_evsel, node);
227} 247}
228 248
229static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel) 249static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel)
250{
251 return evsel->leader == evsel;
252}
253
254struct perf_attr_details {
255 bool freq;
256 bool verbose;
257 bool event_group;
258};
259
260int perf_evsel__fprintf(struct perf_evsel *evsel,
261 struct perf_attr_details *details, FILE *fp);
262
263bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
264 char *msg, size_t msgsize);
265int perf_evsel__open_strerror(struct perf_evsel *evsel,
266 struct perf_target *target,
267 int err, char *msg, size_t size);
268
269static inline int perf_evsel__group_idx(struct perf_evsel *evsel)
230{ 270{
231 return evsel->leader != NULL; 271 return evsel->idx - evsel->leader->idx;
232} 272}
273
274#define for_each_group_member(_evsel, _leader) \
275for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \
276 (_evsel) && (_evsel)->leader == (_leader); \
277 (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
278
233#endif /* __PERF_EVSEL_H */ 279#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b7da4634a047..f4bfd79ef6a7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -148,7 +148,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
148 u32 len; 148 u32 len;
149 char *buf; 149 char *buf;
150 150
151 sz = read(fd, &len, sizeof(len)); 151 sz = readn(fd, &len, sizeof(len));
152 if (sz < (ssize_t)sizeof(len)) 152 if (sz < (ssize_t)sizeof(len))
153 return NULL; 153 return NULL;
154 154
@@ -159,7 +159,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
159 if (!buf) 159 if (!buf)
160 return NULL; 160 return NULL;
161 161
162 ret = read(fd, buf, len); 162 ret = readn(fd, buf, len);
163 if (ret == (ssize_t)len) { 163 if (ret == (ssize_t)len) {
164 /* 164 /*
165 * strings are padded by zeroes 165 * strings are padded by zeroes
@@ -287,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
287 struct perf_session *session = container_of(header, 287 struct perf_session *session = container_of(header,
288 struct perf_session, header); 288 struct perf_session, header);
289 struct rb_node *nd; 289 struct rb_node *nd;
290 int err = machine__write_buildid_table(&session->host_machine, fd); 290 int err = machine__write_buildid_table(&session->machines.host, fd);
291 291
292 if (err) 292 if (err)
293 return err; 293 return err;
294 294
295 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 295 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
296 struct machine *pos = rb_entry(nd, struct machine, rb_node); 296 struct machine *pos = rb_entry(nd, struct machine, rb_node);
297 err = machine__write_buildid_table(pos, fd); 297 err = machine__write_buildid_table(pos, fd);
298 if (err) 298 if (err)
@@ -313,7 +313,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
313 if (is_kallsyms) { 313 if (is_kallsyms) {
314 if (symbol_conf.kptr_restrict) { 314 if (symbol_conf.kptr_restrict) {
315 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); 315 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
316 return 0; 316 err = 0;
317 goto out_free;
317 } 318 }
318 realname = (char *) name; 319 realname = (char *) name;
319 } else 320 } else
@@ -448,9 +449,9 @@ static int perf_session__cache_build_ids(struct perf_session *session)
448 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 449 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
449 return -1; 450 return -1;
450 451
451 ret = machine__cache_build_ids(&session->host_machine, debugdir); 452 ret = machine__cache_build_ids(&session->machines.host, debugdir);
452 453
453 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 454 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
454 struct machine *pos = rb_entry(nd, struct machine, rb_node); 455 struct machine *pos = rb_entry(nd, struct machine, rb_node);
455 ret |= machine__cache_build_ids(pos, debugdir); 456 ret |= machine__cache_build_ids(pos, debugdir);
456 } 457 }
@@ -467,9 +468,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits)
467static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) 468static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
468{ 469{
469 struct rb_node *nd; 470 struct rb_node *nd;
470 bool ret = machine__read_build_ids(&session->host_machine, with_hits); 471 bool ret = machine__read_build_ids(&session->machines.host, with_hits);
471 472
472 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 473 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
473 struct machine *pos = rb_entry(nd, struct machine, rb_node); 474 struct machine *pos = rb_entry(nd, struct machine, rb_node);
474 ret |= machine__read_build_ids(pos, with_hits); 475 ret |= machine__read_build_ids(pos, with_hits);
475 } 476 }
@@ -954,6 +955,7 @@ static int write_topo_node(int fd, int node)
954 } 955 }
955 956
956 fclose(fp); 957 fclose(fp);
958 fp = NULL;
957 959
958 ret = do_write(fd, &mem_total, sizeof(u64)); 960 ret = do_write(fd, &mem_total, sizeof(u64));
959 if (ret) 961 if (ret)
@@ -980,7 +982,8 @@ static int write_topo_node(int fd, int node)
980 ret = do_write_string(fd, buf); 982 ret = do_write_string(fd, buf);
981done: 983done:
982 free(buf); 984 free(buf);
983 fclose(fp); 985 if (fp)
986 fclose(fp);
984 return ret; 987 return ret;
985} 988}
986 989
@@ -1051,16 +1054,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1051 struct perf_pmu *pmu = NULL; 1054 struct perf_pmu *pmu = NULL;
1052 off_t offset = lseek(fd, 0, SEEK_CUR); 1055 off_t offset = lseek(fd, 0, SEEK_CUR);
1053 __u32 pmu_num = 0; 1056 __u32 pmu_num = 0;
1057 int ret;
1054 1058
1055 /* write real pmu_num later */ 1059 /* write real pmu_num later */
1056 do_write(fd, &pmu_num, sizeof(pmu_num)); 1060 ret = do_write(fd, &pmu_num, sizeof(pmu_num));
1061 if (ret < 0)
1062 return ret;
1057 1063
1058 while ((pmu = perf_pmu__scan(pmu))) { 1064 while ((pmu = perf_pmu__scan(pmu))) {
1059 if (!pmu->name) 1065 if (!pmu->name)
1060 continue; 1066 continue;
1061 pmu_num++; 1067 pmu_num++;
1062 do_write(fd, &pmu->type, sizeof(pmu->type)); 1068
1063 do_write_string(fd, pmu->name); 1069 ret = do_write(fd, &pmu->type, sizeof(pmu->type));
1070 if (ret < 0)
1071 return ret;
1072
1073 ret = do_write_string(fd, pmu->name);
1074 if (ret < 0)
1075 return ret;
1064 } 1076 }
1065 1077
1066 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { 1078 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
@@ -1073,6 +1085,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1073} 1085}
1074 1086
1075/* 1087/*
1088 * File format:
1089 *
1090 * struct group_descs {
1091 * u32 nr_groups;
1092 * struct group_desc {
1093 * char name[];
1094 * u32 leader_idx;
1095 * u32 nr_members;
1096 * }[nr_groups];
1097 * };
1098 */
1099static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
1100 struct perf_evlist *evlist)
1101{
1102 u32 nr_groups = evlist->nr_groups;
1103 struct perf_evsel *evsel;
1104 int ret;
1105
1106 ret = do_write(fd, &nr_groups, sizeof(nr_groups));
1107 if (ret < 0)
1108 return ret;
1109
1110 list_for_each_entry(evsel, &evlist->entries, node) {
1111 if (perf_evsel__is_group_leader(evsel) &&
1112 evsel->nr_members > 1) {
1113 const char *name = evsel->group_name ?: "{anon_group}";
1114 u32 leader_idx = evsel->idx;
1115 u32 nr_members = evsel->nr_members;
1116
1117 ret = do_write_string(fd, name);
1118 if (ret < 0)
1119 return ret;
1120
1121 ret = do_write(fd, &leader_idx, sizeof(leader_idx));
1122 if (ret < 0)
1123 return ret;
1124
1125 ret = do_write(fd, &nr_members, sizeof(nr_members));
1126 if (ret < 0)
1127 return ret;
1128 }
1129 }
1130 return 0;
1131}
1132
1133/*
1076 * default get_cpuid(): nothing gets recorded 1134 * default get_cpuid(): nothing gets recorded
1077 * actual implementation must be in arch/$(ARCH)/util/header.c 1135 * actual implementation must be in arch/$(ARCH)/util/header.c
1078 */ 1136 */
@@ -1209,14 +1267,14 @@ read_event_desc(struct perf_header *ph, int fd)
1209 size_t msz; 1267 size_t msz;
1210 1268
1211 /* number of events */ 1269 /* number of events */
1212 ret = read(fd, &nre, sizeof(nre)); 1270 ret = readn(fd, &nre, sizeof(nre));
1213 if (ret != (ssize_t)sizeof(nre)) 1271 if (ret != (ssize_t)sizeof(nre))
1214 goto error; 1272 goto error;
1215 1273
1216 if (ph->needs_swap) 1274 if (ph->needs_swap)
1217 nre = bswap_32(nre); 1275 nre = bswap_32(nre);
1218 1276
1219 ret = read(fd, &sz, sizeof(sz)); 1277 ret = readn(fd, &sz, sizeof(sz));
1220 if (ret != (ssize_t)sizeof(sz)) 1278 if (ret != (ssize_t)sizeof(sz))
1221 goto error; 1279 goto error;
1222 1280
@@ -1244,7 +1302,7 @@ read_event_desc(struct perf_header *ph, int fd)
1244 * must read entire on-file attr struct to 1302 * must read entire on-file attr struct to
1245 * sync up with layout. 1303 * sync up with layout.
1246 */ 1304 */
1247 ret = read(fd, buf, sz); 1305 ret = readn(fd, buf, sz);
1248 if (ret != (ssize_t)sz) 1306 if (ret != (ssize_t)sz)
1249 goto error; 1307 goto error;
1250 1308
@@ -1253,7 +1311,7 @@ read_event_desc(struct perf_header *ph, int fd)
1253 1311
1254 memcpy(&evsel->attr, buf, msz); 1312 memcpy(&evsel->attr, buf, msz);
1255 1313
1256 ret = read(fd, &nr, sizeof(nr)); 1314 ret = readn(fd, &nr, sizeof(nr));
1257 if (ret != (ssize_t)sizeof(nr)) 1315 if (ret != (ssize_t)sizeof(nr))
1258 goto error; 1316 goto error;
1259 1317
@@ -1274,7 +1332,7 @@ read_event_desc(struct perf_header *ph, int fd)
1274 evsel->id = id; 1332 evsel->id = id;
1275 1333
1276 for (j = 0 ; j < nr; j++) { 1334 for (j = 0 ; j < nr; j++) {
1277 ret = read(fd, id, sizeof(*id)); 1335 ret = readn(fd, id, sizeof(*id));
1278 if (ret != (ssize_t)sizeof(*id)) 1336 if (ret != (ssize_t)sizeof(*id))
1279 goto error; 1337 goto error;
1280 if (ph->needs_swap) 1338 if (ph->needs_swap)
@@ -1435,6 +1493,31 @@ error:
1435 fprintf(fp, "# pmu mappings: unable to read\n"); 1493 fprintf(fp, "# pmu mappings: unable to read\n");
1436} 1494}
1437 1495
1496static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
1497 FILE *fp)
1498{
1499 struct perf_session *session;
1500 struct perf_evsel *evsel;
1501 u32 nr = 0;
1502
1503 session = container_of(ph, struct perf_session, header);
1504
1505 list_for_each_entry(evsel, &session->evlist->entries, node) {
1506 if (perf_evsel__is_group_leader(evsel) &&
1507 evsel->nr_members > 1) {
1508 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
1509 perf_evsel__name(evsel));
1510
1511 nr = evsel->nr_members - 1;
1512 } else if (nr) {
1513 fprintf(fp, ",%s", perf_evsel__name(evsel));
1514
1515 if (--nr == 0)
1516 fprintf(fp, "}\n");
1517 }
1518 }
1519}
1520
1438static int __event_process_build_id(struct build_id_event *bev, 1521static int __event_process_build_id(struct build_id_event *bev,
1439 char *filename, 1522 char *filename,
1440 struct perf_session *session) 1523 struct perf_session *session)
@@ -1506,14 +1589,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1506 while (offset < limit) { 1589 while (offset < limit) {
1507 ssize_t len; 1590 ssize_t len;
1508 1591
1509 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) 1592 if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1510 return -1; 1593 return -1;
1511 1594
1512 if (header->needs_swap) 1595 if (header->needs_swap)
1513 perf_event_header__bswap(&old_bev.header); 1596 perf_event_header__bswap(&old_bev.header);
1514 1597
1515 len = old_bev.header.size - sizeof(old_bev); 1598 len = old_bev.header.size - sizeof(old_bev);
1516 if (read(input, filename, len) != len) 1599 if (readn(input, filename, len) != len)
1517 return -1; 1600 return -1;
1518 1601
1519 bev.header = old_bev.header; 1602 bev.header = old_bev.header;
@@ -1548,14 +1631,14 @@ static int perf_header__read_build_ids(struct perf_header *header,
1548 while (offset < limit) { 1631 while (offset < limit) {
1549 ssize_t len; 1632 ssize_t len;
1550 1633
1551 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 1634 if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
1552 goto out; 1635 goto out;
1553 1636
1554 if (header->needs_swap) 1637 if (header->needs_swap)
1555 perf_event_header__bswap(&bev.header); 1638 perf_event_header__bswap(&bev.header);
1556 1639
1557 len = bev.header.size - sizeof(bev); 1640 len = bev.header.size - sizeof(bev);
1558 if (read(input, filename, len) != len) 1641 if (readn(input, filename, len) != len)
1559 goto out; 1642 goto out;
1560 /* 1643 /*
1561 * The a1645ce1 changeset: 1644 * The a1645ce1 changeset:
@@ -1641,7 +1724,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1641 size_t ret; 1724 size_t ret;
1642 u32 nr; 1725 u32 nr;
1643 1726
1644 ret = read(fd, &nr, sizeof(nr)); 1727 ret = readn(fd, &nr, sizeof(nr));
1645 if (ret != sizeof(nr)) 1728 if (ret != sizeof(nr))
1646 return -1; 1729 return -1;
1647 1730
@@ -1650,7 +1733,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1650 1733
1651 ph->env.nr_cpus_online = nr; 1734 ph->env.nr_cpus_online = nr;
1652 1735
1653 ret = read(fd, &nr, sizeof(nr)); 1736 ret = readn(fd, &nr, sizeof(nr));
1654 if (ret != sizeof(nr)) 1737 if (ret != sizeof(nr))
1655 return -1; 1738 return -1;
1656 1739
@@ -1684,7 +1767,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
1684 uint64_t mem; 1767 uint64_t mem;
1685 size_t ret; 1768 size_t ret;
1686 1769
1687 ret = read(fd, &mem, sizeof(mem)); 1770 ret = readn(fd, &mem, sizeof(mem));
1688 if (ret != sizeof(mem)) 1771 if (ret != sizeof(mem))
1689 return -1; 1772 return -1;
1690 1773
@@ -1756,7 +1839,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
1756 u32 nr, i; 1839 u32 nr, i;
1757 struct strbuf sb; 1840 struct strbuf sb;
1758 1841
1759 ret = read(fd, &nr, sizeof(nr)); 1842 ret = readn(fd, &nr, sizeof(nr));
1760 if (ret != sizeof(nr)) 1843 if (ret != sizeof(nr))
1761 return -1; 1844 return -1;
1762 1845
@@ -1792,7 +1875,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1792 char *str; 1875 char *str;
1793 struct strbuf sb; 1876 struct strbuf sb;
1794 1877
1795 ret = read(fd, &nr, sizeof(nr)); 1878 ret = readn(fd, &nr, sizeof(nr));
1796 if (ret != sizeof(nr)) 1879 if (ret != sizeof(nr))
1797 return -1; 1880 return -1;
1798 1881
@@ -1813,7 +1896,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1813 } 1896 }
1814 ph->env.sibling_cores = strbuf_detach(&sb, NULL); 1897 ph->env.sibling_cores = strbuf_detach(&sb, NULL);
1815 1898
1816 ret = read(fd, &nr, sizeof(nr)); 1899 ret = readn(fd, &nr, sizeof(nr));
1817 if (ret != sizeof(nr)) 1900 if (ret != sizeof(nr))
1818 return -1; 1901 return -1;
1819 1902
@@ -1850,7 +1933,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1850 struct strbuf sb; 1933 struct strbuf sb;
1851 1934
1852 /* nr nodes */ 1935 /* nr nodes */
1853 ret = read(fd, &nr, sizeof(nr)); 1936 ret = readn(fd, &nr, sizeof(nr));
1854 if (ret != sizeof(nr)) 1937 if (ret != sizeof(nr))
1855 goto error; 1938 goto error;
1856 1939
@@ -1862,15 +1945,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1862 1945
1863 for (i = 0; i < nr; i++) { 1946 for (i = 0; i < nr; i++) {
1864 /* node number */ 1947 /* node number */
1865 ret = read(fd, &node, sizeof(node)); 1948 ret = readn(fd, &node, sizeof(node));
1866 if (ret != sizeof(node)) 1949 if (ret != sizeof(node))
1867 goto error; 1950 goto error;
1868 1951
1869 ret = read(fd, &mem_total, sizeof(u64)); 1952 ret = readn(fd, &mem_total, sizeof(u64));
1870 if (ret != sizeof(u64)) 1953 if (ret != sizeof(u64))
1871 goto error; 1954 goto error;
1872 1955
1873 ret = read(fd, &mem_free, sizeof(u64)); 1956 ret = readn(fd, &mem_free, sizeof(u64));
1874 if (ret != sizeof(u64)) 1957 if (ret != sizeof(u64))
1875 goto error; 1958 goto error;
1876 1959
@@ -1909,7 +1992,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1909 u32 type; 1992 u32 type;
1910 struct strbuf sb; 1993 struct strbuf sb;
1911 1994
1912 ret = read(fd, &pmu_num, sizeof(pmu_num)); 1995 ret = readn(fd, &pmu_num, sizeof(pmu_num));
1913 if (ret != sizeof(pmu_num)) 1996 if (ret != sizeof(pmu_num))
1914 return -1; 1997 return -1;
1915 1998
@@ -1925,7 +2008,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1925 strbuf_init(&sb, 128); 2008 strbuf_init(&sb, 128);
1926 2009
1927 while (pmu_num) { 2010 while (pmu_num) {
1928 if (read(fd, &type, sizeof(type)) != sizeof(type)) 2011 if (readn(fd, &type, sizeof(type)) != sizeof(type))
1929 goto error; 2012 goto error;
1930 if (ph->needs_swap) 2013 if (ph->needs_swap)
1931 type = bswap_32(type); 2014 type = bswap_32(type);
@@ -1949,6 +2032,98 @@ error:
1949 return -1; 2032 return -1;
1950} 2033}
1951 2034
2035static int process_group_desc(struct perf_file_section *section __maybe_unused,
2036 struct perf_header *ph, int fd,
2037 void *data __maybe_unused)
2038{
2039 size_t ret = -1;
2040 u32 i, nr, nr_groups;
2041 struct perf_session *session;
2042 struct perf_evsel *evsel, *leader = NULL;
2043 struct group_desc {
2044 char *name;
2045 u32 leader_idx;
2046 u32 nr_members;
2047 } *desc;
2048
2049 if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups))
2050 return -1;
2051
2052 if (ph->needs_swap)
2053 nr_groups = bswap_32(nr_groups);
2054
2055 ph->env.nr_groups = nr_groups;
2056 if (!nr_groups) {
2057 pr_debug("group desc not available\n");
2058 return 0;
2059 }
2060
2061 desc = calloc(nr_groups, sizeof(*desc));
2062 if (!desc)
2063 return -1;
2064
2065 for (i = 0; i < nr_groups; i++) {
2066 desc[i].name = do_read_string(fd, ph);
2067 if (!desc[i].name)
2068 goto out_free;
2069
2070 if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32))
2071 goto out_free;
2072
2073 if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32))
2074 goto out_free;
2075
2076 if (ph->needs_swap) {
2077 desc[i].leader_idx = bswap_32(desc[i].leader_idx);
2078 desc[i].nr_members = bswap_32(desc[i].nr_members);
2079 }
2080 }
2081
2082 /*
2083 * Rebuild group relationship based on the group_desc
2084 */
2085 session = container_of(ph, struct perf_session, header);
2086 session->evlist->nr_groups = nr_groups;
2087
2088 i = nr = 0;
2089 list_for_each_entry(evsel, &session->evlist->entries, node) {
2090 if (evsel->idx == (int) desc[i].leader_idx) {
2091 evsel->leader = evsel;
2092 /* {anon_group} is a dummy name */
2093 if (strcmp(desc[i].name, "{anon_group}"))
2094 evsel->group_name = desc[i].name;
2095 evsel->nr_members = desc[i].nr_members;
2096
2097 if (i >= nr_groups || nr > 0) {
2098 pr_debug("invalid group desc\n");
2099 goto out_free;
2100 }
2101
2102 leader = evsel;
2103 nr = evsel->nr_members - 1;
2104 i++;
2105 } else if (nr) {
2106 /* This is a group member */
2107 evsel->leader = leader;
2108
2109 nr--;
2110 }
2111 }
2112
2113 if (i != nr_groups || nr != 0) {
2114 pr_debug("invalid group desc\n");
2115 goto out_free;
2116 }
2117
2118 ret = 0;
2119out_free:
2120 while ((int) --i >= 0)
2121 free(desc[i].name);
2122 free(desc);
2123
2124 return ret;
2125}
2126
1952struct feature_ops { 2127struct feature_ops {
1953 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 2128 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1954 void (*print)(struct perf_header *h, int fd, FILE *fp); 2129 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1988,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1988 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), 2163 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1989 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), 2164 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1990 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 2165 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
2166 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1991}; 2167};
1992 2168
1993struct header_print_data { 2169struct header_print_data {
@@ -2077,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header,
2077 if (!nr_sections) 2253 if (!nr_sections)
2078 return 0; 2254 return 0;
2079 2255
2080 feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); 2256 feat_sec = p = calloc(nr_sections, sizeof(*feat_sec));
2081 if (feat_sec == NULL) 2257 if (feat_sec == NULL)
2082 return -ENOMEM; 2258 return -ENOMEM;
2083 2259
@@ -2249,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
2249 if (!nr_sections) 2425 if (!nr_sections)
2250 return 0; 2426 return 0;
2251 2427
2252 feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); 2428 feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec));
2253 if (!feat_sec) 2429 if (!feat_sec)
2254 return -1; 2430 return -1;
2255 2431
@@ -2912,16 +3088,22 @@ int perf_event__process_tracing_data(union perf_event *event,
2912 session->repipe); 3088 session->repipe);
2913 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3089 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
2914 3090
2915 if (read(session->fd, buf, padding) < 0) 3091 if (readn(session->fd, buf, padding) < 0) {
2916 die("reading input file"); 3092 pr_err("%s: reading input file", __func__);
3093 return -1;
3094 }
2917 if (session->repipe) { 3095 if (session->repipe) {
2918 int retw = write(STDOUT_FILENO, buf, padding); 3096 int retw = write(STDOUT_FILENO, buf, padding);
2919 if (retw <= 0 || retw != padding) 3097 if (retw <= 0 || retw != padding) {
2920 die("repiping tracing data padding"); 3098 pr_err("%s: repiping tracing data padding", __func__);
3099 return -1;
3100 }
2921 } 3101 }
2922 3102
2923 if (size_read + padding != size) 3103 if (size_read + padding != size) {
2924 die("tracing data size mismatch"); 3104 pr_err("%s: tracing data size mismatch", __func__);
3105 return -1;
3106 }
2925 3107
2926 perf_evlist__prepare_tracepoint_events(session->evlist, 3108 perf_evlist__prepare_tracepoint_events(session->evlist,
2927 session->pevent); 3109 session->pevent);
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 20f0344accb1..c9fc55cada6d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -29,6 +29,7 @@ enum {
29 HEADER_NUMA_TOPOLOGY, 29 HEADER_NUMA_TOPOLOGY,
30 HEADER_BRANCH_STACK, 30 HEADER_BRANCH_STACK,
31 HEADER_PMU_MAPPINGS, 31 HEADER_PMU_MAPPINGS,
32 HEADER_GROUP_DESC,
32 HEADER_LAST_FEATURE, 33 HEADER_LAST_FEATURE,
33 HEADER_FEAT_BITS = 256, 34 HEADER_FEAT_BITS = 256,
34}; 35};
@@ -79,6 +80,7 @@ struct perf_session_env {
79 char *numa_nodes; 80 char *numa_nodes;
80 int nr_pmu_mappings; 81 int nr_pmu_mappings;
81 char *pmu_mappings; 82 char *pmu_mappings;
83 int nr_groups;
82}; 84};
83 85
84struct perf_header { 86struct perf_header {
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index cb17e2a8c6ed..f855941bebea 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "hist.h" 4#include "hist.h"
5#include "session.h" 5#include "session.h"
6#include "sort.h" 6#include "sort.h"
7#include "evsel.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -82,6 +83,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
82 hists__new_col_len(hists, HISTC_DSO, len); 83 hists__new_col_len(hists, HISTC_DSO, len);
83 } 84 }
84 85
86 if (h->parent)
87 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
88
85 if (h->branch_info) { 89 if (h->branch_info) {
86 int symlen; 90 int symlen;
87 /* 91 /*
@@ -242,6 +246,14 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
242 246
243 if (he->ms.map) 247 if (he->ms.map)
244 he->ms.map->referenced = true; 248 he->ms.map->referenced = true;
249
250 if (he->branch_info) {
251 if (he->branch_info->from.map)
252 he->branch_info->from.map->referenced = true;
253 if (he->branch_info->to.map)
254 he->branch_info->to.map->referenced = true;
255 }
256
245 if (symbol_conf.use_callchain) 257 if (symbol_conf.use_callchain)
246 callchain_init(he->callchain); 258 callchain_init(he->callchain);
247 259
@@ -251,7 +263,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
251 return he; 263 return he;
252} 264}
253 265
254static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) 266void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
255{ 267{
256 if (!h->filtered) { 268 if (!h->filtered) {
257 hists__calc_col_len(hists, h); 269 hists__calc_col_len(hists, h);
@@ -285,7 +297,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
285 parent = *p; 297 parent = *p;
286 he = rb_entry(parent, struct hist_entry, rb_node_in); 298 he = rb_entry(parent, struct hist_entry, rb_node_in);
287 299
288 cmp = hist_entry__cmp(entry, he); 300 /*
301 * Make sure that it receives arguments in a same order as
302 * hist_entry__collapse() so that we can use an appropriate
303 * function when searching an entry regardless which sort
304 * keys were used.
305 */
306 cmp = hist_entry__cmp(he, entry);
289 307
290 if (!cmp) { 308 if (!cmp) {
291 he_stat__add_period(&he->stat, period); 309 he_stat__add_period(&he->stat, period);
@@ -523,6 +541,62 @@ void hists__collapse_resort_threaded(struct hists *hists)
523 * reverse the map, sort on period. 541 * reverse the map, sort on period.
524 */ 542 */
525 543
544static int period_cmp(u64 period_a, u64 period_b)
545{
546 if (period_a > period_b)
547 return 1;
548 if (period_a < period_b)
549 return -1;
550 return 0;
551}
552
553static int hist_entry__sort_on_period(struct hist_entry *a,
554 struct hist_entry *b)
555{
556 int ret;
557 int i, nr_members;
558 struct perf_evsel *evsel;
559 struct hist_entry *pair;
560 u64 *periods_a, *periods_b;
561
562 ret = period_cmp(a->stat.period, b->stat.period);
563 if (ret || !symbol_conf.event_group)
564 return ret;
565
566 evsel = hists_to_evsel(a->hists);
567 nr_members = evsel->nr_members;
568 if (nr_members <= 1)
569 return ret;
570
571 periods_a = zalloc(sizeof(periods_a) * nr_members);
572 periods_b = zalloc(sizeof(periods_b) * nr_members);
573
574 if (!periods_a || !periods_b)
575 goto out;
576
577 list_for_each_entry(pair, &a->pairs.head, pairs.node) {
578 evsel = hists_to_evsel(pair->hists);
579 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period;
580 }
581
582 list_for_each_entry(pair, &b->pairs.head, pairs.node) {
583 evsel = hists_to_evsel(pair->hists);
584 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
585 }
586
587 for (i = 1; i < nr_members; i++) {
588 ret = period_cmp(periods_a[i], periods_b[i]);
589 if (ret)
590 break;
591 }
592
593out:
594 free(periods_a);
595 free(periods_b);
596
597 return ret;
598}
599
526static void __hists__insert_output_entry(struct rb_root *entries, 600static void __hists__insert_output_entry(struct rb_root *entries,
527 struct hist_entry *he, 601 struct hist_entry *he,
528 u64 min_callchain_hits) 602 u64 min_callchain_hits)
@@ -539,7 +613,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
539 parent = *p; 613 parent = *p;
540 iter = rb_entry(parent, struct hist_entry, rb_node); 614 iter = rb_entry(parent, struct hist_entry, rb_node);
541 615
542 if (he->stat.period > iter->stat.period) 616 if (hist_entry__sort_on_period(he, iter) > 0)
543 p = &(*p)->rb_left; 617 p = &(*p)->rb_left;
544 else 618 else
545 p = &(*p)->rb_right; 619 p = &(*p)->rb_right;
@@ -711,25 +785,38 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
711 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 785 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
712} 786}
713 787
788void events_stats__inc(struct events_stats *stats, u32 type)
789{
790 ++stats->nr_events[0];
791 ++stats->nr_events[type];
792}
793
714void hists__inc_nr_events(struct hists *hists, u32 type) 794void hists__inc_nr_events(struct hists *hists, u32 type)
715{ 795{
716 ++hists->stats.nr_events[0]; 796 events_stats__inc(&hists->stats, type);
717 ++hists->stats.nr_events[type];
718} 797}
719 798
720static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 799static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
721 struct hist_entry *pair) 800 struct hist_entry *pair)
722{ 801{
723 struct rb_node **p = &hists->entries.rb_node; 802 struct rb_root *root;
803 struct rb_node **p;
724 struct rb_node *parent = NULL; 804 struct rb_node *parent = NULL;
725 struct hist_entry *he; 805 struct hist_entry *he;
726 int cmp; 806 int cmp;
727 807
808 if (sort__need_collapse)
809 root = &hists->entries_collapsed;
810 else
811 root = hists->entries_in;
812
813 p = &root->rb_node;
814
728 while (*p != NULL) { 815 while (*p != NULL) {
729 parent = *p; 816 parent = *p;
730 he = rb_entry(parent, struct hist_entry, rb_node); 817 he = rb_entry(parent, struct hist_entry, rb_node_in);
731 818
732 cmp = hist_entry__cmp(pair, he); 819 cmp = hist_entry__collapse(he, pair);
733 820
734 if (!cmp) 821 if (!cmp)
735 goto out; 822 goto out;
@@ -744,8 +831,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
744 if (he) { 831 if (he) {
745 memset(&he->stat, 0, sizeof(he->stat)); 832 memset(&he->stat, 0, sizeof(he->stat));
746 he->hists = hists; 833 he->hists = hists;
747 rb_link_node(&he->rb_node, parent, p); 834 rb_link_node(&he->rb_node_in, parent, p);
748 rb_insert_color(&he->rb_node, &hists->entries); 835 rb_insert_color(&he->rb_node_in, root);
749 hists__inc_nr_entries(hists, he); 836 hists__inc_nr_entries(hists, he);
750 } 837 }
751out: 838out:
@@ -755,11 +842,16 @@ out:
755static struct hist_entry *hists__find_entry(struct hists *hists, 842static struct hist_entry *hists__find_entry(struct hists *hists,
756 struct hist_entry *he) 843 struct hist_entry *he)
757{ 844{
758 struct rb_node *n = hists->entries.rb_node; 845 struct rb_node *n;
846
847 if (sort__need_collapse)
848 n = hists->entries_collapsed.rb_node;
849 else
850 n = hists->entries_in->rb_node;
759 851
760 while (n) { 852 while (n) {
761 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 853 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
762 int64_t cmp = hist_entry__cmp(he, iter); 854 int64_t cmp = hist_entry__collapse(iter, he);
763 855
764 if (cmp < 0) 856 if (cmp < 0)
765 n = n->rb_left; 857 n = n->rb_left;
@@ -777,15 +869,21 @@ static struct hist_entry *hists__find_entry(struct hists *hists,
777 */ 869 */
778void hists__match(struct hists *leader, struct hists *other) 870void hists__match(struct hists *leader, struct hists *other)
779{ 871{
872 struct rb_root *root;
780 struct rb_node *nd; 873 struct rb_node *nd;
781 struct hist_entry *pos, *pair; 874 struct hist_entry *pos, *pair;
782 875
783 for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { 876 if (sort__need_collapse)
784 pos = rb_entry(nd, struct hist_entry, rb_node); 877 root = &leader->entries_collapsed;
878 else
879 root = leader->entries_in;
880
881 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
882 pos = rb_entry(nd, struct hist_entry, rb_node_in);
785 pair = hists__find_entry(other, pos); 883 pair = hists__find_entry(other, pos);
786 884
787 if (pair) 885 if (pair)
788 hist__entry_add_pair(pos, pair); 886 hist_entry__add_pair(pair, pos);
789 } 887 }
790} 888}
791 889
@@ -796,17 +894,23 @@ void hists__match(struct hists *leader, struct hists *other)
796 */ 894 */
797int hists__link(struct hists *leader, struct hists *other) 895int hists__link(struct hists *leader, struct hists *other)
798{ 896{
897 struct rb_root *root;
799 struct rb_node *nd; 898 struct rb_node *nd;
800 struct hist_entry *pos, *pair; 899 struct hist_entry *pos, *pair;
801 900
802 for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { 901 if (sort__need_collapse)
803 pos = rb_entry(nd, struct hist_entry, rb_node); 902 root = &other->entries_collapsed;
903 else
904 root = other->entries_in;
905
906 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
907 pos = rb_entry(nd, struct hist_entry, rb_node_in);
804 908
805 if (!hist_entry__has_pairs(pos)) { 909 if (!hist_entry__has_pairs(pos)) {
806 pair = hists__add_dummy_entry(leader, pos); 910 pair = hists__add_dummy_entry(leader, pos);
807 if (pair == NULL) 911 if (pair == NULL)
808 return -1; 912 return -1;
809 hist__entry_add_pair(pair, pos); 913 hist_entry__add_pair(pos, pair);
810 } 914 }
811 } 915 }
812 916
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 8b091a51e4a2..38624686ee9a 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -96,8 +96,10 @@ void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
96 bool zap_kernel); 96 bool zap_kernel);
97void hists__output_recalc_col_len(struct hists *hists, int max_rows); 97void hists__output_recalc_col_len(struct hists *hists, int max_rows);
98 98
99void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
99void hists__inc_nr_events(struct hists *self, u32 type); 100void hists__inc_nr_events(struct hists *self, u32 type);
100size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 101void events_stats__inc(struct events_stats *stats, u32 type);
102size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
101 103
102size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, 104size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
103 int max_cols, FILE *fp); 105 int max_cols, FILE *fp);
@@ -126,13 +128,19 @@ struct perf_hpp {
126}; 128};
127 129
128struct perf_hpp_fmt { 130struct perf_hpp_fmt {
129 bool cond;
130 int (*header)(struct perf_hpp *hpp); 131 int (*header)(struct perf_hpp *hpp);
131 int (*width)(struct perf_hpp *hpp); 132 int (*width)(struct perf_hpp *hpp);
132 int (*color)(struct perf_hpp *hpp, struct hist_entry *he); 133 int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
133 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); 134 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
135
136 struct list_head list;
134}; 137};
135 138
139extern struct list_head perf_hpp__list;
140
141#define perf_hpp__for_each_format(format) \
142 list_for_each_entry(format, &perf_hpp__list, list)
143
136extern struct perf_hpp_fmt perf_hpp__format[]; 144extern struct perf_hpp_fmt perf_hpp__format[];
137 145
138enum { 146enum {
@@ -148,14 +156,14 @@ enum {
148 PERF_HPP__DELTA, 156 PERF_HPP__DELTA,
149 PERF_HPP__RATIO, 157 PERF_HPP__RATIO,
150 PERF_HPP__WEIGHTED_DIFF, 158 PERF_HPP__WEIGHTED_DIFF,
151 PERF_HPP__DISPL,
152 PERF_HPP__FORMULA, 159 PERF_HPP__FORMULA,
153 160
154 PERF_HPP__MAX_INDEX 161 PERF_HPP__MAX_INDEX
155}; 162};
156 163
157void perf_hpp__init(void); 164void perf_hpp__init(void);
158void perf_hpp__column_enable(unsigned col, bool enable); 165void perf_hpp__column_register(struct perf_hpp_fmt *format);
166void perf_hpp__column_enable(unsigned col);
159int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, 167int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
160 bool color); 168 bool color);
161 169
@@ -219,8 +227,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
219 227
220unsigned int hists__sort_list_width(struct hists *self); 228unsigned int hists__sort_list_width(struct hists *self);
221 229
222double perf_diff__compute_delta(struct hist_entry *he); 230double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
223double perf_diff__compute_ratio(struct hist_entry *he); 231double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
224s64 perf_diff__compute_wdiff(struct hist_entry *he); 232s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
225int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); 233int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
234 char *buf, size_t size);
235double perf_diff__period_percent(struct hist_entry *he, u64 period);
226#endif /* __PERF_HIST_H */ 236#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index a55d8cf083c9..45cf10a562bd 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -14,6 +14,7 @@
14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) 15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) 16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
17#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE)
17 18
18#define for_each_set_bit(bit, addr, size) \ 19#define for_each_set_bit(bit, addr, size) \
19 for ((bit) = find_first_bit((addr), (size)); \ 20 for ((bit) = find_first_bit((addr), (size)); \
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
index 9d0740024ba8..11a8d86f7fea 100644
--- a/tools/perf/util/intlist.c
+++ b/tools/perf/util/intlist.c
@@ -59,16 +59,40 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
59 59
60struct int_node *intlist__find(struct intlist *ilist, int i) 60struct int_node *intlist__find(struct intlist *ilist, int i)
61{ 61{
62 struct int_node *node = NULL; 62 struct int_node *node;
63 struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); 63 struct rb_node *rb_node;
64 64
65 if (ilist == NULL)
66 return NULL;
67
68 node = NULL;
69 rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
65 if (rb_node) 70 if (rb_node)
66 node = container_of(rb_node, struct int_node, rb_node); 71 node = container_of(rb_node, struct int_node, rb_node);
67 72
68 return node; 73 return node;
69} 74}
70 75
71struct intlist *intlist__new(void) 76static int intlist__parse_list(struct intlist *ilist, const char *s)
77{
78 char *sep;
79 int err;
80
81 do {
82 long value = strtol(s, &sep, 10);
83 err = -EINVAL;
84 if (*sep != ',' && *sep != '\0')
85 break;
86 err = intlist__add(ilist, value);
87 if (err)
88 break;
89 s = sep + 1;
90 } while (*sep != '\0');
91
92 return err;
93}
94
95struct intlist *intlist__new(const char *slist)
72{ 96{
73 struct intlist *ilist = malloc(sizeof(*ilist)); 97 struct intlist *ilist = malloc(sizeof(*ilist));
74 98
@@ -77,9 +101,15 @@ struct intlist *intlist__new(void)
77 ilist->rblist.node_cmp = intlist__node_cmp; 101 ilist->rblist.node_cmp = intlist__node_cmp;
78 ilist->rblist.node_new = intlist__node_new; 102 ilist->rblist.node_new = intlist__node_new;
79 ilist->rblist.node_delete = intlist__node_delete; 103 ilist->rblist.node_delete = intlist__node_delete;
104
105 if (slist && intlist__parse_list(ilist, slist))
106 goto out_delete;
80 } 107 }
81 108
82 return ilist; 109 return ilist;
110out_delete:
111 intlist__delete(ilist);
112 return NULL;
83} 113}
84 114
85void intlist__delete(struct intlist *ilist) 115void intlist__delete(struct intlist *ilist)
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
index 6d63ab90db50..62351dad848f 100644
--- a/tools/perf/util/intlist.h
+++ b/tools/perf/util/intlist.h
@@ -15,7 +15,7 @@ struct intlist {
15 struct rblist rblist; 15 struct rblist rblist;
16}; 16};
17 17
18struct intlist *intlist__new(void); 18struct intlist *intlist__new(const char *slist);
19void intlist__delete(struct intlist *ilist); 19void intlist__delete(struct intlist *ilist);
20 20
21void intlist__remove(struct intlist *ilist, struct int_node *in); 21void intlist__remove(struct intlist *ilist, struct int_node *in);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 1f09d0581e6b..efdb38e65a92 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1,10 +1,15 @@
1#include "callchain.h"
1#include "debug.h" 2#include "debug.h"
2#include "event.h" 3#include "event.h"
4#include "evsel.h"
5#include "hist.h"
3#include "machine.h" 6#include "machine.h"
4#include "map.h" 7#include "map.h"
8#include "sort.h"
5#include "strlist.h" 9#include "strlist.h"
6#include "thread.h" 10#include "thread.h"
7#include <stdbool.h> 11#include <stdbool.h>
12#include "unwind.h"
8 13
9int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 14int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
10{ 15{
@@ -48,6 +53,29 @@ static void dsos__delete(struct list_head *dsos)
48 } 53 }
49} 54}
50 55
56void machine__delete_dead_threads(struct machine *machine)
57{
58 struct thread *n, *t;
59
60 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
61 list_del(&t->node);
62 thread__delete(t);
63 }
64}
65
66void machine__delete_threads(struct machine *machine)
67{
68 struct rb_node *nd = rb_first(&machine->threads);
69
70 while (nd) {
71 struct thread *t = rb_entry(nd, struct thread, rb_node);
72
73 rb_erase(&t->rb_node, &machine->threads);
74 nd = rb_next(nd);
75 thread__delete(t);
76 }
77}
78
51void machine__exit(struct machine *machine) 79void machine__exit(struct machine *machine)
52{ 80{
53 map_groups__exit(&machine->kmaps); 81 map_groups__exit(&machine->kmaps);
@@ -63,10 +91,22 @@ void machine__delete(struct machine *machine)
63 free(machine); 91 free(machine);
64} 92}
65 93
66struct machine *machines__add(struct rb_root *machines, pid_t pid, 94void machines__init(struct machines *machines)
95{
96 machine__init(&machines->host, "", HOST_KERNEL_ID);
97 machines->guests = RB_ROOT;
98}
99
100void machines__exit(struct machines *machines)
101{
102 machine__exit(&machines->host);
103 /* XXX exit guest */
104}
105
106struct machine *machines__add(struct machines *machines, pid_t pid,
67 const char *root_dir) 107 const char *root_dir)
68{ 108{
69 struct rb_node **p = &machines->rb_node; 109 struct rb_node **p = &machines->guests.rb_node;
70 struct rb_node *parent = NULL; 110 struct rb_node *parent = NULL;
71 struct machine *pos, *machine = malloc(sizeof(*machine)); 111 struct machine *pos, *machine = malloc(sizeof(*machine));
72 112
@@ -88,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid,
88 } 128 }
89 129
90 rb_link_node(&machine->rb_node, parent, p); 130 rb_link_node(&machine->rb_node, parent, p);
91 rb_insert_color(&machine->rb_node, machines); 131 rb_insert_color(&machine->rb_node, &machines->guests);
92 132
93 return machine; 133 return machine;
94} 134}
95 135
96struct machine *machines__find(struct rb_root *machines, pid_t pid) 136struct machine *machines__find(struct machines *machines, pid_t pid)
97{ 137{
98 struct rb_node **p = &machines->rb_node; 138 struct rb_node **p = &machines->guests.rb_node;
99 struct rb_node *parent = NULL; 139 struct rb_node *parent = NULL;
100 struct machine *machine; 140 struct machine *machine;
101 struct machine *default_machine = NULL; 141 struct machine *default_machine = NULL;
102 142
143 if (pid == HOST_KERNEL_ID)
144 return &machines->host;
145
103 while (*p != NULL) { 146 while (*p != NULL) {
104 parent = *p; 147 parent = *p;
105 machine = rb_entry(parent, struct machine, rb_node); 148 machine = rb_entry(parent, struct machine, rb_node);
@@ -116,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid)
116 return default_machine; 159 return default_machine;
117} 160}
118 161
119struct machine *machines__findnew(struct rb_root *machines, pid_t pid) 162struct machine *machines__findnew(struct machines *machines, pid_t pid)
120{ 163{
121 char path[PATH_MAX]; 164 char path[PATH_MAX];
122 const char *root_dir = ""; 165 const char *root_dir = "";
@@ -150,12 +193,12 @@ out:
150 return machine; 193 return machine;
151} 194}
152 195
153void machines__process(struct rb_root *machines, 196void machines__process_guests(struct machines *machines,
154 machine__process_t process, void *data) 197 machine__process_t process, void *data)
155{ 198{
156 struct rb_node *nd; 199 struct rb_node *nd;
157 200
158 for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 201 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
159 struct machine *pos = rb_entry(nd, struct machine, rb_node); 202 struct machine *pos = rb_entry(nd, struct machine, rb_node);
160 process(pos, data); 203 process(pos, data);
161 } 204 }
@@ -175,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
175 return bf; 218 return bf;
176} 219}
177 220
178void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) 221void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
179{ 222{
180 struct rb_node *node; 223 struct rb_node *node;
181 struct machine *machine; 224 struct machine *machine;
182 225
183 for (node = rb_first(machines); node; node = rb_next(node)) { 226 machines->host.id_hdr_size = id_hdr_size;
227
228 for (node = rb_first(&machines->guests); node; node = rb_next(node)) {
184 machine = rb_entry(node, struct machine, rb_node); 229 machine = rb_entry(node, struct machine, rb_node);
185 machine->id_hdr_size = id_hdr_size; 230 machine->id_hdr_size = id_hdr_size;
186 } 231 }
@@ -264,6 +309,537 @@ int machine__process_lost_event(struct machine *machine __maybe_unused,
264 return 0; 309 return 0;
265} 310}
266 311
312struct map *machine__new_module(struct machine *machine, u64 start,
313 const char *filename)
314{
315 struct map *map;
316 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
317
318 if (dso == NULL)
319 return NULL;
320
321 map = map__new2(start, dso, MAP__FUNCTION);
322 if (map == NULL)
323 return NULL;
324
325 if (machine__is_host(machine))
326 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
327 else
328 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
329 map_groups__insert(&machine->kmaps, map);
330 return map;
331}
332
333size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
334{
335 struct rb_node *nd;
336 size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
337 __dsos__fprintf(&machines->host.user_dsos, fp);
338
339 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
340 struct machine *pos = rb_entry(nd, struct machine, rb_node);
341 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
342 ret += __dsos__fprintf(&pos->user_dsos, fp);
343 }
344
345 return ret;
346}
347
348size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
349 bool (skip)(struct dso *dso, int parm), int parm)
350{
351 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) +
352 __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
353}
354
355size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
356 bool (skip)(struct dso *dso, int parm), int parm)
357{
358 struct rb_node *nd;
359 size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
360
361 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
362 struct machine *pos = rb_entry(nd, struct machine, rb_node);
363 ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
364 }
365 return ret;
366}
367
368size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
369{
370 int i;
371 size_t printed = 0;
372 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
373
374 if (kdso->has_build_id) {
375 char filename[PATH_MAX];
376 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
377 printed += fprintf(fp, "[0] %s\n", filename);
378 }
379
380 for (i = 0; i < vmlinux_path__nr_entries; ++i)
381 printed += fprintf(fp, "[%d] %s\n",
382 i + kdso->has_build_id, vmlinux_path[i]);
383
384 return printed;
385}
386
387size_t machine__fprintf(struct machine *machine, FILE *fp)
388{
389 size_t ret = 0;
390 struct rb_node *nd;
391
392 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
393 struct thread *pos = rb_entry(nd, struct thread, rb_node);
394
395 ret += thread__fprintf(pos, fp);
396 }
397
398 return ret;
399}
400
401static struct dso *machine__get_kernel(struct machine *machine)
402{
403 const char *vmlinux_name = NULL;
404 struct dso *kernel;
405
406 if (machine__is_host(machine)) {
407 vmlinux_name = symbol_conf.vmlinux_name;
408 if (!vmlinux_name)
409 vmlinux_name = "[kernel.kallsyms]";
410
411 kernel = dso__kernel_findnew(machine, vmlinux_name,
412 "[kernel]",
413 DSO_TYPE_KERNEL);
414 } else {
415 char bf[PATH_MAX];
416
417 if (machine__is_default_guest(machine))
418 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
419 if (!vmlinux_name)
420 vmlinux_name = machine__mmap_name(machine, bf,
421 sizeof(bf));
422
423 kernel = dso__kernel_findnew(machine, vmlinux_name,
424 "[guest.kernel]",
425 DSO_TYPE_GUEST_KERNEL);
426 }
427
428 if (kernel != NULL && (!kernel->has_build_id))
429 dso__read_running_kernel_build_id(kernel, machine);
430
431 return kernel;
432}
433
434struct process_args {
435 u64 start;
436};
437
438static int symbol__in_kernel(void *arg, const char *name,
439 char type __maybe_unused, u64 start)
440{
441 struct process_args *args = arg;
442
443 if (strchr(name, '['))
444 return 0;
445
446 args->start = start;
447 return 1;
448}
449
450/* Figure out the start address of kernel map from /proc/kallsyms */
451static u64 machine__get_kernel_start_addr(struct machine *machine)
452{
453 const char *filename;
454 char path[PATH_MAX];
455 struct process_args args;
456
457 if (machine__is_host(machine)) {
458 filename = "/proc/kallsyms";
459 } else {
460 if (machine__is_default_guest(machine))
461 filename = (char *)symbol_conf.default_guest_kallsyms;
462 else {
463 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
464 filename = path;
465 }
466 }
467
468 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
469 return 0;
470
471 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
472 return 0;
473
474 return args.start;
475}
476
477int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
478{
479 enum map_type type;
480 u64 start = machine__get_kernel_start_addr(machine);
481
482 for (type = 0; type < MAP__NR_TYPES; ++type) {
483 struct kmap *kmap;
484
485 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
486 if (machine->vmlinux_maps[type] == NULL)
487 return -1;
488
489 machine->vmlinux_maps[type]->map_ip =
490 machine->vmlinux_maps[type]->unmap_ip =
491 identity__map_ip;
492 kmap = map__kmap(machine->vmlinux_maps[type]);
493 kmap->kmaps = &machine->kmaps;
494 map_groups__insert(&machine->kmaps,
495 machine->vmlinux_maps[type]);
496 }
497
498 return 0;
499}
500
501void machine__destroy_kernel_maps(struct machine *machine)
502{
503 enum map_type type;
504
505 for (type = 0; type < MAP__NR_TYPES; ++type) {
506 struct kmap *kmap;
507
508 if (machine->vmlinux_maps[type] == NULL)
509 continue;
510
511 kmap = map__kmap(machine->vmlinux_maps[type]);
512 map_groups__remove(&machine->kmaps,
513 machine->vmlinux_maps[type]);
514 if (kmap->ref_reloc_sym) {
515 /*
516 * ref_reloc_sym is shared among all maps, so free just
517 * on one of them.
518 */
519 if (type == MAP__FUNCTION) {
520 free((char *)kmap->ref_reloc_sym->name);
521 kmap->ref_reloc_sym->name = NULL;
522 free(kmap->ref_reloc_sym);
523 }
524 kmap->ref_reloc_sym = NULL;
525 }
526
527 map__delete(machine->vmlinux_maps[type]);
528 machine->vmlinux_maps[type] = NULL;
529 }
530}
531
532int machines__create_guest_kernel_maps(struct machines *machines)
533{
534 int ret = 0;
535 struct dirent **namelist = NULL;
536 int i, items = 0;
537 char path[PATH_MAX];
538 pid_t pid;
539 char *endp;
540
541 if (symbol_conf.default_guest_vmlinux_name ||
542 symbol_conf.default_guest_modules ||
543 symbol_conf.default_guest_kallsyms) {
544 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
545 }
546
547 if (symbol_conf.guestmount) {
548 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
549 if (items <= 0)
550 return -ENOENT;
551 for (i = 0; i < items; i++) {
552 if (!isdigit(namelist[i]->d_name[0])) {
553 /* Filter out . and .. */
554 continue;
555 }
556 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
557 if ((*endp != '\0') ||
558 (endp == namelist[i]->d_name) ||
559 (errno == ERANGE)) {
560 pr_debug("invalid directory (%s). Skipping.\n",
561 namelist[i]->d_name);
562 continue;
563 }
564 sprintf(path, "%s/%s/proc/kallsyms",
565 symbol_conf.guestmount,
566 namelist[i]->d_name);
567 ret = access(path, R_OK);
568 if (ret) {
569 pr_debug("Can't access file %s\n", path);
570 goto failure;
571 }
572 machines__create_kernel_maps(machines, pid);
573 }
574failure:
575 free(namelist);
576 }
577
578 return ret;
579}
580
581void machines__destroy_kernel_maps(struct machines *machines)
582{
583 struct rb_node *next = rb_first(&machines->guests);
584
585 machine__destroy_kernel_maps(&machines->host);
586
587 while (next) {
588 struct machine *pos = rb_entry(next, struct machine, rb_node);
589
590 next = rb_next(&pos->rb_node);
591 rb_erase(&pos->rb_node, &machines->guests);
592 machine__delete(pos);
593 }
594}
595
596int machines__create_kernel_maps(struct machines *machines, pid_t pid)
597{
598 struct machine *machine = machines__findnew(machines, pid);
599
600 if (machine == NULL)
601 return -1;
602
603 return machine__create_kernel_maps(machine);
604}
605
606int machine__load_kallsyms(struct machine *machine, const char *filename,
607 enum map_type type, symbol_filter_t filter)
608{
609 struct map *map = machine->vmlinux_maps[type];
610 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
611
612 if (ret > 0) {
613 dso__set_loaded(map->dso, type);
614 /*
615 * Since /proc/kallsyms will have multiple sessions for the
616 * kernel, with modules between them, fixup the end of all
617 * sections.
618 */
619 __map_groups__fixup_end(&machine->kmaps, type);
620 }
621
622 return ret;
623}
624
625int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
626 symbol_filter_t filter)
627{
628 struct map *map = machine->vmlinux_maps[type];
629 int ret = dso__load_vmlinux_path(map->dso, map, filter);
630
631 if (ret > 0) {
632 dso__set_loaded(map->dso, type);
633 map__reloc_vmlinux(map);
634 }
635
636 return ret;
637}
638
639static void map_groups__fixup_end(struct map_groups *mg)
640{
641 int i;
642 for (i = 0; i < MAP__NR_TYPES; ++i)
643 __map_groups__fixup_end(mg, i);
644}
645
646static char *get_kernel_version(const char *root_dir)
647{
648 char version[PATH_MAX];
649 FILE *file;
650 char *name, *tmp;
651 const char *prefix = "Linux version ";
652
653 sprintf(version, "%s/proc/version", root_dir);
654 file = fopen(version, "r");
655 if (!file)
656 return NULL;
657
658 version[0] = '\0';
659 tmp = fgets(version, sizeof(version), file);
660 fclose(file);
661
662 name = strstr(version, prefix);
663 if (!name)
664 return NULL;
665 name += strlen(prefix);
666 tmp = strchr(name, ' ');
667 if (tmp)
668 *tmp = '\0';
669
670 return strdup(name);
671}
672
673static int map_groups__set_modules_path_dir(struct map_groups *mg,
674 const char *dir_name)
675{
676 struct dirent *dent;
677 DIR *dir = opendir(dir_name);
678 int ret = 0;
679
680 if (!dir) {
681 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
682 return -1;
683 }
684
685 while ((dent = readdir(dir)) != NULL) {
686 char path[PATH_MAX];
687 struct stat st;
688
689 /*sshfs might return bad dent->d_type, so we have to stat*/
690 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
691 if (stat(path, &st))
692 continue;
693
694 if (S_ISDIR(st.st_mode)) {
695 if (!strcmp(dent->d_name, ".") ||
696 !strcmp(dent->d_name, ".."))
697 continue;
698
699 ret = map_groups__set_modules_path_dir(mg, path);
700 if (ret < 0)
701 goto out;
702 } else {
703 char *dot = strrchr(dent->d_name, '.'),
704 dso_name[PATH_MAX];
705 struct map *map;
706 char *long_name;
707
708 if (dot == NULL || strcmp(dot, ".ko"))
709 continue;
710 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
711 (int)(dot - dent->d_name), dent->d_name);
712
713 strxfrchar(dso_name, '-', '_');
714 map = map_groups__find_by_name(mg, MAP__FUNCTION,
715 dso_name);
716 if (map == NULL)
717 continue;
718
719 long_name = strdup(path);
720 if (long_name == NULL) {
721 ret = -1;
722 goto out;
723 }
724 dso__set_long_name(map->dso, long_name);
725 map->dso->lname_alloc = 1;
726 dso__kernel_module_get_build_id(map->dso, "");
727 }
728 }
729
730out:
731 closedir(dir);
732 return ret;
733}
734
735static int machine__set_modules_path(struct machine *machine)
736{
737 char *version;
738 char modules_path[PATH_MAX];
739
740 version = get_kernel_version(machine->root_dir);
741 if (!version)
742 return -1;
743
744 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
745 machine->root_dir, version);
746 free(version);
747
748 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
749}
750
751static int machine__create_modules(struct machine *machine)
752{
753 char *line = NULL;
754 size_t n;
755 FILE *file;
756 struct map *map;
757 const char *modules;
758 char path[PATH_MAX];
759
760 if (machine__is_default_guest(machine))
761 modules = symbol_conf.default_guest_modules;
762 else {
763 sprintf(path, "%s/proc/modules", machine->root_dir);
764 modules = path;
765 }
766
767 if (symbol__restricted_filename(path, "/proc/modules"))
768 return -1;
769
770 file = fopen(modules, "r");
771 if (file == NULL)
772 return -1;
773
774 while (!feof(file)) {
775 char name[PATH_MAX];
776 u64 start;
777 char *sep;
778 int line_len;
779
780 line_len = getline(&line, &n, file);
781 if (line_len < 0)
782 break;
783
784 if (!line)
785 goto out_failure;
786
787 line[--line_len] = '\0'; /* \n */
788
789 sep = strrchr(line, 'x');
790 if (sep == NULL)
791 continue;
792
793 hex2u64(sep + 1, &start);
794
795 sep = strchr(line, ' ');
796 if (sep == NULL)
797 continue;
798
799 *sep = '\0';
800
801 snprintf(name, sizeof(name), "[%s]", line);
802 map = machine__new_module(machine, start, name);
803 if (map == NULL)
804 goto out_delete_line;
805 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
806 }
807
808 free(line);
809 fclose(file);
810
811 return machine__set_modules_path(machine);
812
813out_delete_line:
814 free(line);
815out_failure:
816 return -1;
817}
818
819int machine__create_kernel_maps(struct machine *machine)
820{
821 struct dso *kernel = machine__get_kernel(machine);
822
823 if (kernel == NULL ||
824 __machine__create_kernel_maps(machine, kernel) < 0)
825 return -1;
826
827 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
828 if (machine__is_host(machine))
829 pr_debug("Problems creating module maps, "
830 "continuing anyway...\n");
831 else
832 pr_debug("Problems creating module maps for guest %d, "
833 "continuing anyway...\n", machine->pid);
834 }
835
836 /*
837 * Now that we have all the maps created, just set the ->end of them:
838 */
839 map_groups__fixup_end(&machine->kmaps);
840 return 0;
841}
842
267static void machine__set_kernel_mmap_len(struct machine *machine, 843static void machine__set_kernel_mmap_len(struct machine *machine,
268 union perf_event *event) 844 union perf_event *event)
269{ 845{
@@ -462,3 +1038,189 @@ int machine__process_event(struct machine *machine, union perf_event *event)
462 1038
463 return ret; 1039 return ret;
464} 1040}
1041
1042void machine__remove_thread(struct machine *machine, struct thread *th)
1043{
1044 machine->last_match = NULL;
1045 rb_erase(&th->rb_node, &machine->threads);
1046 /*
1047 * We may have references to this thread, for instance in some hist_entry
1048 * instances, so just move them to a separate list.
1049 */
1050 list_add_tail(&th->node, &machine->dead_threads);
1051}
1052
1053static bool symbol__match_parent_regex(struct symbol *sym)
1054{
1055 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
1056 return 1;
1057
1058 return 0;
1059}
1060
1061static const u8 cpumodes[] = {
1062 PERF_RECORD_MISC_USER,
1063 PERF_RECORD_MISC_KERNEL,
1064 PERF_RECORD_MISC_GUEST_USER,
1065 PERF_RECORD_MISC_GUEST_KERNEL
1066};
1067#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
1068
1069static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1070 struct addr_map_symbol *ams,
1071 u64 ip)
1072{
1073 struct addr_location al;
1074 size_t i;
1075 u8 m;
1076
1077 memset(&al, 0, sizeof(al));
1078
1079 for (i = 0; i < NCPUMODES; i++) {
1080 m = cpumodes[i];
1081 /*
1082 * We cannot use the header.misc hint to determine whether a
1083 * branch stack address is user, kernel, guest, hypervisor.
1084 * Branches may straddle the kernel/user/hypervisor boundaries.
1085 * Thus, we have to try consecutively until we find a match
1086 * or else, the symbol is unknown
1087 */
1088 thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
1089 ip, &al, NULL);
1090 if (al.sym)
1091 goto found;
1092 }
1093found:
1094 ams->addr = ip;
1095 ams->al_addr = al.addr;
1096 ams->sym = al.sym;
1097 ams->map = al.map;
1098}
1099
1100struct branch_info *machine__resolve_bstack(struct machine *machine,
1101 struct thread *thr,
1102 struct branch_stack *bs)
1103{
1104 struct branch_info *bi;
1105 unsigned int i;
1106
1107 bi = calloc(bs->nr, sizeof(struct branch_info));
1108 if (!bi)
1109 return NULL;
1110
1111 for (i = 0; i < bs->nr; i++) {
1112 ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to);
1113 ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from);
1114 bi[i].flags = bs->entries[i].flags;
1115 }
1116 return bi;
1117}
1118
1119static int machine__resolve_callchain_sample(struct machine *machine,
1120 struct thread *thread,
1121 struct ip_callchain *chain,
1122 struct symbol **parent)
1123
1124{
1125 u8 cpumode = PERF_RECORD_MISC_USER;
1126 unsigned int i;
1127 int err;
1128
1129 callchain_cursor_reset(&callchain_cursor);
1130
1131 if (chain->nr > PERF_MAX_STACK_DEPTH) {
1132 pr_warning("corrupted callchain. skipping...\n");
1133 return 0;
1134 }
1135
1136 for (i = 0; i < chain->nr; i++) {
1137 u64 ip;
1138 struct addr_location al;
1139
1140 if (callchain_param.order == ORDER_CALLEE)
1141 ip = chain->ips[i];
1142 else
1143 ip = chain->ips[chain->nr - i - 1];
1144
1145 if (ip >= PERF_CONTEXT_MAX) {
1146 switch (ip) {
1147 case PERF_CONTEXT_HV:
1148 cpumode = PERF_RECORD_MISC_HYPERVISOR;
1149 break;
1150 case PERF_CONTEXT_KERNEL:
1151 cpumode = PERF_RECORD_MISC_KERNEL;
1152 break;
1153 case PERF_CONTEXT_USER:
1154 cpumode = PERF_RECORD_MISC_USER;
1155 break;
1156 default:
1157 pr_debug("invalid callchain context: "
1158 "%"PRId64"\n", (s64) ip);
1159 /*
1160 * It seems the callchain is corrupted.
1161 * Discard all.
1162 */
1163 callchain_cursor_reset(&callchain_cursor);
1164 return 0;
1165 }
1166 continue;
1167 }
1168
1169 al.filtered = false;
1170 thread__find_addr_location(thread, machine, cpumode,
1171 MAP__FUNCTION, ip, &al, NULL);
1172 if (al.sym != NULL) {
1173 if (sort__has_parent && !*parent &&
1174 symbol__match_parent_regex(al.sym))
1175 *parent = al.sym;
1176 if (!symbol_conf.use_callchain)
1177 break;
1178 }
1179
1180 err = callchain_cursor_append(&callchain_cursor,
1181 ip, al.map, al.sym);
1182 if (err)
1183 return err;
1184 }
1185
1186 return 0;
1187}
1188
1189static int unwind_entry(struct unwind_entry *entry, void *arg)
1190{
1191 struct callchain_cursor *cursor = arg;
1192 return callchain_cursor_append(cursor, entry->ip,
1193 entry->map, entry->sym);
1194}
1195
1196int machine__resolve_callchain(struct machine *machine,
1197 struct perf_evsel *evsel,
1198 struct thread *thread,
1199 struct perf_sample *sample,
1200 struct symbol **parent)
1201
1202{
1203 int ret;
1204
1205 callchain_cursor_reset(&callchain_cursor);
1206
1207 ret = machine__resolve_callchain_sample(machine, thread,
1208 sample->callchain, parent);
1209 if (ret)
1210 return ret;
1211
1212 /* Can we do dwarf post unwind? */
1213 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
1214 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
1215 return 0;
1216
1217 /* Bail out if nothing was captured. */
1218 if ((!sample->user_regs.regs) ||
1219 (!sample->user_stack.size))
1220 return 0;
1221
1222 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
1223 thread, evsel->attr.sample_regs_user,
1224 sample);
1225
1226}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index b7cde7467d55..5ac5892f2326 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -47,23 +47,32 @@ int machine__process_event(struct machine *machine, union perf_event *event);
47 47
48typedef void (*machine__process_t)(struct machine *machine, void *data); 48typedef void (*machine__process_t)(struct machine *machine, void *data);
49 49
50void machines__process(struct rb_root *machines, 50struct machines {
51 machine__process_t process, void *data); 51 struct machine host;
52 struct rb_root guests;
53};
54
55void machines__init(struct machines *machines);
56void machines__exit(struct machines *machines);
52 57
53struct machine *machines__add(struct rb_root *machines, pid_t pid, 58void machines__process_guests(struct machines *machines,
59 machine__process_t process, void *data);
60
61struct machine *machines__add(struct machines *machines, pid_t pid,
54 const char *root_dir); 62 const char *root_dir);
55struct machine *machines__find_host(struct rb_root *machines); 63struct machine *machines__find_host(struct machines *machines);
56struct machine *machines__find(struct rb_root *machines, pid_t pid); 64struct machine *machines__find(struct machines *machines, pid_t pid);
57struct machine *machines__findnew(struct rb_root *machines, pid_t pid); 65struct machine *machines__findnew(struct machines *machines, pid_t pid);
58 66
59void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size); 67void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
60char *machine__mmap_name(struct machine *machine, char *bf, size_t size); 68char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
61 69
62int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 70int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
63void machine__exit(struct machine *machine); 71void machine__exit(struct machine *machine);
72void machine__delete_dead_threads(struct machine *machine);
73void machine__delete_threads(struct machine *machine);
64void machine__delete(struct machine *machine); 74void machine__delete(struct machine *machine);
65 75
66
67struct branch_info *machine__resolve_bstack(struct machine *machine, 76struct branch_info *machine__resolve_bstack(struct machine *machine,
68 struct thread *thread, 77 struct thread *thread,
69 struct branch_stack *bs); 78 struct branch_stack *bs);
@@ -129,19 +138,19 @@ int machine__load_kallsyms(struct machine *machine, const char *filename,
129int machine__load_vmlinux_path(struct machine *machine, enum map_type type, 138int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
130 symbol_filter_t filter); 139 symbol_filter_t filter);
131 140
132size_t machine__fprintf_dsos_buildid(struct machine *machine, 141size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
133 FILE *fp, bool with_hits); 142 bool (skip)(struct dso *dso, int parm), int parm);
134size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); 143size_t machines__fprintf_dsos(struct machines *machines, FILE *fp);
135size_t machines__fprintf_dsos_buildid(struct rb_root *machines, 144size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
136 FILE *fp, bool with_hits); 145 bool (skip)(struct dso *dso, int parm), int parm);
137 146
138void machine__destroy_kernel_maps(struct machine *machine); 147void machine__destroy_kernel_maps(struct machine *machine);
139int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); 148int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
140int machine__create_kernel_maps(struct machine *machine); 149int machine__create_kernel_maps(struct machine *machine);
141 150
142int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); 151int machines__create_kernel_maps(struct machines *machines, pid_t pid);
143int machines__create_guest_kernel_maps(struct rb_root *machines); 152int machines__create_guest_kernel_maps(struct machines *machines);
144void machines__destroy_guest_kernel_maps(struct rb_root *machines); 153void machines__destroy_kernel_maps(struct machines *machines);
145 154
146size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 155size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
147 156
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 0328d45c4f2a..6fcb9de62340 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -11,6 +11,7 @@
11#include "strlist.h" 11#include "strlist.h"
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h" 13#include "build-id.h"
14#include <linux/string.h>
14 15
15const char *map_type__name[MAP__NR_TYPES] = { 16const char *map_type__name[MAP__NR_TYPES] = {
16 [MAP__FUNCTION] = "Functions", 17 [MAP__FUNCTION] = "Functions",
@@ -19,7 +20,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
19 20
20static inline int is_anon_memory(const char *filename) 21static inline int is_anon_memory(const char *filename)
21{ 22{
22 return strcmp(filename, "//anon") == 0; 23 return !strcmp(filename, "//anon") ||
24 !strcmp(filename, "/anon_hugepage (deleted)");
23} 25}
24 26
25static inline int is_no_dso_memory(const char *filename) 27static inline int is_no_dso_memory(const char *filename)
@@ -28,29 +30,29 @@ static inline int is_no_dso_memory(const char *filename)
28 !strcmp(filename, "[heap]"); 30 !strcmp(filename, "[heap]");
29} 31}
30 32
31void map__init(struct map *self, enum map_type type, 33void map__init(struct map *map, enum map_type type,
32 u64 start, u64 end, u64 pgoff, struct dso *dso) 34 u64 start, u64 end, u64 pgoff, struct dso *dso)
33{ 35{
34 self->type = type; 36 map->type = type;
35 self->start = start; 37 map->start = start;
36 self->end = end; 38 map->end = end;
37 self->pgoff = pgoff; 39 map->pgoff = pgoff;
38 self->dso = dso; 40 map->dso = dso;
39 self->map_ip = map__map_ip; 41 map->map_ip = map__map_ip;
40 self->unmap_ip = map__unmap_ip; 42 map->unmap_ip = map__unmap_ip;
41 RB_CLEAR_NODE(&self->rb_node); 43 RB_CLEAR_NODE(&map->rb_node);
42 self->groups = NULL; 44 map->groups = NULL;
43 self->referenced = false; 45 map->referenced = false;
44 self->erange_warned = false; 46 map->erange_warned = false;
45} 47}
46 48
47struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 49struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
48 u64 pgoff, u32 pid, char *filename, 50 u64 pgoff, u32 pid, char *filename,
49 enum map_type type) 51 enum map_type type)
50{ 52{
51 struct map *self = malloc(sizeof(*self)); 53 struct map *map = malloc(sizeof(*map));
52 54
53 if (self != NULL) { 55 if (map != NULL) {
54 char newfilename[PATH_MAX]; 56 char newfilename[PATH_MAX];
55 struct dso *dso; 57 struct dso *dso;
56 int anon, no_dso, vdso; 58 int anon, no_dso, vdso;
@@ -73,10 +75,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
73 if (dso == NULL) 75 if (dso == NULL)
74 goto out_delete; 76 goto out_delete;
75 77
76 map__init(self, type, start, start + len, pgoff, dso); 78 map__init(map, type, start, start + len, pgoff, dso);
77 79
78 if (anon || no_dso) { 80 if (anon || no_dso) {
79 self->map_ip = self->unmap_ip = identity__map_ip; 81 map->map_ip = map->unmap_ip = identity__map_ip;
80 82
81 /* 83 /*
82 * Set memory without DSO as loaded. All map__find_* 84 * Set memory without DSO as loaded. All map__find_*
@@ -84,12 +86,12 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
84 * unnecessary map__load warning. 86 * unnecessary map__load warning.
85 */ 87 */
86 if (no_dso) 88 if (no_dso)
87 dso__set_loaded(dso, self->type); 89 dso__set_loaded(dso, map->type);
88 } 90 }
89 } 91 }
90 return self; 92 return map;
91out_delete: 93out_delete:
92 free(self); 94 free(map);
93 return NULL; 95 return NULL;
94} 96}
95 97
@@ -112,48 +114,48 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
112 return map; 114 return map;
113} 115}
114 116
115void map__delete(struct map *self) 117void map__delete(struct map *map)
116{ 118{
117 free(self); 119 free(map);
118} 120}
119 121
120void map__fixup_start(struct map *self) 122void map__fixup_start(struct map *map)
121{ 123{
122 struct rb_root *symbols = &self->dso->symbols[self->type]; 124 struct rb_root *symbols = &map->dso->symbols[map->type];
123 struct rb_node *nd = rb_first(symbols); 125 struct rb_node *nd = rb_first(symbols);
124 if (nd != NULL) { 126 if (nd != NULL) {
125 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 127 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
126 self->start = sym->start; 128 map->start = sym->start;
127 } 129 }
128} 130}
129 131
130void map__fixup_end(struct map *self) 132void map__fixup_end(struct map *map)
131{ 133{
132 struct rb_root *symbols = &self->dso->symbols[self->type]; 134 struct rb_root *symbols = &map->dso->symbols[map->type];
133 struct rb_node *nd = rb_last(symbols); 135 struct rb_node *nd = rb_last(symbols);
134 if (nd != NULL) { 136 if (nd != NULL) {
135 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 137 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
136 self->end = sym->end; 138 map->end = sym->end;
137 } 139 }
138} 140}
139 141
140#define DSO__DELETED "(deleted)" 142#define DSO__DELETED "(deleted)"
141 143
142int map__load(struct map *self, symbol_filter_t filter) 144int map__load(struct map *map, symbol_filter_t filter)
143{ 145{
144 const char *name = self->dso->long_name; 146 const char *name = map->dso->long_name;
145 int nr; 147 int nr;
146 148
147 if (dso__loaded(self->dso, self->type)) 149 if (dso__loaded(map->dso, map->type))
148 return 0; 150 return 0;
149 151
150 nr = dso__load(self->dso, self, filter); 152 nr = dso__load(map->dso, map, filter);
151 if (nr < 0) { 153 if (nr < 0) {
152 if (self->dso->has_build_id) { 154 if (map->dso->has_build_id) {
153 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 155 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
154 156
155 build_id__sprintf(self->dso->build_id, 157 build_id__sprintf(map->dso->build_id,
156 sizeof(self->dso->build_id), 158 sizeof(map->dso->build_id),
157 sbuild_id); 159 sbuild_id);
158 pr_warning("%s with build id %s not found", 160 pr_warning("%s with build id %s not found",
159 name, sbuild_id); 161 name, sbuild_id);
@@ -183,43 +185,36 @@ int map__load(struct map *self, symbol_filter_t filter)
183 * Only applies to the kernel, as its symtabs aren't relative like the 185 * Only applies to the kernel, as its symtabs aren't relative like the
184 * module ones. 186 * module ones.
185 */ 187 */
186 if (self->dso->kernel) 188 if (map->dso->kernel)
187 map__reloc_vmlinux(self); 189 map__reloc_vmlinux(map);
188 190
189 return 0; 191 return 0;
190} 192}
191 193
192struct symbol *map__find_symbol(struct map *self, u64 addr, 194struct symbol *map__find_symbol(struct map *map, u64 addr,
193 symbol_filter_t filter) 195 symbol_filter_t filter)
194{ 196{
195 if (map__load(self, filter) < 0) 197 if (map__load(map, filter) < 0)
196 return NULL; 198 return NULL;
197 199
198 return dso__find_symbol(self->dso, self->type, addr); 200 return dso__find_symbol(map->dso, map->type, addr);
199} 201}
200 202
201struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 203struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
202 symbol_filter_t filter) 204 symbol_filter_t filter)
203{ 205{
204 if (map__load(self, filter) < 0) 206 if (map__load(map, filter) < 0)
205 return NULL; 207 return NULL;
206 208
207 if (!dso__sorted_by_name(self->dso, self->type)) 209 if (!dso__sorted_by_name(map->dso, map->type))
208 dso__sort_by_name(self->dso, self->type); 210 dso__sort_by_name(map->dso, map->type);
209 211
210 return dso__find_symbol_by_name(self->dso, self->type, name); 212 return dso__find_symbol_by_name(map->dso, map->type, name);
211} 213}
212 214
213struct map *map__clone(struct map *self) 215struct map *map__clone(struct map *map)
214{ 216{
215 struct map *map = malloc(sizeof(*self)); 217 return memdup(map, sizeof(*map));
216
217 if (!map)
218 return NULL;
219
220 memcpy(map, self, sizeof(*self));
221
222 return map;
223} 218}
224 219
225int map__overlap(struct map *l, struct map *r) 220int map__overlap(struct map *l, struct map *r)
@@ -236,10 +231,10 @@ int map__overlap(struct map *l, struct map *r)
236 return 0; 231 return 0;
237} 232}
238 233
239size_t map__fprintf(struct map *self, FILE *fp) 234size_t map__fprintf(struct map *map, FILE *fp)
240{ 235{
241 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 236 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
242 self->start, self->end, self->pgoff, self->dso->name); 237 map->start, map->end, map->pgoff, map->dso->name);
243} 238}
244 239
245size_t map__fprintf_dsoname(struct map *map, FILE *fp) 240size_t map__fprintf_dsoname(struct map *map, FILE *fp)
@@ -527,9 +522,9 @@ static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
527 return ip - (s64)map->pgoff; 522 return ip - (s64)map->pgoff;
528} 523}
529 524
530void map__reloc_vmlinux(struct map *self) 525void map__reloc_vmlinux(struct map *map)
531{ 526{
532 struct kmap *kmap = map__kmap(self); 527 struct kmap *kmap = map__kmap(map);
533 s64 reloc; 528 s64 reloc;
534 529
535 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr) 530 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
@@ -541,9 +536,9 @@ void map__reloc_vmlinux(struct map *self)
541 if (!reloc) 536 if (!reloc)
542 return; 537 return;
543 538
544 self->map_ip = map__reloc_map_ip; 539 map->map_ip = map__reloc_map_ip;
545 self->unmap_ip = map__reloc_unmap_ip; 540 map->unmap_ip = map__reloc_unmap_ip;
546 self->pgoff = reloc; 541 map->pgoff = reloc;
547} 542}
548 543
549void maps__insert(struct rb_root *maps, struct map *map) 544void maps__insert(struct rb_root *maps, struct map *map)
@@ -566,9 +561,9 @@ void maps__insert(struct rb_root *maps, struct map *map)
566 rb_insert_color(&map->rb_node, maps); 561 rb_insert_color(&map->rb_node, maps);
567} 562}
568 563
569void maps__remove(struct rb_root *self, struct map *map) 564void maps__remove(struct rb_root *maps, struct map *map)
570{ 565{
571 rb_erase(&map->rb_node, self); 566 rb_erase(&map->rb_node, maps);
572} 567}
573 568
574struct map *maps__find(struct rb_root *maps, u64 ip) 569struct map *maps__find(struct rb_root *maps, u64 ip)
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index bcb39e2a6965..a887f2c9dfbb 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -57,9 +57,9 @@ struct map_groups {
57 struct machine *machine; 57 struct machine *machine;
58}; 58};
59 59
60static inline struct kmap *map__kmap(struct map *self) 60static inline struct kmap *map__kmap(struct map *map)
61{ 61{
62 return (struct kmap *)(self + 1); 62 return (struct kmap *)(map + 1);
63} 63}
64 64
65static inline u64 map__map_ip(struct map *map, u64 ip) 65static inline u64 map__map_ip(struct map *map, u64 ip)
@@ -85,27 +85,27 @@ struct symbol;
85 85
86typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 86typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
87 87
88void map__init(struct map *self, enum map_type type, 88void map__init(struct map *map, enum map_type type,
89 u64 start, u64 end, u64 pgoff, struct dso *dso); 89 u64 start, u64 end, u64 pgoff, struct dso *dso);
90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
91 u64 pgoff, u32 pid, char *filename, 91 u64 pgoff, u32 pid, char *filename,
92 enum map_type type); 92 enum map_type type);
93struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 93struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
94void map__delete(struct map *self); 94void map__delete(struct map *map);
95struct map *map__clone(struct map *self); 95struct map *map__clone(struct map *map);
96int map__overlap(struct map *l, struct map *r); 96int map__overlap(struct map *l, struct map *r);
97size_t map__fprintf(struct map *self, FILE *fp); 97size_t map__fprintf(struct map *map, FILE *fp);
98size_t map__fprintf_dsoname(struct map *map, FILE *fp); 98size_t map__fprintf_dsoname(struct map *map, FILE *fp);
99 99
100int map__load(struct map *self, symbol_filter_t filter); 100int map__load(struct map *map, symbol_filter_t filter);
101struct symbol *map__find_symbol(struct map *self, 101struct symbol *map__find_symbol(struct map *map,
102 u64 addr, symbol_filter_t filter); 102 u64 addr, symbol_filter_t filter);
103struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 103struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
104 symbol_filter_t filter); 104 symbol_filter_t filter);
105void map__fixup_start(struct map *self); 105void map__fixup_start(struct map *map);
106void map__fixup_end(struct map *self); 106void map__fixup_end(struct map *map);
107 107
108void map__reloc_vmlinux(struct map *self); 108void map__reloc_vmlinux(struct map *map);
109 109
110size_t __map_groups__fprintf_maps(struct map_groups *mg, 110size_t __map_groups__fprintf_maps(struct map_groups *mg,
111 enum map_type type, int verbose, FILE *fp); 111 enum map_type type, int verbose, FILE *fp);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 2d8d53bec17e..c84f48cf9678 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx,
380 return 0; 380 return 0;
381} 381}
382 382
383static int add_tracepoint_multi(struct list_head **list, int *idx, 383static int add_tracepoint_multi_event(struct list_head **list, int *idx,
384 char *sys_name, char *evt_name) 384 char *sys_name, char *evt_name)
385{ 385{
386 char evt_path[MAXPATHLEN]; 386 char evt_path[MAXPATHLEN];
387 struct dirent *evt_ent; 387 struct dirent *evt_ent;
@@ -408,6 +408,47 @@ static int add_tracepoint_multi(struct list_head **list, int *idx,
408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); 408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
409 } 409 }
410 410
411 closedir(evt_dir);
412 return ret;
413}
414
415static int add_tracepoint_event(struct list_head **list, int *idx,
416 char *sys_name, char *evt_name)
417{
418 return strpbrk(evt_name, "*?") ?
419 add_tracepoint_multi_event(list, idx, sys_name, evt_name) :
420 add_tracepoint(list, idx, sys_name, evt_name);
421}
422
423static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
424 char *sys_name, char *evt_name)
425{
426 struct dirent *events_ent;
427 DIR *events_dir;
428 int ret = 0;
429
430 events_dir = opendir(tracing_events_path);
431 if (!events_dir) {
432 perror("Can't open event dir");
433 return -1;
434 }
435
436 while (!ret && (events_ent = readdir(events_dir))) {
437 if (!strcmp(events_ent->d_name, ".")
438 || !strcmp(events_ent->d_name, "..")
439 || !strcmp(events_ent->d_name, "enable")
440 || !strcmp(events_ent->d_name, "header_event")
441 || !strcmp(events_ent->d_name, "header_page"))
442 continue;
443
444 if (!strglobmatch(events_ent->d_name, sys_name))
445 continue;
446
447 ret = add_tracepoint_event(list, idx, events_ent->d_name,
448 evt_name);
449 }
450
451 closedir(events_dir);
411 return ret; 452 return ret;
412} 453}
413 454
@@ -420,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx,
420 if (ret) 461 if (ret)
421 return ret; 462 return ret;
422 463
423 return strpbrk(event, "*?") ? 464 if (strpbrk(sys, "*?"))
424 add_tracepoint_multi(list, idx, sys, event) : 465 return add_tracepoint_multi_sys(list, idx, sys, event);
425 add_tracepoint(list, idx, sys, event); 466 else
467 return add_tracepoint_event(list, idx, sys, event);
426} 468}
427 469
428static int 470static int
@@ -492,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
492} 534}
493 535
494static int config_term(struct perf_event_attr *attr, 536static int config_term(struct perf_event_attr *attr,
495 struct parse_events__term *term) 537 struct parse_events_term *term)
496{ 538{
497#define CHECK_TYPE_VAL(type) \ 539#define CHECK_TYPE_VAL(type) \
498do { \ 540do { \
@@ -537,7 +579,7 @@ do { \
537static int config_attr(struct perf_event_attr *attr, 579static int config_attr(struct perf_event_attr *attr,
538 struct list_head *head, int fail) 580 struct list_head *head, int fail)
539{ 581{
540 struct parse_events__term *term; 582 struct parse_events_term *term;
541 583
542 list_for_each_entry(term, head, list) 584 list_for_each_entry(term, head, list)
543 if (config_term(attr, term) && fail) 585 if (config_term(attr, term) && fail)
@@ -563,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
563 return add_event(list, idx, &attr, NULL); 605 return add_event(list, idx, &attr, NULL);
564} 606}
565 607
566static int parse_events__is_name_term(struct parse_events__term *term) 608static int parse_events__is_name_term(struct parse_events_term *term)
567{ 609{
568 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; 610 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
569} 611}
570 612
571static char *pmu_event_name(struct list_head *head_terms) 613static char *pmu_event_name(struct list_head *head_terms)
572{ 614{
573 struct parse_events__term *term; 615 struct parse_events_term *term;
574 616
575 list_for_each_entry(term, head_terms, list) 617 list_for_each_entry(term, head_terms, list)
576 if (parse_events__is_name_term(term)) 618 if (parse_events__is_name_term(term))
@@ -657,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
657 int exclude = eu | ek | eh; 699 int exclude = eu | ek | eh;
658 int exclude_GH = evsel ? evsel->exclude_GH : 0; 700 int exclude_GH = evsel ? evsel->exclude_GH : 0;
659 701
660 /*
661 * We are here for group and 'GH' was not set as event
662 * modifier and whatever event/group modifier override
663 * default 'GH' setup.
664 */
665 if (evsel && !exclude_GH)
666 eH = eG = 0;
667
668 memset(mod, 0, sizeof(*mod)); 702 memset(mod, 0, sizeof(*mod));
669 703
670 while (*str) { 704 while (*str) {
@@ -814,7 +848,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
814 */ 848 */
815int parse_events_terms(struct list_head *terms, const char *str) 849int parse_events_terms(struct list_head *terms, const char *str)
816{ 850{
817 struct parse_events_data__terms data = { 851 struct parse_events_terms data = {
818 .terms = NULL, 852 .terms = NULL,
819 }; 853 };
820 int ret; 854 int ret;
@@ -830,10 +864,9 @@ int parse_events_terms(struct list_head *terms, const char *str)
830 return ret; 864 return ret;
831} 865}
832 866
833int parse_events(struct perf_evlist *evlist, const char *str, 867int parse_events(struct perf_evlist *evlist, const char *str)
834 int unset __maybe_unused)
835{ 868{
836 struct parse_events_data__events data = { 869 struct parse_events_evlist data = {
837 .list = LIST_HEAD_INIT(data.list), 870 .list = LIST_HEAD_INIT(data.list),
838 .idx = evlist->nr_entries, 871 .idx = evlist->nr_entries,
839 }; 872 };
@@ -843,6 +876,7 @@ int parse_events(struct perf_evlist *evlist, const char *str,
843 if (!ret) { 876 if (!ret) {
844 int entries = data.idx - evlist->nr_entries; 877 int entries = data.idx - evlist->nr_entries;
845 perf_evlist__splice_list_tail(evlist, &data.list, entries); 878 perf_evlist__splice_list_tail(evlist, &data.list, entries);
879 evlist->nr_groups += data.nr_groups;
846 return 0; 880 return 0;
847 } 881 }
848 882
@@ -858,7 +892,7 @@ int parse_events_option(const struct option *opt, const char *str,
858 int unset __maybe_unused) 892 int unset __maybe_unused)
859{ 893{
860 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 894 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
861 int ret = parse_events(evlist, str, unset); 895 int ret = parse_events(evlist, str);
862 896
863 if (ret) { 897 if (ret) {
864 fprintf(stderr, "invalid or unsupported event: '%s'\n", str); 898 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
@@ -1121,16 +1155,16 @@ void print_events(const char *event_glob, bool name_only)
1121 print_tracepoint_events(NULL, NULL, name_only); 1155 print_tracepoint_events(NULL, NULL, name_only);
1122} 1156}
1123 1157
1124int parse_events__is_hardcoded_term(struct parse_events__term *term) 1158int parse_events__is_hardcoded_term(struct parse_events_term *term)
1125{ 1159{
1126 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; 1160 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1127} 1161}
1128 1162
1129static int new_term(struct parse_events__term **_term, int type_val, 1163static int new_term(struct parse_events_term **_term, int type_val,
1130 int type_term, char *config, 1164 int type_term, char *config,
1131 char *str, u64 num) 1165 char *str, u64 num)
1132{ 1166{
1133 struct parse_events__term *term; 1167 struct parse_events_term *term;
1134 1168
1135 term = zalloc(sizeof(*term)); 1169 term = zalloc(sizeof(*term));
1136 if (!term) 1170 if (!term)
@@ -1156,21 +1190,21 @@ static int new_term(struct parse_events__term **_term, int type_val,
1156 return 0; 1190 return 0;
1157} 1191}
1158 1192
1159int parse_events__term_num(struct parse_events__term **term, 1193int parse_events_term__num(struct parse_events_term **term,
1160 int type_term, char *config, u64 num) 1194 int type_term, char *config, u64 num)
1161{ 1195{
1162 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, 1196 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1163 config, NULL, num); 1197 config, NULL, num);
1164} 1198}
1165 1199
1166int parse_events__term_str(struct parse_events__term **term, 1200int parse_events_term__str(struct parse_events_term **term,
1167 int type_term, char *config, char *str) 1201 int type_term, char *config, char *str)
1168{ 1202{
1169 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, 1203 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1170 config, str, 0); 1204 config, str, 0);
1171} 1205}
1172 1206
1173int parse_events__term_sym_hw(struct parse_events__term **term, 1207int parse_events_term__sym_hw(struct parse_events_term **term,
1174 char *config, unsigned idx) 1208 char *config, unsigned idx)
1175{ 1209{
1176 struct event_symbol *sym; 1210 struct event_symbol *sym;
@@ -1188,8 +1222,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term,
1188 (char *) "event", (char *) sym->symbol, 0); 1222 (char *) "event", (char *) sym->symbol, 0);
1189} 1223}
1190 1224
1191int parse_events__term_clone(struct parse_events__term **new, 1225int parse_events_term__clone(struct parse_events_term **new,
1192 struct parse_events__term *term) 1226 struct parse_events_term *term)
1193{ 1227{
1194 return new_term(new, term->type_val, term->type_term, term->config, 1228 return new_term(new, term->type_val, term->type_term, term->config,
1195 term->val.str, term->val.num); 1229 term->val.str, term->val.num);
@@ -1197,7 +1231,7 @@ int parse_events__term_clone(struct parse_events__term **new,
1197 1231
1198void parse_events__free_terms(struct list_head *terms) 1232void parse_events__free_terms(struct list_head *terms)
1199{ 1233{
1200 struct parse_events__term *term, *h; 1234 struct parse_events_term *term, *h;
1201 1235
1202 list_for_each_entry_safe(term, h, terms, list) 1236 list_for_each_entry_safe(term, h, terms, list)
1203 free(term); 1237 free(term);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b7af80b8bdda..8a4859315fd9 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -29,8 +29,7 @@ const char *event_type(int type);
29 29
30extern int parse_events_option(const struct option *opt, const char *str, 30extern int parse_events_option(const struct option *opt, const char *str,
31 int unset); 31 int unset);
32extern int parse_events(struct perf_evlist *evlist, const char *str, 32extern int parse_events(struct perf_evlist *evlist, const char *str);
33 int unset);
34extern int parse_events_terms(struct list_head *terms, const char *str); 33extern int parse_events_terms(struct list_head *terms, const char *str);
35extern int parse_filter(const struct option *opt, const char *str, int unset); 34extern int parse_filter(const struct option *opt, const char *str, int unset);
36 35
@@ -51,7 +50,7 @@ enum {
51 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 50 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
52}; 51};
53 52
54struct parse_events__term { 53struct parse_events_term {
55 char *config; 54 char *config;
56 union { 55 union {
57 char *str; 56 char *str;
@@ -62,24 +61,25 @@ struct parse_events__term {
62 struct list_head list; 61 struct list_head list;
63}; 62};
64 63
65struct parse_events_data__events { 64struct parse_events_evlist {
66 struct list_head list; 65 struct list_head list;
67 int idx; 66 int idx;
67 int nr_groups;
68}; 68};
69 69
70struct parse_events_data__terms { 70struct parse_events_terms {
71 struct list_head *terms; 71 struct list_head *terms;
72}; 72};
73 73
74int parse_events__is_hardcoded_term(struct parse_events__term *term); 74int parse_events__is_hardcoded_term(struct parse_events_term *term);
75int parse_events__term_num(struct parse_events__term **_term, 75int parse_events_term__num(struct parse_events_term **_term,
76 int type_term, char *config, u64 num); 76 int type_term, char *config, u64 num);
77int parse_events__term_str(struct parse_events__term **_term, 77int parse_events_term__str(struct parse_events_term **_term,
78 int type_term, char *config, char *str); 78 int type_term, char *config, char *str);
79int parse_events__term_sym_hw(struct parse_events__term **term, 79int parse_events_term__sym_hw(struct parse_events_term **term,
80 char *config, unsigned idx); 80 char *config, unsigned idx);
81int parse_events__term_clone(struct parse_events__term **new, 81int parse_events_term__clone(struct parse_events_term **new,
82 struct parse_events__term *term); 82 struct parse_events_term *term);
83void parse_events__free_terms(struct list_head *terms); 83void parse_events__free_terms(struct list_head *terms);
84int parse_events__modifier_event(struct list_head *list, char *str, bool add); 84int parse_events__modifier_event(struct list_head *list, char *str, bool add);
85int parse_events__modifier_group(struct list_head *list, char *event_mod); 85int parse_events__modifier_group(struct list_head *list, char *event_mod);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 0f9914ae6bac..afc44c18dfe1 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,5 +1,4 @@
1%pure-parser 1%pure-parser
2%name-prefix "parse_events_"
3%parse-param {void *_data} 2%parse-param {void *_data}
4%parse-param {void *scanner} 3%parse-param {void *scanner}
5%lex-param {void* scanner} 4%lex-param {void* scanner}
@@ -23,6 +22,14 @@ do { \
23 YYABORT; \ 22 YYABORT; \
24} while (0) 23} while (0)
25 24
25static inc_group_count(struct list_head *list,
26 struct parse_events_evlist *data)
27{
28 /* Count groups only have more than 1 members */
29 if (!list_is_last(list->next, list))
30 data->nr_groups++;
31}
32
26%} 33%}
27 34
28%token PE_START_EVENTS PE_START_TERMS 35%token PE_START_EVENTS PE_START_TERMS
@@ -68,7 +75,7 @@ do { \
68 char *str; 75 char *str;
69 u64 num; 76 u64 num;
70 struct list_head *head; 77 struct list_head *head;
71 struct parse_events__term *term; 78 struct parse_events_term *term;
72} 79}
73%% 80%%
74 81
@@ -79,7 +86,7 @@ PE_START_TERMS start_terms
79 86
80start_events: groups 87start_events: groups
81{ 88{
82 struct parse_events_data__events *data = _data; 89 struct parse_events_evlist *data = _data;
83 90
84 parse_events_update_lists($1, &data->list); 91 parse_events_update_lists($1, &data->list);
85} 92}
@@ -123,6 +130,7 @@ PE_NAME '{' events '}'
123{ 130{
124 struct list_head *list = $3; 131 struct list_head *list = $3;
125 132
133 inc_group_count(list, _data);
126 parse_events__set_leader($1, list); 134 parse_events__set_leader($1, list);
127 $$ = list; 135 $$ = list;
128} 136}
@@ -131,6 +139,7 @@ PE_NAME '{' events '}'
131{ 139{
132 struct list_head *list = $2; 140 struct list_head *list = $2;
133 141
142 inc_group_count(list, _data);
134 parse_events__set_leader(NULL, list); 143 parse_events__set_leader(NULL, list);
135 $$ = list; 144 $$ = list;
136} 145}
@@ -186,7 +195,7 @@ event_def: event_pmu |
186event_pmu: 195event_pmu:
187PE_NAME '/' event_config '/' 196PE_NAME '/' event_config '/'
188{ 197{
189 struct parse_events_data__events *data = _data; 198 struct parse_events_evlist *data = _data;
190 struct list_head *list = NULL; 199 struct list_head *list = NULL;
191 200
192 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); 201 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
@@ -202,7 +211,7 @@ PE_VALUE_SYM_SW
202event_legacy_symbol: 211event_legacy_symbol:
203value_sym '/' event_config '/' 212value_sym '/' event_config '/'
204{ 213{
205 struct parse_events_data__events *data = _data; 214 struct parse_events_evlist *data = _data;
206 struct list_head *list = NULL; 215 struct list_head *list = NULL;
207 int type = $1 >> 16; 216 int type = $1 >> 16;
208 int config = $1 & 255; 217 int config = $1 & 255;
@@ -215,7 +224,7 @@ value_sym '/' event_config '/'
215| 224|
216value_sym sep_slash_dc 225value_sym sep_slash_dc
217{ 226{
218 struct parse_events_data__events *data = _data; 227 struct parse_events_evlist *data = _data;
219 struct list_head *list = NULL; 228 struct list_head *list = NULL;
220 int type = $1 >> 16; 229 int type = $1 >> 16;
221 int config = $1 & 255; 230 int config = $1 & 255;
@@ -228,7 +237,7 @@ value_sym sep_slash_dc
228event_legacy_cache: 237event_legacy_cache:
229PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
230{ 239{
231 struct parse_events_data__events *data = _data; 240 struct parse_events_evlist *data = _data;
232 struct list_head *list = NULL; 241 struct list_head *list = NULL;
233 242
234 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); 243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
@@ -237,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
237| 246|
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 247PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
239{ 248{
240 struct parse_events_data__events *data = _data; 249 struct parse_events_evlist *data = _data;
241 struct list_head *list = NULL; 250 struct list_head *list = NULL;
242 251
243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); 252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
@@ -246,7 +255,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
246| 255|
247PE_NAME_CACHE_TYPE 256PE_NAME_CACHE_TYPE
248{ 257{
249 struct parse_events_data__events *data = _data; 258 struct parse_events_evlist *data = _data;
250 struct list_head *list = NULL; 259 struct list_head *list = NULL;
251 260
252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); 261 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
@@ -256,7 +265,7 @@ PE_NAME_CACHE_TYPE
256event_legacy_mem: 265event_legacy_mem:
257PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 266PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
258{ 267{
259 struct parse_events_data__events *data = _data; 268 struct parse_events_evlist *data = _data;
260 struct list_head *list = NULL; 269 struct list_head *list = NULL;
261 270
262 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 271 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -266,7 +275,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
266| 275|
267PE_PREFIX_MEM PE_VALUE sep_dc 276PE_PREFIX_MEM PE_VALUE sep_dc
268{ 277{
269 struct parse_events_data__events *data = _data; 278 struct parse_events_evlist *data = _data;
270 struct list_head *list = NULL; 279 struct list_head *list = NULL;
271 280
272 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 281 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -277,7 +286,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
277event_legacy_tracepoint: 286event_legacy_tracepoint:
278PE_NAME ':' PE_NAME 287PE_NAME ':' PE_NAME
279{ 288{
280 struct parse_events_data__events *data = _data; 289 struct parse_events_evlist *data = _data;
281 struct list_head *list = NULL; 290 struct list_head *list = NULL;
282 291
283 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); 292 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
@@ -287,7 +296,7 @@ PE_NAME ':' PE_NAME
287event_legacy_numeric: 296event_legacy_numeric:
288PE_VALUE ':' PE_VALUE 297PE_VALUE ':' PE_VALUE
289{ 298{
290 struct parse_events_data__events *data = _data; 299 struct parse_events_evlist *data = _data;
291 struct list_head *list = NULL; 300 struct list_head *list = NULL;
292 301
293 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); 302 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
@@ -297,7 +306,7 @@ PE_VALUE ':' PE_VALUE
297event_legacy_raw: 306event_legacy_raw:
298PE_RAW 307PE_RAW
299{ 308{
300 struct parse_events_data__events *data = _data; 309 struct parse_events_evlist *data = _data;
301 struct list_head *list = NULL; 310 struct list_head *list = NULL;
302 311
303 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 312 ABORT_ON(parse_events_add_numeric(&list, &data->idx,
@@ -307,7 +316,7 @@ PE_RAW
307 316
308start_terms: event_config 317start_terms: event_config
309{ 318{
310 struct parse_events_data__terms *data = _data; 319 struct parse_events_terms *data = _data;
311 data->terms = $1; 320 data->terms = $1;
312} 321}
313 322
@@ -315,7 +324,7 @@ event_config:
315event_config ',' event_term 324event_config ',' event_term
316{ 325{
317 struct list_head *head = $1; 326 struct list_head *head = $1;
318 struct parse_events__term *term = $3; 327 struct parse_events_term *term = $3;
319 328
320 ABORT_ON(!head); 329 ABORT_ON(!head);
321 list_add_tail(&term->list, head); 330 list_add_tail(&term->list, head);
@@ -325,7 +334,7 @@ event_config ',' event_term
325event_term 334event_term
326{ 335{
327 struct list_head *head = malloc(sizeof(*head)); 336 struct list_head *head = malloc(sizeof(*head));
328 struct parse_events__term *term = $1; 337 struct parse_events_term *term = $1;
329 338
330 ABORT_ON(!head); 339 ABORT_ON(!head);
331 INIT_LIST_HEAD(head); 340 INIT_LIST_HEAD(head);
@@ -336,70 +345,70 @@ event_term
336event_term: 345event_term:
337PE_NAME '=' PE_NAME 346PE_NAME '=' PE_NAME
338{ 347{
339 struct parse_events__term *term; 348 struct parse_events_term *term;
340 349
341 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, 350 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
342 $1, $3)); 351 $1, $3));
343 $$ = term; 352 $$ = term;
344} 353}
345| 354|
346PE_NAME '=' PE_VALUE 355PE_NAME '=' PE_VALUE
347{ 356{
348 struct parse_events__term *term; 357 struct parse_events_term *term;
349 358
350 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 359 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
351 $1, $3)); 360 $1, $3));
352 $$ = term; 361 $$ = term;
353} 362}
354| 363|
355PE_NAME '=' PE_VALUE_SYM_HW 364PE_NAME '=' PE_VALUE_SYM_HW
356{ 365{
357 struct parse_events__term *term; 366 struct parse_events_term *term;
358 int config = $3 & 255; 367 int config = $3 & 255;
359 368
360 ABORT_ON(parse_events__term_sym_hw(&term, $1, config)); 369 ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
361 $$ = term; 370 $$ = term;
362} 371}
363| 372|
364PE_NAME 373PE_NAME
365{ 374{
366 struct parse_events__term *term; 375 struct parse_events_term *term;
367 376
368 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 377 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
369 $1, 1)); 378 $1, 1));
370 $$ = term; 379 $$ = term;
371} 380}
372| 381|
373PE_VALUE_SYM_HW 382PE_VALUE_SYM_HW
374{ 383{
375 struct parse_events__term *term; 384 struct parse_events_term *term;
376 int config = $1 & 255; 385 int config = $1 & 255;
377 386
378 ABORT_ON(parse_events__term_sym_hw(&term, NULL, config)); 387 ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
379 $$ = term; 388 $$ = term;
380} 389}
381| 390|
382PE_TERM '=' PE_NAME 391PE_TERM '=' PE_NAME
383{ 392{
384 struct parse_events__term *term; 393 struct parse_events_term *term;
385 394
386 ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3)); 395 ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3));
387 $$ = term; 396 $$ = term;
388} 397}
389| 398|
390PE_TERM '=' PE_VALUE 399PE_TERM '=' PE_VALUE
391{ 400{
392 struct parse_events__term *term; 401 struct parse_events_term *term;
393 402
394 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3)); 403 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3));
395 $$ = term; 404 $$ = term;
396} 405}
397| 406|
398PE_TERM 407PE_TERM
399{ 408{
400 struct parse_events__term *term; 409 struct parse_events_term *term;
401 410
402 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1)); 411 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1));
403 $$ = term; 412 $$ = term;
404} 413}
405 414
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 9bdc60c6f138..4c6f9c490a8d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1,4 +1,3 @@
1
2#include <linux/list.h> 1#include <linux/list.h>
3#include <sys/types.h> 2#include <sys/types.h>
4#include <sys/stat.h> 3#include <sys/stat.h>
@@ -11,6 +10,19 @@
11#include "parse-events.h" 10#include "parse-events.h"
12#include "cpumap.h" 11#include "cpumap.h"
13 12
13struct perf_pmu_alias {
14 char *name;
15 struct list_head terms;
16 struct list_head list;
17};
18
19struct perf_pmu_format {
20 char *name;
21 int value;
22 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
23 struct list_head list;
24};
25
14#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 26#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
15 27
16int perf_pmu_parse(struct list_head *list, char *name); 28int perf_pmu_parse(struct list_head *list, char *name);
@@ -85,7 +97,7 @@ static int pmu_format(char *name, struct list_head *format)
85 97
86static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) 98static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
87{ 99{
88 struct perf_pmu__alias *alias; 100 struct perf_pmu_alias *alias;
89 char buf[256]; 101 char buf[256];
90 int ret; 102 int ret;
91 103
@@ -172,15 +184,15 @@ static int pmu_aliases(char *name, struct list_head *head)
172 return 0; 184 return 0;
173} 185}
174 186
175static int pmu_alias_terms(struct perf_pmu__alias *alias, 187static int pmu_alias_terms(struct perf_pmu_alias *alias,
176 struct list_head *terms) 188 struct list_head *terms)
177{ 189{
178 struct parse_events__term *term, *clone; 190 struct parse_events_term *term, *clone;
179 LIST_HEAD(list); 191 LIST_HEAD(list);
180 int ret; 192 int ret;
181 193
182 list_for_each_entry(term, &alias->terms, list) { 194 list_for_each_entry(term, &alias->terms, list) {
183 ret = parse_events__term_clone(&clone, term); 195 ret = parse_events_term__clone(&clone, term);
184 if (ret) { 196 if (ret) {
185 parse_events__free_terms(&list); 197 parse_events__free_terms(&list);
186 return ret; 198 return ret;
@@ -360,10 +372,10 @@ struct perf_pmu *perf_pmu__find(char *name)
360 return pmu_lookup(name); 372 return pmu_lookup(name);
361} 373}
362 374
363static struct perf_pmu__format* 375static struct perf_pmu_format *
364pmu_find_format(struct list_head *formats, char *name) 376pmu_find_format(struct list_head *formats, char *name)
365{ 377{
366 struct perf_pmu__format *format; 378 struct perf_pmu_format *format;
367 379
368 list_for_each_entry(format, formats, list) 380 list_for_each_entry(format, formats, list)
369 if (!strcmp(format->name, name)) 381 if (!strcmp(format->name, name))
@@ -403,9 +415,9 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
403 */ 415 */
404static int pmu_config_term(struct list_head *formats, 416static int pmu_config_term(struct list_head *formats,
405 struct perf_event_attr *attr, 417 struct perf_event_attr *attr,
406 struct parse_events__term *term) 418 struct parse_events_term *term)
407{ 419{
408 struct perf_pmu__format *format; 420 struct perf_pmu_format *format;
409 __u64 *vp; 421 __u64 *vp;
410 422
411 /* 423 /*
@@ -450,7 +462,7 @@ int perf_pmu__config_terms(struct list_head *formats,
450 struct perf_event_attr *attr, 462 struct perf_event_attr *attr,
451 struct list_head *head_terms) 463 struct list_head *head_terms)
452{ 464{
453 struct parse_events__term *term; 465 struct parse_events_term *term;
454 466
455 list_for_each_entry(term, head_terms, list) 467 list_for_each_entry(term, head_terms, list)
456 if (pmu_config_term(formats, attr, term)) 468 if (pmu_config_term(formats, attr, term))
@@ -471,10 +483,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
471 return perf_pmu__config_terms(&pmu->format, attr, head_terms); 483 return perf_pmu__config_terms(&pmu->format, attr, head_terms);
472} 484}
473 485
474static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, 486static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
475 struct parse_events__term *term) 487 struct parse_events_term *term)
476{ 488{
477 struct perf_pmu__alias *alias; 489 struct perf_pmu_alias *alias;
478 char *name; 490 char *name;
479 491
480 if (parse_events__is_hardcoded_term(term)) 492 if (parse_events__is_hardcoded_term(term))
@@ -507,8 +519,8 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
507 */ 519 */
508int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) 520int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
509{ 521{
510 struct parse_events__term *term, *h; 522 struct parse_events_term *term, *h;
511 struct perf_pmu__alias *alias; 523 struct perf_pmu_alias *alias;
512 int ret; 524 int ret;
513 525
514 list_for_each_entry_safe(term, h, head_terms, list) { 526 list_for_each_entry_safe(term, h, head_terms, list) {
@@ -527,7 +539,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
527int perf_pmu__new_format(struct list_head *list, char *name, 539int perf_pmu__new_format(struct list_head *list, char *name,
528 int config, unsigned long *bits) 540 int config, unsigned long *bits)
529{ 541{
530 struct perf_pmu__format *format; 542 struct perf_pmu_format *format;
531 543
532 format = zalloc(sizeof(*format)); 544 format = zalloc(sizeof(*format));
533 if (!format) 545 if (!format)
@@ -548,7 +560,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
548 if (!to) 560 if (!to)
549 to = from; 561 to = from;
550 562
551 memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); 563 memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
552 for (b = from; b <= to; b++) 564 for (b = from; b <= to; b++)
553 set_bit(b, bits); 565 set_bit(b, bits);
554} 566}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index a313ed76a49a..32fe55b659fa 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -12,19 +12,6 @@ enum {
12 12
13#define PERF_PMU_FORMAT_BITS 64 13#define PERF_PMU_FORMAT_BITS 64
14 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__alias {
23 char *name;
24 struct list_head terms;
25 struct list_head list;
26};
27
28struct perf_pmu { 15struct perf_pmu {
29 char *name; 16 char *name;
30 __u32 type; 17 __u32 type;
@@ -42,7 +29,7 @@ int perf_pmu__config_terms(struct list_head *formats,
42 struct list_head *head_terms); 29 struct list_head *head_terms);
43int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); 30int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
44struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 31struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
45 struct list_head *head_terms); 32 struct list_head *head_terms);
46int perf_pmu_wrap(void); 33int perf_pmu_wrap(void);
47void perf_pmu_error(struct list_head *list, char *name, char const *msg); 34void perf_pmu_error(struct list_head *list, char *name, char const *msg);
48 35
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
index ec898047ebb9..bfd7e8509869 100644
--- a/tools/perf/util/pmu.y
+++ b/tools/perf/util/pmu.y
@@ -1,5 +1,4 @@
1 1
2%name-prefix "perf_pmu_"
3%parse-param {struct list_head *format} 2%parse-param {struct list_head *format}
4%parse-param {char *name} 3%parse-param {char *name}
5 4
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 1daf5c14e751..be0329394d56 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die,
413 dwarf_diename(vr_die), dwarf_diename(&type)); 413 dwarf_diename(vr_die), dwarf_diename(&type));
414 return -EINVAL; 414 return -EINVAL;
415 } 415 }
416 if (die_get_real_type(&type, &type) == NULL) {
417 pr_warning("Failed to get a type"
418 " information.\n");
419 return -ENOENT;
420 }
416 if (ret == DW_TAG_pointer_type) { 421 if (ret == DW_TAG_pointer_type) {
417 if (die_get_real_type(&type, &type) == NULL) {
418 pr_warning("Failed to get a type"
419 " information.\n");
420 return -ENOENT;
421 }
422 while (*ref_ptr) 422 while (*ref_ptr)
423 ref_ptr = &(*ref_ptr)->next; 423 ref_ptr = &(*ref_ptr)->next;
424 /* Add new reference with offset +0 */ 424 /* Add new reference with offset +0 */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index c40c2d33199e..64536a993f4a 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -18,4 +18,5 @@ util/cgroup.c
18util/debugfs.c 18util/debugfs.c
19util/rblist.c 19util/rblist.c
20util/strlist.c 20util/strlist.c
21util/sysfs.c
21../../lib/rbtree.c 22../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index a2657fd96837..925e0c3e6d91 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1045,3 +1045,12 @@ error:
1045 if (PyErr_Occurred()) 1045 if (PyErr_Occurred())
1046 PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); 1046 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
1047} 1047}
1048
1049/*
1050 * Dummy, to avoid dragging all the test_attr infrastructure in the python
1051 * binding.
1052 */
1053void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
1054 int fd, int group_fd, unsigned long flags)
1055{
1056}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index f80605eb1855..eacec859f299 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -292,6 +292,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
292 ns = nsecs - s * NSECS_PER_SEC; 292 ns = nsecs - s * NSECS_PER_SEC;
293 293
294 scripting_context->event_data = data; 294 scripting_context->event_data = data;
295 scripting_context->pevent = evsel->tp_format->pevent;
295 296
296 ENTER; 297 ENTER;
297 SAVETMPS; 298 SAVETMPS;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 14683dfca2ee..e87aa5d9696b 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -265,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event
265 ns = nsecs - s * NSECS_PER_SEC; 265 ns = nsecs - s * NSECS_PER_SEC;
266 266
267 scripting_context->event_data = data; 267 scripting_context->event_data = data;
268 scripting_context->pevent = evsel->tp_format->pevent;
268 269
269 context = PyCObject_FromVoidPtr(scripting_context, NULL); 270 context = PyCObject_FromVoidPtr(scripting_context, NULL);
270 271
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce6f51162386..bd85280bb6e8 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -16,7 +16,6 @@
16#include "cpumap.h" 16#include "cpumap.h"
17#include "event-parse.h" 17#include "event-parse.h"
18#include "perf_regs.h" 18#include "perf_regs.h"
19#include "unwind.h"
20#include "vdso.h" 19#include "vdso.h"
21 20
22static int perf_session__open(struct perf_session *self, bool force) 21static int perf_session__open(struct perf_session *self, bool force)
@@ -87,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
87{ 86{
88 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); 87 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
89 88
90 session->host_machine.id_hdr_size = id_hdr_size;
91 machines__set_id_hdr_size(&session->machines, id_hdr_size); 89 machines__set_id_hdr_size(&session->machines, id_hdr_size);
92} 90}
93 91
94int perf_session__create_kernel_maps(struct perf_session *self) 92int perf_session__create_kernel_maps(struct perf_session *self)
95{ 93{
96 int ret = machine__create_kernel_maps(&self->host_machine); 94 int ret = machine__create_kernel_maps(&self->machines.host);
97 95
98 if (ret >= 0) 96 if (ret >= 0)
99 ret = machines__create_guest_kernel_maps(&self->machines); 97 ret = machines__create_guest_kernel_maps(&self->machines);
@@ -102,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self)
102 100
103static void perf_session__destroy_kernel_maps(struct perf_session *self) 101static void perf_session__destroy_kernel_maps(struct perf_session *self)
104{ 102{
105 machine__destroy_kernel_maps(&self->host_machine); 103 machines__destroy_kernel_maps(&self->machines);
106 machines__destroy_guest_kernel_maps(&self->machines);
107} 104}
108 105
109struct perf_session *perf_session__new(const char *filename, int mode, 106struct perf_session *perf_session__new(const char *filename, int mode,
@@ -128,22 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode,
128 goto out; 125 goto out;
129 126
130 memcpy(self->filename, filename, len); 127 memcpy(self->filename, filename, len);
131 /*
132 * On 64bit we can mmap the data file in one go. No need for tiny mmap
133 * slices. On 32bit we use 32MB.
134 */
135#if BITS_PER_LONG == 64
136 self->mmap_window = ULLONG_MAX;
137#else
138 self->mmap_window = 32 * 1024 * 1024ULL;
139#endif
140 self->machines = RB_ROOT;
141 self->repipe = repipe; 128 self->repipe = repipe;
142 INIT_LIST_HEAD(&self->ordered_samples.samples); 129 INIT_LIST_HEAD(&self->ordered_samples.samples);
143 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 130 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
144 INIT_LIST_HEAD(&self->ordered_samples.to_free); 131 INIT_LIST_HEAD(&self->ordered_samples.to_free);
145 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 132 machines__init(&self->machines);
146 hists__init(&self->hists);
147 133
148 if (mode == O_RDONLY) { 134 if (mode == O_RDONLY) {
149 if (perf_session__open(self, force) < 0) 135 if (perf_session__open(self, force) < 0)
@@ -171,37 +157,30 @@ out_delete:
171 return NULL; 157 return NULL;
172} 158}
173 159
174static void machine__delete_dead_threads(struct machine *machine)
175{
176 struct thread *n, *t;
177
178 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
179 list_del(&t->node);
180 thread__delete(t);
181 }
182}
183
184static void perf_session__delete_dead_threads(struct perf_session *session) 160static void perf_session__delete_dead_threads(struct perf_session *session)
185{ 161{
186 machine__delete_dead_threads(&session->host_machine); 162 machine__delete_dead_threads(&session->machines.host);
187} 163}
188 164
189static void machine__delete_threads(struct machine *self) 165static void perf_session__delete_threads(struct perf_session *session)
190{ 166{
191 struct rb_node *nd = rb_first(&self->threads); 167 machine__delete_threads(&session->machines.host);
192
193 while (nd) {
194 struct thread *t = rb_entry(nd, struct thread, rb_node);
195
196 rb_erase(&t->rb_node, &self->threads);
197 nd = rb_next(nd);
198 thread__delete(t);
199 }
200} 168}
201 169
202static void perf_session__delete_threads(struct perf_session *session) 170static void perf_session_env__delete(struct perf_session_env *env)
203{ 171{
204 machine__delete_threads(&session->host_machine); 172 free(env->hostname);
173 free(env->os_release);
174 free(env->version);
175 free(env->arch);
176 free(env->cpu_desc);
177 free(env->cpuid);
178
179 free(env->cmdline);
180 free(env->sibling_cores);
181 free(env->sibling_threads);
182 free(env->numa_nodes);
183 free(env->pmu_mappings);
205} 184}
206 185
207void perf_session__delete(struct perf_session *self) 186void perf_session__delete(struct perf_session *self)
@@ -209,198 +188,13 @@ void perf_session__delete(struct perf_session *self)
209 perf_session__destroy_kernel_maps(self); 188 perf_session__destroy_kernel_maps(self);
210 perf_session__delete_dead_threads(self); 189 perf_session__delete_dead_threads(self);
211 perf_session__delete_threads(self); 190 perf_session__delete_threads(self);
212 machine__exit(&self->host_machine); 191 perf_session_env__delete(&self->header.env);
192 machines__exit(&self->machines);
213 close(self->fd); 193 close(self->fd);
214 free(self); 194 free(self);
215 vdso__exit(); 195 vdso__exit();
216} 196}
217 197
218void machine__remove_thread(struct machine *self, struct thread *th)
219{
220 self->last_match = NULL;
221 rb_erase(&th->rb_node, &self->threads);
222 /*
223 * We may have references to this thread, for instance in some hist_entry
224 * instances, so just move them to a separate list.
225 */
226 list_add_tail(&th->node, &self->dead_threads);
227}
228
229static bool symbol__match_parent_regex(struct symbol *sym)
230{
231 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
232 return 1;
233
234 return 0;
235}
236
237static const u8 cpumodes[] = {
238 PERF_RECORD_MISC_USER,
239 PERF_RECORD_MISC_KERNEL,
240 PERF_RECORD_MISC_GUEST_USER,
241 PERF_RECORD_MISC_GUEST_KERNEL
242};
243#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
244
245static void ip__resolve_ams(struct machine *self, struct thread *thread,
246 struct addr_map_symbol *ams,
247 u64 ip)
248{
249 struct addr_location al;
250 size_t i;
251 u8 m;
252
253 memset(&al, 0, sizeof(al));
254
255 for (i = 0; i < NCPUMODES; i++) {
256 m = cpumodes[i];
257 /*
258 * We cannot use the header.misc hint to determine whether a
259 * branch stack address is user, kernel, guest, hypervisor.
260 * Branches may straddle the kernel/user/hypervisor boundaries.
261 * Thus, we have to try consecutively until we find a match
262 * or else, the symbol is unknown
263 */
264 thread__find_addr_location(thread, self, m, MAP__FUNCTION,
265 ip, &al, NULL);
266 if (al.sym)
267 goto found;
268 }
269found:
270 ams->addr = ip;
271 ams->al_addr = al.addr;
272 ams->sym = al.sym;
273 ams->map = al.map;
274}
275
276struct branch_info *machine__resolve_bstack(struct machine *self,
277 struct thread *thr,
278 struct branch_stack *bs)
279{
280 struct branch_info *bi;
281 unsigned int i;
282
283 bi = calloc(bs->nr, sizeof(struct branch_info));
284 if (!bi)
285 return NULL;
286
287 for (i = 0; i < bs->nr; i++) {
288 ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
289 ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
290 bi[i].flags = bs->entries[i].flags;
291 }
292 return bi;
293}
294
295static int machine__resolve_callchain_sample(struct machine *machine,
296 struct thread *thread,
297 struct ip_callchain *chain,
298 struct symbol **parent)
299
300{
301 u8 cpumode = PERF_RECORD_MISC_USER;
302 unsigned int i;
303 int err;
304
305 callchain_cursor_reset(&callchain_cursor);
306
307 if (chain->nr > PERF_MAX_STACK_DEPTH) {
308 pr_warning("corrupted callchain. skipping...\n");
309 return 0;
310 }
311
312 for (i = 0; i < chain->nr; i++) {
313 u64 ip;
314 struct addr_location al;
315
316 if (callchain_param.order == ORDER_CALLEE)
317 ip = chain->ips[i];
318 else
319 ip = chain->ips[chain->nr - i - 1];
320
321 if (ip >= PERF_CONTEXT_MAX) {
322 switch (ip) {
323 case PERF_CONTEXT_HV:
324 cpumode = PERF_RECORD_MISC_HYPERVISOR;
325 break;
326 case PERF_CONTEXT_KERNEL:
327 cpumode = PERF_RECORD_MISC_KERNEL;
328 break;
329 case PERF_CONTEXT_USER:
330 cpumode = PERF_RECORD_MISC_USER;
331 break;
332 default:
333 pr_debug("invalid callchain context: "
334 "%"PRId64"\n", (s64) ip);
335 /*
336 * It seems the callchain is corrupted.
337 * Discard all.
338 */
339 callchain_cursor_reset(&callchain_cursor);
340 return 0;
341 }
342 continue;
343 }
344
345 al.filtered = false;
346 thread__find_addr_location(thread, machine, cpumode,
347 MAP__FUNCTION, ip, &al, NULL);
348 if (al.sym != NULL) {
349 if (sort__has_parent && !*parent &&
350 symbol__match_parent_regex(al.sym))
351 *parent = al.sym;
352 if (!symbol_conf.use_callchain)
353 break;
354 }
355
356 err = callchain_cursor_append(&callchain_cursor,
357 ip, al.map, al.sym);
358 if (err)
359 return err;
360 }
361
362 return 0;
363}
364
365static int unwind_entry(struct unwind_entry *entry, void *arg)
366{
367 struct callchain_cursor *cursor = arg;
368 return callchain_cursor_append(cursor, entry->ip,
369 entry->map, entry->sym);
370}
371
372int machine__resolve_callchain(struct machine *machine,
373 struct perf_evsel *evsel,
374 struct thread *thread,
375 struct perf_sample *sample,
376 struct symbol **parent)
377
378{
379 int ret;
380
381 callchain_cursor_reset(&callchain_cursor);
382
383 ret = machine__resolve_callchain_sample(machine, thread,
384 sample->callchain, parent);
385 if (ret)
386 return ret;
387
388 /* Can we do dwarf post unwind? */
389 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
390 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
391 return 0;
392
393 /* Bail out if nothing was captured. */
394 if ((!sample->user_regs.regs) ||
395 (!sample->user_stack.size))
396 return 0;
397
398 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
399 thread, evsel->attr.sample_regs_user,
400 sample);
401
402}
403
404static int process_event_synth_tracing_data_stub(union perf_event *event 198static int process_event_synth_tracing_data_stub(union perf_event *event
405 __maybe_unused, 199 __maybe_unused,
406 struct perf_session *session 200 struct perf_session *session
@@ -1027,7 +821,7 @@ static struct machine *
1027 return perf_session__findnew_machine(session, pid); 821 return perf_session__findnew_machine(session, pid);
1028 } 822 }
1029 823
1030 return perf_session__find_host_machine(session); 824 return &session->machines.host;
1031} 825}
1032 826
1033static int perf_session_deliver_event(struct perf_session *session, 827static int perf_session_deliver_event(struct perf_session *session,
@@ -1065,11 +859,11 @@ static int perf_session_deliver_event(struct perf_session *session,
1065 case PERF_RECORD_SAMPLE: 859 case PERF_RECORD_SAMPLE:
1066 dump_sample(evsel, event, sample); 860 dump_sample(evsel, event, sample);
1067 if (evsel == NULL) { 861 if (evsel == NULL) {
1068 ++session->hists.stats.nr_unknown_id; 862 ++session->stats.nr_unknown_id;
1069 return 0; 863 return 0;
1070 } 864 }
1071 if (machine == NULL) { 865 if (machine == NULL) {
1072 ++session->hists.stats.nr_unprocessable_samples; 866 ++session->stats.nr_unprocessable_samples;
1073 return 0; 867 return 0;
1074 } 868 }
1075 return tool->sample(tool, event, sample, evsel, machine); 869 return tool->sample(tool, event, sample, evsel, machine);
@@ -1083,7 +877,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1083 return tool->exit(tool, event, sample, machine); 877 return tool->exit(tool, event, sample, machine);
1084 case PERF_RECORD_LOST: 878 case PERF_RECORD_LOST:
1085 if (tool->lost == perf_event__process_lost) 879 if (tool->lost == perf_event__process_lost)
1086 session->hists.stats.total_lost += event->lost.lost; 880 session->stats.total_lost += event->lost.lost;
1087 return tool->lost(tool, event, sample, machine); 881 return tool->lost(tool, event, sample, machine);
1088 case PERF_RECORD_READ: 882 case PERF_RECORD_READ:
1089 return tool->read(tool, event, sample, evsel, machine); 883 return tool->read(tool, event, sample, evsel, machine);
@@ -1092,7 +886,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1092 case PERF_RECORD_UNTHROTTLE: 886 case PERF_RECORD_UNTHROTTLE:
1093 return tool->unthrottle(tool, event, sample, machine); 887 return tool->unthrottle(tool, event, sample, machine);
1094 default: 888 default:
1095 ++session->hists.stats.nr_unknown_events; 889 ++session->stats.nr_unknown_events;
1096 return -1; 890 return -1;
1097 } 891 }
1098} 892}
@@ -1106,8 +900,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
1106 900
1107 if (!ip_callchain__valid(sample->callchain, event)) { 901 if (!ip_callchain__valid(sample->callchain, event)) {
1108 pr_debug("call-chain problem with event, skipping it.\n"); 902 pr_debug("call-chain problem with event, skipping it.\n");
1109 ++session->hists.stats.nr_invalid_chains; 903 ++session->stats.nr_invalid_chains;
1110 session->hists.stats.total_invalid_chains += sample->period; 904 session->stats.total_invalid_chains += sample->period;
1111 return -EINVAL; 905 return -EINVAL;
1112 } 906 }
1113 return 0; 907 return 0;
@@ -1165,7 +959,7 @@ static int perf_session__process_event(struct perf_session *session,
1165 if (event->header.type >= PERF_RECORD_HEADER_MAX) 959 if (event->header.type >= PERF_RECORD_HEADER_MAX)
1166 return -EINVAL; 960 return -EINVAL;
1167 961
1168 hists__inc_nr_events(&session->hists, event->header.type); 962 events_stats__inc(&session->stats, event->header.type);
1169 963
1170 if (event->header.type >= PERF_RECORD_USER_TYPE_START) 964 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
1171 return perf_session__process_user_event(session, event, tool, file_offset); 965 return perf_session__process_user_event(session, event, tool, file_offset);
@@ -1201,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
1201 995
1202struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 996struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1203{ 997{
1204 return machine__findnew_thread(&session->host_machine, pid); 998 return machine__findnew_thread(&session->machines.host, pid);
1205} 999}
1206 1000
1207static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1001static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1220,39 +1014,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1220 const struct perf_tool *tool) 1014 const struct perf_tool *tool)
1221{ 1015{
1222 if (tool->lost == perf_event__process_lost && 1016 if (tool->lost == perf_event__process_lost &&
1223 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { 1017 session->stats.nr_events[PERF_RECORD_LOST] != 0) {
1224 ui__warning("Processed %d events and lost %d chunks!\n\n" 1018 ui__warning("Processed %d events and lost %d chunks!\n\n"
1225 "Check IO/CPU overload!\n\n", 1019 "Check IO/CPU overload!\n\n",
1226 session->hists.stats.nr_events[0], 1020 session->stats.nr_events[0],
1227 session->hists.stats.nr_events[PERF_RECORD_LOST]); 1021 session->stats.nr_events[PERF_RECORD_LOST]);
1228 } 1022 }
1229 1023
1230 if (session->hists.stats.nr_unknown_events != 0) { 1024 if (session->stats.nr_unknown_events != 0) {
1231 ui__warning("Found %u unknown events!\n\n" 1025 ui__warning("Found %u unknown events!\n\n"
1232 "Is this an older tool processing a perf.data " 1026 "Is this an older tool processing a perf.data "
1233 "file generated by a more recent tool?\n\n" 1027 "file generated by a more recent tool?\n\n"
1234 "If that is not the case, consider " 1028 "If that is not the case, consider "
1235 "reporting to linux-kernel@vger.kernel.org.\n\n", 1029 "reporting to linux-kernel@vger.kernel.org.\n\n",
1236 session->hists.stats.nr_unknown_events); 1030 session->stats.nr_unknown_events);
1237 } 1031 }
1238 1032
1239 if (session->hists.stats.nr_unknown_id != 0) { 1033 if (session->stats.nr_unknown_id != 0) {
1240 ui__warning("%u samples with id not present in the header\n", 1034 ui__warning("%u samples with id not present in the header\n",
1241 session->hists.stats.nr_unknown_id); 1035 session->stats.nr_unknown_id);
1242 } 1036 }
1243 1037
1244 if (session->hists.stats.nr_invalid_chains != 0) { 1038 if (session->stats.nr_invalid_chains != 0) {
1245 ui__warning("Found invalid callchains!\n\n" 1039 ui__warning("Found invalid callchains!\n\n"
1246 "%u out of %u events were discarded for this reason.\n\n" 1040 "%u out of %u events were discarded for this reason.\n\n"
1247 "Consider reporting to linux-kernel@vger.kernel.org.\n\n", 1041 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
1248 session->hists.stats.nr_invalid_chains, 1042 session->stats.nr_invalid_chains,
1249 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 1043 session->stats.nr_events[PERF_RECORD_SAMPLE]);
1250 } 1044 }
1251 1045
1252 if (session->hists.stats.nr_unprocessable_samples != 0) { 1046 if (session->stats.nr_unprocessable_samples != 0) {
1253 ui__warning("%u unprocessable samples recorded.\n" 1047 ui__warning("%u unprocessable samples recorded.\n"
1254 "Do you have a KVM guest running and not using 'perf kvm'?\n", 1048 "Do you have a KVM guest running and not using 'perf kvm'?\n",
1255 session->hists.stats.nr_unprocessable_samples); 1049 session->stats.nr_unprocessable_samples);
1256 } 1050 }
1257} 1051}
1258 1052
@@ -1369,6 +1163,18 @@ fetch_mmaped_event(struct perf_session *session,
1369 return event; 1163 return event;
1370} 1164}
1371 1165
1166/*
1167 * On 64bit we can mmap the data file in one go. No need for tiny mmap
1168 * slices. On 32bit we use 32MB.
1169 */
1170#if BITS_PER_LONG == 64
1171#define MMAP_SIZE ULLONG_MAX
1172#define NUM_MMAPS 1
1173#else
1174#define MMAP_SIZE (32 * 1024 * 1024ULL)
1175#define NUM_MMAPS 128
1176#endif
1177
1372int __perf_session__process_events(struct perf_session *session, 1178int __perf_session__process_events(struct perf_session *session,
1373 u64 data_offset, u64 data_size, 1179 u64 data_offset, u64 data_size,
1374 u64 file_size, struct perf_tool *tool) 1180 u64 file_size, struct perf_tool *tool)
@@ -1376,7 +1182,7 @@ int __perf_session__process_events(struct perf_session *session,
1376 u64 head, page_offset, file_offset, file_pos, progress_next; 1182 u64 head, page_offset, file_offset, file_pos, progress_next;
1377 int err, mmap_prot, mmap_flags, map_idx = 0; 1183 int err, mmap_prot, mmap_flags, map_idx = 0;
1378 size_t mmap_size; 1184 size_t mmap_size;
1379 char *buf, *mmaps[8]; 1185 char *buf, *mmaps[NUM_MMAPS];
1380 union perf_event *event; 1186 union perf_event *event;
1381 uint32_t size; 1187 uint32_t size;
1382 1188
@@ -1391,7 +1197,7 @@ int __perf_session__process_events(struct perf_session *session,
1391 1197
1392 progress_next = file_size / 16; 1198 progress_next = file_size / 16;
1393 1199
1394 mmap_size = session->mmap_window; 1200 mmap_size = MMAP_SIZE;
1395 if (mmap_size > file_size) 1201 if (mmap_size > file_size)
1396 mmap_size = file_size; 1202 mmap_size = file_size;
1397 1203
@@ -1526,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1526 1332
1527size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) 1333size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
1528{ 1334{
1529 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + 1335 return machines__fprintf_dsos(&self->machines, fp);
1530 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
1531 machines__fprintf_dsos(&self->machines, fp);
1532} 1336}
1533 1337
1534size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, 1338size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1535 bool with_hits) 1339 bool (skip)(struct dso *dso, int parm), int parm)
1536{ 1340{
1537 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); 1341 return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
1538 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1539} 1342}
1540 1343
1541size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) 1344size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1543,11 +1346,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1543 struct perf_evsel *pos; 1346 struct perf_evsel *pos;
1544 size_t ret = fprintf(fp, "Aggregated stats:\n"); 1347 size_t ret = fprintf(fp, "Aggregated stats:\n");
1545 1348
1546 ret += hists__fprintf_nr_events(&session->hists, fp); 1349 ret += events_stats__fprintf(&session->stats, fp);
1547 1350
1548 list_for_each_entry(pos, &session->evlist->entries, node) { 1351 list_for_each_entry(pos, &session->evlist->entries, node) {
1549 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); 1352 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1550 ret += hists__fprintf_nr_events(&pos->hists, fp); 1353 ret += events_stats__fprintf(&pos->hists.stats, fp);
1551 } 1354 }
1552 1355
1553 return ret; 1356 return ret;
@@ -1559,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1559 * FIXME: Here we have to actually print all the machines in this 1362 * FIXME: Here we have to actually print all the machines in this
1560 * session, not just the host... 1363 * session, not just the host...
1561 */ 1364 */
1562 return machine__fprintf(&session->host_machine, fp); 1365 return machine__fprintf(&session->machines.host, fp);
1563} 1366}
1564 1367
1565void perf_session__remove_thread(struct perf_session *session, 1368void perf_session__remove_thread(struct perf_session *session,
@@ -1568,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session,
1568 /* 1371 /*
1569 * FIXME: This one makes no sense, we need to remove the thread from 1372 * FIXME: This one makes no sense, we need to remove the thread from
1570 * the machine it belongs to, perf_session can have many machines, so 1373 * the machine it belongs to, perf_session can have many machines, so
1571 * doing it always on ->host_machine is wrong. Fix when auditing all 1374 * doing it always on ->machines.host is wrong. Fix when auditing all
1572 * the 'perf kvm' code. 1375 * the 'perf kvm' code.
1573 */ 1376 */
1574 machine__remove_thread(&session->host_machine, th); 1377 machine__remove_thread(&session->machines.host, th);
1575} 1378}
1576 1379
1577struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1380struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index cea133a6bdf1..b5c0847edfa9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -30,16 +30,10 @@ struct ordered_samples {
30struct perf_session { 30struct perf_session {
31 struct perf_header header; 31 struct perf_header header;
32 unsigned long size; 32 unsigned long size;
33 unsigned long mmap_window; 33 struct machines machines;
34 struct machine host_machine;
35 struct rb_root machines;
36 struct perf_evlist *evlist; 34 struct perf_evlist *evlist;
37 struct pevent *pevent; 35 struct pevent *pevent;
38 /* 36 struct events_stats stats;
39 * FIXME: Need to split this up further, we need global
40 * stats + per event stats.
41 */
42 struct hists hists;
43 int fd; 37 int fd;
44 bool fd_pipe; 38 bool fd_pipe;
45 bool repipe; 39 bool repipe;
@@ -54,7 +48,7 @@ struct perf_tool;
54struct perf_session *perf_session__new(const char *filename, int mode, 48struct perf_session *perf_session__new(const char *filename, int mode,
55 bool force, bool repipe, 49 bool force, bool repipe,
56 struct perf_tool *tool); 50 struct perf_tool *tool);
57void perf_session__delete(struct perf_session *self); 51void perf_session__delete(struct perf_session *session);
58 52
59void perf_event_header__bswap(struct perf_event_header *self); 53void perf_event_header__bswap(struct perf_event_header *self);
60 54
@@ -81,43 +75,24 @@ void perf_session__set_id_hdr_size(struct perf_session *session);
81void perf_session__remove_thread(struct perf_session *self, struct thread *th); 75void perf_session__remove_thread(struct perf_session *self, struct thread *th);
82 76
83static inline 77static inline
84struct machine *perf_session__find_host_machine(struct perf_session *self)
85{
86 return &self->host_machine;
87}
88
89static inline
90struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) 78struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
91{ 79{
92 if (pid == HOST_KERNEL_ID)
93 return &self->host_machine;
94 return machines__find(&self->machines, pid); 80 return machines__find(&self->machines, pid);
95} 81}
96 82
97static inline 83static inline
98struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) 84struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
99{ 85{
100 if (pid == HOST_KERNEL_ID)
101 return &self->host_machine;
102 return machines__findnew(&self->machines, pid); 86 return machines__findnew(&self->machines, pid);
103} 87}
104 88
105static inline
106void perf_session__process_machines(struct perf_session *self,
107 struct perf_tool *tool,
108 machine__process_t process)
109{
110 process(&self->host_machine, tool);
111 return machines__process(&self->machines, process, tool);
112}
113
114struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 89struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
115size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 90size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
116 91
117size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 92size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
118 93
119size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 94size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
120 FILE *fp, bool with_hits); 95 bool (fn)(struct dso *dso, int parm), int parm);
121 96
122size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); 97size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
123 98
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cfd1c0feb32d..d41926cb9e3f 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -60,7 +60,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
60static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 60static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
61 size_t size, unsigned int width) 61 size_t size, unsigned int width)
62{ 62{
63 return repsep_snprintf(bf, size, "%*s:%5d", width, 63 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
64 self->thread->comm ?: "", self->thread->pid); 64 self->thread->comm ?: "", self->thread->pid);
65} 65}
66 66
@@ -97,6 +97,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
98} 98}
99 99
100struct sort_entry sort_comm = {
101 .se_header = "Command",
102 .se_cmp = sort__comm_cmp,
103 .se_collapse = sort__comm_collapse,
104 .se_snprintf = hist_entry__comm_snprintf,
105 .se_width_idx = HISTC_COMM,
106};
107
108/* --sort dso */
109
100static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) 110static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
101{ 111{
102 struct dso *dso_l = map_l ? map_l->dso : NULL; 112 struct dso *dso_l = map_l ? map_l->dso : NULL;
@@ -117,40 +127,12 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
117 return strcmp(dso_name_l, dso_name_r); 127 return strcmp(dso_name_l, dso_name_r);
118} 128}
119 129
120struct sort_entry sort_comm = {
121 .se_header = "Command",
122 .se_cmp = sort__comm_cmp,
123 .se_collapse = sort__comm_collapse,
124 .se_snprintf = hist_entry__comm_snprintf,
125 .se_width_idx = HISTC_COMM,
126};
127
128/* --sort dso */
129
130static int64_t 130static int64_t
131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
132{ 132{
133 return _sort__dso_cmp(left->ms.map, right->ms.map); 133 return _sort__dso_cmp(left->ms.map, right->ms.map);
134} 134}
135 135
136
137static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
138 u64 ip_l, u64 ip_r)
139{
140 if (!sym_l || !sym_r)
141 return cmp_null(sym_l, sym_r);
142
143 if (sym_l == sym_r)
144 return 0;
145
146 if (sym_l)
147 ip_l = sym_l->start;
148 if (sym_r)
149 ip_r = sym_r->start;
150
151 return (int64_t)(ip_r - ip_l);
152}
153
154static int _hist_entry__dso_snprintf(struct map *map, char *bf, 136static int _hist_entry__dso_snprintf(struct map *map, char *bf,
155 size_t size, unsigned int width) 137 size_t size, unsigned int width)
156{ 138{
@@ -169,9 +151,43 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
169 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); 151 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
170} 152}
171 153
154struct sort_entry sort_dso = {
155 .se_header = "Shared Object",
156 .se_cmp = sort__dso_cmp,
157 .se_snprintf = hist_entry__dso_snprintf,
158 .se_width_idx = HISTC_DSO,
159};
160
161/* --sort symbol */
162
163static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
164{
165 u64 ip_l, ip_r;
166
167 if (!sym_l || !sym_r)
168 return cmp_null(sym_l, sym_r);
169
170 if (sym_l == sym_r)
171 return 0;
172
173 ip_l = sym_l->start;
174 ip_r = sym_r->start;
175
176 return (int64_t)(ip_r - ip_l);
177}
178
179static int64_t
180sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
181{
182 if (!left->ms.sym && !right->ms.sym)
183 return right->level - left->level;
184
185 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
186}
187
172static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 188static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
173 u64 ip, char level, char *bf, size_t size, 189 u64 ip, char level, char *bf, size_t size,
174 unsigned int width __maybe_unused) 190 unsigned int width)
175{ 191{
176 size_t ret = 0; 192 size_t ret = 0;
177 193
@@ -197,43 +213,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
197 return ret; 213 return ret;
198} 214}
199 215
200
201struct sort_entry sort_dso = {
202 .se_header = "Shared Object",
203 .se_cmp = sort__dso_cmp,
204 .se_snprintf = hist_entry__dso_snprintf,
205 .se_width_idx = HISTC_DSO,
206};
207
208static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, 216static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
209 size_t size, 217 size_t size, unsigned int width)
210 unsigned int width __maybe_unused)
211{ 218{
212 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, 219 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213 self->level, bf, size, width); 220 self->level, bf, size, width);
214} 221}
215 222
216/* --sort symbol */
217static int64_t
218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
219{
220 u64 ip_l, ip_r;
221
222 if (!left->ms.sym && !right->ms.sym)
223 return right->level - left->level;
224
225 if (!left->ms.sym || !right->ms.sym)
226 return cmp_null(left->ms.sym, right->ms.sym);
227
228 if (left->ms.sym == right->ms.sym)
229 return 0;
230
231 ip_l = left->ms.sym->start;
232 ip_r = right->ms.sym->start;
233
234 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
235}
236
237struct sort_entry sort_sym = { 223struct sort_entry sort_sym = {
238 .se_header = "Symbol", 224 .se_header = "Symbol",
239 .se_cmp = sort__sym_cmp, 225 .se_cmp = sort__sym_cmp,
@@ -253,7 +239,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
253 size_t size, 239 size_t size,
254 unsigned int width __maybe_unused) 240 unsigned int width __maybe_unused)
255{ 241{
256 FILE *fp; 242 FILE *fp = NULL;
257 char cmd[PATH_MAX + 2], *path = self->srcline, *nl; 243 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
258 size_t line_len; 244 size_t line_len;
259 245
@@ -274,7 +260,6 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
274 260
275 if (getline(&path, &line_len, fp) < 0 || !line_len) 261 if (getline(&path, &line_len, fp) < 0 || !line_len)
276 goto out_ip; 262 goto out_ip;
277 fclose(fp);
278 self->srcline = strdup(path); 263 self->srcline = strdup(path);
279 if (self->srcline == NULL) 264 if (self->srcline == NULL)
280 goto out_ip; 265 goto out_ip;
@@ -284,8 +269,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
284 *nl = '\0'; 269 *nl = '\0';
285 path = self->srcline; 270 path = self->srcline;
286out_path: 271out_path:
272 if (fp)
273 pclose(fp);
287 return repsep_snprintf(bf, size, "%s", path); 274 return repsep_snprintf(bf, size, "%s", path);
288out_ip: 275out_ip:
276 if (fp)
277 pclose(fp);
289 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); 278 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
290} 279}
291 280
@@ -335,7 +324,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
335static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, 324static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
336 size_t size, unsigned int width) 325 size_t size, unsigned int width)
337{ 326{
338 return repsep_snprintf(bf, size, "%-*d", width, self->cpu); 327 return repsep_snprintf(bf, size, "%*d", width, self->cpu);
339} 328}
340 329
341struct sort_entry sort_cpu = { 330struct sort_entry sort_cpu = {
@@ -345,6 +334,8 @@ struct sort_entry sort_cpu = {
345 .se_width_idx = HISTC_CPU, 334 .se_width_idx = HISTC_CPU,
346}; 335};
347 336
337/* sort keys for branch stacks */
338
348static int64_t 339static int64_t
349sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) 340sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
350{ 341{
@@ -359,13 +350,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
359 bf, size, width); 350 bf, size, width);
360} 351}
361 352
362struct sort_entry sort_dso_from = {
363 .se_header = "Source Shared Object",
364 .se_cmp = sort__dso_from_cmp,
365 .se_snprintf = hist_entry__dso_from_snprintf,
366 .se_width_idx = HISTC_DSO_FROM,
367};
368
369static int64_t 353static int64_t
370sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 354sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
371{ 355{
@@ -389,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
389 if (!from_l->sym && !from_r->sym) 373 if (!from_l->sym && !from_r->sym)
390 return right->level - left->level; 374 return right->level - left->level;
391 375
392 return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr, 376 return _sort__sym_cmp(from_l->sym, from_r->sym);
393 from_r->addr);
394} 377}
395 378
396static int64_t 379static int64_t
@@ -402,12 +385,11 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
402 if (!to_l->sym && !to_r->sym) 385 if (!to_l->sym && !to_r->sym)
403 return right->level - left->level; 386 return right->level - left->level;
404 387
405 return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr); 388 return _sort__sym_cmp(to_l->sym, to_r->sym);
406} 389}
407 390
408static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, 391static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
409 size_t size, 392 size_t size, unsigned int width)
410 unsigned int width __maybe_unused)
411{ 393{
412 struct addr_map_symbol *from = &self->branch_info->from; 394 struct addr_map_symbol *from = &self->branch_info->from;
413 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 395 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
@@ -416,8 +398,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
416} 398}
417 399
418static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, 400static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
419 size_t size, 401 size_t size, unsigned int width)
420 unsigned int width __maybe_unused)
421{ 402{
422 struct addr_map_symbol *to = &self->branch_info->to; 403 struct addr_map_symbol *to = &self->branch_info->to;
423 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 404 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
@@ -425,6 +406,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
425 406
426} 407}
427 408
409struct sort_entry sort_dso_from = {
410 .se_header = "Source Shared Object",
411 .se_cmp = sort__dso_from_cmp,
412 .se_snprintf = hist_entry__dso_from_snprintf,
413 .se_width_idx = HISTC_DSO_FROM,
414};
415
428struct sort_entry sort_dso_to = { 416struct sort_entry sort_dso_to = {
429 .se_header = "Target Shared Object", 417 .se_header = "Target Shared Object",
430 .se_cmp = sort__dso_to_cmp, 418 .se_cmp = sort__dso_to_cmp,
@@ -484,30 +472,40 @@ struct sort_dimension {
484 472
485#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 473#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
486 474
487static struct sort_dimension sort_dimensions[] = { 475static struct sort_dimension common_sort_dimensions[] = {
488 DIM(SORT_PID, "pid", sort_thread), 476 DIM(SORT_PID, "pid", sort_thread),
489 DIM(SORT_COMM, "comm", sort_comm), 477 DIM(SORT_COMM, "comm", sort_comm),
490 DIM(SORT_DSO, "dso", sort_dso), 478 DIM(SORT_DSO, "dso", sort_dso),
491 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
492 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
493 DIM(SORT_SYM, "symbol", sort_sym), 479 DIM(SORT_SYM, "symbol", sort_sym),
494 DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
495 DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
496 DIM(SORT_PARENT, "parent", sort_parent), 480 DIM(SORT_PARENT, "parent", sort_parent),
497 DIM(SORT_CPU, "cpu", sort_cpu), 481 DIM(SORT_CPU, "cpu", sort_cpu),
498 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
499 DIM(SORT_SRCLINE, "srcline", sort_srcline), 482 DIM(SORT_SRCLINE, "srcline", sort_srcline),
500}; 483};
501 484
485#undef DIM
486
487#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
488
489static struct sort_dimension bstack_sort_dimensions[] = {
490 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
491 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
492 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
493 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
494 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
495};
496
497#undef DIM
498
502int sort_dimension__add(const char *tok) 499int sort_dimension__add(const char *tok)
503{ 500{
504 unsigned int i; 501 unsigned int i;
505 502
506 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 503 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
507 struct sort_dimension *sd = &sort_dimensions[i]; 504 struct sort_dimension *sd = &common_sort_dimensions[i];
508 505
509 if (strncasecmp(tok, sd->name, strlen(tok))) 506 if (strncasecmp(tok, sd->name, strlen(tok)))
510 continue; 507 continue;
508
511 if (sd->entry == &sort_parent) { 509 if (sd->entry == &sort_parent) {
512 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 510 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
513 if (ret) { 511 if (ret) {
@@ -518,9 +516,7 @@ int sort_dimension__add(const char *tok)
518 return -EINVAL; 516 return -EINVAL;
519 } 517 }
520 sort__has_parent = 1; 518 sort__has_parent = 1;
521 } else if (sd->entry == &sort_sym || 519 } else if (sd->entry == &sort_sym) {
522 sd->entry == &sort_sym_from ||
523 sd->entry == &sort_sym_to) {
524 sort__has_sym = 1; 520 sort__has_sym = 1;
525 } 521 }
526 522
@@ -530,52 +526,69 @@ int sort_dimension__add(const char *tok)
530 if (sd->entry->se_collapse) 526 if (sd->entry->se_collapse)
531 sort__need_collapse = 1; 527 sort__need_collapse = 1;
532 528
533 if (list_empty(&hist_entry__sort_list)) { 529 if (list_empty(&hist_entry__sort_list))
534 if (!strcmp(sd->name, "pid")) 530 sort__first_dimension = i;
535 sort__first_dimension = SORT_PID;
536 else if (!strcmp(sd->name, "comm"))
537 sort__first_dimension = SORT_COMM;
538 else if (!strcmp(sd->name, "dso"))
539 sort__first_dimension = SORT_DSO;
540 else if (!strcmp(sd->name, "symbol"))
541 sort__first_dimension = SORT_SYM;
542 else if (!strcmp(sd->name, "parent"))
543 sort__first_dimension = SORT_PARENT;
544 else if (!strcmp(sd->name, "cpu"))
545 sort__first_dimension = SORT_CPU;
546 else if (!strcmp(sd->name, "symbol_from"))
547 sort__first_dimension = SORT_SYM_FROM;
548 else if (!strcmp(sd->name, "symbol_to"))
549 sort__first_dimension = SORT_SYM_TO;
550 else if (!strcmp(sd->name, "dso_from"))
551 sort__first_dimension = SORT_DSO_FROM;
552 else if (!strcmp(sd->name, "dso_to"))
553 sort__first_dimension = SORT_DSO_TO;
554 else if (!strcmp(sd->name, "mispredict"))
555 sort__first_dimension = SORT_MISPREDICT;
556 }
557 531
558 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 532 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
559 sd->taken = 1; 533 sd->taken = 1;
560 534
561 return 0; 535 return 0;
562 } 536 }
537
538 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
539 struct sort_dimension *sd = &bstack_sort_dimensions[i];
540
541 if (strncasecmp(tok, sd->name, strlen(tok)))
542 continue;
543
544 if (sort__branch_mode != 1)
545 return -EINVAL;
546
547 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
548 sort__has_sym = 1;
549
550 if (sd->taken)
551 return 0;
552
553 if (sd->entry->se_collapse)
554 sort__need_collapse = 1;
555
556 if (list_empty(&hist_entry__sort_list))
557 sort__first_dimension = i + __SORT_BRANCH_STACK;
558
559 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
560 sd->taken = 1;
561
562 return 0;
563 }
564
563 return -ESRCH; 565 return -ESRCH;
564} 566}
565 567
566void setup_sorting(const char * const usagestr[], const struct option *opts) 568int setup_sorting(void)
567{ 569{
568 char *tmp, *tok, *str = strdup(sort_order); 570 char *tmp, *tok, *str = strdup(sort_order);
571 int ret = 0;
572
573 if (str == NULL) {
574 error("Not enough memory to setup sort keys");
575 return -ENOMEM;
576 }
569 577
570 for (tok = strtok_r(str, ", ", &tmp); 578 for (tok = strtok_r(str, ", ", &tmp);
571 tok; tok = strtok_r(NULL, ", ", &tmp)) { 579 tok; tok = strtok_r(NULL, ", ", &tmp)) {
572 if (sort_dimension__add(tok) < 0) { 580 ret = sort_dimension__add(tok);
581 if (ret == -EINVAL) {
582 error("Invalid --sort key: `%s'", tok);
583 break;
584 } else if (ret == -ESRCH) {
573 error("Unknown --sort key: `%s'", tok); 585 error("Unknown --sort key: `%s'", tok);
574 usage_with_options(usagestr, opts); 586 break;
575 } 587 }
576 } 588 }
577 589
578 free(str); 590 free(str);
591 return ret;
579} 592}
580 593
581void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 594void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index b4e8c3ba559d..b13e56f6ccbe 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -55,9 +55,6 @@ struct he_stat {
55struct hist_entry_diff { 55struct hist_entry_diff {
56 bool computed; 56 bool computed;
57 57
58 /* PERF_HPP__DISPL */
59 int displacement;
60
61 /* PERF_HPP__DELTA */ 58 /* PERF_HPP__DELTA */
62 double period_ratio_delta; 59 double period_ratio_delta;
63 60
@@ -118,25 +115,29 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
118 return NULL; 115 return NULL;
119} 116}
120 117
121static inline void hist__entry_add_pair(struct hist_entry *he, 118static inline void hist_entry__add_pair(struct hist_entry *he,
122 struct hist_entry *pair) 119 struct hist_entry *pair)
123{ 120{
124 list_add_tail(&he->pairs.head, &pair->pairs.node); 121 list_add_tail(&he->pairs.head, &pair->pairs.node);
125} 122}
126 123
127enum sort_type { 124enum sort_type {
125 /* common sort keys */
128 SORT_PID, 126 SORT_PID,
129 SORT_COMM, 127 SORT_COMM,
130 SORT_DSO, 128 SORT_DSO,
131 SORT_SYM, 129 SORT_SYM,
132 SORT_PARENT, 130 SORT_PARENT,
133 SORT_CPU, 131 SORT_CPU,
134 SORT_DSO_FROM, 132 SORT_SRCLINE,
133
134 /* branch stack specific sort keys */
135 __SORT_BRANCH_STACK,
136 SORT_DSO_FROM = __SORT_BRANCH_STACK,
135 SORT_DSO_TO, 137 SORT_DSO_TO,
136 SORT_SYM_FROM, 138 SORT_SYM_FROM,
137 SORT_SYM_TO, 139 SORT_SYM_TO,
138 SORT_MISPREDICT, 140 SORT_MISPREDICT,
139 SORT_SRCLINE,
140}; 141};
141 142
142/* 143/*
@@ -159,7 +160,7 @@ struct sort_entry {
159extern struct sort_entry sort_thread; 160extern struct sort_entry sort_thread;
160extern struct list_head hist_entry__sort_list; 161extern struct list_head hist_entry__sort_list;
161 162
162void setup_sorting(const char * const usagestr[], const struct option *opts); 163int setup_sorting(void);
163extern int sort_dimension__add(const char *); 164extern int sort_dimension__add(const char *);
164void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 165void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
165 const char *list_name, FILE *fp); 166 const char *list_name, FILE *fp);
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 346707df04b9..29c7b2cb2521 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -332,6 +332,24 @@ char *strxfrchar(char *s, char from, char to)
332} 332}
333 333
334/** 334/**
335 * ltrim - Removes leading whitespace from @s.
336 * @s: The string to be stripped.
337 *
338 * Return pointer to the first non-whitespace character in @s.
339 */
340char *ltrim(char *s)
341{
342 int len = strlen(s);
343
344 while (len && isspace(*s)) {
345 len--;
346 s++;
347 }
348
349 return s;
350}
351
352/**
335 * rtrim - Removes trailing whitespace from @s. 353 * rtrim - Removes trailing whitespace from @s.
336 * @s: The string to be stripped. 354 * @s: The string to be stripped.
337 * 355 *
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 155d8b7078a7..55433aa42c8f 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -35,11 +35,11 @@ out_delete:
35 return NULL; 35 return NULL;
36} 36}
37 37
38static void str_node__delete(struct str_node *self, bool dupstr) 38static void str_node__delete(struct str_node *snode, bool dupstr)
39{ 39{
40 if (dupstr) 40 if (dupstr)
41 free((void *)self->s); 41 free((void *)snode->s);
42 free(self); 42 free(snode);
43} 43}
44 44
45static 45static
@@ -59,12 +59,12 @@ static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
59 return strcmp(snode->s, str); 59 return strcmp(snode->s, str);
60} 60}
61 61
62int strlist__add(struct strlist *self, const char *new_entry) 62int strlist__add(struct strlist *slist, const char *new_entry)
63{ 63{
64 return rblist__add_node(&self->rblist, new_entry); 64 return rblist__add_node(&slist->rblist, new_entry);
65} 65}
66 66
67int strlist__load(struct strlist *self, const char *filename) 67int strlist__load(struct strlist *slist, const char *filename)
68{ 68{
69 char entry[1024]; 69 char entry[1024];
70 int err; 70 int err;
@@ -80,7 +80,7 @@ int strlist__load(struct strlist *self, const char *filename)
80 continue; 80 continue;
81 entry[len - 1] = '\0'; 81 entry[len - 1] = '\0';
82 82
83 err = strlist__add(self, entry); 83 err = strlist__add(slist, entry);
84 if (err != 0) 84 if (err != 0)
85 goto out; 85 goto out;
86 } 86 }
@@ -107,56 +107,56 @@ struct str_node *strlist__find(struct strlist *slist, const char *entry)
107 return snode; 107 return snode;
108} 108}
109 109
110static int strlist__parse_list_entry(struct strlist *self, const char *s) 110static int strlist__parse_list_entry(struct strlist *slist, const char *s)
111{ 111{
112 if (strncmp(s, "file://", 7) == 0) 112 if (strncmp(s, "file://", 7) == 0)
113 return strlist__load(self, s + 7); 113 return strlist__load(slist, s + 7);
114 114
115 return strlist__add(self, s); 115 return strlist__add(slist, s);
116} 116}
117 117
118int strlist__parse_list(struct strlist *self, const char *s) 118int strlist__parse_list(struct strlist *slist, const char *s)
119{ 119{
120 char *sep; 120 char *sep;
121 int err; 121 int err;
122 122
123 while ((sep = strchr(s, ',')) != NULL) { 123 while ((sep = strchr(s, ',')) != NULL) {
124 *sep = '\0'; 124 *sep = '\0';
125 err = strlist__parse_list_entry(self, s); 125 err = strlist__parse_list_entry(slist, s);
126 *sep = ','; 126 *sep = ',';
127 if (err != 0) 127 if (err != 0)
128 return err; 128 return err;
129 s = sep + 1; 129 s = sep + 1;
130 } 130 }
131 131
132 return *s ? strlist__parse_list_entry(self, s) : 0; 132 return *s ? strlist__parse_list_entry(slist, s) : 0;
133} 133}
134 134
135struct strlist *strlist__new(bool dupstr, const char *slist) 135struct strlist *strlist__new(bool dupstr, const char *list)
136{ 136{
137 struct strlist *self = malloc(sizeof(*self)); 137 struct strlist *slist = malloc(sizeof(*slist));
138 138
139 if (self != NULL) { 139 if (slist != NULL) {
140 rblist__init(&self->rblist); 140 rblist__init(&slist->rblist);
141 self->rblist.node_cmp = strlist__node_cmp; 141 slist->rblist.node_cmp = strlist__node_cmp;
142 self->rblist.node_new = strlist__node_new; 142 slist->rblist.node_new = strlist__node_new;
143 self->rblist.node_delete = strlist__node_delete; 143 slist->rblist.node_delete = strlist__node_delete;
144 144
145 self->dupstr = dupstr; 145 slist->dupstr = dupstr;
146 if (slist && strlist__parse_list(self, slist) != 0) 146 if (slist && strlist__parse_list(slist, list) != 0)
147 goto out_error; 147 goto out_error;
148 } 148 }
149 149
150 return self; 150 return slist;
151out_error: 151out_error:
152 free(self); 152 free(slist);
153 return NULL; 153 return NULL;
154} 154}
155 155
156void strlist__delete(struct strlist *self) 156void strlist__delete(struct strlist *slist)
157{ 157{
158 if (self != NULL) 158 if (slist != NULL)
159 rblist__delete(&self->rblist); 159 rblist__delete(&slist->rblist);
160} 160}
161 161
162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) 162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index dd9f922ec67c..5c7f87069d9c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -17,34 +17,34 @@ struct strlist {
17}; 17};
18 18
19struct strlist *strlist__new(bool dupstr, const char *slist); 19struct strlist *strlist__new(bool dupstr, const char *slist);
20void strlist__delete(struct strlist *self); 20void strlist__delete(struct strlist *slist);
21 21
22void strlist__remove(struct strlist *self, struct str_node *sn); 22void strlist__remove(struct strlist *slist, struct str_node *sn);
23int strlist__load(struct strlist *self, const char *filename); 23int strlist__load(struct strlist *slist, const char *filename);
24int strlist__add(struct strlist *self, const char *str); 24int strlist__add(struct strlist *slist, const char *str);
25 25
26struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 26struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx);
27struct str_node *strlist__find(struct strlist *self, const char *entry); 27struct str_node *strlist__find(struct strlist *slist, const char *entry);
28 28
29static inline bool strlist__has_entry(struct strlist *self, const char *entry) 29static inline bool strlist__has_entry(struct strlist *slist, const char *entry)
30{ 30{
31 return strlist__find(self, entry) != NULL; 31 return strlist__find(slist, entry) != NULL;
32} 32}
33 33
34static inline bool strlist__empty(const struct strlist *self) 34static inline bool strlist__empty(const struct strlist *slist)
35{ 35{
36 return rblist__empty(&self->rblist); 36 return rblist__empty(&slist->rblist);
37} 37}
38 38
39static inline unsigned int strlist__nr_entries(const struct strlist *self) 39static inline unsigned int strlist__nr_entries(const struct strlist *slist)
40{ 40{
41 return rblist__nr_entries(&self->rblist); 41 return rblist__nr_entries(&slist->rblist);
42} 42}
43 43
44/* For strlist iteration */ 44/* For strlist iteration */
45static inline struct str_node *strlist__first(struct strlist *self) 45static inline struct str_node *strlist__first(struct strlist *slist)
46{ 46{
47 struct rb_node *rn = rb_first(&self->rblist.entries); 47 struct rb_node *rn = rb_first(&slist->rblist.entries);
48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; 48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
49} 49}
50static inline struct str_node *strlist__next(struct str_node *sn) 50static inline struct str_node *strlist__next(struct str_node *sn)
@@ -59,21 +59,21 @@ static inline struct str_node *strlist__next(struct str_node *sn)
59/** 59/**
60 * strlist_for_each - iterate over a strlist 60 * strlist_for_each - iterate over a strlist
61 * @pos: the &struct str_node to use as a loop cursor. 61 * @pos: the &struct str_node to use as a loop cursor.
62 * @self: the &struct strlist for loop. 62 * @slist: the &struct strlist for loop.
63 */ 63 */
64#define strlist__for_each(pos, self) \ 64#define strlist__for_each(pos, slist) \
65 for (pos = strlist__first(self); pos; pos = strlist__next(pos)) 65 for (pos = strlist__first(slist); pos; pos = strlist__next(pos))
66 66
67/** 67/**
68 * strlist_for_each_safe - iterate over a strlist safe against removal of 68 * strlist_for_each_safe - iterate over a strlist safe against removal of
69 * str_node 69 * str_node
70 * @pos: the &struct str_node to use as a loop cursor. 70 * @pos: the &struct str_node to use as a loop cursor.
71 * @n: another &struct str_node to use as temporary storage. 71 * @n: another &struct str_node to use as temporary storage.
72 * @self: the &struct strlist for loop. 72 * @slist: the &struct strlist for loop.
73 */ 73 */
74#define strlist__for_each_safe(pos, n, self) \ 74#define strlist__for_each_safe(pos, n, slist) \
75 for (pos = strlist__first(self), n = strlist__next(pos); pos;\ 75 for (pos = strlist__first(slist), n = strlist__next(pos); pos;\
76 pos = n, n = strlist__next(n)) 76 pos = n, n = strlist__next(n))
77 77
78int strlist__parse_list(struct strlist *self, const char *s); 78int strlist__parse_list(struct strlist *slist, const char *s);
79#endif /* __PERF_STRLIST_H */ 79#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index db0cc92cf2ea..54efcb5659ac 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1,6 +1,3 @@
1#include <libelf.h>
2#include <gelf.h>
3#include <elf.h>
4#include <fcntl.h> 1#include <fcntl.h>
5#include <stdio.h> 2#include <stdio.h>
6#include <errno.h> 3#include <errno.h>
@@ -718,6 +715,17 @@ int dso__load_sym(struct dso *dso, struct map *map,
718 sym.st_value); 715 sym.st_value);
719 used_opd = true; 716 used_opd = true;
720 } 717 }
718 /*
719 * When loading symbols in a data mapping, ABS symbols (which
720 * has a value of SHN_ABS in its st_shndx) failed at
721 * elf_getscn(). And it marks the loading as a failure so
722 * already loaded symbols cannot be fixed up.
723 *
724 * I'm not sure what should be done. Just ignore them for now.
725 * - Namhyung Kim
726 */
727 if (sym.st_shndx == SHN_ABS)
728 continue;
721 729
722 sec = elf_getscn(runtime_ss->elf, sym.st_shndx); 730 sec = elf_getscn(runtime_ss->elf, sym.st_shndx);
723 if (!sec) 731 if (!sec)
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 259f8f2ea9c9..a7390cde63bc 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,6 +1,5 @@
1#include "symbol.h" 1#include "symbol.h"
2 2
3#include <elf.h>
4#include <stdio.h> 3#include <stdio.h>
5#include <fcntl.h> 4#include <fcntl.h>
6#include <string.h> 5#include <string.h>
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 295f8d4feedf..e6432d85b43d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -28,8 +28,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 28 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
30 symbol_filter_t filter); 30 symbol_filter_t filter);
31static int vmlinux_path__nr_entries; 31int vmlinux_path__nr_entries;
32static char **vmlinux_path; 32char **vmlinux_path;
33 33
34struct symbol_conf symbol_conf = { 34struct symbol_conf symbol_conf = {
35 .exclude_other = true, 35 .exclude_other = true,
@@ -202,13 +202,6 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
202 curr->end = ~0ULL; 202 curr->end = ~0ULL;
203} 203}
204 204
205static void map_groups__fixup_end(struct map_groups *mg)
206{
207 int i;
208 for (i = 0; i < MAP__NR_TYPES; ++i)
209 __map_groups__fixup_end(mg, i);
210}
211
212struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 205struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
213{ 206{
214 size_t namelen = strlen(name) + 1; 207 size_t namelen = strlen(name) + 1;
@@ -652,8 +645,8 @@ discard_symbol: rb_erase(&pos->rb_node, root);
652 return count + moved; 645 return count + moved;
653} 646}
654 647
655static bool symbol__restricted_filename(const char *filename, 648bool symbol__restricted_filename(const char *filename,
656 const char *restricted_filename) 649 const char *restricted_filename)
657{ 650{
658 bool restricted = false; 651 bool restricted = false;
659 652
@@ -775,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
775 else 768 else
776 machine = NULL; 769 machine = NULL;
777 770
778 name = malloc(PATH_MAX);
779 if (!name)
780 return -1;
781
782 dso->adjust_symbols = 0; 771 dso->adjust_symbols = 0;
783 772
784 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 773 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
@@ -802,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
802 if (machine) 791 if (machine)
803 root_dir = machine->root_dir; 792 root_dir = machine->root_dir;
804 793
794 name = malloc(PATH_MAX);
795 if (!name)
796 return -1;
797
805 /* Iterate over candidate debug images. 798 /* Iterate over candidate debug images.
806 * Keep track of "interesting" ones (those which have a symtab, dynsym, 799 * Keep track of "interesting" ones (those which have a symtab, dynsym,
807 * and/or opd section) for processing. 800 * and/or opd section) for processing.
@@ -887,200 +880,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
887 return NULL; 880 return NULL;
888} 881}
889 882
890static int map_groups__set_modules_path_dir(struct map_groups *mg,
891 const char *dir_name)
892{
893 struct dirent *dent;
894 DIR *dir = opendir(dir_name);
895 int ret = 0;
896
897 if (!dir) {
898 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
899 return -1;
900 }
901
902 while ((dent = readdir(dir)) != NULL) {
903 char path[PATH_MAX];
904 struct stat st;
905
906 /*sshfs might return bad dent->d_type, so we have to stat*/
907 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
908 if (stat(path, &st))
909 continue;
910
911 if (S_ISDIR(st.st_mode)) {
912 if (!strcmp(dent->d_name, ".") ||
913 !strcmp(dent->d_name, ".."))
914 continue;
915
916 ret = map_groups__set_modules_path_dir(mg, path);
917 if (ret < 0)
918 goto out;
919 } else {
920 char *dot = strrchr(dent->d_name, '.'),
921 dso_name[PATH_MAX];
922 struct map *map;
923 char *long_name;
924
925 if (dot == NULL || strcmp(dot, ".ko"))
926 continue;
927 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
928 (int)(dot - dent->d_name), dent->d_name);
929
930 strxfrchar(dso_name, '-', '_');
931 map = map_groups__find_by_name(mg, MAP__FUNCTION,
932 dso_name);
933 if (map == NULL)
934 continue;
935
936 long_name = strdup(path);
937 if (long_name == NULL) {
938 ret = -1;
939 goto out;
940 }
941 dso__set_long_name(map->dso, long_name);
942 map->dso->lname_alloc = 1;
943 dso__kernel_module_get_build_id(map->dso, "");
944 }
945 }
946
947out:
948 closedir(dir);
949 return ret;
950}
951
952static char *get_kernel_version(const char *root_dir)
953{
954 char version[PATH_MAX];
955 FILE *file;
956 char *name, *tmp;
957 const char *prefix = "Linux version ";
958
959 sprintf(version, "%s/proc/version", root_dir);
960 file = fopen(version, "r");
961 if (!file)
962 return NULL;
963
964 version[0] = '\0';
965 tmp = fgets(version, sizeof(version), file);
966 fclose(file);
967
968 name = strstr(version, prefix);
969 if (!name)
970 return NULL;
971 name += strlen(prefix);
972 tmp = strchr(name, ' ');
973 if (tmp)
974 *tmp = '\0';
975
976 return strdup(name);
977}
978
979static int machine__set_modules_path(struct machine *machine)
980{
981 char *version;
982 char modules_path[PATH_MAX];
983
984 version = get_kernel_version(machine->root_dir);
985 if (!version)
986 return -1;
987
988 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
989 machine->root_dir, version);
990 free(version);
991
992 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
993}
994
995struct map *machine__new_module(struct machine *machine, u64 start,
996 const char *filename)
997{
998 struct map *map;
999 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
1000
1001 if (dso == NULL)
1002 return NULL;
1003
1004 map = map__new2(start, dso, MAP__FUNCTION);
1005 if (map == NULL)
1006 return NULL;
1007
1008 if (machine__is_host(machine))
1009 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
1010 else
1011 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
1012 map_groups__insert(&machine->kmaps, map);
1013 return map;
1014}
1015
1016static int machine__create_modules(struct machine *machine)
1017{
1018 char *line = NULL;
1019 size_t n;
1020 FILE *file;
1021 struct map *map;
1022 const char *modules;
1023 char path[PATH_MAX];
1024
1025 if (machine__is_default_guest(machine))
1026 modules = symbol_conf.default_guest_modules;
1027 else {
1028 sprintf(path, "%s/proc/modules", machine->root_dir);
1029 modules = path;
1030 }
1031
1032 if (symbol__restricted_filename(path, "/proc/modules"))
1033 return -1;
1034
1035 file = fopen(modules, "r");
1036 if (file == NULL)
1037 return -1;
1038
1039 while (!feof(file)) {
1040 char name[PATH_MAX];
1041 u64 start;
1042 char *sep;
1043 int line_len;
1044
1045 line_len = getline(&line, &n, file);
1046 if (line_len < 0)
1047 break;
1048
1049 if (!line)
1050 goto out_failure;
1051
1052 line[--line_len] = '\0'; /* \n */
1053
1054 sep = strrchr(line, 'x');
1055 if (sep == NULL)
1056 continue;
1057
1058 hex2u64(sep + 1, &start);
1059
1060 sep = strchr(line, ' ');
1061 if (sep == NULL)
1062 continue;
1063
1064 *sep = '\0';
1065
1066 snprintf(name, sizeof(name), "[%s]", line);
1067 map = machine__new_module(machine, start, name);
1068 if (map == NULL)
1069 goto out_delete_line;
1070 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
1071 }
1072
1073 free(line);
1074 fclose(file);
1075
1076 return machine__set_modules_path(machine);
1077
1078out_delete_line:
1079 free(line);
1080out_failure:
1081 return -1;
1082}
1083
1084int dso__load_vmlinux(struct dso *dso, struct map *map, 883int dso__load_vmlinux(struct dso *dso, struct map *map,
1085 const char *vmlinux, symbol_filter_t filter) 884 const char *vmlinux, symbol_filter_t filter)
1086{ 885{
@@ -1124,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1124 filename = dso__build_id_filename(dso, NULL, 0); 923 filename = dso__build_id_filename(dso, NULL, 0);
1125 if (filename != NULL) { 924 if (filename != NULL) {
1126 err = dso__load_vmlinux(dso, map, filename, filter); 925 err = dso__load_vmlinux(dso, map, filename, filter);
1127 if (err > 0) 926 if (err > 0) {
927 dso->lname_alloc = 1;
1128 goto out; 928 goto out;
929 }
1129 free(filename); 930 free(filename);
1130 } 931 }
1131 932
@@ -1133,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1133 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 934 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
1134 if (err > 0) { 935 if (err > 0) {
1135 dso__set_long_name(dso, strdup(vmlinux_path[i])); 936 dso__set_long_name(dso, strdup(vmlinux_path[i]));
937 dso->lname_alloc = 1;
1136 break; 938 break;
1137 } 939 }
1138 } 940 }
@@ -1172,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1172 if (err > 0) { 974 if (err > 0) {
1173 dso__set_long_name(dso, 975 dso__set_long_name(dso,
1174 strdup(symbol_conf.vmlinux_name)); 976 strdup(symbol_conf.vmlinux_name));
977 dso->lname_alloc = 1;
1175 goto out_fixup; 978 goto out_fixup;
1176 } 979 }
1177 return err; 980 return err;
@@ -1300,195 +1103,6 @@ out_try_fixup:
1300 return err; 1103 return err;
1301} 1104}
1302 1105
1303size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1304{
1305 struct rb_node *nd;
1306 size_t ret = 0;
1307
1308 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
1309 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1310 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
1311 ret += __dsos__fprintf(&pos->user_dsos, fp);
1312 }
1313
1314 return ret;
1315}
1316
1317size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
1318 bool with_hits)
1319{
1320 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
1321 __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
1322}
1323
1324size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
1325 FILE *fp, bool with_hits)
1326{
1327 struct rb_node *nd;
1328 size_t ret = 0;
1329
1330 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
1331 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1332 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
1333 }
1334 return ret;
1335}
1336
1337static struct dso *machine__get_kernel(struct machine *machine)
1338{
1339 const char *vmlinux_name = NULL;
1340 struct dso *kernel;
1341
1342 if (machine__is_host(machine)) {
1343 vmlinux_name = symbol_conf.vmlinux_name;
1344 if (!vmlinux_name)
1345 vmlinux_name = "[kernel.kallsyms]";
1346
1347 kernel = dso__kernel_findnew(machine, vmlinux_name,
1348 "[kernel]",
1349 DSO_TYPE_KERNEL);
1350 } else {
1351 char bf[PATH_MAX];
1352
1353 if (machine__is_default_guest(machine))
1354 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
1355 if (!vmlinux_name)
1356 vmlinux_name = machine__mmap_name(machine, bf,
1357 sizeof(bf));
1358
1359 kernel = dso__kernel_findnew(machine, vmlinux_name,
1360 "[guest.kernel]",
1361 DSO_TYPE_GUEST_KERNEL);
1362 }
1363
1364 if (kernel != NULL && (!kernel->has_build_id))
1365 dso__read_running_kernel_build_id(kernel, machine);
1366
1367 return kernel;
1368}
1369
1370struct process_args {
1371 u64 start;
1372};
1373
1374static int symbol__in_kernel(void *arg, const char *name,
1375 char type __maybe_unused, u64 start)
1376{
1377 struct process_args *args = arg;
1378
1379 if (strchr(name, '['))
1380 return 0;
1381
1382 args->start = start;
1383 return 1;
1384}
1385
1386/* Figure out the start address of kernel map from /proc/kallsyms */
1387static u64 machine__get_kernel_start_addr(struct machine *machine)
1388{
1389 const char *filename;
1390 char path[PATH_MAX];
1391 struct process_args args;
1392
1393 if (machine__is_host(machine)) {
1394 filename = "/proc/kallsyms";
1395 } else {
1396 if (machine__is_default_guest(machine))
1397 filename = (char *)symbol_conf.default_guest_kallsyms;
1398 else {
1399 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1400 filename = path;
1401 }
1402 }
1403
1404 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1405 return 0;
1406
1407 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
1408 return 0;
1409
1410 return args.start;
1411}
1412
1413int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
1414{
1415 enum map_type type;
1416 u64 start = machine__get_kernel_start_addr(machine);
1417
1418 for (type = 0; type < MAP__NR_TYPES; ++type) {
1419 struct kmap *kmap;
1420
1421 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
1422 if (machine->vmlinux_maps[type] == NULL)
1423 return -1;
1424
1425 machine->vmlinux_maps[type]->map_ip =
1426 machine->vmlinux_maps[type]->unmap_ip =
1427 identity__map_ip;
1428 kmap = map__kmap(machine->vmlinux_maps[type]);
1429 kmap->kmaps = &machine->kmaps;
1430 map_groups__insert(&machine->kmaps,
1431 machine->vmlinux_maps[type]);
1432 }
1433
1434 return 0;
1435}
1436
1437void machine__destroy_kernel_maps(struct machine *machine)
1438{
1439 enum map_type type;
1440
1441 for (type = 0; type < MAP__NR_TYPES; ++type) {
1442 struct kmap *kmap;
1443
1444 if (machine->vmlinux_maps[type] == NULL)
1445 continue;
1446
1447 kmap = map__kmap(machine->vmlinux_maps[type]);
1448 map_groups__remove(&machine->kmaps,
1449 machine->vmlinux_maps[type]);
1450 if (kmap->ref_reloc_sym) {
1451 /*
1452 * ref_reloc_sym is shared among all maps, so free just
1453 * on one of them.
1454 */
1455 if (type == MAP__FUNCTION) {
1456 free((char *)kmap->ref_reloc_sym->name);
1457 kmap->ref_reloc_sym->name = NULL;
1458 free(kmap->ref_reloc_sym);
1459 }
1460 kmap->ref_reloc_sym = NULL;
1461 }
1462
1463 map__delete(machine->vmlinux_maps[type]);
1464 machine->vmlinux_maps[type] = NULL;
1465 }
1466}
1467
1468int machine__create_kernel_maps(struct machine *machine)
1469{
1470 struct dso *kernel = machine__get_kernel(machine);
1471
1472 if (kernel == NULL ||
1473 __machine__create_kernel_maps(machine, kernel) < 0)
1474 return -1;
1475
1476 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
1477 if (machine__is_host(machine))
1478 pr_debug("Problems creating module maps, "
1479 "continuing anyway...\n");
1480 else
1481 pr_debug("Problems creating module maps for guest %d, "
1482 "continuing anyway...\n", machine->pid);
1483 }
1484
1485 /*
1486 * Now that we have all the maps created, just set the ->end of them:
1487 */
1488 map_groups__fixup_end(&machine->kmaps);
1489 return 0;
1490}
1491
1492static void vmlinux_path__exit(void) 1106static void vmlinux_path__exit(void)
1493{ 1107{
1494 while (--vmlinux_path__nr_entries >= 0) { 1108 while (--vmlinux_path__nr_entries >= 0) {
@@ -1549,25 +1163,6 @@ out_fail:
1549 return -1; 1163 return -1;
1550} 1164}
1551 1165
1552size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
1553{
1554 int i;
1555 size_t printed = 0;
1556 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
1557
1558 if (kdso->has_build_id) {
1559 char filename[PATH_MAX];
1560 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
1561 printed += fprintf(fp, "[0] %s\n", filename);
1562 }
1563
1564 for (i = 0; i < vmlinux_path__nr_entries; ++i)
1565 printed += fprintf(fp, "[%d] %s\n",
1566 i + kdso->has_build_id, vmlinux_path[i]);
1567
1568 return printed;
1569}
1570
1571static int setup_list(struct strlist **list, const char *list_str, 1166static int setup_list(struct strlist **list, const char *list_str,
1572 const char *list_name) 1167 const char *list_name)
1573{ 1168{
@@ -1671,108 +1266,3 @@ void symbol__exit(void)
1671 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 1266 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
1672 symbol_conf.initialized = false; 1267 symbol_conf.initialized = false;
1673} 1268}
1674
1675int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
1676{
1677 struct machine *machine = machines__findnew(machines, pid);
1678
1679 if (machine == NULL)
1680 return -1;
1681
1682 return machine__create_kernel_maps(machine);
1683}
1684
1685int machines__create_guest_kernel_maps(struct rb_root *machines)
1686{
1687 int ret = 0;
1688 struct dirent **namelist = NULL;
1689 int i, items = 0;
1690 char path[PATH_MAX];
1691 pid_t pid;
1692 char *endp;
1693
1694 if (symbol_conf.default_guest_vmlinux_name ||
1695 symbol_conf.default_guest_modules ||
1696 symbol_conf.default_guest_kallsyms) {
1697 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
1698 }
1699
1700 if (symbol_conf.guestmount) {
1701 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
1702 if (items <= 0)
1703 return -ENOENT;
1704 for (i = 0; i < items; i++) {
1705 if (!isdigit(namelist[i]->d_name[0])) {
1706 /* Filter out . and .. */
1707 continue;
1708 }
1709 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
1710 if ((*endp != '\0') ||
1711 (endp == namelist[i]->d_name) ||
1712 (errno == ERANGE)) {
1713 pr_debug("invalid directory (%s). Skipping.\n",
1714 namelist[i]->d_name);
1715 continue;
1716 }
1717 sprintf(path, "%s/%s/proc/kallsyms",
1718 symbol_conf.guestmount,
1719 namelist[i]->d_name);
1720 ret = access(path, R_OK);
1721 if (ret) {
1722 pr_debug("Can't access file %s\n", path);
1723 goto failure;
1724 }
1725 machines__create_kernel_maps(machines, pid);
1726 }
1727failure:
1728 free(namelist);
1729 }
1730
1731 return ret;
1732}
1733
1734void machines__destroy_guest_kernel_maps(struct rb_root *machines)
1735{
1736 struct rb_node *next = rb_first(machines);
1737
1738 while (next) {
1739 struct machine *pos = rb_entry(next, struct machine, rb_node);
1740
1741 next = rb_next(&pos->rb_node);
1742 rb_erase(&pos->rb_node, machines);
1743 machine__delete(pos);
1744 }
1745}
1746
1747int machine__load_kallsyms(struct machine *machine, const char *filename,
1748 enum map_type type, symbol_filter_t filter)
1749{
1750 struct map *map = machine->vmlinux_maps[type];
1751 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
1752
1753 if (ret > 0) {
1754 dso__set_loaded(map->dso, type);
1755 /*
1756 * Since /proc/kallsyms will have multiple sessions for the
1757 * kernel, with modules between them, fixup the end of all
1758 * sections.
1759 */
1760 __map_groups__fixup_end(&machine->kmaps, type);
1761 }
1762
1763 return ret;
1764}
1765
1766int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
1767 symbol_filter_t filter)
1768{
1769 struct map *map = machine->vmlinux_maps[type];
1770 int ret = dso__load_vmlinux_path(map->dso, map, filter);
1771
1772 if (ret > 0) {
1773 dso__set_loaded(map->dso, type);
1774 map__reloc_vmlinux(map);
1775 }
1776
1777 return ret;
1778}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index de68f98b236d..b62ca37c4b77 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -16,8 +16,8 @@
16#ifdef LIBELF_SUPPORT 16#ifdef LIBELF_SUPPORT
17#include <libelf.h> 17#include <libelf.h>
18#include <gelf.h> 18#include <gelf.h>
19#include <elf.h>
20#endif 19#endif
20#include <elf.h>
21 21
22#include "dso.h" 22#include "dso.h"
23 23
@@ -96,7 +96,8 @@ struct symbol_conf {
96 initialized, 96 initialized,
97 kptr_restrict, 97 kptr_restrict,
98 annotate_asm_raw, 98 annotate_asm_raw,
99 annotate_src; 99 annotate_src,
100 event_group;
100 const char *vmlinux_name, 101 const char *vmlinux_name,
101 *kallsyms_name, 102 *kallsyms_name,
102 *source_prefix, 103 *source_prefix,
@@ -120,6 +121,8 @@ struct symbol_conf {
120}; 121};
121 122
122extern struct symbol_conf symbol_conf; 123extern struct symbol_conf symbol_conf;
124extern int vmlinux_path__nr_entries;
125extern char **vmlinux_path;
123 126
124static inline void *symbol__priv(struct symbol *sym) 127static inline void *symbol__priv(struct symbol *sym)
125{ 128{
@@ -223,6 +226,8 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
223size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); 226size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
224size_t symbol__fprintf(struct symbol *sym, FILE *fp); 227size_t symbol__fprintf(struct symbol *sym, FILE *fp);
225bool symbol_type__is_a(char symbol_type, enum map_type map_type); 228bool symbol_type__is_a(char symbol_type, enum map_type map_type);
229bool symbol__restricted_filename(const char *filename,
230 const char *restricted_filename);
226 231
227int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 232int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
228 struct symsrc *runtime_ss, symbol_filter_t filter, 233 struct symsrc *runtime_ss, symbol_filter_t filter,
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
index 48c6902e749f..f71e9eafe15a 100644
--- a/tools/perf/util/sysfs.c
+++ b/tools/perf/util/sysfs.c
@@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = {
8}; 8};
9 9
10static int sysfs_found; 10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX]; 11char sysfs_mountpoint[PATH_MAX + 1];
12 12
13static int sysfs_valid_mountpoint(const char *sysfs) 13static int sysfs_valid_mountpoint(const char *sysfs)
14{ 14{
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index df59623ac763..632e40e5ceca 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -54,10 +54,10 @@ int thread__comm_len(struct thread *self)
54 return self->comm_len; 54 return self->comm_len;
55} 55}
56 56
57static size_t thread__fprintf(struct thread *self, FILE *fp) 57size_t thread__fprintf(struct thread *thread, FILE *fp)
58{ 58{
59 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + 59 return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) +
60 map_groups__fprintf(&self->mg, verbose, fp); 60 map_groups__fprintf(&thread->mg, verbose, fp);
61} 61}
62 62
63void thread__insert_map(struct thread *self, struct map *map) 63void thread__insert_map(struct thread *self, struct map *map)
@@ -84,17 +84,3 @@ int thread__fork(struct thread *self, struct thread *parent)
84 return -ENOMEM; 84 return -ENOMEM;
85 return 0; 85 return 0;
86} 86}
87
88size_t machine__fprintf(struct machine *machine, FILE *fp)
89{
90 size_t ret = 0;
91 struct rb_node *nd;
92
93 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
94 struct thread *pos = rb_entry(nd, struct thread, rb_node);
95
96 ret += thread__fprintf(pos, fp);
97 }
98
99 return ret;
100}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index f2fa17caa7d5..5ad266403098 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -30,6 +30,7 @@ int thread__set_comm(struct thread *self, const char *comm);
30int thread__comm_len(struct thread *self); 30int thread__comm_len(struct thread *self);
31void thread__insert_map(struct thread *self, struct map *map); 31void thread__insert_map(struct thread *self, struct map *map);
32int thread__fork(struct thread *self, struct thread *parent); 32int thread__fork(struct thread *self, struct thread *parent);
33size_t thread__fprintf(struct thread *thread, FILE *fp);
33 34
34static inline struct map *thread__find_map(struct thread *self, 35static inline struct map *thread__find_map(struct thread *self,
35 enum map_type type, u64 addr) 36 enum map_type type, u64 addr)
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 884dde9b9bc1..54d37a4753c5 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -26,6 +26,8 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
26 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec = top->samples / top->delay_secs;
27 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
28 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 28 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
29 struct perf_record_opts *opts = &top->record_opts;
30 struct perf_target *target = &opts->target;
29 size_t ret = 0; 31 size_t ret = 0;
30 32
31 if (!perf_guest) { 33 if (!perf_guest) {
@@ -61,31 +63,31 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
61 struct perf_evsel *first = perf_evlist__first(top->evlist); 63 struct perf_evsel *first = perf_evlist__first(top->evlist);
62 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 64 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
63 (uint64_t)first->attr.sample_period, 65 (uint64_t)first->attr.sample_period,
64 top->freq ? "Hz" : ""); 66 opts->freq ? "Hz" : "");
65 } 67 }
66 68
67 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); 69 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
68 70
69 ret += SNPRINTF(bf + ret, size - ret, "], "); 71 ret += SNPRINTF(bf + ret, size - ret, "], ");
70 72
71 if (top->target.pid) 73 if (target->pid)
72 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", 74 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
73 top->target.pid); 75 target->pid);
74 else if (top->target.tid) 76 else if (target->tid)
75 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", 77 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
76 top->target.tid); 78 target->tid);
77 else if (top->target.uid_str != NULL) 79 else if (target->uid_str != NULL)
78 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", 80 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
79 top->target.uid_str); 81 target->uid_str);
80 else 82 else
81 ret += SNPRINTF(bf + ret, size - ret, " (all"); 83 ret += SNPRINTF(bf + ret, size - ret, " (all");
82 84
83 if (top->target.cpu_list) 85 if (target->cpu_list)
84 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 86 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
85 top->evlist->cpus->nr > 1 ? "s" : "", 87 top->evlist->cpus->nr > 1 ? "s" : "",
86 top->target.cpu_list); 88 target->cpu_list);
87 else { 89 else {
88 if (top->target.tid) 90 if (target->tid)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 91 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 92 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 93 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 86ff1b15059b..7ebf357dc9e1 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -14,7 +14,7 @@ struct perf_session;
14struct perf_top { 14struct perf_top {
15 struct perf_tool tool; 15 struct perf_tool tool;
16 struct perf_evlist *evlist; 16 struct perf_evlist *evlist;
17 struct perf_target target; 17 struct perf_record_opts record_opts;
18 /* 18 /*
19 * Symbols will be added here in perf_event__process_sample and will 19 * Symbols will be added here in perf_event__process_sample and will
20 * get out after decayed. 20 * get out after decayed.
@@ -24,24 +24,16 @@ struct perf_top {
24 u64 exact_samples; 24 u64 exact_samples;
25 u64 guest_us_samples, guest_kernel_samples; 25 u64 guest_us_samples, guest_kernel_samples;
26 int print_entries, count_filter, delay_secs; 26 int print_entries, count_filter, delay_secs;
27 int freq;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool use_tui, use_stdio; 28 bool use_tui, use_stdio;
30 bool sort_has_symbols; 29 bool sort_has_symbols;
31 bool dont_use_callchains;
32 bool kptr_restrict_warned; 30 bool kptr_restrict_warned;
33 bool vmlinux_warned; 31 bool vmlinux_warned;
34 bool inherit;
35 bool group;
36 bool sample_id_all_missing;
37 bool exclude_guest_missing;
38 bool dump_symtab; 32 bool dump_symtab;
39 struct hist_entry *sym_filter_entry; 33 struct hist_entry *sym_filter_entry;
40 struct perf_evsel *sym_evsel; 34 struct perf_evsel *sym_evsel;
41 struct perf_session *session; 35 struct perf_session *session;
42 struct winsize winsize; 36 struct winsize winsize;
43 unsigned int mmap_pages;
44 int default_interval;
45 int realtime_prio; 37 int realtime_prio;
46 int sym_pcnt_filter; 38 int sym_pcnt_filter;
47 const char *sym_filter; 39 const char *sym_filter;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 5906e8426cc7..805d1f52c5b4 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -12,6 +12,8 @@
12 */ 12 */
13unsigned int page_size; 13unsigned int page_size;
14 14
15bool test_attr__enabled;
16
15bool perf_host = true; 17bool perf_host = true;
16bool perf_guest = false; 18bool perf_guest = false;
17 19
@@ -218,3 +220,25 @@ void dump_stack(void)
218#else 220#else
219void dump_stack(void) {} 221void dump_stack(void) {}
220#endif 222#endif
223
224void get_term_dimensions(struct winsize *ws)
225{
226 char *s = getenv("LINES");
227
228 if (s != NULL) {
229 ws->ws_row = atoi(s);
230 s = getenv("COLUMNS");
231 if (s != NULL) {
232 ws->ws_col = atoi(s);
233 if (ws->ws_row && ws->ws_col)
234 return;
235 }
236 }
237#ifdef TIOCGWINSZ
238 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
239 ws->ws_row && ws->ws_col)
240 return;
241#endif
242 ws->ws_row = 25;
243 ws->ws_col = 80;
244}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c2330918110c..09b4c26b71aa 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -265,10 +265,14 @@ bool is_power_of_2(unsigned long n)
265size_t hex_width(u64 v); 265size_t hex_width(u64 v);
266int hex2u64(const char *ptr, u64 *val); 266int hex2u64(const char *ptr, u64 *val);
267 267
268char *ltrim(char *s);
268char *rtrim(char *s); 269char *rtrim(char *s);
269 270
270void dump_stack(void); 271void dump_stack(void);
271 272
272extern unsigned int page_size; 273extern unsigned int page_size;
273 274
275struct winsize;
276void get_term_dimensions(struct winsize *ws);
277
274#endif 278#endif