Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-07-11 Thread Andi Kleen
> so this ^^^ gets removed by
>   perf, tools: Query terminal width and use in perf list
> 
> please move that patch ahead of this one

This cannot be done. There is no code to consume the column width
before the other patch.

-Andi

-- 
a...@linux.intel.com -- Speaking for myself only.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-07-11 Thread Andi Kleen
 so this ^^^ gets removed by
   perf, tools: Query terminal width and use in perf list
 
 please move that patch ahead of this one

This cannot be done. There is no code to consume the column width
before the other patch.

-Andi

-- 
a...@linux.intel.com -- Speaking for myself only.
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-07-09 Thread Jiri Olsa
On Fri, Jun 27, 2014 at 04:15:57PM -0700, Andi Kleen wrote:
> From: Andi Kleen 
> 
> Change pmu.c to allow descriptions of events and add interfaces
> to add aliases at runtime from another file. To be used by jevents in the
> next patch.
> 
> Acked-by: Namhyung Kim 
> Signed-off-by: Andi Kleen 

SNIP

> + return __perf_pmu__new_alias(list, name, dir, NULL, buf);
> +}
> +
>  /*
>   * Process all the sysfs attributes located under the directory
>   * specified in 'dir' parameter.
> @@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
> perf_pmu *pmu,
>   return buf;
>  }

changes below, the list command update should be separated patch

jirka

>  
> -static int cmp_string(const void *a, const void *b)
> +struct pair {
> + char *name;
> + char *desc;
> +};
> +
> +static int cmp_pair(const void *a, const void *b)
> +{
> + const struct pair *as = a;
> + const struct pair *bs = b;
> +
> + /* Put downloaded event list last */
> + if (!!as->desc != !!bs->desc)
> + return !!as->desc - !!bs->desc;
> + return strcmp(as->name, bs->name);
> +}
> +
> +static void wordwrap(char *s, int start, int max, int corr)
>  {
> - const char * const *as = a;
> - const char * const *bs = b;
> - return strcmp(*as, *bs);
> + int column = start;
> + int n;
> +
> + while (*s) {
> + int wlen = strcspn(s, " \t");
> +
> + if (column + wlen >= max && column > start) {
> + printf("\n%*s", start, "");
> + column = start + corr;
> + }
> + n = printf("%s%.*s", column > start ? " " : "", wlen, s);
> + if (n <= 0)
> + break;
> + s += wlen;
> + column += n;
> + while (isspace(*s))
> + s++;
> + }
> +}
> +
> +static int get_columns(void)
> +{
> + /*
> +  * Should ask the terminal with TIOCGWINSZ here, but we
> +  * need the original fd before the pager.
> +  */
> + return 79;
>  }
>  
>  void print_pmu_events(const char *event_glob, bool name_only)
> @@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
> name_only)
>   char buf[1024];
>   int printed = 0;
>   int len, j;
> - char **aliases;
> + struct pair *aliases;
> + int numdesc = 0;
> + int columns = get_columns();
>  
>   pmu = NULL;
>   len = 0;
>   while ((pmu = perf_pmu__scan(pmu)) != NULL)
>   list_for_each_entry(alias, >aliases, list)
>   len++;
> - aliases = malloc(sizeof(char *) * len);
> + aliases = malloc(sizeof(struct pair) * len);
>   if (!aliases)
>   return;
>   pmu = NULL;
>   j = 0;
>   while ((pmu = perf_pmu__scan(pmu)) != NULL)
>   list_for_each_entry(alias, >aliases, list) {
> - char *name = format_alias(buf, sizeof(buf), pmu, alias);
> + char *name = alias->desc ? alias->name :
> + format_alias(buf, sizeof(buf), pmu, alias);
>   bool is_cpu = !strcmp(pmu->name, "cpu");
>  
>   if (event_glob != NULL &&
> @@ -756,22 +816,31 @@ void print_pmu_events(const char *event_glob, bool 
> name_only)
> (!is_cpu && strglobmatch(alias->name,
>  event_glob
>   continue;
> - aliases[j] = name;
> - if (is_cpu && !name_only)
> - aliases[j] = format_alias_or(buf, sizeof(buf),
> -   pmu, alias);
> - aliases[j] = strdup(aliases[j]);
> + aliases[j].name = name;
> + if (is_cpu && !name_only && !alias->desc)
> + aliases[j].name = format_alias_or(buf,
> +   sizeof(buf),
> +   pmu, alias);
> + aliases[j].name = strdup(aliases[j].name);
> + aliases[j].desc = alias->desc;
>   j++;
>   }
>   len = j;
> - qsort(aliases, len, sizeof(char *), cmp_string);
> + qsort(aliases, len, sizeof(struct pair), cmp_pair);
>   for (j = 0; j < len; j++) {
>   if (name_only) {
> - printf("%s ", aliases[j]);
> + printf("%s ", aliases[j].name);
>   continue;
>   }
> - printf("  %-50s [Kernel PMU event]\n", aliases[j]);
> - zfree([j]);
> + if (aliases[j].desc) {
> + if (numdesc++ == 0 && printed)
> + printf("\n");
> + printf("  %-50s [", aliases[j].name);
> + 

Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-07-09 Thread Jiri Olsa
On Fri, Jun 27, 2014 at 04:15:57PM -0700, Andi Kleen wrote:
> From: Andi Kleen 
> 
> Change pmu.c to allow descriptions of events and add interfaces
> to add aliases at runtime from another file. To be used by jevents in the
> next patch.
> 
> Acked-by: Namhyung Kim 
> Signed-off-by: Andi Kleen 
> ---

SNIP

> +}
> +
> +static int get_columns(void)
> +{
> + /*
> +  * Should ask the terminal with TIOCGWINSZ here, but we
> +  * need the original fd before the pager.
> +  */
> + return 79;
>  }

so this ^^^ gets removed by
  perf, tools: Query terminal width and use in perf list

please move that patch ahead of this one

jirka
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-07-09 Thread Jiri Olsa
On Fri, Jun 27, 2014 at 04:15:57PM -0700, Andi Kleen wrote:
 From: Andi Kleen a...@linux.intel.com
 
 Change pmu.c to allow descriptions of events and add interfaces
 to add aliases at runtime from another file. To be used by jevents in the
 next patch.
 
 Acked-by: Namhyung Kim namhy...@kernel.org
 Signed-off-by: Andi Kleen a...@linux.intel.com

SNIP

 + return __perf_pmu__new_alias(list, name, dir, NULL, buf);
 +}
 +
  /*
   * Process all the sysfs attributes located under the directory
   * specified in 'dir' parameter.
 @@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
 perf_pmu *pmu,
   return buf;
  }

changes below, the list command update should be separated patch

jirka

  
 -static int cmp_string(const void *a, const void *b)
 +struct pair {
 + char *name;
 + char *desc;
 +};
 +
 +static int cmp_pair(const void *a, const void *b)
 +{
 + const struct pair *as = a;
 + const struct pair *bs = b;
 +
 + /* Put downloaded event list last */
 + if (!!as-desc != !!bs-desc)
 + return !!as-desc - !!bs-desc;
 + return strcmp(as-name, bs-name);
 +}
 +
 +static void wordwrap(char *s, int start, int max, int corr)
  {
 - const char * const *as = a;
 - const char * const *bs = b;
 - return strcmp(*as, *bs);
 + int column = start;
 + int n;
 +
 + while (*s) {
 + int wlen = strcspn(s,  \t);
 +
 + if (column + wlen = max  column  start) {
 + printf(\n%*s, start, );
 + column = start + corr;
 + }
 + n = printf(%s%.*s, column  start ?   : , wlen, s);
 + if (n = 0)
 + break;
 + s += wlen;
 + column += n;
 + while (isspace(*s))
 + s++;
 + }
 +}
 +
 +static int get_columns(void)
 +{
 + /*
 +  * Should ask the terminal with TIOCGWINSZ here, but we
 +  * need the original fd before the pager.
 +  */
 + return 79;
  }
  
  void print_pmu_events(const char *event_glob, bool name_only)
 @@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
 name_only)
   char buf[1024];
   int printed = 0;
   int len, j;
 - char **aliases;
 + struct pair *aliases;
 + int numdesc = 0;
 + int columns = get_columns();
  
   pmu = NULL;
   len = 0;
   while ((pmu = perf_pmu__scan(pmu)) != NULL)
   list_for_each_entry(alias, pmu-aliases, list)
   len++;
 - aliases = malloc(sizeof(char *) * len);
 + aliases = malloc(sizeof(struct pair) * len);
   if (!aliases)
   return;
   pmu = NULL;
   j = 0;
   while ((pmu = perf_pmu__scan(pmu)) != NULL)
   list_for_each_entry(alias, pmu-aliases, list) {
 - char *name = format_alias(buf, sizeof(buf), pmu, alias);
 + char *name = alias-desc ? alias-name :
 + format_alias(buf, sizeof(buf), pmu, alias);
   bool is_cpu = !strcmp(pmu-name, cpu);
  
   if (event_glob != NULL 
 @@ -756,22 +816,31 @@ void print_pmu_events(const char *event_glob, bool 
 name_only)
 (!is_cpu  strglobmatch(alias-name,
  event_glob
   continue;
 - aliases[j] = name;
 - if (is_cpu  !name_only)
 - aliases[j] = format_alias_or(buf, sizeof(buf),
 -   pmu, alias);
 - aliases[j] = strdup(aliases[j]);
 + aliases[j].name = name;
 + if (is_cpu  !name_only  !alias-desc)
 + aliases[j].name = format_alias_or(buf,
 +   sizeof(buf),
 +   pmu, alias);
 + aliases[j].name = strdup(aliases[j].name);
 + aliases[j].desc = alias-desc;
   j++;
   }
   len = j;
 - qsort(aliases, len, sizeof(char *), cmp_string);
 + qsort(aliases, len, sizeof(struct pair), cmp_pair);
   for (j = 0; j  len; j++) {
   if (name_only) {
 - printf(%s , aliases[j]);
 + printf(%s , aliases[j].name);
   continue;
   }
 - printf(  %-50s [Kernel PMU event]\n, aliases[j]);
 - zfree(aliases[j]);
 + if (aliases[j].desc) {
 + if (numdesc++ == 0  printed)
 + printf(\n);
 + printf(  %-50s [, aliases[j].name);
 + wordwrap(aliases[j].desc, 53, columns, 1);
 + printf(]\n);
 + } else
 +

Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-07-09 Thread Jiri Olsa
On Fri, Jun 27, 2014 at 04:15:57PM -0700, Andi Kleen wrote:
 From: Andi Kleen a...@linux.intel.com
 
 Change pmu.c to allow descriptions of events and add interfaces
 to add aliases at runtime from another file. To be used by jevents in the
 next patch.
 
 Acked-by: Namhyung Kim namhy...@kernel.org
 Signed-off-by: Andi Kleen a...@linux.intel.com
 ---

SNIP

 +}
 +
 +static int get_columns(void)
 +{
 + /*
 +  * Should ask the terminal with TIOCGWINSZ here, but we
 +  * need the original fd before the pager.
 +  */
 + return 79;
  }

so this ^^^ gets removed by
  perf, tools: Query terminal width and use in perf list

please move that patch ahead of this one

jirka
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-27 Thread Andi Kleen
From: Andi Kleen 

Change pmu.c to allow descriptions of events and add interfaces
to add aliases at runtime from another file. To be used by jevents in the
next patch.

Acked-by: Namhyung Kim 
Signed-off-by: Andi Kleen 
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias->scale = 1.0;
alias->unit[0] = '\0';
 
-   ret = parse_events_terms(>terms, buf);
+   ret = parse_events_terms(>terms, val);
if (ret) {
+   pr_err("Cannot parse alias %s: %d\n", val, ret);
free(alias);
return ret;
}
 
alias->name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias->desc = desc ? strdup(desc) : NULL;
list_add_tail(>list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as->desc != !!bs->desc)
+   return !!as->desc - !!bs->desc;
+   return strcmp(as->name, bs->name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s, " \t");
+
+   if (column + wlen >= max && column > start) {
+   printf("\n%*s", start, "");
+   column = start + corr;
+   }
+   n = printf("%s%.*s", column > start ? " " : "", wlen, s);
+   if (n <= 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, >aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-27 Thread Andi Kleen
From: Andi Kleen a...@linux.intel.com

Change pmu.c to allow descriptions of events and add interfaces
to add aliases at runtime from another file. To be used by jevents in the
next patch.

Acked-by: Namhyung Kim namhy...@kernel.org
Signed-off-by: Andi Kleen a...@linux.intel.com
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias-scale = 1.0;
alias-unit[0] = '\0';
 
-   ret = parse_events_terms(alias-terms, buf);
+   ret = parse_events_terms(alias-terms, val);
if (ret) {
+   pr_err(Cannot parse alias %s: %d\n, val, ret);
free(alias);
return ret;
}
 
alias-name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias-desc = desc ? strdup(desc) : NULL;
list_add_tail(alias-list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as-desc != !!bs-desc)
+   return !!as-desc - !!bs-desc;
+   return strcmp(as-name, bs-name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s,  \t);
+
+   if (column + wlen = max  column  start) {
+   printf(\n%*s, start, );
+   column = start + corr;
+   }
+   n = printf(%s%.*s, column  start ?   : , wlen, s);
+   if (n = 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, pmu-aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = 

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-13 Thread Andi Kleen
From: Andi Kleen 

Change pmu.c to allow descriptions of events and add interfaces
to add aliases at runtime from another file. To be used by jevents in the
next patch.

Acked-by: Namhyung Kim 
Signed-off-by: Andi Kleen 
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias->scale = 1.0;
alias->unit[0] = '\0';
 
-   ret = parse_events_terms(>terms, buf);
+   ret = parse_events_terms(>terms, val);
if (ret) {
+   pr_err("Cannot parse alias %s: %d\n", val, ret);
free(alias);
return ret;
}
 
alias->name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias->desc = desc ? strdup(desc) : NULL;
list_add_tail(>list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as->desc != !!bs->desc)
+   return !!as->desc - !!bs->desc;
+   return strcmp(as->name, bs->name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s, " \t");
+
+   if (column + wlen >= max && column > start) {
+   printf("\n%*s", start, "");
+   column = start + corr;
+   }
+   n = printf("%s%.*s", column > start ? " " : "", wlen, s);
+   if (n <= 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, >aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-13 Thread Andi Kleen
From: Andi Kleen a...@linux.intel.com

Change pmu.c to allow descriptions of events and add interfaces
to add aliases at runtime from another file. To be used by jevents in the
next patch.

Acked-by: Namhyung Kim namhy...@kernel.org
Signed-off-by: Andi Kleen a...@linux.intel.com
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias-scale = 1.0;
alias-unit[0] = '\0';
 
-   ret = parse_events_terms(alias-terms, buf);
+   ret = parse_events_terms(alias-terms, val);
if (ret) {
+   pr_err(Cannot parse alias %s: %d\n, val, ret);
free(alias);
return ret;
}
 
alias-name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias-desc = desc ? strdup(desc) : NULL;
list_add_tail(alias-list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as-desc != !!bs-desc)
+   return !!as-desc - !!bs-desc;
+   return strcmp(as-name, bs-name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s,  \t);
+
+   if (column + wlen = max  column  start) {
+   printf(\n%*s, start, );
+   column = start + corr;
+   }
+   n = printf(%s%.*s, column  start ?   : , wlen, s);
+   if (n = 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, pmu-aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = 

Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-09 Thread Namhyung Kim
Hi Andi,

On Mon, 9 Jun 2014 18:52:45 +0200, Andi Kleen wrote:
>> Hmm.. this will print the description at right side and I think it'd be
>> better if it prints in another line(s) like below:
>
> I think it's better to show the descriptions by default without 
> an extra option. I suspect most people want to see them, or if they
> need them they won't know about obscure -v options.

I partially agree, but I guess adding -v option to the command is not
that hard for them. :)  Maybe we could add a message in order to advise
users to use -v option for description like below:

  $ perf list
  # Use -v/--verbose to see event description (if exists)
  ...

>
>> 
>>   agu_bypass_cancel.count[Kernel PMU event]
>> This event counts executed load operations with all the following
>>  traits: 1. addressing of the format [base + offset], 2. the offset
>>  is between 1 and 2047, 3. the address specified in the base register
>>  is in one page and the address [base+offset] is in an
>
> The problem with this format is that it is not compatible, so it would
> break existing parsers that look at perf list output.  That is why I ended up
> with the right side format.

Hmm.. I think existing parsers should not use -v option then.  The perf
list was for listing only event names (and their types).

I think the main problem of the right side format is that it hurts
readability especially on small screens/terminals.

Thanks,
Namhyung

>
>
>>   arith.fpu_div  [Kernel PMU event]
>> Divide operations executed
>>   arith.fpu_div_active   [Kernel PMU event]
>> Cycles when divider is busy executing divide operations
>>   ...
>> 
>> 
>> I just tweaked it using -v option for perf list.  Below is the change I
>> made on top of your series.  What do you think?
>
> I prefer not to apply that patch.
>
> I guess what could make sense is a quiet option to not print
> descriptions.
>
> -Andi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-09 Thread Andi Kleen
> Hmm.. this will print the description at right side and I think it'd be
> better if it prints in another line(s) like below:

I think it's better to show the descriptions by default without 
an extra option. I suspect most people want to see them, or if they
need them they won't know about obscure -v options.

> 
>   agu_bypass_cancel.count[Kernel PMU event]
> This event counts executed load operations with all the following
>  traits: 1. addressing of the format [base + offset], 2. the offset
>  is between 1 and 2047, 3. the address specified in the base register
>  is in one page and the address [base+offset] is in an

The problem with this format is that it is not compatible, so it would
break existing parsers that look at perf list output.  That is why I ended up
with the right side format.


>   arith.fpu_div  [Kernel PMU event]
> Divide operations executed
>   arith.fpu_div_active   [Kernel PMU event]
> Cycles when divider is busy executing divide operations
>   ...
> 
> 
> I just tweaked it using -v option for perf list.  Below is the change I
> made on top of your series.  What do you think?

I prefer not to apply that patch.

I guess what could make sense is a quiet option to not print
descriptions.

-Andi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-09 Thread Andi Kleen
 Hmm.. this will print the description at right side and I think it'd be
 better if it prints in another line(s) like below:

I think it's better to show the descriptions by default without 
an extra option. I suspect most people want to see them, or if they
need them they won't know about obscure -v options.

 
   agu_bypass_cancel.count[Kernel PMU event]
 This event counts executed load operations with all the following
  traits: 1. addressing of the format [base + offset], 2. the offset
  is between 1 and 2047, 3. the address specified in the base register
  is in one page and the address [base+offset] is in an

The problem with this format is that it is not compatible, so it would
break existing parsers that look at perf list output.  That is why I ended up
with the right side format.


   arith.fpu_div  [Kernel PMU event]
 Divide operations executed
   arith.fpu_div_active   [Kernel PMU event]
 Cycles when divider is busy executing divide operations
   ...
 
 
 I just tweaked it using -v option for perf list.  Below is the change I
 made on top of your series.  What do you think?

I prefer not to apply that patch.

I guess what could make sense is a quiet option to not print
descriptions.

-Andi
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-09 Thread Namhyung Kim
Hi Andi,

On Mon, 9 Jun 2014 18:52:45 +0200, Andi Kleen wrote:
 Hmm.. this will print the description at right side and I think it'd be
 better if it prints in another line(s) like below:

 I think it's better to show the descriptions by default without 
 an extra option. I suspect most people want to see them, or if they
 need them they won't know about obscure -v options.

I partially agree, but I guess adding -v option to the command is not
that hard for them. :)  Maybe we could add a message in order to advise
users to use -v option for description like below:

  $ perf list
  # Use -v/--verbose to see event description (if exists)
  ...


 
   agu_bypass_cancel.count[Kernel PMU event]
 This event counts executed load operations with all the following
  traits: 1. addressing of the format [base + offset], 2. the offset
  is between 1 and 2047, 3. the address specified in the base register
  is in one page and the address [base+offset] is in an

 The problem with this format is that it is not compatible, so it would
 break existing parsers that look at perf list output.  That is why I ended up
 with the right side format.

Hmm.. I think existing parsers should not use -v option then.  The perf
list was for listing only event names (and their types).

I think the main problem of the right side format is that it hurts
readability especially on small screens/terminals.

Thanks,
Namhyung



   arith.fpu_div  [Kernel PMU event]
 Divide operations executed
   arith.fpu_div_active   [Kernel PMU event]
 Cycles when divider is busy executing divide operations
   ...
 
 
 I just tweaked it using -v option for perf list.  Below is the change I
 made on top of your series.  What do you think?

 I prefer not to apply that patch.

 I guess what could make sense is a quiet option to not print
 descriptions.

 -Andi
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-08 Thread Namhyung Kim
Hi Andi,

On Fri, 30 May 2014 14:50:08 -0700, Andi Kleen wrote:
> @@ -756,22 +816,31 @@ void print_pmu_events(const char *event_glob, bool 
> name_only)
> (!is_cpu && strglobmatch(alias->name,
>  event_glob
>   continue;
> - aliases[j] = name;
> - if (is_cpu && !name_only)
> - aliases[j] = format_alias_or(buf, sizeof(buf),
> -   pmu, alias);
> - aliases[j] = strdup(aliases[j]);
> + aliases[j].name = name;
> + if (is_cpu && !name_only && !alias->desc)
> + aliases[j].name = format_alias_or(buf,
> +   sizeof(buf),
> +   pmu, alias);
> + aliases[j].name = strdup(aliases[j].name);
> + aliases[j].desc = alias->desc;
>   j++;
>   }
>   len = j;
> - qsort(aliases, len, sizeof(char *), cmp_string);
> + qsort(aliases, len, sizeof(struct pair), cmp_pair);
>   for (j = 0; j < len; j++) {
>   if (name_only) {
> - printf("%s ", aliases[j]);
> + printf("%s ", aliases[j].name);
>   continue;
>   }
> - printf("  %-50s [Kernel PMU event]\n", aliases[j]);
> - zfree([j]);
> + if (aliases[j].desc) {
> + if (numdesc++ == 0 && printed)
> + printf("\n");
> + printf("  %-50s [", aliases[j].name);
> + wordwrap(aliases[j].desc, 53, columns, 1);
> + printf("]\n");
> + } else
> + printf("  %-50s [Kernel PMU event]\n", aliases[j].name);
> + zfree([j].name);

Hmm.. this will print the description at right side and I think it'd be
better if it prints in another line(s) like below:


  agu_bypass_cancel.count[Kernel PMU event]
This event counts executed load operations with all the following
 traits: 1. addressing of the format [base + offset], 2. the offset
 is between 1 and 2047, 3. the address specified in the base register
 is in one page and the address [base+offset] is in an
  arith.fpu_div  [Kernel PMU event]
Divide operations executed
  arith.fpu_div_active   [Kernel PMU event]
Cycles when divider is busy executing divide operations
  ...


I just tweaked it using -v option for perf list.  Below is the change I
made on top of your series.  What do you think?

Thanks,
Namhyung


diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 086c96fa959b..e65a3b428a44 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -13,6 +13,7 @@
 
 #include "util/parse-events.h"
 #include "util/cache.h"
+#include "util/debug.h"
 #include "util/pmu.h"
 #include "util/parse-options.h"
 
@@ -22,6 +23,8 @@ int cmd_list(int argc, const char **argv, const char *prefix 
__maybe_unused)
const struct option list_options[] = {
OPT_STRING(0, "events-file", _file, "json file",
   "Read event json file"),
+   OPT_INCR('v', "verbose", ,
+"be more verbose (show event description if exist)"),
OPT_END()
};
const char * const list_usage[] = {
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b87f52058bb4..99a2156e6c54 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -838,14 +838,16 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
printf("%s ", aliases[j].name);
continue;
}
-   if (aliases[j].desc) {
-   if (numdesc++ == 0 && printed)
-   printf("\n");
-   printf("  %-50s [", aliases[j].name);
-   wordwrap(aliases[j].desc, 53, columns, 1);
-   printf("]\n");
-   } else
-   printf("  %-50s [Kernel PMU event]\n", aliases[j].name);
+
+   if (aliases[j].desc && numdesc++ == 0 && printed)
+   printf("\n");
+   printf("  %-50s [Kernel PMU event]\n", aliases[j].name);
+
+   if (aliases[j].desc && verbose) {
+   printf("%8s", "");
+   wordwrap(aliases[j].desc, 8, columns, 1);
+   printf("\n");
+   }
zfree([j].name);
printed++;
}


--
To unsubscribe from this list: send the 

Re: [PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-06-08 Thread Namhyung Kim
Hi Andi,

On Fri, 30 May 2014 14:50:08 -0700, Andi Kleen wrote:
 @@ -756,22 +816,31 @@ void print_pmu_events(const char *event_glob, bool 
 name_only)
 (!is_cpu  strglobmatch(alias-name,
  event_glob
   continue;
 - aliases[j] = name;
 - if (is_cpu  !name_only)
 - aliases[j] = format_alias_or(buf, sizeof(buf),
 -   pmu, alias);
 - aliases[j] = strdup(aliases[j]);
 + aliases[j].name = name;
 + if (is_cpu  !name_only  !alias-desc)
 + aliases[j].name = format_alias_or(buf,
 +   sizeof(buf),
 +   pmu, alias);
 + aliases[j].name = strdup(aliases[j].name);
 + aliases[j].desc = alias-desc;
   j++;
   }
   len = j;
 - qsort(aliases, len, sizeof(char *), cmp_string);
 + qsort(aliases, len, sizeof(struct pair), cmp_pair);
   for (j = 0; j  len; j++) {
   if (name_only) {
 - printf(%s , aliases[j]);
 + printf(%s , aliases[j].name);
   continue;
   }
 - printf(  %-50s [Kernel PMU event]\n, aliases[j]);
 - zfree(aliases[j]);
 + if (aliases[j].desc) {
 + if (numdesc++ == 0  printed)
 + printf(\n);
 + printf(  %-50s [, aliases[j].name);
 + wordwrap(aliases[j].desc, 53, columns, 1);
 + printf(]\n);
 + } else
 + printf(  %-50s [Kernel PMU event]\n, aliases[j].name);
 + zfree(aliases[j].name);

Hmm.. this will print the description at right side and I think it'd be
better if it prints in another line(s) like below:


  agu_bypass_cancel.count[Kernel PMU event]
This event counts executed load operations with all the following
 traits: 1. addressing of the format [base + offset], 2. the offset
 is between 1 and 2047, 3. the address specified in the base register
 is in one page and the address [base+offset] is in an
  arith.fpu_div  [Kernel PMU event]
Divide operations executed
  arith.fpu_div_active   [Kernel PMU event]
Cycles when divider is busy executing divide operations
  ...


I just tweaked it using -v option for perf list.  Below is the change I
made on top of your series.  What do you think?

Thanks,
Namhyung


diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 086c96fa959b..e65a3b428a44 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -13,6 +13,7 @@
 
 #include util/parse-events.h
 #include util/cache.h
+#include util/debug.h
 #include util/pmu.h
 #include util/parse-options.h
 
@@ -22,6 +23,8 @@ int cmd_list(int argc, const char **argv, const char *prefix 
__maybe_unused)
const struct option list_options[] = {
OPT_STRING(0, events-file, json_file, json file,
   Read event json file),
+   OPT_INCR('v', verbose, verbose,
+be more verbose (show event description if exist)),
OPT_END()
};
const char * const list_usage[] = {
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b87f52058bb4..99a2156e6c54 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -838,14 +838,16 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
printf(%s , aliases[j].name);
continue;
}
-   if (aliases[j].desc) {
-   if (numdesc++ == 0  printed)
-   printf(\n);
-   printf(  %-50s [, aliases[j].name);
-   wordwrap(aliases[j].desc, 53, columns, 1);
-   printf(]\n);
-   } else
-   printf(  %-50s [Kernel PMU event]\n, aliases[j].name);
+
+   if (aliases[j].desc  numdesc++ == 0  printed)
+   printf(\n);
+   printf(  %-50s [Kernel PMU event]\n, aliases[j].name);
+
+   if (aliases[j].desc  verbose) {
+   printf(%8s, );
+   wordwrap(aliases[j].desc, 8, columns, 1);
+   printf(\n);
+   }
zfree(aliases[j].name);
printed++;
}


--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-05-30 Thread Andi Kleen
From: Andi Kleen 

Change pmu.c to allow descriptions of events and add interfaces
to add aliases. Used in the next patch.

Signed-off-by: Andi Kleen 
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias->scale = 1.0;
alias->unit[0] = '\0';
 
-   ret = parse_events_terms(>terms, buf);
+   ret = parse_events_terms(>terms, val);
if (ret) {
+   pr_err("Cannot parse alias %s: %d\n", val, ret);
free(alias);
return ret;
}
 
alias->name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias->desc = desc ? strdup(desc) : NULL;
list_add_tail(>list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as->desc != !!bs->desc)
+   return !!as->desc - !!bs->desc;
+   return strcmp(as->name, bs->name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s, " \t");
+
+   if (column + wlen >= max && column > start) {
+   printf("\n%*s", start, "");
+   column = start + corr;
+   }
+   n = printf("%s%.*s", column > start ? " " : "", wlen, s);
+   if (n <= 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, >aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, >aliases, list) {
-   char 

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-05-30 Thread Andi Kleen
From: Andi Kleen a...@linux.intel.com

Change pmu.c to allow descriptions of events and add interfaces
to add aliases. Used in the next patch.

Signed-off-by: Andi Kleen a...@linux.intel.com
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias-scale = 1.0;
alias-unit[0] = '\0';
 
-   ret = parse_events_terms(alias-terms, buf);
+   ret = parse_events_terms(alias-terms, val);
if (ret) {
+   pr_err(Cannot parse alias %s: %d\n, val, ret);
free(alias);
return ret;
}
 
alias-name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias-desc = desc ? strdup(desc) : NULL;
list_add_tail(alias-list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as-desc != !!bs-desc)
+   return !!as-desc - !!bs-desc;
+   return strcmp(as-name, bs-name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s,  \t);
+
+   if (column + wlen = max  column  start) {
+   printf(\n%*s, start, );
+   column = start + corr;
+   }
+   n = printf(%s%.*s, column  start ?   : , wlen, s);
+   if (n = 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, pmu-aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, pmu-aliases, list) 

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-05-15 Thread Andi Kleen
From: Andi Kleen 

Change pmu.c to allow descriptions of events and add interfaces
to add aliases. Used in the next patch.

Signed-off-by: Andi Kleen 
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias->scale = 1.0;
alias->unit[0] = '\0';
 
-   ret = parse_events_terms(>terms, buf);
+   ret = parse_events_terms(>terms, val);
if (ret) {
+   pr_err("Cannot parse alias %s: %d\n", val, ret);
free(alias);
return ret;
}
 
alias->name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias->desc = desc ? strdup(desc) : NULL;
list_add_tail(>list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as->desc != !!bs->desc)
+   return !!as->desc - !!bs->desc;
+   return strcmp(as->name, bs->name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s, " \t");
+
+   if (column + wlen >= max && column > start) {
+   printf("\n%*s", start, "");
+   column = start + corr;
+   }
+   n = printf("%s%.*s", column > start ? " " : "", wlen, s);
+   if (n <= 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, >aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, >aliases, list) {
-   char 

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-05-15 Thread Andi Kleen
From: Andi Kleen a...@linux.intel.com

Change pmu.c to allow descriptions of events and add interfaces
to add aliases. Used in the next patch.

Signed-off-by: Andi Kleen a...@linux.intel.com
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias-scale = 1.0;
alias-unit[0] = '\0';
 
-   ret = parse_events_terms(alias-terms, buf);
+   ret = parse_events_terms(alias-terms, val);
if (ret) {
+   pr_err(Cannot parse alias %s: %d\n, val, ret);
free(alias);
return ret;
}
 
alias-name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias-desc = desc ? strdup(desc) : NULL;
list_add_tail(alias-list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as-desc != !!bs-desc)
+   return !!as-desc - !!bs-desc;
+   return strcmp(as-name, bs-name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s,  \t);
+
+   if (column + wlen = max  column  start) {
+   printf(\n%*s, start, );
+   column = start + corr;
+   }
+   n = printf(%s%.*s, column  start ?   : , wlen, s);
+   if (n = 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, pmu-aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, pmu-aliases, list) 

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-05-12 Thread Andi Kleen
From: Andi Kleen 

Change pmu.c to allow descriptions of events and add interfaces
to add aliases. Used in the next patch.

Signed-off-by: Andi Kleen 
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias->scale = 1.0;
alias->unit[0] = '\0';
 
-   ret = parse_events_terms(>terms, buf);
+   ret = parse_events_terms(>terms, val);
if (ret) {
+   pr_err("Cannot parse alias %s: %d\n", val, ret);
free(alias);
return ret;
}
 
alias->name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias->desc = desc ? strdup(desc) : NULL;
list_add_tail(>list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as->desc != !!bs->desc)
+   return !!as->desc - !!bs->desc;
+   return strcmp(as->name, bs->name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s, " \t");
+
+   if (column + wlen >= max && column > start) {
+   printf("\n%*s", start, "");
+   column = start + corr;
+   }
+   n = printf("%s%.*s", column > start ? " " : "", wlen, s);
+   if (n <= 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, >aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, >aliases, list) {
-   char 

[PATCH 2/9] perf, tools: Add support for text descriptions of events and alias add

2014-05-12 Thread Andi Kleen
From: Andi Kleen a...@linux.intel.com

Change pmu.c to allow descriptions of events and add interfaces
to add aliases. Used in the next patch.

Signed-off-by: Andi Kleen a...@linux.intel.com
---
 tools/perf/util/pmu.c | 127 ++
 1 file changed, 98 insertions(+), 29 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb..baec090 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -14,6 +14,7 @@
 
 struct perf_pmu_alias {
char *name;
+   char *desc;
struct list_head terms;
struct list_head list;
char unit[UNIT_MAX_LEN+1];
@@ -171,17 +172,12 @@ error:
return -1;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 
FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *name,
+char *dir, char *desc, char *val)
 {
struct perf_pmu_alias *alias;
-   char buf[256];
int ret;
 
-   ret = fread(buf, 1, sizeof(buf), file);
-   if (ret == 0)
-   return -EINVAL;
-   buf[ret] = 0;
-
alias = malloc(sizeof(*alias));
if (!alias)
return -ENOMEM;
@@ -190,24 +186,45 @@ static int perf_pmu__new_alias(struct list_head *list, 
char *dir, char *name, FI
alias-scale = 1.0;
alias-unit[0] = '\0';
 
-   ret = parse_events_terms(alias-terms, buf);
+   ret = parse_events_terms(alias-terms, val);
if (ret) {
+   pr_err(Cannot parse alias %s: %d\n, val, ret);
free(alias);
return ret;
}
 
alias-name = strdup(name);
-   /*
-* load unit name and scale if available
-*/
-   perf_pmu__parse_unit(alias, dir, name);
-   perf_pmu__parse_scale(alias, dir, name);
 
+   if (dir) {
+   /*
+* load unit name and scale if available
+*/
+   perf_pmu__parse_unit(alias, dir, name);
+   perf_pmu__parse_scale(alias, dir, name);
+   }
+
+   alias-desc = desc ? strdup(desc) : NULL;
list_add_tail(alias-list, list);
 
return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list,
+  char *dir,
+  char *name,
+  FILE *file)
+{
+   char buf[256];
+   int ret;
+
+   ret = fread(buf, 1, sizeof(buf), file);
+   if (ret == 0)
+   return -EINVAL;
+   buf[ret] = 0;
+
+   return __perf_pmu__new_alias(list, name, dir, NULL, buf);
+}
+
 /*
  * Process all the sysfs attributes located under the directory
  * specified in 'dir' parameter.
@@ -720,11 +737,51 @@ static char *format_alias_or(char *buf, int len, struct 
perf_pmu *pmu,
return buf;
 }
 
-static int cmp_string(const void *a, const void *b)
+struct pair {
+   char *name;
+   char *desc;
+};
+
+static int cmp_pair(const void *a, const void *b)
+{
+   const struct pair *as = a;
+   const struct pair *bs = b;
+
+   /* Put downloaded event list last */
+   if (!!as-desc != !!bs-desc)
+   return !!as-desc - !!bs-desc;
+   return strcmp(as-name, bs-name);
+}
+
+static void wordwrap(char *s, int start, int max, int corr)
 {
-   const char * const *as = a;
-   const char * const *bs = b;
-   return strcmp(*as, *bs);
+   int column = start;
+   int n;
+
+   while (*s) {
+   int wlen = strcspn(s,  \t);
+
+   if (column + wlen = max  column  start) {
+   printf(\n%*s, start, );
+   column = start + corr;
+   }
+   n = printf(%s%.*s, column  start ?   : , wlen, s);
+   if (n = 0)
+   break;
+   s += wlen;
+   column += n;
+   while (isspace(*s))
+   s++;
+   }
+}
+
+static int get_columns(void)
+{
+   /*
+* Should ask the terminal with TIOCGWINSZ here, but we
+* need the original fd before the pager.
+*/
+   return 79;
 }
 
 void print_pmu_events(const char *event_glob, bool name_only)
@@ -734,21 +791,24 @@ void print_pmu_events(const char *event_glob, bool 
name_only)
char buf[1024];
int printed = 0;
int len, j;
-   char **aliases;
+   struct pair *aliases;
+   int numdesc = 0;
+   int columns = get_columns();
 
pmu = NULL;
len = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, pmu-aliases, list)
len++;
-   aliases = malloc(sizeof(char *) * len);
+   aliases = malloc(sizeof(struct pair) * len);
if (!aliases)
return;
pmu = NULL;
j = 0;
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, pmu-aliases, list)