aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/event.c
diff options
context:
space:
mode:
authorZhang, Yanmin <yanmin_zhang@linux.intel.com>2010-04-19 01:32:50 -0400
committerAvi Kivity <avi@redhat.com>2010-04-19 05:37:24 -0400
commita1645ce12adb6c9cc9e19d7695466204e3f017fe (patch)
tree5d31aaaf534997e6e9cebc07f38eca35f76986cf /tools/perf/util/event.c
parentff9d07a0e7ce756a183e7c2e483aec452ee6b574 (diff)
perf: 'perf kvm' tool for monitoring guest performance from host
Here is the patch of userspace perf tool. Signed-off-by: Zhang Yanmin <yanmin_zhang@linux.intel.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'tools/perf/util/event.c')
-rw-r--r--tools/perf/util/event.c280
1 files changed, 205 insertions, 75 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 571fb25f7eb9..e3fa8d3d11b4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -112,7 +112,11 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
112 event_t ev = { 112 event_t ev = {
113 .header = { 113 .header = {
114 .type = PERF_RECORD_MMAP, 114 .type = PERF_RECORD_MMAP,
115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */ 115 /*
116 * Just like the kernel, see __perf_event_mmap
117 * in kernel/perf_event.c
118 */
119 .misc = PERF_RECORD_MISC_USER,
116 }, 120 },
117 }; 121 };
118 int n; 122 int n;
@@ -167,11 +171,23 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
167} 171}
168 172
169int event__synthesize_modules(event__handler_t process, 173int event__synthesize_modules(event__handler_t process,
170 struct perf_session *session) 174 struct perf_session *session,
175 struct kernel_info *kerninfo)
171{ 176{
172 struct rb_node *nd; 177 struct rb_node *nd;
178 struct map_groups *kmaps = &kerninfo->kmaps;
179 u16 misc;
173 180
174 for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]); 181 /*
182 * kernel uses 0 for user space maps, see kernel/perf_event.c
183 * __perf_event_mmap
184 */
185 if (is_host_kernel(kerninfo))
186 misc = PERF_RECORD_MISC_KERNEL;
187 else
188 misc = PERF_RECORD_MISC_GUEST_KERNEL;
189
190 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
175 nd; nd = rb_next(nd)) { 191 nd; nd = rb_next(nd)) {
176 event_t ev; 192 event_t ev;
177 size_t size; 193 size_t size;
@@ -182,12 +198,13 @@ int event__synthesize_modules(event__handler_t process,
182 198
183 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 199 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
184 memset(&ev, 0, sizeof(ev)); 200 memset(&ev, 0, sizeof(ev));
185 ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */ 201 ev.mmap.header.misc = misc;
186 ev.mmap.header.type = PERF_RECORD_MMAP; 202 ev.mmap.header.type = PERF_RECORD_MMAP;
187 ev.mmap.header.size = (sizeof(ev.mmap) - 203 ev.mmap.header.size = (sizeof(ev.mmap) -
188 (sizeof(ev.mmap.filename) - size)); 204 (sizeof(ev.mmap.filename) - size));
189 ev.mmap.start = pos->start; 205 ev.mmap.start = pos->start;
190 ev.mmap.len = pos->end - pos->start; 206 ev.mmap.len = pos->end - pos->start;
207 ev.mmap.pid = kerninfo->pid;
191 208
192 memcpy(ev.mmap.filename, pos->dso->long_name, 209 memcpy(ev.mmap.filename, pos->dso->long_name,
193 pos->dso->long_name_len + 1); 210 pos->dso->long_name_len + 1);
@@ -250,13 +267,18 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
250 267
251int event__synthesize_kernel_mmap(event__handler_t process, 268int event__synthesize_kernel_mmap(event__handler_t process,
252 struct perf_session *session, 269 struct perf_session *session,
270 struct kernel_info *kerninfo,
253 const char *symbol_name) 271 const char *symbol_name)
254{ 272{
255 size_t size; 273 size_t size;
274 const char *filename, *mmap_name;
275 char path[PATH_MAX];
276 char name_buff[PATH_MAX];
277 struct map *map;
278
256 event_t ev = { 279 event_t ev = {
257 .header = { 280 .header = {
258 .type = PERF_RECORD_MMAP, 281 .type = PERF_RECORD_MMAP,
259 .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
260 }, 282 },
261 }; 283 };
262 /* 284 /*
@@ -266,16 +288,37 @@ int event__synthesize_kernel_mmap(event__handler_t process,
266 */ 288 */
267 struct process_symbol_args args = { .name = symbol_name, }; 289 struct process_symbol_args args = { .name = symbol_name, };
268 290
269 if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0) 291 mmap_name = kern_mmap_name(kerninfo, name_buff);
292 if (is_host_kernel(kerninfo)) {
293 /*
294 * kernel uses PERF_RECORD_MISC_USER for user space maps,
295 * see kernel/perf_event.c __perf_event_mmap
296 */
297 ev.header.misc = PERF_RECORD_MISC_KERNEL;
298 filename = "/proc/kallsyms";
299 } else {
300 ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
301 if (is_default_guest(kerninfo))
302 filename = (char *) symbol_conf.default_guest_kallsyms;
303 else {
304 sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir);
305 filename = path;
306 }
307 }
308
309 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
270 return -ENOENT; 310 return -ENOENT;
271 311
312 map = kerninfo->vmlinux_maps[MAP__FUNCTION];
272 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), 313 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
273 "[kernel.kallsyms.%s]", symbol_name) + 1; 314 "%s%s", mmap_name, symbol_name) + 1;
274 size = ALIGN(size, sizeof(u64)); 315 size = ALIGN(size, sizeof(u64));
275 ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size)); 316 ev.mmap.header.size = (sizeof(ev.mmap) -
317 (sizeof(ev.mmap.filename) - size));
276 ev.mmap.pgoff = args.start; 318 ev.mmap.pgoff = args.start;
277 ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start; 319 ev.mmap.start = map->start;
278 ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ; 320 ev.mmap.len = map->end - ev.mmap.start;
321 ev.mmap.pid = kerninfo->pid;
279 322
280 return process(&ev, session); 323 return process(&ev, session);
281} 324}
@@ -329,22 +372,50 @@ int event__process_lost(event_t *self, struct perf_session *session)
329 return 0; 372 return 0;
330} 373}
331 374
332int event__process_mmap(event_t *self, struct perf_session *session) 375static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
376{
377 maps[MAP__FUNCTION]->start = self->mmap.start;
378 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
379 /*
380 * Be a bit paranoid here, some perf.data file came with
381 * a zero sized synthesized MMAP event for the kernel.
382 */
383 if (maps[MAP__FUNCTION]->end == 0)
384 maps[MAP__FUNCTION]->end = ~0UL;
385}
386
387static int event__process_kernel_mmap(event_t *self,
388 struct perf_session *session)
333{ 389{
334 struct thread *thread;
335 struct map *map; 390 struct map *map;
391 char kmmap_prefix[PATH_MAX];
392 struct kernel_info *kerninfo;
393 enum dso_kernel_type kernel_type;
394 bool is_kernel_mmap;
395
396 kerninfo = kerninfo__findnew(&session->kerninfo_root, self->mmap.pid);
397 if (!kerninfo) {
398 pr_err("Can't find id %d's kerninfo\n", self->mmap.pid);
399 goto out_problem;
400 }
336 401
337 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n", 402 kern_mmap_name(kerninfo, kmmap_prefix);
338 self->mmap.pid, self->mmap.tid, self->mmap.start, 403 if (is_host_kernel(kerninfo))
339 self->mmap.len, self->mmap.pgoff, self->mmap.filename); 404 kernel_type = DSO_TYPE_KERNEL;
405 else
406 kernel_type = DSO_TYPE_GUEST_KERNEL;
340 407
341 if (self->mmap.pid == 0) { 408 is_kernel_mmap = memcmp(self->mmap.filename,
342 static const char kmmap_prefix[] = "[kernel.kallsyms."; 409 kmmap_prefix,
410 strlen(kmmap_prefix)) == 0;
411 if (self->mmap.filename[0] == '/' ||
412 (!is_kernel_mmap && self->mmap.filename[0] == '[')) {
343 413
344 if (self->mmap.filename[0] == '/') { 414 char short_module_name[1024];
345 char short_module_name[1024]; 415 char *name, *dot;
346 char *name = strrchr(self->mmap.filename, '/'), *dot;
347 416
417 if (self->mmap.filename[0] == '/') {
418 name = strrchr(self->mmap.filename, '/');
348 if (name == NULL) 419 if (name == NULL)
349 goto out_problem; 420 goto out_problem;
350 421
@@ -352,59 +423,86 @@ int event__process_mmap(event_t *self, struct perf_session *session)
352 dot = strrchr(name, '.'); 423 dot = strrchr(name, '.');
353 if (dot == NULL) 424 if (dot == NULL)
354 goto out_problem; 425 goto out_problem;
355
356 snprintf(short_module_name, sizeof(short_module_name), 426 snprintf(short_module_name, sizeof(short_module_name),
357 "[%.*s]", (int)(dot - name), name); 427 "[%.*s]", (int)(dot - name), name);
358 strxfrchar(short_module_name, '-', '_'); 428 strxfrchar(short_module_name, '-', '_');
359 429 } else
360 map = perf_session__new_module_map(session, 430 strcpy(short_module_name, self->mmap.filename);
361 self->mmap.start, 431
362 self->mmap.filename); 432 map = map_groups__new_module(&kerninfo->kmaps,
363 if (map == NULL) 433 self->mmap.start,
364 goto out_problem; 434 self->mmap.filename,
365 435 kerninfo);
366 name = strdup(short_module_name); 436 if (map == NULL)
367 if (name == NULL) 437 goto out_problem;
368 goto out_problem; 438
369 439 name = strdup(short_module_name);
370 map->dso->short_name = name; 440 if (name == NULL)
371 map->end = map->start + self->mmap.len; 441 goto out_problem;
372 } else if (memcmp(self->mmap.filename, kmmap_prefix, 442
373 sizeof(kmmap_prefix) - 1) == 0) { 443 map->dso->short_name = name;
374 const char *symbol_name = (self->mmap.filename + 444 map->end = map->start + self->mmap.len;
375 sizeof(kmmap_prefix) - 1); 445 } else if (is_kernel_mmap) {
446 const char *symbol_name = (self->mmap.filename +
447 strlen(kmmap_prefix));
448 /*
449 * Should be there already, from the build-id table in
450 * the header.
451 */
452 struct dso *kernel = __dsos__findnew(&kerninfo->dsos__kernel,
453 kmmap_prefix);
454 if (kernel == NULL)
455 goto out_problem;
456
457 kernel->kernel = kernel_type;
458 if (__map_groups__create_kernel_maps(&kerninfo->kmaps,
459 kerninfo->vmlinux_maps, kernel) < 0)
460 goto out_problem;
461
462 event_set_kernel_mmap_len(kerninfo->vmlinux_maps, self);
463 perf_session__set_kallsyms_ref_reloc_sym(kerninfo->vmlinux_maps,
464 symbol_name,
465 self->mmap.pgoff);
466 if (is_default_guest(kerninfo)) {
376 /* 467 /*
377 * Should be there already, from the build-id table in 468 * preload dso of guest kernel and modules
378 * the header.
379 */ 469 */
380 struct dso *kernel = __dsos__findnew(&dsos__kernel, 470 dso__load(kernel,
381 "[kernel.kallsyms]"); 471 kerninfo->vmlinux_maps[MAP__FUNCTION],
382 if (kernel == NULL) 472 NULL);
383 goto out_problem; 473 }
384 474 }
385 kernel->kernel = 1; 475 return 0;
386 if (__perf_session__create_kernel_maps(session, kernel) < 0) 476out_problem:
387 goto out_problem; 477 return -1;
478}
388 479
389 session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start; 480int event__process_mmap(event_t *self, struct perf_session *session)
390 session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; 481{
391 /* 482 struct kernel_info *kerninfo;
392 * Be a bit paranoid here, some perf.data file came with 483 struct thread *thread;
393 * a zero sized synthesized MMAP event for the kernel. 484 struct map *map;
394 */ 485 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
395 if (session->vmlinux_maps[MAP__FUNCTION]->end == 0) 486 int ret = 0;
396 session->vmlinux_maps[MAP__FUNCTION]->end = ~0UL;
397 487
398 perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name, 488 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
399 self->mmap.pgoff); 489 self->mmap.pid, self->mmap.tid, self->mmap.start,
400 } 490 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
491
492 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
493 cpumode == PERF_RECORD_MISC_KERNEL) {
494 ret = event__process_kernel_mmap(self, session);
495 if (ret < 0)
496 goto out_problem;
401 return 0; 497 return 0;
402 } 498 }
403 499
404 thread = perf_session__findnew(session, self->mmap.pid); 500 thread = perf_session__findnew(session, self->mmap.pid);
405 map = map__new(self->mmap.start, self->mmap.len, self->mmap.pgoff, 501 kerninfo = kerninfo__findhost(&session->kerninfo_root);
406 self->mmap.pid, self->mmap.filename, MAP__FUNCTION, 502 map = map__new(&kerninfo->dsos__user, self->mmap.start,
407 session->cwd, session->cwdlen); 503 self->mmap.len, self->mmap.pgoff,
504 self->mmap.pid, self->mmap.filename,
505 MAP__FUNCTION, session->cwd, session->cwdlen);
408 506
409 if (thread == NULL || map == NULL) 507 if (thread == NULL || map == NULL)
410 goto out_problem; 508 goto out_problem;
@@ -444,22 +542,52 @@ int event__process_task(event_t *self, struct perf_session *session)
444 542
445void thread__find_addr_map(struct thread *self, 543void thread__find_addr_map(struct thread *self,
446 struct perf_session *session, u8 cpumode, 544 struct perf_session *session, u8 cpumode,
447 enum map_type type, u64 addr, 545 enum map_type type, pid_t pid, u64 addr,
448 struct addr_location *al) 546 struct addr_location *al)
449{ 547{
450 struct map_groups *mg = &self->mg; 548 struct map_groups *mg = &self->mg;
549 struct kernel_info *kerninfo = NULL;
451 550
452 al->thread = self; 551 al->thread = self;
453 al->addr = addr; 552 al->addr = addr;
553 al->cpumode = cpumode;
554 al->filtered = false;
454 555
455 if (cpumode == PERF_RECORD_MISC_KERNEL) { 556 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
456 al->level = 'k'; 557 al->level = 'k';
457 mg = &session->kmaps; 558 kerninfo = kerninfo__findhost(&session->kerninfo_root);
458 } else if (cpumode == PERF_RECORD_MISC_USER) 559 mg = &kerninfo->kmaps;
560 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
459 al->level = '.'; 561 al->level = '.';
460 else { 562 kerninfo = kerninfo__findhost(&session->kerninfo_root);
461 al->level = 'H'; 563 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
564 al->level = 'g';
565 kerninfo = kerninfo__find(&session->kerninfo_root, pid);
566 if (!kerninfo) {
567 al->map = NULL;
568 return;
569 }
570 mg = &kerninfo->kmaps;
571 } else {
572 /*
573 * 'u' means guest os user space.
574 * TODO: We don't support guest user space. Might support late.
575 */
576 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
577 al->level = 'u';
578 else
579 al->level = 'H';
462 al->map = NULL; 580 al->map = NULL;
581
582 if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
583 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
584 !perf_guest)
585 al->filtered = true;
586 if ((cpumode == PERF_RECORD_MISC_USER ||
587 cpumode == PERF_RECORD_MISC_KERNEL) &&
588 !perf_host)
589 al->filtered = true;
590
463 return; 591 return;
464 } 592 }
465try_again: 593try_again:
@@ -474,8 +602,11 @@ try_again:
474 * "[vdso]" dso, but for now lets use the old trick of looking 602 * "[vdso]" dso, but for now lets use the old trick of looking
475 * in the whole kernel symbol list. 603 * in the whole kernel symbol list.
476 */ 604 */
477 if ((long long)al->addr < 0 && mg != &session->kmaps) { 605 if ((long long)al->addr < 0 &&
478 mg = &session->kmaps; 606 cpumode == PERF_RECORD_MISC_KERNEL &&
607 kerninfo &&
608 mg != &kerninfo->kmaps) {
609 mg = &kerninfo->kmaps;
479 goto try_again; 610 goto try_again;
480 } 611 }
481 } else 612 } else
@@ -484,11 +615,11 @@ try_again:
484 615
485void thread__find_addr_location(struct thread *self, 616void thread__find_addr_location(struct thread *self,
486 struct perf_session *session, u8 cpumode, 617 struct perf_session *session, u8 cpumode,
487 enum map_type type, u64 addr, 618 enum map_type type, pid_t pid, u64 addr,
488 struct addr_location *al, 619 struct addr_location *al,
489 symbol_filter_t filter) 620 symbol_filter_t filter)
490{ 621{
491 thread__find_addr_map(self, session, cpumode, type, addr, al); 622 thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
492 if (al->map != NULL) 623 if (al->map != NULL)
493 al->sym = map__find_symbol(al->map, al->addr, filter); 624 al->sym = map__find_symbol(al->map, al->addr, filter);
494 else 625 else
@@ -524,7 +655,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
524 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 655 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
525 656
526 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 657 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
527 self->ip.ip, al); 658 self->ip.pid, self->ip.ip, al);
528 dump_printf(" ...... dso: %s\n", 659 dump_printf(" ...... dso: %s\n",
529 al->map ? al->map->dso->long_name : 660 al->map ? al->map->dso->long_name :
530 al->level == 'H' ? "[hypervisor]" : "<not found>"); 661 al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -554,7 +685,6 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
554 !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) 685 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
555 goto out_filtered; 686 goto out_filtered;
556 687
557 al->filtered = false;
558 return 0; 688 return 0;
559 689
560out_filtered: 690out_filtered: