aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r--tools/perf/util/machine.c107
1 files changed, 89 insertions, 18 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index df85b9efd80f..71c9720d4973 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -87,6 +87,25 @@ out_delete:
return NULL;
}
+struct machine *machine__new_kallsyms(void)
+{
+ struct machine *machine = machine__new_host();
+ /*
+ * FIXME:
+ * 1) MAP__FUNCTION will go away when we stop loading separate maps for
+ * functions and data objects.
+ * 2) We should switch to machine__load_kallsyms(), i.e. not explicitely
+ * ask for not using the kcore parsing code, once this one is fixed
+ * to create a map per module.
+ */
+ if (machine && __machine__load_kallsyms(machine, "/proc/kallsyms", MAP__FUNCTION, true) <= 0) {
+ machine__delete(machine);
+ machine = NULL;
+ }
+
+ return machine;
+}
+
static void dsos__purge(struct dsos *dsos)
{
struct dso *pos, *n;
@@ -763,7 +782,7 @@ static u64 machine__get_running_kernel_start(struct machine *machine,
int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
{
- enum map_type type;
+ int type;
u64 start = machine__get_running_kernel_start(machine, NULL);
/* In case of renewal the kernel map, destroy previous one */
@@ -794,7 +813,7 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
void machine__destroy_kernel_maps(struct machine *machine)
{
- enum map_type type;
+ int type;
for (type = 0; type < MAP__NR_TYPES; ++type) {
struct kmap *kmap;
@@ -1546,7 +1565,7 @@ int machine__process_event(struct machine *machine, union perf_event *event,
static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
{
- if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
+ if (!regexec(regex, sym->name, 0, NULL, 0))
return 1;
return 0;
}
@@ -1616,7 +1635,11 @@ static int add_callchain_ip(struct thread *thread,
struct symbol **parent,
struct addr_location *root_al,
u8 *cpumode,
- u64 ip)
+ u64 ip,
+ bool branch,
+ struct branch_flags *flags,
+ int nr_loop_iter,
+ int samples)
{
struct addr_location al;
@@ -1668,7 +1691,8 @@ static int add_callchain_ip(struct thread *thread,
if (symbol_conf.hide_unresolved && al.sym == NULL)
return 0;
- return callchain_cursor_append(cursor, al.addr, al.map, al.sym);
+ return callchain_cursor_append(cursor, al.addr, al.map, al.sym,
+ branch, flags, nr_loop_iter, samples);
}
struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
@@ -1757,7 +1781,9 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
/* LBR only affects the user callchain */
if (i != chain_nr) {
struct branch_stack *lbr_stack = sample->branch_stack;
- int lbr_nr = lbr_stack->nr, j;
+ int lbr_nr = lbr_stack->nr, j, k;
+ bool branch;
+ struct branch_flags *flags;
/*
* LBR callstack can only get user call chain.
* The mix_chain_nr is kernel call chain
@@ -1772,23 +1798,41 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
for (j = 0; j < mix_chain_nr; j++) {
int err;
+ branch = false;
+ flags = NULL;
+
if (callchain_param.order == ORDER_CALLEE) {
if (j < i + 1)
ip = chain->ips[j];
- else if (j > i + 1)
- ip = lbr_stack->entries[j - i - 2].from;
- else
+ else if (j > i + 1) {
+ k = j - i - 2;
+ ip = lbr_stack->entries[k].from;
+ branch = true;
+ flags = &lbr_stack->entries[k].flags;
+ } else {
ip = lbr_stack->entries[0].to;
+ branch = true;
+ flags = &lbr_stack->entries[0].flags;
+ }
} else {
- if (j < lbr_nr)
- ip = lbr_stack->entries[lbr_nr - j - 1].from;
+ if (j < lbr_nr) {
+ k = lbr_nr - j - 1;
+ ip = lbr_stack->entries[k].from;
+ branch = true;
+ flags = &lbr_stack->entries[k].flags;
+ }
else if (j > lbr_nr)
ip = chain->ips[i + 1 - (j - lbr_nr)];
- else
+ else {
ip = lbr_stack->entries[0].to;
+ branch = true;
+ flags = &lbr_stack->entries[0].flags;
+ }
}
- err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip);
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, ip,
+ branch, flags, 0, 0);
if (err)
return (err < 0) ? err : 0;
}
@@ -1813,6 +1857,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
int i, j, err, nr_entries;
int skip_idx = -1;
int first_call = 0;
+ int nr_loop_iter;
if (perf_evsel__has_branch_callstack(evsel)) {
err = resolve_lbr_callchain_sample(thread, cursor, sample, parent,
@@ -1868,14 +1913,37 @@ static int thread__resolve_callchain_sample(struct thread *thread,
be[i] = branch->entries[branch->nr - i - 1];
}
+ nr_loop_iter = nr;
nr = remove_loops(be, nr);
+ /*
+ * Get the number of iterations.
+ * It's only approximation, but good enough in practice.
+ */
+ if (nr_loop_iter > nr)
+ nr_loop_iter = nr_loop_iter - nr + 1;
+ else
+ nr_loop_iter = 0;
+
for (i = 0; i < nr; i++) {
- err = add_callchain_ip(thread, cursor, parent, root_al,
- NULL, be[i].to);
+ if (i == nr - 1)
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al,
+ NULL, be[i].to,
+ true, &be[i].flags,
+ nr_loop_iter, 1);
+ else
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al,
+ NULL, be[i].to,
+ true, &be[i].flags,
+ 0, 0);
+
if (!err)
err = add_callchain_ip(thread, cursor, parent, root_al,
- NULL, be[i].from);
+ NULL, be[i].from,
+ true, &be[i].flags,
+ 0, 0);
if (err == -EINVAL)
break;
if (err)
@@ -1903,7 +1971,9 @@ check_calls:
if (ip < PERF_CONTEXT_MAX)
++nr_entries;
- err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip);
+ err = add_callchain_ip(thread, cursor, parent,
+ root_al, &cpumode, ip,
+ false, NULL, 0, 0);
if (err)
return (err < 0) ? err : 0;
@@ -1919,7 +1989,8 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
if (symbol_conf.hide_unresolved && entry->sym == NULL)
return 0;
return callchain_cursor_append(cursor, entry->ip,
- entry->map, entry->sym);
+ entry->map, entry->sym,
+ false, NULL, 0, 0);
}
static int thread__resolve_callchain_unwind(struct thread *thread,