public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1)
@ 2012-07-24  9:01 Namhyung Kim
  2012-07-24  9:01 ` [PATCH 01/12] perf tools: Add a couple of helper routines to handle groups Namhyung Kim
                   ` (13 more replies)
  0 siblings, 14 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen

Hi all,

This is a patchset to support event grouping on perf report.

It depends on other patches like refactoring hist print [1],
processing file header feature [2] and (obviously) Jiri's event group
management [3]. All of this need to be reviewed though. ;)

The basic idea is move group member's hist entries to a leader, and
sort/collapse them on the leader's tree. The leader will have all of
group members' stat in it. The output is sorted by the leader's period
and in turn first child and so on.

To use it, 'perf record' should group events when recording. And then
perf report parses the saved command line and reconstruct the group
relation. Currently only the '-e { event1,event2 }' syntax is supported
(i.e. --group option is *NOT* supported) to make things easy. But it'd
not be that hard to support --group also.

But I think re-using event parsing routine (at least, in its current
form) has some problems especially if perf report will not run on the
same machine that runs perf record. I cannot find a better way than
extending/changing the perf file format to let perf record know about
the group relationship. Any thought?

Here is an example:

  $ ./perf record -e cycles:u -e '{cache-references,cache-misses}:u' noploop 1

Without --group:

  $ ./perf report --stdio
  ...
  # Samples: 4K of event 'cycles:u'
  # Event count (approx.): 3692183905
  #
  # Overhead  Command       Shared Object                   Symbol
  # ........  .......  ..................  .......................
  #
      99.98%  noploop  noploop             [.] main               
       0.01%  noploop  ld-2.15.so          [.] _dl_relocate_object
       0.00%  noploop  [kernel.kallsyms]   [k] page_fault         
       0.00%  noploop  libc-2.15.so        [.] __execvpe          
       0.00%  noploop  libpthread-2.15.so  [.] __read_nocancel    
       0.00%  noploop  ld-2.15.so          [.] _start             
  
  
  # Samples: 26  of event 'cache-references:u'
  # Event count (approx.): 4229
  #
  # Overhead  Command       Shared Object                              Symbol
  # ........  .......  ..................  ..................................
  #
      55.85%  noploop  ld-2.15.so          [.] do_lookup_x                   
      19.18%  noploop  ld-2.15.so          [.] strlen                        
      14.09%  noploop  libc-2.15.so        [.] getenv                        
       3.17%  noploop  ld-2.15.so          [.] _dl_fini                      
       2.65%  noploop  noploop             [.] main                          
       1.44%  noploop  perf                [.] perf_evlist__prepare_workload 
       1.44%  noploop  [kernel.kallsyms]   [k] page_fault                    
       0.99%  noploop  [kernel.kallsyms]   [k] apic_timer_interrupt          
       0.33%  noploop  noploop             [.] handler                       
       0.33%  noploop  libc-2.15.so        [.] __run_exit_handlers           
       0.33%  noploop  [kernel.kallsyms]   [k] call_function_single_interrupt
       0.12%  noploop  ld-2.15.so          [.] _dl_start                     
       0.05%  noploop  libpthread-2.15.so  [.] __read_nocancel               
       0.02%  noploop  ld-2.15.so          [.] _start                        
  
  
  # Samples: 23  of event 'cache-misses:u'
  # Event count (approx.): 4312
  #
  # Overhead  Command       Shared Object                                Symbol
  # ........  .......  ..................  ....................................
  #
      46.94%  noploop  ld-2.15.so          [.] do_lookup_x                     
      21.78%  noploop  libc-2.15.so        [.] getenv                          
      18.65%  noploop  ld-2.15.so          [.] calloc                          
       6.05%  noploop  ld-2.15.so          [.] rtld_lock_default_lock_recursive
       2.92%  noploop  noploop             [.] main                            
       1.41%  noploop  [kernel.kallsyms]   [k] page_fault                      
       1.32%  noploop  libc-2.15.so        [.] execvp                          
       0.32%  noploop  libc-2.15.so        [.] __run_exit_handlers             
       0.32%  noploop  ld-2.15.so          [.] _dl_fini                        
       0.12%  noploop  perf                [.] perf_evlist__prepare_workload   
       0.12%  noploop  ld-2.15.so          [.] _dl_start                       
       0.02%  noploop  libpthread-2.15.so  [.] __read_nocancel                 
       0.02%  noploop  ld-2.15.so          [.] _start                          
  

With --group:

  $ ./perf report --group --stdio
  ...
  # Samples: 4K of event 'cycles:u'
  # Event count (approx.): 7384367810
  #
  # Overhead  Command       Shared Object                   Symbol
  # ........  .......  ..................  .......................
  #
      99.98%  noploop  noploop             [.] main               
       0.01%  noploop  ld-2.15.so          [.] _dl_relocate_object
       0.00%  noploop  [kernel.kallsyms]   [k] page_fault         
       0.00%  noploop  libc-2.15.so        [.] __execvpe          
       0.00%  noploop  libpthread-2.15.so  [.] __read_nocancel    
       0.00%  noploop  ld-2.15.so          [.] _start             
  
  
  # Samples: 49  of event 'anon_group { cache-references:u, cache-misses:u }'
  # Event count (approx.): 12770
  #
  # Overhead          Command       Shared Object                                Symbol
  # ................  .......  ..................  ....................................
  #
      55.85%  46.94%  noploop  ld-2.15.so          [.] do_lookup_x                     
      19.18%   0.00%  noploop  ld-2.15.so          [.] strlen                          
      14.09%  21.78%  noploop  libc-2.15.so        [.] getenv                          
       3.17%   0.32%  noploop  ld-2.15.so          [.] _dl_fini                        
       2.65%   2.92%  noploop  noploop             [.] main                            
       1.44%   1.41%  noploop  [kernel.kallsyms]   [k] page_fault                      
       1.44%   0.12%  noploop  perf                [.] perf_evlist__prepare_workload   
       0.99%   0.00%  noploop  [kernel.kallsyms]   [k] apic_timer_interrupt            
       0.33%   0.32%  noploop  libc-2.15.so        [.] __run_exit_handlers             
       0.33%   0.00%  noploop  noploop             [.] handler                         
       0.33%   0.00%  noploop  [kernel.kallsyms]   [k] call_function_single_interrupt  
       0.12%   0.12%  noploop  ld-2.15.so          [.] _dl_start                       
       0.05%   0.02%  noploop  libpthread-2.15.so  [.] __read_nocancel                 
       0.02%   0.02%  noploop  ld-2.15.so          [.] _start                          
       0.00%  18.65%  noploop  ld-2.15.so          [.] calloc                          
       0.00%   6.05%  noploop  ld-2.15.so          [.] rtld_lock_default_lock_recursive
       0.00%   1.32%  noploop  libc-2.15.so        [.] execvp                          
  
(Hmm.. looks like there's a bug in group event counting in the header
area. But I believe the period value itself is intact.)

You can access it via my tree as well (if you want to test it).

  git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git perf/report-group-v1

Any comments are welcome, thanks.
Namhyung

[1] https://lkml.org/lkml/2012/7/19/263
[2] https://lkml.org/lkml/2012/7/21/75
[3] https://lkml.org/lkml/2012/7/19/419


Namhyung Kim (12):
  perf tools: Add a couple of helper routines to handle groups
  perf hist: Convert to struct he_stat
  perf hist: Collapse group hist_entries to a leader
  perf hist: Maintain total periods of group members in the leader
  perf report: Make another loop for output resorting
  perf header: Reconstruct group relationship by parsing cmdline
  perf ui/hist: Add support to group viewing
  perf ui/browser: Add support to group viewing
  perf ui/gtk: Add support to group viewing
  perf report: Show leader events only when event group is enabled
  perf report: Show group description when event group is enabled
  perf report: Add --group option

 tools/perf/builtin-report.c    |   29 +++++++
 tools/perf/ui/browsers/hists.c |  105 +++++++++++++++++++++---
 tools/perf/ui/gtk/browser.c    |   69 +++++++++++++---
 tools/perf/ui/hist.c           |  158 +++++++++++++++++++++++++++++------
 tools/perf/util/evsel.c        |   25 ++++++
 tools/perf/util/evsel.h        |   21 +++++
 tools/perf/util/header.c       |  110 +++++++++++++++++++++++++
 tools/perf/util/hist.c         |  177 ++++++++++++++++++++++++++++++++++------
 tools/perf/util/hist.h         |    1 +
 tools/perf/util/parse-events.c |    6 +-
 tools/perf/util/sort.h         |   17 ++--
 tools/perf/util/symbol.c       |    4 +
 tools/perf/util/symbol.h       |    3 +-
 13 files changed, 641 insertions(+), 84 deletions(-)

-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 01/12] perf tools: Add a couple of helper routines to handle groups
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 02/12] perf hist: Convert to struct he_stat Namhyung Kim
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen

This is a preparation for upcoming event grouping feature.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/evsel.h        |   19 +++++++++++++++++++
 tools/perf/util/parse-events.c |    6 +++++-
 tools/perf/util/sort.h         |   10 ++++++++++
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index a4a11f8dfcf5..efc9e5c42210 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -70,8 +70,27 @@ struct perf_evsel {
 	int			exclude_GH;
 	struct perf_evsel	*leader;
 	char			*group_name;
+	union {
+		int		nr_children;
+		int		group_idx;
+	};
 };
 
+static inline struct perf_evsel *hists_2_evsel(struct hists *hists)
+{
+	return container_of(hists, struct perf_evsel, hists);
+}
+
+static inline bool perf_evsel__is_group_leader(struct perf_evsel *evsel)
+{
+	return evsel->leader == NULL;
+}
+
+#define for_each_group_member(_evsel, _leader)				   \
+for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \
+     (_evsel) && (_evsel)->leader == (_leader);				   \
+     (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
+
 struct cpu_map;
 struct thread_map;
 struct perf_evlist;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9eaae05c088d..25dcf9043902 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -611,15 +611,19 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
 
 struct perf_evsel *parse_events__group_leader(struct list_head *list)
 {
+	int idx = 0;
 	struct perf_evsel *evsel, *leader;
 
 	leader = list_entry(list->next, struct perf_evsel, node);
 	leader->leader = NULL;
 
 	list_for_each_entry(evsel, list, node)
-		if (evsel != leader)
+		if (evsel != leader) {
 			evsel->leader = leader;
+			evsel->group_idx = idx++;
+		}
 
+	leader->nr_children = idx;
 	return leader;
 }
 
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index e724b26acd51..9fdd5039339f 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -43,6 +43,15 @@ extern struct sort_entry sort_sym_from;
 extern struct sort_entry sort_sym_to;
 extern enum sort_type sort__first_dimension;
 
+struct he_stat {
+	u64			period;
+	u64			period_sys;
+	u64			period_us;
+	u64			period_guest_sys;
+	u64			period_guest_us;
+	u32			nr_events;
+};
+
 /**
  * struct hist_entry - histogram entry
  *
@@ -57,6 +66,7 @@ struct hist_entry {
 	u64			period_us;
 	u64			period_guest_sys;
 	u64			period_guest_us;
+	struct he_stat		*group_stats;
 	struct map_symbol	ms;
 	struct thread		*thread;
 	u64			ip;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 02/12] perf hist: Convert to struct he_stat
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
  2012-07-24  9:01 ` [PATCH 01/12] perf tools: Add a couple of helper routines to handle groups Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 03/12] perf hist: Collapse group hist_entries to a leader Namhyung Kim
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen

As we have struct he_stat, convert hist_entry's fields to he_stat.
It'll make it easy to deal with group stats.

This is a mechinical change and should not have any functional changes.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/ui/browsers/hists.c |    8 ++++----
 tools/perf/ui/gtk/browser.c    |    2 +-
 tools/perf/ui/hist.c           |   30 +++++++++++++--------------
 tools/perf/util/hist.c         |   44 ++++++++++++++++++++++------------------
 tools/perf/util/sort.h         |    7 +------
 5 files changed, 45 insertions(+), 46 deletions(-)

diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index c261804f467c..69584d79097e 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -557,7 +557,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
 static int hist_browser__hpp_color_ ## _name(struct hist_print_context *ctx,	\
 					     struct hist_entry *he)		\
 {										\
-	double percent = 100.0 * he->_field / ctx->total_period;		\
+	double percent = 100.0 * he->stat._field / ctx->total_period;		\
 	*(double *)ctx->ptr = percent;						\
 	return scnprintf(ctx->s, ctx->size, "%5.2f%%", percent);		\
 }
@@ -976,7 +976,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
 		folded_sign = hist_entry__folded(he);
 
 	hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
-	percent = (he->period * 100.0) / browser->hists->stats.total_period;
+	percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
 
 	if (symbol_conf.use_callchain)
 		printed += fprintf(fp, "%c ", folded_sign);
@@ -984,10 +984,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
 	printed += fprintf(fp, " %5.2f%%", percent);
 
 	if (symbol_conf.show_nr_samples)
-		printed += fprintf(fp, " %11u", he->nr_events);
+		printed += fprintf(fp, " %11u", he->stat.nr_events);
 
 	if (symbol_conf.show_total_period)
-		printed += fprintf(fp, " %12" PRIu64, he->period);
+		printed += fprintf(fp, " %12" PRIu64, he->stat.period);
 
 	printed += fprintf(fp, "%s\n", rtrim(s));
 
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 1e06d6a0ba34..91e11f7bffbf 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -48,7 +48,7 @@ static const char *perf_gtk__get_percent_color(double percent)
 static int perf_gtk__hpp_color_ ## _name(struct hist_print_context *ctx,	\
 					 struct hist_entry *he)			\
 {										\
-	double percent = 100.0 * he->_field / ctx->total_period;		\
+	double percent = 100.0 * he->stat._field / ctx->total_period;		\
 	const char *markup;							\
 	int ret = 0;								\
 										\
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 7e3a5d67764a..8092a621bbec 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -21,14 +21,14 @@ static int hpp_width_overhead(struct hist_print_context *ctx __used)
 static int hpp_color_overhead(struct hist_print_context *ctx,
 			      struct hist_entry *he)
 {
-	double percent = 100.0 * he->period / ctx->total_period;
+	double percent = 100.0 * he->stat.period / ctx->total_period;
 	return percent_color_snprintf(ctx->s, ctx->size, "  %5.2f%%", percent);
 }
 
 static int hpp_entry_overhead(struct hist_print_context *ctx,
 			      struct hist_entry *he)
 {
-	double percent = 100.0 * he->period / ctx->total_period;
+	double percent = 100.0 * he->stat.period / ctx->total_period;
 	return scnprintf(ctx->s, ctx->size, "  %5.2f%%", percent);
 }
 
@@ -45,14 +45,14 @@ static int hpp_width_overhead_sys(struct hist_print_context *ctx __used)
 static int hpp_color_overhead_sys(struct hist_print_context *ctx,
 				  struct hist_entry *he)
 {
-	double percent = 100.0 * he->period_sys / ctx->total_period;
+	double percent = 100.0 * he->stat.period_sys / ctx->total_period;
 	return percent_color_snprintf(ctx->s, ctx->size, "%5.2f%%", percent);
 }
 
 static int hpp_entry_overhead_sys(struct hist_print_context *ctx,
 				  struct hist_entry *he)
 {
-	double percent = 100.0 * he->period_sys / ctx->total_period;
+	double percent = 100.0 * he->stat.period_sys / ctx->total_period;
 	return scnprintf(ctx->s, ctx->size, "%5.2f%%", percent);
 }
 
@@ -69,14 +69,14 @@ static int hpp_width_overhead_us(struct hist_print_context *ctx __used)
 static int hpp_color_overhead_us(struct hist_print_context *ctx,
 				 struct hist_entry *he)
 {
-	double percent = 100.0 * he->period_us / ctx->total_period;
+	double percent = 100.0 * he->stat.period_us / ctx->total_period;
 	return percent_color_snprintf(ctx->s, ctx->size, "%5.2f%%", percent);
 }
 
 static int hpp_entry_overhead_us(struct hist_print_context *ctx,
 				 struct hist_entry *he)
 {
-	double percent = 100.0 * he->period_us / ctx->total_period;
+	double percent = 100.0 * he->stat.period_us / ctx->total_period;
 	return scnprintf(ctx->s, ctx->size, "%5.2f%%", percent);
 }
 
@@ -93,14 +93,14 @@ static int hpp_width_overhead_guest_sys(struct hist_print_context *ctx __used)
 static int hpp_color_overhead_guest_sys(struct hist_print_context *ctx,
 					struct hist_entry *he)
 {
-	double percent = 100.0 * he->period_guest_sys / ctx->total_period;
+	double percent = 100.0 * he->stat.period_guest_sys / ctx->total_period;
 	return percent_color_snprintf(ctx->s, ctx->size, "  %5.2f%% ", percent);
 }
 
 static int hpp_entry_overhead_guest_sys(struct hist_print_context *ctx,
 					struct hist_entry *he)
 {
-	double percent = 100.0 * he->period_guest_sys / ctx->total_period;
+	double percent = 100.0 * he->stat.period_guest_sys / ctx->total_period;
 	return scnprintf(ctx->s, ctx->size, "  %5.2f%% ", percent);
 }
 
@@ -117,14 +117,14 @@ static int hpp_width_overhead_guest_us(struct hist_print_context *ctx __used)
 static int hpp_color_overhead_guest_us(struct hist_print_context *ctx,
 				       struct hist_entry *he)
 {
-	double percent = 100.0 * he->period_guest_us / ctx->total_period;
+	double percent = 100.0 * he->stat.period_guest_us / ctx->total_period;
 	return percent_color_snprintf(ctx->s, ctx->size, "  %5.2f%% ", percent);
 }
 
 static int hpp_entry_overhead_guest_us(struct hist_print_context *ctx,
 				       struct hist_entry *he)
 {
-	double percent = 100.0 * he->period_guest_us / ctx->total_period;
+	double percent = 100.0 * he->stat.period_guest_us / ctx->total_period;
 	return scnprintf(ctx->s, ctx->size, "  %5.2f%% ", percent);
 }
 
@@ -141,7 +141,7 @@ static int hpp_width_samples(struct hist_print_context *ctx __used)
 static int hpp_entry_samples(struct hist_print_context *ctx,
 			     struct hist_entry *he)
 {
-	return scnprintf(ctx->s, ctx->size, "%11" PRIu64, he->nr_events);
+	return scnprintf(ctx->s, ctx->size, "%11" PRIu64, he->stat.nr_events);
 }
 
 static int hpp_header_period(struct hist_print_context *ctx)
@@ -157,7 +157,7 @@ static int hpp_width_period(struct hist_print_context *ctx __used)
 static int hpp_entry_period(struct hist_print_context *ctx,
 			    struct hist_entry *he)
 {
-	return scnprintf(ctx->s, ctx->size, "%12" PRIu64, he->period);
+	return scnprintf(ctx->s, ctx->size, "%12" PRIu64, he->stat.period);
 }
 
 static int hpp_header_delta(struct hist_print_context *ctx)
@@ -180,11 +180,11 @@ static int hpp_entry_delta(struct hist_print_context *ctx,
 
 	old_total = pair_hists->stats.total_period;
 	if (old_total > 0)
-		old_percent = 100.0 * he->pair->period / old_total;
+		old_percent = 100.0 * he->pair->stat.period / old_total;
 
 	new_total = ctx->total_period;
 	if (new_total > 0)
-		new_percent = 100.0 * he->period / new_total;
+		new_percent = 100.0 * he->stat.period / new_total;
 
 	diff = new_percent - old_percent;
 	if (fabs(diff) < 0.01)
@@ -535,7 +535,7 @@ static size_t callchain__fprintf(struct hist_entry *he,
 {
 	switch (callchain_param.mode) {
 	case CHAIN_GRAPH_REL:
-		return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
+		return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period,
 						left_margin);
 		break;
 	case CHAIN_GRAPH_ABS:
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 84b577560d5e..d2a76d379f87 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -135,16 +135,16 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
 {
 	switch (cpumode) {
 	case PERF_RECORD_MISC_KERNEL:
-		he->period_sys += period;
+		he->stat.period_sys += period;
 		break;
 	case PERF_RECORD_MISC_USER:
-		he->period_us += period;
+		he->stat.period_us += period;
 		break;
 	case PERF_RECORD_MISC_GUEST_KERNEL:
-		he->period_guest_sys += period;
+		he->stat.period_guest_sys += period;
 		break;
 	case PERF_RECORD_MISC_GUEST_USER:
-		he->period_guest_us += period;
+		he->stat.period_guest_us += period;
 		break;
 	default:
 		break;
@@ -153,13 +153,13 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
 
 static void hist_entry__decay(struct hist_entry *he)
 {
-	he->period = (he->period * 7) / 8;
-	he->nr_events = (he->nr_events * 7) / 8;
+	he->stat.period = (he->stat.period * 7) / 8;
+	he->stat.nr_events = (he->stat.nr_events * 7) / 8;
 }
 
 static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
 {
-	u64 prev_period = he->period;
+	u64 prev_period = he->stat.period;
 
 	if (prev_period == 0)
 		return true;
@@ -167,9 +167,9 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
 	hist_entry__decay(he);
 
 	if (!he->filtered)
-		hists->stats.total_period -= prev_period - he->period;
+		hists->stats.total_period -= prev_period - he->stat.period;
 
-	return he->period == 0;
+	return he->stat.period == 0;
 }
 
 static void __hists__decay_entries(struct hists *hists, bool zap_user,
@@ -223,7 +223,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
 
 	if (he != NULL) {
 		*he = *template;
-		he->nr_events = 1;
+		he->stat.nr_events = 1;
 		if (he->ms.map)
 			he->ms.map->referenced = true;
 		if (symbol_conf.use_callchain)
@@ -238,7 +238,7 @@ static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
 	if (!h->filtered) {
 		hists__calc_col_len(hists, h);
 		++hists->nr_entries;
-		hists->stats.total_period += h->period;
+		hists->stats.total_period += h->stat.period;
 	}
 }
 
@@ -270,8 +270,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
 		cmp = hist_entry__cmp(entry, he);
 
 		if (!cmp) {
-			he->period += period;
-			++he->nr_events;
+			he->stat.period += period;
+			++he->stat.nr_events;
 
 			/* If the map of an existing hist_entry has
 			 * become out-of-date due to an exec() or
@@ -321,7 +321,9 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
 		.cpu	= al->cpu,
 		.ip	= bi->to.addr,
 		.level	= al->level,
-		.period	= period,
+		.stat = {
+			.period	= period,
+		},
 		.parent = sym_parent,
 		.filtered = symbol__parent_filter(sym_parent),
 		.branch_info = bi,
@@ -343,7 +345,9 @@ struct hist_entry *__hists__add_entry(struct hists *self,
 		.cpu	= al->cpu,
 		.ip	= al->addr,
 		.level	= al->level,
-		.period	= period,
+		.stat = {
+			.period	= period,
+		},
 		.parent = sym_parent,
 		.filtered = symbol__parent_filter(sym_parent),
 	};
@@ -410,8 +414,8 @@ static bool hists__collapse_insert_entry(struct hists *hists __used,
 		cmp = hist_entry__collapse(iter, he);
 
 		if (!cmp) {
-			iter->period += he->period;
-			iter->nr_events += he->nr_events;
+			iter->stat.period += he->stat.period;
+			iter->stat.nr_events += he->stat.nr_events;
 			if (symbol_conf.use_callchain) {
 				callchain_cursor_reset(&callchain_cursor);
 				callchain_merge(&callchain_cursor,
@@ -513,7 +517,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
 		parent = *p;
 		iter = rb_entry(parent, struct hist_entry, rb_node);
 
-		if (he->period > iter->period)
+		if (he->stat.period > iter->stat.period)
 			p = &(*p)->rb_left;
 		else
 			p = &(*p)->rb_right;
@@ -574,8 +578,8 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
 	if (h->ms.unfolded)
 		hists->nr_entries += h->nr_rows;
 	h->row_offset = 0;
-	hists->stats.total_period += h->period;
-	hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
+	hists->stats.total_period += h->stat.period;
+	hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
 
 	hists__calc_col_len(hists, h);
 }
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 9fdd5039339f..f7b05e0b41c7 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -61,17 +61,12 @@ struct he_stat {
 struct hist_entry {
 	struct rb_node		rb_node_in;
 	struct rb_node		rb_node;
-	u64			period;
-	u64			period_sys;
-	u64			period_us;
-	u64			period_guest_sys;
-	u64			period_guest_us;
+	struct he_stat		stat;
 	struct he_stat		*group_stats;
 	struct map_symbol	ms;
 	struct thread		*thread;
 	u64			ip;
 	s32			cpu;
-	u32			nr_events;
 
 	/* XXX These two should move to some tree widget lib */
 	u16			row_offset;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 03/12] perf hist: Collapse group hist_entries to a leader
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
  2012-07-24  9:01 ` [PATCH 01/12] perf tools: Add a couple of helper routines to handle groups Namhyung Kim
  2012-07-24  9:01 ` [PATCH 02/12] perf hist: Convert to struct he_stat Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 04/12] perf hist: Maintain total periods of group members in the leader Namhyung Kim
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen

To support viewing an event group together, collapse all of members
in the group to the leader's tree. The entries in the leader's tree
will have group_stats to store those information.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/hist.c   |  114 ++++++++++++++++++++++++++++++++++++++++++----
 tools/perf/util/symbol.c |    4 ++
 tools/perf/util/symbol.h |    3 +-
 3 files changed, 111 insertions(+), 10 deletions(-)

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index d2a76d379f87..a8f4c56261a0 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
 #include "hist.h"
 #include "session.h"
 #include "sort.h"
+#include "evsel.h"
 #include <math.h>
 
 static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -394,17 +395,50 @@ void hist_entry__free(struct hist_entry *he)
 	free(he);
 }
 
+static void hist_entry__add_stat(struct he_stat *left, struct he_stat *right)
+{
+	left->period		+= right->period;
+	left->period_sys	+= right->period_sys;
+	left->period_us		+= right->period_us;
+	left->period_guest_sys	+= right->period_guest_sys;
+	left->period_guest_us	+= right->period_guest_us;
+	left->nr_events		+= right->nr_events;
+}
+
+static void hist_entry__add_group_stat(struct perf_evsel *evsel,
+				       struct hist_entry *iter,
+				       struct hist_entry *he)
+{
+	struct perf_evsel *leader = evsel->leader;
+	if (!leader)
+		leader = evsel;
+
+	if (!iter->group_stats) {
+		iter->group_stats = calloc(leader->nr_children,
+					   sizeof(struct he_stat));
+		if (!iter->group_stats)
+			return;
+	}
+
+	if (!perf_evsel__is_group_leader(evsel))
+		hist_entry__add_stat(&iter->group_stats[evsel->group_idx],
+				     &he->stat);
+	else
+		hist_entry__add_stat(&iter->stat, &he->stat);
+}
+
 /*
  * collapse the histogram
  */
 
