Skip to content

Commit ef62535

Browse files
tlfalconintel-lab-lkp
authored andcommitted
perf top: populate PMU capabilities data in perf_env
Calling perf top with branch filters enabled on Intel CPU's with branch counters logging (A.K.A LBR event logging [1]) support results in a segfault. $ perf top -e '{cpu_core/cpu-cycles/,cpu_core/event=0xc6,umask=0x3,frontend=0x11,name=frontend_retired_dsb_miss/}' -j any,counter ... Thread 27 "perf" received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7fffafff76c0 (LWP 949003)] perf_env__find_br_cntr_info (env=0xf66dc0 <perf_env>, nr=0x0, width=0x7fffafff62c0) at util/env.c:653 653 *width = env->cpu_pmu_caps ? env->br_cntr_width : (gdb) bt #0 perf_env__find_br_cntr_info (env=0xf66dc0 <perf_env>, nr=0x0, width=0x7fffafff62c0) at util/env.c:653 #1 0x00000000005b1599 in symbol__account_br_cntr (branch=0x7fffcc3db580, evsel=0xfea2d0, offset=12, br_cntr=8) at util/annotate.c:345 #2 0x00000000005b17fb in symbol__account_cycles (addr=5658172, start=5658160, sym=0x7fffcc0ee420, cycles=539, evsel=0xfea2d0, br_cntr=8) at util/annotate.c:389 #3 0x00000000005b1976 in addr_map_symbol__account_cycles (ams=0x7fffcd7b01d0, start=0x7fffcd7b02b0, cycles=539, evsel=0xfea2d0, br_cntr=8) at util/annotate.c:422 #4 0x000000000068d57f in hist__account_cycles (bs=0x110d288, al=0x7fffafff6540, sample=0x7fffafff6760, nonany_branch_mode=false, total_cycles=0x0, evsel=0xfea2d0) at util/hist.c:2850 #5 0x0000000000446216 in hist_iter__top_callback (iter=0x7fffafff6590, al=0x7fffafff6540, single=true, arg=0x7fffffff9e00) at builtin-top.c:737 torvalds#6 0x0000000000689787 in hist_entry_iter__add (iter=0x7fffafff6590, al=0x7fffafff6540, max_stack_depth=127, arg=0x7fffffff9e00) at util/hist.c:1359 torvalds#7 0x0000000000446710 in perf_event__process_sample (tool=0x7fffffff9e00, event=0x110d250, evsel=0xfea2d0, sample=0x7fffafff6760, machine=0x108c968) at builtin-top.c:845 torvalds#8 0x0000000000447735 in deliver_event (qe=0x7fffffffa120, qevent=0x10fc200) at builtin-top.c:1211 torvalds#9 0x000000000064ccae in do_flush (oe=0x7fffffffa120, show_progress=false) at util/ordered-events.c:245 torvalds#10 0x000000000064d005 in __ordered_events__flush (oe=0x7fffffffa120, how=OE_FLUSH__TOP, timestamp=0) at util/ordered-events.c:324 torvalds#11 0x000000000064d0ef in ordered_events__flush (oe=0x7fffffffa120, how=OE_FLUSH__TOP) at util/ordered-events.c:342 torvalds#12 0x00000000004472a9 in process_thread (arg=0x7fffffff9e00) at builtin-top.c:1120 torvalds#13 0x00007ffff6e7dba8 in start_thread (arg=<optimized out>) at pthread_create.c:448 torvalds#14 0x00007ffff6f01b8c in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78 The cause is that perf_env__find_br_cntr_info tries to access a null pointer pmu_caps in the perf_env struct. A similar issue exists for homogeneous core systems which use the cpu_pmu_caps structure. Fix this by populating cpu_pmu_caps and pmu_caps structures with values from sysfs when calling perf top with branch stack sampling enabled. [1], LBR event logging introduced here: https://lore.kernel.org/all/[email protected]/ Reviewed-by: Ian Rogers <[email protected]> Signed-off-by: Thomas Falcon <[email protected]>
1 parent 3b2b007 commit ef62535

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

tools/perf/builtin-top.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,6 +1734,14 @@ int cmd_top(int argc, const char **argv)
17341734
if (opts->branch_stack && callchain_param.enabled)
17351735
symbol_conf.show_branchflag_count = true;
17361736

1737+
if (opts->branch_stack) {
1738+
status = perf_env__read_core_pmu_caps(&perf_env);
1739+
if (status) {
1740+
pr_err("PMU capability data is not available\n");
1741+
goto out_delete_evlist;
1742+
}
1743+
}
1744+
17371745
sort__mode = SORT_MODE__TOP;
17381746
/* display thread wants entries to be collapsed in a different tree */
17391747
perf_hpp_list.need_collapse = 1;

