[PATCH 3/9] perf, tools, stat: Basic support for TopDown in perf stat

2015-08-07 Thread Andi Kleen
From: Andi Kleen 

Add basic plumbing for TopDown in perf stat

Add a new --topdown options to enable events.
When --topdown is specified set up events for all topdown
events supported by the kernel.
Add topdown-* as a special case to the event parser, as is
needed for all events containing -.

The actual code to compute the metrics is in follow-on patches.

Signed-off-by: Andi Kleen 
---
 tools/perf/Documentation/perf-stat.txt |   8 +++
 tools/perf/builtin-stat.c  | 124 -
 tools/perf/util/parse-events.l |   1 +
 3 files changed, 131 insertions(+), 2 deletions(-)

diff --git a/tools/perf/Documentation/perf-stat.txt 
b/tools/perf/Documentation/perf-stat.txt
index 47469ab..86c03e9 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -158,6 +158,14 @@ filter out the startup phase of the program, which is 
often very different.
 
 Print statistics of transactional execution if supported.
 
+--topdown::
+
+Print top down level 1 metrics if supported by the CPU. This allows to
+determine bottle necks in the CPU pipeline for CPU bound workloads,
+by breaking it down into frontend bound, backend bound, bad speculation
+and retiring.  Specifying the option multiple times shows metrics even
+if the don't cross a threshold.
+
 EXAMPLES
 
 
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 2590c75..a83f26f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -93,6 +93,15 @@ static const char * transaction_limited_attrs = {
"}"
 };
 
+static const char * topdown_attrs[] = {
+   "topdown-total-slots",
+   "topdown-fetch-bubbles",
+   "topdown-slots-retired",
+   "topdown-recovery-bubbles",
+   "topdown-slots-issued",
+   NULL,
+};
+
 static struct perf_evlist  *evsel_list;
 
 static struct target target = {
@@ -105,6 +114,7 @@ static volatile pid_t   child_pid   
= -1;
 static boolnull_run=  false;
 static int detailed_run=  0;
 static booltransaction_run;
+static int topdown_run = 0;
 static boolbig_num =  true;
 static int big_num_opt =  -1;
 static const char  *csv_sep= NULL;
@@ -735,7 +745,8 @@ static void printout(int id, int nr, struct perf_evsel 
*counter, double uval,
first_shadow_cpu(counter, id),
pm,
nl,
-   );
+   ,
+   topdown_run);
 
if (!csv_output) {
print_noise(counter, noise);
@@ -1093,12 +1104,90 @@ static int perf_stat_init_aggr_mode(void)
return 0;
 }
 