-static bool hists__collapse_insert_entry(struct hists *hists __used,
+static bool hists__collapse_insert_entry(struct hists *hists,
 					 struct rb_root *root,
 					 struct hist_entry *he)
 {
 	struct rb_node **p = &root->rb_node;
 	struct rb_node *parent = NULL;
 	struct hist_entry *iter;
+	struct perf_evsel *evsel = hists_2_evsel(hists);
 	int64_t cmp;
 
 	while (*p != NULL) {
@@ -414,8 +448,11 @@ static bool hists__collapse_insert_entry(struct hists *hists __used,
 		cmp = hist_entry__collapse(iter, he);
 
 		if (!cmp) {
-			iter->stat.period += he->stat.period;
-			iter->stat.nr_events += he->stat.nr_events;
+			if (symbol_conf.report_group)
+				hist_entry__add_group_stat(evsel, iter, he);
+			else
+				hist_entry__add_stat(&iter->stat, &he->stat);
+
 			if (symbol_conf.use_callchain) {
 				callchain_cursor_reset(&callchain_cursor);
 				callchain_merge(&callchain_cursor,
@@ -432,6 +469,16 @@ static bool hists__collapse_insert_entry(struct hists *hists __used,
 			p = &(*p)->rb_right;
 	}
 
+	if (symbol_conf.report_group) {
+		/*
+		 * 'he' is not found in the leader tree.
+		 * Insert it to the tree and setup stats properly.
+		 */
+		hist_entry__add_group_stat(evsel, he, he);
+		if (!perf_evsel__is_group_leader(evsel))
+			memset(&he->stat, 0, sizeof(struct he_stat));
+	}
+
 	rb_link_node(&he->rb_node_in, parent, p);
 	rb_insert_color(&he->rb_node_in, root);
 	return true;
@@ -462,6 +509,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
 static void __hists__collapse_resort(struct hists *hists, bool threaded)
 {
 	struct rb_root *root;
+	struct rb_root *dest;
 	struct rb_node *next;
 	struct hist_entry *n;
 
@@ -470,13 +518,26 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
 
 	root = hists__get_rotate_entries_in(hists);
 	next = rb_first(root);
+	dest = &hists->entries_collapsed;
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *leader;
+
+		/*
+		 * Collapse hist entries to the leader's tree.
+		 * If evsel->leader == NULL, it's the leader.
+		 */
+		leader = hists_2_evsel(hists)->leader;
+		if (leader)
+			dest = &leader->hists.entries_collapsed;
+	}
 
 	while (next) {
 		n = rb_entry(next, struct hist_entry, rb_node_in);
 		next = rb_next(&n->rb_node_in);
 
 		rb_erase(&n->rb_node_in, root);
-		if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
+		if (hists__collapse_insert_entry(hists, dest, n)) {
 			/*
 			 * If it wasn't combined with one of the entries already
 			 * collapsed, we need to apply the filters that may have
@@ -501,13 +562,38 @@ void hists__collapse_resort_threaded(struct hists *hists)
  * reverse the map, sort on period.
  */
 
-static void __hists__insert_output_entry(struct rb_root *entries,
+static int __hists__output_cmd_period(struct hist_entry *left,
+				      struct hist_entry *right,
+				      int nr_group)
+{
+	if (left->stat.period > right->stat.period)
+		return 1;
+	if (left->stat.period < right->stat.period)
+		return -1;
+
+	if (symbol_conf.report_group) {
+		int i;
+
+		for (i = 0; i < nr_group; i++) {
+			if (left->group_stats[i].period >
+			    right->group_stats[i].period)
+				return 1;
+			if (left->group_stats[i].period <
+			    right->group_stats[i].period)
+				return -1;
+		}
+	}
+	return 0;
+}
+
+static void __hists__insert_output_entry(struct hists *hists,
 					 struct hist_entry *he,
 					 u64 min_callchain_hits)
 {
-	struct rb_node **p = &entries->rb_node;
+	struct rb_node **p = &hists->entries.rb_node;
 	struct rb_node *parent = NULL;
 	struct hist_entry *iter;
+	struct perf_evsel *evsel = hists_2_evsel(hists);
 
 	if (symbol_conf.use_callchain)
 		callchain_param.sort(&he->sorted_chain, he->callchain,
@@ -517,14 +603,14 @@ static void __hists__insert_output_entry(struct rb_root *entries,
 		parent = *p;
 		iter = rb_entry(parent, struct hist_entry, rb_node);
 
-		if (he->stat.period > iter->stat.period)
+		if (__hists__output_cmd_period(he, iter, evsel->nr_children) > 0)
 			p = &(*p)->rb_left;
 		else
 			p = &(*p)->rb_right;
 	}
 
 	rb_link_node(&he->rb_node, parent, p);
-	rb_insert_color(&he->rb_node, entries);
+	rb_insert_color(&he->rb_node, &hists->entries);
 }
 
 static void __hists__output_resort(struct hists *hists, bool threaded)
@@ -536,6 +622,16 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
 
 	min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
 
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(hists);
+
+		/*
+		 * We've collapsed all of non-leader entries to the leader.
+		 */
+		if (!perf_evsel__is_group_leader(evsel))
+			return;
+	}
+
 	if (sort__need_collapse || threaded)
 		root = &hists->entries_collapsed;
 	else
@@ -552,7 +648,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
 		n = rb_entry(next, struct hist_entry, rb_node_in);
 		next = rb_next(&n->rb_node_in);
 
-		__hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
+		__hists__insert_output_entry(hists, n, min_callchain_hits);
 		hists__inc_nr_entries(hists, n);
 	}
 }
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 50958bbeb26a..753faa76b7c3 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -14,6 +14,7 @@
 #include "debug.h"
 #include "symbol.h"
 #include "strlist.h"
+#include "sort.h"
 
 #include <libelf.h>
 #include <gelf.h>
@@ -2733,6 +2734,9 @@ int symbol__init(void)
 
 	symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
 
+	if (symbol_conf.report_group)
+		sort__need_collapse = 1;
+
 	symbol_conf.initialized = true;
 	return 0;
 
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index a884b99017f0..9da14d6b1729 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -88,7 +88,8 @@ struct symbol_conf {
 			initialized,
 			kptr_restrict,
 			annotate_asm_raw,
-			annotate_src;
+			annotate_src,
+			report_group;
 	const char	*vmlinux_name,
 			*kallsyms_name,
 			*source_prefix,
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 04/12] perf hist: Maintain total periods of group members in the leader
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (2 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 03/12] perf hist: Collapse group hist_entries to a leader Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 05/12] perf report: Make another loop for output resorting Namhyung Kim
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen,
	Namhyung Kim

From: Namhyung Kim <namhyung.kim@lge.com>

Like group_stats in hist_entry, total periods information also need
to be known to the leader.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/hist.c |   25 +++++++++++++++++++++++++
 tools/perf/util/hist.h |    1 +
 2 files changed, 26 insertions(+)

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index a8f4c56261a0..5ae71429ba53 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -427,6 +427,28 @@ static void hist_entry__add_group_stat(struct perf_evsel *evsel,
 		hist_entry__add_stat(&iter->stat, &he->stat);
 }
 
+static void hists__add_group_stat(struct hists *hists)
+{
+	struct perf_evsel *evsel = hists_2_evsel(hists);
+	struct perf_evsel *leader = evsel->leader;
+	struct hists *leader_hists;
+
+	if (perf_evsel__is_group_leader(evsel))
+		return;
+
+	leader_hists = &leader->hists;
+
+	if (!leader_hists->group_stats) {
+		leader_hists->group_stats = calloc(leader->nr_children,
+						sizeof(struct events_stats));
+		if (!leader_hists->group_stats)
+			return;
+	}
+
+	memcpy(&leader_hists->group_stats[evsel->group_idx],
+	       &hists->stats, sizeof(struct events_stats));
+}
+
 /*
  * collapse the histogram
  */
@@ -546,6 +568,9 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
 			hists__apply_filters(hists, n);
 		}
 	}
+
+	if (symbol_conf.report_group)
+		hists__add_group_stat(hists);
 }
 
 void hists__collapse_resort(struct hists *hists)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 8594459594d9..5f81ee723c77 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -66,6 +66,7 @@ struct hists {
 	const char		*symbol_filter_str;
 	pthread_mutex_t		lock;
 	struct events_stats	stats;
+	struct events_stats	*group_stats;
 	u64			event_stream;
 	u16			col_len[HISTC_NR_COLS];
 };
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 05/12] perf report: Make another loop for output resorting
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (3 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 04/12] perf hist: Maintain total periods of group members in the leader Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 06/12] perf header: Reconstruct group relationship by parsing cmdline Namhyung Kim
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen,
	Namhyung Kim

From: Namhyung Kim <namhyung.kim@lge.com>

Now the event grouping viewing requires collapsing all member's in a
group to the leader. Thus hists__output_resort should be called after
collapsing all entreis in evlist.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-report.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 69b1c1185159..46ed9c2ad4ed 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -415,6 +415,11 @@ static int __cmd_report(struct perf_report *rep)
 			hists->symbol_filter_str = rep->symbol_filter_str;
 
 		hists__collapse_resort(hists);
+	}
+
+	list_for_each_entry(pos, &session->evlist->entries, node) {
+		struct hists *hists = &pos->hists;
+
 		hists__output_resort(hists);
 		nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
 	}
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 06/12] perf header: Reconstruct group relationship by parsing cmdline
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (4 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 05/12] perf report: Make another loop for output resorting Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-25 15:39   ` Jiri Olsa
  2012-07-24  9:01 ` [PATCH 07/12] perf ui/hist: Add support to group viewing Namhyung Kim
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen

