Commit 58cea307 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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 Carvalho de Melo:

 * Allow specifying syscalls in 'perf trace', a la strace.

 * Simplify symbol filtering by doing it at machine class level,
   from Adrian Hunter.

 * Add option to 'perf kvm' to print only events that exceed a specified time
   duration, from David Ahern.

 * 'perf sched' improvements, including removing some tracepoints that provide
   the same information as the PERF_RECORD_{FORK,EXIT} events.

 * Improve stack trace printing, from David Ahern.

 * Update documentation with live command, from David Ahern

 * Fix 'perf test' compile failure on do_sort_something, from David Ahern.

 * Improve robustness of topology parsing code, from Stephane Eranian.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 0a3d23a2 2ae3a312
...@@ -13,6 +13,7 @@ SYNOPSIS ...@@ -13,6 +13,7 @@ SYNOPSIS
{top|record|report|diff|buildid-list} {top|record|report|diff|buildid-list}
'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
| --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat}
'perf kvm stat [record|report|live] [<options>]
DESCRIPTION DESCRIPTION
----------- -----------
...@@ -50,6 +51,10 @@ There are a couple of variants of perf kvm: ...@@ -50,6 +51,10 @@ There are a couple of variants of perf kvm:
'perf kvm stat report' reports statistical data which includes events 'perf kvm stat report' reports statistical data which includes events
handled time, samples, and so on. handled time, samples, and so on.
'perf kvm stat live' reports statistical data in a live mode (similar to
record + report but with statistical data updated live at a given display
rate).
OPTIONS OPTIONS
------- -------
-i:: -i::
...@@ -85,13 +90,50 @@ STAT REPORT OPTIONS ...@@ -85,13 +90,50 @@ STAT REPORT OPTIONS
--vcpu=<value>:: --vcpu=<value>::
analyze events which occures on this vcpu. (default: all vcpus) analyze events which occures on this vcpu. (default: all vcpus)
--events=<value>:: --event=<value>::
events to be analyzed. Possible values: vmexit, mmio, ioport. event to be analyzed. Possible values: vmexit, mmio, ioport.
(default: vmexit) (default: vmexit)
-k:: -k::
--key=<value>:: --key=<value>::
Sorting key. Possible values: sample (default, sort by samples Sorting key. Possible values: sample (default, sort by samples
number), time (sort by average time). number), time (sort by average time).
-p::
--pid=::
Analyze events only for given process ID(s) (comma separated list).
STAT LIVE OPTIONS
-----------------
-d::
--display::
Time in seconds between display updates
-m::
--mmap-pages=::
Number of mmap data pages. Must be a power of two.
-a::
--all-cpus::
System-wide collection from all CPUs.
-p::
--pid=::
Analyze events only for given process ID(s) (comma separated list).
--vcpu=<value>::
analyze events which occures on this vcpu. (default: all vcpus)
--event=<value>::
event to be analyzed. Possible values: vmexit, mmio, ioport.
(default: vmexit)
-k::
--key=<value>::
Sorting key. Possible values: sample (default, sort by samples
number), time (sort by average time).
--duration=<value>::
Show events other than HLT that take longer than duration usecs.
SEE ALSO SEE ALSO
-------- --------
......
...@@ -26,6 +26,10 @@ OPTIONS ...@@ -26,6 +26,10 @@ OPTIONS
--all-cpus:: --all-cpus::
System-wide collection from all CPUs. System-wide collection from all CPUs.
-e::
--expr::
List of events to show, currently only syscall names.
-p:: -p::
--pid=:: --pid=::
Record events on existing process ID (comma separated list). Record events on existing process ID (comma separated list).
......
...@@ -90,8 +90,7 @@ static int process_sample_event(struct perf_tool *tool, ...@@ -90,8 +90,7 @@ static int process_sample_event(struct perf_tool *tool,
struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool); struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
struct addr_location al; struct addr_location al;
if (perf_event__preprocess_sample(event, machine, &al, sample, if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
symbol__annotate_init) < 0) {
pr_warning("problem processing %d event, skipping it.\n", pr_warning("problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; return -1;
...@@ -195,6 +194,8 @@ static int __cmd_annotate(struct perf_annotate *ann) ...@@ -195,6 +194,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;
machines__set_symbol_filter(&session->machines, symbol__annotate_init);
if (ann->cpu_list) { if (ann->cpu_list) {
ret = perf_session__cpu_bitmap(session, ann->cpu_list, ret = perf_session__cpu_bitmap(session, ann->cpu_list,
ann->cpu_bitmap); ann->cpu_bitmap);
......
...@@ -319,7 +319,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -319,7 +319,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
{ {
struct addr_location al; struct addr_location al;
if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
pr_warning("problem processing %d event, skipping it.\n", pr_warning("problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; return -1;
......
...@@ -206,7 +206,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, ...@@ -206,7 +206,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
} }
thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
event->ip.ip, &al, NULL); event->ip.ip, &al);
if (al.map != NULL) { if (al.map != NULL) {
if (!al.map->dso->hit) { if (!al.map->dso->hit) {
......
...@@ -106,6 +106,7 @@ struct perf_kvm_stat { ...@@ -106,6 +106,7 @@ struct perf_kvm_stat {
u64 total_time; u64 total_time;
u64 total_count; u64 total_count;
u64 lost_events; u64 lost_events;
u64 duration;
const char *pid_str; const char *pid_str;
struct intlist *pid_list; struct intlist *pid_list;
...@@ -473,7 +474,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id, ...@@ -473,7 +474,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
static bool handle_end_event(struct perf_kvm_stat *kvm, static bool handle_end_event(struct perf_kvm_stat *kvm,
struct vcpu_event_record *vcpu_record, struct vcpu_event_record *vcpu_record,
struct event_key *key, struct event_key *key,
u64 timestamp) struct perf_sample *sample)
{ {
struct kvm_event *event; struct kvm_event *event;
u64 time_begin, time_diff; u64 time_begin, time_diff;
...@@ -510,12 +511,24 @@ static bool handle_end_event(struct perf_kvm_stat *kvm, ...@@ -510,12 +511,24 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
vcpu_record->start_time = 0; vcpu_record->start_time = 0;
/* seems to happen once in a while during live mode */ /* seems to happen once in a while during live mode */
if (timestamp < time_begin) { if (sample->time < time_begin) {
pr_debug("End time before begin time; skipping event.\n"); pr_debug("End time before begin time; skipping event.\n");
return true; return true;
} }
time_diff = timestamp - time_begin; time_diff = sample->time - time_begin;
if (kvm->duration && time_diff > kvm->duration) {
char decode[32];
kvm->events_ops->decode_key(kvm, &event->key, decode);
if (strcmp(decode, "HLT")) {
pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
sample->time, sample->pid, vcpu_record->vcpu_id,
decode, time_diff/1000);
}
}
return update_kvm_event(event, vcpu, time_diff); return update_kvm_event(event, vcpu, time_diff);
} }
...@@ -562,7 +575,7 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm, ...@@ -562,7 +575,7 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
return handle_begin_event(kvm, vcpu_record, &key, sample->time); return handle_begin_event(kvm, vcpu_record, &key, sample->time);
if (kvm->events_ops->is_end_event(evsel, sample, &key)) if (kvm->events_ops->is_end_event(evsel, sample, &key))
return handle_end_event(kvm, vcpu_record, &key, sample->time); return handle_end_event(kvm, vcpu_record, &key, sample);
return true; return true;
} }
...@@ -1429,6 +1442,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, ...@@ -1429,6 +1442,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
OPT_STRING('k', "key", &kvm->sort_key, "sort-key", OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
"key for sorting: sample(sort by samples number)" "key for sorting: sample(sort by samples number)"
" time (sort by avg time)"), " time (sort by avg time)"),
OPT_U64(0, "duration", &kvm->duration,
"show events other than HALT that take longer than duration usecs"),
OPT_END() OPT_END()
}; };
const char * const live_usage[] = { const char * const live_usage[] = {
...@@ -1467,6 +1482,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, ...@@ -1467,6 +1482,8 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
usage_with_options(live_usage, live_options); usage_with_options(live_usage, live_options);
} }
kvm->duration *= NSEC_PER_USEC; /* convert usec to nsec */
/* /*
* target related setups * target related setups
*/ */
......
...@@ -14,7 +14,6 @@ static const char *mem_operation = MEM_OPERATION_LOAD; ...@@ -14,7 +14,6 @@ static const char *mem_operation = MEM_OPERATION_LOAD;
struct perf_mem { struct perf_mem {
struct perf_tool tool; struct perf_tool tool;
char const *input_name; char const *input_name;
symbol_filter_t annotate_init;
bool hide_unresolved; bool hide_unresolved;
bool dump_raw; bool dump_raw;
const char *cpu_list; const char *cpu_list;
...@@ -69,8 +68,7 @@ dump_raw_samples(struct perf_tool *tool, ...@@ -69,8 +68,7 @@ dump_raw_samples(struct perf_tool *tool,
struct addr_location al; struct addr_location al;
const char *fmt; const char *fmt;
if (perf_event__preprocess_sample(event, machine, &al, sample, if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
mem->annotate_init) < 0) {
fprintf(stderr, "problem processing %d event, skipping it.\n", fprintf(stderr, "problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; return -1;
......
...@@ -49,7 +49,6 @@ struct perf_report { ...@@ -49,7 +49,6 @@ struct perf_report {
bool mem_mode; bool mem_mode;
struct perf_read_values show_threads_values; struct perf_read_values show_threads_values;
const char *pretty_printing_style; const char *pretty_printing_style;
symbol_filter_t annotate_init;
const char *cpu_list; const char *cpu_list;
const char *symbol_filter_str; const char *symbol_filter_str;
float min_percent; float min_percent;
...@@ -305,8 +304,7 @@ static int process_sample_event(struct perf_tool *tool, ...@@ -305,8 +304,7 @@ static int process_sample_event(struct perf_tool *tool,
struct addr_location al; struct addr_location al;
int ret; int ret;
if (perf_event__preprocess_sample(event, machine, &al, sample, if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
rep->annotate_init) < 0) {
fprintf(stderr, "problem processing %d event, skipping it.\n", fprintf(stderr, "problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; return -1;
...@@ -924,7 +922,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -924,7 +922,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
*/ */
if (use_browser == 1 && sort__has_sym) { if (use_browser == 1 && sort__has_sym) {
symbol_conf.priv_size = sizeof(struct annotation); symbol_conf.priv_size = sizeof(struct annotation);
report.annotate_init = symbol__annotate_init; machines__set_symbol_filter(&session->machines,
symbol__annotate_init);
/* /*
* For searching by name on the "Browse map details". * For searching by name on the "Browse map details".
* providing it only in verbose mode not to bloat too * providing it only in verbose mode not to bloat too
......
...@@ -109,8 +109,9 @@ struct trace_sched_handler { ...@@ -109,8 +109,9 @@ struct trace_sched_handler {
int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel, int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel,
struct perf_sample *sample, struct machine *machine); struct perf_sample *sample, struct machine *machine);
int (*fork_event)(struct perf_sched *sched, struct perf_evsel *evsel, /* PERF_RECORD_FORK event, not sched_process_fork tracepoint */
struct perf_sample *sample); int (*fork_event)(struct perf_sched *sched, union perf_event *event,
struct machine *machine);
int (*migrate_task_event)(struct perf_sched *sched, int (*migrate_task_event)(struct perf_sched *sched,
struct perf_evsel *evsel, struct perf_evsel *evsel,
...@@ -717,22 +718,29 @@ static int replay_switch_event(struct perf_sched *sched, ...@@ -717,22 +718,29 @@ static int replay_switch_event(struct perf_sched *sched,
return 0; return 0;
} }
static int replay_fork_event(struct perf_sched *sched, struct perf_evsel *evsel, static int replay_fork_event(struct perf_sched *sched,
struct perf_sample *sample) union perf_event *event,
struct machine *machine)
{ {
const char *parent_comm = perf_evsel__strval(evsel, sample, "parent_comm"), struct thread *child, *parent;
*child_comm = perf_evsel__strval(evsel, sample, "child_comm");
const u32 parent_pid = perf_evsel__intval(evsel, sample, "parent_pid"), child = machine__findnew_thread(machine, event->fork.tid);
child_pid = perf_evsel__intval(evsel, sample, "child_pid"); parent = machine__findnew_thread(machine, event->fork.ptid);
if (child == NULL || parent == NULL) {
pr_debug("thread does not exist on fork event: child %p, parent %p\n",
child, parent);
return 0;
}
if (verbose) { if (verbose) {
printf("sched_fork event %p\n", evsel); printf("fork event\n");
printf("... parent: %s/%d\n", parent_comm, parent_pid); printf("... parent: %s/%d\n", parent->comm, parent->tid);
printf("... child: %s/%d\n", child_comm, child_pid); printf("... child: %s/%d\n", child->comm, child->tid);
} }
register_pid(sched, parent_pid, parent_comm); register_pid(sched, parent->tid, parent->comm);
register_pid(sched, child_pid, child_comm); register_pid(sched, child->tid, child->comm);
return 0; return 0;
} }
...@@ -824,14 +832,6 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread) ...@@ -824,14 +832,6 @@ static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread)
return 0; return 0;
} }
static int latency_fork_event(struct perf_sched *sched __maybe_unused,
struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample __maybe_unused)
{
/* should insert the newcomer */
return 0;
}
static char sched_out_state(u64 prev_state) static char sched_out_state(u64 prev_state)
{ {
const char *str = TASK_STATE_TO_CHAR_STR; const char *str = TASK_STATE_TO_CHAR_STR;
...@@ -1379,25 +1379,20 @@ static int process_sched_runtime_event(struct perf_tool *tool, ...@@ -1379,25 +1379,20 @@ static int process_sched_runtime_event(struct perf_tool *tool,
return 0; return 0;
} }
static int process_sched_fork_event(struct perf_tool *tool, static int perf_sched__process_fork_event(struct perf_tool *tool,
struct perf_evsel *evsel, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct machine *machine __maybe_unused) struct machine *machine)
{ {
struct perf_sched *sched = container_of(tool, struct perf_sched, tool); struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
if (sched->tp_handler->fork_event) /* run the fork event through the perf machineruy */
return sched->tp_handler->fork_event(sched, evsel, sample); perf_event__process_fork(tool, event, sample, machine);
return 0; /* and then run additional processing needed for this command */
} if (sched->tp_handler->fork_event)
return sched->tp_handler->fork_event(sched, event, machine);
static int process_sched_exit_event(struct perf_tool *tool __maybe_unused,
struct perf_evsel *evsel,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
{
pr_debug("sched_exit event %p\n", evsel);
return 0; return 0;
} }
...@@ -1425,15 +1420,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ ...@@ -1425,15 +1420,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine) struct machine *machine)
{ {
struct thread *thread = machine__findnew_thread(machine, sample->tid);
int err = 0; int err = 0;
if (thread == NULL) {
pr_debug("problem processing %s event, skipping it.\n",
perf_evsel__name(evsel));
return -1;
}
evsel->hists.stats.total_period += sample->period; evsel->hists.stats.total_period += sample->period;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
...@@ -1445,7 +1433,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ ...@@ -1445,7 +1433,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
return err; return err;
} }
static int perf_sched__read_events(struct perf_sched *sched, bool destroy, static int perf_sched__read_events(struct perf_sched *sched,
struct perf_session **psession) struct perf_session **psession)
{ {
const struct perf_evsel_str_handler handlers[] = { const struct perf_evsel_str_handler handlers[] = {
...@@ -1453,8 +1441,6 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy, ...@@ -1453,8 +1441,6 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
{ "sched:sched_stat_runtime", process_sched_runtime_event, }, { "sched:sched_stat_runtime", process_sched_runtime_event, },
{ "sched:sched_wakeup", process_sched_wakeup_event, }, { "sched:sched_wakeup", process_sched_wakeup_event, },
{ "sched:sched_wakeup_new", process_sched_wakeup_event, }, { "sched:sched_wakeup_new", process_sched_wakeup_event, },
{ "sched:sched_process_fork", process_sched_fork_event, },
{ "sched:sched_process_exit", process_sched_exit_event, },
{ "sched:sched_migrate_task", process_sched_migrate_task_event, }, { "sched:sched_migrate_task", process_sched_migrate_task_event, },
}; };
struct perf_session *session; struct perf_session *session;
...@@ -1480,11 +1466,10 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy, ...@@ -1480,11 +1466,10 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
} }
if (destroy)
perf_session__delete(session);
if (psession) if (psession)
*psession = session; *psession = session;
else
perf_session__delete(session);
return 0; return 0;
...@@ -1529,8 +1514,11 @@ static int perf_sched__lat(struct perf_sched *sched) ...@@ -1529,8 +1514,11 @@ static int perf_sched__lat(struct perf_sched *sched)
struct perf_session *session; struct perf_session *session;
setup_pager(); setup_pager();
if (perf_sched__read_events(sched, false, &session))
/* save session -- references to threads are held in work_list */
if (perf_sched__read_events(sched, &session))
return -1; return -1;
perf_sched__sort_lat(sched); perf_sched__sort_lat(sched);
printf("\n ---------------------------------------------------------------------------------------------------------------\n"); printf("\n ---------------------------------------------------------------------------------------------------------------\n");
...@@ -1565,7 +1553,7 @@ static int perf_sched__map(struct perf_sched *sched) ...@@ -1565,7 +1553,7 @@ static int perf_sched__map(struct perf_sched *sched)
sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
setup_pager(); setup_pager();
if (perf_sched__read_events(sched, true, NULL)) if (perf_sched__read_events(sched, NULL))
return -1; return -1;
print_bad_events(sched); print_bad_events(sched);
return 0; return 0;
...@@ -1580,7 +1568,7 @@ static int perf_sched__replay(struct perf_sched *sched) ...@@ -1580,7 +1568,7 @@ static int perf_sched__replay(struct perf_sched *sched)
test_calibrations(sched); test_calibrations(sched);
if (perf_sched__read_events(sched, true, NULL)) if (perf_sched__read_events(sched, NULL))
return -1; return -1;
printf("nr_run_events: %ld\n", sched->nr_run_events); printf("nr_run_events: %ld\n", sched->nr_run_events);
...@@ -1639,7 +1627,6 @@ static int __cmd_record(int argc, const char **argv) ...@@ -1639,7 +1627,6 @@ static int __cmd_record(int argc, const char **argv)
"-e", "sched:sched_stat_sleep", "-e", "sched:sched_stat_sleep",
"-e", "sched:sched_stat_iowait", "-e", "sched:sched_stat_iowait",
"-e", "sched:sched_stat_runtime", "-e", "sched:sched_stat_runtime",
"-e", "sched:sched_process_exit",
"-e", "sched:sched_process_fork", "-e", "sched:sched_process_fork",
"-e", "sched:sched_wakeup", "-e", "sched:sched_wakeup",
"-e", "sched:sched_migrate_task", "-e", "sched:sched_migrate_task",
...@@ -1668,7 +1655,7 @@ static struct perf_sched sched = { ...@@ -1668,7 +1655,7 @@ static struct perf_sched sched = {
.sample = perf_sched__process_tracepoint_sample, .sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.fork = perf_event__process_fork, .fork = perf_sched__process_fork_event,
.ordered_samples = true, .ordered_samples = true,
}, },
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
...@@ -1730,7 +1717,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1730,7 +1717,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
.wakeup_event = latency_wakeup_event, .wakeup_event = latency_wakeup_event,
.switch_event = latency_switch_event, .switch_event = latency_switch_event,
.runtime_event = latency_runtime_event, .runtime_event = latency_runtime_event,
.fork_event = latency_fork_event,
.migrate_task_event = latency_migrate_task_event, .migrate_task_event = latency_migrate_task_event,
}; };
struct trace_sched_handler map_ops = { struct trace_sched_handler map_ops = {
......
...@@ -66,6 +66,7 @@ struct output_option { ...@@ -66,6 +66,7 @@ struct output_option {
static struct { static struct {
bool user_set; bool user_set;
bool wildcard_set; bool wildcard_set;
unsigned int print_ip_opts;
u64 fields; u64 fields;
u64 invalid_fields; u64 invalid_fields;
} output[PERF_TYPE_MAX] = { } output[PERF_TYPE_MAX] = {
...@@ -235,6 +236,7 @@ static int perf_session__check_output_opt(struct perf_session *session) ...@@ -235,6 +236,7 @@ static int perf_session__check_output_opt(struct perf_session *session)
{ {
int j; int j;
struct perf_evsel *evsel; struct perf_evsel *evsel;
struct perf_event_attr *attr;
for (j = 0; j < PERF_TYPE_MAX; ++j) { for (j = 0; j < PERF_TYPE_MAX; ++j) {
evsel = perf_session__find_first_evtype(session, j); evsel = perf_session__find_first_evtype(session, j);
...@@ -253,6 +255,24 @@ static int perf_session__check_output_opt(struct perf_session *session) ...@@ -253,6 +255,24 @@ static int perf_session__check_output_opt(struct perf_session *session)
if (evsel && output[j].fields && if (evsel && output[j].fields &&
perf_evsel__check_attr(evsel, session)) perf_evsel__check_attr(evsel, session))
return -1; return -1;
if (evsel == NULL)
continue;
attr = &evsel->attr;
output[j].print_ip_opts = 0;
if (PRINT_FIELD(IP))
output[j].print_ip_opts |= PRINT_IP_OPT_IP;
if (PRINT_FIELD(SYM))
output[j].print_ip_opts |= PRINT_IP_OPT_SYM;
if (PRINT_FIELD(DSO))
output[j].print_ip_opts |= PRINT_IP_OPT_DSO;
if (PRINT_FIELD(SYMOFFSET))
output[j].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
} }
return 0; return 0;
...@@ -341,10 +361,10 @@ static void print_sample_addr(union perf_event *event, ...@@ -341,10 +361,10 @@ static void print_sample_addr(union perf_event *event,
return; return;
thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
sample->addr, &al, NULL); sample->addr, &al);
if (!al.map) if (!al.map)
thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
sample->addr, &al, NULL); sample->addr, &al);
al.cpu = sample->cpu; al.cpu = sample->cpu;
al.sym = NULL; al.sym = NULL;
...@@ -382,8 +402,8 @@ static void print_sample_bts(union perf_event *event, ...@@ -382,8 +402,8 @@ static void print_sample_bts(union perf_event *event,
else else
printf("\n"); printf("\n");
perf_evsel__print_ip(evsel, event, sample, machine, perf_evsel__print_ip(evsel, event, sample, machine,
PRINT_FIELD(SYM), PRINT_FIELD(DSO), output[attr->type].print_ip_opts,
PRINT_FIELD(SYMOFFSET)); PERF_MAX_STACK_DEPTH);
} }
printf(" => "); printf(" => ");
...@@ -423,9 +443,10 @@ static void process_event(union perf_event *event, struct perf_sample *sample, ...@@ -423,9 +443,10 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
printf(" "); printf(" ");
else else
printf("\n"); printf("\n");
perf_evsel__print_ip(evsel, event, sample, machine, perf_evsel__print_ip(evsel, event, sample, machine,
PRINT_FIELD(SYM), PRINT_FIELD(DSO), output[attr->type].print_ip_opts,
PRINT_FIELD(SYMOFFSET)); PERF_MAX_STACK_DEPTH);
} }
printf("\n"); printf("\n");
...@@ -499,7 +520,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -499,7 +520,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
return 0; return 0;
} }
if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) { if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
pr_err("problem processing %d event, skipping it.\n", pr_err("problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; return -1;
......
...@@ -716,8 +716,7 @@ static void perf_event__process_sample(struct perf_tool *tool, ...@@ -716,8 +716,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
top->exact_samples++; top->exact_samples++;
if (perf_event__preprocess_sample(event, machine, &al, sample, if (perf_event__preprocess_sample(event, machine, &al, sample) < 0 ||
symbol_filter) < 0 ||
al.filtered) al.filtered)
return; return;
...@@ -938,6 +937,8 @@ static int __cmd_top(struct perf_top *top) ...@@ -938,6 +937,8 @@ static int __cmd_top(struct perf_top *top)
if (top->session == NULL) if (top->session == NULL)
return -ENOMEM; return -ENOMEM;
machines__set_symbol_filter(&top->session->machines, symbol_filter);
if (!objdump_path) { if (!objdump_path) {
ret = perf_session_env__lookup_objdump(&top->session->header.env); ret = perf_session_env__lookup_objdump(&top->session->header.env);
if (ret) if (ret)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "util/machine.h" #include "util/machine.h"
#include "util/thread.h" #include "util/thread.h"
#include "util/parse-options.h" #include "util/parse-options.h"
#include "util/strlist.h"
#include "util/thread_map.h" #include "util/thread_map.h"
#include <libaudit.h> #include <libaudit.h>
...@@ -47,6 +48,7 @@ static struct syscall_fmt *syscall_fmt__find(const char *name) ...@@ -47,6 +48,7 @@ static struct syscall_fmt *syscall_fmt__find(const char *name)
struct syscall { struct syscall {
struct event_format *tp_format; struct event_format *tp_format;
const char *name; const char *name;
bool filtered;
struct syscall_fmt *fmt; struct syscall_fmt *fmt;
}; };
...@@ -110,6 +112,7 @@ struct trace { ...@@ -110,6 +112,7 @@ struct trace {
struct perf_record_opts opts; struct perf_record_opts opts;
struct machine host; struct machine host;
u64 base_time; u64 base_time;
struct strlist *ev_qualifier;
unsigned long nr_events; unsigned long nr_events;
bool sched; bool sched;
bool multiple_threads; bool multiple_threads;
...@@ -226,6 +229,16 @@ static int trace__read_syscall_info(struct trace *trace, int id) ...@@ -226,6 +229,16 @@ static int trace__read_syscall_info(struct trace *trace, int id)
sc = trace->syscalls.table + id; sc = trace->syscalls.table + id;
sc->name = name; sc->name = name;
if (trace->ev_qualifier && !strlist__find(trace->ev_qualifier, name)) {
sc->filtered = true;
/*
* No need to do read tracepoint information since this will be
* filtered out.
*/
return 0;
}
sc->fmt = syscall_fmt__find(sc->name); sc->fmt = syscall_fmt__find(sc->name);
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
...@@ -302,11 +315,19 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, ...@@ -302,11 +315,19 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
char *msg; char *msg;
void *args; void *args;
size_t printed = 0; size_t printed = 0;
struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); struct thread *thread;
struct syscall *sc = trace__syscall_info(trace, evsel, sample); struct syscall *sc = trace__syscall_info(trace, evsel, sample);
struct thread_trace *ttrace = thread__trace(thread); struct thread_trace *ttrace;
if (sc == NULL)
return -1;
if (ttrace == NULL || sc == NULL) if (sc->filtered)
return 0;
thread = machine__findnew_thread(&trace->host, sample->tid);
ttrace = thread__trace(thread);
if (ttrace == NULL)
return -1; return -1;
args = perf_evsel__rawptr(evsel, sample, "args"); args = perf_evsel__rawptr(evsel, sample, "args");
...@@ -345,11 +366,19 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ...@@ -345,11 +366,19 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
{ {
int ret; int ret;
u64 duration = 0; u64 duration = 0;
struct thread *thread = machine__findnew_thread(&trace->host, sample->tid); struct thread *thread;
struct thread_trace *ttrace = thread__trace(thread);
struct syscall *sc = trace__syscall_info(trace, evsel, sample); struct syscall *sc = trace__syscall_info(trace, evsel, sample);
struct thread_trace *ttrace;
if (sc == NULL)
return -1;
if (ttrace == NULL || sc == NULL) if (sc->filtered)
return 0;
thread = machine__findnew_thread(&trace->host, sample->tid);
ttrace = thread__trace(thread);
if (ttrace == NULL)
return -1; return -1;
ret = perf_evsel__intval(evsel, sample, "ret"); ret = perf_evsel__intval(evsel, sample, "ret");
...@@ -634,7 +663,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -634,7 +663,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
.mmap_pages = 1024, .mmap_pages = 1024,
}, },
}; };
const char *ev_qualifier_str = NULL;
const struct option trace_options[] = { const struct option trace_options[] = {
OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
"list of events to trace"),
OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
"trace events on existing process id"), "trace events on existing process id"),
OPT_STRING(0, "tid", &trace.opts.target.tid, "tid", OPT_STRING(0, "tid", &trace.opts.target.tid, "tid",
...@@ -660,6 +692,14 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -660,6 +692,14 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
argc = parse_options(argc, argv, trace_options, trace_usage, 0); argc = parse_options(argc, argv, trace_options, trace_usage, 0);
if (ev_qualifier_str != NULL) {
trace.ev_qualifier = strlist__new(true, ev_qualifier_str);
if (trace.ev_qualifier == NULL) {
puts("Not enough memory to parse event qualifier");
return -ENOMEM;
}
}
err = perf_target__validate(&trace.opts.target); err = perf_target__validate(&trace.opts.target);
if (err) { if (err) {
perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
......
...@@ -125,6 +125,9 @@ ...@@ -125,6 +125,9 @@
#ifndef NSEC_PER_SEC #ifndef NSEC_PER_SEC
# define NSEC_PER_SEC 1000000000ULL # define NSEC_PER_SEC 1000000000ULL
#endif #endif
#ifndef NSEC_PER_USEC
# define NSEC_PER_USEC 1000ULL
#endif
static inline unsigned long long rdclock(void) static inline unsigned long long rdclock(void)
{ {
......
...@@ -147,7 +147,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, ...@@ -147,7 +147,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, addr, thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, addr,
&al, NULL); &al);
if (!al.map || !al.map->dso) { if (!al.map || !al.map->dso) {
pr_debug("thread__find_addr_map failed\n"); pr_debug("thread__find_addr_map failed\n");
return -1; return -1;
...@@ -304,15 +304,14 @@ static int comp(const void *a, const void *b) ...@@ -304,15 +304,14 @@ static int comp(const void *a, const void *b)
static void do_sort_something(void) static void do_sort_something(void)
{ {
size_t sz = 40960; int buf[40960], i;
int buf[sz], i;
for (i = 0; i < (int)sz; i++) for (i = 0; i < (int)ARRAY_SIZE(buf); i++)
buf[i] = sz - i - 1; buf[i] = ARRAY_SIZE(buf) - i - 1;
qsort(buf, sz, sizeof(int), comp); qsort(buf, ARRAY_SIZE(buf), sizeof(int), comp);
for (i = 0; i < (int)sz; i++) { for (i = 0; i < (int)ARRAY_SIZE(buf); i++) {
if (buf[i] != i) { if (buf[i] != i) {
pr_debug("qsort failed\n"); pr_debug("qsort failed\n");
break; break;
......
...@@ -220,7 +220,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) ...@@ -220,7 +220,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
}; };
if (perf_event__preprocess_sample(&event, machine, &al, if (perf_event__preprocess_sample(&event, machine, &al,
&sample, 0) < 0) &sample) < 0)
goto out; goto out;
he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
...@@ -244,7 +244,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) ...@@ -244,7 +244,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
}; };
if (perf_event__preprocess_sample(&event, machine, &al, if (perf_event__preprocess_sample(&event, machine, &al,
&sample, 0) < 0) &sample) < 0)
goto out; goto out;
he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1); he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
......
...@@ -33,7 +33,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, ...@@ -33,7 +33,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
} }
thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
event->ip.ip, &al, NULL); event->ip.ip, &al);
if (al.map != NULL) if (al.map != NULL)
al.map->dso->hit = 1; al.map->dso->hit = 1;
......
...@@ -592,7 +592,7 @@ int perf_event__process(struct perf_tool *tool __maybe_unused, ...@@ -592,7 +592,7 @@ int perf_event__process(struct perf_tool *tool __maybe_unused,
void thread__find_addr_map(struct thread *self, void thread__find_addr_map(struct thread *self,
struct machine *machine, u8 cpumode, struct machine *machine, u8 cpumode,
enum map_type type, u64 addr, enum map_type type, u64 addr,
struct addr_location *al, symbol_filter_t filter) struct addr_location *al)
{ {
struct map_groups *mg = &self->mg; struct map_groups *mg = &self->mg;
bool load_map = false; bool load_map = false;
...@@ -663,19 +663,19 @@ void thread__find_addr_map(struct thread *self, ...@@ -663,19 +663,19 @@ void thread__find_addr_map(struct thread *self,
* must be done prior to using kernel maps. * must be done prior to using kernel maps.
*/ */
if (load_map) if (load_map)
map__load(al->map, filter); map__load(al->map, machine->symbol_filter);
al->addr = al->map->map_ip(al->map, al->addr); al->addr = al->map->map_ip(al->map, al->addr);
} }
} }
void thread__find_addr_location(struct thread *thread, struct machine *machine, void thread__find_addr_location(struct thread *thread, struct machine *machine,
u8 cpumode, enum map_type type, u64 addr, u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al, struct addr_location *al)
symbol_filter_t filter)
{ {
thread__find_addr_map(thread, machine, cpumode, type, addr, al, filter); thread__find_addr_map(thread, machine, cpumode, type, addr, al);
if (al->map != NULL) if (al->map != NULL)
al->sym = map__find_symbol(al->map, al->addr, filter); al->sym = map__find_symbol(al->map, al->addr,
machine->symbol_filter);
else else
al->sym = NULL; al->sym = NULL;
} }
...@@ -683,8 +683,7 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine, ...@@ -683,8 +683,7 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
int perf_event__preprocess_sample(const union perf_event *event, int perf_event__preprocess_sample(const union perf_event *event,
struct machine *machine, struct machine *machine,
struct addr_location *al, struct addr_location *al,
struct perf_sample *sample, struct perf_sample *sample)
symbol_filter_t filter)
{ {
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
struct thread *thread = machine__findnew_thread(machine, event->ip.pid); struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
...@@ -709,7 +708,7 @@ int perf_event__preprocess_sample(const union perf_event *event, ...@@ -709,7 +708,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
machine__create_kernel_maps(machine); machine__create_kernel_maps(machine);
thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
event->ip.ip, al, filter); event->ip.ip, al);
dump_printf(" ...... dso: %s\n", dump_printf(" ...... dso: %s\n",
al->map ? al->map->dso->long_name : al->map ? al->map->dso->long_name :
al->level == 'H' ? "[hypervisor]" : "<not found>"); al->level == 'H' ? "[hypervisor]" : "<not found>");
...@@ -727,7 +726,8 @@ int perf_event__preprocess_sample(const union perf_event *event, ...@@ -727,7 +726,8 @@ int perf_event__preprocess_sample(const union perf_event *event,
dso->long_name))))) dso->long_name)))))
goto out_filtered; goto out_filtered;
al->sym = map__find_symbol(al->map, al->addr, filter); al->sym = map__find_symbol(al->map, al->addr,
machine->symbol_filter);
} }
if (symbol_conf.sym_list && if (symbol_conf.sym_list &&
......
...@@ -234,8 +234,7 @@ struct addr_location; ...@@ -234,8 +234,7 @@ struct addr_location;
int perf_event__preprocess_sample(const union perf_event *self, int perf_event__preprocess_sample(const union perf_event *self,
struct machine *machine, struct machine *machine,
struct addr_location *al, struct addr_location *al,
struct perf_sample *sample, struct perf_sample *sample);
symbol_filter_t filter);
const char *perf_event__name(unsigned int id); const char *perf_event__name(unsigned int id);
......
...@@ -716,18 +716,19 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu) ...@@ -716,18 +716,19 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu)
char filename[MAXPATHLEN]; char filename[MAXPATHLEN];
char *buf = NULL, *p; char *buf = NULL, *p;
size_t len = 0; size_t len = 0;
ssize_t sret;
u32 i = 0; u32 i = 0;
int ret = -1; int ret = -1;
sprintf(filename, CORE_SIB_FMT, cpu); sprintf(filename, CORE_SIB_FMT, cpu);
fp = fopen(filename, "r"); fp = fopen(filename, "r");
if (!fp) if (!fp)
return -1; goto try_threads;
if (getline(&buf, &len, fp) <= 0)
goto done;
sret = getline(&buf, &len, fp);
fclose(fp); fclose(fp);
if (sret <= 0)
goto try_threads;
p = strchr(buf, '\n'); p = strchr(buf, '\n');
if (p) if (p)
...@@ -743,7 +744,9 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu) ...@@ -743,7 +744,9 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu)
buf = NULL; buf = NULL;
len = 0; len = 0;
} }
ret = 0;
try_threads:
sprintf(filename, THRD_SIB_FMT, cpu); sprintf(filename, THRD_SIB_FMT, cpu);
fp = fopen(filename, "r"); fp = fopen(filename, "r");
if (!fp) if (!fp)
......
...@@ -25,6 +25,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) ...@@ -25,6 +25,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->kmaps.machine = machine; machine->kmaps.machine = machine;
machine->pid = pid; machine->pid = pid;
machine->symbol_filter = NULL;
machine->root_dir = strdup(root_dir); machine->root_dir = strdup(root_dir);
if (machine->root_dir == NULL) if (machine->root_dir == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -95,6 +97,7 @@ void machines__init(struct machines *machines) ...@@ -95,6 +97,7 @@ void machines__init(struct machines *machines)
{ {
machine__init(&machines->host, "", HOST_KERNEL_ID); machine__init(&machines->host, "", HOST_KERNEL_ID);
machines->guests = RB_ROOT; machines->guests = RB_ROOT;
machines->symbol_filter = NULL;
} }
void machines__exit(struct machines *machines) void machines__exit(struct machines *machines)
...@@ -118,6 +121,8 @@ struct machine *machines__add(struct machines *machines, pid_t pid, ...@@ -118,6 +121,8 @@ struct machine *machines__add(struct machines *machines, pid_t pid,
return NULL; return NULL;
} }
machine->symbol_filter = machines->symbol_filter;
while (*p != NULL) { while (*p != NULL) {
parent = *p; parent = *p;
pos = rb_entry(parent, struct machine, rb_node); pos = rb_entry(parent, struct machine, rb_node);
...@@ -133,6 +138,21 @@ struct machine *machines__add(struct machines *machines, pid_t pid, ...@@ -133,6 +138,21 @@ struct machine *machines__add(struct machines *machines, pid_t pid,
return machine; return machine;
} }
void machines__set_symbol_filter(struct machines *machines,
symbol_filter_t symbol_filter)
{
struct rb_node *nd;
machines->symbol_filter = symbol_filter;
machines->host.symbol_filter = symbol_filter;
for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
struct machine *machine = rb_entry(nd, struct machine, rb_node);
machine->symbol_filter = symbol_filter;
}
}
struct machine *machines__find(struct machines *machines, pid_t pid) struct machine *machines__find(struct machines *machines, pid_t pid)
{ {
struct rb_node **p = &machines->guests.rb_node; struct rb_node **p = &machines->guests.rb_node;
...@@ -1110,7 +1130,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread, ...@@ -1110,7 +1130,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
* or else, the symbol is unknown * or else, the symbol is unknown
*/ */
thread__find_addr_location(thread, machine, m, MAP__FUNCTION, thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
ip, &al, NULL); ip, &al);
if (al.sym) if (al.sym)
goto found; goto found;
} }
...@@ -1128,8 +1148,8 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread, ...@@ -1128,8 +1148,8 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
memset(&al, 0, sizeof(al)); memset(&al, 0, sizeof(al));
thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al, thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr,
NULL); &al);
ams->addr = addr; ams->addr = addr;
ams->al_addr = al.addr; ams->al_addr = al.addr;
ams->sym = al.sym; ams->sym = al.sym;
...@@ -1224,7 +1244,7 @@ static int machine__resolve_callchain_sample(struct machine *machine, ...@@ -1224,7 +1244,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
al.filtered = false; al.filtered = false;
thread__find_addr_location(thread, machine, cpumode, thread__find_addr_location(thread, machine, cpumode,
MAP__FUNCTION, ip, &al, NULL); MAP__FUNCTION, ip, &al);
if (al.sym != NULL) { if (al.sym != NULL) {
if (sort__has_parent && !*parent && if (sort__has_parent && !*parent &&
symbol__match_regex(al.sym, &parent_regex)) symbol__match_regex(al.sym, &parent_regex))
......
...@@ -29,6 +29,7 @@ struct machine { ...@@ -29,6 +29,7 @@ struct machine {
struct list_head kernel_dsos; struct list_head kernel_dsos;
struct map_groups kmaps; struct map_groups kmaps;
struct map *vmlinux_maps[MAP__NR_TYPES]; struct map *vmlinux_maps[MAP__NR_TYPES];
symbol_filter_t symbol_filter;
}; };
static inline static inline
...@@ -51,6 +52,7 @@ typedef void (*machine__process_t)(struct machine *machine, void *data); ...@@ -51,6 +52,7 @@ typedef void (*machine__process_t)(struct machine *machine, void *data);
struct machines { struct machines {
struct machine host; struct machine host;
struct rb_root guests; struct rb_root guests;
symbol_filter_t symbol_filter;
}; };
void machines__init(struct machines *machines); void machines__init(struct machines *machines);
...@@ -68,6 +70,9 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid); ...@@ -68,6 +70,9 @@ struct machine *machines__findnew(struct machines *machines, pid_t pid);
void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
char *machine__mmap_name(struct machine *machine, char *bf, size_t size); char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
void machines__set_symbol_filter(struct machines *machines,
symbol_filter_t symbol_filter);
int machine__init(struct machine *machine, const char *root_dir, pid_t pid); int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
void machine__exit(struct machine *machine); void machine__exit(struct machine *machine);
void machine__delete_dead_threads(struct machine *machine); void machine__delete_dead_threads(struct machine *machine);
......
...@@ -1401,12 +1401,15 @@ int perf_session__process_events(struct perf_session *self, ...@@ -1401,12 +1401,15 @@ int perf_session__process_events(struct perf_session *self,
bool perf_session__has_traces(struct perf_session *session, const char *msg) bool perf_session__has_traces(struct perf_session *session, const char *msg)
{ {
if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) { struct perf_evsel *evsel;
pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
return false; list_for_each_entry(evsel, &session->evlist->entries, node) {
if (evsel->attr.type == PERF_TYPE_TRACEPOINT)
return true;
} }
return true; pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
return false;
} }
int maps__set_kallsyms_ref_reloc_sym(struct map **maps, int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
...@@ -1489,13 +1492,18 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, ...@@ -1489,13 +1492,18 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
struct perf_sample *sample, struct machine *machine, struct perf_sample *sample, struct machine *machine,
int print_sym, int print_dso, int print_symoffset) unsigned int print_opts, unsigned int stack_depth)
{ {
struct addr_location al; struct addr_location al;
struct callchain_cursor_node *node; struct callchain_cursor_node *node;
int print_ip = print_opts & PRINT_IP_OPT_IP;
if (perf_event__preprocess_sample(event, machine, &al, sample, int print_sym = print_opts & PRINT_IP_OPT_SYM;
NULL) < 0) { int print_dso = print_opts & PRINT_IP_OPT_DSO;
int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
char s = print_oneline ? ' ' : '\t';
if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
error("problem processing %d event, skipping it.\n", error("problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return; return;
...@@ -1511,12 +1519,14 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, ...@@ -1511,12 +1519,14 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
} }
callchain_cursor_commit(&callchain_cursor); callchain_cursor_commit(&callchain_cursor);
while (1) { while (stack_depth) {
node = callchain_cursor_current(&callchain_cursor); node = callchain_cursor_current(&callchain_cursor);
if (!node) if (!node)
break; break;
printf("\t%16" PRIx64, node->ip); if (print_ip)
printf("%c%16" PRIx64, s, node->ip);
if (print_sym) { if (print_sym) {
printf(" "); printf(" ");
if (print_symoffset) { if (print_symoffset) {
...@@ -1531,13 +1541,19 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, ...@@ -1531,13 +1541,19 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
map__fprintf_dsoname(node->map, stdout); map__fprintf_dsoname(node->map, stdout);
printf(")"); printf(")");
} }
printf("\n");
if (!print_oneline)
printf("\n");
callchain_cursor_advance(&callchain_cursor); callchain_cursor_advance(&callchain_cursor);
stack_depth--;
} }
} else { } else {
printf("%16" PRIx64, sample->ip); if (print_ip)
printf("%16" PRIx64, sample->ip);
if (print_sym) { if (print_sym) {
printf(" "); printf(" ");
if (print_symoffset) if (print_symoffset)
......
...@@ -41,6 +41,12 @@ struct perf_session { ...@@ -41,6 +41,12 @@ struct perf_session {
char filename[1]; char filename[1];
}; };
#define PRINT_IP_OPT_IP (1<<0)
#define PRINT_IP_OPT_SYM (1<<1)
#define PRINT_IP_OPT_DSO (1<<2)
#define PRINT_IP_OPT_SYMOFFSET (1<<3)
#define PRINT_IP_OPT_ONELINE (1<<4)
struct perf_tool; struct perf_tool;
struct perf_session *perf_session__new(const char *filename, int mode, struct perf_session *perf_session__new(const char *filename, int mode,
...@@ -103,7 +109,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, ...@@ -103,7 +109,7 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
struct perf_sample *sample, struct machine *machine, struct perf_sample *sample, struct machine *machine,
int print_sym, int print_dso, int print_symoffset); unsigned int print_opts, unsigned int stack_depth);
int perf_session__cpu_bitmap(struct perf_session *session, int perf_session__cpu_bitmap(struct perf_session *session,
const char *cpu_list, unsigned long *cpu_bitmap); const char *cpu_list, unsigned long *cpu_bitmap);
......
...@@ -41,12 +41,11 @@ static inline struct map *thread__find_map(struct thread *self, ...@@ -41,12 +41,11 @@ static inline struct map *thread__find_map(struct thread *self,
void thread__find_addr_map(struct thread *thread, struct machine *machine, void thread__find_addr_map(struct thread *thread, struct machine *machine,
u8 cpumode, enum map_type type, u64 addr, u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al, symbol_filter_t filter); struct addr_location *al);
void thread__find_addr_location(struct thread *thread, struct machine *machine, void thread__find_addr_location(struct thread *thread, struct machine *machine,
u8 cpumode, enum map_type type, u64 addr, u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al, struct addr_location *al);
symbol_filter_t filter);
static inline void *thread__priv(struct thread *thread) static inline void *thread__priv(struct thread *thread)
{ {
......
...@@ -272,7 +272,7 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui) ...@@ -272,7 +272,7 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
struct addr_location al; struct addr_location al;
thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER, thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
MAP__FUNCTION, ip, &al, NULL); MAP__FUNCTION, ip, &al);
return al.map; return al.map;
} }
...@@ -349,7 +349,7 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, ...@@ -349,7 +349,7 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
ssize_t size; ssize_t size;
thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER, thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
MAP__FUNCTION, addr, &al, NULL); MAP__FUNCTION, addr, &al);
if (!al.map) { if (!al.map) {
pr_debug("unwind: no map for %lx\n", (unsigned long)addr); pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
return -1; return -1;
...@@ -473,7 +473,7 @@ static int entry(u64 ip, struct thread *thread, struct machine *machine, ...@@ -473,7 +473,7 @@ static int entry(u64 ip, struct thread *thread, struct machine *machine,
thread__find_addr_location(thread, machine, thread__find_addr_location(thread, machine,
PERF_RECORD_MISC_USER, PERF_RECORD_MISC_USER,
MAP__FUNCTION, ip, &al, NULL); MAP__FUNCTION, ip, &al);
e.ip = ip; e.ip = ip;
e.map = al.map; e.map = al.map;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment