perf record: Use per-task-per-cpu events for inherited events
Create events with a pid and cpu contraint for inherited events
so that we get a stream per cpu, instead of all cpus contending
on a single stream.
Signed-off-by: Peter Zijlstra <a.p.zi...@chello.nl>
Cc: Arnaldo Carvalho de Melo <ac...@redhat.com>
Cc: fwei...@gmail.com
Cc: Paul Mackerras <pau...@samba.org>
LKML-Reference: <200912161659...@chello.nl>
Signed-off-by: Ingo Molnar <mi...@elte.hu>
---
tools/perf/builtin-record.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 9b7c6d8..63136d0 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -278,7 +278,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
attr->mmap = track;
attr->comm = track;
- attr->inherit = (cpu < 0) && inherit;
+ attr->inherit = inherit;
attr->disabled = 1;
try_again:
@@ -537,7 +537,7 @@ static int __cmd_record(int argc __used, const char **argv)
}
- if (!system_wide || profile_cpu != -1) {
+ if ((!system_wide && !inherit) || profile_cpu != -1) {
open_counters(profile_cpu, target_pid);
} else {
for (i = 0; i < nr_cpus; i++)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
perf record: Properly synchronize child creation
Remove that ugly usleep and provide proper serialization between
parent and child just like perf-stat does.
Signed-off-by: Peter Zijlstra <a.p.zi...@chello.nl>
Cc: Arnaldo Carvalho de Melo <ac...@redhat.com>
Cc: fwei...@gmail.com
Cc: Paul Mackerras <pau...@samba.org>
LKML-Reference: <200912161659...@chello.nl>
Signed-off-by: Ingo Molnar <mi...@elte.hu>
---
tools/perf/builtin-record.c | 109 ++++++++++++++++++++++++++++---------------
1 files changed, 71 insertions(+), 38 deletions(-)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 65301c5..9b7c6d8 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -402,7 +402,7 @@ static void atexit_header(void)
perf_header__write(&session->header, output, true);
}
-static int __cmd_record(int argc, const char **argv)
+static int __cmd_record(int argc __used, const char **argv)
{
int i, counter;
struct stat st;
@@ -410,6 +410,8 @@ static int __cmd_record(int argc, const char **argv)
int flags;
int err;
unsigned long waking = 0;
+ int child_ready_pipe[2], go_pipe[2];
+ char buf;
page_size = sysconf(_SC_PAGE_SIZE);
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -420,6 +422,11 @@ static int __cmd_record(int argc, const char **argv)
signal(SIGCHLD, sig_handler);
signal(SIGINT, sig_handler);
+ if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
+ perror("failed to create pipes");
+ exit(-1);
+ }
+
if (!stat(output_name, &st) && st.st_size) {
if (!force) {
if (!append_file) {
@@ -476,19 +483,65 @@ static int __cmd_record(int argc, const char **argv)
atexit(atexit_header);
- if (!system_wide) {
- pid = target_pid;
- if (pid == -1)
- pid = getpid();
+ if (target_pid == -1) {
+ pid = fork();
+ if (pid < 0) {
+ perror("failed to fork");
+ exit(-1);
+ }
- open_counters(profile_cpu, pid);
- } else {
- if (profile_cpu != -1) {
- open_counters(profile_cpu, target_pid);
- } else {
- for (i = 0; i < nr_cpus; i++)
- open_counters(i, target_pid);
+ if (!pid) {
+ close(child_ready_pipe[0]);
+ close(go_pipe[1]);
+ fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
+
+ /*
+ * Do a dummy execvp to get the PLT entry resolved,
+ * so we avoid the resolver overhead on the real
+ * execvp call.
+ */
+ execvp("", (char **)argv);
+
+ /*
+ * Tell the parent we're ready to go
+ */
+ close(child_ready_pipe[1]);
+
+ /*
+ * Wait until the parent tells us to go.
+ */
+ if (read(go_pipe[0], &buf, 1) == -1)
+ perror("unable to read pipe");
+
+ execvp(argv[0], (char **)argv);
+
+ perror(argv[0]);
+ exit(-1);
}
+
+ child_pid = pid;
+
+ if (!system_wide)
+ target_pid = pid;
+
+ close(child_ready_pipe[1]);
+ close(go_pipe[0]);
+ /*
+ * wait for child to settle
+ */
+ if (read(child_ready_pipe[0], &buf, 1) == -1) {
+ perror("unable to read pipe");
+ exit(-1);
+ }
+ close(child_ready_pipe[0]);
+ }
+
+
+ if (!system_wide || profile_cpu != -1) {
+ open_counters(profile_cpu, target_pid);
+ } else {
+ for (i = 0; i < nr_cpus; i++)
+ open_counters(i, target_pid);
}
if (file_new) {
@@ -503,31 +556,6 @@ static int __cmd_record(int argc, const char **argv)
else
event__synthesize_threads(process_synthesized_event, session);
- if (target_pid == -1 && argc) {
- pid = fork();
- if (pid < 0)
- die("failed to fork");
-
- if (!pid) {
- if (execvp(argv[0], (char **)argv)) {
- perror(argv[0]);
- exit(-1);
- }
- } else {
- /*
- * Wait a bit for the execv'ed child to appear
- * and be updated in /proc
- * FIXME: Do you know a less heuristical solution?
- */
- usleep(1000);
- event__synthesize_thread(pid,
- process_synthesized_event,
- session);
- }
-
- child_pid = pid;
- }
-
if (realtime_prio) {
struct sched_param param;
@@ -538,6 +566,11 @@ static int __cmd_record(int argc, const char **argv)
}
}
+ /*
+ * Let the child rip
+ */
+ close(go_pipe[1]);
+
for (;;) {
int hits = samples;
@@ -634,7 +667,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
argc = parse_options(argc, argv, options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
- if (!argc && target_pid == -1 && !system_wide)
+ if (!argc && target_pid == -1 && (!system_wide || profile_cpu == -1))
usage_with_options(record_usage, options);
symbol__init();
perf events: Allow per-task-per-cpu counters
In order to allow for per-task-per-cpu counters, useful for
scalability when profiling task hierarchies, we allow installing
events with event->cpu != -1 in task contexts.
__perf_event_sched_in() already skips events where ->cpu
mis-matches the current cpu, fix up __perf_install_in_context()
and __perf_event_enable() to also respect this filter.
This does lead to vary hard to interpret enabled/running times
for such counters, but I don't see a simple solution for that.
Signed-off-by: Peter Zijlstra <a.p.zi...@chello.nl>
Cc: Arnaldo Carvalho de Melo <ac...@redhat.com>
Cc: fwei...@gmail.com
Cc: Paul Mackerras <pau...@samba.org>
LKML-Reference: <200912161659...@chello.nl>
Signed-off-by: Ingo Molnar <mi...@elte.hu>
---
kernel/perf_event.c | 11 +++++++----
1 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 0dd8e5d..2e0aaa3 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -782,6 +782,9 @@ static void __perf_install_in_context(void *info)
add_event_to_ctx(event, ctx);
+ if (event->cpu != -1 && event->cpu != smp_processor_id())
+ goto unlock;
+
/*
* Don't put the event on if it is disabled or if
* it is in a group and the group isn't on.
@@ -925,6 +928,9 @@ static void __perf_event_enable(void *info)
goto unlock;
__perf_event_mark_enabled(event, ctx);
+ if (event->cpu != -1 && event->cpu != smp_processor_id())
+ goto unlock;
+
/*
* If the event is in a group and isn't the group leader,
* then don't put it on unless the group is on.
@@ -1595,10 +1601,7 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
unsigned long flags;
int err;
- /*
- * If cpu is not a wildcard then this is a percpu event:
- */
- if (cpu != -1) {
+ if (pid == -1 && cpu != -1) {
/* Must be root to operate on a CPU event: */
if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
return ERR_PTR(-EACCES);