Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf36eb5c authored by Milian Wolff's avatar Milian Wolff Committed by Arnaldo Carvalho de Melo
Browse files

perf report: Properly handle branch count in match_chain()



Some of the code paths I introduced before returned too early without
running the code to handle a node's branch count.  By refactoring
match_chain to only have one exit point, this can be remedied.

Signed-off-by: default avatarMilian Wolff <milian.wolff@kdab.com>
Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1707691.qaJ269GSZW@agathebauer
Link: http://lkml.kernel.org/r/20171018185350.14893-2-milian.wolff@kdab.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent aa441895
Loading
Loading
Loading
Loading
+78 −62
Original line number Diff line number Diff line
@@ -666,49 +666,69 @@ static enum match_result match_chain_strings(const char *left,
	return ret;
}

static enum match_result match_chain(struct callchain_cursor_node *node,
				     struct callchain_list *cnode)
/*
 * We need to always use relative addresses because we're aggregating
 * callchains from multiple threads, i.e. different address spaces, so
 * comparing absolute addresses make no sense as a symbol in a DSO may end up
 * in a different address when used in a different binary or even the same
 * binary but with some sort of address randomization technique, thus we need
 * to compare just relative addresses. -acme
 */
static enum match_result match_chain_dso_addresses(struct map *left_map, u64 left_ip,
						   struct map *right_map, u64 right_ip)
{
	struct symbol *sym = node->sym;
	u64 left, right;
	struct dso *left_dso = NULL;
	struct dso *right_dso = NULL;
	struct dso *left_dso = left_map ? left_map->dso : NULL;
	struct dso *right_dso = right_map ? right_map->dso : NULL;

	if (callchain_param.key == CCKEY_SRCLINE) {
		enum match_result match = match_chain_strings(cnode->srcline,
							      node->srcline);
	if (left_dso != right_dso)
		return left_dso < right_dso ? MATCH_LT : MATCH_GT;

		/* if no srcline is available, fallback to symbol name */
		if (match == MATCH_ERROR && cnode->ms.sym && node->sym)
			match = match_chain_strings(cnode->ms.sym->name,
						    node->sym->name);

		if (match != MATCH_ERROR)
			return match;
	if (left_ip != right_ip)
 		return left_ip < right_ip ? MATCH_LT : MATCH_GT;

		/* otherwise fall-back to IP-based comparison below */
	return MATCH_EQ;
}

	if (cnode->ms.sym && sym && callchain_param.key == CCKEY_FUNCTION) {
static enum match_result match_chain(struct callchain_cursor_node *node,
				     struct callchain_list *cnode)
{
	enum match_result match = MATCH_ERROR;

	switch (callchain_param.key) {
	case CCKEY_SRCLINE:
		match = match_chain_strings(cnode->srcline, node->srcline);
		if (match != MATCH_ERROR)
			break;
		/* otherwise fall-back to symbol-based comparison below */
		__fallthrough;
	case CCKEY_FUNCTION:
		if (node->sym && cnode->ms.sym) {
			/*
		 * Compare inlined frames based on their symbol name because
		 * different inlined frames will have the same symbol start
			 * Compare inlined frames based on their symbol name
			 * because different inlined frames will have the same
			 * symbol start. Otherwise do a faster comparison based
			 * on the symbol start address.
			 */
		if (cnode->ms.sym->inlined || node->sym->inlined)
			return match_chain_strings(cnode->ms.sym->name,
			if (cnode->ms.sym->inlined || node->sym->inlined) {
				match = match_chain_strings(cnode->ms.sym->name,
							    node->sym->name);

		left = cnode->ms.sym->start;
		right = sym->start;
		left_dso = cnode->ms.map->dso;
		right_dso = node->map->dso;
				if (match != MATCH_ERROR)
					break;
			} else {
		left = cnode->ip;
		right = node->ip;
				match = match_chain_dso_addresses(cnode->ms.map, cnode->ms.sym->start,
								  node->map, node->sym->start);
				break;
			}
		}
		/* otherwise fall-back to IP-based comparison below */
		__fallthrough;
	case CCKEY_ADDRESS:
	default:
		match = match_chain_dso_addresses(cnode->ms.map, cnode->ip, node->map, node->ip);
		break;
	}

	if (left == right && left_dso == right_dso) {
		if (node->branch) {
	if (match == MATCH_EQ && node->branch) {
		cnode->branch_count++;

		if (node->branch_from) {
@@ -732,17 +752,13 @@ static enum match_result match_chain(struct callchain_cursor_node *node,
			 * It's "from" of a branch
			 */
			cnode->brtype_stat.branch_to = false;
				cnode->cycles_count +=
					node->branch_flags.cycles;
			cnode->cycles_count += node->branch_flags.cycles;
			cnode->iter_count += node->nr_loop_iter;
			cnode->iter_cycles += node->iter_cycles;
		}
	}

		return MATCH_EQ;
	}

	return left > right ? MATCH_GT : MATCH_LT;
	return match;
}

/*