Adding kvm command support to see when all events
are down and forcing it to stop in that case.
Like following kvm stat live session will stop if the
monitored pid (1234) exits:
$ sudo perf kvm stat live -p 1234
Cc: Adrian Hunter <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jean Pihet <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
---
tools/perf/builtin-kvm.c | 111 +++++++++++++++++++++++----------------------
tools/perf/util/kvm-stat.h | 1 -
2 files changed, 57 insertions(+), 55 deletions(-)
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index ff404750d744..30057b6fb44b 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -808,10 +808,10 @@ static void sig_handler(int sig __maybe_unused)
static int perf_kvm__timerfd_create(struct perf_kvm_stat *kvm)
{
struct itimerspec new_value;
- int rc = -1;
+ int fd;
- kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
- if (kvm->timerfd < 0) {
+ fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
+ if (fd < 0) {
pr_err("timerfd_create failed\n");
goto out;
}
@@ -821,23 +821,24 @@ static int perf_kvm__timerfd_create(struct perf_kvm_stat
*kvm)
new_value.it_interval.tv_sec = kvm->display_time;
new_value.it_interval.tv_nsec = 0;
- if (timerfd_settime(kvm->timerfd, 0, &new_value, NULL) != 0) {
+ if (timerfd_settime(fd, 0, &new_value, NULL) != 0) {
pr_err("timerfd_settime failed: %d\n", errno);
- close(kvm->timerfd);
- goto out;
+ close(fd);
+ return -1;
}
- rc = 0;
out:
- return rc;
+ return fd;
}
-static int perf_kvm__handle_timerfd(struct perf_kvm_stat *kvm)
+static int perf_kvm__handle_timerfd(struct poller *p __maybe_unused,
+ struct poller_item *item)
{
+ struct perf_kvm_stat *kvm = item->data;
uint64_t c;
int rc;
- rc = read(kvm->timerfd, &c, sizeof(uint64_t));
+ rc = read(item->fd, &c, sizeof(uint64_t));
if (rc < 0) {
if (errno == EAGAIN)
return 0;
@@ -867,40 +868,59 @@ static int perf_kvm__handle_timerfd(struct perf_kvm_stat
*kvm)
return 0;
}
-static int fd_set_nonblock(int fd)
+static int data_error(struct poller *p, struct poller_item *item)
{
- long arg = 0;
+ pr_debug("got HUP/ERROR on fd %d\n", item->fd);
- arg = fcntl(fd, F_GETFL);
- if (arg < 0) {
- pr_err("Failed to get current flags for fd %d\n", fd);
- return -1;
- }
+ poller__del(p, item);
- if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) {
- pr_err("Failed to set non-block option on fd %d\n", fd);
- return -1;
+ /*
+ * Only 2 remains (stdin and timerfd), that mean we are
+ * out of events, time to leave.
+ */
+ if (p->n == 2) {
+ pr_debug("All events closed, shutting down.\n");
+ done = 1;
}
-
return 0;
}
-static int perf_kvm__handle_stdin(void)
+static
+int perf_kvm__handle_stdin(struct poller *p __maybe_unused,
+ struct poller_item *item __maybe_unused)
{
int c;
c = getc(stdin);
if (c == 'q')
- return 1;
+ done = 1;
return 0;
}
static int kvm_events_live_report(struct perf_kvm_stat *kvm)
{
- struct pollfd *pollfds = NULL;
- int nr_fds, nr_stdin, ret, err = -EINVAL;
+ int ret, err = -EINVAL;
struct termios save;
+ struct poller *poller = &kvm->evlist->poller;
+ struct poller_item input = {
+ .fd = fileno(stdin),
+ .ops = {
+ .data = perf_kvm__handle_stdin,
+ }
+ };
+ struct poller_item timer = {
+ .data = kvm,
+ .ops = {
+ .data = perf_kvm__handle_timerfd,
+ },
+ };
+ struct poller_ops poller_ops = {
+ .error = data_error,
+ .hup = data_error,
+ };
+
+ poller__set_ops(poller, &poller_ops);
/* live flag must be set first */
kvm->live = true;
@@ -921,31 +941,22 @@ static int kvm_events_live_report(struct perf_kvm_stat
*kvm)
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
- /* copy pollfds -- need to add timerfd and stdin */
- nr_fds = kvm->evlist->nr_fds;
- pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
- if (!pollfds) {
- err = -ENOMEM;
+ err = perf_evlist__set_poller(kvm->evlist);
+ if (err < 0)
goto out;
- }
- memcpy(pollfds, kvm->evlist->pollfd,
- sizeof(struct pollfd) * kvm->evlist->nr_fds);
- /* add timer fd */
- if (perf_kvm__timerfd_create(kvm) < 0) {
+ /* create timer fd */
+ timer.fd = perf_kvm__timerfd_create(kvm);
+ if (timer.fd < 0) {
err = -1;
goto out;
}
- pollfds[nr_fds].fd = kvm->timerfd;
- pollfds[nr_fds].events = POLLIN;
- nr_fds++;
+ err = -1;
- pollfds[nr_fds].fd = fileno(stdin);
- pollfds[nr_fds].events = POLLIN;
- nr_stdin = nr_fds;
- nr_fds++;
- if (fd_set_nonblock(fileno(stdin)) != 0)
+ /* add stdin and timer into poller */
+ if (poller__add(poller, &timer) ||
+ poller__add(poller, &input))
goto out;
/* everything is good - enable the events and process */
@@ -958,15 +969,8 @@ static int kvm_events_live_report(struct perf_kvm_stat
*kvm)
if (rc < 0)
break;
- err = perf_kvm__handle_timerfd(kvm);
- if (err)
- goto out;
-
- if (pollfds[nr_stdin].revents & POLLIN)
- done = perf_kvm__handle_stdin();
-
if (!rc && !done)
- err = poll(pollfds, nr_fds, 100);
+ err = poller__poll(poller, 100);
}
perf_evlist__disable(kvm->evlist);
@@ -977,11 +981,10 @@ static int kvm_events_live_report(struct perf_kvm_stat
*kvm)
}
out:
- if (kvm->timerfd >= 0)
- close(kvm->timerfd);
+ if (timer.fd >= 0)
+ close(timer.fd);
tcsetattr(0, TCSAFLUSH, &save);
- free(pollfds);
return err;
}
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
index 0b5a8cd2ee79..eb34bee83615 100644
--- a/tools/perf/util/kvm-stat.h
+++ b/tools/perf/util/kvm-stat.h
@@ -97,7 +97,6 @@ struct perf_kvm_stat {
struct rb_root result;
- int timerfd;
unsigned int display_time;
bool live;
};
--
1.8.3.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/