tools/perf/util/env.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,116 @@ static int perf_env__read_nr_cpus_avail(struct perf_env *env)
416416
return env->nr_cpus_avail ? 0 : -ENOENT;
417417
}
418418

419+
static int __perf_env__read_core_pmu_caps(const struct perf_pmu *pmu,
420+
int *nr_caps, char ***caps,
421+
unsigned int *max_branches,
422+
unsigned int *br_cntr_nr,
423+
unsigned int *br_cntr_width)
424+
{
425+
struct perf_pmu_caps *pcaps = NULL;
426+
char *ptr, **tmp;
427+
int ret = 0;
428+
429+
*nr_caps = 0;
430+
*caps = NULL;
431+
432+
if (!pmu->nr_caps)
433+
return 0;
434+
435+
*caps = calloc(pmu->nr_caps, sizeof(char *));
436+
if (!*caps)
437+
return -ENOMEM;
438+
439+
tmp = *caps;
440+
list_for_each_entry(pcaps, &pmu->caps, list) {
441+
if (asprintf(&ptr, "%s=%s", pcaps->name, pcaps->value) < 0) {
442+
ret = -ENOMEM;
443+
goto error;
444+
}
445+
446+
*tmp++ = ptr;
447+
448+
if (!strcmp(pcaps->name, "branches"))
449+
*max_branches = atoi(pcaps->value);
450+
else if (!strcmp(pcaps->name, "branch_counter_nr"))
451+
*br_cntr_nr = atoi(pcaps->value);
452+
else if (!strcmp(pcaps->name, "branch_counter_width"))
453+
*br_cntr_width = atoi(pcaps->value);
454+
}
455+
*nr_caps = pmu->nr_caps;
456+
return 0;
457+
error:
458+
while (tmp-- != *caps)
459+
zfree(tmp);
460+
zfree(caps);
461+
*nr_caps = 0;
462+
return ret;
463+
}
464+
465+
int perf_env__read_core_pmu_caps(struct perf_env *env)
466+
{
467+
struct pmu_caps *pmu_caps;
468+
struct perf_pmu *pmu = NULL;
469+
int nr_pmu, i = 0, j;
470+
int ret;
471+
472+
nr_pmu = perf_pmus__num_core_pmus();
473+
474+
if (!nr_pmu)
475+
return -ENODEV;
476+
477+
if (nr_pmu == 1) {
478+
pmu = perf_pmus__find_core_pmu();
479+
if (!pmu)
480+
return -ENODEV;
481+
ret = perf_pmu__caps_parse(pmu);
482+
if (ret < 0)
483+
return ret;
484+
return __perf_env__read_core_pmu_caps(pmu, &env->nr_cpu_pmu_caps,
485+
&env->cpu_pmu_caps,
486+
&env->max_branches,
487+
&env->br_cntr_nr,
488+
&env->br_cntr_width);
489+
}
490+
491+
pmu_caps = calloc(nr_pmu, sizeof(*pmu_caps));
492+
if (!pmu_caps)
493+
return -ENOMEM;
494+
495+
while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
496+
if (perf_pmu__caps_parse(pmu) <= 0)
497+
continue;
498+
ret = __perf_env__read_core_pmu_caps(pmu, &pmu_caps[i].nr_caps,
499+
&pmu_caps[i].caps,
500+
&pmu_caps[i].max_branches,
501+
&pmu_caps[i].br_cntr_nr,
502+
&pmu_caps[i].br_cntr_width);
503+
if (ret)
504+
goto error;
505+
506+
pmu_caps[i].pmu_name = strdup(pmu->name);
507+
if (!pmu_caps[i].pmu_name) {
508+
ret = -ENOMEM;
509+
goto error;
510+
}
511+
i++;
512+
}
513+
514+
env->nr_pmus_with_caps = nr_pmu;
515+
env->pmu_caps = pmu_caps;
516+
517+
return 0;
518+
error:
519+
for (i = 0; i < nr_pmu; i++) {
520+
for (j = 0; j < pmu_caps[i].nr_caps; j++)
521+
zfree(&pmu_caps[i].caps[j]);
522+
zfree(&pmu_caps[i].caps);
523+
zfree(&pmu_caps[i].pmu_name);
524+
}
525+
zfree(&pmu_caps);
526+
return ret;
527+
}
528+
419529
const char *perf_env__raw_arch(struct perf_env *env)
420530
{
421531
return env && !perf_env__read_arch(env) ? env->arch : "unknown";

tools/perf/util/env.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ struct btf_node;
152152

153153
extern struct perf_env perf_env;
154154

155+
int perf_env__read_core_pmu_caps(struct perf_env *env);
155156
void perf_env__exit(struct perf_env *env);
156157

157158
int perf_env__kernel_is_64_bit(struct perf_env *env);

0 commit comments

Comments
 (0)