diff options
Diffstat (limited to 'tools/perf/util/machine.c')
| -rw-r--r-- | tools/perf/util/machine.c | 82 | 
1 files changed, 67 insertions, 15 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index df85b9efd80f..9b33bef54581 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1616,7 +1616,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 +1672,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 +1762,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 +1779,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 +1838,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 +1894,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 +1952,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 +1970,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,  |