aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-inject.c
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2015-11-30 04:02:21 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-02-05 07:46:45 -0500
commit9b07e27f88b9cd785cdb23f9a2231c12521dda94 (patch)
tree5634fa81d6d34df7ef2378f0c37f76bff3ec6a5e /tools/perf/builtin-inject.c
parent921f3fadbc48c7c3799b415b895297cd476cf7f1 (diff)
perf inject: Add jitdump mmap injection support
This patch adds a --jit/-j option to perf inject. This options injects MMAP records into the perf.data file to cover the jitted code mmaps. It also emits ELF images for each function in the jidump file. Those images are created where the jitdump file is. The MMAP records point to that location as well. Typical flow: $ perf record -k mono -- java -agentpath:libpjvmti.so java_class $ perf inject --jit -i perf.data -o perf.data.jitted $ perf report -i perf.data.jitted Note that jitdump.h support is not limited to Java, it works with any jitted environment modified to emit the jitdump file format, include those where code can be jitted multiple times and moved around. The jitdump.h format is adapted from the Oprofile project. The genelf.c (ELF binary generation) depends on MD5 hash encoding for the buildid. To enable this, libssl-dev must be installed. If not, then genelf.c defaults to using urandom to generate the buildid, which is not ideal. The Makefile auto-detects the presence on libssl-dev. This version mmaps the jitdump file to create a marker MMAP record in the perf.data file. The marker is used to detect jitdump and cause perf inject to inject the jitted mmaps and generate ELF images for jitted functions. In V8, the following fixes and changes were made among other things: - the jidump header format include a new flags field to be used to carry information about the configuration of the runtime agent. Contributed by: Adrian Hunter <adrian.hunter@intel.com> - Fix mmap pgoff: MMAP event pgoff must be the offset within the ELF file at which the code resides. Contributed by: Adrian Hunter <adrian.hunter@intel.com> - Fix ELF virtual addresses: perf tools expect the ELF virtual addresses of dynamic objects to match the file offset. Contributed by: Adrian Hunter <adrian.hunter@intel.com> - JIT MMAP injection does not obey finished_round semantics. JIT MMAP injection injects all MMAP events in one go, so it does not obey finished_round semantics, so drop the finished_round events from the output perf.data file. Contributed by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Stephane Eranian <eranian@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Carl Love <cel@us.ibm.com> Cc: David Ahern <dsahern@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: John McCutchan <johnmccutchan@google.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Pawel Moll <pawel.moll@arm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Sonny Rao <sonnyrao@chromium.org> Cc: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> Link: http://lkml.kernel.org/r/1448874143-7269-3-git-send-email-eranian@google.com [ Moved inject.build_ids ordering bits to a separate patch, fixed the NO_LIBELF=1 build ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-inject.c')
-rw-r--r--tools/perf/builtin-inject.c98
1 files changed, 95 insertions, 3 deletions
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 6567baedd92a..b38445f08c2f 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -17,6 +17,7 @@
17#include "util/build-id.h" 17#include "util/build-id.h"
18#include "util/data.h" 18#include "util/data.h"
19#include "util/auxtrace.h" 19#include "util/auxtrace.h"
20#include "util/jit.h"
20 21
21#include <subcmd/parse-options.h> 22#include <subcmd/parse-options.h>
22 23
@@ -29,6 +30,7 @@ struct perf_inject {
29 bool sched_stat; 30 bool sched_stat;
30 bool have_auxtrace; 31 bool have_auxtrace;
31 bool strip; 32 bool strip;
33 bool jit_mode;
32 const char *input_name; 34 const char *input_name;
33 struct perf_data_file output; 35 struct perf_data_file output;
34 u64 bytes_written; 36 u64 bytes_written;
@@ -71,6 +73,15 @@ static int perf_event__repipe_oe_synth(struct perf_tool *tool,
71 return perf_event__repipe_synth(tool, event); 73 return perf_event__repipe_synth(tool, event);
72} 74}
73 75
76#ifdef HAVE_LIBELF_SUPPORT
77static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
78 union perf_event *event __maybe_unused,
79 struct ordered_events *oe __maybe_unused)
80{
81 return 0;
82}
83#endif
84
74static int perf_event__repipe_op2_synth(struct perf_tool *tool, 85static int perf_event__repipe_op2_synth(struct perf_tool *tool,
75 union perf_event *event, 86 union perf_event *event,
76 struct perf_session *session 87 struct perf_session *session
@@ -234,6 +245,27 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
234 return err; 245 return err;
235} 246}
236 247
248#ifdef HAVE_LIBELF_SUPPORT
249static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
250 union perf_event *event,
251 struct perf_sample *sample,
252 struct machine *machine)
253{
254 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
255 u64 n = 0;
256
257 /*
258 * if jit marker, then inject jit mmaps and generate ELF images
259 */
260 if (!jit_process(inject->session, &inject->output, machine,
261 event->mmap.filename, sample->pid, &n)) {
262 inject->bytes_written += n;
263 return 0;
264 }
265 return perf_event__repipe_mmap(tool, event, sample, machine);
266}
267#endif
268
237static int perf_event__repipe_mmap2(struct perf_tool *tool, 269static int perf_event__repipe_mmap2(struct perf_tool *tool,
238 union perf_event *event, 270 union perf_event *event,
239 struct perf_sample *sample, 271 struct perf_sample *sample,
@@ -247,6 +279,27 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
247 return err; 279 return err;
248} 280}
249 281
282#ifdef HAVE_LIBELF_SUPPORT
283static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
284 union perf_event *event,
285 struct perf_sample *sample,
286 struct machine *machine)
287{
288 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
289 u64 n = 0;
290
291 /*
292 * if jit marker, then inject jit mmaps and generate ELF images
293 */
294 if (!jit_process(inject->session, &inject->output, machine,
295 event->mmap2.filename, sample->pid, &n)) {
296 inject->bytes_written += n;
297 return 0;
298 }
299 return perf_event__repipe_mmap2(tool, event, sample, machine);
300}
301#endif
302
250static int perf_event__repipe_fork(struct perf_tool *tool, 303static int perf_event__repipe_fork(struct perf_tool *tool,
251 union perf_event *event, 304 union perf_event *event,
252 struct perf_sample *sample, 305 struct perf_sample *sample,
@@ -664,6 +717,23 @@ static int __cmd_inject(struct perf_inject *inject)
664 return ret; 717 return ret;
665} 718}
666 719
720#ifdef HAVE_LIBELF_SUPPORT
721static int
722jit_validate_events(struct perf_session *session)
723{
724 struct perf_evsel *evsel;
725
726 /*
727 * check that all events use CLOCK_MONOTONIC
728 */
729 evlist__for_each(session->evlist, evsel) {
730 if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
731 return -1;
732 }
733 return 0;
734}
735#endif
736
667int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) 737int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
668{ 738{
669 struct perf_inject inject = { 739 struct perf_inject inject = {
@@ -703,7 +773,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
703 }; 773 };
704 int ret; 774 int ret;
705 775
706 const struct option options[] = { 776 struct option options[] = {
707 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 777 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
708 "Inject build-ids into the output stream"), 778 "Inject build-ids into the output stream"),
709 OPT_STRING('i', "input", &inject.input_name, "file", 779 OPT_STRING('i', "input", &inject.input_name, "file",
@@ -713,6 +783,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
713 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 783 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
714 "Merge sched-stat and sched-switch for getting events " 784 "Merge sched-stat and sched-switch for getting events "
715 "where and how long tasks slept"), 785 "where and how long tasks slept"),
786 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
716 OPT_INCR('v', "verbose", &verbose, 787 OPT_INCR('v', "verbose", &verbose,
717 "be more verbose (show build ids, etc)"), 788 "be more verbose (show build ids, etc)"),
718 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 789 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
@@ -729,7 +800,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
729 "perf inject [<options>]", 800 "perf inject [<options>]",
730 NULL 801 NULL
731 }; 802 };
732 803#ifndef HAVE_LIBELF_SUPPORT
804 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
805#endif
733 argc = parse_options(argc, argv, options, inject_usage, 0); 806 argc = parse_options(argc, argv, options, inject_usage, 0);
734 807
735 /* 808 /*
@@ -765,7 +838,26 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
765 inject.tool.ordered_events = true; 838 inject.tool.ordered_events = true;
766 inject.tool.ordering_requires_timestamps = true; 839 inject.tool.ordering_requires_timestamps = true;
767 } 840 }
768 841#ifdef HAVE_LIBELF_SUPPORT
842 if (inject.jit_mode) {
843 /*
844 * validate event is using the correct clockid
845 */
846 if (jit_validate_events(inject.session)) {
847 fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
848 return -1;
849 }
850 inject.tool.mmap2 = perf_event__jit_repipe_mmap2;
851 inject.tool.mmap = perf_event__jit_repipe_mmap;
852 inject.tool.ordered_events = true;
853 inject.tool.ordering_requires_timestamps = true;
854 /*
855 * JIT MMAP injection injects all MMAP events in one go, so it
856 * does not obey finished_round semantics.
857 */
858 inject.tool.finished_round = perf_event__drop_oe;
859 }
860#endif
769 ret = symbol__init(&inject.session->header.env); 861 ret = symbol__init(&inject.session->header.env);
770 if (ret < 0) 862 if (ret < 0)
771 goto out_delete; 863 goto out_delete;