aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-03-18 04:23:09 -0400
committerIngo Molnar <mingo@kernel.org>2014-03-18 04:23:09 -0400
commit0afd2d51029961281572d02545c7bde1b3f4292c (patch)
tree73f8b07ee0b43ebd93fb0556b0af0f217f897d5c /tools/perf/util
parent81827ed8d85e892311965dc9ec4120b2b2e745bd (diff)
parentd75e6097ef1f7669deb500fbbdf53cfe524f1b53 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo: User visible: * Add several futex 'perf bench' microbenchmarks (Davidlohr Bueso) * Speed up thread map generation (Don Zickus) * Fix synthesizing mmaps for threads (Don Zickus) * Fix invalid output on event group stdio report (Namhyung Kim) * Introduce 'perf kvm --list-cmds' command line option for use by scripts (Ramkumar Ramachandra) Documentation: * Clarify load-latency information in the 'perf mem' docs (Andi Kleen) * Clarify x86 register naming in 'perf probe' docs (Andi Kleen) Refactorings: * hists browser refactorings to reuse code accross UIs (Namhyung Kim) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/event.c156
-rw-r--r--tools/perf/util/hist.h20
-rw-r--r--tools/perf/util/machine.c46
-rw-r--r--tools/perf/util/machine.h3
-rw-r--r--tools/perf/util/parse-options.c37
-rw-r--r--tools/perf/util/parse-options.h8
-rw-r--r--tools/perf/util/session.c2
-rw-r--r--tools/perf/util/thread.c21
-rw-r--r--tools/perf/util/thread.h5
9 files changed, 204 insertions, 94 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index b0f3ca850e9e..3e580be0f6fb 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -94,14 +94,10 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
94 94
95static pid_t perf_event__synthesize_comm(struct perf_tool *tool, 95static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
96 union perf_event *event, pid_t pid, 96 union perf_event *event, pid_t pid,
97 int full,
98 perf_event__handler_t process, 97 perf_event__handler_t process,
99 struct machine *machine) 98 struct machine *machine)
100{ 99{
101 char filename[PATH_MAX];
102 size_t size; 100 size_t size;
103 DIR *tasks;
104 struct dirent dirent, *next;
105 pid_t tgid; 101 pid_t tgid;
106 102
107 memset(&event->comm, 0, sizeof(event->comm)); 103 memset(&event->comm, 0, sizeof(event->comm));
@@ -124,55 +120,35 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
124 event->comm.header.size = (sizeof(event->comm) - 120 event->comm.header.size = (sizeof(event->comm) -
125 (sizeof(event->comm.comm) - size) + 121 (sizeof(event->comm.comm) - size) +
126 machine->id_hdr_size); 122 machine->id_hdr_size);
127 if (!full) { 123 event->comm.tid = pid;
128 event->comm.tid = pid;
129
130 if (process(tool, event, &synth_sample, machine) != 0)
131 return -1;
132 124
133 goto out; 125 if (process(tool, event, &synth_sample, machine) != 0)
134 } 126 return -1;
135
136 if (machine__is_default_guest(machine))
137 return 0;
138
139 snprintf(filename, sizeof(filename), "%s/proc/%d/task",
140 machine->root_dir, pid);
141
142 tasks = opendir(filename);
143 if (tasks == NULL) {
144 pr_debug("couldn't open %s\n", filename);
145 return 0;
146 }
147 127
148 while (!readdir_r(tasks, &dirent, &next) && next) { 128out:
149 char *end; 129 return tgid;
150 pid = strtol(dirent.d_name, &end, 10); 130}
151 if (*end)
152 continue;
153 131
154 /* already have tgid; jut want to update the comm */ 132static int perf_event__synthesize_fork(struct perf_tool *tool,
155 (void) perf_event__get_comm_tgid(pid, event->comm.comm, 133 union perf_event *event, pid_t pid,
156 sizeof(event->comm.comm)); 134 pid_t tgid, perf_event__handler_t process,
135 struct machine *machine)
136{
137 memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);
157 138
158 size = strlen(event->comm.comm) + 1; 139 /* this is really a clone event but we use fork to synthesize it */
159 size = PERF_ALIGN(size, sizeof(u64)); 140 event->fork.ppid = tgid;
160 memset(event->comm.comm + size, 0, machine->id_hdr_size); 141 event->fork.ptid = tgid;
161 event->comm.header.size = (sizeof(event->comm) - 142 event->fork.pid = tgid;
162 (sizeof(event->comm.comm) - size) + 143 event->fork.tid = pid;
163 machine->id_hdr_size); 144 event->fork.header.type = PERF_RECORD_FORK;
164 145
165 event->comm.tid = pid; 146 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
166 147
167 if (process(tool, event, &synth_sample, machine) != 0) { 148 if (process(tool, event, &synth_sample, machine) != 0)
168 tgid = -1; 149 return -1;
169 break;
170 }
171 }
172 150
173 closedir(tasks); 151 return 0;
174out:
175 return tgid;
176} 152}
177 153
178int perf_event__synthesize_mmap_events(struct perf_tool *tool, 154int perf_event__synthesize_mmap_events(struct perf_tool *tool,
@@ -324,17 +300,71 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
324 300
325static int __event__synthesize_thread(union perf_event *comm_event, 301static int __event__synthesize_thread(union perf_event *comm_event,
326 union perf_event *mmap_event, 302 union perf_event *mmap_event,
303 union perf_event *fork_event,
327 pid_t pid, int full, 304 pid_t pid, int full,
328 perf_event__handler_t process, 305 perf_event__handler_t process,
329 struct perf_tool *tool, 306 struct perf_tool *tool,
330 struct machine *machine, bool mmap_data) 307 struct machine *machine, bool mmap_data)
331{ 308{
332 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full, 309 char filename[PATH_MAX];
310 DIR *tasks;
311 struct dirent dirent, *next;
312 pid_t tgid;
313
314 /* special case: only send one comm event using passed in pid */
315 if (!full) {
316 tgid = perf_event__synthesize_comm(tool, comm_event, pid,
317 process, machine);
318
319 if (tgid == -1)
320 return -1;
321
322 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
323 process, machine, mmap_data);
324 }
325
326 if (machine__is_default_guest(machine))
327 return 0;
328
329 snprintf(filename, sizeof(filename), "%s/proc/%d/task",
330 machine->root_dir, pid);
331
332 tasks = opendir(filename);
333 if (tasks == NULL) {
334 pr_debug("couldn't open %s\n", filename);
335 return 0;
336 }
337
338 while (!readdir_r(tasks, &dirent, &next) && next) {
339 char *end;
340 int rc = 0;
341 pid_t _pid;
342
343 _pid = strtol(dirent.d_name, &end, 10);
344 if (*end)
345 continue;
346
347 tgid = perf_event__synthesize_comm(tool, comm_event, _pid,
348 process, machine);
349 if (tgid == -1)
350 return -1;
351
352 if (_pid == pid) {
353 /* process the parent's maps too */
354 rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
355 process, machine, mmap_data);
356 } else {
357 /* only fork the tid's map, to save time */
358 rc = perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
333 process, machine); 359 process, machine);
334 if (tgid == -1) 360 }
335 return -1; 361
336 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 362 if (rc)
337 process, machine, mmap_data); 363 return rc;
364 }
365
366 closedir(tasks);
367 return 0;
338} 368}
339 369
340int perf_event__synthesize_thread_map(struct perf_tool *tool, 370int perf_event__synthesize_thread_map(struct perf_tool *tool,
@@ -343,7 +373,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
343 struct machine *machine, 373 struct machine *machine,
344 bool mmap_data) 374 bool mmap_data)
345{ 375{
346 union perf_event *comm_event, *mmap_event; 376 union perf_event *comm_event, *mmap_event, *fork_event;
347 int err = -1, thread, j; 377 int err = -1, thread, j;
348 378
349 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 379 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -354,9 +384,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
354 if (mmap_event == NULL) 384 if (mmap_event == NULL)
355 goto out_free_comm; 385 goto out_free_comm;
356 386
387 fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
388 if (fork_event == NULL)
389 goto out_free_mmap;
390
357 err = 0; 391 err = 0;
358 for (thread = 0; thread < threads->nr; ++thread) { 392 for (thread = 0; thread < threads->nr; ++thread) {
359 if (__event__synthesize_thread(comm_event, mmap_event, 393 if (__event__synthesize_thread(comm_event, mmap_event,
394 fork_event,
360 threads->map[thread], 0, 395 threads->map[thread], 0,
361 process, tool, machine, 396 process, tool, machine,
362 mmap_data)) { 397 mmap_data)) {
@@ -382,6 +417,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
382 /* if not, generate events for it */ 417 /* if not, generate events for it */
383 if (need_leader && 418 if (need_leader &&
384 __event__synthesize_thread(comm_event, mmap_event, 419 __event__synthesize_thread(comm_event, mmap_event,
420 fork_event,
385 comm_event->comm.pid, 0, 421 comm_event->comm.pid, 0,
386 process, tool, machine, 422 process, tool, machine,
387 mmap_data)) { 423 mmap_data)) {
@@ -390,6 +426,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
390 } 426 }
391 } 427 }
392 } 428 }
429 free(fork_event);
430out_free_mmap:
393 free(mmap_event); 431 free(mmap_event);
394out_free_comm: 432out_free_comm:
395 free(comm_event); 433 free(comm_event);
@@ -404,7 +442,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
404 DIR *proc; 442 DIR *proc;
405 char proc_path[PATH_MAX]; 443 char proc_path[PATH_MAX];
406 struct dirent dirent, *next; 444 struct dirent dirent, *next;
407 union perf_event *comm_event, *mmap_event; 445 union perf_event *comm_event, *mmap_event, *fork_event;
408 int err = -1; 446 int err = -1;
409 447
410 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 448 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -415,6 +453,10 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
415 if (mmap_event == NULL) 453 if (mmap_event == NULL)
416 goto out_free_comm; 454 goto out_free_comm;
417 455
456 fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
457 if (fork_event == NULL)
458 goto out_free_mmap;
459
418 if (machine__is_default_guest(machine)) 460 if (machine__is_default_guest(machine))
419 return 0; 461 return 0;
420 462
@@ -422,7 +464,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
422 proc = opendir(proc_path); 464 proc = opendir(proc_path);
423 465
424 if (proc == NULL) 466 if (proc == NULL)
425 goto out_free_mmap; 467 goto out_free_fork;
426 468
427 while (!readdir_r(proc, &dirent, &next) && next) { 469 while (!readdir_r(proc, &dirent, &next) && next) {
428 char *end; 470 char *end;
@@ -434,12 +476,14 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
434 * We may race with exiting thread, so don't stop just because 476 * We may race with exiting thread, so don't stop just because
435 * one thread couldn't be synthesized. 477 * one thread couldn't be synthesized.
436 */ 478 */
437 __event__synthesize_thread(comm_event, mmap_event, pid, 1, 479 __event__synthesize_thread(comm_event, mmap_event, fork_event, pid,
438 process, tool, machine, mmap_data); 480 1, process, tool, machine, mmap_data);
439 } 481 }
440 482
441 err = 0; 483 err = 0;
442 closedir(proc); 484 closedir(proc);
485out_free_fork:
486 free(fork_event);
443out_free_mmap: 487out_free_mmap:
444 free(mmap_event); 488 free(mmap_event);
445out_free_comm: 489out_free_comm:
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a59743fa3ef7..0c76bf972736 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -132,8 +132,10 @@ struct perf_hpp {
132}; 132};
133 133
134struct perf_hpp_fmt { 134struct perf_hpp_fmt {
135 int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp); 135 int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
136 int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp); 136 struct perf_evsel *evsel);
137 int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
138 struct perf_evsel *evsel);
137 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 139 int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
138 struct hist_entry *he); 140 struct hist_entry *he);
139 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 141 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -166,6 +168,20 @@ void perf_hpp__init(void);
166void perf_hpp__column_register(struct perf_hpp_fmt *format); 168void perf_hpp__column_register(struct perf_hpp_fmt *format);
167void perf_hpp__column_enable(unsigned col); 169void perf_hpp__column_enable(unsigned col);
168 170
171typedef u64 (*hpp_field_fn)(struct hist_entry *he);
172typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
173typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
174
175int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
176 hpp_field_fn get_field, hpp_callback_fn callback,
177 const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent);
178
179static inline void advance_hpp(struct perf_hpp *hpp, int inc)
180{
181 hpp->buf += inc;
182 hpp->size -= inc;
183}
184
169static inline size_t perf_hpp__use_color(void) 185static inline size_t perf_hpp__use_color(void)
170{ 186{
171 return !symbol_conf.field_sep; 187 return !symbol_conf.field_sep;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 813e94e7cf29..5cecd98c1bc0 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -327,9 +327,10 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
327 return __machine__findnew_thread(machine, pid, tid, true); 327 return __machine__findnew_thread(machine, pid, tid, true);
328} 328}
329 329
330struct thread *machine__find_thread(struct machine *machine, pid_t tid) 330struct thread *machine__find_thread(struct machine *machine, pid_t pid,
331 pid_t tid)
331{ 332{
332 return __machine__findnew_thread(machine, 0, tid, false); 333 return __machine__findnew_thread(machine, pid, tid, false);
333} 334}
334 335
335int machine__process_comm_event(struct machine *machine, union perf_event *event, 336int machine__process_comm_event(struct machine *machine, union perf_event *event,
@@ -1114,7 +1115,9 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
1114int machine__process_fork_event(struct machine *machine, union perf_event *event, 1115int machine__process_fork_event(struct machine *machine, union perf_event *event,
1115 struct perf_sample *sample) 1116 struct perf_sample *sample)
1116{ 1117{
1117 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1118 struct thread *thread = machine__find_thread(machine,
1119 event->fork.pid,
1120 event->fork.tid);
1118 struct thread *parent = machine__findnew_thread(machine, 1121 struct thread *parent = machine__findnew_thread(machine,
1119 event->fork.ppid, 1122 event->fork.ppid,
1120 event->fork.ptid); 1123 event->fork.ptid);
@@ -1140,7 +1143,9 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1140int machine__process_exit_event(struct machine *machine, union perf_event *event, 1143int machine__process_exit_event(struct machine *machine, union perf_event *event,
1141 struct perf_sample *sample __maybe_unused) 1144 struct perf_sample *sample __maybe_unused)
1142{ 1145{
1143 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1146 struct thread *thread = machine__find_thread(machine,
1147 event->fork.pid,
1148 event->fork.tid);
1144 1149
1145 if (dump_trace) 1150 if (dump_trace)
1146 perf_event__fprintf_task(event, stdout); 1151 perf_event__fprintf_task(event, stdout);
@@ -1184,39 +1189,22 @@ static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
1184 return 0; 1189 return 0;
1185} 1190}
1186 1191
1187static const u8 cpumodes[] = {
1188 PERF_RECORD_MISC_USER,
1189 PERF_RECORD_MISC_KERNEL,
1190 PERF_RECORD_MISC_GUEST_USER,
1191 PERF_RECORD_MISC_GUEST_KERNEL
1192};
1193#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
1194
1195static void ip__resolve_ams(struct machine *machine, struct thread *thread, 1192static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1196 struct addr_map_symbol *ams, 1193 struct addr_map_symbol *ams,
1197 u64 ip) 1194 u64 ip)
1198{ 1195{
1199 struct addr_location al; 1196 struct addr_location al;
1200 size_t i;
1201 u8 m;
1202 1197
1203 memset(&al, 0, sizeof(al)); 1198 memset(&al, 0, sizeof(al));
1199 /*
1200 * We cannot use the header.misc hint to determine whether a
1201 * branch stack address is user, kernel, guest, hypervisor.
1202 * Branches may straddle the kernel/user/hypervisor boundaries.
1203 * Thus, we have to try consecutively until we find a match
1204 * or else, the symbol is unknown
1205 */
1206 thread__find_cpumode_addr_location(thread, machine, MAP__FUNCTION, ip, &al);
1204 1207
1205 for (i = 0; i < NCPUMODES; i++) {
1206 m = cpumodes[i];
1207 /*
1208 * We cannot use the header.misc hint to determine whether a
1209 * branch stack address is user, kernel, guest, hypervisor.
1210 * Branches may straddle the kernel/user/hypervisor boundaries.
1211 * Thus, we have to try consecutively until we find a match
1212 * or else, the symbol is unknown
1213 */
1214 thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
1215 ip, &al);
1216 if (al.map)
1217 goto found;
1218 }
1219found:
1220 ams->addr = ip; 1208 ams->addr = ip;
1221 ams->al_addr = al.addr; 1209 ams->al_addr = al.addr;
1222 ams->sym = al.sym; 1210 ams->sym = al.sym;
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 2e6c248c870f..c8c74a119398 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -41,7 +41,8 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
41 return machine->vmlinux_maps[type]; 41 return machine->vmlinux_maps[type];
42} 42}
43 43
44struct thread *machine__find_thread(struct machine *machine, pid_t tid); 44struct thread *machine__find_thread(struct machine *machine, pid_t pid,
45 pid_t tid);
45 46
46int machine__process_comm_event(struct machine *machine, union perf_event *event, 47int machine__process_comm_event(struct machine *machine, union perf_event *event,
47 struct perf_sample *sample); 48 struct perf_sample *sample);
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index d22e3f8017dc..bf48092983c6 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -407,7 +407,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
407 if (internal_help && !strcmp(arg + 2, "help")) 407 if (internal_help && !strcmp(arg + 2, "help"))
408 return usage_with_options_internal(usagestr, options, 0); 408 return usage_with_options_internal(usagestr, options, 0);
409 if (!strcmp(arg + 2, "list-opts")) 409 if (!strcmp(arg + 2, "list-opts"))
410 return PARSE_OPT_LIST; 410 return PARSE_OPT_LIST_OPTS;
411 if (!strcmp(arg + 2, "list-cmds"))
412 return PARSE_OPT_LIST_SUBCMDS;
411 switch (parse_long_opt(ctx, arg + 2, options)) { 413 switch (parse_long_opt(ctx, arg + 2, options)) {
412 case -1: 414 case -1:
413 return parse_options_usage(usagestr, options, arg + 2, 0); 415 return parse_options_usage(usagestr, options, arg + 2, 0);
@@ -433,25 +435,45 @@ int parse_options_end(struct parse_opt_ctx_t *ctx)
433 return ctx->cpidx + ctx->argc; 435 return ctx->cpidx + ctx->argc;
434} 436}
435 437
436int parse_options(int argc, const char **argv, const struct option *options, 438int parse_options_subcommand(int argc, const char **argv, const struct option *options,
437 const char * const usagestr[], int flags) 439 const char *const subcommands[], const char *usagestr[], int flags)
438{ 440{
439 struct parse_opt_ctx_t ctx; 441 struct parse_opt_ctx_t ctx;
440 442
441 perf_header__set_cmdline(argc, argv); 443 perf_header__set_cmdline(argc, argv);
442 444
445 /* build usage string if it's not provided */
446 if (subcommands && !usagestr[0]) {
447 struct strbuf buf = STRBUF_INIT;
448
449 strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
450 for (int i = 0; subcommands[i]; i++) {
451 if (i)
452 strbuf_addstr(&buf, "|");
453 strbuf_addstr(&buf, subcommands[i]);
454 }
455 strbuf_addstr(&buf, "}");
456
457 usagestr[0] = strdup(buf.buf);
458 strbuf_release(&buf);
459 }
460
443 parse_options_start(&ctx, argc, argv, flags); 461 parse_options_start(&ctx, argc, argv, flags);
444 switch (parse_options_step(&ctx, options, usagestr)) { 462 switch (parse_options_step(&ctx, options, usagestr)) {
445 case PARSE_OPT_HELP: 463 case PARSE_OPT_HELP:
446 exit(129); 464 exit(129);
447 case PARSE_OPT_DONE: 465 case PARSE_OPT_DONE:
448 break; 466 break;
449 case PARSE_OPT_LIST: 467 case PARSE_OPT_LIST_OPTS:
450 while (options->type != OPTION_END) { 468 while (options->type != OPTION_END) {
451 printf("--%s ", options->long_name); 469 printf("--%s ", options->long_name);
452 options++; 470 options++;
453 } 471 }
454 exit(130); 472 exit(130);
473 case PARSE_OPT_LIST_SUBCMDS:
474 for (int i = 0; subcommands[i]; i++)
475 printf("%s ", subcommands[i]);
476 exit(130);
455 default: /* PARSE_OPT_UNKNOWN */ 477 default: /* PARSE_OPT_UNKNOWN */
456 if (ctx.argv[0][1] == '-') { 478 if (ctx.argv[0][1] == '-') {
457 error("unknown option `%s'", ctx.argv[0] + 2); 479 error("unknown option `%s'", ctx.argv[0] + 2);
@@ -464,6 +486,13 @@ int parse_options(int argc, const char **argv, const struct option *options,
464 return parse_options_end(&ctx); 486 return parse_options_end(&ctx);
465} 487}
466 488
489int parse_options(int argc, const char **argv, const struct option *options,
490 const char * const usagestr[], int flags)
491{
492 return parse_options_subcommand(argc, argv, options, NULL,
493 (const char **) usagestr, flags);
494}
495
467#define USAGE_OPTS_WIDTH 24 496#define USAGE_OPTS_WIDTH 24
468#define USAGE_GAP 2 497#define USAGE_GAP 2
469 498
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index cbf0149cf221..d8dac8ac5f37 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -140,6 +140,11 @@ extern int parse_options(int argc, const char **argv,
140 const struct option *options, 140 const struct option *options,
141 const char * const usagestr[], int flags); 141 const char * const usagestr[], int flags);
142 142
143extern int parse_options_subcommand(int argc, const char **argv,
144 const struct option *options,
145 const char *const subcommands[],
146 const char *usagestr[], int flags);
147
143extern NORETURN void usage_with_options(const char * const *usagestr, 148extern NORETURN void usage_with_options(const char * const *usagestr,
144 const struct option *options); 149 const struct option *options);
145 150
@@ -148,7 +153,8 @@ extern NORETURN void usage_with_options(const char * const *usagestr,
148enum { 153enum {
149 PARSE_OPT_HELP = -1, 154 PARSE_OPT_HELP = -1,
150 PARSE_OPT_DONE, 155 PARSE_OPT_DONE,
151 PARSE_OPT_LIST, 156 PARSE_OPT_LIST_OPTS,
157 PARSE_OPT_LIST_SUBCMDS,
152 PARSE_OPT_UNKNOWN, 158 PARSE_OPT_UNKNOWN,
153}; 159};
154 160
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1d555d652f58..55960f22233c 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -794,7 +794,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
794 if (!dump_trace) 794 if (!dump_trace)
795 return; 795 return;
796 796
797 printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n", 797 printf("(IP, 0x%x): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
798 event->header.misc, sample->pid, sample->tid, sample->ip, 798 event->header.misc, sample->pid, sample->tid, sample->ip,
799 sample->period, sample->addr); 799 sample->period, sample->addr);
800 800
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 0358882c8910..3ce0498bdae6 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -142,3 +142,24 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
142 142
143 return 0; 143 return 0;
144} 144}
145
146void thread__find_cpumode_addr_location(struct thread *thread,
147 struct machine *machine,
148 enum map_type type, u64 addr,
149 struct addr_location *al)
150{
151 size_t i;
152 const u8 const cpumodes[] = {
153 PERF_RECORD_MISC_USER,
154 PERF_RECORD_MISC_KERNEL,
155 PERF_RECORD_MISC_GUEST_USER,
156 PERF_RECORD_MISC_GUEST_KERNEL
157 };
158
159 for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
160 thread__find_addr_location(thread, machine, cpumodes[i], type,
161 addr, al);
162 if (al->map)
163 break;
164 }
165}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 5b856bf942e1..9a070743270c 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -58,6 +58,11 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
58 u8 cpumode, enum map_type type, u64 addr, 58 u8 cpumode, enum map_type type, u64 addr,
59 struct addr_location *al); 59 struct addr_location *al);
60 60
61void thread__find_cpumode_addr_location(struct thread *thread,
62 struct machine *machine,
63 enum map_type type, u64 addr,
64 struct addr_location *al);
65
61static inline void *thread__priv(struct thread *thread) 66static inline void *thread__priv(struct thread *thread)
62{ 67{
63 return thread->priv; 68 return thread->priv;