+static void filter_events(const char **attr, char **str, bool use_group)
+{
+   int off = 0;
+   int i;
+   int len = 0;
+   char *s;
+
+   for (i = 0; attr[i]; i++) {
+   if (pmu_have_event("cpu", attr[i])) {
+   len += strlen(attr[i]) + 1;
+   attr[i - off] = attr[i];
+   } else
+   off++;
+   }
+   attr[i - off] = NULL;
+
+   *str = malloc(len + 1 + 2);
+   if (!*str)
+   return;
+   s = *str;
+   if (i - off == 0) {
+   *s = 0;
+   return;
+   }
+   if (use_group)
+   *s++ = '{';
+   for (i = 0; attr[i]; i++) {
+   strcpy(s, attr[i]);
+   s += strlen(s);
+   *s++ = ',';
+   }
+   if (use_group) {
+   s[-1] = '}';
+   *s = 0;
+   } else
+   s[-1] = 0;
+}
+
+/* Caller must free result */
+static char *sysctl_read(const char *fn)
+{
+   int n;
+   char *line = NULL;
+   size_t linelen = 0;
+   FILE *f = fopen(fn, "r");
+   if (!f)
+   return NULL;
+   n = getline(, , f);
+   fclose(f);
+   if (n > 0)
+   return line;
+   free(line);
+   return NULL;
+}
+
+/*
+ * Check whether we can use a group for top down.
+ * Without a group may get bad results.
+ */
+static bool check_group(bool *warn)
+{
+   char *v = sysctl_read("/proc/sys/kernel/nmi_watchdog");
+   int n;
+
+   *warn = false;
+   if (v) {
+   bool res = sscanf(v, "%d", ) == 1 && n != 0;
+   free(v);
+   if (res) {
+   *warn = true;
+   return false;
+   }
+   return true;
+   }
+   return false; /* Don't know, so don't use group */
+}
+
 /*
  * Add default attributes, if there were no attributes specified or
  * if -d/--detailed, -d -d or -d -d -d is used:
  

[PATCH 3/9] perf, tools, stat: Basic support for TopDown in perf stat

2015-08-07 Thread Andi Kleen
From: Andi Kleen a...@linux.intel.com

Add basic plumbing for TopDown in perf stat

Add a new --topdown options to enable events.
When --topdown is specified set up events for all topdown
events supported by the kernel.
Add topdown-* as a special case to the event parser, as is
needed for all events containing -.

The actual code to compute the metrics is in follow-on patches.

Signed-off-by: Andi Kleen a...@linux.intel.com
---
 tools/perf/Documentation/perf-stat.txt |   8 +++
 tools/perf/builtin-stat.c  | 124 -
 tools/perf/util/parse-events.l |   1 +
 3 files changed, 131 insertions(+), 2 deletions(-)

diff --git a/tools/perf/Documentation/perf-stat.txt 
b/tools/perf/Documentation/perf-stat.txt
index 47469ab..86c03e9 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -158,6 +158,14 @@ filter out the startup phase of the program, which is 
often very different.
 
 Print statistics of transactional execution if supported.
 
+--topdown::
+
+Print top down level 1 metrics if supported by the CPU. This allows to
+determine bottle necks in the CPU pipeline for CPU bound workloads,
+by breaking it down into frontend bound, backend bound, bad speculation
+and retiring.  Specifying the option multiple times shows metrics even
+if the don't cross a threshold.
+
 EXAMPLES
 
 
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 2590c75..a83f26f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -93,6 +93,15 @@ static const char * transaction_limited_attrs = {
}
 };
 
+static const char * topdown_attrs[] = {
+   topdown-total-slots,
+   topdown-fetch-bubbles,
+   topdown-slots-retired,
+   topdown-recovery-bubbles,
+   topdown-slots-issued,
+   NULL,
+};
+
 static struct perf_evlist  *evsel_list;
 
 static struct target target = {
@@ -105,6 +114,7 @@ static volatile pid_t   child_pid   
= -1;
 static boolnull_run=  false;
 static int detailed_run=  0;
 static booltransaction_run;
+static int topdown_run = 0;
 static boolbig_num =  true;
 static int big_num_opt =  -1;
 static const char  *csv_sep= NULL;
@@ -735,7 +745,8 @@ static void printout(int id, int nr, struct perf_evsel 
*counter, double uval,
first_shadow_cpu(counter, id),
pm,
nl,
-   os);
+   os,
+   topdown_run);
 
if (!csv_output) {
print_noise(counter, noise);
@@ -1093,12 +1104,90 @@ static int perf_stat_init_aggr_mode(void)
return 0;
 }
 
+static void filter_events(const char **attr, char **str, bool use_group)
+{
+   int off = 0;
+   int i;
+   int len = 0;
+   char *s;
+
+   for (i = 0; attr[i]; i++) {
+   if (pmu_have_event(cpu, attr[i])) {
+   len += strlen(attr[i]) + 1;
+   attr[i - off] = attr[i];
+   } else
+   off++;
+   }
+   attr[i - off] = NULL;
+
+   *str = malloc(len + 1 + 2);
+   if (!*str)
+   return;
+   s = *str;
+   if (i - off == 0) {
+   *s = 0;
+   return;
+   }
+   if (use_group)
+   *s++ = '{';
+   for (i = 0; attr[i]; i++) {
+   strcpy(s, attr[i]);
+   s += strlen(s);
+   *s++ = ',';
+   }
+   if (use_group) {
+   s[-1] = '}';
+   *s = 0;
+   } else
+   s[-1] = 0;
+}
+
+/* Caller must free result */
+static char *sysctl_read(const char *fn)
+{
+   int n;
+   char *line = NULL;
+   size_t linelen = 0;
+   FILE *f = fopen(fn, r);
+   if (!f)
+   return NULL;
+   n = getline(line, linelen, f);
+   fclose(f);
+   if (n  0)
+   return line;
+   free(line);
+   return NULL;
+}
+
+/*
+ * Check whether we can use a group for top down.
+ * Without a group may get bad results.
+ */
+static bool check_group(bool *warn)
+{
+   char *v = sysctl_read(/proc/sys/kernel/nmi_watchdog);
+   int n;
+
+   *warn = false;
+   if (v) {
+   bool res = sscanf(v, %d, n) == 1  n != 0;
+   free(v);
+   if (res) {
+   *warn = true;
+   return false;
+   }
+   return true;
+   }
+   return false; /* Don't know, so don't use group */
+}
+
 /*
  * Add default attributes, if there were no attributes specified or
  * if