perf record: Fix continue profiling after draining the buffer
authorYang Jihong <yangjihong1@huawei.com>
Fri, 5 Feb 2021 06:50:01 +0000 (14:50 +0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 18 Feb 2021 16:30:09 +0000 (13:30 -0300)
Commit da231338ec9c0987 ("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: da231338ec9c0987 ("perf record: Use an eventfd to wakeup when done")
Signed-off-by: Yang Jihong <yangjihong1@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Jiri 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.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-record.c
tools/perf/util/evlist.c
tools/perf/util/evlist.h

index 8a0127d4fb52193570df24310dc1476ed8f98f48..29abc04007eb0d2deb58462f77fe7ff7d1684104 100644 (file)
@@ -1664,7 +1664,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                status = -1;
                goto out_delete_session;
        }
-       err = evlist__add_pollfd(rec->evlist, done_fd);
+       err = evlist__add_wakeup_eventfd(rec->evlist, done_fd);
        if (err < 0) {
                pr_err("Failed to add wakeup eventfd to poll list\n");
                status = err;
index 5983a9f1393055857262297fc794126c2aba69bd..5121b4db66fe5d58abc48aab2b2a025240a8eb51 100644 (file)
@@ -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);
 }
 
+#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)
 {
        return perf_evlist__poll(&evlist->core, timeout);
index 7243e94da398a405f4c40dca1a63cd7245857116..b695ffaae519a5d09d184325c33a4c37639f4e0c 100644 (file)
@@ -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__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);
 
 struct evsel *evlist__id2evsel(struct evlist *evlist, u64 id);