perf stat: fix case where guest/host monitoring is not supported by kernel
PATCH 1/1 perf stat: fix case where guest/host monitoring is not supported by kernel
By default, perf stat sets exclude_guest = 1. But when you run perf on a kernel which does not support host/guest filtering, then you get an error saying the event in unsupported. This comes from the fact that when the perf_event_attr struct passed by the user is larger than the one known to the kernel there is safety check which ensures that all unknown bits are zero. But here, exclude_guest is 1 (part of the unknown bits) and thus the perf_event_open() syscall return EINVAL.
To my surprise, running perf record on the same kernel did not exhibit the problem. The reason is that perf record handles the problem by catching the error and retrying with guest/host excludes set to zero. For some reason, this was not done with perf stat. This patch fixes this problem.
---
tools/perf/builtin-stat.c +29 -4
@@ -283,6 +283,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, {struct perf_event_attr *attr = &evsel->attr;struct xyarray *group_fd =NULL ; +bool exclude_guest_missing = false; +int ret;if (group && evsel != first) group_fd = first->fd;
@@ -293,16 +295,39 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, attr->inherit = !no_inherit; -if (system_wide) -return perf_evsel__open_per_cpu (evsel, evsel_list->cpus, +retry: +if (exclude_guest_missing) + evsel->attr.exclude_guest = evsel->attr.exclude_host =0 ; + +if (system_wide) { + ret =perf_evsel__open_per_cpu (evsel, evsel_list->cpus, group, group_fd); +if (ret) + goto check_ret; +return 0 ; + } +if (!target_pid && !target_tid && (!group || evsel == first)) { attr->disabled =1 ; attr->enable_on_exec =1 ; } -return perf_evsel__open_per_thread (evsel, evsel_list->threads, - group, group_fd); + ret =perf_evsel__open_per_thread (evsel, evsel_list->threads, + group, group_fd); +if (!ret) +return 0 ; +/* fall through */ +check_ret: +if (ret && errno ==EINVAL ) { +if (!exclude_guest_missing && + (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { +pr_debug ("Old kernel, cannot exclude " +"guest or host samples.\n" ); + exclude_guest_missing = true; + goto retry; + } + } +return ret; }/*
Em Fri, Apr 27, 2012 at 02:45:38PM +0200, Stephane Eranian escreveu:
Quoted 9 lines
By default, perf stat sets
exclude_guest= 1. But when you run perf on a kernel which does not support host/guest filtering, then you get an error saying the event in unsupported. This comes from the fact that when theperf_event_attrstruct passed by the user is larger than the one known to the kernel there is safety check which ensures that all unknown bits are zero. But here,exclude_guestis 1 (part of the unknown bits) and thus theperf_event_open()syscall return EINVAL.
Quoted 5 lines
To my surprise, running perf record on the same kernel did not exhibit the problem. The reason is that perf record handles the problem by catching the error and retrying with guest/host excludes set to zero. For some reason, this was not done with perf stat. This patch fixes this problem.
yeah, I have to sit down and finish perf_evlist__open, i.e. get all this capability queries.
Thanks, applying to my perf/urgent branch.
- Arnaldo
Quoted 59 lines
Signed-off-by Stephane Eranian <[email protected]>---
tools/perf/builtin-stat.c +29
-4@@ -283,6 +283,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, {struct perf_event_attr *attr = &evsel->attr;struct xyarray *group_fd =NULL ; +bool exclude_guest_missing = false; +int ret;if (group && evsel != first) group_fd = first->fd;@@ -293,16 +295,39 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, attr->inherit = !no_inherit; -if (system_wide) -return perf_evsel__open_per_cpu (evsel, evsel_list->cpus, +retry: +if (exclude_guest_missing) + evsel->attr.exclude_guest = evsel->attr.exclude_host =0 ; + +if (system_wide) { + ret =perf_evsel__open_per_cpu (evsel, evsel_list->cpus, group, group_fd); +if (ret) + goto check_ret; +return 0 ; + } +if (!target_pid && !target_tid && (!group || evsel == first)) { attr->disabled =1 ; attr->enable_on_exec =1 ; } -return perf_evsel__open_per_thread (evsel, evsel_list->threads, - group, group_fd); + ret =perf_evsel__open_per_thread (evsel, evsel_list->threads, + group, group_fd); +if (!ret) +return 0 ; +/* fall through */ +check_ret: +if (ret && errno ==EINVAL ) { +if (!exclude_guest_missing && + (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { +pr_debug ("Old kernel, cannot exclude " +"guest or host samples.\n" ); + exclude_guest_missing = true; + goto retry; + } + } +return ret; }/*
[tip:perf/urgent] perf stat: Fix case where guest/ host monitoring is not supported by kernel
In reply to Stephane EranianCommit-ID: 5622c07b4741e0afd7607bce6e850b76eeb23210 Gitweb: http://git.kernel.org/tip/5622c07b4741e0afd7607bce6e850b76eeb23210 Author: Stephane Eranian <[email protected]> AuthorDate: Fri, 27 Apr 2012 14:45:38 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 1 May 2012 14:20:00 -0300
perf stat: Fix case where guest/host monitoring is not supported by kernel
By default, perf stat sets exclude_guest = 1. But when you run perf on a kernel which does not support host/guest filtering, then you get an error saying the event in unsupported. This comes from the fact that when the perf_event_attr struct passed by the user is larger than the one known to the kernel there is safety check which ensures that all unknown bits are zero. But here, exclude_guest is 1 (part of the unknown bits) and thus the perf_event_open() syscall return EINVAL.
To my surprise, running perf record on the same kernel did not exhibit the problem. The reason is that perf record handles the problem by catching the error and retrying with guest/host excludes set to zero. For some reason, this was not done with perf stat. This patch fixes this problem.
--- tools/perf/builtin-stat.c | 33 +++++++++++++++++++++++++++++---- 1 files changed, 29 insertions(+), 4 deletions(-)
tools/perf/builtin-stat.c +29 -4
@@ -283,6 +283,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, {struct perf_event_attr *attr = &evsel->attr;struct xyarray *group_fd =NULL ; +bool exclude_guest_missing = false; +int ret;if (group && evsel != first) group_fd = first->fd;
@@ -293,16 +295,39 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, attr->inherit = !no_inherit; -if (system_wide) -return perf_evsel__open_per_cpu (evsel, evsel_list->cpus, +retry: +if (exclude_guest_missing) + evsel->attr.exclude_guest = evsel->attr.exclude_host =0 ; + +if (system_wide) { + ret =perf_evsel__open_per_cpu (evsel, evsel_list->cpus, group, group_fd); +if (ret) + goto check_ret; +return 0 ; + } +if (!target_pid && !target_tid && (!group || evsel == first)) { attr->disabled =1 ; attr->enable_on_exec =1 ; } -return perf_evsel__open_per_thread (evsel, evsel_list->threads, - group, group_fd); + ret =perf_evsel__open_per_thread (evsel, evsel_list->threads, + group, group_fd); +if (!ret) +return 0 ; +/* fall through */ +check_ret: +if (ret && errno ==EINVAL ) { +if (!exclude_guest_missing && + (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { +pr_debug ("Old kernel, cannot exclude " +"guest or host samples.\n" ); + exclude_guest_missing = true; + goto retry; + } + } +return ret; }/*