Commit e16c2ce7 authored by Yang Jihong's avatar Yang Jihong Committed by Arnaldo Carvalho de Melo

perf record: Fix continue profiling after draining the buffer

Commit da231338 ("perf record: Use an eventfd to wakeup when
done") uses eventfd() to solve a rare race where the setting and
checking of 'done' which add done_fd to pollfd.  When draining buffer,
revents of done_fd is 0 and evlist__filter_pollfd function returns a
non-zero value.  As a result, perf record does not stop profiling.

The following simple scenarios can trigger this condition:

  # sleep 10 &
  # perf record -p $!

After the sleep process exits, perf record should stop profiling and exit.
However, perf record keeps running.

If pollfd revents contains only POLLERR or POLLHUP, perf record
indicates that buffer is draining and need to stop profiling.  Use
fdarray_flag__nonfilterable() to set done eventfd to nonfilterable
objects, so that evlist__filter_pollfd() does not filter and check done
eventfd.

Fixes: da231338 ("perf record: Use an eventfd to wakeup when done")
Signed-off-by: default avatarYang Jihong <yangjihong1@huawei.com>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: default avatarJiri Olsa <jolsa@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: zhangjinhao2@huawei.com
Link: http://lore.kernel.org/lkml/20210205065001.23252-1-yangjihong1@huawei.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 52bcc603
...@@ -1664,7 +1664,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) ...@@ -1664,7 +1664,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
status = -1; status = -1;
goto out_delete_session; goto out_delete_session;
} }
err = evlist__add_pollfd(rec->evlist, done_fd); err = evlist__add_wakeup_eventfd(rec->evlist, done_fd);
if (err < 0) { if (err < 0) {
pr_err("Failed to add wakeup eventfd to poll list\n"); pr_err("Failed to add wakeup eventfd to poll list\n");
status = err; status = err;
......
...@@ -578,6 +578,14 @@ int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask) ...@@ -578,6 +578,14 @@ int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask)
return perf_evlist__filter_pollfd(&evlist->core, revents_and_mask); return perf_evlist__filter_pollfd(&evlist->core, revents_and_mask);
} }
#ifdef HAVE_EVENTFD_SUPPORT
int evlist__add_wakeup_eventfd(struct evlist *evlist, int fd)
{
return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN,
fdarray_flag__nonfilterable);
}
#endif
int evlist__poll(struct evlist *evlist, int timeout) int evlist__poll(struct evlist *evlist, int timeout)
{ {
return perf_evlist__poll(&evlist->core, timeout); return perf_evlist__poll(&evlist->core, timeout);
......
...@@ -144,6 +144,10 @@ struct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char ...@@ -144,6 +144,10 @@ struct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char
int evlist__add_pollfd(struct evlist *evlist, int fd); int evlist__add_pollfd(struct evlist *evlist, int fd);
int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask); int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask);
#ifdef HAVE_EVENTFD_SUPPORT
int evlist__add_wakeup_eventfd(struct evlist *evlist, int fd);
#endif
int evlist__poll(struct evlist *evlist, int timeout); int evlist__poll(struct evlist *evlist, int timeout);
struct evsel *evlist__id2evsel(struct evlist *evlist, u64 id); struct evsel *evlist__id2evsel(struct evlist *evlist, u64 id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment