perf tools: Move hist_entry__add common code to hist.c

Now perf report and annotate do the callgraph/hit processing in
their specialized hist_entry__add functions.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 7d5a3b1..8550942 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -80,48 +80,16 @@
 			sym->hist[offset]);
 }
 
-static int
-hist_entry__add(struct thread *thread, struct map *map,
-		struct symbol *sym, u64 ip, char level)
+static int hist_entry__add(struct thread *thread, struct map *map,
+			   struct symbol *sym, u64 ip, u64 count, char level)
 {
-	struct rb_node **p = &hist.rb_node;
-	struct rb_node *parent = NULL;
-	struct hist_entry *he;
-	struct hist_entry entry = {
-		.thread	= thread,
-		.map	= map,
-		.sym	= sym,
-		.ip	= ip,
-		.level	= level,
-		.count	= 1,
-	};
-	int cmp;
-
-	while (*p != NULL) {
-		parent = *p;
-		he = rb_entry(parent, struct hist_entry, rb_node);
-
-		cmp = hist_entry__cmp(&entry, he);
-
-		if (!cmp) {
-			hist_hit(he, ip);
-
-			return 0;
-		}
-
-		if (cmp < 0)
-			p = &(*p)->rb_left;
-		else
-			p = &(*p)->rb_right;
-	}
-
-	he = malloc(sizeof(*he));
-	if (!he)
+	bool hit;
+	struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip,
+						  count, level, &hit);
+	if (he == NULL)
 		return -ENOMEM;
-	*he = entry;
-	rb_link_node(&he->rb_node, parent, p);
-	rb_insert_color(&he->rb_node, &hist);
-
+	if (hit)
+		hist_hit(he, ip);
 	return 0;
 }
 
@@ -191,7 +159,7 @@
 	}
 
 	if (show & show_mask) {
-		if (hist_entry__add(thread, map, sym, ip, level)) {
+		if (hist_entry__add(thread, map, sym, ip, 1, level)) {
 			fprintf(stderr,
 		"problem incrementing symbol count, skipping event\n");
 			return -1;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3ed3baf..0e83ffc 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -407,9 +407,9 @@
 	return 0;
 }
 
-static struct symbol **
-resolve_callchain(struct thread *thread, struct map *map,
-		    struct ip_callchain *chain, struct hist_entry *entry)
+static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
+					 struct ip_callchain *chain,
+					 struct symbol **parent)
 {
 	u64 context = PERF_CONTEXT_MAX;
 	struct symbol **syms = NULL;
@@ -444,9 +444,8 @@
 		}
 
 		if (sym) {
-			if (sort__has_parent && call__match(sym) &&
-			    !entry->parent)
-				entry->parent = sym;
+			if (sort__has_parent && !*parent && call__match(sym))
+				*parent = sym;
 			if (!callchain)
 				break;
 			syms[i] = sym;
@@ -465,57 +464,27 @@
 		struct symbol *sym, u64 ip, struct ip_callchain *chain,
 		char level, u64 count)
 {
-	struct rb_node **p = &hist.rb_node;
-	struct rb_node *parent = NULL;
+	struct symbol **syms = NULL, *parent = NULL;
+	bool hit;
 	struct hist_entry *he;
-	struct symbol **syms = NULL;
-	struct hist_entry entry = {
-		.thread	= thread,
-		.map	= map,
-		.sym	= sym,
-		.ip	= ip,
-		.level	= level,
-		.count	= count,
-		.parent = NULL,
-		.sorted_chain = RB_ROOT
-	};
-	int cmp;
 
 	if ((sort__has_parent || callchain) && chain)
-		syms = resolve_callchain(thread, map, chain, &entry);
+		syms = resolve_callchain(thread, map, chain, &parent);
 
-	while (*p != NULL) {
-		parent = *p;
-		he = rb_entry(parent, struct hist_entry, rb_node);
-
-		cmp = hist_entry__cmp(&entry, he);
-
-		if (!cmp) {
-			he->count += count;
-			if (callchain) {
-				append_chain(&he->callchain, chain, syms);
-				free(syms);
-			}
-			return 0;
-		}
-
-		if (cmp < 0)
-			p = &(*p)->rb_left;
-		else
-			p = &(*p)->rb_right;
-	}
-
-	he = malloc(sizeof(*he));
-	if (!he)
+	he = __hist_entry__add(thread, map, sym, parent,
+			       ip, count, level, &hit);
+	if (he == NULL)
 		return -ENOMEM;
-	*he = entry;
+
+	if (hit)
+		he->count += count;
+
 	if (callchain) {
-		callchain_init(&he->callchain);
+		if (!hit)
+			callchain_init(&he->callchain);
 		append_chain(&he->callchain, chain, syms);
 		free(syms);
 	}
-	rb_link_node(&he->rb_node, parent, p);
-	rb_insert_color(&he->rb_node, &hist);
 
 	return 0;
 }
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 82808dc..7393a02 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -21,6 +21,52 @@
  * histogram, sorted on item, collects counts
  */
 
+struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
+				     struct symbol *sym,
+				     struct symbol *sym_parent,
+				     u64 ip, u64 count, char level, bool *hit)
+{
+	struct rb_node **p = &hist.rb_node;
+	struct rb_node *parent = NULL;
+	struct hist_entry *he;
+	struct hist_entry entry = {
+		.thread	= thread,
+		.map	= map,
+		.sym	= sym,
+		.ip	= ip,
+		.level	= level,
+		.count	= count,
+		.parent = sym_parent,
+	};
+	int cmp;
+
+	while (*p != NULL) {
+		parent = *p;
+		he = rb_entry(parent, struct hist_entry, rb_node);
+
+		cmp = hist_entry__cmp(&entry, he);
+
+		if (!cmp) {
+			*hit = true;
+			return he;
+		}
+
+		if (cmp < 0)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+
+	he = malloc(sizeof(*he));
+	if (!he)
+		return NULL;
+	*he = entry;
+	rb_link_node(&he->rb_node, parent, p);
+	rb_insert_color(&he->rb_node, &hist);
+	*hit = false;
+	return he;
+}
+
 int64_t
 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
 {
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 9a8daa1..ac2149c 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -36,6 +36,9 @@
 extern unsigned long total_unknown;
 extern unsigned long total_lost;
 
+struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
+				     struct symbol *sym, struct symbol *parent,
+				     u64 ip, u64 count, char level, bool *hit);
 extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
 extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
 extern void hist_entry__free(struct hist_entry *);