perf test: Allow running just a subset of the available tests
[deliverable/linux.git] / tools / perf / util / event.c
CommitLineData
234fbbf5
ACM
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
c410a338 4#include "sort.h"
234fbbf5 5#include "string.h"
c410a338 6#include "strlist.h"
62daacb5 7#include "thread.h"
7c940c18 8#include "thread_map.h"
234fbbf5 9
8115d60c 10static const char *perf_event__names[] = {
3cb6d154
FW
11 [0] = "TOTAL",
12 [PERF_RECORD_MMAP] = "MMAP",
13 [PERF_RECORD_LOST] = "LOST",
14 [PERF_RECORD_COMM] = "COMM",
15 [PERF_RECORD_EXIT] = "EXIT",
16 [PERF_RECORD_THROTTLE] = "THROTTLE",
17 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
18 [PERF_RECORD_FORK] = "FORK",
19 [PERF_RECORD_READ] = "READ",
20 [PERF_RECORD_SAMPLE] = "SAMPLE",
21 [PERF_RECORD_HEADER_ATTR] = "ATTR",
22 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
23 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
24 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
25 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
c8446b9b
ACM
26};
27
8115d60c 28const char *perf_event__name(unsigned int id)
3835bc00 29{
8115d60c 30 if (id >= ARRAY_SIZE(perf_event__names))
3835bc00 31 return "INVALID";
8115d60c 32 if (!perf_event__names[id])
3835bc00 33 return "UNKNOWN";
8115d60c 34 return perf_event__names[id];
3835bc00
TG
35}
36
8d50e5b4 37static struct perf_sample synth_sample = {
640c03ce
ACM
38 .pid = -1,
39 .tid = -1,
40 .time = -1,
41 .stream_id = -1,
42 .cpu = -1,
43 .period = 1,
44};
45
45694aa7 46static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
d20deb64 47 union perf_event *event, pid_t pid,
8115d60c 48 int full, perf_event__handler_t process,
743eb868 49 struct machine *machine)
234fbbf5 50{
234fbbf5
ACM
51 char filename[PATH_MAX];
52 char bf[BUFSIZ];
53 FILE *fp;
54 size_t size = 0;
55 DIR *tasks;
56 struct dirent dirent, *next;
57 pid_t tgid = 0;
58
59 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
60
61 fp = fopen(filename, "r");
62 if (fp == NULL) {
63out_race:
64 /*
65 * We raced with a task exiting - just return:
66 */
67 pr_debug("couldn't open %s\n", filename);
68 return 0;
69 }
70
9c90a61c
ACM
71 memset(&event->comm, 0, sizeof(event->comm));
72
73 while (!event->comm.comm[0] || !event->comm.pid) {
74 if (fgets(bf, sizeof(bf), fp) == NULL) {
75 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
76 goto out;
77 }
234fbbf5
ACM
78
79 if (memcmp(bf, "Name:", 5) == 0) {
80 char *name = bf + 5;
81 while (*name && isspace(*name))
82 ++name;
83 size = strlen(name) - 1;
9c90a61c 84 memcpy(event->comm.comm, name, size++);
234fbbf5
ACM
85 } else if (memcmp(bf, "Tgid:", 5) == 0) {
86 char *tgids = bf + 5;
87 while (*tgids && isspace(*tgids))
88 ++tgids;
9c90a61c 89 tgid = event->comm.pid = atoi(tgids);
234fbbf5
ACM
90 }
91 }
92
9c90a61c 93 event->comm.header.type = PERF_RECORD_COMM;
234fbbf5 94 size = ALIGN(size, sizeof(u64));
743eb868 95 memset(event->comm.comm + size, 0, machine->id_hdr_size);
9c90a61c
ACM
96 event->comm.header.size = (sizeof(event->comm) -
97 (sizeof(event->comm.comm) - size) +
743eb868 98 machine->id_hdr_size);
234fbbf5 99 if (!full) {
9c90a61c 100 event->comm.tid = pid;
234fbbf5 101
45694aa7 102 process(tool, event, &synth_sample, machine);
9c90a61c 103 goto out;
234fbbf5
ACM
104 }
105
106 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
107
108 tasks = opendir(filename);
109 if (tasks == NULL)
110 goto out_race;
111
112 while (!readdir_r(tasks, &dirent, &next) && next) {
113 char *end;
114 pid = strtol(dirent.d_name, &end, 10);
115 if (*end)
116 continue;
117
9c90a61c 118 event->comm.tid = pid;
234fbbf5 119
45694aa7 120 process(tool, event, &synth_sample, machine);
234fbbf5 121 }
234fbbf5 122
9c90a61c
ACM
123 closedir(tasks);
124out:
234fbbf5 125 fclose(fp);
234fbbf5 126
9c90a61c 127 return tgid;
234fbbf5
ACM
128}
129
45694aa7 130static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
d20deb64 131 union perf_event *event,
8115d60c
ACM
132 pid_t pid, pid_t tgid,
133 perf_event__handler_t process,
743eb868 134 struct machine *machine)
234fbbf5
ACM
135{
136 char filename[PATH_MAX];
137 FILE *fp;
138
139 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
140
141 fp = fopen(filename, "r");
142 if (fp == NULL) {
143 /*
144 * We raced with a task exiting - just return:
145 */
146 pr_debug("couldn't open %s\n", filename);
147 return -1;
148 }
149
9c90a61c
ACM
150 event->header.type = PERF_RECORD_MMAP;
151 /*
152 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
153 */
154 event->header.misc = PERF_RECORD_MISC_USER;
155
234fbbf5
ACM
156 while (1) {
157 char bf[BUFSIZ], *pbf = bf;
234fbbf5
ACM
158 int n;
159 size_t size;
160 if (fgets(bf, sizeof(bf), fp) == NULL)
161 break;
162
163 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
9c90a61c 164 n = hex2u64(pbf, &event->mmap.start);
234fbbf5
ACM
165 if (n < 0)
166 continue;
167 pbf += n + 1;
9c90a61c 168 n = hex2u64(pbf, &event->mmap.len);
234fbbf5
ACM
169 if (n < 0)
170 continue;
171 pbf += n + 3;
172 if (*pbf == 'x') { /* vm_exec */
6a0e55d8 173 char anonstr[] = "//anon\n";
234fbbf5
ACM
174 char *execname = strchr(bf, '/');
175
176 /* Catch VDSO */
177 if (execname == NULL)
178 execname = strstr(bf, "[vdso]");
179
6a0e55d8
AB
180 /* Catch anonymous mmaps */
181 if ((execname == NULL) && !strstr(bf, "["))
182 execname = anonstr;
183
234fbbf5
ACM
184 if (execname == NULL)
185 continue;
186
4af8b35d 187 pbf += 3;
9c90a61c 188 n = hex2u64(pbf, &event->mmap.pgoff);
4af8b35d 189
234fbbf5
ACM
190 size = strlen(execname);
191 execname[size - 1] = '\0'; /* Remove \n */
9c90a61c 192 memcpy(event->mmap.filename, execname, size);
234fbbf5 193 size = ALIGN(size, sizeof(u64));
9c90a61c
ACM
194 event->mmap.len -= event->mmap.start;
195 event->mmap.header.size = (sizeof(event->mmap) -
196 (sizeof(event->mmap.filename) - size));
743eb868
ACM
197 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
198 event->mmap.header.size += machine->id_hdr_size;
9c90a61c
ACM
199 event->mmap.pid = tgid;
200 event->mmap.tid = pid;
201
45694aa7 202 process(tool, event, &synth_sample, machine);
234fbbf5
ACM
203 }
204 }
205
206 fclose(fp);
207 return 0;
208}
209
45694aa7 210int perf_event__synthesize_modules(struct perf_tool *tool,
d20deb64 211 perf_event__handler_t process,
8115d60c 212 struct machine *machine)
b7cece76
ACM
213{
214 struct rb_node *nd;
23346f21 215 struct map_groups *kmaps = &machine->kmaps;
8115d60c 216 union perf_event *event = zalloc((sizeof(event->mmap) +
743eb868 217 machine->id_hdr_size));
9c90a61c
ACM
218 if (event == NULL) {
219 pr_debug("Not enough memory synthesizing mmap event "
220 "for kernel modules\n");
221 return -1;
222 }
223
224 event->header.type = PERF_RECORD_MMAP;
b7cece76 225
a1645ce1
ZY
226 /*
227 * kernel uses 0 for user space maps, see kernel/perf_event.c
228 * __perf_event_mmap
229 */
23346f21 230 if (machine__is_host(machine))
9c90a61c 231 event->header.misc = PERF_RECORD_MISC_KERNEL;
a1645ce1 232 else
9c90a61c 233 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
a1645ce1
ZY
234
235 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
b7cece76 236 nd; nd = rb_next(nd)) {
b7cece76
ACM
237 size_t size;
238 struct map *pos = rb_entry(nd, struct map, rb_node);
239
240 if (pos->dso->kernel)
241 continue;
242
243 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
9c90a61c
ACM
244 event->mmap.header.type = PERF_RECORD_MMAP;
245 event->mmap.header.size = (sizeof(event->mmap) -
246 (sizeof(event->mmap.filename) - size));
743eb868
ACM
247 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
248 event->mmap.header.size += machine->id_hdr_size;
9c90a61c
ACM
249 event->mmap.start = pos->start;
250 event->mmap.len = pos->end - pos->start;
251 event->mmap.pid = machine->pid;
252
253 memcpy(event->mmap.filename, pos->dso->long_name,
b7cece76 254 pos->dso->long_name_len + 1);
45694aa7 255 process(tool, event, &synth_sample, machine);
b7cece76
ACM
256 }
257
9c90a61c 258 free(event);
b7cece76
ACM
259 return 0;
260}
261
8115d60c
ACM
262static int __event__synthesize_thread(union perf_event *comm_event,
263 union perf_event *mmap_event,
264 pid_t pid, perf_event__handler_t process,
45694aa7 265 struct perf_tool *tool,
743eb868 266 struct machine *machine)
234fbbf5 267{
45694aa7 268 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, 1,
743eb868 269 process, machine);
234fbbf5
ACM
270 if (tgid == -1)
271 return -1;
45694aa7 272 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
743eb868 273 process, machine);
234fbbf5
ACM
274}
275
45694aa7 276int perf_event__synthesize_thread_map(struct perf_tool *tool,
d20deb64 277 struct thread_map *threads,
7c940c18 278 perf_event__handler_t process,
743eb868 279 struct machine *machine)
9c90a61c 280{
8115d60c 281 union perf_event *comm_event, *mmap_event;
401b8e13 282 int err = -1, thread;
9c90a61c 283
743eb868 284 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
9c90a61c
ACM
285 if (comm_event == NULL)
286 goto out;
287
743eb868 288 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
9c90a61c
ACM
289 if (mmap_event == NULL)
290 goto out_free_comm;
291
401b8e13
ACM
292 err = 0;
293 for (thread = 0; thread < threads->nr; ++thread) {
294 if (__event__synthesize_thread(comm_event, mmap_event,
295 threads->map[thread],
45694aa7 296 process, tool, machine)) {
401b8e13
ACM
297 err = -1;
298 break;
299 }
300 }
9c90a61c
ACM
301 free(mmap_event);
302out_free_comm:
303 free(comm_event);
304out:
305 return err;
306}
307
45694aa7 308int perf_event__synthesize_threads(struct perf_tool *tool,
d20deb64 309 perf_event__handler_t process,
743eb868 310 struct machine *machine)
234fbbf5
ACM
311{
312 DIR *proc;
313 struct dirent dirent, *next;
8115d60c 314 union perf_event *comm_event, *mmap_event;
9c90a61c
ACM
315 int err = -1;
316
743eb868 317 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
9c90a61c
ACM
318 if (comm_event == NULL)
319 goto out;
320
743eb868 321 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
9c90a61c
ACM
322 if (mmap_event == NULL)
323 goto out_free_comm;
234fbbf5
ACM
324
325 proc = opendir("/proc");
9c90a61c
ACM
326 if (proc == NULL)
327 goto out_free_mmap;
234fbbf5
ACM
328
329 while (!readdir_r(proc, &dirent, &next) && next) {
330 char *end;
331 pid_t pid = strtol(dirent.d_name, &end, 10);
332
333 if (*end) /* only interested in proper numerical dirents */
334 continue;
335
9c90a61c 336 __event__synthesize_thread(comm_event, mmap_event, pid,
45694aa7 337 process, tool, machine);
234fbbf5
ACM
338 }
339
340 closedir(proc);
9c90a61c
ACM
341 err = 0;
342out_free_mmap:
343 free(mmap_event);
344out_free_comm:
345 free(comm_event);
346out:
347 return err;
234fbbf5 348}
62daacb5 349
56b03f3c
ACM
350struct process_symbol_args {
351 const char *name;
352 u64 start;
353};
354
3b01a413
ACM
355static int find_symbol_cb(void *arg, const char *name, char type,
356 u64 start, u64 end __used)
56b03f3c
ACM
357{
358 struct process_symbol_args *args = arg;
359
881516eb
ACM
360 /*
361 * Must be a function or at least an alias, as in PARISC64, where "_text" is
362 * an 'A' to the same address as "_stext".
363 */
364 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
365 type == 'A') || strcmp(name, args->name))
56b03f3c
ACM
366 return 0;
367
368 args->start = start;
369 return 1;
370}
371
45694aa7 372int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
d20deb64 373 perf_event__handler_t process,
8115d60c
ACM
374 struct machine *machine,
375 const char *symbol_name)
56b03f3c
ACM
376{
377 size_t size;
a1645ce1
ZY
378 const char *filename, *mmap_name;
379 char path[PATH_MAX];
380 char name_buff[PATH_MAX];
381 struct map *map;
9c90a61c 382 int err;
56b03f3c
ACM
383 /*
384 * We should get this from /sys/kernel/sections/.text, but till that is
385 * available use this, and after it is use this as a fallback for older
386 * kernels.
387 */
388 struct process_symbol_args args = { .name = symbol_name, };
8115d60c 389 union perf_event *event = zalloc((sizeof(event->mmap) +
743eb868 390 machine->id_hdr_size));
9c90a61c
ACM
391 if (event == NULL) {
392 pr_debug("Not enough memory synthesizing mmap event "
393 "for kernel modules\n");
394 return -1;
395 }
56b03f3c 396
48ea8f54 397 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
23346f21 398 if (machine__is_host(machine)) {
a1645ce1
ZY
399 /*
400 * kernel uses PERF_RECORD_MISC_USER for user space maps,
401 * see kernel/perf_event.c __perf_event_mmap
402 */
9c90a61c 403 event->header.misc = PERF_RECORD_MISC_KERNEL;
a1645ce1
ZY
404 filename = "/proc/kallsyms";
405 } else {
9c90a61c 406 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
23346f21 407 if (machine__is_default_guest(machine))
a1645ce1
ZY
408 filename = (char *) symbol_conf.default_guest_kallsyms;
409 else {
23346f21 410 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
a1645ce1
ZY
411 filename = path;
412 }
413 }
414
415 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
56b03f3c
ACM
416 return -ENOENT;
417
23346f21 418 map = machine->vmlinux_maps[MAP__FUNCTION];
9c90a61c 419 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
a1645ce1 420 "%s%s", mmap_name, symbol_name) + 1;
56b03f3c 421 size = ALIGN(size, sizeof(u64));
9c90a61c
ACM
422 event->mmap.header.type = PERF_RECORD_MMAP;
423 event->mmap.header.size = (sizeof(event->mmap) -
743eb868 424 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
9c90a61c
ACM
425 event->mmap.pgoff = args.start;
426 event->mmap.start = map->start;
427 event->mmap.len = map->end - event->mmap.start;
428 event->mmap.pid = machine->pid;
429
45694aa7 430 err = process(tool, event, &synth_sample, machine);
9c90a61c
ACM
431 free(event);
432
433 return err;
56b03f3c
ACM
434}
435
45694aa7 436int perf_event__process_comm(struct perf_tool *tool __used,
d20deb64 437 union perf_event *event,
8115d60c 438 struct perf_sample *sample __used,
743eb868 439 struct machine *machine)
62daacb5 440{
743eb868 441 struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
62daacb5 442
8115d60c 443 dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid);
62daacb5 444
d7603d51 445 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
62daacb5
ACM
446 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
447 return -1;
448 }
449
450 return 0;
451}
452
45694aa7 453int perf_event__process_lost(struct perf_tool *tool __used,
d20deb64 454 union perf_event *event,
8115d60c 455 struct perf_sample *sample __used,
743eb868 456 struct machine *machine __used)
62daacb5 457{
9486aa38 458 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
8115d60c 459 event->lost.id, event->lost.lost);
62daacb5
ACM
460 return 0;
461}
462
8115d60c
ACM
463static void perf_event__set_kernel_mmap_len(union perf_event *event,
464 struct map **maps)
a1645ce1 465{
8115d60c
ACM
466 maps[MAP__FUNCTION]->start = event->mmap.start;
467 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
a1645ce1
ZY
468 /*
469 * Be a bit paranoid here, some perf.data file came with
470 * a zero sized synthesized MMAP event for the kernel.
471 */
472 if (maps[MAP__FUNCTION]->end == 0)
9d1faba5 473 maps[MAP__FUNCTION]->end = ~0ULL;
a1645ce1
ZY
474}
475
45694aa7 476static int perf_event__process_kernel_mmap(struct perf_tool *tool __used,
d20deb64 477 union perf_event *event,
743eb868 478 struct machine *machine)
62daacb5 479{
56b03f3c 480 struct map *map;
a1645ce1 481 char kmmap_prefix[PATH_MAX];
a1645ce1
ZY
482 enum dso_kernel_type kernel_type;
483 bool is_kernel_mmap;
484
48ea8f54 485 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
23346f21 486 if (machine__is_host(machine))
a1645ce1
ZY
487 kernel_type = DSO_TYPE_KERNEL;
488 else
489 kernel_type = DSO_TYPE_GUEST_KERNEL;
62daacb5 490
8115d60c 491 is_kernel_mmap = memcmp(event->mmap.filename,
a1645ce1
ZY
492 kmmap_prefix,
493 strlen(kmmap_prefix)) == 0;
8115d60c
ACM
494 if (event->mmap.filename[0] == '/' ||
495 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
b7cece76 496
a1645ce1
ZY
497 char short_module_name[1024];
498 char *name, *dot;
b7cece76 499
8115d60c
ACM
500 if (event->mmap.filename[0] == '/') {
501 name = strrchr(event->mmap.filename, '/');
b7cece76
ACM
502 if (name == NULL)
503 goto out_problem;
504
505 ++name; /* skip / */
506 dot = strrchr(name, '.');
507 if (dot == NULL)
508 goto out_problem;
b7cece76 509 snprintf(short_module_name, sizeof(short_module_name),
a1645ce1 510 "[%.*s]", (int)(dot - name), name);
b7cece76 511 strxfrchar(short_module_name, '-', '_');
a1645ce1 512 } else
8115d60c 513 strcpy(short_module_name, event->mmap.filename);
a1645ce1 514
8115d60c
ACM
515 map = machine__new_module(machine, event->mmap.start,
516 event->mmap.filename);
a1645ce1
ZY
517 if (map == NULL)
518 goto out_problem;
519
520 name = strdup(short_module_name);
521 if (name == NULL)
522 goto out_problem;
523
524 map->dso->short_name = name;
6e406257 525 map->dso->sname_alloc = 1;
8115d60c 526 map->end = map->start + event->mmap.len;
a1645ce1 527 } else if (is_kernel_mmap) {
8115d60c 528 const char *symbol_name = (event->mmap.filename +
a1645ce1
ZY
529 strlen(kmmap_prefix));
530 /*
531 * Should be there already, from the build-id table in
532 * the header.
533 */
23346f21
ACM
534 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
535 kmmap_prefix);
a1645ce1
ZY
536 if (kernel == NULL)
537 goto out_problem;
538
539 kernel->kernel = kernel_type;
d28c6223 540 if (__machine__create_kernel_maps(machine, kernel) < 0)
a1645ce1
ZY
541 goto out_problem;
542
8115d60c 543 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
ec80fde7
ACM
544
545 /*
546 * Avoid using a zero address (kptr_restrict) for the ref reloc
547 * symbol. Effectively having zero here means that at record
548 * time /proc/sys/kernel/kptr_restrict was non zero.
549 */
550 if (event->mmap.pgoff != 0) {
743eb868
ACM
551 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
552 symbol_name,
553 event->mmap.pgoff);
ec80fde7
ACM
554 }
555
23346f21 556 if (machine__is_default_guest(machine)) {
b7cece76 557 /*
a1645ce1 558 * preload dso of guest kernel and modules
b7cece76 559 */
23346f21
ACM
560 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
561 NULL);
a1645ce1
ZY
562 }
563 }
564 return 0;
565out_problem:
566 return -1;
567}
b7cece76 568
45694aa7 569int perf_event__process_mmap(struct perf_tool *tool,
d20deb64 570 union perf_event *event,
8115d60c 571 struct perf_sample *sample __used,
743eb868 572 struct machine *machine)
a1645ce1 573{
a1645ce1
ZY
574 struct thread *thread;
575 struct map *map;
8115d60c 576 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
a1645ce1 577 int ret = 0;
b7cece76 578
9486aa38 579 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
8115d60c
ACM
580 event->mmap.pid, event->mmap.tid, event->mmap.start,
581 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
a1645ce1
ZY
582
583 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
584 cpumode == PERF_RECORD_MISC_KERNEL) {
45694aa7 585 ret = perf_event__process_kernel_mmap(tool, event, machine);
a1645ce1
ZY
586 if (ret < 0)
587 goto out_problem;
56b03f3c
ACM
588 return 0;
589 }
590
743eb868 591 thread = machine__findnew_thread(machine, event->mmap.pid);
d65a458b
ACM
592 if (thread == NULL)
593 goto out_problem;
8115d60c
ACM
594 map = map__new(&machine->user_dsos, event->mmap.start,
595 event->mmap.len, event->mmap.pgoff,
596 event->mmap.pid, event->mmap.filename,
361d1346 597 MAP__FUNCTION);
d65a458b 598 if (map == NULL)
b7cece76
ACM
599 goto out_problem;
600
601 thread__insert_map(thread, map);
602 return 0;
62daacb5 603
b7cece76
ACM
604out_problem:
605 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
62daacb5
ACM
606 return 0;
607}
608
45694aa7 609int perf_event__process_task(struct perf_tool *tool __used,
d20deb64 610 union perf_event *event,
8115d60c 611 struct perf_sample *sample __used,
743eb868 612 struct machine *machine)
62daacb5 613{
743eb868
ACM
614 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
615 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
62daacb5 616
8115d60c
ACM
617 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
618 event->fork.ppid, event->fork.ptid);
62daacb5 619
8115d60c 620 if (event->header.type == PERF_RECORD_EXIT) {
743eb868 621 machine__remove_thread(machine, thread);
62daacb5 622 return 0;
720a3aeb 623 }
62daacb5
ACM
624
625 if (thread == NULL || parent == NULL ||
626 thread__fork(thread, parent) < 0) {
627 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
628 return -1;
629 }
630
631 return 0;
632}
1ed091c4 633
45694aa7 634int perf_event__process(struct perf_tool *tool, union perf_event *event,
743eb868 635 struct perf_sample *sample, struct machine *machine)
b83f920e
SD
636{
637 switch (event->header.type) {
638 case PERF_RECORD_COMM:
45694aa7 639 perf_event__process_comm(tool, event, sample, machine);
b83f920e
SD
640 break;
641 case PERF_RECORD_MMAP:
45694aa7 642 perf_event__process_mmap(tool, event, sample, machine);
b83f920e
SD
643 break;
644 case PERF_RECORD_FORK:
645 case PERF_RECORD_EXIT:
45694aa7 646 perf_event__process_task(tool, event, sample, machine);
b83f920e 647 break;
ef2bf6d0 648 case PERF_RECORD_LOST:
45694aa7 649 perf_event__process_lost(tool, event, sample, machine);
b83f920e
SD
650 default:
651 break;
652 }
653
654 return 0;
655}
656
59ee68ec 657void thread__find_addr_map(struct thread *self,
743eb868
ACM
658 struct machine *machine, u8 cpumode,
659 enum map_type type, u64 addr,
59ee68ec 660 struct addr_location *al)
1ed091c4 661{
9958e1f0 662 struct map_groups *mg = &self->mg;
1ed091c4 663
9958e1f0 664 al->thread = self;
1ed091c4 665 al->addr = addr;
a1645ce1
ZY
666 al->cpumode = cpumode;
667 al->filtered = false;
1ed091c4 668
743eb868
ACM
669 if (machine == NULL) {
670 al->map = NULL;
671 return;
672 }
673
a1645ce1 674 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
1ed091c4 675 al->level = 'k';
23346f21 676 mg = &machine->kmaps;
a1645ce1 677 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
1ed091c4 678 al->level = '.';
a1645ce1
ZY
679 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
680 al->level = 'g';
23346f21 681 mg = &machine->kmaps;
a1645ce1
ZY
682 } else {
683 /*
684 * 'u' means guest os user space.
685 * TODO: We don't support guest user space. Might support late.
686 */
687 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
688 al->level = 'u';
689 else
690 al->level = 'H';
1ed091c4 691 al->map = NULL;
a1645ce1
ZY
692
693 if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
694 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
695 !perf_guest)
696 al->filtered = true;
697 if ((cpumode == PERF_RECORD_MISC_USER ||
698 cpumode == PERF_RECORD_MISC_KERNEL) &&
699 !perf_host)
700 al->filtered = true;
701
1ed091c4
ACM
702 return;
703 }
704try_again:
9958e1f0 705 al->map = map_groups__find(mg, type, al->addr);
1ed091c4
ACM
706 if (al->map == NULL) {
707 /*
708 * If this is outside of all known maps, and is a negative
709 * address, try to look it up in the kernel dso, as it might be
710 * a vsyscall or vdso (which executes in user-mode).
711 *
712 * XXX This is nasty, we should have a symbol list in the
713 * "[vdso]" dso, but for now lets use the old trick of looking
714 * in the whole kernel symbol list.
715 */
a1645ce1 716 if ((long long)al->addr < 0 &&
6c6804fb 717 cpumode == PERF_RECORD_MISC_USER &&
23346f21
ACM
718 machine && mg != &machine->kmaps) {
719 mg = &machine->kmaps;
1ed091c4
ACM
720 goto try_again;
721 }
59ee68ec 722 } else
1ed091c4 723 al->addr = al->map->map_ip(al->map, al->addr);
59ee68ec
ACM
724}
725
743eb868
ACM
726void thread__find_addr_location(struct thread *thread, struct machine *machine,
727 u8 cpumode, enum map_type type, u64 addr,
59ee68ec
ACM
728 struct addr_location *al,
729 symbol_filter_t filter)
730{
743eb868 731 thread__find_addr_map(thread, machine, cpumode, type, addr, al);
59ee68ec 732 if (al->map != NULL)
9de89fe7 733 al->sym = map__find_symbol(al->map, al->addr, filter);
59ee68ec
ACM
734 else
735 al->sym = NULL;
1ed091c4
ACM
736}
737
8115d60c 738int perf_event__preprocess_sample(const union perf_event *event,
743eb868 739 struct machine *machine,
8115d60c
ACM
740 struct addr_location *al,
741 struct perf_sample *sample,
742 symbol_filter_t filter)
1ed091c4 743{
8115d60c 744 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
743eb868 745 struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
41a37e20 746
1ed091c4
ACM
747 if (thread == NULL)
748 return -1;
749
c410a338
ACM
750 if (symbol_conf.comm_list &&
751 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
752 goto out_filtered;
753
1ed091c4 754 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1f626bc3 755 /*
743eb868 756 * Have we already created the kernel maps for this machine?
1f626bc3
ACM
757 *
758 * This should have happened earlier, when we processed the kernel MMAP
759 * events, but for older perf.data files there was no such thing, so do
760 * it now.
761 */
762 if (cpumode == PERF_RECORD_MISC_KERNEL &&
743eb868
ACM
763 machine->vmlinux_maps[MAP__FUNCTION] == NULL)
764 machine__create_kernel_maps(machine);
1ed091c4 765
743eb868
ACM
766 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
767 event->ip.ip, al);
1ed091c4
ACM
768 dump_printf(" ...... dso: %s\n",
769 al->map ? al->map->dso->long_name :
770 al->level == 'H' ? "[hypervisor]" : "<not found>");
96415e4d 771 al->sym = NULL;
8d50e5b4 772 al->cpu = sample->cpu;
96415e4d
ACM
773
774 if (al->map) {
775 if (symbol_conf.dso_list &&
776 (!al->map || !al->map->dso ||
777 !(strlist__has_entry(symbol_conf.dso_list,
778 al->map->dso->short_name) ||
779 (al->map->dso->short_name != al->map->dso->long_name &&
780 strlist__has_entry(symbol_conf.dso_list,
781 al->map->dso->long_name)))))
782 goto out_filtered;
96415e4d
ACM
783
784 al->sym = map__find_symbol(al->map, al->addr, filter);
785 }
c410a338
ACM
786
787 if (symbol_conf.sym_list && al->sym &&
788 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
789 goto out_filtered;
790
c410a338
ACM
791 return 0;
792
793out_filtered:
794 al->filtered = true;
1ed091c4
ACM
795 return 0;
796}
This page took 0.309815 seconds and 5 git commands to generate.