In order to support the event group viewer, their group relationship
is needed. Since it's not recorded explicitly anywhere in the perf.data
we should parse saved cmdline and apply the result to the evlist. It is
assumed that parsed entries are in a same order with the originals.

I know it's fragile but hard to find other way to do it in the current
condition. :(

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/util/header.c |  110 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 0efbaa3c5a6b..9d9553fed8a6 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1404,6 +1404,40 @@ static int process_version(struct perf_file_section *section __used,
 	return ph->version ? 0 : -ENOMEM;
 }
 
+/*
+ * Reconstruct group relationship using parsed entries. It's assumed that
+ * the parsed entries are in a same order with the original entries.
+ */
+static void reconstruct_group_relation(struct list_head *parsed_head,
+				       struct list_head *orig_head)
+{
+	struct perf_evsel *pos, *orig;
+	struct perf_evsel *leader = NULL;
+
+	/* Fake first entry to use list_for_each_entry_continue */
+	orig = container_of(orig_head, struct perf_evsel, node);
+
+	list_for_each_entry(pos, parsed_head, node) {
+		list_for_each_entry_continue(orig, orig_head, node) {
+			BUG_ON(pos->attr.type != orig->attr.type);
+			BUG_ON(pos->attr.config != orig->attr.config);
+
+			if (pos->leader == NULL) {
+				orig->leader = NULL;
+				if (pos->group_name)
+					orig->group_name = strdup(pos->group_name);
+				orig->nr_children = pos->nr_children;
+
+				leader = orig;
+			} else {
+				orig->leader = leader;
+				orig->group_idx = pos->group_idx;
+			}
+			break;
+		}
+	}
+}
+
 /* Each argv would be separated by a NULL character */
 static int process_cmdline(struct perf_file_section *section __used,
 			   struct perf_header *ph, int fd, void *data __used)
@@ -1413,6 +1447,11 @@ static int process_cmdline(struct perf_file_section *section __used,
 	u32 nr, i;
 	char *cmdline = NULL;
 	size_t len = 0;
+	LIST_HEAD(head);
+	struct perf_evlist *evlist = NULL;
+	int nr_entries = 0;
+	bool found = false;
+	bool regenerated = false;
 
 	ret = read(fd, &nr, sizeof(nr));
 	if (ret != (ssize_t)sizeof(nr))
@@ -1421,6 +1460,25 @@ static int process_cmdline(struct perf_file_section *section __used,
 	if (ph->needs_swap)
 		nr = bswap_32(nr);
 
+	if (symbol_conf.report_group) {
+		struct perf_session *session;
+
+		session = container_of(ph, struct perf_session, header);
+		evlist = session->evlist;
+
+		/*
+		 * The evlist->entries will be regenerated by parsing cmdline
+		 * to track grouping information. However we cannot use the
+		 * generated entries since they lack sample id information.
+		 *
+		 * Save the original entries to 'head' and reconstruct group
+		 * information using parse entries.
+		 */
+		list_splice_init(&evlist->entries, &head);
+		nr_entries = evlist->nr_entries;
+		evlist->nr_entries = 0;
+	}
+
 	ph->cmdline_argc = nr;
 
 	for (i = 0; i < nr; i++) {
@@ -1428,6 +1486,19 @@ static int process_cmdline(struct perf_file_section *section __used,
 		if (!str)
 			goto error;
 
+		if (symbol_conf.report_group) {
+			if (found) {
+				/* Regenerate evlist */
+				if (!parse_events(evlist, str, 0))
+					regenerated = true;
+			}
+
+			if (!strcmp(str, "-e"))
+				found = true;
+			else
+				found = false;
+		}
+
 		tmp = realloc(cmdline, len + strlen(str) + 1);
 		if (!tmp)
 			goto error;
@@ -1439,10 +1510,49 @@ static int process_cmdline(struct perf_file_section *section __used,
 		len += strlen(str) + 1;
 		free(str);
 	}
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *pos, *orig;
+
+		if (regenerated) {
+			BUG_ON(evlist->nr_entries != nr_entries);
+
+			reconstruct_group_relation(&evlist->entries, &head);
+
+			/* Parsed entries are not needed anymore */
+			list_for_each_entry_safe(pos, orig, &evlist->entries, node) {
+				list_del_init(&pos->node);
+				perf_evsel__delete(pos);
+			}
+
+			/* Restore the original entries */
+			list_splice(&head, &evlist->entries);
+		} else {
+			/*
+			 * Indirect record command doesn't contain events on
+			 * the cmdline. Restore original entries.
+			 */
+			list_splice(&head, &evlist->entries);
+			evlist->nr_entries = nr_entries;
+		}
+	}
 	ph->cmdline = cmdline;
 	return 0;
 
 error:
+	if (symbol_conf.report_group) {
+		struct perf_evsel *pos, *n;
+
+		/* Delete intermediate entries */
+		list_for_each_entry_safe(pos, n, &evlist->entries, node) {
+			list_del_init(&pos->node);
+			perf_evsel__delete(pos);
+		}
+
+		/* Restore original entries */
+		list_splice(&head, &evlist->entries);
+		evlist->nr_entries = nr_entries;
+	}
 	free(cmdline);
 	free(str);
 	return -1;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 07/12] perf ui/hist: Add support to group viewing
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (5 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 06/12] perf header: Reconstruct group relationship by parsing cmdline Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 08/12] perf ui/browser: " Namhyung Kim
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen

Show group members' overhead also when showing the leader's.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/ui/hist.c |  132 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 119 insertions(+), 13 deletions(-)

diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 8092a621bbec..57d00b75b6fa 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -4,32 +4,83 @@
 #include "../util/util.h"
 #include "../util/hist.h"
 #include "../util/sort.h"
+#include "../util/evsel.h"
 
 static int hpp_header_overhead(struct hist_print_context *ctx)
 {
+	int len = 8;
+	const char *str = "Overhead";
+
 	if (ctx->pair_hists)
-		return scnprintf(ctx->s, ctx->size, "Baseline");
-	else
-		return scnprintf(ctx->s, ctx->size, "Overhead");
+		str = "Baseline";
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+
+		BUG_ON(!perf_evsel__is_group_leader(evsel));
+
+		len *= evsel->nr_children + 1;
+	}
+	return scnprintf(ctx->s, ctx->size, "%-*s", len, str);
 }
 
 static int hpp_width_overhead(struct hist_print_context *ctx __used)
 {
-	return 8;
+	int len = 8;
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		len *= evsel->nr_children + 1;
+	}
+	return len;
 }
 
 static int hpp_color_overhead(struct hist_print_context *ctx,
 			      struct hist_entry *he)
 {
+	int ret;
 	double percent = 100.0 * he->stat.period / ctx->total_period;
-	return percent_color_snprintf(ctx->s, ctx->size, "  %5.2f%%", percent);
+
+	ret = percent_color_snprintf(ctx->s, ctx->size, "  %5.2f%%", percent);
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		int i;
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			u64 period = he->group_stats[i].period;
+			u64 total_period = ctx->hists->group_stats[i].total_period;
+
+			percent = 100.0 * period / total_period;
+			ret += percent_color_snprintf(ctx->s + ret, ctx->size - ret,
+						      "  %5.2f%%", percent);
+		}
+	}
+	return ret;
 }
 
 static int hpp_entry_overhead(struct hist_print_context *ctx,
 			      struct hist_entry *he)
 {
+	int ret;
 	double percent = 100.0 * he->stat.period / ctx->total_period;
-	return scnprintf(ctx->s, ctx->size, "  %5.2f%%", percent);
+
+	ret = scnprintf(ctx->s, ctx->size, "  %5.2f%%", percent);
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		int i;
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			u64 period = he->group_stats[i].period;
+			u64 total_period = ctx->hists->group_stats[i].total_period;
+
+			percent = 100.0 * period / total_period;
+			ret += scnprintf(ctx->s + ret, ctx->size - ret,
+					 "  %5.2f%%", percent);
+		}
+	}
+	return ret;
 }
 
 static int hpp_header_overhead_sys(struct hist_print_context *ctx)
