浏览代码

perf trace: Add support for tracing workload given by command line

Now perf trace is able to trace specified workload by forking it like
perf record does.  And also finish the tracing if the workload quits or
gets SIGINT.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1349413336-26936-5-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Namhyung Kim 13 年之前
父节点
当前提交
f15eb531d3
共有 1 个文件被更改,包括 36 次插入7 次删除
  1. 36 7
      tools/perf/builtin-trace.c

+ 36 - 7
tools/perf/builtin-trace.c

@@ -52,6 +52,13 @@ struct trace {
 	struct perf_record_opts opts;
 	struct perf_record_opts opts;
 };
 };
 
 
+static bool done = false;
+
+static void sig_handler(int sig __maybe_unused)
+{
+	done = true;
+}
+
 static int trace__read_syscall_info(struct trace *trace, int id)
 static int trace__read_syscall_info(struct trace *trace, int id)
 {
 {
 	char tp_name[128];
 	char tp_name[128];
@@ -189,11 +196,12 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
 	return 0;
 	return 0;
 }
 }
 
 
-static int trace__run(struct trace *trace)
+static int trace__run(struct trace *trace, int argc, const char **argv)
 {
 {
 	struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
 	struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
 	struct perf_evsel *evsel;
 	struct perf_evsel *evsel;
 	int err = -1, i, nr_events = 0, before;
 	int err = -1, i, nr_events = 0, before;
+	const bool forks = argc > 0;
 
 
 	if (evlist == NULL) {
 	if (evlist == NULL) {
 		printf("Not enough memory to run!\n");
 		printf("Not enough memory to run!\n");
@@ -214,6 +222,17 @@ static int trace__run(struct trace *trace)
 
 
 	perf_evlist__config_attrs(evlist, &trace->opts);
 	perf_evlist__config_attrs(evlist, &trace->opts);
 
 
+	signal(SIGCHLD, sig_handler);
+	signal(SIGINT, sig_handler);
+
+	if (forks) {
+		err = perf_evlist__prepare_workload(evlist, &trace->opts, argv);
+		if (err < 0) {
+			printf("Couldn't run the workload!\n");
+			goto out_delete_evlist;
+		}
+	}
+
 	err = perf_evlist__open(evlist);
 	err = perf_evlist__open(evlist);
 	if (err < 0) {
 	if (err < 0) {
 		printf("Couldn't create the events: %s\n", strerror(errno));
 		printf("Couldn't create the events: %s\n", strerror(errno));
@@ -227,6 +246,10 @@ static int trace__run(struct trace *trace)
 	}
 	}
 
 
 	perf_evlist__enable(evlist);
 	perf_evlist__enable(evlist);
+
+	if (forks)
+		perf_evlist__start_workload(evlist);
+
 again:
 again:
 	before = nr_events;
 	before = nr_events;
 
 
@@ -272,8 +295,15 @@ again:
 		}
 		}
 	}
 	}
 
 
-	if (nr_events == before)
+	if (nr_events == before) {
+		if (done)
+			goto out_delete_evlist;
+
 		poll(evlist->pollfd, evlist->nr_fds, -1);
 		poll(evlist->pollfd, evlist->nr_fds, -1);
+	}
+
+	if (done)
+		perf_evlist__disable(evlist);
 
 
 	goto again;
 	goto again;
 
 
@@ -286,7 +316,8 @@ out:
 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 {
 	const char * const trace_usage[] = {
 	const char * const trace_usage[] = {
-		"perf trace [<options>]",
+		"perf trace [<options>] [<command>]",
+		"perf trace [<options>] -- <command> [<options>]",
 		NULL
 		NULL
 	};
 	};
 	struct trace trace = {
 	struct trace trace = {
@@ -326,8 +357,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 	char bf[BUFSIZ];
 	char bf[BUFSIZ];
 
 
 	argc = parse_options(argc, argv, trace_options, trace_usage, 0);
 	argc = parse_options(argc, argv, trace_options, trace_usage, 0);
-	if (argc)
-		usage_with_options(trace_usage, trace_options);
 
 
 	err = perf_target__validate(&trace.opts.target);
 	err = perf_target__validate(&trace.opts.target);
 	if (err) {
 	if (err) {
@@ -343,8 +372,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 		return err;
 		return err;
 	}
 	}
 
 
-	if (perf_target__none(&trace.opts.target))
+	if (!argc && perf_target__none(&trace.opts.target))
 		trace.opts.target.system_wide = true;
 		trace.opts.target.system_wide = true;
 
 
-	return trace__run(&trace);
+	return trace__run(&trace, argc, argv);
 }
 }