summaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorThomas Richter <tmricht@linux.ibm.com>2018-06-15 06:11:05 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2018-06-25 10:59:37 -0400
commit6dde6429c5ff5b38d6d40a14a6ee105117e6364d (patch)
tree1a15fc00cee2ecafdc4a74297ce069e1af0c04c1 /tools/perf
parent0c24d6fb7bd3578e5b9e4972d01bbe3d087ded33 (diff)
perf stat: Remove duplicate event counting
'perf stat' shows a mismatch in perf stat regarding counter names on s390: Run command: [root@s35lp76 perf]# ./perf stat -e tx_nc_tend -v -- ~/mytesttx 1 >/tmp/111 tx_nc_tend: 1 573146 573146 tx_nc_tend: 1 573146 573146 Performance counter stats for '/root/mytesttx 1': 3 tx_nc_tend 0.001037252 seconds time elapsed [root@s35lp76 perf]# shows transaction counter tx_nc_tend with value 3 but it was triggered only once as seen by the output of mytesttx. When looking up the event name tx_nc_tend the following function sequence is called: parse_events_multi_pmu_add() +--> perf_pmu__scan() being called with NULL argument +--> pmu_read_sysfs() scans directory ../devices/ for all PMUs +--> perf_pmu__find() tries to find a PMU in the global pmu list. +--> pmu_lookup() called to read all file entries when not in global list. pmu_lookup() causes the issue. It calls +---> pmu_aliases() to read all the entries in the PMU directory. On s390 this is named /sys/devices/cpum_cf/events. +--> pmu_aliases_parse() reads all files and creates an alias for each file name. So we end up with first entry created by reading the sysfs file [root@s35lp76 perf]# cat /sys/devices/cpum_cf /events/TX_NC_TEND event=0x008d [root@s35lp76 perf]# Debug output shows this entry tx_nc_tend -> 'cpum_cf'/'event=0x008d '/ After all files in this directory have been read and aliases created this function is called: +--> pmu_add_cpu_aliases() This function looks up the CPU tables created by the json files. With json files for s390 now available all the aliases are added to the PMU alias list a second time. The second entry is added by reading the json file converted by jevent resulting in file pmu-events/pmu-events.c: { .name = "tx_nc_tend", .event = "event=0x8d", .desc = "Unit: cpum_cf Completed TEND \ instructions \ in non-constrained TX mode", .topic = "extended", .long_desc = "A TEND instruction has \ completed in a \ non-constrained \ transactional-execution mode", .pmu = "cpum_cf", }, Debug output shows this entry tx_nc_tend -> 'cpum_cf'/'event=0x8d'/ Function pmu_aliases_parse() and pmu_add_cpu_aliases() both use __perf_pmu__new_alias() to add an alias to the PMU alias list. There is no check if an alias already exist So we end up with 2 entries for tx_nc_tend in the PMU alias list. Having set up the PMU alias list for this PMU now parse_events_multi_add_pmu() reads the complete alias list and adds each alias with parse_events_add_pmu() to the global perfev_list. This causes the alias to be added multiple times to the event list. Fix this by making __perf_pmu__new_alias() to merge alias definitions if an alias is already on the alias list. Also print a debug message when the alias has mismatches in some fields. Output before: [root@s35lp76 perf]# ./perf stat -e tx_nc_tend -v \ -- ~/mytesttx 1 >/tmp/111 tx_nc_tend: 1 551446 551446 Performance counter stats for '/root/mytesttx 1': 3 tx_nc_tend 0.000961134 seconds time elapsed [root@s35lp76 perf]# Output after: [root@s35lp76 perf]# ./perf stat -e tx_nc_tend -v \ -- ~/mytesttx 1 >/tmp/111 tx_nc_tend: 1 551446 551446 Performance counter stats for '/root/mytesttx 1': 1 tx_nc_tend 0.000961134 seconds time elapsed [root@s35lp76 perf]# Signed-off-by: Thomas Richter <tmricht@linux.ibm.com> Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com> Reviewed-by: Jiri Olsa <jolsa@redhat.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Link: http://lkml.kernel.org/r/20180615101105.47047-3-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/pmu.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index f321ce97d9ec..3ba6a1742f91 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -234,6 +234,74 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
234 return 0; 234 return 0;
235} 235}
236 236
237static void perf_pmu_assign_str(char *name, const char *field, char **old_str,
238 char **new_str)
239{
240 if (!*old_str)
241 goto set_new;
242
243 if (*new_str) { /* Have new string, check with old */
244 if (strcasecmp(*old_str, *new_str))
245 pr_debug("alias %s differs in field '%s'\n",
246 name, field);
247 zfree(old_str);
248 } else /* Nothing new --> keep old string */
249 return;
250set_new:
251 *old_str = *new_str;
252 *new_str = NULL;
253}
254
255static void perf_pmu_update_alias(struct perf_pmu_alias *old,
256 struct perf_pmu_alias *newalias)
257{
258 perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc);
259 perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
260 &newalias->long_desc);
261 perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
262 perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
263 &newalias->metric_expr);
264 perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
265 &newalias->metric_name);
266 perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
267 old->scale = newalias->scale;
268 old->per_pkg = newalias->per_pkg;
269 old->snapshot = newalias->snapshot;
270 memcpy(old->unit, newalias->unit, sizeof(old->unit));
271}
272
273/* Delete an alias entry. */
274static void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
275{
276 zfree(&newalias->name);
277 zfree(&newalias->desc);
278 zfree(&newalias->long_desc);
279 zfree(&newalias->topic);
280 zfree(&newalias->str);
281 zfree(&newalias->metric_expr);
282 zfree(&newalias->metric_name);
283 parse_events_terms__purge(&newalias->terms);
284 free(newalias);
285}
286
287/* Merge an alias, search in alias list. If this name is already
288 * present merge both of them to combine all information.
289 */
290static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
291 struct list_head *alist)
292{
293 struct perf_pmu_alias *a;
294
295 list_for_each_entry(a, alist, list) {
296 if (!strcasecmp(newalias->name, a->name)) {
297 perf_pmu_update_alias(a, newalias);
298 perf_pmu_free_alias(newalias);
299 return true;
300 }
301 }
302 return false;
303}
304
237static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 305static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
238 char *desc, char *val, 306 char *desc, char *val,
239 char *long_desc, char *topic, 307 char *long_desc, char *topic,
@@ -310,7 +378,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
310 alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 378 alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
311 alias->str = strdup(newval); 379 alias->str = strdup(newval);
312 380
313 list_add_tail(&alias->list, list); 381 if (!perf_pmu_merge_alias(alias, list))
382 list_add_tail(&alias->list, list);
314 383
315 return 0; 384 return 0;
316} 385}