Skip to content

Commit

Permalink
perf inject: Add jitdump mmap injection support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stephane Eranian authored and acmel committed Feb 5, 2016
1 parent 921f3fa commit 9b07e27
Show file tree
Hide file tree
Showing 8 changed files with 1,418 additions and 3 deletions.
7 changes: 7 additions & 0 deletions tools/perf/Documentation/perf-inject.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ include::itrace.txt[]
--strip::
Use with --itrace to strip out non-synthesized events.

-j::
--jit::
Process jitdump files by injecting the mmap records corresponding to jitted
functions. This option also generates the ELF images for each jitted function
found in the jitdumps files captured in the input perf.data file. Use this option
if you are monitoring environment using JIT runtimes, such as Java, DART or V8.

SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
98 changes: 95 additions & 3 deletions tools/perf/builtin-inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "util/build-id.h"
#include "util/data.h"
#include "util/auxtrace.h"
#include "util/jit.h"

#include <subcmd/parse-options.h>

Expand All @@ -29,6 +30,7 @@ struct perf_inject {
bool sched_stat;
bool have_auxtrace;
bool strip;
bool jit_mode;
const char *input_name;
struct perf_data_file output;
u64 bytes_written;
Expand Down Expand Up @@ -71,6 +73,15 @@ static int perf_event__repipe_oe_synth(struct perf_tool *tool,
return perf_event__repipe_synth(tool, event);
}

#ifdef HAVE_LIBELF_SUPPORT
static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused,
struct ordered_events *oe __maybe_unused)
{
return 0;
}
#endif

static int perf_event__repipe_op2_synth(struct perf_tool *tool,
union perf_event *event,
struct perf_session *session
Expand Down Expand Up @@ -234,6 +245,27 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
return err;
}

#ifdef HAVE_LIBELF_SUPPORT
static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine)
{
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
u64 n = 0;

/*
* if jit marker, then inject jit mmaps and generate ELF images
*/
if (!jit_process(inject->session, &inject->output, machine,
event->mmap.filename, sample->pid, &n)) {
inject->bytes_written += n;
return 0;
}
return perf_event__repipe_mmap(tool, event, sample, machine);
}
#endif

static int perf_event__repipe_mmap2(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
Expand All @@ -247,6 +279,27 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
return err;
}

#ifdef HAVE_LIBELF_SUPPORT
static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct machine *machine)
{
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
u64 n = 0;

/*
* if jit marker, then inject jit mmaps and generate ELF images
*/
if (!jit_process(inject->session, &inject->output, machine,
event->mmap2.filename, sample->pid, &n)) {
inject->bytes_written += n;
return 0;
}
return perf_event__repipe_mmap2(tool, event, sample, machine);
}
#endif

static int perf_event__repipe_fork(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
Expand Down Expand Up @@ -664,6 +717,23 @@ static int __cmd_inject(struct perf_inject *inject)
return ret;
}

#ifdef HAVE_LIBELF_SUPPORT
static int
jit_validate_events(struct perf_session *session)
{
struct perf_evsel *evsel;

/*
* check that all events use CLOCK_MONOTONIC
*/
evlist__for_each(session->evlist, evsel) {
if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
return -1;
}
return 0;
}
#endif

int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
{
struct perf_inject inject = {
Expand Down Expand Up @@ -703,7 +773,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
};
int ret;

const struct option options[] = {
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",
Expand All @@ -713,6 +783,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
"Merge sched-stat and sched-switch for getting events "
"where and how long tasks slept"),
OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show build ids, etc)"),
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
Expand All @@ -729,7 +800,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
"perf inject [<options>]",
NULL
};

#ifndef HAVE_LIBELF_SUPPORT
set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
#endif
argc = parse_options(argc, argv, options, inject_usage, 0);

/*
Expand Down Expand Up @@ -765,7 +838,26 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
inject.tool.ordered_events = true;
inject.tool.ordering_requires_timestamps = true;
}

#ifdef HAVE_LIBELF_SUPPORT
if (inject.jit_mode) {
/*
* validate event is using the correct clockid
*/
if (jit_validate_events(inject.session)) {
fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
return -1;
}
inject.tool.mmap2 = perf_event__jit_repipe_mmap2;
inject.tool.mmap = perf_event__jit_repipe_mmap;
inject.tool.ordered_events = true;
inject.tool.ordering_requires_timestamps = true;
/*
* JIT MMAP injection injects all MMAP events in one go, so it
* does not obey finished_round semantics.
*/
inject.tool.finished_round = perf_event__drop_oe;
}
#endif
ret = symbol__init(&inject.session->header.env);
if (ret < 0)
goto out_delete;
Expand Down
2 changes: 2 additions & 0 deletions tools/perf/util/Build
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ libperf-y += scripting-engines/
libperf-$(CONFIG_ZLIB) += zlib.o
libperf-$(CONFIG_LZMA) += lzma.o
libperf-y += demangle-java.o
libperf-$(CONFIG_LIBELF) += jitdump.o
libperf-$(CONFIG_LIBELF) += genelf.o

CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"

Expand Down
Loading

0 comments on commit 9b07e27

Please sign in to comment.