diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 18:14:31 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 18:14:31 -0800 |
commit | 090f8ccba37034cec5a5972a70abeaae7eb0222b (patch) | |
tree | 0b7cf8a4bb94601816399acfb336835fbf309a2a /tools/perf/builtin-inject.c | |
parent | aefb058b0c27dafb15072406fbfd92d2ac2c8790 (diff) | |
parent | cc1b39dbf9f55a438e8a21a694394c20e6a17129 (diff) | |
download | linux-stable-090f8ccba37034cec5a5972a70abeaae7eb0222b.tar.gz linux-stable-090f8ccba37034cec5a5972a70abeaae7eb0222b.tar.bz2 linux-stable-090f8ccba37034cec5a5972a70abeaae7eb0222b.zip |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"Lots of activity:
211 files changed, 8328 insertions(+), 4116 deletions(-)
most of it on the tooling side.
Main changes:
* ftrace enhancements and fixes from Steve Rostedt.
* uprobes fixes, cleanups and preparation for the ARM port from Oleg
Nesterov.
* UAPI fixes, from David Howels - prepares the arch/x86 UAPI
transition
* Separate perf tests into multiple objects, one per test, from Jiri
Olsa.
* Make hardware event translations available in sysfs, from Jiri
Olsa.
* Fixes to /proc/pid/maps parsing, preparatory to supporting data
maps, from Namhyung Kim
* Implement ui_progress for GTK, from Namhyung Kim
* Add framework for automated perf_event_attr tests, where tools with
different command line options will be run from a 'perf test', via
python glue, and the perf syscall will be intercepted to verify
that the perf_event_attr fields set by the tool are those expected,
from Jiri Olsa
* Add a 'link' method for hists, so that we can have the leader with
buckets for all the entries in all the hists. This new method is
now used in the default 'diff' output, making the sum of the
'baseline' column be 100%, eliminating blind spots.
* libtraceevent fixes for compiler warnings trying to make perf it
build on some distros, like fedora 14, 32-bit, some of the warnings
really pointed to real bugs.
* Add a browser for 'perf script' and make it available from the
report and annotate browsers. It does filtering to find the
scripts that handle events found in the perf.data file used. From
Feng Tang
* perf inject changes to allow showing where a task sleeps, from
Andrew Vagin.
* Makefile improvements from Namhyung Kim.
* Add --pre and --post command hooks in 'stat', from Peter Zijlstra.
* Don't stop synthesizing threads when one vanishes, this is for the
existing threads when we start a tool like trace.
* Use sched:sched_stat_runtime to provide a thread summary, this
produces the same output as the 'trace summary' subcommand of
tglx's original "trace" tool.
* Support interrupted syscalls in 'trace'
* Add an event duration column and filter in 'trace'.
* There are references to the man pages in some tools, so try to
build Documentation when installing, warning the user if that is
not possible, from Borislav Petkov.
* Give user better message if precise is not supported, from David
Ahern.
* Try to find cross-built objdump path by using the session
environment information in the perf.data file header, from Irina
Tirdea, original patch and idea by Namhyung Kim.
* Diplays more output on features check for make V=1, so that one can
figure out what is happening by looking at gcc output, etc. From
Jiri Olsa.
* Add on_exit implementation for systems without one, e.g. Android,
from Bernhard Rosenkraenzer.
* Only process events for vcpus of interest, helps handling large
number of events, from David Ahern.
* Cross compilation fixes for Android, from Irina Tirdea.
* Add documentation on compiling for Android, from Irina Tirdea.
* perf diff improvements from Jiri Olsa.
* Target (task/user/cpu/syswide) handling improvements, from Namhyung
Kim.
* Add support in 'trace' for tracing workload given by command line,
from Namhyung Kim.
* ... and much more."
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (194 commits)
uprobes: Use percpu_rw_semaphore to fix register/unregister vs dup_mmap() race
perf evsel: Introduce is_group_member method
perf powerpc: Use uapi/unistd.h to fix build error
tools: Pass the target in descend
tools: Honour the O= flag when tool build called from a higher Makefile
tools: Define a Makefile function to do subdir processing
perf ui: Always compile browser setup code
perf ui: Add ui_progress__finish()
perf ui gtk: Implement ui_progress functions
perf ui: Introduce generic ui_progress helper
perf ui tui: Move progress.c under ui/tui directory
perf tools: Add basic event modifier sanity check
perf tools: Omit group members from perf_evlist__disable/enable
perf tools: Ensure single disable call per event in record comand
perf tools: Fix 'disabled' attribute config for record command
perf tools: Fix attributes for '{}' defined event groups
perf tools: Use sscanf for parsing /proc/pid/maps
perf tools: Add gtk.<command> config option for launching GTK browser
perf tools: Fix compile error on NO_NEWT=1 build
perf hists: Initialize all of he->stat with zeroes
...
Diffstat (limited to 'tools/perf/builtin-inject.c')
-rw-r--r-- | tools/perf/builtin-inject.c | 195 |
1 files changed, 184 insertions, 11 deletions
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 4688bea95c12..84ad6abe4258 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -8,33 +8,53 @@ #include "builtin.h" #include "perf.h" +#include "util/color.h" +#include "util/evlist.h" +#include "util/evsel.h" #include "util/session.h" #include "util/tool.h" #include "util/debug.h" +#include "util/build-id.h" #include "util/parse-options.h" +#include <linux/list.h> + struct perf_inject { struct perf_tool tool; bool build_ids; + bool sched_stat; + const char *input_name; + int pipe_output, + output; + u64 bytes_written; + struct list_head samples; +}; + +struct event_entry { + struct list_head node; + u32 tid; + union perf_event event[0]; }; -static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused, +static int perf_event__repipe_synth(struct perf_tool *tool, union perf_event *event, struct machine *machine __maybe_unused) { + struct perf_inject *inject = container_of(tool, struct perf_inject, tool); uint32_t size; void *buf = event; size = event->header.size; while (size) { - int ret = write(STDOUT_FILENO, buf, size); + int ret = write(inject->output, buf, size); if (ret < 0) return -errno; size -= ret; buf += ret; + inject->bytes_written += ret; } return 0; @@ -80,12 +100,25 @@ static int perf_event__repipe(struct perf_tool *tool, return perf_event__repipe_synth(tool, event, machine); } +typedef int (*inject_handler)(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine); + static int perf_event__repipe_sample(struct perf_tool *tool, union perf_event *event, - struct perf_sample *sample __maybe_unused, - struct perf_evsel *evsel __maybe_unused, - struct machine *machine) + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine) { + if (evsel->handler.func) { + inject_handler f = evsel->handler.func; + return f(tool, event, sample, evsel, machine); + } + + build_id__mark_dso_hit(tool, event, sample, evsel, machine); + return perf_event__repipe_synth(tool, event, machine); } @@ -102,14 +135,14 @@ static int perf_event__repipe_mmap(struct perf_tool *tool, return err; } -static int perf_event__repipe_task(struct perf_tool *tool, +static int perf_event__repipe_fork(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine) { int err; - err = perf_event__process_task(tool, event, sample, machine); + err = perf_event__process_fork(tool, event, sample, machine); perf_event__repipe(tool, event, sample, machine); return err; @@ -210,6 +243,80 @@ repipe: return 0; } +static int perf_inject__sched_process_exit(struct perf_tool *tool, + union perf_event *event __maybe_unused, + struct perf_sample *sample, + struct perf_evsel *evsel __maybe_unused, + struct machine *machine __maybe_unused) +{ + struct perf_inject *inject = container_of(tool, struct perf_inject, tool); + struct event_entry *ent; + + list_for_each_entry(ent, &inject->samples, node) { + if (sample->tid == ent->tid) { + list_del_init(&ent->node); + free(ent); + break; + } + } + + return 0; +} + +static int perf_inject__sched_switch(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine) +{ + struct perf_inject *inject = container_of(tool, struct perf_inject, tool); + struct event_entry *ent; + + perf_inject__sched_process_exit(tool, event, sample, evsel, machine); + + ent = malloc(event->header.size + sizeof(struct event_entry)); + if (ent == NULL) { + color_fprintf(stderr, PERF_COLOR_RED, + "Not enough memory to process sched switch event!"); + return -1; + } + + ent->tid = sample->tid; + memcpy(&ent->event, event, event->header.size); + list_add(&ent->node, &inject->samples); + return 0; +} + +static int perf_inject__sched_stat(struct perf_tool *tool, + union perf_event *event __maybe_unused, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine) +{ + struct event_entry *ent; + union perf_event *event_sw; + struct perf_sample sample_sw; + struct perf_inject *inject = container_of(tool, struct perf_inject, tool); + u32 pid = perf_evsel__intval(evsel, sample, "pid"); + + list_for_each_entry(ent, &inject->samples, node) { + if (pid == ent->tid) + goto found; + } + + return 0; +found: + event_sw = &ent->event[0]; + perf_evsel__parse_sample(evsel, event_sw, &sample_sw); + + sample_sw.period = sample->period; + sample_sw.time = sample->time; + perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, + &sample_sw, false); + build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); + return perf_event__repipe(tool, event_sw, &sample_sw, machine); +} + extern volatile int session_done; static void sig_handler(int sig __maybe_unused) @@ -217,6 +324,21 @@ static void sig_handler(int sig __maybe_unused) session_done = 1; } +static int perf_evsel__check_stype(struct perf_evsel *evsel, + u64 sample_type, const char *sample_msg) +{ + struct perf_event_attr *attr = &evsel->attr; + const char *name = perf_evsel__name(evsel); + + if (!(attr->sample_type & sample_type)) { + pr_err("Samples for %s event do not have %s attribute set.", + name, sample_msg); + return -EINVAL; + } + + return 0; +} + static int __cmd_inject(struct perf_inject *inject) { struct perf_session *session; @@ -224,19 +346,48 @@ static int __cmd_inject(struct perf_inject *inject) signal(SIGINT, sig_handler); - if (inject->build_ids) { - inject->tool.sample = perf_event__inject_buildid; + if (inject->build_ids || inject->sched_stat) { inject->tool.mmap = perf_event__repipe_mmap; - inject->tool.fork = perf_event__repipe_task; + inject->tool.fork = perf_event__repipe_fork; inject->tool.tracing_data = perf_event__repipe_tracing_data; } - session = perf_session__new("-", O_RDONLY, false, true, &inject->tool); + session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool); if (session == NULL) return -ENOMEM; + if (inject->build_ids) { + inject->tool.sample = perf_event__inject_buildid; + } else if (inject->sched_stat) { + struct perf_evsel *evsel; + + inject->tool.ordered_samples = true; + + list_for_each_entry(evsel, &session->evlist->entries, node) { + const char *name = perf_evsel__name(evsel); + + if (!strcmp(name, "sched:sched_switch")) { + if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID")) + return -EINVAL; + + evsel->handler.func = perf_inject__sched_switch; + } else if (!strcmp(name, "sched:sched_process_exit")) + evsel->handler.func = perf_inject__sched_process_exit; + else if (!strncmp(name, "sched:sched_stat_", 17)) + evsel->handler.func = perf_inject__sched_stat; + } + } + + if (!inject->pipe_output) + lseek(inject->output, session->header.data_offset, SEEK_SET); + ret = perf_session__process_events(session, &inject->tool); + if (!inject->pipe_output) { + session->header.data_size = inject->bytes_written; + perf_session__write_header(session, session->evlist, inject->output, true); + } + perf_session__delete(session); return ret; @@ -260,10 +411,20 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .tracing_data = perf_event__repipe_tracing_data_synth, .build_id = perf_event__repipe_op2_synth, }, + .input_name = "-", + .samples = LIST_HEAD_INIT(inject.samples), }; + const char *output_name = "-"; const struct option options[] = { OPT_BOOLEAN('b', "build-ids", &inject.build_ids, "Inject build-ids into the output stream"), + OPT_STRING('i', "input", &inject.input_name, "file", + "input file name"), + OPT_STRING('o', "output", &output_name, "file", + "output file name"), + OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, + "Merge sched-stat and sched-switch for getting events " + "where and how long tasks slept"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show build ids, etc)"), OPT_END() @@ -281,6 +442,18 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) if (argc) usage_with_options(inject_usage, options); + if (!strcmp(output_name, "-")) { + inject.pipe_output = 1; + inject.output = STDOUT_FILENO; + } else { + inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC, + S_IRUSR | S_IWUSR); + if (inject.output < 0) { + perror("failed to create output file"); + return -1; + } + } + if (symbol__init() < 0) return -1; |