@@ -130,34 +181,86 @@ static int hpp_entry_overhead_guest_us(struct hist_print_context *ctx,
 
 static int hpp_header_samples(struct hist_print_context *ctx)
 {
-	return scnprintf(ctx->s, ctx->size, "  Samples  ");
+	int len = 11;
+	const char str[] = "  Samples  ";
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		len += (len + 2) * evsel->nr_children;
+	}
+	return scnprintf(ctx->s, ctx->size, "%-*s", len, str);
 }
 
 static int hpp_width_samples(struct hist_print_context *ctx __used)
 {
-	return 11;
+	int len = 11;
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		len += (len + 2) * evsel->nr_children;
+	}
+	return len;
 }
 
 static int hpp_entry_samples(struct hist_print_context *ctx,
 			     struct hist_entry *he)
 {
-	return scnprintf(ctx->s, ctx->size, "%11" PRIu64, he->stat.nr_events);
+	int ret;
+
+	ret = scnprintf(ctx->s, ctx->size, "%11" PRIu64, he->stat.nr_events);
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		int i;
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			ret += scnprintf(ctx->s + ret, ctx->size - ret,
+				"  %11" PRIu64, he->group_stats[i].nr_events);
+		}
+	}
+	return ret;
 }
 
 static int hpp_header_period(struct hist_print_context *ctx)
 {
-	return scnprintf(ctx->s, ctx->size, "   Period   ");
+	int len = 12;
+	const char str[] = "   Period   ";
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		len += (len + 2) * evsel->nr_children;
+	}
+	return scnprintf(ctx->s, ctx->size, "%-*s", len, str);
 }
 
 static int hpp_width_period(struct hist_print_context *ctx __used)
 {
-	return 12;
+	int len = 12;
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		len += (len + 2) * evsel->nr_children;
+	}
+	return len;
 }
 
 static int hpp_entry_period(struct hist_print_context *ctx,
 			    struct hist_entry *he)
 {
-	return scnprintf(ctx->s, ctx->size, "%12" PRIu64, he->stat.period);
+	int ret;
+
+	ret = scnprintf(ctx->s, ctx->size, "%12" PRIu64, he->stat.period);
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		int i;
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			ret += scnprintf(ctx->s + ret, ctx->size - ret,
+				"  %12" PRIu64, he->group_stats[i].period);
+		}
+	}
+	return ret;
 }
 
 static int hpp_header_delta(struct hist_print_context *ctx)
@@ -801,6 +904,9 @@ unsigned int hists__sort_list_width(struct hists *hists)
 {
 	struct sort_entry *se;
 	int i, ret = 0;
+	struct hist_print_context dummy_ctx = {
+		.hists	= hists,
+	};
 
 	for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
 		if (!hpp_functions[i].cond)
@@ -808,7 +914,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
 		if (i)
 			ret += 2;
 
-		ret += hpp_functions[i].width(NULL);
+		ret += hpp_functions[i].width(&dummy_ctx);
 	}
 
 	list_for_each_entry(se, &hist_entry__sort_list, list)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 08/12] perf ui/browser: Add support to group viewing
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (6 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 07/12] perf ui/hist: Add support to group viewing Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 09/12] perf ui/gtk: " Namhyung Kim
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen,
	Namhyung Kim

From: Namhyung Kim <namhyung.kim@lge.com>

Show group members' overhead also when showing the leader's.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/ui/browsers/hists.c |   28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 69584d79097e..bdb1b2f9f819 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -553,6 +553,33 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
 	return row - first_row;
 }
 
+static int hist_browser__hpp_color_overhead(struct hist_print_context *ctx,
+					    struct hist_entry *he)
+{
+	int ret;
+	double percent = 100.0 * he->stat.period / ctx->total_period;
+
+	/* the leader determines the color */
+	*(double *)ctx->ptr = percent;
+
+	ret = scnprintf(ctx->s, ctx->size, "%5.2f%%", percent);
+
+	if (symbol_conf.report_group) {
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+		int i;
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			u64 period = he->group_stats[i].period;
+			u64 total_period = ctx->hists->group_stats[i].total_period;
+
+			percent = 100.0 * period / total_period;
+			ret += scnprintf(ctx->s + ret, ctx->size - ret,
+					 "  %5.2f%%", percent);
+		}
+	}
+	return ret;
+}
+
 #define HPP_COLOR_FN(_name, _field)						\
 static int hist_browser__hpp_color_ ## _name(struct hist_print_context *ctx,	\
 					     struct hist_entry *he)		\
@@ -562,7 +589,6 @@ static int hist_browser__hpp_color_ ## _name(struct hist_print_context *ctx,	\
 	return scnprintf(ctx->s, ctx->size, "%5.2f%%", percent);		\
 }
 
-HPP_COLOR_FN(overhead, period)
 HPP_COLOR_FN(overhead_sys, period_sys)
 HPP_COLOR_FN(overhead_us, period_us)
 HPP_COLOR_FN(overhead_guest_sys, period_guest_sys)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 09/12] perf ui/gtk: Add support to group viewing
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (7 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 08/12] perf ui/browser: " Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 10/12] perf report: Show leader events only when event group is enabled Namhyung Kim
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen,
	Namhyung Kim, Pekka Enberg

From: Namhyung Kim <namhyung.kim@lge.com>

Show group members' overhead also when showing the leader's.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Pekka Enberg <penberg@kernel.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/ui/gtk/browser.c |   57 +++++++++++++++++++++++++++++++++----------
 1 file changed, 44 insertions(+), 13 deletions(-)

diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 91e11f7bffbf..e39c83cd5ac5 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -44,25 +44,56 @@ static const char *perf_gtk__get_percent_color(double percent)
 	return NULL;
 }
 
