aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2010-03-01 02:55:20 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-03-01 02:55:20 -0500
commit35858adbfca13678af99fb31618ef4428d6dedb0 (patch)
tree3336feaa61324486945816cb52c347733e7c0821 /tools/perf/util
parent197d4db752e67160d79fed09968c2140376a80a3 (diff)
parent4b70858ba8d4537daf782defebe5f2ff80ccef2b (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/data_map.c96
-rw-r--r--tools/perf/util/data_map.h29
-rw-r--r--tools/perf/util/event.c142
-rw-r--r--tools/perf/util/event.h40
-rw-r--r--tools/perf/util/header.c2
-rw-r--r--tools/perf/util/hist.c518
-rw-r--r--tools/perf/util/hist.h55
-rw-r--r--tools/perf/util/map.c18
-rw-r--r--tools/perf/util/probe-event.c222
-rw-r--r--tools/perf/util/probe-event.h11
-rw-r--r--tools/perf/util/probe-finder.c4
-rw-r--r--tools/perf/util/probe-finder.h58
-rw-r--r--tools/perf/util/session.c84
-rw-r--r--tools/perf/util/session.h45
-rw-r--r--tools/perf/util/sort.c26
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/string.c25
-rw-r--r--tools/perf/util/string.h2
-rw-r--r--tools/perf/util/strlist.c6
-rw-r--r--tools/perf/util/strlist.h41
-rw-r--r--tools/perf/util/symbol.c144
-rw-r--r--tools/perf/util/symbol.h34
-rw-r--r--tools/perf/util/thread.c37
-rw-r--r--tools/perf/util/thread.h16
-rw-r--r--tools/perf/util/trace-event-perl.c42
-rw-r--r--tools/perf/util/trace-event.h2
26 files changed, 1291 insertions, 420 deletions
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index 6d46dda53a29..b557b836de3d 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -1,20 +1,17 @@
1#include "data_map.h"
2#include "symbol.h" 1#include "symbol.h"
3#include "util.h" 2#include "util.h"
4#include "debug.h" 3#include "debug.h"
4#include "thread.h"
5#include "session.h"
5 6
6 7static int process_event_stub(event_t *event __used,
7static struct perf_file_handler *curr_handler; 8 struct perf_session *session __used)
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int process_event_stub(event_t *event __used)
12{ 9{
13 dump_printf(": unhandled!\n"); 10 dump_printf(": unhandled!\n");
14 return 0; 11 return 0;
15} 12}
16 13
17void register_perf_file_handler(struct perf_file_handler *handler) 14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
18{ 15{
19 if (!handler->process_sample_event) 16 if (!handler->process_sample_event)
20 handler->process_sample_event = process_event_stub; 17 handler->process_sample_event = process_event_stub;
@@ -34,8 +31,6 @@ void register_perf_file_handler(struct perf_file_handler *handler)
34 handler->process_throttle_event = process_event_stub; 31 handler->process_throttle_event = process_event_stub;
35 if (!handler->process_unthrottle_event) 32 if (!handler->process_unthrottle_event)
36 handler->process_unthrottle_event = process_event_stub; 33 handler->process_unthrottle_event = process_event_stub;
37
38 curr_handler = handler;
39} 34}
40 35
41static const char *event__name[] = { 36static const char *event__name[] = {
@@ -61,8 +56,9 @@ void event__print_totals(void)
61 event__name[i], event__total[i]); 56 event__name[i], event__total[i]);
62} 57}
63 58
64static int 59static int process_event(event_t *event, struct perf_session *session,
65process_event(event_t *event, unsigned long offset, unsigned long head) 60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
66{ 62{
67 trace_event(event); 63 trace_event(event);
68 64
@@ -77,25 +73,25 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
77 73
78 switch (event->header.type) { 74 switch (event->header.type) {
79 case PERF_RECORD_SAMPLE: 75 case PERF_RECORD_SAMPLE:
80 return curr_handler->process_sample_event(event); 76 return ops->process_sample_event(event, session);
81 case PERF_RECORD_MMAP: 77 case PERF_RECORD_MMAP:
82 return curr_handler->process_mmap_event(event); 78 return ops->process_mmap_event(event, session);
83 case PERF_RECORD_COMM: 79 case PERF_RECORD_COMM:
84 return curr_handler->process_comm_event(event); 80 return ops->process_comm_event(event, session);
85 case PERF_RECORD_FORK: 81 case PERF_RECORD_FORK:
86 return curr_handler->process_fork_event(event); 82 return ops->process_fork_event(event, session);
87 case PERF_RECORD_EXIT: 83 case PERF_RECORD_EXIT:
88 return curr_handler->process_exit_event(event); 84 return ops->process_exit_event(event, session);
89 case PERF_RECORD_LOST: 85 case PERF_RECORD_LOST:
90 return curr_handler->process_lost_event(event); 86 return ops->process_lost_event(event, session);
91 case PERF_RECORD_READ: 87 case PERF_RECORD_READ:
92 return curr_handler->process_read_event(event); 88 return ops->process_read_event(event, session);
93 case PERF_RECORD_THROTTLE: 89 case PERF_RECORD_THROTTLE:
94 return curr_handler->process_throttle_event(event); 90 return ops->process_throttle_event(event, session);
95 case PERF_RECORD_UNTHROTTLE: 91 case PERF_RECORD_UNTHROTTLE:
96 return curr_handler->process_unthrottle_event(event); 92 return ops->process_unthrottle_event(event, session);
97 default: 93 default:
98 curr_handler->total_unknown++; 94 ops->total_unknown++;
99 return -1; 95 return -1;
100 } 96 }
101} 97}
@@ -129,44 +125,58 @@ out:
129 return err; 125 return err;
130} 126}
131 127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
132int perf_session__process_events(struct perf_session *self, 140int perf_session__process_events(struct perf_session *self,
133 int full_paths, int *cwdlen, char **cwd) 141 struct perf_event_ops *ops)
134{ 142{
135 int err; 143 int err;
136 unsigned long head, shift; 144 unsigned long head, shift;
137 unsigned long offset = 0; 145 unsigned long offset = 0;
138 size_t page_size; 146 size_t page_size;
139 u64 sample_type;
140 event_t *event; 147 event_t *event;
141 uint32_t size; 148 uint32_t size;
142 char *buf; 149 char *buf;
143 150
144 if (curr_handler == NULL) { 151 if (perf_session__register_idle_thread(self) == NULL)
145 pr_debug("Forgot to register perf file handler\n"); 152 return -ENOMEM;
146 return -EINVAL; 153
147 } 154 perf_event_ops__fill_defaults(ops);
148 155
149 page_size = getpagesize(); 156 page_size = getpagesize();
150 157
151 head = self->header.data_offset; 158 head = self->header.data_offset;
152 sample_type = perf_header__sample_type(&self->header); 159 self->sample_type = perf_header__sample_type(&self->header);
153 160
154 err = -EINVAL; 161 err = -EINVAL;
155 if (curr_handler->sample_type_check && 162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
156 curr_handler->sample_type_check(sample_type) < 0)
157 goto out_err; 163 goto out_err;
158 164
159 if (!full_paths) { 165 if (!ops->full_paths) {
160 if (getcwd(__cwd, sizeof(__cwd)) == NULL) { 166 char bf[PATH_MAX];
161 pr_err("failed to get the current directory\n"); 167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
162 err = -errno; 169 err = -errno;
170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
163 goto out_err; 172 goto out_err;
164 } 173 }
165 *cwd = __cwd; 174 self->cwd = strdup(bf);
166 *cwdlen = strlen(*cwd); 175 if (self->cwd == NULL) {
167 } else { 176 err = -ENOMEM;
168 *cwd = NULL; 177 goto out_getcwd_err;
169 *cwdlen = 0; 178 }
179 self->cwdlen = strlen(self->cwd);
170 } 180 }
171 181
172 shift = page_size * (head / page_size); 182 shift = page_size * (head / page_size);
@@ -174,7 +184,7 @@ int perf_session__process_events(struct perf_session *self,
174 head -= shift; 184 head -= shift;
175 185
176remap: 186remap:
177 buf = mmap(NULL, page_size * mmap_window, PROT_READ, 187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
178 MAP_SHARED, self->fd, offset); 188 MAP_SHARED, self->fd, offset);
179 if (buf == MAP_FAILED) { 189 if (buf == MAP_FAILED) {
180 pr_err("failed to mmap file\n"); 190 pr_err("failed to mmap file\n");
@@ -189,12 +199,12 @@ more:
189 if (!size) 199 if (!size)
190 size = 8; 200 size = 8;
191 201
192 if (head + event->header.size >= page_size * mmap_window) { 202 if (head + event->header.size >= page_size * self->mmap_window) {
193 int munmap_ret; 203 int munmap_ret;
194 204
195 shift = page_size * (head / page_size); 205 shift = page_size * (head / page_size);
196 206
197 munmap_ret = munmap(buf, page_size * mmap_window); 207 munmap_ret = munmap(buf, page_size * self->mmap_window);
198 assert(munmap_ret == 0); 208 assert(munmap_ret == 0);
199 209
200 offset += shift; 210 offset += shift;
@@ -209,7 +219,7 @@ more:
209 (void *)(long)event->header.size, 219 (void *)(long)event->header.size,
210 event->header.type); 220 event->header.type);
211 221
212 if (!size || process_event(event, offset, head) < 0) { 222 if (!size || process_event(event, self, ops, offset, head) < 0) {
213 223
214 dump_printf("%p [%p]: skipping unknown header type: %d\n", 224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
215 (void *)(offset + head), 225 (void *)(offset + head),
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
deleted file mode 100644
index 98c5b823388c..000000000000
--- a/tools/perf/util/data_map.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef __PERF_DATAMAP_H
2#define __PERF_DATAMAP_H
3
4#include "event.h"
5#include "header.h"
6#include "session.h"
7
8typedef int (*event_type_handler_t)(event_t *);
9
10struct perf_file_handler {
11 event_type_handler_t process_sample_event;
12 event_type_handler_t process_mmap_event;
13 event_type_handler_t process_comm_event;
14 event_type_handler_t process_fork_event;
15 event_type_handler_t process_exit_event;
16 event_type_handler_t process_lost_event;
17 event_type_handler_t process_read_event;
18 event_type_handler_t process_throttle_event;
19 event_type_handler_t process_unthrottle_event;
20 int (*sample_type_check)(u64 sample_type);
21 unsigned long total_unknown;
22};
23
24void register_perf_file_handler(struct perf_file_handler *handler);
25int perf_session__process_events(struct perf_session *self,
26 int full_paths, int *cwdlen, char **cwd);
27int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
28
29#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index ba0de90cd3d4..bb0fd6da2d56 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,11 +1,16 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "session.h"
5#include "sort.h"
4#include "string.h" 6#include "string.h"
7#include "strlist.h"
5#include "thread.h" 8#include "thread.h"
6 9
7static pid_t event__synthesize_comm(pid_t pid, int full, 10static pid_t event__synthesize_comm(pid_t pid, int full,
8 int (*process)(event_t *event)) 11 int (*process)(event_t *event,
12 struct perf_session *session),
13 struct perf_session *session)
9{ 14{
10 event_t ev; 15 event_t ev;
11 char filename[PATH_MAX]; 16 char filename[PATH_MAX];
@@ -54,7 +59,7 @@ out_race:
54 if (!full) { 59 if (!full) {
55 ev.comm.tid = pid; 60 ev.comm.tid = pid;
56 61
57 process(&ev); 62 process(&ev, session);
58 goto out_fclose; 63 goto out_fclose;
59 } 64 }
60 65
@@ -72,7 +77,7 @@ out_race:
72 77
73 ev.comm.tid = pid; 78 ev.comm.tid = pid;
74 79
75 process(&ev); 80 process(&ev, session);
76 } 81 }
77 closedir(tasks); 82 closedir(tasks);
78 83
@@ -86,7 +91,9 @@ out_failure:
86} 91}
87 92
88static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89 int (*process)(event_t *event)) 94 int (*process)(event_t *event,
95 struct perf_session *session),
96 struct perf_session *session)
90{ 97{
91 char filename[PATH_MAX]; 98 char filename[PATH_MAX];
92 FILE *fp; 99 FILE *fp;
@@ -141,7 +148,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
141 ev.mmap.pid = tgid; 148 ev.mmap.pid = tgid;
142 ev.mmap.tid = pid; 149 ev.mmap.tid = pid;
143 150
144 process(&ev); 151 process(&ev, session);
145 } 152 }
146 } 153 }
147 154
@@ -149,15 +156,20 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
149 return 0; 156 return 0;
150} 157}
151 158
152int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)) 159int event__synthesize_thread(pid_t pid,
160 int (*process)(event_t *event,
161 struct perf_session *session),
162 struct perf_session *session)
153{ 163{
154 pid_t tgid = event__synthesize_comm(pid, 1, process); 164 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
155 if (tgid == -1) 165 if (tgid == -1)
156 return -1; 166 return -1;
157 return event__synthesize_mmap_events(pid, tgid, process); 167 return event__synthesize_mmap_events(pid, tgid, process, session);
158} 168}
159 169
160void event__synthesize_threads(int (*process)(event_t *event)) 170void event__synthesize_threads(int (*process)(event_t *event,
171 struct perf_session *session),
172 struct perf_session *session)
161{ 173{
162 DIR *proc; 174 DIR *proc;
163 struct dirent dirent, *next; 175 struct dirent dirent, *next;
@@ -171,24 +183,47 @@ void event__synthesize_threads(int (*process)(event_t *event))
171 if (*end) /* only interested in proper numerical dirents */ 183 if (*end) /* only interested in proper numerical dirents */
172 continue; 184 continue;
173 185
174 event__synthesize_thread(pid, process); 186 event__synthesize_thread(pid, process, session);
175 } 187 }
176 188
177 closedir(proc); 189 closedir(proc);
178} 190}
179 191
180char *event__cwd; 192static void thread__comm_adjust(struct thread *self)
181int event__cwdlen; 193{
194 char *comm = self->comm;
182 195
183struct events_stats event__stats; 196 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
197 (!symbol_conf.comm_list ||
198 strlist__has_entry(symbol_conf.comm_list, comm))) {
199 unsigned int slen = strlen(comm);
184 200
185int event__process_comm(event_t *self) 201 if (slen > comms__col_width) {
202 comms__col_width = slen;
203 threads__col_width = slen + 6;
204 }
205 }
206}
207
208static int thread__set_comm_adjust(struct thread *self, const char *comm)
186{ 209{
187 struct thread *thread = threads__findnew(self->comm.pid); 210 int ret = thread__set_comm(self, comm);
211
212 if (ret)
213 return ret;
214
215 thread__comm_adjust(self);
216
217 return 0;
218}
219
220int event__process_comm(event_t *self, struct perf_session *session)
221{
222 struct thread *thread = perf_session__findnew(session, self->comm.pid);
188 223
189 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190 225
191 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) { 226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
192 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
193 return -1; 228 return -1;
194 } 229 }
@@ -196,18 +231,18 @@ int event__process_comm(event_t *self)
196 return 0; 231 return 0;
197} 232}
198 233
199int event__process_lost(event_t *self) 234int event__process_lost(event_t *self, struct perf_session *session)
200{ 235{
201 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
202 event__stats.lost += self->lost.lost; 237 session->events_stats.lost += self->lost.lost;
203 return 0; 238 return 0;
204} 239}
205 240
206int event__process_mmap(event_t *self) 241int event__process_mmap(event_t *self, struct perf_session *session)
207{ 242{
208 struct thread *thread = threads__findnew(self->mmap.pid); 243 struct thread *thread = perf_session__findnew(session, self->mmap.pid);
209 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 244 struct map *map = map__new(&self->mmap, MAP__FUNCTION,
210 event__cwd, event__cwdlen); 245 session->cwd, session->cwdlen);
211 246
212 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
213 self->mmap.pid, self->mmap.tid, 248 self->mmap.pid, self->mmap.tid,
@@ -224,10 +259,10 @@ int event__process_mmap(event_t *self)
224 return 0; 259 return 0;
225} 260}
226 261
227int event__process_task(event_t *self) 262int event__process_task(event_t *self, struct perf_session *session)
228{ 263{
229 struct thread *thread = threads__findnew(self->fork.pid); 264 struct thread *thread = perf_session__findnew(session, self->fork.pid);
230 struct thread *parent = threads__findnew(self->fork.ppid); 265 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
231 266
232 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
233 self->fork.ppid, self->fork.ptid); 268 self->fork.ppid, self->fork.ptid);
@@ -249,7 +284,8 @@ int event__process_task(event_t *self)
249 return 0; 284 return 0;
250} 285}
251 286
252void thread__find_addr_location(struct thread *self, u8 cpumode, 287void thread__find_addr_location(struct thread *self,
288 struct perf_session *session, u8 cpumode,
253 enum map_type type, u64 addr, 289 enum map_type type, u64 addr,
254 struct addr_location *al, 290 struct addr_location *al,
255 symbol_filter_t filter) 291 symbol_filter_t filter)
@@ -261,7 +297,7 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
261 297
262 if (cpumode & PERF_RECORD_MISC_KERNEL) { 298 if (cpumode & PERF_RECORD_MISC_KERNEL) {
263 al->level = 'k'; 299 al->level = 'k';
264 mg = kmaps; 300 mg = &session->kmaps;
265 } else if (cpumode & PERF_RECORD_MISC_USER) 301 } else if (cpumode & PERF_RECORD_MISC_USER)
266 al->level = '.'; 302 al->level = '.';
267 else { 303 else {
@@ -282,33 +318,73 @@ try_again:
282 * "[vdso]" dso, but for now lets use the old trick of looking 318 * "[vdso]" dso, but for now lets use the old trick of looking
283 * in the whole kernel symbol list. 319 * in the whole kernel symbol list.
284 */ 320 */
285 if ((long long)al->addr < 0 && mg != kmaps) { 321 if ((long long)al->addr < 0 && mg != &session->kmaps) {
286 mg = kmaps; 322 mg = &session->kmaps;
287 goto try_again; 323 goto try_again;
288 } 324 }
289 al->sym = NULL; 325 al->sym = NULL;
290 } else { 326 } else {
291 al->addr = al->map->map_ip(al->map, al->addr); 327 al->addr = al->map->map_ip(al->map, al->addr);
292 al->sym = map__find_symbol(al->map, al->addr, filter); 328 al->sym = map__find_symbol(al->map, session, al->addr, filter);
293 } 329 }
294} 330}
295 331
296int event__preprocess_sample(const event_t *self, struct addr_location *al, 332static void dso__calc_col_width(struct dso *self)
297 symbol_filter_t filter) 333{
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name);
338 if (slen > dsos__col_width)
339 dsos__col_width = slen;
340 }
341
342 self->slen_calculated = 1;
343}
344
345int event__preprocess_sample(const event_t *self, struct perf_session *session,
346 struct addr_location *al, symbol_filter_t filter)
298{ 347{
299 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 348 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
300 struct thread *thread = threads__findnew(self->ip.pid); 349 struct thread *thread = perf_session__findnew(session, self->ip.pid);
301 350
302 if (thread == NULL) 351 if (thread == NULL)
303 return -1; 352 return -1;
304 353
354 if (symbol_conf.comm_list &&
355 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
356 goto out_filtered;
357
305 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
306 359
307 thread__find_addr_location(thread, cpumode, MAP__FUNCTION, 360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
308 self->ip.ip, al, filter); 361 self->ip.ip, al, filter);
309 dump_printf(" ...... dso: %s\n", 362 dump_printf(" ...... dso: %s\n",
310 al->map ? al->map->dso->long_name : 363 al->map ? al->map->dso->long_name :
311 al->level == 'H' ? "[hypervisor]" : "<not found>"); 364 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /*
366 * We have to do this here as we may have a dso with no symbol hit that
367 * has a name longer than the ones with symbols sampled.
368 */
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated)
370 dso__calc_col_width(al->map->dso);
371
372 if (symbol_conf.dso_list &&
373 (!al->map || !al->map->dso ||
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) ||
375 (al->map->dso->short_name != al->map->dso->long_name &&
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name)))))
377 goto out_filtered;
378
379 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered;
382
383 al->filtered = false;
384 return 0;
385
386out_filtered:
387 al->filtered = true;
312 return 0; 388 return 0;
313} 389}
314 390
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 51a96c2effde..690a96d0467c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -95,8 +95,8 @@ typedef union event_union {
95} event_t; 95} event_t;
96 96
97struct events_stats { 97struct events_stats {
98 unsigned long total; 98 u64 total;
99 unsigned long lost; 99 u64 lost;
100}; 100};
101 101
102void event__print_totals(void); 102void event__print_totals(void);
@@ -149,29 +149,35 @@ void map__delete(struct map *self);
149struct map *map__clone(struct map *self); 149struct map *map__clone(struct map *self);
150int map__overlap(struct map *l, struct map *r); 150int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
152struct symbol *map__find_symbol(struct map *self, u64 addr, 152
153 symbol_filter_t filter); 153struct perf_session;
154
155int map__load(struct map *self, struct perf_session *session,
156 symbol_filter_t filter);
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
158 u64 addr, symbol_filter_t filter);
154struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
155 symbol_filter_t filter); 161 symbol_filter_t filter);
156void map__fixup_start(struct map *self); 162void map__fixup_start(struct map *self);
157void map__fixup_end(struct map *self); 163void map__fixup_end(struct map *self);
158 164
159int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); 165int event__synthesize_thread(pid_t pid,
160void event__synthesize_threads(int (*process)(event_t *event)); 166 int (*process)(event_t *event,
161 167 struct perf_session *session),
162extern char *event__cwd; 168 struct perf_session *session);
163extern int event__cwdlen; 169void event__synthesize_threads(int (*process)(event_t *event,
164extern struct events_stats event__stats; 170 struct perf_session *session),
165extern unsigned long event__total[PERF_RECORD_MAX]; 171 struct perf_session *session);
166 172
167int event__process_comm(event_t *self); 173int event__process_comm(event_t *self, struct perf_session *session);
168int event__process_lost(event_t *self); 174int event__process_lost(event_t *self, struct perf_session *session);
169int event__process_mmap(event_t *self); 175int event__process_mmap(event_t *self, struct perf_session *session);
170int event__process_task(event_t *self); 176int event__process_task(event_t *self, struct perf_session *session);
171 177
172struct addr_location; 178struct addr_location;
173int event__preprocess_sample(const event_t *self, struct addr_location *al, 179int event__preprocess_sample(const event_t *self, struct perf_session *session,
174 symbol_filter_t filter); 180 struct addr_location *al, symbol_filter_t filter);
175int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 181int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
176 182
177#endif /* __PERF_RECORD_H */ 183#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f2e8d8715111..8a0bca55106f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -8,8 +8,8 @@
8#include "header.h" 8#include "header.h"
9#include "../perf.h" 9#include "../perf.h"
10#include "trace-event.h" 10#include "trace-event.h"
11#include "session.h"
11#include "symbol.h" 12#include "symbol.h"
12#include "data_map.h"
13#include "debug.h" 13#include "debug.h"
14 14
15/* 15/*
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 0ebf6ee16caa..e8daf5ca6fd2 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,9 +1,7 @@
1#include "hist.h" 1#include "hist.h"
2 2#include "session.h"
3struct rb_root hist; 3#include "sort.h"
4struct rb_root collapse_hists; 4#include <math.h>
5struct rb_root output_hists;
6int callchain;
7 5
8struct callchain_param callchain_param = { 6struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL, 7 .mode = CHAIN_GRAPH_REL,
@@ -14,11 +12,12 @@ struct callchain_param callchain_param = {
14 * histogram, sorted on item, collects counts 12 * histogram, sorted on item, collects counts
15 */ 13 */
16 14
17struct hist_entry *__hist_entry__add(struct addr_location *al, 15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
18 struct symbol *sym_parent, 16 struct addr_location *al,
19 u64 count, bool *hit) 17 struct symbol *sym_parent,
18 u64 count, bool *hit)
20{ 19{
21 struct rb_node **p = &hist.rb_node; 20 struct rb_node **p = &self->hists.rb_node;
22 struct rb_node *parent = NULL; 21 struct rb_node *parent = NULL;
23 struct hist_entry *he; 22 struct hist_entry *he;
24 struct hist_entry entry = { 23 struct hist_entry entry = {
@@ -54,7 +53,7 @@ struct hist_entry *__hist_entry__add(struct addr_location *al,
54 return NULL; 53 return NULL;
55 *he = entry; 54 *he = entry;
56 rb_link_node(&he->rb_node, parent, p); 55 rb_link_node(&he->rb_node, parent, p);
57 rb_insert_color(&he->rb_node, &hist); 56 rb_insert_color(&he->rb_node, &self->hists);
58 *hit = false; 57 *hit = false;
59 return he; 58 return he;
60} 59}
@@ -102,9 +101,9 @@ void hist_entry__free(struct hist_entry *he)
102 * collapse the histogram 101 * collapse the histogram
103 */ 102 */
104 103
105void collapse__insert_entry(struct hist_entry *he) 104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
106{ 105{
107 struct rb_node **p = &collapse_hists.rb_node; 106 struct rb_node **p = &root->rb_node;
108 struct rb_node *parent = NULL; 107 struct rb_node *parent = NULL;
109 struct hist_entry *iter; 108 struct hist_entry *iter;
110 int64_t cmp; 109 int64_t cmp;
@@ -128,38 +127,45 @@ void collapse__insert_entry(struct hist_entry *he)
128 } 127 }
129 128
130 rb_link_node(&he->rb_node, parent, p); 129 rb_link_node(&he->rb_node, parent, p);
131 rb_insert_color(&he->rb_node, &collapse_hists); 130 rb_insert_color(&he->rb_node, root);
132} 131}
133 132
134void collapse__resort(void) 133void perf_session__collapse_resort(struct perf_session *self)
135{ 134{
135 struct rb_root tmp;
136 struct rb_node *next; 136 struct rb_node *next;
137 struct hist_entry *n; 137 struct hist_entry *n;
138 138
139 if (!sort__need_collapse) 139 if (!sort__need_collapse)
140 return; 140 return;
141 141
142 next = rb_first(&hist); 142 tmp = RB_ROOT;
143 next = rb_first(&self->hists);
144
143 while (next) { 145 while (next) {
144 n = rb_entry(next, struct hist_entry, rb_node); 146 n = rb_entry(next, struct hist_entry, rb_node);
145 next = rb_next(&n->rb_node); 147 next = rb_next(&n->rb_node);
146 148
147 rb_erase(&n->rb_node, &hist); 149 rb_erase(&n->rb_node, &self->hists);
148 collapse__insert_entry(n); 150 collapse__insert_entry(&tmp, n);
149 } 151 }
152
153 self->hists = tmp;
150} 154}
151 155
152/* 156/*
153 * reverse the map, sort on count. 157 * reverse the map, sort on count.
154 */ 158 */
155 159
156void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits) 160static void perf_session__insert_output_hist_entry(struct rb_root *root,
161 struct hist_entry *he,
162 u64 min_callchain_hits)
157{ 163{
158 struct rb_node **p = &output_hists.rb_node; 164 struct rb_node **p = &root->rb_node;
159 struct rb_node *parent = NULL; 165 struct rb_node *parent = NULL;
160 struct hist_entry *iter; 166 struct hist_entry *iter;
161 167
162 if (callchain) 168 if (symbol_conf.use_callchain)
163 callchain_param.sort(&he->sorted_chain, &he->callchain, 169 callchain_param.sort(&he->sorted_chain, &he->callchain,
164 min_callchain_hits, &callchain_param); 170 min_callchain_hits, &callchain_param);
165 171
@@ -174,29 +180,483 @@ void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
174 } 180 }
175 181
176 rb_link_node(&he->rb_node, parent, p); 182 rb_link_node(&he->rb_node, parent, p);
177 rb_insert_color(&he->rb_node, &output_hists); 183 rb_insert_color(&he->rb_node, root);
178} 184}
179 185
180void output__resort(u64 total_samples) 186void perf_session__output_resort(struct perf_session *self, u64 total_samples)
181{ 187{
188 struct rb_root tmp;
182 struct rb_node *next; 189 struct rb_node *next;
183 struct hist_entry *n; 190 struct hist_entry *n;
184 struct rb_root *tree = &hist;
185 u64 min_callchain_hits; 191 u64 min_callchain_hits;
186 192
187 min_callchain_hits = 193 min_callchain_hits =
188 total_samples * (callchain_param.min_percent / 100); 194 total_samples * (callchain_param.min_percent / 100);
189 195
190 if (sort__need_collapse) 196 tmp = RB_ROOT;
191 tree = &collapse_hists; 197 next = rb_first(&self->hists);
192
193 next = rb_first(tree);
194 198
195 while (next) { 199 while (next) {
196 n = rb_entry(next, struct hist_entry, rb_node); 200 n = rb_entry(next, struct hist_entry, rb_node);
197 next = rb_next(&n->rb_node); 201 next = rb_next(&n->rb_node);
198 202
199 rb_erase(&n->rb_node, tree); 203 rb_erase(&n->rb_node, &self->hists);
200 output__insert_entry(n, min_callchain_hits); 204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits);
206 }
207
208 self->hists = tmp;
209}
210
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
212{
213 int i;
214 int ret = fprintf(fp, " ");
215
216 for (i = 0; i < left_margin; i++)
217 ret += fprintf(fp, " ");
218
219 return ret;
220}
221
222static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
223 int left_margin)
224{
225 int i;
226 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
227
228 for (i = 0; i < depth; i++)
229 if (depth_mask & (1 << i))
230 ret += fprintf(fp, "| ");
231 else
232 ret += fprintf(fp, " ");
233
234 ret += fprintf(fp, "\n");
235
236 return ret;
237}
238
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count,
241 u64 total_samples, int hits,
242 int left_margin)
243{
244 int i;
245 size_t ret = 0;
246
247 ret += callchain__fprintf_left_margin(fp, left_margin);
248 for (i = 0; i < depth; i++) {
249 if (depth_mask & (1 << i))
250 ret += fprintf(fp, "|");
251 else
252 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) {
254 double percent;
255
256 percent = hits * 100.0 / total_samples;
257 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
258 } else
259 ret += fprintf(fp, "%s", " ");
260 }
261 if (chain->sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name);
263 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265
266 return ret;
267}
268
269static struct symbol *rem_sq_bracket;
270static struct callchain_list rem_hits;
271
272static void init_rem_hits(void)
273{
274 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
275 if (!rem_sq_bracket) {
276 fprintf(stderr, "Not enough memory to display remaining hits\n");
277 return;
278 }
279
280 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket;
282}
283
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
285 u64 total_samples, int depth,
286 int depth_mask, int left_margin)
287{
288 struct rb_node *node, *next;
289 struct callchain_node *child;
290 struct callchain_list *chain;
291 int new_depth_mask = depth_mask;
292 u64 new_total;
293 u64 remaining;
294 size_t ret = 0;
295 int i;
296
297 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit;
299 else
300 new_total = total_samples;
301
302 remaining = new_total;
303
304 node = rb_first(&self->rb_root);
305 while (node) {
306 u64 cumul;
307
308 child = rb_entry(node, struct callchain_node, rb_node);
309 cumul = cumul_hits(child);
310 remaining -= cumul;
311
312 /*
313 * The depth mask manages the output of pipes that show
314 * the depth. We don't want to keep the pipes of the current
315 * level for the last child of this depth.
316 * Except if we have remaining filtered hits. They will
317 * supersede the last child
318 */
319 next = rb_next(node);
320 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
321 new_depth_mask &= ~(1 << (depth - 1));
322
323 /*
324 * But we keep the older depth mask for the line seperator
325 * to keep the level link until we reach the last child
326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin);
329 i = 0;
330 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++,
335 new_total,
336 cumul,
337 left_margin);
338 }
339 ret += __callchain__fprintf_graph(fp, child, new_total,
340 depth + 1,
341 new_depth_mask | (1 << depth),
342 left_margin);
343 node = next;
344 }
345
346 if (callchain_param.mode == CHAIN_GRAPH_REL &&
347 remaining && remaining != new_total) {
348
349 if (!rem_sq_bracket)
350 return ret;
351
352 new_depth_mask &= ~(1 << (depth - 1));
353
354 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
355 new_depth_mask, 0, new_total,
356 remaining, left_margin);
357 }
358
359 return ret;
360}
361
362static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
363 u64 total_samples, int left_margin)
364{
365 struct callchain_list *chain;
366 bool printed = false;
367 int i = 0;
368 int ret = 0;
369
370 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue;
376
377 if (!printed) {
378 ret += callchain__fprintf_left_margin(fp, left_margin);
379 ret += fprintf(fp, "|\n");
380 ret += callchain__fprintf_left_margin(fp, left_margin);
381 ret += fprintf(fp, "---");
382
383 left_margin += 3;
384 printed = true;
385 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin);
387
388 if (chain->sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name);
390 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
392 }
393
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
395
396 return ret;
397}
398
399static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
400 u64 total_samples)
401{
402 struct callchain_list *chain;
403 size_t ret = 0;
404
405 if (!self)
406 return 0;
407
408 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
409
410
411 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue;
414 if (chain->sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name);
416 else
417 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip);
419 }
420
421 return ret;
422}
423
424static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
425 u64 total_samples, int left_margin)
426{
427 struct rb_node *rb_node;
428 struct callchain_node *chain;
429 size_t ret = 0;
430
431 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) {
433 double percent;
434
435 chain = rb_entry(rb_node, struct callchain_node, rb_node);
436 percent = chain->hit * 100.0 / total_samples;
437 switch (callchain_param.mode) {
438 case CHAIN_FLAT:
439 ret += percent_color_fprintf(fp, " %6.2f%%\n",
440 percent);
441 ret += callchain__fprintf_flat(fp, chain, total_samples);
442 break;
443 case CHAIN_GRAPH_ABS: /* Falldown */
444 case CHAIN_GRAPH_REL:
445 ret += callchain__fprintf_graph(fp, chain, total_samples,
446 left_margin);
447 case CHAIN_NONE:
448 default:
449 break;
450 }
451 ret += fprintf(fp, "\n");
452 rb_node = rb_next(rb_node);
453 }
454
455 return ret;
456}
457
458static size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *session,
460 struct perf_session *pair_session,
461 bool show_displacement,
462 long displacement, FILE *fp)
463{
464 struct sort_entry *se;
465 u64 count, total;
466 const char *sep = symbol_conf.field_sep;
467 size_t ret;
468
469 if (symbol_conf.exclude_other && !self->parent)
470 return 0;
471
472 if (pair_session) {
473 count = self->pair ? self->pair->count : 0;
474 total = pair_session->events_stats.total;
475 } else {
476 count = self->count;
477 total = session->events_stats.total;
478 }
479
480 if (total)
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%",
482 (count * 100.0) / total);
483 else
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count);
485
486 if (symbol_conf.show_nr_samples) {
487 if (sep)
488 fprintf(fp, "%c%lld", *sep, count);
489 else
490 fprintf(fp, "%11lld", count);
491 }
492
493 if (pair_session) {
494 char bf[32];
495 double old_percent = 0, new_percent = 0, diff;
496
497 if (total > 0)
498 old_percent = (count * 100.0) / total;
499 if (session->events_stats.total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total;
501
502 diff = new_percent - old_percent;
503
504 if (fabs(diff) >= 0.01)
505 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
506 else
507 snprintf(bf, sizeof(bf), " ");
508
509 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf);
511 else
512 ret += fprintf(fp, "%11.11s", bf);
513
514 if (show_displacement) {
515 if (displacement)
516 snprintf(bf, sizeof(bf), "%+4ld", displacement);
517 else
518 snprintf(bf, sizeof(bf), " ");
519
520 if (sep)
521 fprintf(fp, "%c%s", *sep, bf);
522 else
523 fprintf(fp, "%6.6s", bf);
524 }
525 }
526
527 list_for_each_entry(se, &hist_entry__sort_list, list) {
528 if (se->elide)
529 continue;
530
531 fprintf(fp, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0);
533 }
534
535 ret += fprintf(fp, "\n");
536
537 if (symbol_conf.use_callchain) {
538 int left_margin = 0;
539
540 if (sort__first_dimension == SORT_COMM) {
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
542 list);
543 left_margin = se->width ? *se->width : 0;
544 left_margin -= thread__comm_len(self->thread);
545 }
546
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total,
548 left_margin);
549 }
550
551 return ret;
552}
553
554size_t perf_session__fprintf_hists(struct perf_session *self,
555 struct perf_session *pair,
556 bool show_displacement, FILE *fp)
557{
558 struct sort_entry *se;
559 struct rb_node *nd;
560 size_t ret = 0;
561 unsigned long position = 1;
562 long displacement = 0;
563 unsigned int width;
564 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str;
566
567 init_rem_hits();
568
569 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
570
571 if (symbol_conf.show_nr_samples) {
572 if (sep)
573 fprintf(fp, "%cSamples", *sep);
574 else
575 fputs(" Samples ", fp);
576 }
577
578 if (pair) {
579 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep);
581 else
582 ret += fprintf(fp, " Delta ");
583
584 if (show_displacement) {
585 if (sep)
586 ret += fprintf(fp, "%cDisplacement", *sep);
587 else
588 ret += fprintf(fp, " Displ");
589 }
590 }
591
592 list_for_each_entry(se, &hist_entry__sort_list, list) {
593 if (se->elide)
594 continue;
595 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header);
597 continue;
598 }
599 width = strlen(se->header);
600 if (se->width) {
601 if (symbol_conf.col_width_list_str) {
602 if (col_width) {
603 *se->width = atoi(col_width);
604 col_width = strchr(col_width, ',');
605 if (col_width)
606 ++col_width;
607 }
608 }
609 width = *se->width = max(*se->width, width);
610 }
611 fprintf(fp, " %*s", width, se->header);
612 }
613 fprintf(fp, "\n");
614
615 if (sep)
616 goto print_entries;
617
618 fprintf(fp, "# ........");
619 if (symbol_conf.show_nr_samples)
620 fprintf(fp, " ..........");
621 if (pair) {
622 fprintf(fp, " ..........");
623 if (show_displacement)
624 fprintf(fp, " .....");
625 }
626 list_for_each_entry(se, &hist_entry__sort_list, list) {
627 unsigned int i;
628
629 if (se->elide)
630 continue;
631
632 fprintf(fp, " ");
633 if (se->width)
634 width = *se->width;
635 else
636 width = strlen(se->header);
637 for (i = 0; i < width; i++)
638 fprintf(fp, ".");
639 }
640
641 fprintf(fp, "\n#\n");
642
643print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646
647 if (show_displacement) {
648 if (h->pair != NULL)
649 displacement = ((long)h->pair->position -
650 (long)position);
651 else
652 displacement = 0;
653 ++position;
654 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement,
656 displacement, fp);
201 } 657 }
658
659 free(rem_sq_bracket);
660
661 return ret;
202} 662}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3020db0c9292..e5f99b24048b 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -1,50 +1,27 @@
1#ifndef __PERF_HIST_H 1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3#include "../builtin.h"
4 3
5#include "util.h" 4#include <linux/types.h>
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h" 5#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23 6
24#include "thread.h"
25#include "sort.h"
26
27extern struct rb_root hist;
28extern struct rb_root collapse_hists;
29extern struct rb_root output_hists;
30extern int callchain;
31extern struct callchain_param callchain_param; 7extern struct callchain_param callchain_param;
32extern unsigned long total;
33extern unsigned long total_mmap;
34extern unsigned long total_comm;
35extern unsigned long total_fork;
36extern unsigned long total_unknown;
37extern unsigned long total_lost;
38 8
39struct hist_entry *__hist_entry__add(struct addr_location *al, 9struct perf_session;
40 struct symbol *parent, 10struct hist_entry;
41 u64 count, bool *hit); 11struct addr_location;
12struct symbol;
13
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
15 struct addr_location *al,
16 struct symbol *parent,
17 u64 count, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *); 20void hist_entry__free(struct hist_entry *);
45extern void collapse__insert_entry(struct hist_entry *);
46extern void collapse__resort(void);
47extern void output__insert_entry(struct hist_entry *, u64);
48extern void output__resort(u64);
49 21
22void perf_session__output_resort(struct perf_session *self, u64 total_samples);
23void perf_session__collapse_resort(struct perf_session *self);
24size_t perf_session__fprintf_hists(struct perf_session *self,
25 struct perf_session *pair,
26 bool show_displacement, FILE *fp);
50#endif /* __PERF_HIST_H */ 27#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 76bdca640a9b..c4d55a0da2ea 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -104,11 +104,16 @@ void map__fixup_end(struct map *self)
104 104
105#define DSO__DELETED "(deleted)" 105#define DSO__DELETED "(deleted)"
106 106
107static int map__load(struct map *self, symbol_filter_t filter) 107int map__load(struct map *self, struct perf_session *session,
108 symbol_filter_t filter)
108{ 109{
109 const char *name = self->dso->long_name; 110 const char *name = self->dso->long_name;
110 int nr = dso__load(self->dso, self, filter); 111 int nr;
111 112
113 if (dso__loaded(self->dso, self->type))
114 return 0;
115
116 nr = dso__load(self->dso, self, session, filter);
112 if (nr < 0) { 117 if (nr < 0) {
113 if (self->dso->has_build_id) { 118 if (self->dso->has_build_id) {
114 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 119 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -143,19 +148,20 @@ static int map__load(struct map *self, symbol_filter_t filter)
143 return 0; 148 return 0;
144} 149}
145 150
146struct symbol *map__find_symbol(struct map *self, u64 addr, 151struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
147 symbol_filter_t filter) 152 u64 addr, symbol_filter_t filter)
148{ 153{
149 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0) 154 if (map__load(self, session, filter) < 0)
150 return NULL; 155 return NULL;
151 156
152 return dso__find_symbol(self->dso, self->type, addr); 157 return dso__find_symbol(self->dso, self->type, addr);
153} 158}
154 159
155struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 160struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
156 symbol_filter_t filter) 162 symbol_filter_t filter)
157{ 163{
158 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0) 164 if (map__load(self, session, filter) < 0)
159 return NULL; 165 return NULL;
160 166
161 if (!dso__sorted_by_name(self->dso, self->type)) 167 if (!dso__sorted_by_name(self->dso, self->type))
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d14a4585bcaf..29465d440043 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -62,6 +62,18 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
62 return ret; 62 return ret;
63} 63}
64 64
65/* Check the name is good for event/group */
66static bool check_event_name(const char *name)
67{
68 if (!isalpha(*name) && *name != '_')
69 return false;
70 while (*++name != '\0') {
71 if (!isalpha(*name) && !isdigit(*name) && *name != '_')
72 return false;
73 }
74 return true;
75}
76
65/* Parse probepoint definition. */ 77/* Parse probepoint definition. */
66static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
67{ 79{
@@ -69,10 +81,26 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
69 char c, nc = 0; 81 char c, nc = 0;
70 /* 82 /*
71 * <Syntax> 83 * <Syntax>
72 * perf probe SRC:LN 84 * perf probe [EVENT=]SRC:LN
73 * perf probe FUNC[+OFFS|%return][@SRC] 85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
86 *
87 * TODO:Group name support
74 */ 88 */
75 89
90 ptr = strchr(arg, '=');
91 if (ptr) { /* Event name */
92 *ptr = '\0';
93 tmp = ptr + 1;
94 ptr = strchr(arg, ':');
95 if (ptr) /* Group name is not supported yet. */
96 semantic_error("Group name is not supported yet.");
97 if (!check_event_name(arg))
98 semantic_error("%s is bad for event name -it must "
99 "follow C symbol-naming rule.", arg);
100 pp->event = strdup(arg);
101 arg = tmp;
102 }
103
76 ptr = strpbrk(arg, ":+@%"); 104 ptr = strpbrk(arg, ":+@%");
77 if (ptr) { 105 if (ptr) {
78 nc = *ptr; 106 nc = *ptr;
@@ -150,10 +178,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
150} 178}
151 179
152/* Parse perf-probe event definition */ 180/* Parse perf-probe event definition */
153int parse_perf_probe_event(const char *str, struct probe_point *pp) 181void parse_perf_probe_event(const char *str, struct probe_point *pp,
182 bool *need_dwarf)
154{ 183{
155 char **argv; 184 char **argv;
156 int argc, i, need_dwarf = 0; 185 int argc, i;
186
187 *need_dwarf = false;
157 188
158 argv = argv_split(str, &argc); 189 argv = argv_split(str, &argc);
159 if (!argv) 190 if (!argv)
@@ -164,7 +195,7 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
164 /* Parse probe point */ 195 /* Parse probe point */
165 parse_perf_probe_probepoint(argv[0], pp); 196 parse_perf_probe_probepoint(argv[0], pp);
166 if (pp->file || pp->line) 197 if (pp->file || pp->line)
167 need_dwarf = 1; 198 *need_dwarf = true;
168 199
169 /* Copy arguments and ensure return probe has no C argument */ 200 /* Copy arguments and ensure return probe has no C argument */
170 pp->nr_args = argc - 1; 201 pp->nr_args = argc - 1;
@@ -177,17 +208,15 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
177 if (pp->retprobe) 208 if (pp->retprobe)
178 semantic_error("You can't specify local" 209 semantic_error("You can't specify local"
179 " variable for kretprobe"); 210 " variable for kretprobe");
180 need_dwarf = 1; 211 *need_dwarf = true;
181 } 212 }
182 } 213 }
183 214
184 argv_free(argv); 215 argv_free(argv);
185 return need_dwarf;
186} 216}
187 217
188/* Parse kprobe_events event into struct probe_point */ 218/* Parse kprobe_events event into struct probe_point */
189void parse_trace_kprobe_event(const char *str, char **group, char **event, 219void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
190 struct probe_point *pp)
191{ 220{
192 char pr; 221 char pr;
193 char *p; 222 char *p;
@@ -203,18 +232,17 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
203 232
204 /* Scan event and group name. */ 233 /* Scan event and group name. */
205 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
206 &pr, (float *)(void *)group, (float *)(void *)event); 235 &pr, (float *)(void *)&pp->group,
236 (float *)(void *)&pp->event);
207 if (ret != 3) 237 if (ret != 3)
208 semantic_error("Failed to parse event name: %s", argv[0]); 238 semantic_error("Failed to parse event name: %s", argv[0]);
209 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr); 239 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
210
211 if (!pp)
212 goto end;
213 240
214 pp->retprobe = (pr == 'r'); 241 pp->retprobe = (pr == 'r');
215 242
216 /* Scan function name and offset */ 243 /* Scan function name and offset */
217 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset); 244 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
245 &pp->offset);
218 if (ret == 1) 246 if (ret == 1)
219 pp->offset = 0; 247 pp->offset = 0;
220 248
@@ -233,15 +261,15 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
233 die("Failed to copy argument."); 261 die("Failed to copy argument.");
234 } 262 }
235 263
236end:
237 argv_free(argv); 264 argv_free(argv);
238} 265}
239 266
240int synthesize_perf_probe_event(struct probe_point *pp) 267/* Synthesize only probe point (not argument) */
268int synthesize_perf_probe_point(struct probe_point *pp)
241{ 269{
242 char *buf; 270 char *buf;
243 char offs[64] = "", line[64] = ""; 271 char offs[64] = "", line[64] = "";
244 int i, len, ret; 272 int ret;
245 273
246 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 274 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
247 if (!buf) 275 if (!buf)
@@ -262,10 +290,24 @@ int synthesize_perf_probe_event(struct probe_point *pp)
262 offs, pp->retprobe ? "%return" : "", line); 290 offs, pp->retprobe ? "%return" : "", line);
263 else 291 else
264 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
265 if (ret <= 0) 293 if (ret <= 0) {
266 goto error; 294error:
267 len = ret; 295 free(pp->probes[0]);
296 pp->probes[0] = NULL;
297 }
298 return ret;
299}
300
301int synthesize_perf_probe_event(struct probe_point *pp)
302{
303 char *buf;
304 int i, len, ret;
305
306 len = synthesize_perf_probe_point(pp);
307 if (len < 0)
308 return 0;
268 309
310 buf = pp->probes[0];
269 for (i = 0; i < pp->nr_args; i++) { 311 for (i = 0; i < pp->nr_args; i++) {
270 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
271 pp->args[i]); 313 pp->args[i]);
@@ -278,6 +320,7 @@ int synthesize_perf_probe_event(struct probe_point *pp)
278 return pp->found; 320 return pp->found;
279error: 321error:
280 free(pp->probes[0]); 322 free(pp->probes[0]);
323 pp->probes[0] = NULL;
281 324
282 return ret; 325 return ret;
283} 326}
@@ -307,6 +350,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
307 return pp->found; 350 return pp->found;
308error: 351error:
309 free(pp->probes[0]); 352 free(pp->probes[0]);
353 pp->probes[0] = NULL;
310 354
311 return ret; 355 return ret;
312} 356}
@@ -366,6 +410,10 @@ static void clear_probe_point(struct probe_point *pp)
366{ 410{
367 int i; 411 int i;
368 412
413 if (pp->event)
414 free(pp->event);
415 if (pp->group)
416 free(pp->group);
369 if (pp->function) 417 if (pp->function)
370 free(pp->function); 418 free(pp->function);
371 if (pp->file) 419 if (pp->file)
@@ -380,13 +428,15 @@ static void clear_probe_point(struct probe_point *pp)
380} 428}
381 429
382/* Show an event */ 430/* Show an event */
383static void show_perf_probe_event(const char *group, const char *event, 431static void show_perf_probe_event(const char *event, const char *place,
384 const char *place, struct probe_point *pp) 432 struct probe_point *pp)
385{ 433{
386 int i; 434 int i, ret;
387 char buf[128]; 435 char buf[128];
388 436
389 e_snprintf(buf, 128, "%s:%s", group, event); 437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
438 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret));
390 printf(" %-40s (on %s", buf, place); 440 printf(" %-40s (on %s", buf, place);
391 441
392 if (pp->nr_args > 0) { 442 if (pp->nr_args > 0) {
@@ -400,9 +450,7 @@ static void show_perf_probe_event(const char *group, const char *event,
400/* List up current perf-probe events */ 450/* List up current perf-probe events */
401void show_perf_probe_events(void) 451void show_perf_probe_events(void)
402{ 452{
403 unsigned int i; 453 int fd;
404 int fd, nr;
405 char *group, *event;
406 struct probe_point pp; 454 struct probe_point pp;
407 struct strlist *rawlist; 455 struct strlist *rawlist;
408 struct str_node *ent; 456 struct str_node *ent;
@@ -411,18 +459,12 @@ void show_perf_probe_events(void)
411 rawlist = get_trace_kprobe_event_rawlist(fd); 459 rawlist = get_trace_kprobe_event_rawlist(fd);
412 close(fd); 460 close(fd);
413 461
414 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 462 strlist__for_each(ent, rawlist) {
415 ent = strlist__entry(rawlist, i); 463 parse_trace_kprobe_event(ent->s, &pp);
416 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
417 /* Synthesize only event probe point */ 464 /* Synthesize only event probe point */
418 nr = pp.nr_args; 465 synthesize_perf_probe_point(&pp);
419 pp.nr_args = 0;
420 synthesize_perf_probe_event(&pp);
421 pp.nr_args = nr;
422 /* Show an event */ 466 /* Show an event */
423 show_perf_probe_event(group, event, pp.probes[0], &pp); 467 show_perf_probe_event(pp.event, pp.probes[0], &pp);
424 free(group);
425 free(event);
426 clear_probe_point(&pp); 468 clear_probe_point(&pp);
427 } 469 }
428 470
@@ -432,26 +474,25 @@ void show_perf_probe_events(void)
432/* Get current perf-probe event names */ 474/* Get current perf-probe event names */
433static struct strlist *get_perf_event_names(int fd, bool include_group) 475static struct strlist *get_perf_event_names(int fd, bool include_group)
434{ 476{
435 unsigned int i;
436 char *group, *event;
437 char buf[128]; 477 char buf[128];
438 struct strlist *sl, *rawlist; 478 struct strlist *sl, *rawlist;
439 struct str_node *ent; 479 struct str_node *ent;
480 struct probe_point pp;
440 481
482 memset(&pp, 0, sizeof(pp));
441 rawlist = get_trace_kprobe_event_rawlist(fd); 483 rawlist = get_trace_kprobe_event_rawlist(fd);
442 484
443 sl = strlist__new(true, NULL); 485 sl = strlist__new(true, NULL);
444 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 486 strlist__for_each(ent, rawlist) {
445 ent = strlist__entry(rawlist, i); 487 parse_trace_kprobe_event(ent->s, &pp);
446 parse_trace_kprobe_event(ent->s, &group, &event, NULL);
447 if (include_group) { 488 if (include_group) {
448 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 489 if (e_snprintf(buf, 128, "%s:%s", pp.group,
490 pp.event) < 0)
449 die("Failed to copy group:event name."); 491 die("Failed to copy group:event name.");
450 strlist__add(sl, buf); 492 strlist__add(sl, buf);
451 } else 493 } else
452 strlist__add(sl, event); 494 strlist__add(sl, pp.event);
453 free(group); 495 clear_probe_point(&pp);
454 free(event);
455 } 496 }
456 497
457 strlist__delete(rawlist); 498 strlist__delete(rawlist);
@@ -470,7 +511,7 @@ static void write_trace_kprobe_event(int fd, const char *buf)
470} 511}
471 512
472static void get_new_event_name(char *buf, size_t len, const char *base, 513static void get_new_event_name(char *buf, size_t len, const char *base,
473 struct strlist *namelist) 514 struct strlist *namelist, bool allow_suffix)
474{ 515{
475 int i, ret; 516 int i, ret;
476 517
@@ -481,6 +522,12 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
481 if (!strlist__has_entry(namelist, buf)) 522 if (!strlist__has_entry(namelist, buf))
482 return; 523 return;
483 524
525 if (!allow_suffix) {
526 pr_warning("Error: event \"%s\" already exists. "
527 "(Use -f to force duplicates.)\n", base);
528 die("Can't add new event.");
529 }
530
484 /* Try to add suffix */ 531 /* Try to add suffix */
485 for (i = 1; i < MAX_EVENT_INDEX; i++) { 532 for (i = 1; i < MAX_EVENT_INDEX; i++) {
486 ret = e_snprintf(buf, len, "%s_%d", base, i); 533 ret = e_snprintf(buf, len, "%s_%d", base, i);
@@ -493,13 +540,15 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
493 die("Too many events are on the same function."); 540 die("Too many events are on the same function.");
494} 541}
495 542
496void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) 543void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
544 bool force_add)
497{ 545{
498 int i, j, fd; 546 int i, j, fd;
499 struct probe_point *pp; 547 struct probe_point *pp;
500 char buf[MAX_CMDLEN]; 548 char buf[MAX_CMDLEN];
501 char event[64]; 549 char event[64];
502 struct strlist *namelist; 550 struct strlist *namelist;
551 bool allow_suffix;
503 552
504 fd = open_kprobe_events(O_RDWR, O_APPEND); 553 fd = open_kprobe_events(O_RDWR, O_APPEND);
505 /* Get current event names */ 554 /* Get current event names */
@@ -507,21 +556,35 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
507 556
508 for (j = 0; j < nr_probes; j++) { 557 for (j = 0; j < nr_probes; j++) {
509 pp = probes + j; 558 pp = probes + j;
559 if (!pp->event)
560 pp->event = strdup(pp->function);
561 if (!pp->group)
562 pp->group = strdup(PERFPROBE_GROUP);
563 DIE_IF(!pp->event || !pp->group);
564 /* If force_add is true, suffix search is allowed */
565 allow_suffix = force_add;
510 for (i = 0; i < pp->found; i++) { 566 for (i = 0; i < pp->found; i++) {
511 /* Get an unused new event name */ 567 /* Get an unused new event name */
512 get_new_event_name(event, 64, pp->function, namelist); 568 get_new_event_name(event, 64, pp->event, namelist,
569 allow_suffix);
513 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
514 pp->retprobe ? 'r' : 'p', 571 pp->retprobe ? 'r' : 'p',
515 PERFPROBE_GROUP, event, 572 pp->group, event,
516 pp->probes[i]); 573 pp->probes[i]);
517 write_trace_kprobe_event(fd, buf); 574 write_trace_kprobe_event(fd, buf);
518 printf("Added new event:\n"); 575 printf("Added new event:\n");
519 /* Get the first parameter (probe-point) */ 576 /* Get the first parameter (probe-point) */
520 sscanf(pp->probes[i], "%s", buf); 577 sscanf(pp->probes[i], "%s", buf);
521 show_perf_probe_event(PERFPROBE_GROUP, event, 578 show_perf_probe_event(event, buf, pp);
522 buf, pp);
523 /* Add added event name to namelist */ 579 /* Add added event name to namelist */
524 strlist__add(namelist, event); 580 strlist__add(namelist, event);
581 /*
582 * Probes after the first probe which comes from same
583 * user input are always allowed to add suffix, because
584 * there might be several addresses corresponding to
585 * one code line.
586 */
587 allow_suffix = true;
525 } 588 }
526 } 589 }
527 /* Show how to use the event. */ 590 /* Show how to use the event. */
@@ -532,29 +595,55 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
532 close(fd); 595 close(fd);
533} 596}
534 597
598static void __del_trace_kprobe_event(int fd, struct str_node *ent)
599{
600 char *p;
601 char buf[128];
602
603 /* Convert from perf-probe event to trace-kprobe event */
604 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
605 die("Failed to copy event.");
606 p = strchr(buf + 2, ':');
607 if (!p)
608 die("Internal error: %s should have ':' but not.", ent->s);
609 *p = '/';
610
611 write_trace_kprobe_event(fd, buf);
612 printf("Remove event: %s\n", ent->s);
613}
614
535static void del_trace_kprobe_event(int fd, const char *group, 615static void del_trace_kprobe_event(int fd, const char *group,
536 const char *event, struct strlist *namelist) 616 const char *event, struct strlist *namelist)
537{ 617{
538 char buf[128]; 618 char buf[128];
619 struct str_node *ent, *n;
620 int found = 0;
539 621
540 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
541 die("Failed to copy event."); 623 die("Failed to copy event.");
542 if (!strlist__has_entry(namelist, buf)) {
543 pr_warning("Warning: event \"%s\" is not found.\n", buf);
544 return;
545 }
546 /* Convert from perf-probe event to trace-kprobe event */
547 if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0)
548 die("Failed to copy event.");
549 624
550 write_trace_kprobe_event(fd, buf); 625 if (strpbrk(buf, "*?")) { /* Glob-exp */
551 printf("Remove event: %s:%s\n", group, event); 626 strlist__for_each_safe(ent, n, namelist)
627 if (strglobmatch(ent->s, buf)) {
628 found++;
629 __del_trace_kprobe_event(fd, ent);
630 strlist__remove(namelist, ent);
631 }
632 } else {
633 ent = strlist__find(namelist, buf);
634 if (ent) {
635 found++;
636 __del_trace_kprobe_event(fd, ent);
637 strlist__remove(namelist, ent);
638 }
639 }
640 if (found == 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
552} 642}
553 643
554void del_trace_kprobe_events(struct strlist *dellist) 644void del_trace_kprobe_events(struct strlist *dellist)
555{ 645{
556 int fd; 646 int fd;
557 unsigned int i;
558 const char *group, *event; 647 const char *group, *event;
559 char *p, *str; 648 char *p, *str;
560 struct str_node *ent; 649 struct str_node *ent;
@@ -564,20 +653,21 @@ void del_trace_kprobe_events(struct strlist *dellist)
564 /* Get current event names */ 653 /* Get current event names */
565 namelist = get_perf_event_names(fd, true); 654 namelist = get_perf_event_names(fd, true);
566 655
567 for (i = 0; i < strlist__nr_entries(dellist); i++) { 656 strlist__for_each(ent, dellist) {
568 ent = strlist__entry(dellist, i);
569 str = strdup(ent->s); 657 str = strdup(ent->s);
570 if (!str) 658 if (!str)
571 die("Failed to copy event."); 659 die("Failed to copy event.");
660 pr_debug("Parsing: %s\n", str);
572 p = strchr(str, ':'); 661 p = strchr(str, ':');
573 if (p) { 662 if (p) {
574 group = str; 663 group = str;
575 *p = '\0'; 664 *p = '\0';
576 event = p + 1; 665 event = p + 1;
577 } else { 666 } else {
578 group = PERFPROBE_GROUP; 667 group = "*";
579 event = str; 668 event = str;
580 } 669 }
670 pr_debug("Group: %s, Event: %s\n", group, event);
581 del_trace_kprobe_event(fd, group, event, namelist); 671 del_trace_kprobe_event(fd, group, event, namelist);
582 free(str); 672 free(str);
583 } 673 }
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index f752159124ae..7f1d499118c0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -1,15 +1,18 @@
1#ifndef _PROBE_EVENT_H 1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include <stdbool.h>
4#include "probe-finder.h" 5#include "probe-finder.h"
5#include "strlist.h" 6#include "strlist.h"
6 7
7extern int parse_perf_probe_event(const char *str, struct probe_point *pp); 8extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp);
8extern int synthesize_perf_probe_event(struct probe_point *pp); 11extern int synthesize_perf_probe_event(struct probe_point *pp);
9extern void parse_trace_kprobe_event(const char *str, char **group, 12extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
10 char **event, struct probe_point *pp);
11extern int synthesize_trace_kprobe_event(struct probe_point *pp); 13extern int synthesize_trace_kprobe_event(struct probe_point *pp);
12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); 14extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add);
13extern void del_trace_kprobe_events(struct strlist *dellist); 16extern void del_trace_kprobe_events(struct strlist *dellist);
14extern void show_perf_probe_events(void); 17extern void show_perf_probe_events(void);
15 18
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4585f1d86792..4b852c0d16a5 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -687,10 +687,8 @@ int find_probepoint(int fd, struct probe_point *pp)
687 struct probe_finder pf = {.pp = pp}; 687 struct probe_finder pf = {.pp = pp};
688 688
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
690 if (ret != DW_DLV_OK) { 690 if (ret != DW_DLV_OK)
691 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO.\n");
692 return -ENOENT; 691 return -ENOENT;
693 }
694 692
695 pp->found = 0; 693 pp->found = 0;
696 while (++cu_number) { 694 while (++cu_number) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index bdebca6697d2..a4086aaddb73 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,9 +1,9 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#define MAX_PATH_LEN 256 4#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024 5#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128 6#define MAX_PROBES 128
7 7
8static inline int is_c_varname(const char *name) 8static inline int is_c_varname(const char *name)
9{ 9{
@@ -12,45 +12,53 @@ static inline int is_c_varname(const char *name)
12} 12}
13 13
14struct probe_point { 14struct probe_point {
15 char *event; /* Event name */
16 char *group; /* Event group */
17
15 /* Inputs */ 18 /* Inputs */
16 char *file; /* File name */ 19 char *file; /* File name */
17 int line; /* Line number */ 20 int line; /* Line number */
18 21
19 char *function; /* Function name */ 22 char *function; /* Function name */
20 int offset; /* Offset bytes */ 23 int offset; /* Offset bytes */
21 24
22 int nr_args; /* Number of arguments */ 25 int nr_args; /* Number of arguments */
23 char **args; /* Arguments */ 26 char **args; /* Arguments */
24 27
25 int retprobe; /* Return probe */ 28 int retprobe; /* Return probe */
26 29
27 /* Output */ 30 /* Output */
28 int found; /* Number of found probe points */ 31 int found; /* Number of found probe points */
29 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ 32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
30}; 33};
31 34
32#ifndef NO_LIBDWARF 35#ifndef NO_LIBDWARF
33extern int find_probepoint(int fd, struct probe_point *pp); 36extern int find_probepoint(int fd, struct probe_point *pp);
34 37
35#include <libdwarf/dwarf.h> 38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
36#include <libdwarf/libdwarf.h> 39#ifndef _MIPS_SZLONG
40# define _MIPS_SZLONG 0
41#endif
42
43#include <dwarf.h>
44#include <libdwarf.h>
37 45
38struct probe_finder { 46struct probe_finder {
39 struct probe_point *pp; /* Target probe point */ 47 struct probe_point *pp; /* Target probe point */
40 48
41 /* For function searching */ 49 /* For function searching */
42 Dwarf_Addr addr; /* Address */ 50 Dwarf_Addr addr; /* Address */
43 Dwarf_Unsigned fno; /* File number */ 51 Dwarf_Unsigned fno; /* File number */
44 Dwarf_Unsigned lno; /* Line number */ 52 Dwarf_Unsigned lno; /* Line number */
45 Dwarf_Off inl_offs; /* Inline offset */ 53 Dwarf_Off inl_offs; /* Inline offset */
46 Dwarf_Die cu_die; /* Current CU */ 54 Dwarf_Die cu_die; /* Current CU */
47 55
48 /* For variable searching */ 56 /* For variable searching */
49 Dwarf_Addr cu_base; /* Current CU base address */ 57 Dwarf_Addr cu_base; /* Current CU base address */
50 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
51 const char *var; /* Current variable name */ 59 const char *var; /* Current variable name */
52 char *buf; /* Current output buffer */ 60 char *buf; /* Current output buffer */
53 int len; /* Length of output buffer */ 61 int len; /* Length of output buffer */
54}; 62};
55#endif /* NO_LIBDWARF */ 63#endif /* NO_LIBDWARF */
56 64
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 707ce1cb1621..ce3a6c8abe76 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -4,6 +4,7 @@
4#include <sys/types.h> 4#include <sys/types.h>
5 5
6#include "session.h" 6#include "session.h"
7#include "sort.h"
7#include "util.h" 8#include "util.h"
8 9
9static int perf_session__open(struct perf_session *self, bool force) 10static int perf_session__open(struct perf_session *self, bool force)
@@ -50,31 +51,100 @@ out_close:
50 51
51struct perf_session *perf_session__new(const char *filename, int mode, bool force) 52struct perf_session *perf_session__new(const char *filename, int mode, bool force)
52{ 53{
53 size_t len = strlen(filename) + 1; 54 size_t len = filename ? strlen(filename) + 1 : 0;
54 struct perf_session *self = zalloc(sizeof(*self) + len); 55 struct perf_session *self = zalloc(sizeof(*self) + len);
55 56
56 if (self == NULL) 57 if (self == NULL)
57 goto out; 58 goto out;
58 59
59 if (perf_header__init(&self->header) < 0) 60 if (perf_header__init(&self->header) < 0)
60 goto out_delete; 61 goto out_free;
61 62
62 memcpy(self->filename, filename, len); 63 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT;
65 self->last_match = NULL;
66 self->mmap_window = 32;
67 self->cwd = NULL;
68 self->cwdlen = 0;
69 map_groups__init(&self->kmaps);
70
71 if (perf_session__create_kernel_maps(self) < 0)
72 goto out_delete;
63 73
64 if (mode == O_RDONLY && perf_session__open(self, force) < 0) { 74 if (mode == O_RDONLY && perf_session__open(self, force) < 0)
65 perf_session__delete(self); 75 goto out_delete;
66 self = NULL;
67 }
68out: 76out:
69 return self; 77 return self;
70out_delete: 78out_free:
71 free(self); 79 free(self);
72 return NULL; 80 return NULL;
81out_delete:
82 perf_session__delete(self);
83 return NULL;
73} 84}
74 85
75void perf_session__delete(struct perf_session *self) 86void perf_session__delete(struct perf_session *self)
76{ 87{
77 perf_header__exit(&self->header); 88 perf_header__exit(&self->header);
78 close(self->fd); 89 close(self->fd);
90 free(self->cwd);
79 free(self); 91 free(self);
80} 92}
93
94static bool symbol__match_parent_regex(struct symbol *sym)
95{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
97 return 1;
98
99 return 0;
100}
101
102struct symbol **perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread,
104 struct ip_callchain *chain,
105 struct symbol **parent)
106{
107 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i;
110
111 if (symbol_conf.use_callchain) {
112 syms = calloc(chain->nr, sizeof(*syms));
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118
119 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i];
121 struct addr_location al;
122
123 if (ip >= PERF_CONTEXT_MAX) {
124 switch (ip) {
125 case PERF_CONTEXT_HV:
126 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
127 case PERF_CONTEXT_KERNEL:
128 cpumode = PERF_RECORD_MISC_KERNEL; break;
129 case PERF_CONTEXT_USER:
130 cpumode = PERF_RECORD_MISC_USER; break;
131 default:
132 break;
133 }
134 continue;
135 }
136
137 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL);
139 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym))
142 *parent = al.sym;
143 if (!symbol_conf.use_callchain)
144 break;
145 syms[i] = al.sym;
146 }
147 }
148
149 return syms;
150}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index f3699c8c8ed4..32eaa1bada06 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -1,16 +1,61 @@
1#ifndef __PERF_SESSION_H 1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H 2#define __PERF_SESSION_H
3 3
4#include "event.h"
4#include "header.h" 5#include "header.h"
6#include "thread.h"
7#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h"
9
10struct ip_callchain;
11struct thread;
12struct symbol;
5 13
6struct perf_session { 14struct perf_session {
7 struct perf_header header; 15 struct perf_header header;
8 unsigned long size; 16 unsigned long size;
17 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads;
20 struct thread *last_match;
21 struct events_stats events_stats;
22 unsigned long event_total[PERF_RECORD_MAX];
23 struct rb_root hists;
24 u64 sample_type;
9 int fd; 25 int fd;
26 int cwdlen;
27 char *cwd;
10 char filename[0]; 28 char filename[0];
11}; 29};
12 30
31typedef int (*event_op)(event_t *self, struct perf_session *session);
32
33struct perf_event_ops {
34 event_op process_sample_event;
35 event_op process_mmap_event;
36 event_op process_comm_event;
37 event_op process_fork_event;
38 event_op process_exit_event;
39 event_op process_lost_event;
40 event_op process_read_event;
41 event_op process_throttle_event;
42 event_op process_unthrottle_event;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46};
47
13struct perf_session *perf_session__new(const char *filename, int mode, bool force); 48struct perf_session *perf_session__new(const char *filename, int mode, bool force);
14void perf_session__delete(struct perf_session *self); 49void perf_session__delete(struct perf_session *self);
15 50
51int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops);
53
54struct symbol **perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread,
56 struct ip_callchain *chain,
57 struct symbol **parent);
58
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
60
16#endif /* __PERF_SESSION_H */ 61#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index b490354d1b23..cb0f327de9e8 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -288,3 +288,29 @@ int sort_dimension__add(const char *tok)
288 288
289 return -ESRCH; 289 return -ESRCH;
290} 290}
291
292void setup_sorting(const char * const usagestr[], const struct option *opts)
293{
294 char *tmp, *tok, *str = strdup(sort_order);
295
296 for (tok = strtok_r(str, ", ", &tmp);
297 tok; tok = strtok_r(NULL, ", ", &tmp)) {
298 if (sort_dimension__add(tok) < 0) {
299 error("Unknown --sort key: `%s'", tok);
300 usage_with_options(usagestr, opts);
301 }
302 }
303
304 free(str);
305}
306
307void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
308 const char *list_name, FILE *fp)
309{
310 if (list && strlist__nr_entries(list) == 1) {
311 if (fp != NULL)
312 fprintf(fp, "# %s: %s\n", list_name,
313 strlist__entry(list, 0)->s);
314 self->elide = true;
315 }
316}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 333e664ff45f..753f9ea99fb0 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -49,9 +49,13 @@ struct hist_entry {
49 struct symbol *sym; 49 struct symbol *sym;
50 u64 ip; 50 u64 ip;
51 char level; 51 char level;
52 struct symbol *parent; 52 struct symbol *parent;
53 struct callchain_node callchain; 53 struct callchain_node callchain;
54 struct rb_root sorted_chain; 54 union {
55 unsigned long position;
56 struct hist_entry *pair;
57 struct rb_root sorted_chain;
58 };
55}; 59};
56 60
57enum sort_type { 61enum sort_type {
@@ -81,6 +85,8 @@ struct sort_entry {
81extern struct sort_entry sort_thread; 85extern struct sort_entry sort_thread;
82extern struct list_head hist_entry__sort_list; 86extern struct list_head hist_entry__sort_list;
83 87
88void setup_sorting(const char * const usagestr[], const struct option *opts);
89
84extern int repsep_fprintf(FILE *fp, const char *fmt, ...); 90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
85extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); 91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
86extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); 92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
@@ -95,5 +101,7 @@ extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
95extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); 101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
96extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); 102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
97extern int sort_dimension__add(const char *); 103extern int sort_dimension__add(const char *);
104void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
105 const char *list_name, FILE *fp);
98 106
99#endif /* __PERF_SORT_H */ 107#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index f24a8cc933d5..5352d7dccc61 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -226,3 +226,28 @@ fail:
226 argv_free(argv); 226 argv_free(argv);
227 return NULL; 227 return NULL;
228} 228}
229
230/* Glob expression pattern matching */
231bool strglobmatch(const char *str, const char *pat)
232{
233 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') {
235 str++;
236 pat++;
237 } else
238 if (*str++ != *pat++)
239 return false;
240 }
241 /* Check wild card */
242 if (*pat == '*') {
243 while (*pat == '*')
244 pat++;
245 if (!*pat) /* Tail wild card matches all */
246 return true;
247 while (*str)
248 if (strglobmatch(str++, pat))
249 return true;
250 }
251 return !*str && !*pat;
252}
253
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bfecec265a1a..02ede58c54b4 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define __PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include <stdbool.h>
4#include "types.h" 5#include "types.h"
5 6
6int hex2u64(const char *ptr, u64 *val); 7int hex2u64(const char *ptr, u64 *val);
@@ -8,6 +9,7 @@ char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str); 9s64 perf_atoll(const char *str);
9char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
10void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
11 13
12#define _STR(x) #x 14#define _STR(x) #x
13#define STR(x) _STR(x) 15#define STR(x) _STR(x)
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 7ad38171dc2b..6783a2043555 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -102,7 +102,7 @@ void strlist__remove(struct strlist *self, struct str_node *sn)
102 str_node__delete(sn, self->dupstr); 102 str_node__delete(sn, self->dupstr);
103} 103}
104 104
105bool strlist__has_entry(struct strlist *self, const char *entry) 105struct str_node *strlist__find(struct strlist *self, const char *entry)
106{ 106{
107 struct rb_node **p = &self->entries.rb_node; 107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL; 108 struct rb_node *parent = NULL;
@@ -120,10 +120,10 @@ bool strlist__has_entry(struct strlist *self, const char *entry)
120 else if (rc < 0) 120 else if (rc < 0)
121 p = &(*p)->rb_right; 121 p = &(*p)->rb_right;
122 else 122 else
123 return true; 123 return sn;
124 } 124 }
125 125
126 return false; 126 return NULL;
127} 127}
128 128
129static int strlist__parse_list_entry(struct strlist *self, const char *s) 129static int strlist__parse_list_entry(struct strlist *self, const char *s)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index cb4659306d7b..3ba839007d2c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -23,7 +23,12 @@ int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
24 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry); 26struct str_node *strlist__find(struct strlist *self, const char *entry);
27
28static inline bool strlist__has_entry(struct strlist *self, const char *entry)
29{
30 return strlist__find(self, entry) != NULL;
31}
27 32
28static inline bool strlist__empty(const struct strlist *self) 33static inline bool strlist__empty(const struct strlist *self)
29{ 34{
@@ -35,5 +40,39 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
35 return self->nr_entries; 40 return self->nr_entries;
36} 41}
37 42
43/* For strlist iteration */
44static inline struct str_node *strlist__first(struct strlist *self)
45{
46 struct rb_node *rn = rb_first(&self->entries);
47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
48}
49static inline struct str_node *strlist__next(struct str_node *sn)
50{
51 struct rb_node *rn;
52 if (!sn)
53 return NULL;
54 rn = rb_next(&sn->rb_node);
55 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
56}
57
58/**
59 * strlist_for_each - iterate over a strlist
60 * @pos: the &struct str_node to use as a loop cursor.
61 * @self: the &struct strlist for loop.
62 */
63#define strlist__for_each(pos, self) \
64 for (pos = strlist__first(self); pos; pos = strlist__next(pos))
65
66/**
67 * strlist_for_each_safe - iterate over a strlist safe against removal of
68 * str_node
69 * @pos: the &struct str_node to use as a loop cursor.
70 * @n: another &struct str_node to use as temporary storage.
71 * @self: the &struct strlist for loop.
72 */
73#define strlist__for_each_safe(pos, n, self) \
74 for (pos = strlist__first(self), n = strlist__next(pos); pos;\
75 pos = n, n = strlist__next(n))
76
38int strlist__parse_list(struct strlist *self, const char *s); 77int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* __PERF_STRLIST_H */ 78#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index d3d9fed74f1d..ab92763edb03 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,5 +1,7 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "session.h"
4#include "sort.h"
3#include "string.h" 5#include "string.h"
4#include "symbol.h" 6#include "symbol.h"
5#include "thread.h" 7#include "thread.h"
@@ -31,19 +33,16 @@ enum dso_origin {
31static void dsos__add(struct list_head *head, struct dso *dso); 33static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
33static int dso__load_kernel_sym(struct dso *self, struct map *map, 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
34 struct map_groups *mg, symbol_filter_t filter); 36 struct perf_session *session, symbol_filter_t filter);
35unsigned int symbol__priv_size;
36static int vmlinux_path__nr_entries; 37static int vmlinux_path__nr_entries;
37static char **vmlinux_path; 38static char **vmlinux_path;
38 39
39static struct symbol_conf symbol_conf__defaults = { 40struct symbol_conf symbol_conf = {
41 .exclude_other = true,
40 .use_modules = true, 42 .use_modules = true,
41 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
42}; 44};
43 45
44static struct map_groups kmaps_mem;
45struct map_groups *kmaps = &kmaps_mem;
46
47bool dso__loaded(const struct dso *self, enum map_type type) 46bool dso__loaded(const struct dso *self, enum map_type type)
48{ 47{
49 return self->loaded & (1 << type); 48 return self->loaded & (1 << type);
@@ -132,13 +131,13 @@ static void map_groups__fixup_end(struct map_groups *self)
132static struct symbol *symbol__new(u64 start, u64 len, const char *name) 131static struct symbol *symbol__new(u64 start, u64 len, const char *name)
133{ 132{
134 size_t namelen = strlen(name) + 1; 133 size_t namelen = strlen(name) + 1;
135 struct symbol *self = zalloc(symbol__priv_size + 134 struct symbol *self = zalloc(symbol_conf.priv_size +
136 sizeof(*self) + namelen); 135 sizeof(*self) + namelen);
137 if (self == NULL) 136 if (self == NULL)
138 return NULL; 137 return NULL;
139 138
140 if (symbol__priv_size) 139 if (symbol_conf.priv_size)
141 self = ((void *)self) + symbol__priv_size; 140 self = ((void *)self) + symbol_conf.priv_size;
142 141
143 self->start = start; 142 self->start = start;
144 self->end = len ? start + len - 1 : start; 143 self->end = len ? start + len - 1 : start;
@@ -152,7 +151,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name)
152 151
153static void symbol__delete(struct symbol *self) 152static void symbol__delete(struct symbol *self)
154{ 153{
155 free(((void *)self) - symbol__priv_size); 154 free(((void *)self) - symbol_conf.priv_size);
156} 155}
157 156
158static size_t symbol__fprintf(struct symbol *self, FILE *fp) 157static size_t symbol__fprintf(struct symbol *self, FILE *fp)
@@ -456,7 +455,7 @@ out_failure:
456 * the original ELF section names vmlinux have. 455 * the original ELF section names vmlinux have.
457 */ 456 */
458static int dso__split_kallsyms(struct dso *self, struct map *map, 457static int dso__split_kallsyms(struct dso *self, struct map *map,
459 struct map_groups *mg, symbol_filter_t filter) 458 struct perf_session *session, symbol_filter_t filter)
460{ 459{
461 struct map *curr_map = map; 460 struct map *curr_map = map;
462 struct symbol *pos; 461 struct symbol *pos;
@@ -473,13 +472,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
473 472
474 module = strchr(pos->name, '\t'); 473 module = strchr(pos->name, '\t');
475 if (module) { 474 if (module) {
476 if (!mg->use_modules) 475 if (!symbol_conf.use_modules)
477 goto discard_symbol; 476 goto discard_symbol;
478 477
479 *module++ = '\0'; 478 *module++ = '\0';
480 479
481 if (strcmp(self->name, module)) { 480 if (strcmp(self->name, module)) {
482 curr_map = map_groups__find_by_name(mg, map->type, module); 481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
483 if (curr_map == NULL) { 482 if (curr_map == NULL) {
484 pr_debug("/proc/{kallsyms,modules} " 483 pr_debug("/proc/{kallsyms,modules} "
485 "inconsistency!\n"); 484 "inconsistency!\n");
@@ -510,7 +509,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
510 } 509 }
511 510
512 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
513 map_groups__insert(mg, curr_map); 512 map_groups__insert(&session->kmaps, curr_map);
514 ++kernel_range; 513 ++kernel_range;
515 } 514 }
516 515
@@ -531,7 +530,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
531 530
532 531
533static int dso__load_kallsyms(struct dso *self, struct map *map, 532static int dso__load_kallsyms(struct dso *self, struct map *map,
534 struct map_groups *mg, symbol_filter_t filter) 533 struct perf_session *session, symbol_filter_t filter)
535{ 534{
536 if (dso__load_all_kallsyms(self, map) < 0) 535 if (dso__load_all_kallsyms(self, map) < 0)
537 return -1; 536 return -1;
@@ -539,14 +538,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
539 symbols__fixup_end(&self->symbols[map->type]); 538 symbols__fixup_end(&self->symbols[map->type]);
540 self->origin = DSO__ORIG_KERNEL; 539 self->origin = DSO__ORIG_KERNEL;
541 540
542 return dso__split_kallsyms(self, map, mg, filter); 541 return dso__split_kallsyms(self, map, session, filter);
543}
544
545size_t kernel_maps__fprintf(FILE *fp)
546{
547 size_t printed = fprintf(fp, "Kernel maps:\n");
548 printed += map_groups__fprintf_maps(kmaps, fp);
549 return printed + fprintf(fp, "END kernel maps\n");
550} 542}
551 543
552static int dso__load_perf_map(struct dso *self, struct map *map, 544static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -873,7 +865,7 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
873} 865}
874 866
875static int dso__load_sym(struct dso *self, struct map *map, 867static int dso__load_sym(struct dso *self, struct map *map,
876 struct map_groups *mg, const char *name, int fd, 868 struct perf_session *session, const char *name, int fd,
877 symbol_filter_t filter, int kernel, int kmodule) 869 symbol_filter_t filter, int kernel, int kmodule)
878{ 870{
879 struct map *curr_map = map; 871 struct map *curr_map = map;
@@ -977,7 +969,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
977 snprintf(dso_name, sizeof(dso_name), 969 snprintf(dso_name, sizeof(dso_name),
978 "%s%s", self->short_name, section_name); 970 "%s%s", self->short_name, section_name);
979 971
980 curr_map = map_groups__find_by_name(mg, map->type, dso_name); 972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
981 if (curr_map == NULL) { 973 if (curr_map == NULL) {
982 u64 start = sym.st_value; 974 u64 start = sym.st_value;
983 975
@@ -996,7 +988,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
996 curr_map->map_ip = identity__map_ip; 988 curr_map->map_ip = identity__map_ip;
997 curr_map->unmap_ip = identity__map_ip; 989 curr_map->unmap_ip = identity__map_ip;
998 curr_dso->origin = DSO__ORIG_KERNEL; 990 curr_dso->origin = DSO__ORIG_KERNEL;
999 map_groups__insert(kmaps, curr_map); 991 map_groups__insert(&session->kmaps, curr_map);
1000 dsos__add(&dsos__kernel, curr_dso); 992 dsos__add(&dsos__kernel, curr_dso);
1001 } else 993 } else
1002 curr_dso = curr_map->dso; 994 curr_dso = curr_map->dso;
@@ -1211,7 +1203,8 @@ char dso__symtab_origin(const struct dso *self)
1211 return origin[self->origin]; 1203 return origin[self->origin];
1212} 1204}
1213 1205
1214int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 1206int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1207 symbol_filter_t filter)
1215{ 1208{
1216 int size = PATH_MAX; 1209 int size = PATH_MAX;
1217 char *name; 1210 char *name;
@@ -1222,7 +1215,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1222 dso__set_loaded(self, map->type); 1215 dso__set_loaded(self, map->type);
1223 1216
1224 if (self->kernel) 1217 if (self->kernel)
1225 return dso__load_kernel_sym(self, map, kmaps, filter); 1218 return dso__load_kernel_sym(self, map, session, filter);
1226 1219
1227 name = malloc(size); 1220 name = malloc(size);
1228 if (!name) 1221 if (!name)
@@ -1323,7 +1316,7 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1323 return NULL; 1316 return NULL;
1324} 1317}
1325 1318
1326static int dsos__set_modules_path_dir(char *dirname) 1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
1327{ 1320{
1328 struct dirent *dent; 1321 struct dirent *dent;
1329 DIR *dir = opendir(dirname); 1322 DIR *dir = opendir(dirname);
@@ -1343,7 +1336,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1343 1336
1344 snprintf(path, sizeof(path), "%s/%s", 1337 snprintf(path, sizeof(path), "%s/%s",
1345 dirname, dent->d_name); 1338 dirname, dent->d_name);
1346 if (dsos__set_modules_path_dir(path) < 0) 1339 if (perf_session__set_modules_path_dir(self, path) < 0)
1347 goto failure; 1340 goto failure;
1348 } else { 1341 } else {
1349 char *dot = strrchr(dent->d_name, '.'), 1342 char *dot = strrchr(dent->d_name, '.'),
@@ -1357,7 +1350,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1357 (int)(dot - dent->d_name), dent->d_name); 1350 (int)(dot - dent->d_name), dent->d_name);
1358 1351
1359 strxfrchar(dso_name, '-', '_'); 1352 strxfrchar(dso_name, '-', '_');
1360 map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name); 1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
1361 if (map == NULL) 1354 if (map == NULL)
1362 continue; 1355 continue;
1363 1356
@@ -1377,7 +1370,7 @@ failure:
1377 return -1; 1370 return -1;
1378} 1371}
1379 1372
1380static int dsos__set_modules_path(void) 1373static int perf_session__set_modules_path(struct perf_session *self)
1381{ 1374{
1382 struct utsname uts; 1375 struct utsname uts;
1383 char modules_path[PATH_MAX]; 1376 char modules_path[PATH_MAX];
@@ -1388,7 +1381,7 @@ static int dsos__set_modules_path(void)
1388 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1389 uts.release); 1382 uts.release);
1390 1383
1391 return dsos__set_modules_path_dir(modules_path); 1384 return perf_session__set_modules_path_dir(self, modules_path);
1392} 1385}
1393 1386
1394/* 1387/*
@@ -1410,7 +1403,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1410 return self; 1403 return self;
1411} 1404}
1412 1405
1413static int map_groups__create_module_maps(struct map_groups *self) 1406static int perf_session__create_module_maps(struct perf_session *self)
1414{ 1407{
1415 char *line = NULL; 1408 char *line = NULL;
1416 size_t n; 1409 size_t n;
@@ -1467,14 +1460,14 @@ static int map_groups__create_module_maps(struct map_groups *self)
1467 dso->has_build_id = true; 1460 dso->has_build_id = true;
1468 1461
1469 dso->origin = DSO__ORIG_KMODULE; 1462 dso->origin = DSO__ORIG_KMODULE;
1470 map_groups__insert(self, map); 1463 map_groups__insert(&self->kmaps, map);
1471 dsos__add(&dsos__kernel, dso); 1464 dsos__add(&dsos__kernel, dso);
1472 } 1465 }
1473 1466
1474 free(line); 1467 free(line);
1475 fclose(file); 1468 fclose(file);
1476 1469
1477 return dsos__set_modules_path(); 1470 return perf_session__set_modules_path(self);
1478 1471
1479out_delete_line: 1472out_delete_line:
1480 free(line); 1473 free(line);
@@ -1483,7 +1476,7 @@ out_failure:
1483} 1476}
1484 1477
1485static int dso__load_vmlinux(struct dso *self, struct map *map, 1478static int dso__load_vmlinux(struct dso *self, struct map *map,
1486 struct map_groups *mg, 1479 struct perf_session *session,
1487 const char *vmlinux, symbol_filter_t filter) 1480 const char *vmlinux, symbol_filter_t filter)
1488{ 1481{
1489 int err = -1, fd; 1482 int err = -1, fd;
@@ -1517,14 +1510,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1517 return -1; 1510 return -1;
1518 1511
1519 dso__set_loaded(self, map->type); 1512 dso__set_loaded(self, map->type);
1520 err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0); 1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0);
1521 close(fd); 1514 close(fd);
1522 1515
1523 return err; 1516 return err;
1524} 1517}
1525 1518
1526static int dso__load_kernel_sym(struct dso *self, struct map *map, 1519static int dso__load_kernel_sym(struct dso *self, struct map *map,
1527 struct map_groups *mg, symbol_filter_t filter) 1520 struct perf_session *session, symbol_filter_t filter)
1528{ 1521{
1529 int err; 1522 int err;
1530 bool is_kallsyms; 1523 bool is_kallsyms;
@@ -1534,7 +1527,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1534 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1535 vmlinux_path__nr_entries); 1528 vmlinux_path__nr_entries);
1536 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1537 err = dso__load_vmlinux(self, map, mg, 1530 err = dso__load_vmlinux(self, map, session,
1538 vmlinux_path[i], filter); 1531 vmlinux_path[i], filter);
1539 if (err > 0) { 1532 if (err > 0) {
1540 pr_debug("Using %s for symbols\n", 1533 pr_debug("Using %s for symbols\n",
@@ -1550,12 +1543,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1550 if (is_kallsyms) 1543 if (is_kallsyms)
1551 goto do_kallsyms; 1544 goto do_kallsyms;
1552 1545
1553 err = dso__load_vmlinux(self, map, mg, self->long_name, filter); 1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
1554 if (err <= 0) { 1547 if (err <= 0) {
1555 pr_info("The file %s cannot be used, " 1548 pr_info("The file %s cannot be used, "
1556 "trying to use /proc/kallsyms...", self->long_name); 1549 "trying to use /proc/kallsyms...", self->long_name);
1557do_kallsyms: 1550do_kallsyms:
1558 err = dso__load_kallsyms(self, map, mg, filter); 1551 err = dso__load_kallsyms(self, map, session, filter);
1559 if (err > 0 && !is_kallsyms) 1552 if (err > 0 && !is_kallsyms)
1560 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1553 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1561 } 1554 }
@@ -1748,32 +1741,69 @@ out_fail:
1748 return -1; 1741 return -1;
1749} 1742}
1750 1743
1751int symbol__init(struct symbol_conf *conf) 1744static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name)
1752{ 1746{
1753 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1747 if (list_str == NULL)
1748 return 0;
1749
1750 *list = strlist__new(true, list_str);
1751 if (!*list) {
1752 pr_err("problems parsing %s list\n", list_name);
1753 return -1;
1754 }
1755 return 0;
1756}
1754 1757
1758int symbol__init(void)
1759{
1755 elf_version(EV_CURRENT); 1760 elf_version(EV_CURRENT);
1756 symbol__priv_size = pconf->priv_size; 1761 if (symbol_conf.sort_by_name)
1757 if (pconf->sort_by_name) 1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1758 symbol__priv_size += (sizeof(struct symbol_name_rb_node) - 1763 sizeof(struct symbol));
1759 sizeof(struct symbol));
1760 map_groups__init(kmaps);
1761 1764
1762 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1765 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1763 return -1; 1766 return -1;
1764 1767
1765 if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) { 1768 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1766 vmlinux_path__exit(); 1769 pr_err("'.' is the only non valid --field-separator argument\n");
1767 return -1; 1770 return -1;
1768 } 1771 }
1769 1772
1770 kmaps->use_modules = pconf->use_modules; 1773 if (setup_list(&symbol_conf.dso_list,
1771 if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) 1774 symbol_conf.dso_list_str, "dso") < 0)
1772 pr_debug("Failed to load list of modules in use, " 1775 return -1;
1773 "continuing...\n"); 1776
1777 if (setup_list(&symbol_conf.comm_list,
1778 symbol_conf.comm_list_str, "comm") < 0)
1779 goto out_free_dso_list;
1780
1781 if (setup_list(&symbol_conf.sym_list,
1782 symbol_conf.sym_list_str, "symbol") < 0)
1783 goto out_free_comm_list;
1784
1785 return 0;
1786
1787out_free_dso_list:
1788 strlist__delete(symbol_conf.dso_list);
1789out_free_comm_list:
1790 strlist__delete(symbol_conf.comm_list);
1791 return -1;
1792}
1793
1794int perf_session__create_kernel_maps(struct perf_session *self)
1795{
1796 if (map_groups__create_kernel_maps(&self->kmaps,
1797 symbol_conf.vmlinux_name) < 0)
1798 return -1;
1799
1800 if (symbol_conf.use_modules &&
1801 perf_session__create_module_maps(self) < 0)
1802 pr_debug("Failed to load list of modules for session %s, "
1803 "continuing...\n", self->filename);
1774 /* 1804 /*
1775 * Now that we have all the maps created, just set the ->end of them: 1805 * Now that we have all the maps created, just set the ->end of them:
1776 */ 1806 */
1777 map_groups__fixup_end(kmaps); 1807 map_groups__fixup_end(&self->kmaps);
1778 return 0; 1808 return 0;
1779} 1809}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index cf99f88adf39..8aded2356f79 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -49,19 +49,32 @@ struct symbol {
49 char name[0]; 49 char name[0];
50}; 50};
51 51
52struct strlist;
53
52struct symbol_conf { 54struct symbol_conf {
53 unsigned short priv_size; 55 unsigned short priv_size;
54 bool try_vmlinux_path, 56 bool try_vmlinux_path,
55 use_modules, 57 use_modules,
56 sort_by_name; 58 sort_by_name,
57 const char *vmlinux_name; 59 show_nr_samples,
60 use_callchain,
61 exclude_other;
62 const char *vmlinux_name,
63 *field_sep;
64 char *dso_list_str,
65 *comm_list_str,
66 *sym_list_str,
67 *col_width_list_str;
68 struct strlist *dso_list,
69 *comm_list,
70 *sym_list;
58}; 71};
59 72
60extern unsigned int symbol__priv_size; 73extern struct symbol_conf symbol_conf;
61 74
62static inline void *symbol__priv(struct symbol *self) 75static inline void *symbol__priv(struct symbol *self)
63{ 76{
64 return ((void *)self) - symbol__priv_size; 77 return ((void *)self) - symbol_conf.priv_size;
65} 78}
66 79
67struct addr_location { 80struct addr_location {
@@ -70,6 +83,7 @@ struct addr_location {
70 struct symbol *sym; 83 struct symbol *sym;
71 u64 addr; 84 u64 addr;
72 char level; 85 char level;
86 bool filtered;
73}; 87};
74 88
75struct dso { 89struct dso {
@@ -98,8 +112,11 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type);
98 112
99void dso__sort_by_name(struct dso *self, enum map_type type); 113void dso__sort_by_name(struct dso *self, enum map_type type);
100 114
115struct perf_session;
116
101struct dso *dsos__findnew(const char *name); 117struct dso *dsos__findnew(const char *name);
102int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 118int dso__load(struct dso *self, struct map *map, struct perf_session *session,
119 symbol_filter_t filter);
103void dsos__fprintf(FILE *fp); 120void dsos__fprintf(FILE *fp);
104size_t dsos__fprintf_buildid(FILE *fp); 121size_t dsos__fprintf_buildid(FILE *fp);
105 122
@@ -116,12 +133,9 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size);
116bool dsos__read_build_ids(void); 133bool dsos__read_build_ids(void);
117int build_id__sprintf(u8 *self, int len, char *bf); 134int build_id__sprintf(u8 *self, int len, char *bf);
118 135
119size_t kernel_maps__fprintf(FILE *fp); 136int symbol__init(void);
120 137int perf_session__create_kernel_maps(struct perf_session *self);
121int symbol__init(struct symbol_conf *conf);
122 138
123struct map_groups;
124struct map_groups *kmaps;
125extern struct list_head dsos__user, dsos__kernel; 139extern struct list_head dsos__user, dsos__kernel;
126extern struct dso *vdso; 140extern struct dso *vdso;
127#endif /* __PERF_SYMBOL */ 141#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index b68a00ea4121..4a08dcf50b68 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,13 +2,11 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include "session.h"
5#include "thread.h" 6#include "thread.h"
6#include "util.h" 7#include "util.h"
7#include "debug.h" 8#include "debug.h"
8 9
9static struct rb_root threads;
10static struct thread *last_match;
11
12void map_groups__init(struct map_groups *self) 10void map_groups__init(struct map_groups *self)
13{ 11{
14 int i; 12 int i;
@@ -122,9 +120,9 @@ static size_t thread__fprintf(struct thread *self, FILE *fp)
122 map_groups__fprintf(&self->mg, fp); 120 map_groups__fprintf(&self->mg, fp);
123} 121}
124 122
125struct thread *threads__findnew(pid_t pid) 123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
126{ 124{
127 struct rb_node **p = &threads.rb_node; 125 struct rb_node **p = &self->threads.rb_node;
128 struct rb_node *parent = NULL; 126 struct rb_node *parent = NULL;
129 struct thread *th; 127 struct thread *th;
130 128
@@ -133,15 +131,15 @@ struct thread *threads__findnew(pid_t pid)
133 * so most of the time we dont have to look up 131 * so most of the time we dont have to look up
134 * the full rbtree: 132 * the full rbtree:
135 */ 133 */
136 if (last_match && last_match->pid == pid) 134 if (self->last_match && self->last_match->pid == pid)
137 return last_match; 135 return self->last_match;
138 136
139 while (*p != NULL) { 137 while (*p != NULL) {
140 parent = *p; 138 parent = *p;
141 th = rb_entry(parent, struct thread, rb_node); 139 th = rb_entry(parent, struct thread, rb_node);
142 140
143 if (th->pid == pid) { 141 if (th->pid == pid) {
144 last_match = th; 142 self->last_match = th;
145 return th; 143 return th;
146 } 144 }
147 145
@@ -154,25 +152,13 @@ struct thread *threads__findnew(pid_t pid)
154 th = thread__new(pid); 152 th = thread__new(pid);
155 if (th != NULL) { 153 if (th != NULL) {
156 rb_link_node(&th->rb_node, parent, p); 154 rb_link_node(&th->rb_node, parent, p);
157 rb_insert_color(&th->rb_node, &threads); 155 rb_insert_color(&th->rb_node, &self->threads);
158 last_match = th; 156 self->last_match = th;
159 } 157 }
160 158
161 return th; 159 return th;
162} 160}
163 161
164struct thread *register_idle_thread(void)
165{
166 struct thread *thread = threads__findnew(0);
167
168 if (!thread || thread__set_comm(thread, "swapper")) {
169 fprintf(stderr, "problem inserting idle task.\n");
170 exit(-1);
171 }
172
173 return thread;
174}
175
176static void map_groups__remove_overlappings(struct map_groups *self, 162static void map_groups__remove_overlappings(struct map_groups *self,
177 struct map *map) 163 struct map *map)
178{ 164{
@@ -281,12 +267,12 @@ int thread__fork(struct thread *self, struct thread *parent)
281 return 0; 267 return 0;
282} 268}
283 269
284size_t threads__fprintf(FILE *fp) 270size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
285{ 271{
286 size_t ret = 0; 272 size_t ret = 0;
287 struct rb_node *nd; 273 struct rb_node *nd;
288 274
289 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 275 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
290 struct thread *pos = rb_entry(nd, struct thread, rb_node); 276 struct thread *pos = rb_entry(nd, struct thread, rb_node);
291 277
292 ret += thread__fprintf(pos, fp); 278 ret += thread__fprintf(pos, fp);
@@ -296,13 +282,14 @@ size_t threads__fprintf(FILE *fp)
296} 282}
297 283
298struct symbol *map_groups__find_symbol(struct map_groups *self, 284struct symbol *map_groups__find_symbol(struct map_groups *self,
285 struct perf_session *session,
299 enum map_type type, u64 addr, 286 enum map_type type, u64 addr,
300 symbol_filter_t filter) 287 symbol_filter_t filter)
301{ 288{
302 struct map *map = map_groups__find(self, type, addr); 289 struct map *map = map_groups__find(self, type, addr);
303 290
304 if (map != NULL) 291 if (map != NULL)
305 return map__find_symbol(map, map->map_ip(map, addr), filter); 292 return map__find_symbol(map, session, map->map_ip(map, addr), filter);
306 293
307 return NULL; 294 return NULL;
308} 295}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 1751802a09ba..c206f72c8881 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -8,7 +8,6 @@
8struct map_groups { 8struct map_groups {
9 struct rb_root maps[MAP__NR_TYPES]; 9 struct rb_root maps[MAP__NR_TYPES];
10 struct list_head removed_maps[MAP__NR_TYPES]; 10 struct list_head removed_maps[MAP__NR_TYPES];
11 bool use_modules;
12}; 11};
13 12
14struct thread { 13struct thread {
@@ -23,12 +22,11 @@ struct thread {
23void map_groups__init(struct map_groups *self); 22void map_groups__init(struct map_groups *self);
24int thread__set_comm(struct thread *self, const char *comm); 23int thread__set_comm(struct thread *self, const char *comm);
25int thread__comm_len(struct thread *self); 24int thread__comm_len(struct thread *self);
26struct thread *threads__findnew(pid_t pid); 25struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
27struct thread *register_idle_thread(void);
28void thread__insert_map(struct thread *self, struct map *map); 26void thread__insert_map(struct thread *self, struct map *map);
29int thread__fork(struct thread *self, struct thread *parent); 27int thread__fork(struct thread *self, struct thread *parent);
30size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp); 28size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
31size_t threads__fprintf(FILE *fp); 29size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
32 30
33void maps__insert(struct rb_root *maps, struct map *map); 31void maps__insert(struct rb_root *maps, struct map *map);
34struct map *maps__find(struct rb_root *maps, u64 addr); 32struct map *maps__find(struct rb_root *maps, u64 addr);
@@ -50,19 +48,21 @@ static inline struct map *thread__find_map(struct thread *self,
50 return self ? map_groups__find(&self->mg, type, addr) : NULL; 48 return self ? map_groups__find(&self->mg, type, addr) : NULL;
51} 49}
52 50
53void thread__find_addr_location(struct thread *self, u8 cpumode, 51void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode,
54 enum map_type type, u64 addr, 53 enum map_type type, u64 addr,
55 struct addr_location *al, 54 struct addr_location *al,
56 symbol_filter_t filter); 55 symbol_filter_t filter);
57struct symbol *map_groups__find_symbol(struct map_groups *self, 56struct symbol *map_groups__find_symbol(struct map_groups *self,
57 struct perf_session *session,
58 enum map_type type, u64 addr, 58 enum map_type type, u64 addr,
59 symbol_filter_t filter); 59 symbol_filter_t filter);
60 60
61static inline struct symbol * 61static inline struct symbol *
62map_groups__find_function(struct map_groups *self, u64 addr, 62map_groups__find_function(struct map_groups *self, struct perf_session *session,
63 symbol_filter_t filter) 63 u64 addr, symbol_filter_t filter)
64{ 64{
65 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter); 65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter);
66} 66}
67 67
68struct map *map_groups__find_by_name(struct map_groups *self, 68struct map *map_groups__find_by_name(struct map_groups *self,
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
index a5ffe60db5d6..6d6d76b8a21e 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/trace-event-perl.c
@@ -267,7 +267,7 @@ int common_lock_depth(struct scripting_context *context)
267} 267}
268 268
269static void perl_process_event(int cpu, void *data, 269static void perl_process_event(int cpu, void *data,
270 int size __attribute((unused)), 270 int size __unused,
271 unsigned long long nsecs, char *comm) 271 unsigned long long nsecs, char *comm)
272{ 272{
273 struct format_field *field; 273 struct format_field *field;
@@ -359,28 +359,46 @@ static void run_start_sub(void)
359/* 359/*
360 * Start trace script 360 * Start trace script
361 */ 361 */
362static int perl_start_script(const char *script) 362static int perl_start_script(const char *script, int argc, const char **argv)
363{ 363{
364 const char *command_line[2] = { "", NULL }; 364 const char **command_line;
365 int i, err = 0;
365 366
367 command_line = malloc((argc + 2) * sizeof(const char *));
368 command_line[0] = "";
366 command_line[1] = script; 369 command_line[1] = script;
370 for (i = 2; i < argc + 2; i++)
371 command_line[i] = argv[i - 2];
367 372
368 my_perl = perl_alloc(); 373 my_perl = perl_alloc();
369 perl_construct(my_perl); 374 perl_construct(my_perl);
370 375
371 if (perl_parse(my_perl, xs_init, 2, (char **)command_line, 376 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
372 (char **)NULL)) 377 (char **)NULL)) {
373 return -1; 378 err = -1;
379 goto error;
380 }
374 381
375 perl_run(my_perl); 382 if (perl_run(my_perl)) {
376 if (SvTRUE(ERRSV)) 383 err = -1;
377 return -1; 384 goto error;
385 }
386
387 if (SvTRUE(ERRSV)) {
388 err = -1;
389 goto error;
390 }
378 391
379 run_start_sub(); 392 run_start_sub();
380 393
394 free(command_line);
381 fprintf(stderr, "perf trace started with Perl script %s\n\n", script); 395 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
382
383 return 0; 396 return 0;
397error:
398 perl_free(my_perl);
399 free(command_line);
400
401 return err;
384} 402}
385 403
386/* 404/*
@@ -579,7 +597,9 @@ static void print_unsupported_msg(void)
579 "\n etc.\n"); 597 "\n etc.\n");
580} 598}
581 599
582static int perl_start_script_unsupported(const char *script __unused) 600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
583{ 603{
584 print_unsupported_msg(); 604 print_unsupported_msg();
585 605
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 81698d5e6503..6ad405620c9b 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -270,7 +270,7 @@ enum trace_flag_type {
270 270
271struct scripting_ops { 271struct scripting_ops {
272 const char *name; 272 const char *name;
273 int (*start_script) (const char *); 273 int (*start_script) (const char *script, int argc, const char **argv);
274 int (*stop_script) (void); 274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size, 275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm); 276 unsigned long long nsecs, char *comm);