aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2016-09-15 18:24:43 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-10-03 20:34:54 -0400
commit08e60ed15d0483be38a87d17538ccf02acff5b1f (patch)
treeec8df54befe7e2e5b8426980ace74a7a82f29876
parentdc720ffc9863b618a192f5949234c54aad00ed24 (diff)
perf pmu: Support alias descriptions
Add support to print alias descriptions in perf list, which are taken from the generated event files. The sorting code is changed to put the events with descriptions at the end. The descriptions are printed as possibly multiple word wrapped lines. Example output: % perf list ... arith.fpu_div [Divide operations executed] arith.fpu_div_active [Cycles when divider is busy executing divide operations] Committer notes: Further testing on a Broadwell machine (ThinkPad t450s), using these files: $ find tools/perf/pmu-events/arch/x86/ tools/perf/pmu-events/arch/x86/ tools/perf/pmu-events/arch/x86/Broadwell tools/perf/pmu-events/arch/x86/Broadwell/Cache.json tools/perf/pmu-events/arch/x86/Broadwell/Other.json tools/perf/pmu-events/arch/x86/Broadwell/Frontend.json tools/perf/pmu-events/arch/x86/Broadwell/Virtual-Memory.json tools/perf/pmu-events/arch/x86/Broadwell/Pipeline.json tools/perf/pmu-events/arch/x86/Broadwell/Floating-point.json tools/perf/pmu-events/arch/x86/Broadwell/Memory.json tools/perf/pmu-events/arch/x86/mapfile.csv $ Taken from: https://github.com/sukadev/linux/tree/json-code+data-v21/tools/perf/pmu-events/arch/x86/ to get this machinery to actually parse JSON files, generate $(OUTPUT)pmu-events/pmu-events.c, compile it and link it with perf, that will then use the table it contains, these files will be submitted right after this patchkit. [acme@jouet linux]$ perf list page_walker List of pre-defined events (to be used in -e): page_walker_loads.dtlb_l1 [Number of DTLB page walker hits in the L1+FB] page_walker_loads.dtlb_l2 [Number of DTLB page walker hits in the L2] page_walker_loads.dtlb_l3 [Number of DTLB page walker hits in the L3 + XSNP] page_walker_loads.dtlb_memory [Number of DTLB page walker hits in Memory] page_walker_loads.itlb_l1 [Number of ITLB page walker hits in the L1+FB] page_walker_loads.itlb_l2 [Number of ITLB page walker hits in the L2] page_walker_loads.itlb_l3 [Number of ITLB page walker hits in the L3 + XSNP] [acme@jouet linux]$ Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> Acked-by: Ingo Molnar <mingo@kernel.org> Acked-by: Jiri Olsa <jolsa@redhat.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Madhavan Srinivasan <maddy@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: linuxppc-dev@lists.ozlabs.org Link: http://lkml.kernel.org/r/1473978296-20712-7-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/util/pmu.c83
-rw-r--r--tools/perf/util/pmu.h1
2 files changed, 68 insertions, 16 deletions
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 10668b7f5272..9857fb14ea86 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -222,7 +222,7 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
222} 222}
223 223
224static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 224static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
225 char *desc __maybe_unused, char *val) 225 char *desc, char *val)
226{ 226{
227 struct perf_pmu_alias *alias; 227 struct perf_pmu_alias *alias;
228 int ret; 228 int ret;
@@ -255,6 +255,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
255 perf_pmu__parse_snapshot(alias, dir, name); 255 perf_pmu__parse_snapshot(alias, dir, name);
256 } 256 }
257 257
258 alias->desc = desc ? strdup(desc) : NULL;
259
258 list_add_tail(&alias->list, list); 260 list_add_tail(&alias->list, list);
259 261
260 return 0; 262 return 0;
@@ -1043,11 +1045,42 @@ static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
1043 return buf; 1045 return buf;
1044} 1046}
1045 1047
1046static int cmp_string(const void *a, const void *b) 1048struct pair {
1049 char *name;
1050 char *desc;
1051};
1052
1053static int cmp_pair(const void *a, const void *b)
1054{
1055 const struct pair *as = a;
1056 const struct pair *bs = b;
1057
1058 /* Put extra events last */
1059 if (!!as->desc != !!bs->desc)
1060 return !!as->desc - !!bs->desc;
1061 return strcmp(as->name, bs->name);
1062}
1063
1064static void wordwrap(char *s, int start, int max, int corr)
1047{ 1065{
1048 const char * const *as = a; 1066 int column = start;
1049 const char * const *bs = b; 1067 int n;
1050 return strcmp(*as, *bs); 1068
1069 while (*s) {
1070 int wlen = strcspn(s, " \t");
1071
1072 if (column + wlen >= max && column > start) {
1073 printf("\n%*s", start, "");
1074 column = start + corr;
1075 }
1076 n = printf("%s%.*s", column > start ? " " : "", wlen, s);
1077 if (n <= 0)
1078 break;
1079 s += wlen;
1080 column += n;
1081 while (isspace(*s))
1082 s++;
1083 }
1051} 1084}
1052 1085
1053void print_pmu_events(const char *event_glob, bool name_only) 1086void print_pmu_events(const char *event_glob, bool name_only)
@@ -1057,7 +1090,9 @@ void print_pmu_events(const char *event_glob, bool name_only)
1057 char buf[1024]; 1090 char buf[1024];
1058 int printed = 0; 1091 int printed = 0;
1059 int len, j; 1092 int len, j;
1060 char **aliases; 1093 struct pair *aliases;
1094 int numdesc = 0;
1095 int columns = 78;
1061 1096
1062 pmu = NULL; 1097 pmu = NULL;
1063 len = 0; 1098 len = 0;
@@ -1067,14 +1102,15 @@ void print_pmu_events(const char *event_glob, bool name_only)
1067 if (pmu->selectable) 1102 if (pmu->selectable)
1068 len++; 1103 len++;
1069 } 1104 }
1070 aliases = zalloc(sizeof(char *) * len); 1105 aliases = zalloc(sizeof(struct pair) * len);
1071 if (!aliases) 1106 if (!aliases)
1072 goto out_enomem; 1107 goto out_enomem;
1073 pmu = NULL; 1108 pmu = NULL;
1074 j = 0; 1109 j = 0;
1075 while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1110 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
1076 list_for_each_entry(alias, &pmu->aliases, list) { 1111 list_for_each_entry(alias, &pmu->aliases, list) {
1077 char *name = format_alias(buf, sizeof(buf), pmu, alias); 1112 char *name = alias->desc ? alias->name :
1113 format_alias(buf, sizeof(buf), pmu, alias);
1078 bool is_cpu = !strcmp(pmu->name, "cpu"); 1114 bool is_cpu = !strcmp(pmu->name, "cpu");
1079 1115
1080 if (event_glob != NULL && 1116 if (event_glob != NULL &&
@@ -1083,12 +1119,19 @@ void print_pmu_events(const char *event_glob, bool name_only)
1083 event_glob)))) 1119 event_glob))))
1084 continue; 1120 continue;
1085 1121
1086 if (is_cpu && !name_only) 1122 if (is_cpu && !name_only && !alias->desc)
1087 name = format_alias_or(buf, sizeof(buf), pmu, alias); 1123 name = format_alias_or(buf, sizeof(buf), pmu, alias);
1088 1124
1089 aliases[j] = strdup(name); 1125 aliases[j].name = name;
1090 if (aliases[j] == NULL) 1126 if (is_cpu && !name_only && !alias->desc)
1127 aliases[j].name = format_alias_or(buf,
1128 sizeof(buf),
1129 pmu, alias);
1130 aliases[j].name = strdup(aliases[j].name);
1131 if (!aliases[j].name)
1091 goto out_enomem; 1132 goto out_enomem;
1133
1134 aliases[j].desc = alias->desc;
1092 j++; 1135 j++;
1093 } 1136 }
1094 if (pmu->selectable && 1137 if (pmu->selectable &&
@@ -1096,25 +1139,33 @@ void print_pmu_events(const char *event_glob, bool name_only)
1096 char *s; 1139 char *s;
1097 if (asprintf(&s, "%s//", pmu->name) < 0) 1140 if (asprintf(&s, "%s//", pmu->name) < 0)
1098 goto out_enomem; 1141 goto out_enomem;
1099 aliases[j] = s; 1142 aliases[j].name = s;
1100 j++; 1143 j++;
1101 } 1144 }
1102 } 1145 }
1103 len = j; 1146 len = j;
1104 qsort(aliases, len, sizeof(char *), cmp_string); 1147 qsort(aliases, len, sizeof(struct pair), cmp_pair);
1105 for (j = 0; j < len; j++) { 1148 for (j = 0; j < len; j++) {
1106 if (name_only) { 1149 if (name_only) {
1107 printf("%s ", aliases[j]); 1150 printf("%s ", aliases[j].name);
1108 continue; 1151 continue;
1109 } 1152 }
1110 printf(" %-50s [Kernel PMU event]\n", aliases[j]); 1153 if (aliases[j].desc) {
1154 if (numdesc++ == 0)
1155 printf("\n");
1156 printf(" %-50s\n", aliases[j].name);
1157 printf("%*s", 8, "[");
1158 wordwrap(aliases[j].desc, 8, columns, 0);
1159 printf("]\n");
1160 } else
1161 printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
1111 printed++; 1162 printed++;
1112 } 1163 }
1113 if (printed && pager_in_use()) 1164 if (printed && pager_in_use())
1114 printf("\n"); 1165 printf("\n");
1115out_free: 1166out_free:
1116 for (j = 0; j < len; j++) 1167 for (j = 0; j < len; j++)
1117 zfree(&aliases[j]); 1168 zfree(&aliases[j].name);
1118 zfree(&aliases); 1169 zfree(&aliases);
1119 return; 1170 return;
1120 1171
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 743422ad900b..51d8d0d35e63 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -40,6 +40,7 @@ struct perf_pmu_info {
40 40
41struct perf_pmu_alias { 41struct perf_pmu_alias {
42 char *name; 42 char *name;
43 char *desc;
43 struct list_head terms; /* HEAD struct parse_events_term -> list */ 44 struct list_head terms; /* HEAD struct parse_events_term -> list */
44 struct list_head list; /* ELEM */ 45 struct list_head list; /* ELEM */
45 char unit[UNIT_MAX_LEN+1]; 46 char unit[UNIT_MAX_LEN+1];