+static int perf_gtk__percent_color_snprintf(char *s, size_t size,
+					    u64 period, u64 total_period)
+{
+	double percent = 100.0 * period / total_period;
+	const char *markup;
+	int ret = 0;
+
+	markup = perf_gtk__get_percent_color(percent);
+	if (markup)
+		ret += scnprintf(s, size, "%s", markup);
+
+	ret += scnprintf(s + ret, size - ret, "%5.2f%%", percent);
+
+	if (markup)
+		ret += scnprintf(s + ret, size - ret, "</span>");
+
+	return ret;
+}
+
+static int perf_gtk__hpp_color_overhead(struct hist_print_context *ctx,
+					struct hist_entry *he)
+{
+	int ret;
+
+	ret = perf_gtk__percent_color_snprintf(ctx->s, ctx->size,
+					he->stat.period, ctx->total_period);
+
+	if (symbol_conf.report_group) {
+		int i;
+		struct perf_evsel *evsel = hists_2_evsel(ctx->hists);
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			ret += scnprintf(ctx->s + ret, ctx->size - ret, "  ");
+			ret += perf_gtk__percent_color_snprintf(ctx->s + ret,
+					ctx->size - ret,
+					he->group_stats[i].period,
+					ctx->hists->group_stats[i].total_period);
+		}
+	}
+	return ret;
+}
+
 #define HPP_COLOR_FN(_name, _field)						\
 static int perf_gtk__hpp_color_ ## _name(struct hist_print_context *ctx,	\
 					 struct hist_entry *he)			\
 {										\
-	double percent = 100.0 * he->stat._field / ctx->total_period;		\
-	const char *markup;							\
-	int ret = 0;								\
-										\
-	markup = perf_gtk__get_percent_color(percent);				\
-	if (markup)								\
-		ret += scnprintf(ctx->s, ctx->size, "%s", markup);		\
-	ret += scnprintf(ctx->s + ret, ctx->size - ret, "%5.2f%%", percent); 	\
-	if (markup)								\
-		ret += scnprintf(ctx->s + ret, ctx->size - ret, "</span>"); 	\
-										\
-	return ret;								\
+	return perf_gtk__percent_color_snprintf(ctx->s, ctx->size,		\
+					he->stat._field, ctx->total_period); 	\
 }
 
-HPP_COLOR_FN(overhead, period)
 HPP_COLOR_FN(overhead_sys, period_sys)
 HPP_COLOR_FN(overhead_us, period_us)
 HPP_COLOR_FN(overhead_guest_sys, period_guest_sys)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 10/12] perf report: Show leader events only when event group is enabled
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (8 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 09/12] perf ui/gtk: " Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 11/12] perf report: Show group description " Namhyung Kim
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen,
	Namhyung Kim, Pekka Enberg

From: Namhyung Kim <namhyung.kim@lge.com>

Since we have all necessary information in the leader events and
other members don't, show only leaders.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Pekka Enberg <penberg@kernel.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-report.c    |    4 ++++
 tools/perf/ui/browsers/hists.c |   38 ++++++++++++++++++++++++++++++++------
 tools/perf/ui/gtk/browser.c    |    4 ++++
 3 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 46ed9c2ad4ed..6f34a2d6e5a8 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -318,6 +318,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
 		struct hists *hists = &pos->hists;
 		const char *evname = perf_evsel__name(pos);
 
+		if (symbol_conf.report_group &&
+		    !perf_evsel__is_group_leader(pos))
+			continue;
+
 		hists__fprintf_nr_sample_events(hists, evname, stdout);
 		hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
 		fprintf(stdout, "\n\n");
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index bdb1b2f9f819..dbd6995609bf 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1567,8 +1567,18 @@ out:
 	return key;
 }
 
+static bool filter_group_entries(struct ui_browser *self __used, void *entry)
+{
+	struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
+
+	if (symbol_conf.report_group && !perf_evsel__is_group_leader(evsel))
+		return true;
+
+	return false;
+}
+
 static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
-					   const char *help,
+					   int nr_entries, const char *help,
 					   void(*timer)(void *arg), void *arg,
 					   int delay_secs)
 {
@@ -1579,7 +1589,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
 			.refresh    = ui_browser__list_head_refresh,
 			.seek	    = ui_browser__list_head_seek,
 			.write	    = perf_evsel_menu__write,
-			.nr_entries = evlist->nr_entries,
+			.filter	    = filter_group_entries,
+			.nr_entries = nr_entries,
 			.priv	    = evlist,
 		},
 	};
@@ -1594,7 +1605,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
 			menu.b.width = line_len;
 	}
 
-	return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
+	return perf_evsel_menu__run(&menu, nr_entries, help, timer,
 				    arg, delay_secs);
 }
 
@@ -1602,15 +1613,30 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
 				  void(*timer)(void *arg), void *arg,
 				  int delay_secs)
 {
-	if (evlist->nr_entries == 1) {
+	int nr_entries = evlist->nr_entries;
+
+single_entry:
+	if (nr_entries == 1) {
 		struct perf_evsel *first = list_entry(evlist->entries.next,
 						      struct perf_evsel, node);
 		const char *ev_name = perf_evsel__name(first);
-		return perf_evsel__hists_browse(first, evlist->nr_entries, help,
+		return perf_evsel__hists_browse(first, nr_entries, help,
 						ev_name, false, timer, arg,
 						delay_secs);
 	}
 
-	return __perf_evlist__tui_browse_hists(evlist, help,
+	if (symbol_conf.report_group) {
+		struct perf_evsel *pos;
+
+		nr_entries = 0;
+		list_for_each_entry(pos, &evlist->entries, node)
+			if (perf_evsel__is_group_leader(pos))
+				nr_entries++;
+
+		if (nr_entries == 1)
+			goto single_entry;
+	}
+
+	return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
 					       timer, arg, delay_secs);
 }
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index e39c83cd5ac5..cc53a01ba14b 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -306,6 +306,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
 		GtkWidget *scrolled_window;
 		GtkWidget *tab_label;
 
+		if (symbol_conf.report_group &&
+		    !perf_evsel__is_group_leader(pos))
+			continue;
+
 		scrolled_window = gtk_scrolled_window_new(NULL, NULL);
 
 		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 11/12] perf report: Show group description when event group is enabled
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (9 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 10/12] perf report: Show leader events only when event group is enabled Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:01 ` [PATCH 12/12] perf report: Add --group option Namhyung Kim
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen,
	Namhyung Kim, Pekka Enberg

From: Namhyung Kim <namhyung.kim@lge.com>

When using event group viewer, it's better to show the group
description rather than the leader information alone.

If a leader did not contain any children, it's a non-group event.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Pekka Enberg <penberg@kernel.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-report.c    |   18 ++++++++++++++++++
 tools/perf/ui/browsers/hists.c |   31 +++++++++++++++++++++++++++++++
 tools/perf/ui/gtk/browser.c    |   14 +++++++++++---
 tools/perf/util/evsel.c        |   25 +++++++++++++++++++++++++
 tools/perf/util/evsel.h        |    2 ++
 5 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 6f34a2d6e5a8..d7dfa2863ece 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -298,6 +298,24 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
 	char unit;
 	unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
 	u64 nr_events = self->stats.total_period;
+	struct perf_evsel *evsel = hists_2_evsel(self);
+	char buf[512];
+	size_t size = sizeof(buf);
+
+	if (symbol_conf.report_group && evsel->nr_children) {
+		int i;
+		struct events_stats *stats;
+
+		perf_evsel__group_desc(evsel, buf, size);
+		evname = buf;
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			stats = &self->group_stats[i];
+
+			nr_samples += stats->nr_events[PERF_RECORD_SAMPLE];
+			nr_events += stats->total_period;
+		}
+	}
 
 	nr_samples = convert_unit(nr_samples, &unit);
 	ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index dbd6995609bf..031d6eba83d9 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1114,6 +1114,24 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
 	const struct thread *thread = hists->thread_filter;
 	unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
 	u64 nr_events = hists->stats.total_period;
+	struct perf_evsel *evsel = hists_2_evsel(hists);
+	char buf[512];
+	size_t buflen = sizeof(buf);
+
+	if (symbol_conf.report_group && evsel->nr_children) {
+		int i;
+		struct events_stats *stats;
+
+		perf_evsel__group_desc(evsel, buf, buflen);
+		ev_name = buf;
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			stats = &hists->group_stats[i];
+
+			nr_samples += stats->nr_events[PERF_RECORD_SAMPLE];
+			nr_events += stats->total_period;
+		}
+	}
 
 	nr_samples = convert_unit(nr_samples, &unit);
 	printed = scnprintf(bf, size,
@@ -1458,6 +1476,19 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
 	ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
 						       HE_COLORSET_NORMAL);
 
+	if (symbol_conf.report_group && evsel->nr_children) {
+		int i;
+		struct events_stats *stats;
+
+		ev_name = perf_evsel__group_name(evsel);
+
+		for (i = 0; i < evsel->nr_children; i++) {
+			stats = &evsel->hists.group_stats[i];
+
+			nr_events += stats->nr_events[PERF_RECORD_SAMPLE];
+		}
+	}
+
 	nr_events = convert_unit(nr_events, &unit);
 	printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
 			   unit, unit == ' ' ? "" : " ", ev_name);
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index cc53a01ba14b..fddedb504d47 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -305,10 +305,18 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
 		const char *evname = perf_evsel__name(pos);
 		GtkWidget *scrolled_window;
 		GtkWidget *tab_label;
+		char buf[512];
+		size_t size = sizeof(buf);
 
-		if (symbol_conf.report_group &&
-		    !perf_evsel__is_group_leader(pos))
-			continue;
+		if (symbol_conf.report_group) {
+			if (!perf_evsel__is_group_leader(pos))
+				continue;
+
+			if (pos->nr_children) {
+				perf_evsel__group_desc(pos, buf, size);
+				evname = buf;
+			}
+		}
 
 		scrolled_window = gtk_scrolled_window_new(NULL, NULL);
 
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index fcb357c35649..f6ab9a1c2a46 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -324,6 +324,31 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
 	return evsel->name ?: "unknown";
 }
 
+const char *perf_evsel__group_name(struct perf_evsel *evsel)
+{
+	return evsel->group_name ?: "anon_group";
+}
+
+int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
+{
+	int ret;
+	struct perf_evsel *pos;
+	const char *group_name = perf_evsel__group_name(evsel);
+
+	ret = scnprintf(buf, size, "%s", group_name);
+
+	ret += scnprintf(buf + ret, size - ret, " { %s",
+			 perf_evsel__name(evsel));
+
+	for_each_group_member(pos, evsel)
+		ret += scnprintf(buf + ret, size - ret, ", %s",
+				 perf_evsel__name(pos));
+
+	ret += scnprintf(buf + ret, size - ret, " }");
+
+	return ret;
+}
+
 void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
 			struct perf_evsel *first)
 {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index efc9e5c42210..eeb2c38a1df7 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -119,6 +119,8 @@ const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
 int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
 					    char *bf, size_t size);
 const char *perf_evsel__name(struct perf_evsel *evsel);
+const char *perf_evsel__group_name(struct perf_evsel *evsel);
+int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 12/12] perf report: Add --group option
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (10 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 11/12] perf report: Show group description " Namhyung Kim
@ 2012-07-24  9:01 ` Namhyung Kim
  2012-07-24  9:13 ` [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
  2012-07-24 21:17 ` Andi Kleen
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:01 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen,
	Namhyung Kim

From: Namhyung Kim <namhyung.kim@lge.com>

Add --group option to enable event grouping. When enabled, all the
group members information will be shown together with the leader.

Cc: Stephane Eranian <eranian@google.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/builtin-report.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index d7dfa2863ece..2570ca66e15b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -662,6 +662,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
 	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
 		    "Show a column with the sum of periods"),
