[RFC PATCH 1/2] perf stat: wait on unix domain socket before calling sys_perf_event_open()

From: Hitoshi Mitake
Date: Tue Dec 14 2010 - 00:47:24 EST


This patch adds new option "--wait-on" option to perf stat.

Current perf stat can monitor
1) lifetime of program specified as command line argument, or
2) lifetime of perf stat. Target process is specified with pid,
and end of monitoring is triggered with signal.
1) is too coarse grain. And 2) is difficult to distinguish the range to monitor.

This patch makes it possible to wait before sys_perf_event_open().
Monitored process can wake up perf stat via unix domain socket,
and terminate monitoring via signal.

New option --wait-on requires the string as the path of unix domain socket.
perf stat read the pid from the socket for target_pid. Monitored program
should write the pid of itself to it.
perf stat replies the pid of itself to monitored program. The monitored program
should send signal SIGINT to perf stat with this pid. Then monitoring is terminated.

I feel current implementation is really dirty. As Arnaldo and Peter suggested,
more unified way like interception or self monitoring library is ideal.
This is the proof of concept version. I'd like to hear your comments.

Cc: Miao Xie <miaox@xxxxxxxxxxxxxx>
Cc: Ma Ling <ling.ma@xxxxxxxxx>
Cc: Zhao Yakui <yakui.zhao@xxxxxxxxx>
Cc: Peter Zijlstra <a.p.zijlstra@xxxxxxxxx>
Cc: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
Cc: Paul Mackerras <paulus@xxxxxxxxx>
Cc: Frederic Weisbecker <fweisbec@xxxxxxxxx>
Cc: Steven Rostedt <rostedt@xxxxxxxxxxx>
Cc: Andi Kleen <andi@xxxxxxxxxxxxxx>
Signed-off-by: Hitoshi Mitake <mitake@xxxxxxxxxxxxxxxxxxxxx>
---
tools/perf/builtin-stat.c | 63 ++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 7ff746d..4cc10a1 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -51,6 +51,8 @@
#include <sys/prctl.h>
#include <math.h>
#include <locale.h>
+#include <sys/socket.h>
+#include <sys/un.h>

#define DEFAULT_SEPARATOR " "

@@ -90,11 +92,15 @@ static const char *cpu_list;
static const char *csv_sep = NULL;
static bool csv_output = false;

+static const char *wait_path;

static int *fd[MAX_NR_CPUS][MAX_COUNTERS];

static int event_scaled[MAX_COUNTERS];

+static int wait_fd = -1;
+static struct sockaddr_un wait_addr;
+
static struct {
u64 val;
u64 ena;
@@ -342,7 +348,7 @@ static int run_perf_stat(int argc __used, const char **argv)
unsigned long long t0, t1;
int status = 0;
int counter, ncreated = 0;
- int child_ready_pipe[2], go_pipe[2];
+ int child_ready_pipe[2], go_pipe[2], accepted_fd;
bool perm_err = false;
const bool forks = (argc > 0);
char buf;
@@ -401,6 +407,43 @@ static int run_perf_stat(int argc __used, const char **argv)
close(child_ready_pipe[0]);
}

+ if (wait_path) {
+ int sock_err;
+ struct sockaddr accepted_addr;
+ socklen_t accepted_len = sizeof(accepted_addr);
+
+ wait_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (wait_fd < 0)
+ die("unable to create socket for sync\n");
+
+ memset(&wait_addr, 0, sizeof(wait_addr));
+ wait_addr.sun_family = PF_UNIX;
+ strncpy(wait_addr.sun_path, wait_path,
+ sizeof(wait_addr.sun_path));
+
+ sock_err = bind(wait_fd, (struct sockaddr *)&wait_addr,
+ sizeof(wait_addr));
+ if (sock_err < 0)
+ die("bind() failed\n");
+
+ sock_err = listen(wait_fd, 1);
+ if (sock_err < 0)
+ die("listen() failed\n");
+
+ accepted_fd = accept(wait_fd, &accepted_addr, &accepted_len);
+ if (accepted_fd < 0)
+ die("accept() failed\n");
+
+ if (read(accepted_fd, &target_pid, sizeof(target_pid))
+ != sizeof(target_pid))
+ die("read() pid from socket failed\n");
+
+ target_tid = target_pid;
+ thread_num = find_all_tid(target_pid, &all_tids);
+ if (thread_num <= 0)
+ die("couldn't find threads of %d\n", target_pid);
+ }
+
for (counter = 0; counter < nr_counters; counter++)
ncreated += create_perf_stat_counter(counter, &perm_err);

@@ -425,6 +468,14 @@ static int run_perf_stat(int argc __used, const char **argv)
close(go_pipe[1]);
wait(&status);
} else {
+ if (wait_path) {
+ pid_t myself = getpid();
+ if (write(accepted_fd, &myself, sizeof(myself))
+ != sizeof(myself))
+ die("write() my pid failed\n");
+ close(accepted_fd);
+ }
+
while(!done) sleep(1);
}

@@ -670,6 +721,9 @@ static void sig_atexit(void)
if (signr == -1)
return;

+ if (wait_path)
+ unlink(wait_path);
+
signal(signr, SIG_DFL);
kill(getpid(), signr);
}
@@ -715,6 +769,8 @@ static const struct option options[] = {
"disable CPU count aggregation"),
OPT_STRING('x', "field-separator", &csv_sep, "separator",
"print counts with custom separator"),
+ OPT_STRING('w', "wait-on", &wait_path, "path",
+ "path of unix domain socket to wait on"),
OPT_END()
};

@@ -746,7 +802,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
} else if (big_num_opt == 0) /* User passed --no-big-num */
big_num = false;

- if (!argc && target_pid == -1 && target_tid == -1)
+ if (!argc && target_pid == -1 && target_tid == -1 && !wait_path)
usage_with_options(stat_usage, options);
if (run_count <= 0)
usage_with_options(stat_usage, options);
@@ -769,7 +825,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
if (nr_cpus < 1)
usage_with_options(stat_usage, options);

- if (target_pid != -1) {
+ /* if wait_path is specified, we read pid to monitor from it later */
+ if (target_pid != -1 && !wait_path) {
target_tid = target_pid;
thread_num = find_all_tid(target_pid, &all_tids);
if (thread_num <= 0) {
--
1.7.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/