+	OPT_BOOLEAN(0, "group", &symbol_conf.report_group,
+		    "Show event group information together"),
 	OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
 		    "use branch records for histogram filling", parse_branch_mode),
 	OPT_END()
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1)
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (11 preceding siblings ...)
  2012-07-24  9:01 ` [PATCH 12/12] perf report: Add --group option Namhyung Kim
@ 2012-07-24  9:13 ` Namhyung Kim
  2012-07-24 21:17 ` Andi Kleen
  13 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-24  9:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Paul Mackerras, Ingo Molnar, LKML,
	Stephane Eranian, Jiri Olsa, Ulrich Drepper, Andi Kleen

On Tue, 24 Jul 2012 18:01:21 +0900, Namhyung Kim wrote:
> Hi all,
>
> This is a patchset to support event grouping on perf report.
>
> It depends on other patches like refactoring hist print [1],
> processing file header feature [2] and (obviously) Jiri's event group
> management [3]. All of this need to be reviewed though. ;)
>
> The basic idea is move group member's hist entries to a leader, and
> sort/collapse them on the leader's tree. The leader will have all of
> group members' stat in it. The output is sorted by the leader's period
> and in turn first child and so on.
>
> To use it, 'perf record' should group events when recording. And then
> perf report parses the saved command line and reconstruct the group
> relation. Currently only the '-e { event1,event2 }' syntax is supported
> (i.e. --group option is *NOT* supported) to make things easy. But it'd
> not be that hard to support --group also.
>
> But I think re-using event parsing routine (at least, in its current
> form) has some problems especially if perf report will not run on the
> same machine that runs perf record. I cannot find a better way than
> extending/changing the perf file format to let perf record know about

s/perf record/perf report/

Thanks,
Namhyung

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1)
  2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
                   ` (12 preceding siblings ...)
  2012-07-24  9:13 ` [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
@ 2012-07-24 21:17 ` Andi Kleen
  13 siblings, 0 replies; 17+ messages in thread
From: Andi Kleen @ 2012-07-24 21:17 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, LKML, Stephane Eranian, Jiri Olsa, Ulrich Drepper,
	Andi Kleen

On Tue, Jul 24, 2012 at 06:01:21PM +0900, Namhyung Kim wrote:
> Hi all,
> 
> This is a patchset to support event grouping on perf report.

I haven't read it in detail, but the concept looks good.

The main thing I'm interested in would be a group aware annotation.
So that you can use one event as a leader, but when you look at
the annotated source/assembler you see the average counts of all the 
events as they were when the leader fired.

-Andi


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 06/12] perf header: Reconstruct group relationship by parsing cmdline
  2012-07-24  9:01 ` [PATCH 06/12] perf header: Reconstruct group relationship by parsing cmdline Namhyung Kim
@ 2012-07-25 15:39   ` Jiri Olsa
  2012-07-25 15:52     ` Namhyung Kim
  0 siblings, 1 reply; 17+ messages in thread
From: Jiri Olsa @ 2012-07-25 15:39 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, LKML, Stephane Eranian, Ulrich Drepper, Andi Kleen

On Tue, Jul 24, 2012 at 06:01:27PM +0900, Namhyung Kim wrote:
> In order to support the event group viewer, their group relationship
> is needed. Since it's not recorded explicitly anywhere in the perf.data
> we should parse saved cmdline and apply the result to the evlist. It is
> assumed that parsed entries are in a same order with the originals.
> 
> I know it's fragile but hard to find other way to do it in the current
> condition. :(

How about storing grouping details in new perf.data feature?
As you said reparsing looks too fragile.

jirka

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 06/12] perf header: Reconstruct group relationship by parsing cmdline
  2012-07-25 15:39   ` Jiri Olsa
@ 2012-07-25 15:52     ` Namhyung Kim
  0 siblings, 0 replies; 17+ messages in thread
From: Namhyung Kim @ 2012-07-25 15:52 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Paul Mackerras,
	Ingo Molnar, LKML, Stephane Eranian, Ulrich Drepper, Andi Kleen

2012-07-25 (수), 17:39 +0200, Jiri Olsa:
> On Tue, Jul 24, 2012 at 06:01:27PM +0900, Namhyung Kim wrote:
> > In order to support the event group viewer, their group relationship
> > is needed. Since it's not recorded explicitly anywhere in the perf.data
> > we should parse saved cmdline and apply the result to the evlist. It is
> > assumed that parsed entries are in a same order with the originals.
> > 
> > I know it's fragile but hard to find other way to do it in the current
> > condition. :(
> 
> How about storing grouping details in new perf.data feature?
> As you said reparsing looks too fragile.
> 
> jirka

Yeah, maybe it's the best thing I can do now.

Thanks,
Namhyung



^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2012-07-25 15:52 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-07-24  9:01 [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
2012-07-24  9:01 ` [PATCH 01/12] perf tools: Add a couple of helper routines to handle groups Namhyung Kim
2012-07-24  9:01 ` [PATCH 02/12] perf hist: Convert to struct he_stat Namhyung Kim
2012-07-24  9:01 ` [PATCH 03/12] perf hist: Collapse group hist_entries to a leader Namhyung Kim
2012-07-24  9:01 ` [PATCH 04/12] perf hist: Maintain total periods of group members in the leader Namhyung Kim
2012-07-24  9:01 ` [PATCH 05/12] perf report: Make another loop for output resorting Namhyung Kim
2012-07-24  9:01 ` [PATCH 06/12] perf header: Reconstruct group relationship by parsing cmdline Namhyung Kim
2012-07-25 15:39   ` Jiri Olsa
2012-07-25 15:52     ` Namhyung Kim
2012-07-24  9:01 ` [PATCH 07/12] perf ui/hist: Add support to group viewing Namhyung Kim
2012-07-24  9:01 ` [PATCH 08/12] perf ui/browser: " Namhyung Kim
2012-07-24  9:01 ` [PATCH 09/12] perf ui/gtk: " Namhyung Kim
2012-07-24  9:01 ` [PATCH 10/12] perf report: Show leader events only when event group is enabled Namhyung Kim
2012-07-24  9:01 ` [PATCH 11/12] perf report: Show group description " Namhyung Kim
2012-07-24  9:01 ` [PATCH 12/12] perf report: Add --group option Namhyung Kim
2012-07-24  9:13 ` [RFC/PATCHSET 00/12] perf report: Add support to event group viewing (v1) Namhyung Kim
2012-07-24 21:17 ` Andi Kleen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox