All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 0/4] perf: add support for profiling jitted code
@ 2015-11-30  9:02 Stephane Eranian
  2015-11-30  9:02 ` [PATCH v8 1/4] perf tools: add Java demangling support Stephane Eranian
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Stephane Eranian @ 2015-11-30  9:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: acme, peterz, mingo, ak, jolsa, namhyung, cel, sukadev, sonnyrao,
	johnmccutchan, dsahern, adrian.hunter, pawel.moll

This patch series extends perf record/report/annotate to enable
profiling of jitted (just-in-time compiled) code. The current
perf tool provides very limited support for profiling jitted
code for some runtime environments. But the support is experimental
and cannot be used in complex environments. It relies on files
in /tmp, for instance. It does not support annotate mode or
rejitted code.

This patch series adds a better way of profiling jitted code
with the following advantages:
   - support any jitted code environment (some with modifications)
   - support Java runtime with JVMTI interface with no modifications
   - provides a portable JVMTI agent library
   - known to support V8 runtime
   - known to support DART runtime
   - supports code rejitting and code movements
   - no files in /tmp
   - meta-data file is unique to each run
   - no changes to perf report/annotate
   - support per-thread and system-wide profiling
   - support monitoring of multiple simultaneous Jit runtimes
   - source level view in perf annotate
   - works on x86_64, i386, arm32, arm64

The support is based on cooperation with the runtime. For Java runtimes,
supporting the JVMTI interface, there is no change necessary. For other
runtimes, modifications are necessary to emit the meta-data to support
symbolization, annotation, source lines correlation of the samples.
Those modifications are relatively straighforward, some have been 
implemented in V8 and DART.

The jit environment emits a binary dump file which contains the jitted
code (in raw format) and meta-data describing the mapping of functions.
The binary format is documented in the jitdump.h header file. It is
adapted from the OProfile jitdump format.

To enable synchronization of the runtime MMAPs with those recorded by
the kernel on behalf of the perf tool, the runtime needs to timestamp
any record in the dump file using the same time source. This is possible
since Linux 4.1 where the kernel supports per event timestamp clock source.
In the case of the JVMTI agent, the clock used is CLOCK_MONOTONIC, thus
perf record is invoked with -k mono such that it matches the agent.

The current support only works when the runtime is monitored from
start to finish: perf record java --agentpath:libpfmjvmti.so my_class.

Once the run is completed, the jitdump file needs to be injected into
the perf.data file. This is accomplished by using the perf inject command.
This will also generate an ELF image for each jitted function. The
injected MMAP records will point to these ELF images. The reasoning
behind using ELF images is that it makes processing for perf report
and annotate automatic and transparent. It also makes it easier to
package and analyze on a remote machine. Binutils tools can decode
the ELF images easily.

The reporting is unchanged, simply invoke perf report or perf annotate
on the modified perf.data file. The jitted code will appear symbolized
and the assembly view will display the instruction level profile and
source level profile.

As an added bonus, the series includes support for demangling function
signature from OpenJDK.

Furthermore, we believe there is a way to skip the perf inject phase
and have perf report/annotate directly inject the MMAP records 
on the fly during processing of the perf.data file. Perf report would
also generate the ELF files if necessary. Such optimization, would
make using this extension seamless in system-wide mode and larger
environments. This will be added in a later update as well.

In V2, we have switched to Pawell Moll and David Ahern posix
clock kernel module instead. We have dropped the patch which
modified the arguments to map_init() because the change was
not used. We are not printing the return type of Java methods
anymore and have made the Java demangler a separate module.
We also rebased to 3.19.0+ from tip.git.

In V3, we switched to Pawel Moll's CLOCK_MONOTONIC perf
clock patches. This patch switch perf_events from sched_clock
to CLOCK_MONOTONIC, a clock source which is available to users.

In V4, we rebased to 4.0-rc5. We also simplified the process by
getting rid of the requirement to pass the jitdump file name to
perf inject. Now, perf injects automtically detects if jitdumps
were generated and it merges the relevant meta-data. This is
accomplished by having the jit runtime mmap the jitdump file
for the purpose of creating a MMAP record in the perf.data file.
That MMAP contains all the info to locate the jitdump file and
generate the ELF images for jitted functions.

In V5, we rebase to acme's perf/core branch (instead of tip.git).
We fixed some bswap issues, switched to using scnprintf() and fixed
formatting issues. Also made sure all the files were included in the
patches. We also fix one error message in the JVMTI agent.


In V6, we switched back to using tip.git to leverage PeterZ's clockid
patch for perf_events in 4.0.0-rc6. Clock source can now be specified
per event and they are connected with the MONOTONIC Posix clock. We
leverage this extension to timestamp samples in the jit runtime and
correlate them with perf samples. Notice the -k mono option in perf
record example below.

In V7, we rebased to 4.3.0-rc3 using tip.git (at commit 0dc7757).
We fixed several issues in the agent. We also added source line
information in the jitdump file from the JVMTI agent. This is
still experimental and probably has some issues. The source
line info is encoded in DWARF2 format in each ELF image. The
code to do this is leveraged from Oprofile with some fixes
and cleanups.

In V8, we rebased to 4.4.0-rc2 using tip.git (at commit 9962da9).
We received great contributions from Andrian Hunter (adrian.hunter@intel.com).
He has fixed several issues in the jitdump injection code, see changelog
of the patch. The jitdump header has a new flags field to be used for
Intel PT. The series has been verified to work on x86_64, i386, arm32
and arm64 running 4.1 or later.

To use the new feature:
  - need to run with 4.1 or later
  - compile perf
  - cd tools/perf/jvmti; make; install wherever is appropriate

  Example using openJDK:
   $ perf record -k mono java -agentpath:libjvmti.so my_class
   $ perf inject -i perf.data -jit -o perf.data.jitted
   $ perf report -i perf.data.jitted

Thanks to all the contributors and testers. Special thanks
to PeterZ for adding the clock source to perf_events and solving
the problem of common timesource for user and kernel level samples.
Thanks to the Oprofile authors for the DWARF2 source line code
generation.

Special thanks to Adrian Hunter for his many bug fixes and improvements
for the V8 version of this series.

Enjoy,

Stephane Eranian (4):
  perf tools: add Java demangling support
  perf inject: add jitdump mmap injection support
  perf tools: add JVMTI agent library
  perf/jit: add source line info support

 tools/build/Makefile.feature             |   2 +
 tools/build/feature/Makefile             |   4 +
 tools/build/feature/test-all.c           |   5 +
 tools/build/feature/test-libcrypto.c     |  17 +
 tools/perf/Documentation/perf-inject.txt |   7 +
 tools/perf/builtin-inject.c              |  93 +++++
 tools/perf/config/Makefile               |  11 +
 tools/perf/jvmti/Makefile                |  73 ++++
 tools/perf/jvmti/jvmti_agent.c           | 465 +++++++++++++++++++++
 tools/perf/jvmti/jvmti_agent.h           |  36 ++
 tools/perf/jvmti/libjvmti.c              | 304 ++++++++++++++
 tools/perf/util/Build                    |   7 +
 tools/perf/util/demangle-java.c          | 199 +++++++++
 tools/perf/util/demangle-java.h          |  10 +
 tools/perf/util/genelf.c                 | 449 +++++++++++++++++++++
 tools/perf/util/genelf.h                 |  67 +++
 tools/perf/util/genelf_debug.c           | 610 ++++++++++++++++++++++++++++
 tools/perf/util/jit.h                    |  15 +
 tools/perf/util/jitdump.c                | 672 +++++++++++++++++++++++++++++++
 tools/perf/util/jitdump.h                | 124 ++++++
 tools/perf/util/symbol-elf.c             |   3 +
 21 files changed, 3173 insertions(+)
 create mode 100644 tools/build/feature/test-libcrypto.c
 create mode 100644 tools/perf/jvmti/Makefile
 create mode 100644 tools/perf/jvmti/jvmti_agent.c
 create mode 100644 tools/perf/jvmti/jvmti_agent.h
 create mode 100644 tools/perf/jvmti/libjvmti.c
 create mode 100644 tools/perf/util/demangle-java.c
 create mode 100644 tools/perf/util/demangle-java.h
 create mode 100644 tools/perf/util/genelf.c
 create mode 100644 tools/perf/util/genelf.h
 create mode 100644 tools/perf/util/genelf_debug.c
 create mode 100644 tools/perf/util/jit.h
 create mode 100644 tools/perf/util/jitdump.c
 create mode 100644 tools/perf/util/jitdump.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v8 1/4] perf tools: add Java demangling support
  2015-11-30  9:02 [PATCH v8 0/4] perf: add support for profiling jitted code Stephane Eranian
@ 2015-11-30  9:02 ` Stephane Eranian
  2016-02-09 12:14   ` [tip:perf/core] perf symbols: " tip-bot for Stephane Eranian
  2015-11-30  9:02 ` [PATCH v8 2/4] perf inject: add jitdump mmap injection support Stephane Eranian
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 27+ messages in thread
From: Stephane Eranian @ 2015-11-30  9:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: acme, peterz, mingo, ak, jolsa, namhyung, cel, sukadev, sonnyrao,
	johnmccutchan, dsahern, adrian.hunter, pawel.moll

Add Java function descriptor demangling support.
Something bfd cannot do.

Use the JAVA_DEMANGLE_NORET flag to avoid decoding the
return type of functions.

Signed-off-by: Stephane Eranian <eranian@google.com>
---
 tools/perf/util/Build           |   1 +
 tools/perf/util/demangle-java.c | 199 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/demangle-java.h |  10 ++
 tools/perf/util/symbol-elf.c    |   3 +
 4 files changed, 213 insertions(+)
 create mode 100644 tools/perf/util/demangle-java.c
 create mode 100644 tools/perf/util/demangle-java.h

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 0513dd5..a265088 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -110,6 +110,7 @@ libperf-y += scripting-engines/
 
 libperf-$(CONFIG_ZLIB) += zlib.o
 libperf-$(CONFIG_LZMA) += lzma.o
+libperf-y += demangle-java.o
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
new file mode 100644
index 0000000..19b7c06
--- /dev/null
+++ b/tools/perf/util/demangle-java.c
@@ -0,0 +1,199 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include "util.h"
+#include "debug.h"
+#include "symbol.h"
+
+#include "demangle-java.h"
+
+enum {
+	MODE_PREFIX=0,
+	MODE_CLASS=1,
+	MODE_FUNC=2,
+	MODE_TYPE=3,
+	MODE_CTYPE=3, /* class arg */
+};
+
+#define BASE_ENT(c, n)	[c-'A']=n
+static const char *base_types['Z'-'A' + 1]={
+	BASE_ENT('B', "byte" ),
+	BASE_ENT('C', "char" ),
+	BASE_ENT('D', "double" ),
+	BASE_ENT('F', "float" ),
+	BASE_ENT('I', "int" ),
+	BASE_ENT('J', "long" ),
+	BASE_ENT('S', "short" ),
+	BASE_ENT('Z', "bool" ),
+};
+
+/*
+ * demangle Java symbol between str and end positions and stores
+ * up to maxlen characters into buf. The parser starts in mode.
+ *
+ * Use MODE_PREFIX to process entire prototype till end position
+ * Use MODE_TYPE to process return type if str starts on return type char
+ *
+ *  Return:
+ *	success: buf
+ *	error  : NULL
+ */
+static char *
+__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
+{
+	int rlen = 0;
+	int array = 0;
+	int narg = 0;
+	const char *q;
+
+	if (!end)
+		end = str + strlen(str);
+
+	for (q = str; q != end; q++) {
+
+		if (rlen == (maxlen - 1))
+			break;
+
+		switch (*q) {
+		case 'L':
+			if (mode == MODE_PREFIX || mode == MODE_CTYPE) {
+				if (mode == MODE_CTYPE) {
+					if (narg)
+						rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
+					narg++;
+				}
+				rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
+				if (mode == MODE_PREFIX)
+					mode = MODE_CLASS;
+			} else
+				buf[rlen++] = *q;
+			break;
+		case 'B':
+		case 'C':
+		case 'D':
+		case 'F':
+		case 'I':
+		case 'J':
+		case 'S':
+		case 'Z':
+			if (mode == MODE_TYPE) {
+				if (narg)
+					rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
+				rlen += scnprintf(buf+rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
+				while(array--)
+					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
+				array = 0;
+				narg++;
+			} else
+				buf[rlen++] = *q;
+			break;
+		case 'V':
+			if (mode == MODE_TYPE) {
+				rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
+				while(array--)
+					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
+				array = 0;
+			} else
+				buf[rlen++] = *q;
+			break;
+		case '[':
+			if (mode != MODE_TYPE)
+				goto error;
+			array++;
+			break;
+		case '(':
+			if (mode != MODE_FUNC)
+				goto error;
+			buf[rlen++] = *q;
+			mode = MODE_TYPE;
+			break;
+		case ')':
+			if (mode != MODE_TYPE)
+				goto error;
+			buf[rlen++] = *q;
+			narg = 0;
+			break;
+		case ';':
+			if (mode != MODE_CLASS && mode != MODE_CTYPE)
+				goto error;
+			/* safe because at least one other char to process */
+			if (isalpha(*(q+1)))
+				rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
+			if (mode == MODE_CLASS)
+				mode = MODE_FUNC;
+			else if (mode == MODE_CTYPE)
+				mode = MODE_TYPE;
+			break;
+		case '/':
+			if (mode != MODE_CLASS && mode != MODE_CTYPE)
+				goto error;
+			rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
+			break;
+		default :
+			buf[rlen++] = *q;
+		}
+	}
+	buf[rlen] = '\0';
+	return buf;
+error:
+	return NULL;
+}
+
+/*
+ * Demangle Java function signature (openJDK, not GCJ)
+ * input:
+ * 	str: string to parse. String is not modified
+ *    flags: comobination of JAVA_DEMANGLE_* flags to modify demangling
+ * return:
+ *	if input can be demangled, then a newly allocated string is returned.
+ *	if input cannot be demangled, then NULL is returned
+ *
+ * Note: caller is responsible for freeing demangled string
+ */
+char *
+java_demangle_sym(const char *str, int flags)
+{
+	char *buf, *ptr;
+	char *p;
+	size_t len, l1 = 0;
+
+	if (!str)
+		return NULL;
+
+	/* find start of retunr type */
+	p = strrchr(str, ')');
+	if (!p)
+		return NULL;
+
+	/*
+	 * expansion factor estimated to 3x
+	 */
+	len = strlen(str) * 3 + 1;
+	buf = malloc(len);
+	if (!buf)
+		return NULL;
+
+	buf[0] = '\0';
+	if (!(flags & JAVA_DEMANGLE_NORET)) {
+		/*
+		 * get return type first
+		 */
+		ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
+		if (!ptr)
+			goto error;
+
+		/* add space between return type and function prototype */
+		l1 = strlen(buf);
+		buf[l1++] = ' ';
+	}
+
+	/* process function up to return type */
+	ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
+	if (!ptr)
+		goto error;
+
+	return buf;
+error:
+	free(buf);
+	return NULL;
+}
diff --git a/tools/perf/util/demangle-java.h b/tools/perf/util/demangle-java.h
new file mode 100644
index 0000000..a981c1f
--- /dev/null
+++ b/tools/perf/util/demangle-java.h
@@ -0,0 +1,10 @@
+#ifndef __PERF_DEMANGLE_JAVA
+#define __PERF_DEMANGLE_JAVA 1
+/*
+ * demangle function flags
+ */
+#define JAVA_DEMANGLE_NORET	0x1 /* do not process return type */
+
+char * java_demangle_sym(const char *str, int flags);
+
+#endif /* __PERF_DEMANGLE_JAVA */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 53f1996..54452f7 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -6,6 +6,7 @@
 #include <inttypes.h>
 
 #include "symbol.h"
+#include "demangle-java.h"
 #include "machine.h"
 #include "vdso.h"
 #include <symbol/kallsyms.h>
@@ -1072,6 +1073,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
 				demangle_flags = DMGL_PARAMS | DMGL_ANSI;
 
 			demangled = bfd_demangle(NULL, elf_name, demangle_flags);
+			if (demangled == NULL)
+				demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
 			if (demangled != NULL)
 				elf_name = demangled;
 		}
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2015-11-30  9:02 [PATCH v8 0/4] perf: add support for profiling jitted code Stephane Eranian
  2015-11-30  9:02 ` [PATCH v8 1/4] perf tools: add Java demangling support Stephane Eranian
@ 2015-11-30  9:02 ` Stephane Eranian
  2016-01-22 20:44   ` Arnaldo Carvalho de Melo
                     ` (3 more replies)
  2015-11-30  9:02 ` [PATCH v8 3/4] perf tools: add JVMTI agent library Stephane Eranian
  2015-11-30  9:02 ` [PATCH v8 4/4] perf/jit: add source line info support Stephane Eranian
  3 siblings, 4 replies; 27+ messages in thread
From: Stephane Eranian @ 2015-11-30  9:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: acme, peterz, mingo, ak, jolsa, namhyung, cel, sukadev, sonnyrao,
	johnmccutchan, dsahern, adrian.hunter, pawel.moll

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>
---
 tools/build/Makefile.feature             |   2 +
 tools/build/feature/Makefile             |   4 +
 tools/build/feature/test-all.c           |   5 +
 tools/build/feature/test-libcrypto.c     |  17 +
 tools/perf/Documentation/perf-inject.txt |   7 +
 tools/perf/builtin-inject.c              |  93 +++++
 tools/perf/config/Makefile               |  11 +
 tools/perf/util/Build                    |   2 +
 tools/perf/util/genelf.c                 | 442 ++++++++++++++++++++
 tools/perf/util/genelf.h                 |  63 +++
 tools/perf/util/jit.h                    |  15 +
 tools/perf/util/jitdump.c                | 670 +++++++++++++++++++++++++++++++
 tools/perf/util/jitdump.h                | 124 ++++++
 13 files changed, 1455 insertions(+)
 create mode 100644 tools/build/feature/test-libcrypto.c
 create mode 100644 tools/perf/util/genelf.c
 create mode 100644 tools/perf/util/genelf.h
 create mode 100644 tools/perf/util/jit.h
 create mode 100644 tools/perf/util/jitdump.c
 create mode 100644 tools/perf/util/jitdump.h

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 37ff4c9..6feb98b 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -46,6 +46,7 @@ FEATURE_TESTS ?=			\
 	libpython			\
 	libpython-version		\
 	libslang			\
+	libcrypto			\
 	libunwind			\
 	pthread-attr-setaffinity-np	\
 	stackprotector-all		\
@@ -68,6 +69,7 @@ FEATURE_DISPLAY ?=			\
 	libperl				\
 	libpython			\
 	libslang			\
+	libcrypto			\
 	libunwind			\
 	libdw-dwarf-unwind		\
 	zlib				\
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index cea04ce9..bb3fc48 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -24,6 +24,7 @@ FILES=					\
 	test-libpython.bin		\
 	test-libpython-version.bin	\
 	test-libslang.bin		\
+	test-libcrypto.bin		\
 	test-libunwind.bin		\
 	test-libunwind-debug-frame.bin	\
 	test-pthread-attr-setaffinity-np.bin	\
@@ -104,6 +105,9 @@ endif
 test-libslang.bin:
 	$(BUILD) -I/usr/include/slang -lslang
 
+test-libcrypto.bin:
+	$(BUILD) -lcrypto
+
 test-gtk2.bin:
 	$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
 
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 33cf6f2..00ab716 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -125,6 +125,10 @@
 # include "test-get_cpuid.c"
 #undef main
 
+#define main main_test_libcrypto
+# include "test-libcrypto.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -153,6 +157,7 @@ int main(int argc, char *argv[])
 	main_test_pthread_attr_setaffinity_np();
 	main_test_lzma();
 	main_test_get_cpuid();
+	main_test_libcrypto();
 
 	return 0;
 }
diff --git a/tools/build/feature/test-libcrypto.c b/tools/build/feature/test-libcrypto.c
new file mode 100644
index 0000000..bd79dc7
--- /dev/null
+++ b/tools/build/feature/test-libcrypto.c
@@ -0,0 +1,17 @@
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+
+int main(void)
+{
+	MD5_CTX context;
+	unsigned char md[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
+	unsigned char dat[] = "12345";
+
+	MD5_Init(&context);
+	MD5_Update(&context, &dat[0], sizeof(dat));
+	MD5_Final(&md[0], &context);
+
+	SHA1(&dat[0], sizeof(dat), &md[0]);
+
+	return 0;
+}
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index 0b1cede..87b2588 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -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]
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 99d127f..cfc579b 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -17,6 +17,7 @@
 #include "util/build-id.h"
 #include "util/data.h"
 #include "util/auxtrace.h"
+#include "util/jit.h"
 
 #include "util/parse-options.h"
 
@@ -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;
@@ -71,6 +73,13 @@ static int perf_event__repipe_oe_synth(struct perf_tool *tool,
 	return perf_event__repipe_synth(tool, event);
 }
 
+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;
+}
+
 static int perf_event__repipe_op2_synth(struct perf_tool *tool,
 					union perf_event *event,
 					struct perf_session *session
@@ -234,6 +243,25 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
 	return err;
 }
 
+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);
+}
+
 static int perf_event__repipe_mmap2(struct perf_tool *tool,
 				   union perf_event *event,
 				   struct perf_sample *sample,
@@ -247,6 +275,25 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
 	return err;
 }
 
+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);
+}
+
 static int perf_event__repipe_fork(struct perf_tool *tool,
 				   union perf_event *event,
 				   struct perf_sample *sample,
@@ -664,6 +711,21 @@ static int __cmd_inject(struct perf_inject *inject)
 	return ret;
 }
 
+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;
+}
+
 int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_inject inject = {
@@ -713,6 +775,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",
@@ -755,6 +818,36 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (inject.session == NULL)
 		return -1;
 
+	if (inject.build_ids) {
+		/*
+		 * to make sure the mmap records are ordered correctly
+		 * and so that the correct especially due to jitted code
+		 * mmaps. We cannot generate the buildid hit list and
+		 * inject the jit mmaps at the same time for now.
+		 */
+		inject.tool.ordered_events = true;
+		inject.tool.ordering_requires_timestamps = true;
+	}
+
+	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;
+	}
+
 	ret = symbol__init(&inject.session->header.env);
 	if (ret < 0)
 		goto out_delete;
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 6eb9a95..ae95cd4 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -409,6 +409,17 @@ ifndef NO_LIBAUDIT
   endif
 endif
 
+ifndef NO_LIBCRYPTO
+  ifneq ($(feature-libcrypto), 1)
+    msg := $(warning No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev);
+    NO_LIBCRYPTO := 1
+  else
+    CFLAGS += -DHAVE_LIBCRYPTO_SUPPORT
+    EXTLIBS += -lcrypto
+    $(call detected,CONFIG_CRYPTO)
+  endif
+endif
+
 ifdef NO_NEWT
   NO_SLANG=1
 endif
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index a265088..53efead 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -111,6 +111,8 @@ libperf-y += scripting-engines/
 libperf-$(CONFIG_ZLIB) += zlib.o
 libperf-$(CONFIG_LZMA) += lzma.o
 libperf-y += demangle-java.o
+libperf-y += jitdump.o
+libperf-y += genelf.o
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
new file mode 100644
index 0000000..145f811
--- /dev/null
+++ b/tools/perf/util/genelf.c
@@ -0,0 +1,442 @@
+/*
+ * genelf.c
+ * Copyright (C) 2014, Google, Inc
+ *
+ * Contributed by:
+ * 	Stephane Eranian <eranian@gmail.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <libelf.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <err.h>
+#include <dwarf.h>
+
+#include "perf.h"
+#include "genelf.h"
+#include "../util/jitdump.h"
+
+#define JVMTI
+
+#define BUILD_ID_URANDOM /* different uuid for each run */
+
+#ifdef HAVE_LIBCRYPTO
+
+#define BUILD_ID_MD5
+#undef BUILD_ID_SHA	/* does not seem to work well when linked with Java */
+#undef BUILD_ID_URANDOM /* different uuid for each run */
+
+#ifdef BUILD_ID_SHA
+#include <openssl/sha.h>
+#endif
+
+#ifdef BUILD_ID_MD5
+#include <openssl/md5.h>
+#endif
+#endif
+
+
+typedef struct {
+  unsigned int namesz;  /* Size of entry's owner string */
+  unsigned int descsz;  /* Size of the note descriptor */
+  unsigned int type;    /* Interpretation of the descriptor */
+  char         name[0]; /* Start of the name+desc data */
+} Elf_Note;
+
+struct options {
+	char *output;
+	int fd;
+};
+
+static char shd_string_table[] = {
+	0,
+	'.', 't', 'e', 'x', 't', 0,			/*  1 */
+	'.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /*  7 */
+	'.', 's', 'y', 'm', 't', 'a', 'b', 0,		/* 17 */
+	'.', 's', 't', 'r', 't', 'a', 'b', 0,		/* 25 */
+	'.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */
+	'.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
+	'.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
+	'.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
+};
+
+static struct buildid_note {
+	Elf_Note desc;		/* descsz: size of build-id, must be multiple of 4 */
+	char	 name[4];	/* GNU\0 */
+	char	 build_id[20];
+} bnote;
+
+static Elf_Sym symtab[]={
+	/* symbol 0 MUST be the undefined symbol */
+	{ .st_name  = 0, /* index in sym_string table */
+	  .st_info  = ELF_ST_TYPE(STT_NOTYPE),
+	  .st_shndx = 0, /* for now */
+	  .st_value = 0x0,
+	  .st_other = ELF_ST_VIS(STV_DEFAULT),
+	  .st_size  = 0,
+	},
+	{ .st_name  = 1, /* index in sym_string table */
+	  .st_info  = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
+	  .st_shndx = 1,
+	  .st_value = 0, /* for now */
+	  .st_other = ELF_ST_VIS(STV_DEFAULT),
+	  .st_size  = 0, /* for now */
+	}
+};
+
+#ifdef BUILD_ID_URANDOM
+static void
+gen_build_id(struct buildid_note *note,
+	     unsigned long load_addr __maybe_unused,
+	     const void *code __maybe_unused,
+	     size_t csize __maybe_unused)
+{
+	int fd;
+	size_t sz = sizeof(note->build_id);
+	ssize_t sret;
+
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd == -1)
+		err(1, "cannot access /dev/urandom for builid");
+
+	sret = read(fd, note->build_id, sz);
+
+	close(fd);
+
+	if (sret != (ssize_t)sz)
+		memset(note->build_id, 0, sz);
+}
+#endif
+
+#ifdef BUILD_ID_SHA
+static void
+gen_build_id(struct buildid_note *note,
+	     unsigned long load_addr __maybe_unused,
+	     const void *code,
+	     size_t csize)
+{
+	if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
+		errx(1, "build_id too small for SHA1");
+
+	SHA1(code, csize, (unsigned char *)note->build_id);
+}
+#endif
+
+#ifdef BUILD_ID_MD5
+static void
+gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
+{
+	MD5_CTX context;
+
+	if (sizeof(note->build_id) < 16)
+		errx(1, "build_id too small for MD5");
+
+	MD5_Init(&context);
+	MD5_Update(&context, &load_addr, sizeof(load_addr));
+	MD5_Update(&context, code, csize);
+	MD5_Final((unsigned char *)note->build_id, &context);
+}
+#endif
+
+/*
+ * fd: file descriptor open for writing for the output file
+ * load_addr: code load address (could be zero, just used for buildid)
+ * sym: function name (for native code - used as the symbol)
+ * code: the native code
+ * csize: the code size in bytes
+ */
+int
+jit_write_elf(int fd, uint64_t load_addr, const char *sym,
+	      const void *code, int csize)
+{
+	Elf *e;
+	Elf_Data *d;
+	Elf_Scn *scn;
+	Elf_Ehdr *ehdr;
+	Elf_Shdr *shdr;
+	char *strsym = NULL;
+	int symlen;
+	int retval = -1;
+
+	if (elf_version(EV_CURRENT) == EV_NONE) {
+		warnx("ELF initialization failed");
+		return -1;
+	}
+
+	e = elf_begin(fd, ELF_C_WRITE, NULL);
+	if (!e) {
+		warnx("elf_begin failed");
+		goto error;
+	}
+
+	/*
+	 * setup ELF header
+	 */
+	ehdr = elf_newehdr(e);
+	if (!ehdr) {
+		warnx("cannot get ehdr");
+		goto error;
+	}
+
+	ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
+	ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
+	ehdr->e_machine = GEN_ELF_ARCH;
+	ehdr->e_type = ET_DYN;
+	ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
+	ehdr->e_version = EV_CURRENT;
+	ehdr->e_shstrndx= 2; /* shdr index for section name */
+
+	/*
+	 * setup text section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	d->d_align = 16;
+	d->d_off = 0LL;
+	d->d_buf = (void *)code;
+	d->d_type = ELF_T_BYTE;
+	d->d_size = csize;
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 1;
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
+	shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup section headers string table
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = shd_string_table;
+	d->d_type = ELF_T_BYTE;
+	d->d_size = sizeof(shd_string_table);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
+	shdr->sh_type = SHT_STRTAB;
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup symtab section
+	 */
+	symtab[1].st_size  = csize;
+	symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
+
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	d->d_align = 8;
+	d->d_off = 0LL;
+	d->d_buf = symtab;
+	d->d_type = ELF_T_SYM;
+	d->d_size = sizeof(symtab);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
+	shdr->sh_type = SHT_SYMTAB;
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = sizeof(Elf_Sym);
+	shdr->sh_link = 4; /* index of .strtab section */
+
+	/*
+	 * setup symbols string table
+	 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
+	 */
+	symlen = 2 + strlen(sym);
+	strsym = calloc(1, symlen);
+	if (!strsym) {
+		warnx("cannot allocate strsym");
+		goto error;
+	}
+	strcpy(strsym + 1, sym);
+
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = strsym;
+	d->d_type = ELF_T_BYTE;
+	d->d_size = symlen;
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 25; /* offset in shd_string_table */
+	shdr->sh_type = SHT_STRTAB;
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup build-id section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	/*
+	 * build-id generation
+	 */
+	gen_build_id(&bnote, load_addr, code, csize);
+	bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
+	bnote.desc.descsz = sizeof(bnote.build_id);
+	bnote.desc.type   = NT_GNU_BUILD_ID;
+	strcpy(bnote.name, "GNU");
+
+	d->d_align = 4;
+	d->d_off = 0LL;
+	d->d_buf = &bnote;
+	d->d_type = ELF_T_BYTE;
+	d->d_size = sizeof(bnote);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 33; /* offset in shd_string_table */
+	shdr->sh_type = SHT_NOTE;
+	shdr->sh_addr = 0x0;
+	shdr->sh_flags = SHF_ALLOC;
+	shdr->sh_size = sizeof(bnote);
+	shdr->sh_entsize = 0;
+
+	if (elf_update(e, ELF_C_WRITE) < 0) {
+		warnx("elf_update 4 failed");
+		goto error;
+	}
+
+	retval = 0;
+error:
+	(void)elf_end(e);
+
+	free(strsym);
+
+
+	return retval;
+}
+
+#ifndef JVMTI
+
+static unsigned char x86_code[] = {
+    0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */
+    0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */
+    0xCD, 0x80            /* int $0x80 */
+};
+
+static struct options options;
+
+int main(int argc, char **argv)
+{
+	int c, fd, ret;
+
+	while ((c = getopt(argc, argv, "o:h")) != -1) {
+		switch (c) {
+		case 'o':
+			options.output = optarg;
+			break;
+		case 'h':
+			printf("Usage: genelf -o output_file [-h]\n");
+			return 0;
+		default:
+			errx(1, "unknown option");
+		}
+	}
+
+	fd = open(options.output, O_CREAT|O_TRUNC|O_RDWR, 0666);
+	if (fd == -1)
+		err(1, "cannot create file %s", options.output);
+
+	ret = jit_write_elf(fd, "main", x86_code, sizeof(x86_code));
+	close(fd);
+
+	if (ret != 0)
+		unlink(options.output);
+
+	return ret;
+}
+#endif
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
new file mode 100644
index 0000000..d8e9ece
--- /dev/null
+++ b/tools/perf/util/genelf.h
@@ -0,0 +1,63 @@
+#ifndef __GENELF_H__
+#define __GENELF_H__
+
+/* genelf.c */
+extern int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
+			 const void *code, int csize);
+
+#if   defined(__arm__)
+#define GEN_ELF_ARCH	EM_ARM
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS32
+#elif defined(__aarch64__)
+#define GEN_ELF_ARCH	EM_AARCH64
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#elif defined(__x86_64__)
+#define GEN_ELF_ARCH	EM_X86_64
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#elif defined(__i386__)
+#define GEN_ELF_ARCH	EM_386
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS32
+#elif defined(__ppcle__)
+#define GEN_ELF_ARCH	EM_PPC
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#elif defined(__powerpc__)
+#define GEN_ELF_ARCH	EM_PPC64
+#define GEN_ELF_ENDIAN	ELFDATA2MSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#elif defined(__powerpcle__)
+#define GEN_ELF_ARCH	EM_PPC64
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#else
+#error "unsupported architecture"
+#endif
+
+#if GEN_ELF_CLASS == ELFCLASS64
+#define elf_newehdr	elf64_newehdr
+#define elf_getshdr	elf64_getshdr
+#define Elf_Ehdr	Elf64_Ehdr
+#define Elf_Shdr	Elf64_Shdr
+#define Elf_Sym		Elf64_Sym
+#define ELF_ST_TYPE(a)	ELF64_ST_TYPE(a)
+#define ELF_ST_BIND(a)	ELF64_ST_BIND(a)
+#define ELF_ST_VIS(a)	ELF64_ST_VISIBILITY(a)
+#else
+#define elf_newehdr	elf32_newehdr
+#define elf_getshdr	elf32_getshdr
+#define Elf_Ehdr	Elf32_Ehdr
+#define Elf_Shdr	Elf32_Shdr
+#define Elf_Sym		Elf32_Sym
+#define ELF_ST_TYPE(a)	ELF32_ST_TYPE(a)
+#define ELF_ST_BIND(a)	ELF32_ST_BIND(a)
+#define ELF_ST_VIS(a)	ELF32_ST_VISIBILITY(a)
+#endif
+
+/* The .text section is directly after the ELF header */
+#define GEN_ELF_TEXT_OFFSET sizeof(Elf_Ehdr)
+
+#endif
diff --git a/tools/perf/util/jit.h b/tools/perf/util/jit.h
new file mode 100644
index 0000000..a1e99da
--- /dev/null
+++ b/tools/perf/util/jit.h
@@ -0,0 +1,15 @@
+#ifndef __JIT_H__
+#define __JIT_H__
+
+#include <data.h>
+
+extern int jit_process(struct perf_session *session,
+		       struct perf_data_file *output,
+		       struct machine *machine,
+		       char *filename,
+		       pid_t pid,
+		       u64 *nbytes);
+
+extern int jit_inject_record(const char *filename);
+
+#endif /* __JIT_H__ */
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
new file mode 100644
index 0000000..9f7a012
--- /dev/null
+++ b/tools/perf/util/jitdump.c
@@ -0,0 +1,670 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <byteswap.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "util.h"
+#include "event.h"
+#include "debug.h"
+#include "evlist.h"
+#include "symbol.h"
+#include "strlist.h"
+#include <elf.h>
+
+#include "session.h"
+#include "jit.h"
+#include "jitdump.h"
+#include "genelf.h"
+#include "../builtin.h"
+
+struct jit_buf_desc {
+	struct perf_data_file *output;
+	struct perf_session *session;
+	struct machine *machine;
+	union jr_entry   *entry;
+	void             *buf;
+	uint64_t	 sample_type;
+	size_t           bufsize;
+	FILE             *in;
+	bool		 needs_bswap; /* handles cross-endianess */
+	void		 *debug_data;
+	size_t		 nr_debug_entries;
+	uint32_t         code_load_count;
+	u64		 bytes_written;
+	struct rb_root   code_root;
+	char		 dir[PATH_MAX];
+};
+
+struct debug_line_info {
+	unsigned long vma;
+	unsigned int lineno;
+	/* The filename format is unspecified, absolute path, relative etc. */
+	char const filename[0];
+};
+
+struct jit_tool {
+	struct perf_tool tool;
+	struct perf_data_file	output;
+	struct perf_data_file	input;
+	u64 bytes_written;
+};
+
+#define hmax(a, b) ((a) > (b) ? (a) : (b))
+#define get_jit_tool(t) (container_of(tool, struct jit_tool, tool))
+
+static int
+jit_emit_elf(char *filename,
+	     const char *sym,
+	     uint64_t code_addr,
+	     const void *code,
+	     int csize)
+{
+	int ret, fd;
+
+	if (verbose > 0)
+		fprintf(stderr, "write ELF image %s\n", filename);
+
+	fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
+	if (fd == -1) {
+		pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(errno));
+		return -1;
+	}
+
+        ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize);
+
+        close(fd);
+
+        if (ret)
+                unlink(filename);
+
+	return ret;
+}
+
+static void
+jit_close(struct jit_buf_desc *jd)
+{
+	if (!(jd && jd->in))
+		return;
+	funlockfile(jd->in);
+	fclose(jd->in);
+	jd->in = NULL;
+}
+
+static int
+jit_open(struct jit_buf_desc *jd, const char *name)
+{
+	struct jitheader header;
+	struct jr_prefix *prefix;
+	ssize_t bs, bsz = 0;
+	void *n, *buf = NULL;
+	int ret, retval = -1;
+
+	jd->in = fopen(name, "r");
+	if (!jd->in)
+		return -1;
+
+	bsz = hmax(sizeof(header), sizeof(*prefix));
+
+	buf = malloc(bsz);
+	if (!buf)
+		goto error;
+
+	/*
+	 * protect from writer modifying the file while we are reading it
+	 */
+	flockfile(jd->in);
+
+	ret = fread(buf, sizeof(header), 1, jd->in);
+	if (ret != 1)
+		goto error;
+
+	memcpy(&header, buf, sizeof(header));
+
+	if (header.magic != JITHEADER_MAGIC) {
+		if (header.magic != JITHEADER_MAGIC_SW)
+			goto error;
+		jd->needs_bswap = true;
+	}
+
+	if (jd->needs_bswap) {
+		header.version    = bswap_32(header.version);
+		header.total_size = bswap_32(header.total_size);
+		header.pid	  = bswap_32(header.pid);
+		header.elf_mach   = bswap_32(header.elf_mach);
+		header.timestamp  = bswap_64(header.timestamp);
+		header.flags      = bswap_64(header.flags);
+	}
+
+	if (verbose > 2)
+		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
+			header.version,
+			header.total_size,
+			(unsigned long long)header.timestamp,
+			header.pid,
+			header.elf_mach);
+
+	if (header.flags & JITDUMP_FLAGS_RESERVED) {
+		pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
+		       (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED);
+		goto error;
+	}
+
+	bs = header.total_size - sizeof(header);
+
+	if (bs > bsz) {
+		n = realloc(buf, bs);
+		if (!n)
+			goto error;
+		bsz = bs;
+		buf = n;
+		/* read extra we do not know about */
+		ret = fread(buf, bs - bsz, 1, jd->in);
+		if (ret != 1)
+			goto error;
+	}
+	/*
+	 * keep dirname for generating files and mmap records
+	 */
+	strcpy(jd->dir, name);
+	dirname(jd->dir);
+
+	return 0;
+error:
+	funlockfile(jd->in);
+	fclose(jd->in);
+	return retval;
+}
+
+static union jr_entry *
+jit_get_next_entry(struct jit_buf_desc *jd)
+{
+	struct jr_prefix *prefix;
+	union jr_entry *jr;
+	void *addr;
+	size_t bs, size;
+	int id, ret;
+
+	if (!(jd && jd->in))
+		return NULL;
+
+	if (jd->buf == NULL) {
+		size_t sz = getpagesize();
+		if (sz < sizeof(*prefix))
+			sz = sizeof(*prefix);
+
+		jd->buf = malloc(sz);
+		if (jd->buf == NULL)
+			return NULL;
+
+		jd->bufsize = sz;
+	}
+
+	prefix = jd->buf;
+
+	/*
+	 * file is still locked at this point
+	 */
+	ret = fread(prefix, sizeof(*prefix), 1, jd->in);
+	if (ret  != 1)
+		return NULL;
+
+	if (jd->needs_bswap) {
+		prefix->id   	   = bswap_32(prefix->id);
+		prefix->total_size = bswap_32(prefix->total_size);
+		prefix->timestamp  = bswap_64(prefix->timestamp);
+	}
+	id   = prefix->id;
+	size = prefix->total_size;
+
+	bs = (size_t)size;
+	if (bs < sizeof(*prefix))
+		return NULL;
+
+	if (id >= JIT_CODE_MAX) {
+		pr_warning("next_entry: unknown prefix %d, skipping\n", id);
+		return NULL;
+	}
+	if (bs > jd->bufsize) {
+		void *n;
+		n = realloc(jd->buf, bs);
+		if (!n)
+			return NULL;
+		jd->buf = n;
+		jd->bufsize = bs;
+	}
+
+	addr = ((void *)jd->buf) + sizeof(*prefix);
+
+	ret = fread(addr, bs - sizeof(*prefix), 1, jd->in);
+	if (ret != 1)
+		return NULL;
+
+	jr = (union jr_entry *)jd->buf;
+
+	switch(id) {
+	case JIT_CODE_DEBUG_INFO:
+		if (jd->needs_bswap) {
+			uint64_t n;
+			jr->info.code_addr = bswap_64(jr->info.code_addr);
+			jr->info.nr_entry  = bswap_64(jr->info.nr_entry);
+			for (n = 0 ; n < jr->info.nr_entry; n++) {
+				jr->info.entries[n].addr    = bswap_64(jr->info.entries[n].addr);
+				jr->info.entries[n].lineno  = bswap_32(jr->info.entries[n].lineno);
+				jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
+			}
+		}
+		break;
+	case JIT_CODE_CLOSE:
+		break;
+	case JIT_CODE_LOAD:
+		if (jd->needs_bswap) {
+			jr->load.pid       = bswap_32(jr->load.pid);
+			jr->load.tid       = bswap_32(jr->load.tid);
+			jr->load.vma       = bswap_64(jr->load.vma);
+			jr->load.code_addr = bswap_64(jr->load.code_addr);
+			jr->load.code_size = bswap_64(jr->load.code_size);
+			jr->load.code_index= bswap_64(jr->load.code_index);
+		}
+		jd->code_load_count++;
+		break;
+	case JIT_CODE_MOVE:
+		if (jd->needs_bswap) {
+			jr->move.pid           = bswap_32(jr->move.pid);
+			jr->move.tid           = bswap_32(jr->move.tid);
+			jr->move.vma           = bswap_64(jr->move.vma);
+			jr->move.old_code_addr = bswap_64(jr->move.old_code_addr);
+			jr->move.new_code_addr = bswap_64(jr->move.new_code_addr);
+			jr->move.code_size     = bswap_64(jr->move.code_size);
+			jr->move.code_index    = bswap_64(jr->move.code_index);
+		}
+		break;
+	case JIT_CODE_MAX:
+	default:
+		return NULL;
+	}
+	return jr;
+}
+
+static int
+jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
+{
+	ssize_t size;
+
+	size = perf_data_file__write(jd->output, event, event->header.size);
+	if (size < 0)
+		return -1;
+
+	jd->bytes_written += size;
+	return 0;
+}
+
+static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
+{
+	struct perf_sample sample;
+	union perf_event *event;
+	struct perf_tool *tool = jd->session->tool;
+	uint64_t code, addr;
+	uintptr_t uaddr;
+	char *filename;
+	struct stat st;
+	size_t size;
+	u16 idr_size;
+	const char *sym;
+	uint32_t count;
+	int ret, csize;
+	pid_t pid, tid;
+	struct {
+		u32 pid, tid;
+		u64 time;
+	} *id;
+
+	pid   = jr->load.pid;
+	tid   = jr->load.tid;
+	csize = jr->load.code_size;
+	addr  = jr->load.code_addr;
+	sym   = (void *)((unsigned long)jr + sizeof(jr->load));
+	code  = (unsigned long)jr + jr->load.p.total_size - csize;
+	count = jr->load.code_index;
+	idr_size = jd->machine->id_hdr_size;
+
+	event = calloc(1, sizeof(*event) + idr_size);
+	if (!event)
+		return -1;
+
+	filename = event->mmap2.filename;
+	size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%u.so",
+			jd->dir,
+			pid,
+			count);
+
+	size++; /* for \0 */
+
+	size = PERF_ALIGN(size, sizeof(u64));
+	uaddr = (uintptr_t)code;
+	ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize);
+
+	if (jd->debug_data && jd->nr_debug_entries) {
+		free(jd->debug_data);
+		jd->debug_data = NULL;
+		jd->nr_debug_entries = 0;
+	}
+
+	if (ret) {
+		free(event);
+		return -1;
+	}
+	if (stat(filename, &st))
+		memset(&st, 0, sizeof(stat));
+
+	event->mmap2.header.type = PERF_RECORD_MMAP2;
+	event->mmap2.header.misc = PERF_RECORD_MISC_USER;
+	event->mmap2.header.size = (sizeof(event->mmap2) -
+			(sizeof(event->mmap2.filename) - size) + idr_size);
+
+	event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
+	event->mmap2.start = addr;
+	event->mmap2.len   = csize;
+	event->mmap2.pid   = pid;
+	event->mmap2.tid   = tid;
+	event->mmap2.ino   = st.st_ino;
+	event->mmap2.maj   = major(st.st_dev);
+	event->mmap2.min   = minor(st.st_dev);
+	event->mmap2.prot  = st.st_mode;
+	event->mmap2.flags = MAP_SHARED;
+	event->mmap2.ino_generation = 1;
+
+	id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
+	if (jd->sample_type & PERF_SAMPLE_TID) {
+		id->pid  = pid;
+		id->tid  = tid;
+	}
+	if (jd->sample_type & PERF_SAMPLE_TIME)
+		id->time = jr->load.p.timestamp;
+
+	/*
+	 * create pseudo sample to induce dso hit increment
+	 * use first address as sample address
+	 */
+	memset(&sample, 0, sizeof(sample));
+	sample.pid  = pid;
+	sample.tid  = tid;
+	sample.time = id->time;
+	sample.ip   = addr;
+
+	ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
+	if (ret)
+		return ret;
+
+	ret = jit_inject_event(jd, event);
+	/*
+	 * mark dso as use to generate buildid in the header
+	 */
+	if (!ret)
+		build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
+
+	return ret;
+}
+
+static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
+{
+	struct perf_sample sample;
+	union perf_event *event;
+	struct perf_tool *tool = jd->session->tool;
+	char *filename;
+	size_t size;
+	struct stat st;
+	u16 idr_size;
+	int ret;
+	pid_t pid, tid;
+	struct {
+		u32 pid, tid;
+		u64 time;
+	} *id;
+
+	pid = jr->move.pid;
+	tid =  jr->move.tid;
+	idr_size = jd->machine->id_hdr_size;
+
+	/*
+	 * +16 to account for sample_id_all (hack)
+	 */
+	event = calloc(1, sizeof(*event) + 16);
+	if (!event)
+		return -1;
+
+	filename = event->mmap2.filename;
+	size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%"PRIu64,
+	         jd->dir,
+	         pid,
+		 jr->move.code_index);
+
+	size++; /* for \0 */
+
+	if (stat(filename, &st))
+		memset(&st, 0, sizeof(stat));
+
+	size = PERF_ALIGN(size, sizeof(u64));
+
+	event->mmap2.header.type = PERF_RECORD_MMAP2;
+	event->mmap2.header.misc = PERF_RECORD_MISC_USER;
+	event->mmap2.header.size = (sizeof(event->mmap2) -
+			(sizeof(event->mmap2.filename) - size) + idr_size);
+	event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
+	event->mmap2.start = jr->move.new_code_addr;
+	event->mmap2.len   = jr->move.code_size;
+	event->mmap2.pid   = pid;
+	event->mmap2.tid   = tid;
+	event->mmap2.ino   = st.st_ino;
+	event->mmap2.maj   = major(st.st_dev);
+	event->mmap2.min   = minor(st.st_dev);
+	event->mmap2.prot  = st.st_mode;
+	event->mmap2.flags = MAP_SHARED;
+	event->mmap2.ino_generation = 1;
+
+	id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
+	if (jd->sample_type & PERF_SAMPLE_TID) {
+		id->pid  = pid;
+		id->tid  = tid;
+	}
+	if (jd->sample_type & PERF_SAMPLE_TIME)
+		id->time = jr->load.p.timestamp;
+
+	/*
+	 * create pseudo sample to induce dso hit increment
+	 * use first address as sample address
+	 */
+	memset(&sample, 0, sizeof(sample));
+	sample.pid  = pid;
+	sample.tid  = tid;
+	sample.time = id->time;
+	sample.ip   = jr->move.new_code_addr;
+
+	ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
+	if (ret)
+		return ret;
+
+	ret = jit_inject_event(jd, event);
+	if (!ret)
+		build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
+
+	return ret;
+}
+
+static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
+{
+	void *data;
+	size_t sz;
+
+	if (!(jd && jr))
+		return -1;
+
+	sz  = jr->prefix.total_size - sizeof(jr->info);
+	data = malloc(sz);
+	if (!data)
+		return -1;
+
+	memcpy(data, &jr->info.entries, sz);
+
+	jd->debug_data       = data;
+
+	/*
+	 * we must use nr_entry instead of size here because
+	 * we cannot distinguish actual entry from padding otherwise
+	 */
+	jd->nr_debug_entries = jr->info.nr_entry;
+
+	return 0;
+}
+
+static int
+jit_process_dump(struct jit_buf_desc *jd)
+{
+	union jr_entry *jr;
+	int ret;
+
+	while ((jr = jit_get_next_entry(jd))) {
+		switch(jr->prefix.id) {
+		case JIT_CODE_LOAD:
+			ret = jit_repipe_code_load(jd, jr);
+			break;
+		case JIT_CODE_MOVE:
+			ret = jit_repipe_code_move(jd, jr);
+			break;
+		case JIT_CODE_DEBUG_INFO:
+			ret = jit_repipe_debug_info(jd, jr);
+			break;
+		default:
+			ret = 0;
+			continue;
+		}
+	}
+	return ret;
+}
+
+static int
+jit_inject(struct jit_buf_desc *jd, char *path)
+{
+	int ret;
+
+	if (verbose > 0)
+		fprintf(stderr, "injecting: %s\n", path);
+
+	ret = jit_open(jd, path);
+	if (ret)
+		return -1;
+
+	ret = jit_process_dump(jd);
+
+	jit_close(jd);
+
+	if (verbose > 0)
+		fprintf(stderr, "injected: %s (%d)\n", path, ret);
+
+	return 0;
+}
+
+/*
+ * File must be with pattern .../jit-XXXX.dump
+ * where XXXX is the PID of the process which did the mmap()
+ * as captured in the RECORD_MMAP record
+ */
+static int
+jit_detect(char *mmap_name, pid_t pid)
+ {
+	char *p;
+	char *end = NULL;
+	pid_t pid2;
+
+	if (verbose > 2)
+		fprintf(stderr, "jit marker trying : %s\n", mmap_name);
+	/*
+	 * get file name
+	 */
+	p = strrchr(mmap_name, '/');
+	if (!p)
+		return -1;
+
+	/*
+	 * match prefix
+	 */
+	if (strncmp(p, "/jit-", 5))
+		return -1;
+
+	/*
+	 * skip prefix
+	 */
+	p += 5;
+
+	/*
+	 * must be followed by a pid
+	 */
+	if (!isdigit(*p))
+		return -1;
+
+	pid2 = (int)strtol(p, &end, 10);
+	if (!end)
+		return -1;
+
+	/*
+	 * pid does not match mmap pid
+	 * pid==0 in system-wide mode (synthesized)
+	 */
+	if (pid && pid2 != pid)
+		return -1;
+	/*
+	 * validate suffix
+	 */
+	if (strcmp(end, ".dump"))
+		return -1;
+
+	if (verbose > 0)
+		fprintf(stderr, "jit marker found: %s\n", mmap_name);
+
+	return 0;
+}
+
+int
+jit_process(struct perf_session *session,
+	    struct perf_data_file *output,
+	    struct machine *machine,
+	    char *filename,
+	    pid_t pid,
+	    u64 *nbytes)
+{
+	struct perf_evsel *first;
+	struct jit_buf_desc jd;
+	int ret;
+
+	/*
+	 * first, detect marker mmap (i.e., the jitdump mmap)
+	 */
+	if (jit_detect(filename, pid))
+		return -1;
+
+	memset(&jd, 0, sizeof(jd));
+
+	jd.session = session;
+	jd.output  = output;
+	jd.machine = machine;
+
+	/*
+	 * track sample_type to compute id_all layout
+	 * perf sets the same sample type to all events as of now
+	 */
+	first = perf_evlist__first(session->evlist);
+	jd.sample_type = first->attr.sample_type;
+
+	*nbytes = 0;
+
+	ret = jit_inject(&jd, filename);
+	if (!ret)
+		*nbytes = jd.bytes_written;
+
+	return ret;
+}
diff --git a/tools/perf/util/jitdump.h b/tools/perf/util/jitdump.h
new file mode 100644
index 0000000..b66c1f5
--- /dev/null
+++ b/tools/perf/util/jitdump.h
@@ -0,0 +1,124 @@
+/*
+ * jitdump.h: jitted code info encapsulation file format
+ *
+ * Adapted from OProfile GPLv2 support jidump.h:
+ * Copyright 2007 OProfile authors
+ * Jens Wilke
+ * Daniel Hansel
+ * Copyright IBM Corporation 2007
+ */
+#ifndef JITDUMP_H
+#define JITDUMP_H
+
+#include <sys/time.h>
+#include <time.h>
+#include <stdint.h>
+
+/* JiTD */
+#define JITHEADER_MAGIC		0x4A695444
+#define JITHEADER_MAGIC_SW	0x4454694A
+
+#define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7)
+
+#define JITHEADER_VERSION 1
+
+enum jitdump_flags_bits {
+	JITDUMP_FLAGS_MAX_BIT,
+};
+
+#define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
+				(~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
+
+struct jitheader {
+	uint32_t magic;		/* characters "jItD" */
+	uint32_t version;	/* header version */
+	uint32_t total_size;	/* total size of header */
+	uint32_t elf_mach;	/* elf mach target */
+	uint32_t pad1;		/* reserved */
+	uint32_t pid;		/* JIT process id */
+	uint64_t timestamp;	/* timestamp */
+	uint64_t flags;		/* flags */
+};
+
+enum jit_record_type {
+	JIT_CODE_LOAD		= 0,
+        JIT_CODE_MOVE           = 1,
+	JIT_CODE_DEBUG_INFO	= 2,
+	JIT_CODE_CLOSE		= 3,
+
+	JIT_CODE_MAX,
+};
+
+/* record prefix (mandatory in each record) */
+struct jr_prefix {
+	uint32_t id;
+	uint32_t total_size;
+	uint64_t timestamp;
+};
+
+struct jr_code_load {
+	struct jr_prefix p;
+
+	uint32_t pid;
+	uint32_t tid;
+	uint64_t vma;
+	uint64_t code_addr;
+	uint64_t code_size;
+	uint64_t code_index;
+};
+
+struct jr_code_close {
+	struct jr_prefix p;
+};
+
+struct jr_code_move {
+	struct jr_prefix p;
+
+	uint32_t pid;
+	uint32_t tid;
+	uint64_t vma;
+	uint64_t old_code_addr;
+	uint64_t new_code_addr;
+	uint64_t code_size;
+	uint64_t code_index;
+};
+
+struct debug_entry {
+	uint64_t addr;
+	int lineno;	    /* source line number starting at 1 */
+	int discrim;	    /* column discriminator, 0 is default */
+	const char name[0]; /* null terminated filename, \xff\0 if same as previous entry */
+};
+
+struct jr_code_debug_info {
+	struct jr_prefix p;
+
+	uint64_t code_addr;
+	uint64_t nr_entry;
+	struct debug_entry entries[0];
+};
+
+union jr_entry {
+        struct jr_code_debug_info info;
+        struct jr_code_close close;
+        struct jr_code_load load;
+        struct jr_code_move move;
+        struct jr_prefix prefix;
+};
+
+static inline struct debug_entry *
+debug_entry_next(struct debug_entry *ent)
+{
+	void *a = ent + 1;
+	size_t l = strlen(ent->name) + 1;
+	return a + l;
+}
+
+static inline char *
+debug_entry_file(struct debug_entry *ent)
+{
+	void *a = ent + 1;
+	return a;
+}
+
+#endif /* !JITDUMP_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v8 3/4] perf tools: add JVMTI agent library
  2015-11-30  9:02 [PATCH v8 0/4] perf: add support for profiling jitted code Stephane Eranian
  2015-11-30  9:02 ` [PATCH v8 1/4] perf tools: add Java demangling support Stephane Eranian
  2015-11-30  9:02 ` [PATCH v8 2/4] perf inject: add jitdump mmap injection support Stephane Eranian
@ 2015-11-30  9:02 ` Stephane Eranian
  2016-02-09 12:16   ` [tip:perf/core] " tip-bot for Stephane Eranian
  2015-11-30  9:02 ` [PATCH v8 4/4] perf/jit: add source line info support Stephane Eranian
  3 siblings, 1 reply; 27+ messages in thread
From: Stephane Eranian @ 2015-11-30  9:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: acme, peterz, mingo, ak, jolsa, namhyung, cel, sukadev, sonnyrao,
	johnmccutchan, dsahern, adrian.hunter, pawel.moll

This is a standalone JVMTI library to help  profile Java jitted
code with perf record/perf report. The library is not installed
or compiled automatically by perf Makefile. It is not used
directly by perf. It is arch agnostic and has been tested on
X86 and ARM. It needs to be used with a Java runtime, such
as OpenJDK, as follows:

$ java -agentpath:libjvmti.so .......

When used this way, java will generate a jitdump binary file in
$HOME/.debug/java/jit/java-jit-*

This binary dump file contains information to help symbolize and
annotate jitted code.

The jitdump information must be injected into the perf.data file
using:
$ perf inject --jit -i perf.data -o perf.data.jitted

This injects the MMAP records to cover the jitted code and also generates
one ELF image for each jitted function. The ELF images are created in the
same subdir as the jitdump file. The MMAP records point there too.

Then, to visualize the function or asm profile, simply use the regular
perf commands:
$ perf report -i perf.data.jitted
or
$ perf annotate -i perf.data.jitted

JVMTI agent code adapted from the OProfile's opagent code.

This version of the JVMTI agent is using the CLOCK_MONOTIC
as the time source to timestamp jit samples. To correlate
with perf_events samples, it needs to run on kernel 4.0.0-rc5+
or later with the following commit from Peter Zijlstra:
   34f4392 perf: Add per event clockid support

With this patch recording jitted code is done as follows:
   $ perf record -k mono -- java -agentpath:libjvmti.so .......

Signed-off-by: Stephane Eranian <eranian@google.com>
---
 tools/perf/jvmti/Makefile      |  73 +++++++
 tools/perf/jvmti/jvmti_agent.c | 465 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/jvmti/jvmti_agent.h |  29 +++
 tools/perf/jvmti/libjvmti.c    | 208 ++++++++++++++++++
 4 files changed, 775 insertions(+)
 create mode 100644 tools/perf/jvmti/Makefile
 create mode 100644 tools/perf/jvmti/jvmti_agent.c
 create mode 100644 tools/perf/jvmti/jvmti_agent.h
 create mode 100644 tools/perf/jvmti/libjvmti.c

diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
new file mode 100644
index 0000000..5e46f51
--- /dev/null
+++ b/tools/perf/jvmti/Makefile
@@ -0,0 +1,73 @@
+ARCH=$(shell uname -m)
+
+ifeq ($(ARCH), x86_64)
+JARCH=amd64
+endif
+ifeq ($(ARCH), armv7l)
+JARCH=armhf
+endif
+ifeq ($(ARCH), armv6l)
+JARCH=armhf
+endif
+ifeq ($(ARCH), aarch64)
+JARCH=aarch64
+endif
+ifeq ($(ARCH), ppc64)
+JARCH=powerpc
+endif
+ifeq ($(ARCH), ppc64le)
+JARCH=powerpc
+endif
+
+DESTDIR=/usr/local
+
+VERSION=1
+REVISION=0
+AGE=0
+
+LN=ln -sf
+RM=rm
+
+SLIBJVMTI=libjvmti.so.$(VERSION).$(REVISION).$(AGE)
+VLIBJVMTI=libjvmti.so.$(VERSION)
+SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBJVMTI)
+SOLIBEXT=so
+
+JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
+# -lrt required in 32-bit mode for clock_gettime()
+LIBS=-lelf -lrt
+INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
+
+TARGETS=$(SLIBJVMTI)
+
+SRCS=libjvmti.c jvmti_agent.c
+OBJS=$(SRCS:.c=.o)
+SOBJS=$(OBJS:.o=.lo)
+OPT=-O2 -g -Werror -Wall
+
+CFLAGS=$(INCDIR) $(OPT)
+
+all: $(TARGETS)
+
+.c.o:
+	$(CC) $(CFLAGS) -c $*.c
+.c.lo:
+	$(CC) -fPIC -DPIC $(CFLAGS) -c $*.c -o $*.lo
+
+$(OBJS) $(SOBJS): Makefile jvmti_agent.h ../util/jitdump.h
+
+$(SLIBJVMTI):  $(SOBJS)
+	$(CC) $(CFLAGS) $(SLDFLAGS)  -o $@ $(SOBJS) $(LIBS)
+	$(LN) $@ libjvmti.$(SOLIBEXT)
+
+clean:
+	$(RM) -f *.o *.so.* *.so *.lo
+
+install:
+	-mkdir -p $(DESTDIR)/lib
+	install -m 755 $(SLIBJVMTI) $(DESTDIR)/lib/
+	(cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) $(VLIBJVMTI))
+	(cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) libjvmti.$(SOLIBEXT))
+	ldconfig
+
+.SUFFIXES: .c .S .o .lo
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
new file mode 100644
index 0000000..cbab139
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -0,0 +1,465 @@
+/*
+ * jvmti_agent.c: JVMTI agent interface
+ *
+ * Adapted from the Oprofile code in opagent.c:
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Copyright 2007 OProfile authors
+ * Jens Wilke
+ * Daniel Hansel
+ * Copyright IBM Corporation 2007
+ */
+#include <sys/types.h>
+#include <sys/stat.h> /* for mkdir() */
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <syscall.h> /* for gettid() */
+#include <err.h>
+
+#include "jvmti_agent.h"
+#include "../util/jitdump.h"
+
+#define JIT_LANG "java"
+
+static char jit_path[PATH_MAX];
+static void *marker_addr;
+
+/*
+ * padding buffer
+ */
+static const char pad_bytes[7];
+
+static inline pid_t gettid(void)
+{
+	return (pid_t)syscall(__NR_gettid);
+}
+
+static int get_e_machine(struct jitheader *hdr)
+{
+	ssize_t sret;
+	char id[16];
+	int fd, ret = -1;
+	int m = -1;
+	struct {
+		uint16_t e_type;
+		uint16_t e_machine;
+	} info;
+
+	fd = open("/proc/self/exe", O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	sret = read(fd, id, sizeof(id));
+	if (sret != sizeof(id))
+		goto error;
+
+	/* check ELF signature */
+	if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F')
+		goto error;
+
+	sret = read(fd, &info, sizeof(info));
+	if (sret != sizeof(info))
+		goto error;
+
+	m = info.e_machine;
+	if (m < 0)
+		m = 0; /* ELF EM_NONE */
+
+	hdr->elf_mach = m;
+	ret = 0;
+error:
+	close(fd);
+	return ret;
+}
+
+#define NSEC_PER_SEC	1000000000
+static int perf_clk_id = CLOCK_MONOTONIC;
+
+static inline uint64_t
+timespec_to_ns(const struct timespec *ts)
+{
+        return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
+}
+
+static inline uint64_t
+perf_get_timestamp(void)
+{
+	struct timespec ts;
+	int ret;
+
+	ret = clock_gettime(perf_clk_id, &ts);
+	if (ret)
+		return 0;
+
+	return timespec_to_ns(&ts);
+}
+
+static int
+debug_cache_init(void)
+{
+	char str[32];
+	char *base, *p;
+	struct tm tm;
+	time_t t;
+	int ret;
+
+	time(&t);
+	localtime_r(&t, &tm);
+
+	base = getenv("JITDUMPDIR");
+	if (!base)
+		base = getenv("HOME");
+	if (!base)
+		base = ".";
+
+	strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
+
+	snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base);
+
+	ret = mkdir(jit_path, 0755);
+	if (ret == -1) {
+		if (errno != EEXIST) {
+			warn("jvmti: cannot create jit cache dir %s", jit_path);
+			return -1;
+		}
+	}
+
+	snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base);
+	ret = mkdir(jit_path, 0755);
+	if (ret == -1) {
+		if (errno != EEXIST) {
+			warn("cannot create jit cache dir %s", jit_path);
+			return -1;
+		}
+	}
+
+	snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str);
+
+	p = mkdtemp(jit_path);
+	if (p != jit_path) {
+		warn("cannot create jit cache dir %s", jit_path);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+perf_open_marker_file(int fd)
+{
+	long pgsz;
+
+	pgsz = sysconf(_SC_PAGESIZE);
+	if (pgsz == -1)
+		return -1;
+
+	/*
+	 * we mmap the jitdump to create an MMAP RECORD in perf.data file.
+	 * The mmap is captured either live (perf record running when we mmap)
+	 * or  in deferred mode, via /proc/PID/maps
+	 * the MMAP record is used as a marker of a jitdump file for more meta
+	 * data info about the jitted code. Perf report/annotate detect this
+	 * special filename and process the jitdump file.
+	 *
+	 * mapping must be PROT_EXEC to ensure it is captured by perf record
+	 * even when not using -d option
+	 */
+	marker_addr = mmap(NULL, pgsz, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
+	return (marker_addr == MAP_FAILED) ? -1 : 0;
+}
+
+static void
+perf_close_marker_file(void)
+{
+	long pgsz;
+
+	if (!marker_addr)
+		return;
+
+	pgsz = sysconf(_SC_PAGESIZE);
+	if (pgsz == -1)
+		return;
+
+	munmap(marker_addr, pgsz);
+}
+
+void *jvmti_open(void)
+{
+	int pad_cnt;
+	char dump_path[PATH_MAX];
+	struct jitheader header;
+	int fd;
+	FILE *fp;
+
+	/*
+	 * check if clockid is supported
+	 */
+	if (!perf_get_timestamp())
+		warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
+
+	memset(&header, 0, sizeof(header));
+
+	debug_cache_init();
+
+	/*
+	 * jitdump file name
+	 */
+	snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
+
+	fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
+	if (fd == -1)
+		return NULL;
+
+	/*
+	 * create perf.data maker for the jitdump file
+	 */
+	if (perf_open_marker_file(fd)) {
+		warnx("jvmti: failed to create marker file");
+		return NULL;
+	}
+
+	fp = fdopen(fd, "w+");
+	if (!fp) {
+		warn("jvmti: cannot create %s", dump_path);
+		close(fd);
+		goto error;
+	}
+
+	warnx("jvmti: jitdump in %s", dump_path);
+
+	if (get_e_machine(&header)) {
+		warn("get_e_machine failed\n");
+		goto error;
+	}
+
+	header.magic      = JITHEADER_MAGIC;
+	header.version    = JITHEADER_VERSION;
+	header.total_size = sizeof(header);
+	header.pid        = getpid();
+
+	/* calculate amount of padding '\0' */
+	pad_cnt = PADDING_8ALIGNED(header.total_size);
+	header.total_size += pad_cnt;
+
+	header.timestamp = perf_get_timestamp();
+
+	if (!fwrite(&header, sizeof(header), 1, fp)) {
+		warn("jvmti: cannot write dumpfile header");
+		goto error;
+	}
+
+	/* write padding '\0' if necessary */
+	if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, fp)) {
+		warn("jvmti: cannot write dumpfile header padding");
+		goto error;
+	}
+
+	return fp;
+error:
+	fclose(fp);
+	return NULL;
+}
+
+int
+jvmti_close(void *agent)
+{
+	struct jr_code_close rec;
+	FILE *fp = agent;
+
+	if (!fp) {
+		warnx("jvmti: incalid fd in close_agent");
+		return -1;
+	}
+
+	rec.p.id = JIT_CODE_CLOSE;
+	rec.p.total_size = sizeof(rec);
+
+	rec.p.timestamp = perf_get_timestamp();
+
+	if (!fwrite(&rec, sizeof(rec), 1, fp))
+		return -1;
+
+	fclose(fp);
+
+	fp = NULL;
+
+	perf_close_marker_file();
+
+	return 0;
+}
+
+int
+jvmti_write_code(void *agent, char const *sym,
+	uint64_t vma, void const *code, unsigned int const size)
+{
+	static int code_generation = 1;
+	struct jr_code_load rec;
+	size_t sym_len;
+	size_t padding_count;
+	FILE *fp = agent;
+	int ret = -1;
+
+	/* don't care about 0 length function, no samples */
+	if (size == 0)
+		return 0;
+
+	if (!fp) {
+		warnx("jvmti: invalid fd in write_native_code");
+		return -1;
+	}
+
+	sym_len = strlen(sym) + 1;
+
+	rec.p.id           = JIT_CODE_LOAD;
+	rec.p.total_size   = sizeof(rec) + sym_len;
+	padding_count      = PADDING_8ALIGNED(rec.p.total_size);
+	rec.p. total_size += padding_count;
+	rec.p.timestamp    = perf_get_timestamp();
+
+	rec.code_size  = size;
+	rec.vma        = vma;
+	rec.code_addr  = vma;
+	rec.pid	       = getpid();
+	rec.tid	       = gettid();
+
+	if (code)
+		rec.p.total_size += size;
+
+	/*
+	 * If JVM is multi-threaded, nultiple concurrent calls to agent
+	 * may be possible, so protect file writes
+	 */
+	flockfile(fp);
+
+	/*
+	 * get code index inside lock to avoid race condition
+	 */
+	rec.code_index = code_generation++;
+
+	ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
+	fwrite_unlocked(sym, sym_len, 1, fp);
+
+	if (padding_count)
+		fwrite_unlocked(pad_bytes, padding_count, 1, fp);
+
+	if (code)
+		fwrite_unlocked(code, size, 1, fp);
+
+	funlockfile(fp);
+
+	ret = 0;
+
+	return ret;
+}
+
+int
+jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
+		       jvmtiAddrLocationMap const *map,
+		       jvmtiLineNumberEntry *li, jint num)
+{
+	static const char *prev_str = "\xff";
+	struct jr_code_debug_info rec;
+	size_t sret, len, size, flen;
+	size_t padding_count;
+	FILE *fp = agent;
+	int i;
+
+	/*
+	 * no entry to write
+	 */
+	if (!num)
+		return 0;
+
+	if (!fp) {
+		warnx("jvmti: invalid fd in write_debug_info");
+		return -1;
+	}
+
+	flen = strlen(file) + 1;
+
+	rec.p.id        = JIT_CODE_DEBUG_INFO;
+	size            = sizeof(rec);
+	rec.p.timestamp = perf_get_timestamp();
+	rec.code_addr   = (uint64_t)(uintptr_t)code;
+	rec.nr_entry    = num;
+
+	/*
+	 * on disk source line info layout:
+	 * uint64_t : addr
+	 * int      : line number
+	 * file[]   : source file name
+	 * padding  : pad to multiple of 8 bytes
+	 */
+	size += num * (sizeof(uint64_t) + sizeof(int));
+	size += flen + (num - 1) * 2;
+	/*
+	 * pad to 8 bytes
+	 */
+	padding_count = PADDING_8ALIGNED(size);
+
+	rec.p.total_size = size + padding_count;
+
+	/*
+	 * If JVM is multi-threaded, nultiple concurrent calls to agent
+	 * may be possible, so protect file writes
+	 */
+	flockfile(fp);
+
+	sret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
+	if (sret != 1)
+		goto error;
+
+	for (i = 0; i < num; i++) {
+		uint64_t addr;
+
+		addr = (uint64_t)map[i].start_address;
+		len  = sizeof(addr);
+		sret = fwrite_unlocked(&addr, len, 1, fp);
+		if (sret != 1)
+			goto error;
+
+		len  = sizeof(int);
+		sret = fwrite_unlocked(&li[i].line_number, len, 1, fp);
+		if (sret != 1)
+			goto error;
+
+		if (i == 0) {
+			sret = fwrite_unlocked(file, flen, 1, fp);
+		} else {
+			sret = fwrite_unlocked(prev_str, 2, 1, fp);
+		}
+		if (sret != 1)
+			goto error;
+
+	}
+	if (padding_count)
+		sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp);
+		if (sret != 1)
+			goto error;
+
+	funlockfile(fp);
+	return 0;
+error:
+	funlockfile(fp);
+	return -1;
+}
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h
new file mode 100644
index 0000000..8251a1c
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.h
@@ -0,0 +1,29 @@
+#ifndef __JVMTI_AGENT_H__
+#define __JVMTI_AGENT_H__
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <jvmti.h>
+
+#define __unused __attribute__((unused))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void *jvmti_open(void);
+int   jvmti_close(void *agent);
+int   jvmti_write_code(void *agent, char const *symbol_name,
+		       uint64_t vma, void const *code,
+		       const unsigned int code_size);
+int   jvmti_write_debug_info(void *agent,
+		             uint64_t code,
+			     const char *file,
+			     jvmtiAddrLocationMap const *map,
+			     jvmtiLineNumberEntry *tab, jint nr);
+
+#if defined(__cplusplus)
+}
+
+#endif
+#endif /* __JVMTI_H__ */
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
new file mode 100644
index 0000000..745f20c
--- /dev/null
+++ b/tools/perf/jvmti/libjvmti.c
@@ -0,0 +1,208 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+#include <jvmti.h>
+#include <limits.h>
+
+#include "jvmti_agent.h"
+
+static int has_line_numbers;
+void *jvmti_agent;
+
+static void JNICALL
+compiled_method_load_cb(jvmtiEnv *jvmti,
+			jmethodID method,
+			jint code_size,
+			void const *code_addr,
+			jint map_length,
+			jvmtiAddrLocationMap const *map,
+			void const *compile_info __unused)
+{
+	jvmtiLineNumberEntry *tab = NULL;
+	jclass decl_class;
+	char *class_sign = NULL;
+	char *func_name = NULL;
+	char *func_sign = NULL;
+	char *file_name= NULL;
+	char fn[PATH_MAX];
+	uint64_t addr = (uint64_t)(uintptr_t)code_addr;
+	jvmtiError ret;
+	jint nr_lines = 0;
+	size_t len;
+
+	ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
+						&decl_class);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: cannot get declaring class");
+		return;
+	}
+
+	if (has_line_numbers && map && map_length) {
+
+		ret = (*jvmti)->GetLineNumberTable(jvmti, method, &nr_lines, &tab);
+		if (ret != JVMTI_ERROR_NONE) {
+			warnx("jvmti: cannot get line table for method");
+		} else {
+			ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
+			if (ret != JVMTI_ERROR_NONE) {
+				warnx("jvmti: cannot get source filename ret=%d", ret);
+				nr_lines = 0;
+			}
+		}
+	}
+
+	ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
+					  &class_sign, NULL);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: getclassignature failed");
+		goto error;
+	}
+
+	ret = (*jvmti)->GetMethodName(jvmti, method, &func_name,
+				      &func_sign, NULL);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: failed getmethodname");
+		goto error;
+	}
+
+	/*
+	 * Assume path name is class hierarchy, this is a common practice with Java programs
+	 */
+	if (*class_sign == 'L') {
+		int j, i = 0;
+		char *p = strrchr(class_sign, '/');
+		if (p) {
+			/* drop the 'L' prefix and copy up to the final '/' */
+			for (i = 0; i < (p - class_sign); i++)
+				fn[i] = class_sign[i+1];
+		}
+		/*
+		 * append file name, we use loops and not string ops to avoid modifying
+		 * class_sign which is used later for the symbol name
+		 */
+		for (j = 0; i < (PATH_MAX - 1) && j < strlen(file_name); j++, i++)
+			fn[i] = file_name[j];
+		fn[i] = '\0';
+	} else {
+		/* fallback case */
+		strcpy(fn, file_name);
+	}
+	/*
+	 * write source line info record if we have it
+	 */
+	if (jvmti_write_debug_info(jvmti_agent, addr, fn, map, tab, nr_lines))
+		warnx("jvmti: write_debug_info() failed");
+
+	len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
+	{
+		char str[len];
+		snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
+		if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
+			warnx("jvmti: write_code() failed");
+	}
+error:
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)tab);
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
+}
+
+static void JNICALL
+code_generated_cb(jvmtiEnv *jvmti,
+		  char const *name,
+		  void const *code_addr,
+		  jint code_size)
+{
+	uint64_t addr = (uint64_t)(unsigned long)code_addr;
+	int ret;
+
+	ret = jvmti_write_code(jvmti_agent, name, addr, code_addr, code_size);
+	if (ret)
+		warnx("jvmti: write_code() failed for code_generated");
+}
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
+{
+	jvmtiEventCallbacks cb;
+	jvmtiCapabilities caps1;
+	jvmtiJlocationFormat format;
+	jvmtiEnv *jvmti = NULL;
+	jint ret;
+
+	jvmti_agent = jvmti_open();
+	if (!jvmti_agent) {
+		warnx("jvmti: open_agent failed");
+		return -1;
+	}
+
+	/*
+	 * Request a JVMTI interface version 1 environment
+	 */
+	ret = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);
+	if (ret != JNI_OK) {
+		warnx("jvmti: jvmti version 1 not supported");
+		return -1;
+	}
+
+	/*
+	 * acquire method_load capability, we require it
+	 * request line numbers (optional)
+	 */
+	memset(&caps1, 0, sizeof(caps1));
+	caps1.can_generate_compiled_method_load_events = 1;
+
+	ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: acquire compiled_method capability failed");
+		return -1;
+	}
+	ret = (*jvmti)->GetJLocationFormat(jvmti, &format);
+        if (ret == JVMTI_ERROR_NONE && format == JVMTI_JLOCATION_JVMBCI) {
+                memset(&caps1, 0, sizeof(caps1));
+                caps1.can_get_line_numbers = 1;
+                caps1.can_get_source_file_name = 1;
+		ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
+                if (ret == JVMTI_ERROR_NONE)
+                        has_line_numbers = 1;
+        }
+
+	memset(&cb, 0, sizeof(cb));
+
+	cb.CompiledMethodLoad   = compiled_method_load_cb;
+	cb.DynamicCodeGenerated = code_generated_cb;
+
+	ret = (*jvmti)->SetEventCallbacks(jvmti, &cb, sizeof(cb));
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: cannot set event callbacks");
+		return -1;
+	}
+
+	ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
+			JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: setnotification failed for method_load");
+		return -1;
+	}
+
+	ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
+			JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: setnotification failed on code_generated");
+		return -1;
+	}
+	return 0;
+}
+
+JNIEXPORT void JNICALL
+Agent_OnUnload(JavaVM *jvm __unused)
+{
+	int ret;
+
+	ret = jvmti_close(jvmti_agent);
+	if (ret)
+		errx(1, "Error: op_close_agent()");
+}
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v8 4/4] perf/jit: add source line info support
  2015-11-30  9:02 [PATCH v8 0/4] perf: add support for profiling jitted code Stephane Eranian
                   ` (2 preceding siblings ...)
  2015-11-30  9:02 ` [PATCH v8 3/4] perf tools: add JVMTI agent library Stephane Eranian
@ 2015-11-30  9:02 ` Stephane Eranian
  2016-02-09 12:16   ` [tip:perf/core] perf jit: " tip-bot for Stephane Eranian
  3 siblings, 1 reply; 27+ messages in thread
From: Stephane Eranian @ 2015-11-30  9:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: acme, peterz, mingo, ak, jolsa, namhyung, cel, sukadev, sonnyrao,
	johnmccutchan, dsahern, adrian.hunter, pawel.moll

This patch adds source line information support to perf for jitted code.
The source line info must be emitted by the runtime, such as JVMTI.
Perf injects extract the source line info from the jitdump file and
adds the corresponding .debug_lines section in the ELF image generated
for each jitted function. The source line enables matching any address
in the profile with a source file and line number. The improvement is
visible in perf annotate with the source code displayed alongside
the assembly code.

The dwarf code leverages the support from OProfile which is also released
under GPLv2.  Copyright 2007 OProfile authors.

Signed-off-by: Stephane Eranian <eranian@google.com>
---
 tools/perf/jvmti/jvmti_agent.c |  32 +--
 tools/perf/jvmti/jvmti_agent.h |  11 +-
 tools/perf/jvmti/libjvmti.c    | 122 ++++++++-
 tools/perf/util/Build          |   4 +
 tools/perf/util/genelf.c       |  15 +-
 tools/perf/util/genelf.h       |   6 +-
 tools/perf/util/genelf_debug.c | 610 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/jitdump.c      |   8 +-
 8 files changed, 769 insertions(+), 39 deletions(-)
 create mode 100644 tools/perf/util/genelf_debug.c

diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
index cbab139..6461e02 100644
--- a/tools/perf/jvmti/jvmti_agent.c
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -374,20 +374,20 @@ jvmti_write_code(void *agent, char const *sym,
 
 int
 jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
-		       jvmtiAddrLocationMap const *map,
-		       jvmtiLineNumberEntry *li, jint num)
+		       jvmti_line_info_t *li, int nr_lines)
 {
-	static const char *prev_str = "\xff";
 	struct jr_code_debug_info rec;
 	size_t sret, len, size, flen;
 	size_t padding_count;
+	uint64_t addr;
+	const char *fn = file;
 	FILE *fp = agent;
 	int i;
 
 	/*
 	 * no entry to write
 	 */
-	if (!num)
+	if (!nr_lines)
 		return 0;
 
 	if (!fp) {
@@ -401,17 +401,18 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
 	size            = sizeof(rec);
 	rec.p.timestamp = perf_get_timestamp();
 	rec.code_addr   = (uint64_t)(uintptr_t)code;
-	rec.nr_entry    = num;
+	rec.nr_entry    = nr_lines;
 
 	/*
 	 * on disk source line info layout:
 	 * uint64_t : addr
 	 * int      : line number
+	 * int      : column discriminator
 	 * file[]   : source file name
 	 * padding  : pad to multiple of 8 bytes
 	 */
-	size += num * (sizeof(uint64_t) + sizeof(int));
-	size += flen + (num - 1) * 2;
+	size += nr_lines * sizeof(struct debug_entry);
+	size += flen * nr_lines;
 	/*
 	 * pad to 8 bytes
 	 */
@@ -429,28 +430,27 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
 	if (sret != 1)
 		goto error;
 
-	for (i = 0; i < num; i++) {
-		uint64_t addr;
+	for (i = 0; i < nr_lines; i++) {
 
-		addr = (uint64_t)map[i].start_address;
+		addr = (uint64_t)li[i].pc;
 		len  = sizeof(addr);
 		sret = fwrite_unlocked(&addr, len, 1, fp);
 		if (sret != 1)
 			goto error;
 
-		len  = sizeof(int);
+		len  = sizeof(li[0].line_number);
 		sret = fwrite_unlocked(&li[i].line_number, len, 1, fp);
 		if (sret != 1)
 			goto error;
 
-		if (i == 0) {
-			sret = fwrite_unlocked(file, flen, 1, fp);
-		} else {
-			sret = fwrite_unlocked(prev_str, 2, 1, fp);
-		}
+		len  = sizeof(li[0].discrim);
+		sret = fwrite_unlocked(&li[i].discrim, len, 1, fp);
 		if (sret != 1)
 			goto error;
 
+		sret = fwrite_unlocked(fn, flen, 1, fp);
+		if (sret != 1)
+			goto error;
 	}
 	if (padding_count)
 		sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp);
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h
index 8251a1c..bedf5d0 100644
--- a/tools/perf/jvmti/jvmti_agent.h
+++ b/tools/perf/jvmti/jvmti_agent.h
@@ -11,16 +11,23 @@
 extern "C" {
 #endif
 
+typedef struct {
+	unsigned long	pc;
+	int		line_number;
+	int		discrim; /* discriminator -- 0 for now */
+} jvmti_line_info_t;
+
 void *jvmti_open(void);
 int   jvmti_close(void *agent);
 int   jvmti_write_code(void *agent, char const *symbol_name,
 		       uint64_t vma, void const *code,
 		       const unsigned int code_size);
+
 int   jvmti_write_debug_info(void *agent,
 		             uint64_t code,
 			     const char *file,
-			     jvmtiAddrLocationMap const *map,
-			     jvmtiLineNumberEntry *tab, jint nr);
+			     jvmti_line_info_t *li,
+			     int nr_lines);
 
 #if defined(__cplusplus)
 }
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
index 745f20c..6ee98b0 100644
--- a/tools/perf/jvmti/libjvmti.c
+++ b/tools/perf/jvmti/libjvmti.c
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <err.h>
 #include <jvmti.h>
+#include <jvmticmlr.h>
 #include <limits.h>
 
 #include "jvmti_agent.h"
@@ -11,6 +12,100 @@
 static int has_line_numbers;
 void *jvmti_agent;
 
+static jvmtiError
+do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
+		    jvmti_line_info_t *tab, jint *nr)
+{
+	jint i, lines = 0;
+	jint nr_lines = 0;
+	jvmtiLineNumberEntry *loc_tab = NULL;
+	jvmtiError ret;
+
+	ret = (*jvmti)->GetLineNumberTable(jvmti, m, &nr_lines, &loc_tab);
+	if (ret != JVMTI_ERROR_NONE)
+		return ret;
+
+	for (i = 0; i < nr_lines; i++) {
+		if (loc_tab[i].start_location < bci) {
+			tab[lines].pc = (unsigned long)pc;
+			tab[lines].line_number = loc_tab[i].line_number;
+			tab[lines].discrim = 0; /* not yet used */
+			lines++;
+		} else {
+			break;
+		}
+	}
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)loc_tab);
+	*nr = lines;
+	return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError
+get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **tab, int *nr_lines)
+{
+	const jvmtiCompiledMethodLoadRecordHeader *hdr;
+	jvmtiCompiledMethodLoadInlineRecord *rec;
+	jvmtiLineNumberEntry *lne = NULL;
+	PCStackInfo *c;
+	jint nr, ret;
+	int nr_total = 0;
+	int i, lines_total = 0;
+
+	if (!(tab && nr_lines))
+		return JVMTI_ERROR_NULL_POINTER;
+
+	/*
+	 * Phase 1 -- get the number of lines necessary
+	 */
+	for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
+		if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
+			rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
+			for (i = 0; i < rec->numpcs; i++) {
+				c = rec->pcinfo + i;
+				nr = 0;
+				/*
+				 * unfortunately, need a tab to get the number of lines!
+				 */
+				ret = (*jvmti)->GetLineNumberTable(jvmti, c->methods[0], &nr, &lne);
+				if (ret == JVMTI_ERROR_NONE) {
+					/* free what was allocated for nothing */
+					(*jvmti)->Deallocate(jvmti, (unsigned char *)lne);
+					nr_total += (int)nr;
+				}
+			}
+		}
+	}
+
+	if (nr_total == 0)
+		return JVMTI_ERROR_NOT_FOUND;
+
+	/*
+	 * Phase 2 -- allocate big enough line table
+	 */
+	*tab = malloc(nr_total * sizeof(**tab));
+	if (!*tab)
+		return JVMTI_ERROR_OUT_OF_MEMORY;
+
+	for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
+		if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
+			rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
+			for (i = 0; i < rec->numpcs; i++) {
+				c = rec->pcinfo + i;
+				nr = 0;
+				ret = do_get_line_numbers(jvmti, c->pc,
+							  c->methods[0],
+							  c->bcis[0],
+							  *tab + lines_total,
+							  &nr);
+				if (ret == JVMTI_ERROR_NONE)
+					lines_total += nr;
+			}
+		}
+	}
+	*nr_lines = lines_total;
+	return JVMTI_ERROR_NONE;
+}
+
 static void JNICALL
 compiled_method_load_cb(jvmtiEnv *jvmti,
 			jmethodID method,
@@ -18,9 +113,9 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 			void const *code_addr,
 			jint map_length,
 			jvmtiAddrLocationMap const *map,
-			void const *compile_info __unused)
+			const void *compile_info)
 {
-	jvmtiLineNumberEntry *tab = NULL;
+	jvmti_line_info_t *line_tab = NULL;
 	jclass decl_class;
 	char *class_sign = NULL;
 	char *func_name = NULL;
@@ -29,7 +124,7 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 	char fn[PATH_MAX];
 	uint64_t addr = (uint64_t)(uintptr_t)code_addr;
 	jvmtiError ret;
-	jint nr_lines = 0;
+	int nr_lines = 0; /* in line_tab[] */
 	size_t len;
 
 	ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
@@ -40,19 +135,19 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 	}
 
 	if (has_line_numbers && map && map_length) {
-
-		ret = (*jvmti)->GetLineNumberTable(jvmti, method, &nr_lines, &tab);
+		ret = get_line_numbers(jvmti, compile_info, &line_tab, &nr_lines);
 		if (ret != JVMTI_ERROR_NONE) {
 			warnx("jvmti: cannot get line table for method");
-		} else {
-			ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
-			if (ret != JVMTI_ERROR_NONE) {
-				warnx("jvmti: cannot get source filename ret=%d", ret);
-				nr_lines = 0;
-			}
+			nr_lines = 0;
 		}
 	}
 
+	ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: cannot get source filename ret=%d", ret);
+		goto error;
+	}
+
 	ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
 					  &class_sign, NULL);
 	if (ret != JVMTI_ERROR_NONE) {
@@ -92,13 +187,14 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 	/*
 	 * write source line info record if we have it
 	 */
-	if (jvmti_write_debug_info(jvmti_agent, addr, fn, map, tab, nr_lines))
+	if (jvmti_write_debug_info(jvmti_agent, addr, fn, line_tab, nr_lines))
 		warnx("jvmti: write_debug_info() failed");
 
 	len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
 	{
 		char str[len];
 		snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
+
 		if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
 			warnx("jvmti: write_code() failed");
 	}
@@ -106,8 +202,8 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 	(*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
 	(*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
 	(*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
-	(*jvmti)->Deallocate(jvmti, (unsigned char *)tab);
 	(*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
+	free(line_tab);
 }
 
 static void JNICALL
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 53efead..41de648 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -113,9 +113,13 @@ libperf-$(CONFIG_LZMA) += lzma.o
 libperf-y += demangle-java.o
 libperf-y += jitdump.o
 libperf-y += genelf.o
+libperf-y += genelf_debug.o
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
+# avoid compiler warnings in 32-bit mode
+CFLAGS_genelf_debug.o  += -Wno-packed
+
 
 $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
 	$(call rule_mkdir)
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
index 145f811..c1ef805 100644
--- a/tools/perf/util/genelf.c
+++ b/tools/perf/util/genelf.c
@@ -156,7 +156,8 @@ gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *cod
  */
 int
 jit_write_elf(int fd, uint64_t load_addr, const char *sym,
-	      const void *code, int csize)
+	      const void *code, int csize,
+	      void *debug, int nr_debug_entries)
 {
 	Elf *e;
 	Elf_Data *d;
@@ -385,9 +386,15 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
 	shdr->sh_size = sizeof(bnote);
 	shdr->sh_entsize = 0;
 
-	if (elf_update(e, ELF_C_WRITE) < 0) {
-		warnx("elf_update 4 failed");
-		goto error;
+	if (debug && nr_debug_entries) {
+		retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
+		if (retval)
+			goto error;
+	} else {
+		if (elf_update(e, ELF_C_WRITE) < 0) {
+			warnx("elf_update 4 failed");
+			goto error;
+		}
 	}
 
 	retval = 0;
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
index d8e9ece..45bf9c6 100644
--- a/tools/perf/util/genelf.h
+++ b/tools/perf/util/genelf.h
@@ -3,7 +3,11 @@
 
 /* genelf.c */
 extern int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
-			 const void *code, int csize);
+			 const void *code, int csize,
+			 void *debug, int nr_debug_entries);
+/* genelf_debug.c */
+extern int jit_add_debug_info(Elf *e, uint64_t code_addr,
+			      void *debug, int nr_debug_entries);
 
 #if   defined(__arm__)
 #define GEN_ELF_ARCH	EM_ARM
diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c
new file mode 100644
index 0000000..5980f7d
--- /dev/null
+++ b/tools/perf/util/genelf_debug.c
@@ -0,0 +1,610 @@
+/*
+ * genelf_debug.c
+ * Copyright (C) 2015, Google, Inc
+ *
+ * Contributed by:
+ * 	Stephane Eranian <eranian@google.com>
+ *
+ * Released under the GPL v2.
+ *
+ * based on GPLv2 source code from Oprofile
+ * @remark Copyright 2007 OProfile authors
+ * @author Philippe Elie
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <libelf.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <err.h>
+#include <dwarf.h>
+
+#include "perf.h"
+#include "genelf.h"
+#include "../util/jitdump.h"
+
+#define BUFFER_EXT_DFL_SIZE	(4 * 1024)
+
+typedef uint32_t uword;
+typedef uint16_t uhalf;
+typedef int32_t  sword;
+typedef int16_t  shalf;
+typedef uint8_t  ubyte;
+typedef int8_t   sbyte;
+
+struct buffer_ext {
+	size_t cur_pos;
+	size_t max_sz;
+	void *data;
+};
+
+static void
+buffer_ext_dump(struct buffer_ext *be, const char *msg)
+{
+	size_t i;
+	warnx("DUMP for %s", msg);
+	for (i = 0 ; i < be->cur_pos; i++)
+		warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff);
+}
+
+static inline int
+buffer_ext_add(struct buffer_ext *be, void *addr, size_t sz)
+{
+	void *tmp;
+	size_t be_sz = be->max_sz;
+
+retry:
+	if ((be->cur_pos + sz) < be_sz) {
+		memcpy(be->data + be->cur_pos, addr, sz);
+		be->cur_pos += sz;
+		return 0;
+	}
+
+	if (!be_sz)
+		be_sz = BUFFER_EXT_DFL_SIZE;
+	else
+		be_sz <<= 1;
+
+	tmp = realloc(be->data, be_sz);
+	if (!tmp)
+		return -1;
+
+	be->data   = tmp;
+	be->max_sz = be_sz;
+
+	goto retry;
+}
+
+static void
+buffer_ext_init(struct buffer_ext *be)
+{
+	be->data = NULL;
+	be->cur_pos = 0;
+	be->max_sz = 0;
+}
+
+static inline size_t
+buffer_ext_size(struct buffer_ext *be)
+{
+	return be->cur_pos;
+}
+
+static inline void *
+buffer_ext_addr(struct buffer_ext *be)
+{
+	return be->data;
+}
+
+struct debug_line_header {
+	// Not counting this field
+	uword total_length;
+	// version number (2 currently)
+	uhalf version;
+	// relative offset from next field to
+	// program statement
+	uword prolog_length;
+	ubyte minimum_instruction_length;
+	ubyte default_is_stmt;
+	// line_base - see DWARF 2 specs
+	sbyte line_base;
+	// line_range - see DWARF 2 specs
+	ubyte line_range;
+	// number of opcode + 1
+	ubyte opcode_base;
+	/* follow the array of opcode args nr: ubytes [nr_opcode_base] */
+	/* follow the search directories index, zero terminated string
+	 * terminated by an empty string.
+	 */
+	/* follow an array of { filename, LEB128, LEB128, LEB128 }, first is
+	 * the directory index entry, 0 means current directory, then mtime
+	 * and filesize, last entry is followed by en empty string.
+	 */
+	/* follow the first program statement */
+} __attribute__((packed));
+
+/* DWARF 2 spec talk only about one possible compilation unit header while
+ * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not
+ * related to the used arch, an ELF 32 can hold more than 4 Go of debug
+ * information. For now we handle only DWARF 2 32 bits comp unit. It'll only
+ * become a problem if we generate more than 4GB of debug information.
+ */
+struct compilation_unit_header {
+	uword total_length;
+	uhalf version;
+	uword debug_abbrev_offset;
+	ubyte pointer_size;
+} __attribute__((packed));
+
+#define DW_LNS_num_opcode (DW_LNS_set_isa + 1)
+
+/* field filled at run time are marked with -1 */
+static struct debug_line_header const default_debug_line_header = {
+	.total_length = -1,
+	.version = 2,
+	.prolog_length = -1,
+	.minimum_instruction_length = 1,	/* could be better when min instruction size != 1 */
+	.default_is_stmt = 1,	/* we don't take care about basic block */
+	.line_base = -5,	/* sensible value for line base ... */
+	.line_range = -14,     /* ... and line range are guessed statically */
+	.opcode_base = DW_LNS_num_opcode
+};
+
+static ubyte standard_opcode_length[] =
+{
+	0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
+};
+#if 0
+{
+	[DW_LNS_advance_pc]   = 1,
+	[DW_LNS_advance_line] = 1,
+	[DW_LNS_set_file] =  1,
+	[DW_LNS_set_column] = 1,
+	[DW_LNS_fixed_advance_pc] = 1,
+	[DW_LNS_set_isa] = 1,
+};
+#endif
+
+/* field filled at run time are marked with -1 */
+static struct compilation_unit_header default_comp_unit_header = {
+	.total_length = -1,
+	.version = 2,
+	.debug_abbrev_offset = 0,     /* we reuse the same abbrev entries for all comp unit */
+	.pointer_size = sizeof(void *)
+};
+
+static void emit_uword(struct buffer_ext *be, uword data)
+{
+	buffer_ext_add(be, &data, sizeof(uword));
+}
+
+static void emit_string(struct buffer_ext *be, const char *s)
+{
+	buffer_ext_add(be, (void *)s, strlen(s) + 1);
+}
+
+static void emit_unsigned_LEB128(struct buffer_ext *be,
+				 unsigned long data)
+{
+	do {
+		ubyte cur = data & 0x7F;
+		data >>= 7;
+		if (data)
+			cur |= 0x80;
+		buffer_ext_add(be, &cur, 1);
+	} while (data);
+}
+
+static void emit_signed_LEB128(struct buffer_ext *be, long data)
+{
+	int more = 1;
+	int negative = data < 0;
+	int size = sizeof(long) * CHAR_BIT;
+	while (more) {
+		ubyte cur = data & 0x7F;
+		data >>= 7;
+		if (negative)
+			data |= - (1 << (size - 7));
+		if ((data == 0 && !(cur & 0x40)) ||
+		    (data == -1l && (cur & 0x40)))
+			more = 0;
+		else
+			cur |= 0x80;
+		buffer_ext_add(be, &cur, 1);
+	}
+}
+
+static void emit_extended_opcode(struct buffer_ext *be, ubyte opcode,
+				 void *data, size_t data_len)
+{
+	buffer_ext_add(be, (char *)"", 1);
+
+	emit_unsigned_LEB128(be, data_len + 1);
+
+	buffer_ext_add(be, &opcode, 1);
+	buffer_ext_add(be, data, data_len);
+}
+
+static void emit_opcode(struct buffer_ext *be, ubyte opcode)
+{
+	buffer_ext_add(be, &opcode, 1);
+}
+
+static void emit_opcode_signed(struct buffer_ext  *be,
+			       ubyte opcode, long data)
+{
+	buffer_ext_add(be, &opcode, 1);
+	emit_signed_LEB128(be, data);
+}
+
+static void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode,
+				 unsigned long data)
+{
+	buffer_ext_add(be, &opcode, 1);
+	emit_unsigned_LEB128(be, data);
+}
+
+static void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc)
+{
+	emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc);
+}
+
+static void emit_advance_lineno(struct buffer_ext  *be, long delta_lineno)
+{
+	emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno);
+}
+
+static void emit_lne_end_of_sequence(struct buffer_ext *be)
+{
+	emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0);
+}
+
+static void emit_set_file(struct buffer_ext *be, unsigned long idx)
+{
+	emit_opcode_unsigned(be, DW_LNS_set_file, idx);
+}
+
+static void emit_lne_define_filename(struct buffer_ext *be,
+				     const char *filename)
+{
+	buffer_ext_add(be, (void *)"", 1);
+
+	/* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */
+	emit_unsigned_LEB128(be, strlen(filename) + 5);
+	emit_opcode(be, DW_LNE_define_file);
+	emit_string(be, filename);
+	/* directory index 0=do not know */
+        emit_unsigned_LEB128(be, 0);
+	/* last modification date on file 0=do not know */
+        emit_unsigned_LEB128(be, 0);
+	/* filesize 0=do not know */
+        emit_unsigned_LEB128(be, 0);
+}
+
+static void emit_lne_set_address(struct buffer_ext *be,
+				 void *address)
+{
+	emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long));
+}
+
+static ubyte get_special_opcode(struct debug_entry *ent,
+				unsigned int last_line,
+				unsigned long last_vma)
+{
+	unsigned int temp;
+	unsigned long delta_addr;
+
+	/*
+	 * delta from line_base
+	 */
+	temp = (ent->lineno - last_line) - default_debug_line_header.line_base;
+
+	if (temp >= default_debug_line_header.line_range)
+		return 0;
+
+	/*
+	 * delta of addresses
+	 */
+	delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length;
+
+	/* This is not sufficient to ensure opcode will be in [0-256] but
+	 * sufficient to ensure when summing with the delta lineno we will
+	 * not overflow the unsigned long opcode */
+
+	if (delta_addr <= 256 / default_debug_line_header.line_range) {
+		unsigned long opcode = temp +
+			(delta_addr * default_debug_line_header.line_range) +
+			default_debug_line_header.opcode_base;
+
+		return opcode <= 255 ? opcode : 0;
+	}
+	return 0;
+}
+
+static void emit_lineno_info(struct buffer_ext *be,
+			     struct debug_entry *ent, size_t nr_entry,
+			     unsigned long code_addr)
+{
+	size_t i;
+
+	/*
+	 * Machine state at start of a statement program
+	 * address = 0
+	 * file    = 1
+	 * line    = 1
+	 * column  = 0
+	 * is_stmt = default_is_stmt as given in the debug_line_header
+	 * basic block = 0
+	 * end sequence = 0
+	 */
+
+	/* start state of the state machine we take care of */
+	unsigned long last_vma = code_addr;
+	char const  *cur_filename = NULL;
+	unsigned long cur_file_idx = 0;
+	int last_line = 1;
+
+	emit_lne_set_address(be, (void *)code_addr);
+
+	for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) {
+		int need_copy = 0;
+		ubyte special_opcode;
+
+		/*
+		 * check if filename changed, if so add it
+		 */
+		if (!cur_filename || strcmp(cur_filename, ent->name)) {
+			emit_lne_define_filename(be, ent->name);
+			cur_filename = ent->name;
+			emit_set_file(be, ++cur_file_idx);
+			need_copy = 1;
+		}
+
+		special_opcode = get_special_opcode(ent, last_line, last_vma);
+		if (special_opcode != 0) {
+			last_line = ent->lineno;
+			last_vma  = ent->addr;
+			emit_opcode(be, special_opcode);
+		} else {
+			/*
+			 * lines differ, emit line delta
+			 */
+			if (last_line != ent->lineno) {
+				emit_advance_lineno(be, ent->lineno - last_line);
+				last_line = ent->lineno;
+				need_copy = 1;
+			}
+			/*
+			 * addresses differ, emit address delta
+			 */
+			if (last_vma != ent->addr) {
+				emit_advance_pc(be, ent->addr - last_vma);
+				last_vma = ent->addr;
+				need_copy = 1;
+			}
+			/*
+			 * add new row to matrix
+			 */
+			if (need_copy)
+				emit_opcode(be, DW_LNS_copy);
+		}
+	}
+}
+
+static void add_debug_line(struct buffer_ext *be,
+	struct debug_entry *ent, size_t nr_entry,
+	unsigned long code_addr)
+{
+	struct debug_line_header * dbg_header;
+	size_t old_size;
+
+	old_size = buffer_ext_size(be);
+
+	buffer_ext_add(be, (void *)&default_debug_line_header,
+		 sizeof(default_debug_line_header));
+
+	buffer_ext_add(be, &standard_opcode_length,  sizeof(standard_opcode_length));
+
+	// empty directory entry
+	buffer_ext_add(be, (void *)"", 1);
+
+	// empty filename directory
+	buffer_ext_add(be, (void *)"", 1);
+
+	dbg_header = buffer_ext_addr(be) + old_size;
+	dbg_header->prolog_length = (buffer_ext_size(be) - old_size) -
+		offsetof(struct debug_line_header, minimum_instruction_length);
+
+	emit_lineno_info(be, ent, nr_entry, code_addr);
+
+	emit_lne_end_of_sequence(be);
+
+	dbg_header = buffer_ext_addr(be) + old_size;
+	dbg_header->total_length = (buffer_ext_size(be) - old_size) -
+		offsetof(struct debug_line_header, version);
+}
+
+static void
+add_debug_abbrev(struct buffer_ext *be)
+{
+        emit_unsigned_LEB128(be, 1);
+        emit_unsigned_LEB128(be, DW_TAG_compile_unit);
+        emit_unsigned_LEB128(be, DW_CHILDREN_yes);
+        emit_unsigned_LEB128(be, DW_AT_stmt_list);
+        emit_unsigned_LEB128(be, DW_FORM_data4);
+        emit_unsigned_LEB128(be, 0);
+        emit_unsigned_LEB128(be, 0);
+        emit_unsigned_LEB128(be, 0);
+}
+
+static void
+add_compilation_unit(struct buffer_ext *be,
+		     size_t offset_debug_line)
+{
+	struct compilation_unit_header *comp_unit_header;
+	size_t old_size = buffer_ext_size(be);
+
+	buffer_ext_add(be, &default_comp_unit_header,
+		       sizeof(default_comp_unit_header));
+
+	emit_unsigned_LEB128(be, 1);
+	emit_uword(be, offset_debug_line);
+
+	comp_unit_header = buffer_ext_addr(be) + old_size;
+	comp_unit_header->total_length = (buffer_ext_size(be) - old_size) -
+		offsetof(struct compilation_unit_header, version);
+}
+
+static int
+jit_process_debug_info(uint64_t code_addr,
+		       void *debug, int nr_debug_entries,
+		       struct buffer_ext *dl,
+		       struct buffer_ext *da,
+		       struct buffer_ext *di)
+{
+	struct debug_entry *ent = debug;
+	int i;
+
+	for (i = 0; i < nr_debug_entries; i++) {
+		ent->addr = ent->addr - code_addr;
+		ent = debug_entry_next(ent);
+	}
+	add_compilation_unit(di, buffer_ext_size(dl));
+	add_debug_line(dl, debug, nr_debug_entries, 0);
+	add_debug_abbrev(da);
+	if (0) buffer_ext_dump(da, "abbrev");
+
+	return 0;
+}
+
+int
+jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries)
+{
+	Elf_Data *d;
+	Elf_Scn *scn;
+	Elf_Shdr *shdr;
+	struct buffer_ext dl, di, da;
+	int ret;
+
+	buffer_ext_init(&dl);
+	buffer_ext_init(&di);
+	buffer_ext_init(&da);
+
+	ret = jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di);
+	if (ret)
+		return -1;
+	/*
+	 * setup .debug_line section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		return -1;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		return -1;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = buffer_ext_addr(&dl);
+	d->d_type = ELF_T_BYTE;
+	d->d_size = buffer_ext_size(&dl);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		return -1;
+	}
+
+	shdr->sh_name = 52; /* .debug_line */
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup .debug_info section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		return -1;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		return -1;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = buffer_ext_addr(&di);
+	d->d_type = ELF_T_BYTE;
+	d->d_size = buffer_ext_size(&di);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		return -1;
+	}
+
+	shdr->sh_name = 64; /* .debug_info */
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup .debug_abbrev section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		return -1;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		return -1;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = buffer_ext_addr(&da);
+	d->d_type = ELF_T_BYTE;
+	d->d_size = buffer_ext_size(&da);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		return -1;
+	}
+
+	shdr->sh_name = 76; /* .debug_info */
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * now we update the ELF image with all the sections
+	 */
+	if (elf_update(e, ELF_C_WRITE) < 0) {
+		warnx("elf_update debug failed");
+		return -1;
+	}
+	return 0;
+}
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 9f7a012..99fa5ee 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -63,7 +63,9 @@ jit_emit_elf(char *filename,
 	     const char *sym,
 	     uint64_t code_addr,
 	     const void *code,
-	     int csize)
+	     int csize,
+	     void *debug,
+	     int nr_debug_entries)
 {
 	int ret, fd;
 
@@ -76,7 +78,7 @@ jit_emit_elf(char *filename,
 		return -1;
 	}
 
-        ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize);
+        ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries);
 
         close(fd);
 
@@ -347,7 +349,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 
 	size = PERF_ALIGN(size, sizeof(u64));
 	uaddr = (uintptr_t)code;
-	ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize);
+	ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries);
 
 	if (jd->debug_data && jd->nr_debug_entries) {
 		free(jd->debug_data);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2015-11-30  9:02 ` [PATCH v8 2/4] perf inject: add jitdump mmap injection support Stephane Eranian
@ 2016-01-22 20:44   ` Arnaldo Carvalho de Melo
  2016-01-22 21:22     ` Stephane Eranian
  2016-02-09 12:14   ` [tip:perf/core] perf build: Add libcrypto feature detection tip-bot for Stephane Eranian
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-01-22 20:44 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: linux-kernel, peterz, mingo, ak, jolsa, namhyung, cel, sukadev,
	sonnyrao, johnmccutchan, dsahern, adrian.hunter, pawel.moll,
	acme

Em Mon, Nov 30, 2015 at 10:02:21AM +0100, Stephane Eranian escreveu:
> 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

So, it fails 'make -C tools/perf build-test', specifically the one where
we ask for a NO_LIBELF build, trying to fix:

- make_no_libelf: cd . && make -f Makefile   DESTDIR=/tmp/tmp.AzIgKZ2Y7K NO_LIBELF=1
cd . && make -f Makefile DESTDIR=/tmp/tmp.AzIgKZ2Y7K NO_LIBELF=1
  BUILD:   Doing 'make -j4' parallel build

Auto-detecting system features:
...                         dwarf: [ on  ]
...                         glibc: [ on  ]
...                          gtk2: [ on  ]
...                      libaudit: [ on  ]
...                        libbfd: [ on  ]
...                        libelf: [ on  ]
...                       libnuma: [ on  ]
...        numa_num_possible_cpus: [ on  ]
...                       libperl: [ on  ]
...                     libpython: [ on  ]
...                      libslang: [ on  ]
...                     libcrypto: [ on  ]
...                     libunwind: [ on  ]
...            libdw-dwarf-unwind: [ OFF ]
...                          zlib: [ on  ]
...                          lzma: [ on  ]
...                     get_cpuid: [ on  ]
...                           bpf: [ on  ]

config/Makefile:364: Disabling post unwind, no support found.
  GEN      common-cmds.h
  CC       fd/array.o
  CC       util/abspath.o
  LD       fd/libapi-in.o
  CC       fs/fs.o
  CC       fs/tracing_path.o
  LD       fs/libapi-in.o
  CC       cpu.o
  CC       event-parse.o
  LD       libapi-in.o
  AR       libapi.a
  CC       util/alias.o
  CC       event-plugin.o
  CC       trace-seq.o
  CC       parse-filter.o
  CC       parse-utils.o
  CC       kbuffer-parse.o
  CC       arch/common.o
  LD       libtraceevent-in.o
  LINK     libtraceevent.a
  CC       exec-cmd.o
  PERF_VERSION = 4.4.gac64671
  CC       help.o
  CC       plugin_jbd2.o
  CC       util/annotate.o
  CC       pager.o
  LD       plugin_jbd2-in.o
  CC       plugin_hrtimer.o
  CC       parse-options.o
  LD       plugin_hrtimer-in.o
  CC       plugin_kmem.o
  CC       run-command.o
  CC       arch/x86/util/header.o
  LD       plugin_kmem-in.o
  CC       sigchain.o
  CC       plugin_kvm.o
  CC       subcmd-config.o
  LD       plugin_kvm-in.o
  CC       plugin_mac80211.o
  LD       libsubcmd-in.o
  AR       libsubcmd.a
  CC       arch/x86/util/tsc.o
  LD       plugin_mac80211-in.o
  CC       plugin_sched_switch.o
  CC       arch/x86/util/pmu.o
  LD       plugin_sched_switch-in.o
  CC       plugin_function.o
  CC       plugin_xen.o
  LD       plugin_function-in.o
  CC       arch/x86/util/kvm-stat.o
  CC       plugin_scsi.o
  LD       plugin_xen-in.o
  CC       plugin_cfg80211.o
  LD       plugin_scsi-in.o
  LINK     plugin_jbd2.so
  LD       plugin_cfg80211-in.o
  LINK     plugin_hrtimer.so
  CC       arch/x86/tests/arch-tests.o
  LINK     plugin_kmem.so
  CC       arch/x86/tests/rdpmc.o
  LINK     plugin_kvm.so
  LINK     plugin_mac80211.so
  LINK     plugin_sched_switch.so
  LINK     plugin_function.so
  LINK     plugin_xen.so
  CC       arch/x86/util/perf_regs.o
  LINK     plugin_scsi.so
  LINK     plugin_cfg80211.so
  CC       arch/x86/tests/perf-time-to-tsc.o
  GEN      perf-archive
  CC       arch/x86/util/auxtrace.o
  GEN      perf-with-kcore
  CC       ui/gtk/browser.o
  CC       util/build-id.o
  CC       arch/x86/util/intel-pt.o
  CC       arch/x86/tests/insn-x86.o
  CC       arch/x86/tests/intel-cqm.o
  CC       util/config.o
  CC       ui/gtk/hists.o
  CC       arch/x86/util/intel-bts.o
  LD       arch/x86/tests/libperf-in.o
  CC       util/ctype.o
  CC       util/db-export.o
  CC       util/env.o
  LD       arch/x86/util/libperf-in.o
  LD       arch/x86/libperf-in.o
  LD       arch/libperf-in.o
  CC       ui/setup.o
  CC       util/event.o
  CC       util/evlist.o
  CC       ui/helpline.o
  CC       ui/gtk/setup.o
  CC       ui/progress.o
  CC       ui/util.o
  CC       util/evsel.o
  CC       ui/gtk/util.o
  CC       ui/hist.o
  CC       util/find_bit.o
  CC       ui/gtk/helpline.o
  CC       util/kallsyms.o
  CC       util/levenshtein.o
  CC       ui/gtk/progress.o
  CC       util/llvm-utils.o
  BISON    util/parse-events-bison.c
  CC       util/perf_regs.o
  CC       ui/gtk/annotate.o
  CC       util/path.o
  CC       util/rbtree.o
  CC       util/libstring.o
  CC       ui/stdio/hist.o
  CC       util/bitmap.o
  CC       util/hweight.o
  CC       util/quote.o
  CC       util/strbuf.o
  LD       ui/gtk/gtk-in.o
  LD       gtk-in.o
  CC       util/string.o
  CC       builtin-bench.o
  CC       ui/browser.o
  CC       util/strlist.o
  CC       builtin-annotate.o
  CC       util/strfilter.o
  CC       util/top.o
  CC       builtin-config.o
  CC       ui/browsers/annotate.o
  CC       util/usage.o
  CC       builtin-diff.o
  CC       util/wrapper.o
  CC       util/dso.o
  CC       util/symbol.o
  CC       ui/browsers/hists.o
  CC       builtin-evlist.o
  CC       builtin-help.o
  CC       ui/tui/setup.o
  CC       util/color.o
  CC       builtin-sched.o
  CC       ui/tui/util.o
  CC       util/header.o
  CC       ui/tui/helpline.o
  CC       ui/tui/progress.o
  LD       ui/tui/libperf-in.o
  CC       builtin-buildid-list.o
  CC       builtin-buildid-cache.o
  CC       builtin-list.o
  CC       builtin-record.o
  CC       builtin-report.o
  CC       ui/browsers/map.o
  CC       util/callchain.o
  CC       ui/browsers/scripts.o
  CC       builtin-stat.o
  CC       builtin-timechart.o
  CC       ui/browsers/header.o
  LD       ui/browsers/libperf-in.o
  LD       ui/libperf-in.o
  CC       util/values.o
  CC       scripts/perl/Perf-Trace-Util/Context.o
  CC       util/debug.o
  CC       builtin-top.o
  LD       scripts/perl/Perf-Trace-Util/libperf-in.o
  CC       scripts/python/Perf-Trace-Util/Context.o
  CC       builtin-script.o
  CC       util/machine.o
  LD       scripts/python/Perf-Trace-Util/libperf-in.o
  LD       scripts/libperf-in.o
  CC       util/map.o
  CC       builtin-kmem.o
  CC       util/pstack.o
  CC       util/session.o
  CC       util/ordered-events.o
  CC       builtin-lock.o
  CC       util/comm.o
  CC       builtin-kvm.o
  CC       util/thread.o
  CC       util/thread_map.o
  CC       util/trace-event-parse.o
  CC       builtin-inject.o
  CC       builtin-mem.o
  CC       builtin-data.o
  CC       util/parse-events-bison.o
  CC       builtin-version.o
  CC       builtin-trace.o
  CC       bench/sched-messaging.o
  CC       tests/builtin-test.o
  BISON    util/pmu-bison.c
  CC       bench/sched-pipe.o
  CC       util/trace-event-read.o
  CC       tests/parse-events.o
  CC       bench/mem-functions.o
  CC       util/trace-event-info.o
  CC       bench/futex-hash.o
  CC       util/trace-event-scripting.o
  CC       bench/futex-wake.o
  CC       util/trace-event.o
  CC       perf.o
  CC       bench/futex-wake-parallel.o
  CC       util/svghelper.o
  CC       tests/dso-data.o
  CC       bench/futex-requeue.o
  CC       bench/futex-lock-pi.o
  CC       bench/mem-memcpy-x86-64-asm.o
  CC       bench/mem-memset-x86-64-asm.o
  CC       bench/numa.o
  CC       tests/attr.o
  CC       tests/vmlinux-kallsyms.o
  CC       util/sort.o
  CC       tests/openat-syscall.o
  CC       tests/openat-syscall-all-cpus.o
  CC       tests/openat-syscall-tp-fields.o
  CC       tests/mmap-basic.o
  CC       tests/perf-record.o
  LD       bench/perf-in.o
  CC       tests/evsel-roundtrip-name.o
  CC       tests/evsel-tp-sched.o
  CC       tests/fdarray.o
  CC       tests/pmu.o
  CC       tests/hists_common.o
  CC       tests/hists_link.o
  CC       util/hist.o
  CC       tests/hists_filter.o
  CC       tests/hists_output.o
  CC       tests/hists_cumulate.o
  CC       tests/python-use.o
  CC       tests/bp_signal.o
  CC       util/util.o
  CC       util/xyarray.o
  CC       tests/bp_signal_overflow.o
  CC       util/cpumap.o
  CC       util/cgroup.o
  CC       tests/task-exit.o
  CC       util/target.o
  CC       tests/sw-clock.o
  CC       util/rblist.o
  CC       util/intlist.o
  CC       util/vdso.o
  CC       util/counts.o
  CC       tests/mmap-thread-lookup.o
  CC       tests/thread-mg-share.o
  CC       util/stat.o
  CC       util/stat-shadow.o
  CC       tests/switch-tracking.o
  CC       tests/keep-tracking.o
  CC       util/record.o
  CC       util/srcline.o
  CC       tests/code-reading.o
  CC       tests/sample-parsing.o
  CC       util/data.o
  CC       tests/parse-no-sample-id-all.o
  CC       util/tsc.o
  CC       util/cloexec.o
  CC       tests/kmod-path.o
  CC       util/thread-stack.o
  CC       tests/thread-map.o
  CC       util/auxtrace.o
  CC       tests/llvm.o
  CC       tests/bpf.o
  CC       util/intel-pt-decoder/intel-pt-pkt-decoder.o
  CC       tests/topology.o
  CC       tests/cpumap.o
  GEN      util/intel-pt-decoder/inat-tables.c
  CC       util/scripting-engines/trace-event-perl.o
  CC       util/intel-pt-decoder/intel-pt-log.o
  CC       tests/stat.o
  CC       tests/event_update.o
  CC       util/intel-pt-decoder/intel-pt-decoder.o
  CC       tests/llvm-src-base.o
  CC       tests/llvm-src-kbuild.o
  CC       tests/llvm-src-prologue.o
  CC       util/scripting-engines/trace-event-python.o
  LD       tests/perf-in.o
  LD       perf-in.o
  CC       util/intel-pt.o
  CC       util/intel-bts.o
  LD       util/scripting-engines/libperf-in.o
  CC       util/parse-branch-options.o
  GEN      libtraceevent-dynamic-list
  CC       util/intel-pt-decoder/intel-pt-insn-decoder.o
  CC       util/parse-regs-options.o
  CC       util/term.o
  CC       util/help-unknown-cmd.o
  CC       util/symbol-minimal.o
  CC       util/zlib.o
  GEN      python/perf.so
  CC       util/lzma.o
  LD       util/intel-pt-decoder/libperf-in.o
  CC       util/demangle-java.o
  CC       util/jitdump.o
  CC       util/genelf.o
  FLEX     util/parse-events-flex.c
  FLEX     util/pmu-flex.c
  CC       util/pmu-bison.o
  CC       util/parse-events.o
  CC       util/parse-events-flex.o
  CC       util/pmu.o
  CC       util/pmu-flex.o
  LD       util/libperf-in.o
  LD       libperf-in.o
  AR       libperf.a
  LINK     perf
  LINK     libperf-gtk.so
libperf.a(libperf-in.o): In function `jit_write_elf':
/home/acme/git/linux/tools/perf/util/genelf.c:170: undefined reference to `elf_version'
/home/acme/git/linux/tools/perf/util/genelf.c:175: undefined reference to `elf_begin'
/home/acme/git/linux/tools/perf/util/genelf.c:184: undefined reference to `elf64_newehdr'
/home/acme/git/linux/tools/perf/util/genelf.c:201: undefined reference to `elf_newscn'
/home/acme/git/linux/tools/perf/util/genelf.c:207: undefined reference to `elf_newdata'
/home/acme/git/linux/tools/perf/util/genelf.c:220: undefined reference to `elf64_getshdr'
/home/acme/git/linux/tools/perf/util/genelf.c:235: undefined reference to `elf_newscn'
/home/acme/git/linux/tools/perf/util/genelf.c:241: undefined reference to `elf_newdata'
/home/acme/git/linux/tools/perf/util/genelf.c:254: undefined reference to `elf64_getshdr'
/home/acme/git/linux/tools/perf/util/genelf.c:271: undefined reference to `elf_newscn'
/home/acme/git/linux/tools/perf/util/genelf.c:277: undefined reference to `elf_newdata'
/home/acme/git/linux/tools/perf/util/genelf.c:290: undefined reference to `elf64_getshdr'
/home/acme/git/linux/tools/perf/util/genelf.c:314: undefined reference to `elf_newscn'
/home/acme/git/linux/tools/perf/util/genelf.c:320: undefined reference to `elf_newdata'
/home/acme/git/linux/tools/perf/util/genelf.c:333: undefined reference to `elf64_getshdr'
/home/acme/git/linux/tools/perf/util/genelf.c:347: undefined reference to `elf_newscn'
/home/acme/git/linux/tools/perf/util/genelf.c:353: undefined reference to `elf_newdata'
/home/acme/git/linux/tools/perf/util/genelf.c:375: undefined reference to `elf64_getshdr'
/home/acme/git/linux/tools/perf/util/genelf.c:388: undefined reference to `elf_update'
/home/acme/git/linux/tools/perf/util/genelf.c:395: undefined reference to `elf_end'
collect2: error: ld returned 1 exit status
Makefile.perf:333: recipe for target 'perf' failed
make[4]: *** [perf] Error 1
make[4]: *** Waiting for unfinished jobs....
Makefile:68: recipe for target 'all' failed
make[3]: *** [all] Error 2
  test: test -x ./perf
tests/make:273: recipe for target 'make_no_libelf' failed
make[2]: *** [make_no_libelf] Error 1
tests/make:7: recipe for target 'all' failed
make[1]: *** [all] Error 2
Makefile:81: recipe for target 'build-test' failed
make: *** [build-test] Error 2
make: Leaving directory '/home/acme/git/linux/tools/perf'

 Performance counter stats for 'make -C tools/perf build-test':

    1007267.820554      task-clock (msec)         #    2.516 CPUs utilized          
           591,484      context-switches          #    0.587 K/sec                  
            66,439      cpu-migrations            #    0.066 K/sec                  
        26,771,257      page-faults               #    0.027 M/sec                  
 2,863,648,588,724      cycles                    #    2.843 GHz                    
   <not supported>      stalled-cycles-frontend  
   <not supported>      stalled-cycles-backend   
 2,459,464,718,802      instructions              #    0.86  insns per cycle        
   547,848,880,912      branches                  #  543.896 M/sec                  
    14,513,951,279      branch-misses             #    2.65% of all branches        

     400.280077927 seconds time elapsed

[acme@jouet linux]$ 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-01-22 20:44   ` Arnaldo Carvalho de Melo
@ 2016-01-22 21:22     ` Stephane Eranian
       [not found]       ` <20160122215542.GK4034@kernel.org>
  2016-02-04 21:53       ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 27+ messages in thread
From: Stephane Eranian @ 2016-01-22 21:22 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: LKML, Peter Zijlstra, mingo, ak, Jiri Olsa, Namhyung Kim,
	Rose Belcher, Sukadev Bhattiprolu, Sonny Rao, John Mccutchan,
	David Ahern, Adrian Hunter, Pawel Moll, Arnaldo Carvalho de Melo

On Fri, Jan 22, 2016 at 12:44 PM, Arnaldo Carvalho de Melo
<acme@redhat.com> wrote:
> Em Mon, Nov 30, 2015 at 10:02:21AM +0100, Stephane Eranian escreveu:
>> 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
>
> So, it fails 'make -C tools/perf build-test', specifically the one where
> we ask for a NO_LIBELF build, trying to fix:
>
I have rebase to tip.git last night. Will try your branch today.
Will add a couple of minor adjustments and also better documentation
on how to use it.

> - make_no_libelf: cd . && make -f Makefile   DESTDIR=/tmp/tmp.AzIgKZ2Y7K NO_LIBELF=1
> cd . && make -f Makefile DESTDIR=/tmp/tmp.AzIgKZ2Y7K NO_LIBELF=1
>   BUILD:   Doing 'make -j4' parallel build
>
> Auto-detecting system features:
> ...                         dwarf: [ on  ]
> ...                         glibc: [ on  ]
> ...                          gtk2: [ on  ]
> ...                      libaudit: [ on  ]
> ...                        libbfd: [ on  ]
> ...                        libelf: [ on  ]
> ...                       libnuma: [ on  ]
> ...        numa_num_possible_cpus: [ on  ]
> ...                       libperl: [ on  ]
> ...                     libpython: [ on  ]
> ...                      libslang: [ on  ]
> ...                     libcrypto: [ on  ]
> ...                     libunwind: [ on  ]
> ...            libdw-dwarf-unwind: [ OFF ]
> ...                          zlib: [ on  ]
> ...                          lzma: [ on  ]
> ...                     get_cpuid: [ on  ]
> ...                           bpf: [ on  ]
>
> config/Makefile:364: Disabling post unwind, no support found.
>   GEN      common-cmds.h
>   CC       fd/array.o
>   CC       util/abspath.o
>   LD       fd/libapi-in.o
>   CC       fs/fs.o
>   CC       fs/tracing_path.o
>   LD       fs/libapi-in.o
>   CC       cpu.o
>   CC       event-parse.o
>   LD       libapi-in.o
>   AR       libapi.a
>   CC       util/alias.o
>   CC       event-plugin.o
>   CC       trace-seq.o
>   CC       parse-filter.o
>   CC       parse-utils.o
>   CC       kbuffer-parse.o
>   CC       arch/common.o
>   LD       libtraceevent-in.o
>   LINK     libtraceevent.a
>   CC       exec-cmd.o
>   PERF_VERSION = 4.4.gac64671
>   CC       help.o
>   CC       plugin_jbd2.o
>   CC       util/annotate.o
>   CC       pager.o
>   LD       plugin_jbd2-in.o
>   CC       plugin_hrtimer.o
>   CC       parse-options.o
>   LD       plugin_hrtimer-in.o
>   CC       plugin_kmem.o
>   CC       run-command.o
>   CC       arch/x86/util/header.o
>   LD       plugin_kmem-in.o
>   CC       sigchain.o
>   CC       plugin_kvm.o
>   CC       subcmd-config.o
>   LD       plugin_kvm-in.o
>   CC       plugin_mac80211.o
>   LD       libsubcmd-in.o
>   AR       libsubcmd.a
>   CC       arch/x86/util/tsc.o
>   LD       plugin_mac80211-in.o
>   CC       plugin_sched_switch.o
>   CC       arch/x86/util/pmu.o
>   LD       plugin_sched_switch-in.o
>   CC       plugin_function.o
>   CC       plugin_xen.o
>   LD       plugin_function-in.o
>   CC       arch/x86/util/kvm-stat.o
>   CC       plugin_scsi.o
>   LD       plugin_xen-in.o
>   CC       plugin_cfg80211.o
>   LD       plugin_scsi-in.o
>   LINK     plugin_jbd2.so
>   LD       plugin_cfg80211-in.o
>   LINK     plugin_hrtimer.so
>   CC       arch/x86/tests/arch-tests.o
>   LINK     plugin_kmem.so
>   CC       arch/x86/tests/rdpmc.o
>   LINK     plugin_kvm.so
>   LINK     plugin_mac80211.so
>   LINK     plugin_sched_switch.so
>   LINK     plugin_function.so
>   LINK     plugin_xen.so
>   CC       arch/x86/util/perf_regs.o
>   LINK     plugin_scsi.so
>   LINK     plugin_cfg80211.so
>   CC       arch/x86/tests/perf-time-to-tsc.o
>   GEN      perf-archive
>   CC       arch/x86/util/auxtrace.o
>   GEN      perf-with-kcore
>   CC       ui/gtk/browser.o
>   CC       util/build-id.o
>   CC       arch/x86/util/intel-pt.o
>   CC       arch/x86/tests/insn-x86.o
>   CC       arch/x86/tests/intel-cqm.o
>   CC       util/config.o
>   CC       ui/gtk/hists.o
>   CC       arch/x86/util/intel-bts.o
>   LD       arch/x86/tests/libperf-in.o
>   CC       util/ctype.o
>   CC       util/db-export.o
>   CC       util/env.o
>   LD       arch/x86/util/libperf-in.o
>   LD       arch/x86/libperf-in.o
>   LD       arch/libperf-in.o
>   CC       ui/setup.o
>   CC       util/event.o
>   CC       util/evlist.o
>   CC       ui/helpline.o
>   CC       ui/gtk/setup.o
>   CC       ui/progress.o
>   CC       ui/util.o
>   CC       util/evsel.o
>   CC       ui/gtk/util.o
>   CC       ui/hist.o
>   CC       util/find_bit.o
>   CC       ui/gtk/helpline.o
>   CC       util/kallsyms.o
>   CC       util/levenshtein.o
>   CC       ui/gtk/progress.o
>   CC       util/llvm-utils.o
>   BISON    util/parse-events-bison.c
>   CC       util/perf_regs.o
>   CC       ui/gtk/annotate.o
>   CC       util/path.o
>   CC       util/rbtree.o
>   CC       util/libstring.o
>   CC       ui/stdio/hist.o
>   CC       util/bitmap.o
>   CC       util/hweight.o
>   CC       util/quote.o
>   CC       util/strbuf.o
>   LD       ui/gtk/gtk-in.o
>   LD       gtk-in.o
>   CC       util/string.o
>   CC       builtin-bench.o
>   CC       ui/browser.o
>   CC       util/strlist.o
>   CC       builtin-annotate.o
>   CC       util/strfilter.o
>   CC       util/top.o
>   CC       builtin-config.o
>   CC       ui/browsers/annotate.o
>   CC       util/usage.o
>   CC       builtin-diff.o
>   CC       util/wrapper.o
>   CC       util/dso.o
>   CC       util/symbol.o
>   CC       ui/browsers/hists.o
>   CC       builtin-evlist.o
>   CC       builtin-help.o
>   CC       ui/tui/setup.o
>   CC       util/color.o
>   CC       builtin-sched.o
>   CC       ui/tui/util.o
>   CC       util/header.o
>   CC       ui/tui/helpline.o
>   CC       ui/tui/progress.o
>   LD       ui/tui/libperf-in.o
>   CC       builtin-buildid-list.o
>   CC       builtin-buildid-cache.o
>   CC       builtin-list.o
>   CC       builtin-record.o
>   CC       builtin-report.o
>   CC       ui/browsers/map.o
>   CC       util/callchain.o
>   CC       ui/browsers/scripts.o
>   CC       builtin-stat.o
>   CC       builtin-timechart.o
>   CC       ui/browsers/header.o
>   LD       ui/browsers/libperf-in.o
>   LD       ui/libperf-in.o
>   CC       util/values.o
>   CC       scripts/perl/Perf-Trace-Util/Context.o
>   CC       util/debug.o
>   CC       builtin-top.o
>   LD       scripts/perl/Perf-Trace-Util/libperf-in.o
>   CC       scripts/python/Perf-Trace-Util/Context.o
>   CC       builtin-script.o
>   CC       util/machine.o
>   LD       scripts/python/Perf-Trace-Util/libperf-in.o
>   LD       scripts/libperf-in.o
>   CC       util/map.o
>   CC       builtin-kmem.o
>   CC       util/pstack.o
>   CC       util/session.o
>   CC       util/ordered-events.o
>   CC       builtin-lock.o
>   CC       util/comm.o
>   CC       builtin-kvm.o
>   CC       util/thread.o
>   CC       util/thread_map.o
>   CC       util/trace-event-parse.o
>   CC       builtin-inject.o
>   CC       builtin-mem.o
>   CC       builtin-data.o
>   CC       util/parse-events-bison.o
>   CC       builtin-version.o
>   CC       builtin-trace.o
>   CC       bench/sched-messaging.o
>   CC       tests/builtin-test.o
>   BISON    util/pmu-bison.c
>   CC       bench/sched-pipe.o
>   CC       util/trace-event-read.o
>   CC       tests/parse-events.o
>   CC       bench/mem-functions.o
>   CC       util/trace-event-info.o
>   CC       bench/futex-hash.o
>   CC       util/trace-event-scripting.o
>   CC       bench/futex-wake.o
>   CC       util/trace-event.o
>   CC       perf.o
>   CC       bench/futex-wake-parallel.o
>   CC       util/svghelper.o
>   CC       tests/dso-data.o
>   CC       bench/futex-requeue.o
>   CC       bench/futex-lock-pi.o
>   CC       bench/mem-memcpy-x86-64-asm.o
>   CC       bench/mem-memset-x86-64-asm.o
>   CC       bench/numa.o
>   CC       tests/attr.o
>   CC       tests/vmlinux-kallsyms.o
>   CC       util/sort.o
>   CC       tests/openat-syscall.o
>   CC       tests/openat-syscall-all-cpus.o
>   CC       tests/openat-syscall-tp-fields.o
>   CC       tests/mmap-basic.o
>   CC       tests/perf-record.o
>   LD       bench/perf-in.o
>   CC       tests/evsel-roundtrip-name.o
>   CC       tests/evsel-tp-sched.o
>   CC       tests/fdarray.o
>   CC       tests/pmu.o
>   CC       tests/hists_common.o
>   CC       tests/hists_link.o
>   CC       util/hist.o
>   CC       tests/hists_filter.o
>   CC       tests/hists_output.o
>   CC       tests/hists_cumulate.o
>   CC       tests/python-use.o
>   CC       tests/bp_signal.o
>   CC       util/util.o
>   CC       util/xyarray.o
>   CC       tests/bp_signal_overflow.o
>   CC       util/cpumap.o
>   CC       util/cgroup.o
>   CC       tests/task-exit.o
>   CC       util/target.o
>   CC       tests/sw-clock.o
>   CC       util/rblist.o
>   CC       util/intlist.o
>   CC       util/vdso.o
>   CC       util/counts.o
>   CC       tests/mmap-thread-lookup.o
>   CC       tests/thread-mg-share.o
>   CC       util/stat.o
>   CC       util/stat-shadow.o
>   CC       tests/switch-tracking.o
>   CC       tests/keep-tracking.o
>   CC       util/record.o
>   CC       util/srcline.o
>   CC       tests/code-reading.o
>   CC       tests/sample-parsing.o
>   CC       util/data.o
>   CC       tests/parse-no-sample-id-all.o
>   CC       util/tsc.o
>   CC       util/cloexec.o
>   CC       tests/kmod-path.o
>   CC       util/thread-stack.o
>   CC       tests/thread-map.o
>   CC       util/auxtrace.o
>   CC       tests/llvm.o
>   CC       tests/bpf.o
>   CC       util/intel-pt-decoder/intel-pt-pkt-decoder.o
>   CC       tests/topology.o
>   CC       tests/cpumap.o
>   GEN      util/intel-pt-decoder/inat-tables.c
>   CC       util/scripting-engines/trace-event-perl.o
>   CC       util/intel-pt-decoder/intel-pt-log.o
>   CC       tests/stat.o
>   CC       tests/event_update.o
>   CC       util/intel-pt-decoder/intel-pt-decoder.o
>   CC       tests/llvm-src-base.o
>   CC       tests/llvm-src-kbuild.o
>   CC       tests/llvm-src-prologue.o
>   CC       util/scripting-engines/trace-event-python.o
>   LD       tests/perf-in.o
>   LD       perf-in.o
>   CC       util/intel-pt.o
>   CC       util/intel-bts.o
>   LD       util/scripting-engines/libperf-in.o
>   CC       util/parse-branch-options.o
>   GEN      libtraceevent-dynamic-list
>   CC       util/intel-pt-decoder/intel-pt-insn-decoder.o
>   CC       util/parse-regs-options.o
>   CC       util/term.o
>   CC       util/help-unknown-cmd.o
>   CC       util/symbol-minimal.o
>   CC       util/zlib.o
>   GEN      python/perf.so
>   CC       util/lzma.o
>   LD       util/intel-pt-decoder/libperf-in.o
>   CC       util/demangle-java.o
>   CC       util/jitdump.o
>   CC       util/genelf.o
>   FLEX     util/parse-events-flex.c
>   FLEX     util/pmu-flex.c
>   CC       util/pmu-bison.o
>   CC       util/parse-events.o
>   CC       util/parse-events-flex.o
>   CC       util/pmu.o
>   CC       util/pmu-flex.o
>   LD       util/libperf-in.o
>   LD       libperf-in.o
>   AR       libperf.a
>   LINK     perf
>   LINK     libperf-gtk.so
> libperf.a(libperf-in.o): In function `jit_write_elf':
> /home/acme/git/linux/tools/perf/util/genelf.c:170: undefined reference to `elf_version'
> /home/acme/git/linux/tools/perf/util/genelf.c:175: undefined reference to `elf_begin'
> /home/acme/git/linux/tools/perf/util/genelf.c:184: undefined reference to `elf64_newehdr'
> /home/acme/git/linux/tools/perf/util/genelf.c:201: undefined reference to `elf_newscn'
> /home/acme/git/linux/tools/perf/util/genelf.c:207: undefined reference to `elf_newdata'
> /home/acme/git/linux/tools/perf/util/genelf.c:220: undefined reference to `elf64_getshdr'
> /home/acme/git/linux/tools/perf/util/genelf.c:235: undefined reference to `elf_newscn'
> /home/acme/git/linux/tools/perf/util/genelf.c:241: undefined reference to `elf_newdata'
> /home/acme/git/linux/tools/perf/util/genelf.c:254: undefined reference to `elf64_getshdr'
> /home/acme/git/linux/tools/perf/util/genelf.c:271: undefined reference to `elf_newscn'
> /home/acme/git/linux/tools/perf/util/genelf.c:277: undefined reference to `elf_newdata'
> /home/acme/git/linux/tools/perf/util/genelf.c:290: undefined reference to `elf64_getshdr'
> /home/acme/git/linux/tools/perf/util/genelf.c:314: undefined reference to `elf_newscn'
> /home/acme/git/linux/tools/perf/util/genelf.c:320: undefined reference to `elf_newdata'
> /home/acme/git/linux/tools/perf/util/genelf.c:333: undefined reference to `elf64_getshdr'
> /home/acme/git/linux/tools/perf/util/genelf.c:347: undefined reference to `elf_newscn'
> /home/acme/git/linux/tools/perf/util/genelf.c:353: undefined reference to `elf_newdata'
> /home/acme/git/linux/tools/perf/util/genelf.c:375: undefined reference to `elf64_getshdr'
> /home/acme/git/linux/tools/perf/util/genelf.c:388: undefined reference to `elf_update'
> /home/acme/git/linux/tools/perf/util/genelf.c:395: undefined reference to `elf_end'
> collect2: error: ld returned 1 exit status
> Makefile.perf:333: recipe for target 'perf' failed
> make[4]: *** [perf] Error 1
> make[4]: *** Waiting for unfinished jobs....
> Makefile:68: recipe for target 'all' failed
> make[3]: *** [all] Error 2
>   test: test -x ./perf
> tests/make:273: recipe for target 'make_no_libelf' failed
> make[2]: *** [make_no_libelf] Error 1
> tests/make:7: recipe for target 'all' failed
> make[1]: *** [all] Error 2
> Makefile:81: recipe for target 'build-test' failed
> make: *** [build-test] Error 2
> make: Leaving directory '/home/acme/git/linux/tools/perf'
>
>  Performance counter stats for 'make -C tools/perf build-test':
>
>     1007267.820554      task-clock (msec)         #    2.516 CPUs utilized
>            591,484      context-switches          #    0.587 K/sec
>             66,439      cpu-migrations            #    0.066 K/sec
>         26,771,257      page-faults               #    0.027 M/sec
>  2,863,648,588,724      cycles                    #    2.843 GHz
>    <not supported>      stalled-cycles-frontend
>    <not supported>      stalled-cycles-backend
>  2,459,464,718,802      instructions              #    0.86  insns per cycle
>    547,848,880,912      branches                  #  543.896 M/sec
>     14,513,951,279      branch-misses             #    2.65% of all branches
>
>      400.280077927 seconds time elapsed
>
> [acme@jouet linux]$
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
       [not found]         ` <20160122220929.GL4034@kernel.org>
@ 2016-01-22 22:10           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-01-22 22:10 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, mingo, ak, Jiri Olsa, Namhyung Kim,
	Rose Belcher, Sukadev Bhattiprolu, Sonny Rao, John Mccutchan,
	David Ahern, Adrian Hunter, Pawel Moll

Em Fri, Jan 22, 2016 at 07:09:29PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Fri, Jan 22, 2016 at 06:55:42PM -0300, Arnaldo Carvalho de Melo escreveu:
> > Em Fri, Jan 22, 2016 at 01:22:51PM -0800, Stephane Eranian escreveu:
> > > On Fri, Jan 22, 2016 at 12:44 PM, Arnaldo Carvalho de Melo
> > > > So, it fails 'make -C tools/perf build-test', specifically the one where
> > > > we ask for a NO_LIBELF build, trying to fix:
> 
> > > I have rebase to tip.git last night. Will try your branch today.
> > > Will add a couple of minor adjustments and also better documentation
> > > on how to use it.
> > 
> > Ok, but please work on top of my branch, that I'll push soon, for
> > instance, I had to fold the patch below, to fix the NO_LIBELF=1 case,
> > so, when one builds that way perf inject -h will say:
> > 
> > [acme@jouet linux]$ tools/perf/perf inject -h
> > 
> >  Usage: perf inject [<options>]
> > 
> >     -j, --jit             merge jitdump files into perf.data file
> >                           (not built-in because NO_LIBELF=1)
> > 
> > [acme@jouet linux]$ 
> > 
> > I did some other changes and carved out two bits into separate patches,
> > will soon push what I have to a perf/jit branch in my tree so that you
> > can take a look.
> 
> There, I just pushed it to:
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git perf/jit
> 
> More specifically:
> 
> https://git.kernel.org/cgit/linux/kernel/git/acme/linux.git/commit/?h=perf/jit&id=0be8362109bb431e50bbc10d167fb2748c90ffb4
> 
> And the branch in gitweb:
> 
> https://git.kernel.org/cgit/linux/kernel/git/acme/linux.git/log/?h=perf/jit
> 
> Haven't looked at these yet:
> 
>  1907 N C 11/30 Stephane Erania ( 27K) ┌─>[PATCH v8 4/4] perf/jit: add source line info support
>  1908   C 11/30 Stephane Erania ( 20K) ├─>[PATCH v8 3/4] perf tools: add JVMTI agent library
> 
> Then I'll have to test them one by one, following your detailed
> instructions, thanks for that!

And, FYI, this branch is holding up so far:


[acme@jouet linux]$ perf stat make -C tools/perf build-test
make: Entering directory '/home/acme/git/linux/tools/perf'
Testing Makefile
- make_tags: cd . && make -f Makefile   DESTDIR=/tmp/tmp.IzTl6vhMbZ tags
- make_no_libelf: cd . && make -f Makefile   DESTDIR=/tmp/tmp.PSI0yBKcc8 NO_LIBELF=1
- make_no_libnuma: cd . && make -f Makefile   DESTDIR=/tmp/tmp.VcfD5YNNRi NO_LIBNUMA=1
- make_no_libaudit: cd . && make -f Makefile   DESTDIR=/tmp/tmp.i4SdxuHf1t NO_LIBAUDIT=1
- make_no_backtrace: cd . && make -f Makefile   DESTDIR=/tmp/tmp.I3v5QmV8Nh NO_BACKTRACE=1
- make_no_libpython: cd . && make -f Makefile   DESTDIR=/tmp/tmp.fOCkt4C1FM NO_LIBPYTHON=1
- make_pure: cd . && make -f Makefile   DESTDIR=/tmp/tmp.TctwSew68Q 
- make_perf_o: cd . && make -f Makefile   DESTDIR=/tmp/tmp.iknvKKT2Kb perf.o
- make_debug: cd . && make -f Makefile   DESTDIR=/tmp/tmp.l3lwBXfwnz DEBUG=1
- make_no_libbpf: cd . && make -f Makefile   DESTDIR=/tmp/tmp.Ywr6DYlKsI NO_LIBBPF=1
- make_python_perf_so: cd . && make -f Makefile   DESTDIR=/tmp/tmp.ye9o7RStSb python/perf.so
- make_no_libunwind: cd . && make -f Makefile   DESTDIR=/tmp/tmp.tNz27kyNoW NO_LIBUNWIND=1
- make_util_map_o: cd . && make -f Makefile   DESTDIR=/tmp/tmp.JpfFPERI7A util/map.o
- make_no_newt: cd . && make -f Makefile   DESTDIR=/tmp/tmp.xU9UfQCceZ NO_NEWT=1
- make_install_prefix_slash: cd . && make -f Makefile   DESTDIR=/tmp/tmp.zmS2BuQqV6 install prefix=/tmp/krava/
- make_no_ui: cd . && make -f Makefile   DESTDIR=/tmp/tmp.iiop3KRzFG NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
- make_no_demangle: cd . && make -f Makefile   DESTDIR=/tmp/tmp.A6Q5hlpmZ4 NO_DEMANGLE=1
- make_install_bin: cd . && make -f Makefile   DESTDIR=/tmp/tmp.m9d8Vq1ajF install-bin
- make_no_gtk2: cd . && make -f Makefile   DESTDIR=/tmp/tmp.JJdsy8pHNK NO_GTK2=1
- make_install: cd . && make -f Makefile   DESTDIR=/tmp/tmp.Sj2Xg4PitI install
- make_util_pmu_bison_o: cd . && make -f Makefile   DESTDIR=/tmp/tmp.wKGJJU3eyc util/pmu-bison.o
- make_no_libdw_dwarf_unwind: cd . && make -f Makefile   DESTDIR=/tmp/tmp.2182Tdx2VE NO_LIBDW_DWARF_UNWIND=1
- make_minimal: cd . && make -f Makefile   DESTDIR=/tmp/tmp.Q5ezRmcMm1 NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1
- make_install_prefix: cd . && make -f Makefile   DESTDIR=/tmp/tmp.lyfQvxT5ix install prefix=/tmp/krava
- make_clean_all: cd . && make -f Makefile   DESTDIR=/tmp/tmp.nhRZPPng6t clean all
- make_help: cd . && make -f Makefile   DESTDIR=/tmp/tmp.R8qWp9kt22 help
- make_no_auxtrace: cd . && make -f Makefile   DESTDIR=/tmp/tmp.fNEq3tJ2KG NO_AUXTRACE=1
- make_static: cd . && make -f Makefile   DESTDIR=/tmp/tmp.9MvNcJxaVZ LDFLAGS=-static
- make_no_scripts: cd . && make -f Makefile   DESTDIR=/tmp/tmp.L2iW1bNMbb NO_LIBPYTHON=1 NO_LIBPERL=1
- make_no_libbionic: cd . && make -f Makefile   DESTDIR=/tmp/tmp.M3DA8x7ek1 NO_LIBBIONIC=1
- make_doc: cd . && make -f Makefile   DESTDIR=/tmp/tmp.mPzyUE4voE doc
- make_no_slang: cd . && make -f Makefile   DESTDIR=/tmp/tmp.w1T8U77HFl NO_SLANG=1
- make_no_libperl: cd . && make -f Makefile   DESTDIR=/tmp/tmp.T06LfKQxnS NO_LIBPERL=1
- make_doc_O: cd . && make -f Makefile  O=/tmp/tmp.r6w33h3LtW DESTDIR=/tmp/tmp.NHa0Rhy101 doc
- make_no_libbionic_O: cd . && make -f Makefile  O=/tmp/tmp.h8UfMSiZWb DESTDIR=/tmp/tmp.iQ5FPiVjUl NO_LIBBIONIC=1
- make_clean_all_O: cd . && make -f Makefile  O=/tmp/tmp.7tUqBFwxuC DESTDIR=/tmp/tmp.77k1WKoYsK clean all
- make_install_prefix_O: cd . && make -f Makefile  O=/tmp/tmp.tdnh6ul7op DESTDIR=/tmp/tmp.Gm7tzkZUSJ install prefix=/tmp/krava
- make_perf_o_O: cd . && make -f Makefile  O=/tmp/tmp.1Fae4o1h2s DESTDIR=/tmp/tmp.B8Nmjm2Wor perf.o
- make_no_libpython_O: cd . && make -f Makefile  O=/tmp/tmp.O9ATQ4Mjjt DESTDIR=/tmp/tmp.F7spQK99VU NO_LIBPYTHON=1
- make_no_newt_O: cd . && make -f Makefile  O=/tmp/tmp.7pT6bKzd7K DESTDIR=/tmp/tmp.egSS3beEh7 NO_NEWT=1
- make_util_pmu_bison_o_O: cd . && make -f Makefile  O=/tmp/tmp.giN3W13SYR DESTDIR=/tmp/tmp.S8hRxRWVnb util/pmu-bison.o
- make_no_slang_O: cd . && make -f Makefile  O=/tmp/tmp.E4NQ8vMPdt DESTDIR=/tmp/tmp.WQbb9Nyf7s NO_SLANG=1
- make_pure_O: cd . && make -f Makefile  O=/tmp/tmp.sL7RlaW7QZ DESTDIR=/tmp/tmp.iKuoNAvr3v 
    

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-01-22 21:22     ` Stephane Eranian
       [not found]       ` <20160122215542.GK4034@kernel.org>
@ 2016-02-04 21:53       ` Arnaldo Carvalho de Melo
  2016-02-04 23:02         ` Stephane Eranian
  1 sibling, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-04 21:53 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Em Fri, Jan 22, 2016 at 01:22:51PM -0800, Stephane Eranian escreveu:
> On Fri, Jan 22, 2016 at 12:44 PM, Arnaldo Carvalho de Melo
> <acme@redhat.com> wrote:
> > Em Mon, Nov 30, 2015 at 10:02:21AM +0100, Stephane Eranian escreveu:
> >> 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
> >
> > So, it fails 'make -C tools/perf build-test', specifically the one where
> > we ask for a NO_LIBELF build, trying to fix:
> >
> I have rebase to tip.git last night. Will try your branch today.
> Will add a couple of minor adjustments and also better documentation
> on how to use it.

So, trying to continue with this, digged for instructions on how to
build this the libjvmti.so thing, figure out its java-devel (aka
java-1.8.0-openjdk-devel).

And I needed this to build it, hacky tho, as was what was there before,
BTW, what distro was it you tested this for that
update-java-alternatives to be available?

I'm keeping what I have a perf/jit branch in my git tree.

- Arnaldo


diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
index 5e46f518e045..d7005f1608d2 100644
--- a/tools/perf/jvmti/Makefile
+++ b/tools/perf/jvmti/Makefile
@@ -33,7 +33,8 @@ VLIBJVMTI=libjvmti.so.$(VERSION)
 SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBJVMTI)
 SOLIBEXT=so
 
-JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
+#JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
+JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
 # -lrt required in 32-bit mode for clock_gettime()
 LIBS=-lelf -lrt
 INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-04 21:53       ` Arnaldo Carvalho de Melo
@ 2016-02-04 23:02         ` Stephane Eranian
  2016-02-05 13:47           ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 27+ messages in thread
From: Stephane Eranian @ 2016-02-04 23:02 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Hi,

On Thu, Feb 4, 2016 at 1:53 PM, Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
> Em Fri, Jan 22, 2016 at 01:22:51PM -0800, Stephane Eranian escreveu:
>> On Fri, Jan 22, 2016 at 12:44 PM, Arnaldo Carvalho de Melo
>> <acme@redhat.com> wrote:
>> > Em Mon, Nov 30, 2015 at 10:02:21AM +0100, Stephane Eranian escreveu:
>> >> 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
>> >
>> > So, it fails 'make -C tools/perf build-test', specifically the one where
>> > we ask for a NO_LIBELF build, trying to fix:
>> >
>> I have rebase to tip.git last night. Will try your branch today.
>> Will add a couple of minor adjustments and also better documentation
>> on how to use it.
>
> So, trying to continue with this, digged for instructions on how to
> build this the libjvmti.so thing, figure out its java-devel (aka
> java-1.8.0-openjdk-devel).
>
I will try on Ubuntu again with the latest JVM.
Clearly the environment is different.

> And I needed this to build it, hacky tho, as was what was there before,
> BTW, what distro was it you tested this for that
> update-java-alternatives to be available?
>
Ubuntu Trusty and Wily.

> I'm keeping what I have a perf/jit branch in my git tree.
>

Ok, I will try it out.
Thanks.

>
> diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
> index 5e46f518e045..d7005f1608d2 100644
> --- a/tools/perf/jvmti/Makefile
> +++ b/tools/perf/jvmti/Makefile
> @@ -33,7 +33,8 @@ VLIBJVMTI=libjvmti.so.$(VERSION)
>  SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBJVMTI)
>  SOLIBEXT=so
>
> -JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
> +#JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
> +JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
>  # -lrt required in 32-bit mode for clock_gettime()
>  LIBS=-lelf -lrt
>  INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-04 23:02         ` Stephane Eranian
@ 2016-02-05 13:47           ` Arnaldo Carvalho de Melo
  2016-02-05 13:51             ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-05 13:47 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Em Thu, Feb 04, 2016 at 03:02:59PM -0800, Stephane Eranian escreveu:
> > I'm keeping what I have a perf/jit branch in my git tree.

What am I doing wrong? Continuing to investigate...

[acme@jouet linux]$ cd tools/perf/jvmti/
[acme@jouet jvmti]$ make clean
rm -f *.o *.so.* *.so *.lo
[acme@jouet jvmti]$ make
cc -fPIC -DPIC -I /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/include -I /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/include/linux -O2 -g -Werror -Wall -c libjvmti.c -o libjvmti.lo
cc -fPIC -DPIC -I /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/include -I /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/include/linux -O2 -g -Werror -Wall -c jvmti_agent.c -o jvmti_agent.lo
cc -I /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/include -I /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/include/linux -O2 -g -Werror -Wall -shared -Wl,-soname -Wl,libjvmti.so.1  -o libjvmti.so.1.0.0 libjvmti.lo jvmti_agent.lo -lelf -lrt
ln -sf libjvmti.so.1.0.0 libjvmti.so
[acme@jouet jvmti]$ 
[acme@jouet java]$ cat hello.java 
public class hello {
	public static void main(String[] args) {
                 System.out.println("Hello, World");
       	}
}
[acme@jouet java]$ javac hello.java 
[acme@jouet java]$ java hello
Hello, World
[acme@jouet java]$ 
[acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello.java 
java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXIKKHRA/jit-27730.dump
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f4aaed9bb3a, pid=27730, tid=139957992613632
#
# JRE version: OpenJDK Runtime Environment (8.0_71-b15) (build 1.8.0_71-b15)
# Java VM: OpenJDK 64-Bit Server VM (25.71-b15 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libc.so.6+0x8ab3a]  strlen+0x2a
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/acme/java/hs_err_pid27730.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#
Aborted (core dumped)
[acme@jouet java]$
[acme@jouet java]$ type java
java is hashed (/usr/bin/java)
[acme@jouet java]$ ls -la /usr/bin/java
lrwxrwxrwx. 1 root root 22 Jan 26 10:45 /usr/bin/java -> /etc/alternatives/java
[acme@jouet java]$ ls -la /etc/alternatives/java
lrwxrwxrwx. 1 root root 71 Jan 26 10:45 /etc/alternatives/java -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
[acme@jouet java]$ rpm -qf /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
java-1.8.0-openjdk-headless-1.8.0.71-1.b15.fc23.x86_64
[acme@jouet java]$

[acme@jouet java]$ vim hs_err_pid27730.log
[acme@jouet java]$ ulimit -c unlimited
[acme@jouet java]$ rm -f *.log
[acme@jouet java]$ 
[acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello.java 
java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXJ6KUZS/jit-27922.dump
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fef53f31b3a, pid=27922, tid=140665269741312
#
# JRE version: OpenJDK Runtime Environment (8.0_71-b15) (build 1.8.0_71-b15)
# Java VM: OpenJDK 64-Bit Server VM (25.71-b15 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libc.so.6+0x8ab3a]  strlen+0x2a
#
# Core dump written. Default location: /home/acme/java/core or core.27922
#
# An error report file with more information is saved as:
# /home/acme/java/hs_err_pid27922.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#
Aborted (core dumped)
[acme@jouet java]$ dnf --enablerepo='*debug*' install /usr/lib/debug/.build-id/4c/91a5aff28a4820b667eab14b2188229ef63503
java-1.8.0-openjdk-debuginfo-1.8.0.71-1.b15.fc23.x86_64.rpm      7.0 MB/s |  75 MB   00:10    

[acme@jouet java]$ gdb -c core.27922 
GNU gdb (GDB) Fedora 7.10.1-30.fc23
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
[New LWP 27935]
[New LWP 27922]
[New LWP 27926]
[New LWP 27923]
[New LWP 27924]
[New LWP 27925]
[New LWP 27933]
[New LWP 27928]
[New LWP 27929]
[New LWP 27934]
[New LWP 27930]
[New LWP 27936]
[New LWP 27931]
[New LWP 27927]
[New LWP 27932]
Reading symbols from /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java...Reading symbols from /usr/lib/debug/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java.debug...done.
done.
Missing separate debuginfo for /home/acme/git/linux/tools/perf/jvmti/libjvmti.so
Try: dnf --enablerepo='*debug*' install /usr/lib/debug/.build-id/af/a16eaaafdfc278c5ade69b9c63b20d733c0baf
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello.java'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007fef53edba98 in raise () from /lib64/libc.so.6
[Current thread is 1 (Thread 0x7fef2f6f6700 (LWP 27935))]
Missing separate debuginfos, use: dnf debuginfo-install elfutils-libelf-0.165-2.fc23.x86_64 glibc-2.22-7.fc23.x86_64 libgcc-5.3.1-2.fc23.x86_64 libstdc++-5.3.1-2.fc23.x86_64 zlib-1.2.8-9.fc23.x86_64
(gdb) bt
#0  0x00007fef53edba98 in raise () from /lib64/libc.so.6
#1  0x00007fef53edd69a in abort () from /lib64/libc.so.6
#2  0x00007fef53820ff9 in os::abort (dump_core=<optimized out>)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:1500
#3  0x00007fef539d1737 in VMError::report_and_die (this=this@entry=0x7fef2f6f4310)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/utilities/vmError.cpp:1060
#4  0x00007fef5382a2cf in JVM_handle_linux_signal (sig=sig@entry=11, info=info@entry=0x7fef2f6f45b0, ucVoid=ucVoid@entry=0x7fef2f6f4480, 
    abort_if_unrecognized=abort_if_unrecognized@entry=1)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp:541
#5  0x00007fef5381e138 in signalHandler (sig=11, info=0x7fef2f6f45b0, uc=0x7fef2f6f4480)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:4233
#6  <signal handler called>
#7  0x00007fef53f31b3a in strlen () from /lib64/libc.so.6
#8  0x00007fef51e8e4c1 in compiled_method_load_cb (jvmti=0x7fef4c003ef0, method=<optimized out>, code_size=520, code_addr=0x7fef3d0ffd00, map_length=<optimized out>, 
    map=0x0, compile_info=0x7fef04019e80) at libjvmti.c:85
#9  0x00007fef536982b1 in JvmtiExport::post_compiled_method_load (nm=nm@entry=0x7fef3d0ffb90)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/prims/jvmtiExport.cpp:1793
#10 0x00007fef536a68d4 in JvmtiDeferredEvent::post (this=<optimized out>)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/prims/jvmtiImpl.cpp:957
#11 0x00007fef538c54a8 in ServiceThread::service_thread_entry (jt=0x7fef4c0d0000, __the_thread__=0x7fef4c0d0000)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/runtime/serviceThread.cpp:120
#12 0x00007fef53976343 in JavaThread::thread_main_inner (this=this@entry=0x7fef4c0d0000)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1699
#13 0x00007fef53976814 in JavaThread::run (this=0x7fef4c0d0000)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1679
#14 0x00007fef5381ffc2 in java_start (thread=0x7fef4c0d0000)
    at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:782
#15 0x00007fef5489860a in start_thread () from /lib64/libpthread.so.0
#16 0x00007fef53fa9a4d in clone () from /lib64/libc.so.6
(gdb)


And it generates this file:

/home/acme/.debug/jit/java-jit-20160205.XXIKKHRA/jit-27730.dump

Continuing...

- Arnaldo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-05 13:47           ` Arnaldo Carvalho de Melo
@ 2016-02-05 13:51             ` Arnaldo Carvalho de Melo
  2016-02-05 13:57               ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-05 13:51 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Em Fri, Feb 05, 2016 at 10:47:31AM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Thu, Feb 04, 2016 at 03:02:59PM -0800, Stephane Eranian escreveu:
> > > I'm keeping what I have a perf/jit branch in my git tree.
> 
> What am I doing wrong? Continuing to investigate...
> #7  0x00007fef53f31b3a in strlen () from /lib64/libc.so.6
> #8  0x00007fef51e8e4c1 in compiled_method_load_cb (jvmti=0x7fef4c003ef0, method=<optimized out>, code_size=520, code_addr=0x7fef3d0ffd00, map_length=<optimized out>, 
>     map=0x0, compile_info=0x7fef04019e80) at libjvmti.c:85


Ok, this bandaid cured the segfault:


-------------------------------------------------------------
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
index 745f20c7b4bd..92ffbe4ff160 100644
--- a/tools/perf/jvmti/libjvmti.c
+++ b/tools/perf/jvmti/libjvmti.c
@@ -82,7 +82,7 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 		 * append file name, we use loops and not string ops to avoid modifying
 		 * class_sign which is used later for the symbol name
 		 */
-		for (j = 0; i < (PATH_MAX - 1) && j < strlen(file_name); j++, i++)
+		for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++)
 			fn[i] = file_name[j];
 		fn[i] = '\0';
 	} else {
-------------------------------------------------------------

Now:

[acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello.java 
java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXdDr2Wr/jit-28322.dump
Error: Could not find or load main class hello.java
[acme@jouet java]$

Do I need to set CLASSPATH or something? /me tries...



> #9  0x00007fef536982b1 in JvmtiExport::post_compiled_method_load (nm=nm@entry=0x7fef3d0ffb90)
>     at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/prims/jvmtiExport.cpp:1793
> #10 0x00007fef536a68d4 in JvmtiDeferredEvent::post (this=<optimized out>)
>     at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/prims/jvmtiImpl.cpp:957
> #11 0x00007fef538c54a8 in ServiceThread::service_thread_entry (jt=0x7fef4c0d0000, __the_thread__=0x7fef4c0d0000)
>     at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/runtime/serviceThread.cpp:120
> #12 0x00007fef53976343 in JavaThread::thread_main_inner (this=this@entry=0x7fef4c0d0000)
>     at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1699
> #13 0x00007fef53976814 in JavaThread::run (this=0x7fef4c0d0000)
>     at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/share/vm/runtime/thread.cpp:1679
> #14 0x00007fef5381ffc2 in java_start (thread=0x7fef4c0d0000)
>     at /usr/src/debug/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:782
> #15 0x00007fef5489860a in start_thread () from /lib64/libpthread.so.0
> #16 0x00007fef53fa9a4d in clone () from /lib64/libc.so.6
> (gdb)
> 
> 
> And it generates this file:
> 
> /home/acme/.debug/jit/java-jit-20160205.XXIKKHRA/jit-27730.dump
> 
> Continuing...
> 
> - Arnaldo

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-05 13:51             ` Arnaldo Carvalho de Melo
@ 2016-02-05 13:57               ` Arnaldo Carvalho de Melo
  2016-02-05 14:24                 ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-05 13:57 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Em Fri, Feb 05, 2016 at 10:51:18AM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Fri, Feb 05, 2016 at 10:47:31AM -0300, Arnaldo Carvalho de Melo escreveu:
> > Em Thu, Feb 04, 2016 at 03:02:59PM -0800, Stephane Eranian escreveu:
> > > > I'm keeping what I have a perf/jit branch in my git tree.
> > 
> > What am I doing wrong? Continuing to investigate...
> > #7  0x00007fef53f31b3a in strlen () from /lib64/libc.so.6
> > #8  0x00007fef51e8e4c1 in compiled_method_load_cb (jvmti=0x7fef4c003ef0, method=<optimized out>, code_size=520, code_addr=0x7fef3d0ffd00, map_length=<optimized out>, 
> >     map=0x0, compile_info=0x7fef04019e80) at libjvmti.c:85
> 
> 
> Ok, this bandaid cured the segfault:
> 
> 
> -------------------------------------------------------------
> diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
> index 745f20c7b4bd..92ffbe4ff160 100644
> --- a/tools/perf/jvmti/libjvmti.c
> +++ b/tools/perf/jvmti/libjvmti.c
> @@ -82,7 +82,7 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
>  		 * append file name, we use loops and not string ops to avoid modifying
>  		 * class_sign which is used later for the symbol name
>  		 */
> -		for (j = 0; i < (PATH_MAX - 1) && j < strlen(file_name); j++, i++)
> +		for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++)
>  			fn[i] = file_name[j];
>  		fn[i] = '\0';
>  	} else {
> -------------------------------------------------------------
> 
> Now:
> 
> [acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello.java 
> java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXdDr2Wr/jit-28322.dump
> Error: Could not find or load main class hello.java
> [acme@jouet java]$
> 
> Do I need to set CLASSPATH or something? /me tries...

Duh:

[acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXFb472a/jit-28966.dump
Hello, World
[acme@jouet java]$ 

- Arnaldo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-05 13:57               ` Arnaldo Carvalho de Melo
@ 2016-02-05 14:24                 ` Arnaldo Carvalho de Melo
  2016-02-08 18:53                   ` Stephane Eranian
  0 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-05 14:24 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Em Fri, Feb 05, 2016 at 10:57:17AM -0300, Arnaldo Carvalho de Melo escreveu:
> Duh:
> 
> [acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
> java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXFb472a/jit-28966.dump
> Hello, World
> [acme@jouet java]$ 

Ok, so mucho progress:

[acme@jouet java]$ perf record -k 1 java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jit-31400.dump
Hello, World
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.030 MB perf.data (268 samples) ]
[acme@jouet java]$ perf inject --jit -i perf.data -o perf.data.jitted
[acme@jouet java]$ perf report -D -i perf.data | grep PERF_RECORD_MMAP > mmaps.before
Failed to open /tmp/perf-31400.map, continuing without symbols
[acme@jouet java]$ perf report -D -i perf.data. | grep PERF_RECORD_MMAP > mmaps.before
perf.data.jitted      perf.data.jitted.old  perf.data.old         
[acme@jouet java]$ perf report -D -i perf.data.jitted | grep PERF_RECORD_MMAP > mmaps.jitted
[acme@jouet java]$ diff -u mmaps.before mmaps.jitted
--- mmaps.before	2016-02-05 11:01:16.019257683 -0300
+++ mmaps.jitted	2016-02-05 11:01:28.966232802 -0300
<SNIP>
+77539479986521 0xfc80 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102880(0xc0) @ 0x40 fd:02 1840179 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-281.so
+77539480189814 0xfd20 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d0fef60(0x80) @ 0x40 fd:02 1840180 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-282.so
+77539480541065 0xfdc0 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102560(0x180) @ 0x40 fd:02 1840181 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-283.so
+77539480541871 0xfe60 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102360(0x180) @ 0x40 fd:02 1840182 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-284.so
+77539480848667 0xff00 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102160(0x180) @ 0x40 fd:02 1840183 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-285.so
+77539480910925 0xffa0 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d101f60(0x180) @ 0x40 fd:02 1840184 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-286.so
<SNIP>

Quite a lot of those, but I noticed this, probably harmless, at the start:

 0 0x3fd8 [0x88]: PERF_RECORD_MMAP -1/0: [0xffffffffa0991000(0x5000) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/net/dns_resolver/dns_resolver.ko.xz
 0 0x4060 [0x78]: PERF_RECORD_MMAP -1/0: [0xffffffffa0996000(0x7b000) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/fs/nfs/nfsv4.ko.xz
 0 0x40d8 [0x88]: PERF_RECORD_MMAP -1/0: [0xffffffffa0a11000(0x5f5eefff) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/drivers/usb/storage/usb-storage.ko.xz
-77539437123281 0x6b98 [0xa0]: PERF_RECORD_MMAP2 31400/31400: [0x557b73152000(0x202000) @ 0 fd:00 7858 3897326142]: r-xp /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
+77539437123281 0x42a0 [0xa0]: PERF_RECORD_MMAP2 31400/31400: [0x557b73152000(0x202000) @ 0 fd:00 7858 3897326142]: r-xp /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java

I.e. the MMAP records for the kernel modules comes in ok, humm, because
probably you don't hook on PERF_RECORD_MMAP in perf-inject, just on MMAP2, and
in those the only difference is the second field, 0x6b98 -> 0x42a0, what is
that?

static void dump_event(struct perf_evlist *evlist, union perf_event *event,
                       u64 file_offset, struct perf_sample *sample)
{
        if (sample)
                perf_evlist__print_tstamp(evlist, event, sample);

        printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
               event->header.size, perf_event__name(event->header.type));

File offset, what changed?

-0x7c18 [0x8]: event: 68
-.
-. ... raw event: size 8 bytes
-.  0000:  44 00 00 00 00 00 08 00                          D.......
-.
-0x7c18 [0x8]: PERF_RECORD_FINISHED_ROUND
-
-0x6a80 [0x28]: event: 9

Humm, inject doesn't preserves PERF_RECORD_FINISHED_ROUND? Or user events in
general? On purpose?

- Arnaldo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-05 14:24                 ` Arnaldo Carvalho de Melo
@ 2016-02-08 18:53                   ` Stephane Eranian
  2016-02-11 22:16                     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 27+ messages in thread
From: Stephane Eranian @ 2016-02-08 18:53 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Hi Arnaldo,

Sorry for the delay, I missed your message.

I tried with openjdk-8 on Ubuntu/Wily and I do not get the crash using
the same hello world test program.
In fact, if I print file_name, it is never NULL for me.

$ java -agentpath:/home/eranian/tip/tools/perf/jvmti/libjvmti.so hello
java: jvmti: jitdump in
/home/eranian/.debug/jit/java-jit-20160208.XX8wCwyY/jit-20156.dump
java: FILE_NAME: Object.java
java: FILE_NAME: String.java
java: FILE_NAME: String.java
java: FILE_NAME: String.java
java: FILE_NAME: String.java
java: FILE_NAME: String.java
java: FILE_NAME: System.java
java: FILE_NAME: Math.java
java: FILE_NAME: Object.java
java: FILE_NAME: Reference.java
java: FILE_NAME: AbstractStringBuilder.java
java: FILE_NAME: ThreadLocal.java
java: FILE_NAME: AbstractStringBuilder.java
java: FILE_NAME: String.java
Hello, World

So I am not sure what is different in your setup especially if the
function GetSourceFileName() did not fail.
Could you print file_name in your code to check?


As for the MMAP, it is normal to have the extra mmaps pointing to the
jitted code.
Event for a simple program as hello world, there are several function
jitted, including the
java interpreter itself. There is one MMAP for each jitted function.



On Fri, Feb 5, 2016 at 6:24 AM, Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> Em Fri, Feb 05, 2016 at 10:57:17AM -0300, Arnaldo Carvalho de Melo escreveu:
> > Duh:
> >
> > [acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
> > java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXFb472a/jit-28966.dump
> > Hello, World
> > [acme@jouet java]$
>
> Ok, so mucho progress:
>
> [acme@jouet java]$ perf record -k 1 java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
> java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jit-31400.dump
> Hello, World
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.030 MB perf.data (268 samples) ]
> [acme@jouet java]$ perf inject --jit -i perf.data -o perf.data.jitted
> [acme@jouet java]$ perf report -D -i perf.data | grep PERF_RECORD_MMAP > mmaps.before
> Failed to open /tmp/perf-31400.map, continuing without symbols
> [acme@jouet java]$ perf report -D -i perf.data. | grep PERF_RECORD_MMAP > mmaps.before
> perf.data.jitted      perf.data.jitted.old  perf.data.old
> [acme@jouet java]$ perf report -D -i perf.data.jitted | grep PERF_RECORD_MMAP > mmaps.jitted
> [acme@jouet java]$ diff -u mmaps.before mmaps.jitted
> --- mmaps.before        2016-02-05 11:01:16.019257683 -0300
> +++ mmaps.jitted        2016-02-05 11:01:28.966232802 -0300
> <SNIP>
> +77539479986521 0xfc80 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102880(0xc0) @ 0x40 fd:02 1840179 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-281.so
> +77539480189814 0xfd20 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d0fef60(0x80) @ 0x40 fd:02 1840180 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-282.so
> +77539480541065 0xfdc0 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102560(0x180) @ 0x40 fd:02 1840181 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-283.so
> +77539480541871 0xfe60 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102360(0x180) @ 0x40 fd:02 1840182 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-284.so
> +77539480848667 0xff00 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102160(0x180) @ 0x40 fd:02 1840183 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-285.so
> +77539480910925 0xffa0 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d101f60(0x180) @ 0x40 fd:02 1840184 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-286.so
> <SNIP>
>
> Quite a lot of those, but I noticed this, probably harmless, at the start:
>
>  0 0x3fd8 [0x88]: PERF_RECORD_MMAP -1/0: [0xffffffffa0991000(0x5000) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/net/dns_resolver/dns_resolver.ko.xz
>  0 0x4060 [0x78]: PERF_RECORD_MMAP -1/0: [0xffffffffa0996000(0x7b000) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/fs/nfs/nfsv4.ko.xz
>  0 0x40d8 [0x88]: PERF_RECORD_MMAP -1/0: [0xffffffffa0a11000(0x5f5eefff) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/drivers/usb/storage/usb-storage.ko.xz
> -77539437123281 0x6b98 [0xa0]: PERF_RECORD_MMAP2 31400/31400: [0x557b73152000(0x202000) @ 0 fd:00 7858 3897326142]: r-xp /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
> +77539437123281 0x42a0 [0xa0]: PERF_RECORD_MMAP2 31400/31400: [0x557b73152000(0x202000) @ 0 fd:00 7858 3897326142]: r-xp /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
>
> I.e. the MMAP records for the kernel modules comes in ok, humm, because
> probably you don't hook on PERF_RECORD_MMAP in perf-inject, just on MMAP2, and
> in those the only difference is the second field, 0x6b98 -> 0x42a0, what is
> that?
>
I have both MMAP and MMAP2 hooks for the jit mode of perf inject.

>
> static void dump_event(struct perf_evlist *evlist, union perf_event *event,
>                        u64 file_offset, struct perf_sample *sample)
> {
>         if (sample)
>                 perf_evlist__print_tstamp(evlist, event, sample);
>
>         printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
>                event->header.size, perf_event__name(event->header.type));
>
> File offset, what changed?
>
As for this, the offset is not recorded in the MMAP2 record, this is
an artifact of the __perf_Session__process_events()
which passes the file_offset in the perf.data file (read by mmapping).
The offsets are changed because we inject
new mmap records, and thus the existing MMAP may be moved to a later
position in the file.

Hope this helps.

>
> -0x7c18 [0x8]: event: 68
> -.
> -. ... raw event: size 8 bytes
> -.  0000:  44 00 00 00 00 00 08 00                          D.......
> -.
> -0x7c18 [0x8]: PERF_RECORD_FINISHED_ROUND
> -
> -0x6a80 [0x28]: event: 9
>
> Humm, inject doesn't preserves PERF_RECORD_FINISHED_ROUND? Or user events in
> general? On purpose?
>
> - Arnaldo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [tip:perf/core] perf symbols: add Java demangling support
  2015-11-30  9:02 ` [PATCH v8 1/4] perf tools: add Java demangling support Stephane Eranian
@ 2016-02-09 12:14   ` tip-bot for Stephane Eranian
  0 siblings, 0 replies; 27+ messages in thread
From: tip-bot for Stephane Eranian @ 2016-02-09 12:14 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: dsahern, mingo, johnmccutchan, hpa, cel, jolsa, pawel.moll,
	sukadev, namhyung, sonnyrao, tglx, linux-kernel, ak, acme,
	peterz, adrian.hunter, eranian

Commit-ID:  e9c4bcdd349eb00f6c704450a063b3dcbea25864
Gitweb:     http://git.kernel.org/tip/e9c4bcdd349eb00f6c704450a063b3dcbea25864
Author:     Stephane Eranian <eranian@google.com>
AuthorDate: Mon, 30 Nov 2015 10:02:20 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 5 Feb 2016 09:46:45 -0300

perf symbols: add Java demangling support

Add Java function descriptor demangling support.  Something bfd cannot
do.

Use the JAVA_DEMANGLE_NORET flag to avoid decoding the return type of
functions.

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-2-git-send-email-eranian@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/Build           |   1 +
 tools/perf/util/demangle-java.c | 199 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/demangle-java.h |  10 ++
 tools/perf/util/symbol-elf.c    |   3 +
 4 files changed, 213 insertions(+)

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5eec53a..edae107 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -105,6 +105,7 @@ libperf-y += scripting-engines/
 
 libperf-$(CONFIG_ZLIB) += zlib.o
 libperf-$(CONFIG_LZMA) += lzma.o
+libperf-y += demangle-java.o
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 
diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
new file mode 100644
index 0000000..3e6062a
--- /dev/null
+++ b/tools/perf/util/demangle-java.c
@@ -0,0 +1,199 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include "util.h"
+#include "debug.h"
+#include "symbol.h"
+
+#include "demangle-java.h"
+
+enum {
+	MODE_PREFIX = 0,
+	MODE_CLASS  = 1,
+	MODE_FUNC   = 2,
+	MODE_TYPE   = 3,
+	MODE_CTYPE  = 3, /* class arg */
+};
+
+#define BASE_ENT(c, n)	[c - 'A']=n
+static const char *base_types['Z' - 'A' + 1] = {
+	BASE_ENT('B', "byte" ),
+	BASE_ENT('C', "char" ),
+	BASE_ENT('D', "double" ),
+	BASE_ENT('F', "float" ),
+	BASE_ENT('I', "int" ),
+	BASE_ENT('J', "long" ),
+	BASE_ENT('S', "short" ),
+	BASE_ENT('Z', "bool" ),
+};
+
+/*
+ * demangle Java symbol between str and end positions and stores
+ * up to maxlen characters into buf. The parser starts in mode.
+ *
+ * Use MODE_PREFIX to process entire prototype till end position
+ * Use MODE_TYPE to process return type if str starts on return type char
+ *
+ *  Return:
+ *	success: buf
+ *	error  : NULL
+ */
+static char *
+__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
+{
+	int rlen = 0;
+	int array = 0;
+	int narg = 0;
+	const char *q;
+
+	if (!end)
+		end = str + strlen(str);
+
+	for (q = str; q != end; q++) {
+
+		if (rlen == (maxlen - 1))
+			break;
+
+		switch (*q) {
+		case 'L':
+			if (mode == MODE_PREFIX || mode == MODE_CTYPE) {
+				if (mode == MODE_CTYPE) {
+					if (narg)
+						rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
+					narg++;
+				}
+				rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
+				if (mode == MODE_PREFIX)
+					mode = MODE_CLASS;
+			} else
+				buf[rlen++] = *q;
+			break;
+		case 'B':
+		case 'C':
+		case 'D':
+		case 'F':
+		case 'I':
+		case 'J':
+		case 'S':
+		case 'Z':
+			if (mode == MODE_TYPE) {
+				if (narg)
+					rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
+				rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
+				while (array--)
+					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
+				array = 0;
+				narg++;
+			} else
+				buf[rlen++] = *q;
+			break;
+		case 'V':
+			if (mode == MODE_TYPE) {
+				rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
+				while (array--)
+					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
+				array = 0;
+			} else
+				buf[rlen++] = *q;
+			break;
+		case '[':
+			if (mode != MODE_TYPE)
+				goto error;
+			array++;
+			break;
+		case '(':
+			if (mode != MODE_FUNC)
+				goto error;
+			buf[rlen++] = *q;
+			mode = MODE_TYPE;
+			break;
+		case ')':
+			if (mode != MODE_TYPE)
+				goto error;
+			buf[rlen++] = *q;
+			narg = 0;
+			break;
+		case ';':
+			if (mode != MODE_CLASS && mode != MODE_CTYPE)
+				goto error;
+			/* safe because at least one other char to process */
+			if (isalpha(*(q + 1)))
+				rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
+			if (mode == MODE_CLASS)
+				mode = MODE_FUNC;
+			else if (mode == MODE_CTYPE)
+				mode = MODE_TYPE;
+			break;
+		case '/':
+			if (mode != MODE_CLASS && mode != MODE_CTYPE)
+				goto error;
+			rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
+			break;
+		default :
+			buf[rlen++] = *q;
+		}
+	}
+	buf[rlen] = '\0';
+	return buf;
+error:
+	return NULL;
+}
+
+/*
+ * Demangle Java function signature (openJDK, not GCJ)
+ * input:
+ * 	str: string to parse. String is not modified
+ *    flags: comobination of JAVA_DEMANGLE_* flags to modify demangling
+ * return:
+ *	if input can be demangled, then a newly allocated string is returned.
+ *	if input cannot be demangled, then NULL is returned
+ *
+ * Note: caller is responsible for freeing demangled string
+ */
+char *
+java_demangle_sym(const char *str, int flags)
+{
+	char *buf, *ptr;
+	char *p;
+	size_t len, l1 = 0;
+
+	if (!str)
+		return NULL;
+
+	/* find start of retunr type */
+	p = strrchr(str, ')');
+	if (!p)
+		return NULL;
+
+	/*
+	 * expansion factor estimated to 3x
+	 */
+	len = strlen(str) * 3 + 1;
+	buf = malloc(len);
+	if (!buf)
+		return NULL;
+
+	buf[0] = '\0';
+	if (!(flags & JAVA_DEMANGLE_NORET)) {
+		/*
+		 * get return type first
+		 */
+		ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
+		if (!ptr)
+			goto error;
+
+		/* add space between return type and function prototype */
+		l1 = strlen(buf);
+		buf[l1++] = ' ';
+	}
+
+	/* process function up to return type */
+	ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
+	if (!ptr)
+		goto error;
+
+	return buf;
+error:
+	free(buf);
+	return NULL;
+}
diff --git a/tools/perf/util/demangle-java.h b/tools/perf/util/demangle-java.h
new file mode 100644
index 0000000..a981c1f
--- /dev/null
+++ b/tools/perf/util/demangle-java.h
@@ -0,0 +1,10 @@
+#ifndef __PERF_DEMANGLE_JAVA
+#define __PERF_DEMANGLE_JAVA 1
+/*
+ * demangle function flags
+ */
+#define JAVA_DEMANGLE_NORET	0x1 /* do not process return type */
+
+char * java_demangle_sym(const char *str, int flags);
+
+#endif /* __PERF_DEMANGLE_JAVA */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 562b8eb..b1dd68f 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -6,6 +6,7 @@
 #include <inttypes.h>
 
 #include "symbol.h"
+#include "demangle-java.h"
 #include "machine.h"
 #include "vdso.h"
 #include <symbol/kallsyms.h>
@@ -1077,6 +1078,8 @@ new_symbol:
 				demangle_flags = DMGL_PARAMS | DMGL_ANSI;
 
 			demangled = bfd_demangle(NULL, elf_name, demangle_flags);
+			if (demangled == NULL)
+				demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
 			if (demangled != NULL)
 				elf_name = demangled;
 		}

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [tip:perf/core] perf build: Add libcrypto feature detection
  2015-11-30  9:02 ` [PATCH v8 2/4] perf inject: add jitdump mmap injection support Stephane Eranian
  2016-01-22 20:44   ` Arnaldo Carvalho de Melo
@ 2016-02-09 12:14   ` tip-bot for Stephane Eranian
  2016-02-09 12:15   ` [tip:perf/core] perf inject: Make sure mmap records are ordered when injecting build_ids tip-bot for Arnaldo Carvalho de Melo
  2016-02-09 12:15   ` [tip:perf/core] perf inject: Add jitdump mmap injection support tip-bot for Stephane Eranian
  3 siblings, 0 replies; 27+ messages in thread
From: tip-bot for Stephane Eranian @ 2016-02-09 12:14 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, dsahern, peterz, hpa, johnmccutchan, ak, mingo,
	namhyung, cel, jolsa, acme, eranian, sukadev, pawel.moll,
	sonnyrao, adrian.hunter, tglx

Commit-ID:  8ee4646038e47d065d35703e3e343136c4cd42aa
Gitweb:     http://git.kernel.org/tip/8ee4646038e47d065d35703e3e343136c4cd42aa
Author:     Stephane Eranian <eranian@google.com>
AuthorDate: Mon, 30 Nov 2015 10:02:21 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 5 Feb 2016 09:46:45 -0300

perf build: Add libcrypto feature detection

Will be used to generate build-ids in the jitdump code.

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
[ tools/perf/Makefile.perf comment about NO_LIBCRYPTO and added it to tests/make ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/build/Makefile.feature         |  2 ++
 tools/build/feature/Makefile         |  4 ++++
 tools/build/feature/test-all.c       |  5 +++++
 tools/build/feature/test-libcrypto.c | 17 +++++++++++++++++
 tools/perf/Makefile.perf             |  3 +++
 tools/perf/config/Makefile           | 11 +++++++++++
 tools/perf/tests/make                |  2 ++
 7 files changed, 44 insertions(+)

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 7bff2ea..6b77072 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -46,6 +46,7 @@ FEATURE_TESTS_BASIC :=			\
 	libpython			\
 	libpython-version		\
 	libslang			\
+	libcrypto			\
 	libunwind			\
 	pthread-attr-setaffinity-np	\
 	stackprotector-all		\
@@ -87,6 +88,7 @@ FEATURE_DISPLAY ?=			\
 	libperl				\
 	libpython			\
 	libslang			\
+	libcrypto			\
 	libunwind			\
 	libdw-dwarf-unwind		\
 	zlib				\
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index bf8f035..c5f4c41 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -23,6 +23,7 @@ FILES=					\
 	test-libpython.bin		\
 	test-libpython-version.bin	\
 	test-libslang.bin		\
+	test-libcrypto.bin		\
 	test-libunwind.bin		\
 	test-libunwind-debug-frame.bin	\
 	test-pthread-attr-setaffinity-np.bin	\
@@ -105,6 +106,9 @@ $(OUTPUT)test-libaudit.bin:
 $(OUTPUT)test-libslang.bin:
 	$(BUILD) -I/usr/include/slang -lslang
 
+$(OUTPUT)test-libcrypto.bin:
+	$(BUILD) -lcrypto
+
 $(OUTPUT)test-gtk2.bin:
 	$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
 
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 81025ca..e499a36 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -129,6 +129,10 @@
 # include "test-bpf.c"
 #undef main
 
+#define main main_test_libcrypto
+# include "test-libcrypto.c"
+#undef main
+
 int main(int argc, char *argv[])
 {
 	main_test_libpython();
@@ -158,6 +162,7 @@ int main(int argc, char *argv[])
 	main_test_lzma();
 	main_test_get_cpuid();
 	main_test_bpf();
+	main_test_libcrypto();
 
 	return 0;
 }
diff --git a/tools/build/feature/test-libcrypto.c b/tools/build/feature/test-libcrypto.c
new file mode 100644
index 0000000..bd79dc7
--- /dev/null
+++ b/tools/build/feature/test-libcrypto.c
@@ -0,0 +1,17 @@
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+
+int main(void)
+{
+	MD5_CTX context;
+	unsigned char md[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
+	unsigned char dat[] = "12345";
+
+	MD5_Init(&context);
+	MD5_Update(&context, &dat[0], sizeof(dat));
+	MD5_Final(&md[0], &context);
+
+	SHA1(&dat[0], sizeof(dat), &md[0]);
+
+	return 0;
+}
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 0ef3d97..d404117 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -58,6 +58,9 @@ include config/utilities.mak
 #
 # Define NO_LIBBIONIC if you do not want bionic support
 #
+# Define NO_LIBCRYPTO if you do not want libcrypto (openssl) support
+# used for generating build-ids for ELFs generated by jitdump.
+#
 # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
 # for dwarf backtrace post unwind.
 #
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 0045a5d..f7aeaf3 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -404,6 +404,17 @@ ifndef NO_LIBAUDIT
   endif
 endif
 
+ifndef NO_LIBCRYPTO
+  ifneq ($(feature-libcrypto), 1)
+    msg := $(warning No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev);
+    NO_LIBCRYPTO := 1
+  else
+    CFLAGS += -DHAVE_LIBCRYPTO_SUPPORT
+    EXTLIBS += -lcrypto
+    $(call detected,CONFIG_CRYPTO)
+  endif
+endif
+
 ifdef NO_NEWT
   NO_SLANG=1
 endif
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 12dcae7..cac15d9 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -80,6 +80,7 @@ make_no_libaudit    := NO_LIBAUDIT=1
 make_no_libbionic   := NO_LIBBIONIC=1
 make_no_auxtrace    := NO_AUXTRACE=1
 make_no_libbpf	    := NO_LIBBPF=1
+make_no_libcrypto   := NO_LIBCRYPTO=1
 make_tags           := tags
 make_cscope         := cscope
 make_help           := help
@@ -103,6 +104,7 @@ make_minimal        := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
 make_minimal        += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
 make_minimal        += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
 make_minimal        += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1
+make_minimal        += NO_LIBCRYPTO=1
 
 # $(run) contains all available tests
 run := make_pure

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [tip:perf/core] perf inject: Make sure mmap records are ordered when injecting build_ids
  2015-11-30  9:02 ` [PATCH v8 2/4] perf inject: add jitdump mmap injection support Stephane Eranian
  2016-01-22 20:44   ` Arnaldo Carvalho de Melo
  2016-02-09 12:14   ` [tip:perf/core] perf build: Add libcrypto feature detection tip-bot for Stephane Eranian
@ 2016-02-09 12:15   ` tip-bot for Arnaldo Carvalho de Melo
  2016-02-09 12:15   ` [tip:perf/core] perf inject: Add jitdump mmap injection support tip-bot for Stephane Eranian
  3 siblings, 0 replies; 27+ messages in thread
From: tip-bot for Arnaldo Carvalho de Melo @ 2016-02-09 12:15 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: eranian, mingo, sonnyrao, linux-kernel, adrian.hunter, ak,
	pawel.moll, cel, jolsa, peterz, dsahern, tglx, hpa, namhyung,
	sukadev, johnmccutchan, acme

Commit-ID:  921f3fadbc48c7c3799b415b895297cd476cf7f1
Gitweb:     http://git.kernel.org/tip/921f3fadbc48c7c3799b415b895297cd476cf7f1
Author:     Arnaldo Carvalho de Melo <acme@redhat.com>
AuthorDate: Fri, 22 Jan 2016 18:41:00 -0300
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 5 Feb 2016 09:46:45 -0300

perf inject: Make sure mmap records are ordered when injecting build_ids

To make sure the mmap records are ordered correctly and so that the
correct especially due to jitted code mmaps.

We cannot generate the buildid hit list and inject the jit mmaps (will
come right after this patch) in at the same time for now.

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
[ Carved out from a larger patch ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-inject.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 0022e02..6567bae 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -755,6 +755,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (inject.session == NULL)
 		return -1;
 
+	if (inject.build_ids) {
+		/*
+		 * to make sure the mmap records are ordered correctly
+		 * and so that the correct especially due to jitted code
+		 * mmaps. We cannot generate the buildid hit list and
+		 * inject the jit mmaps at the same time for now.
+		 */
+		inject.tool.ordered_events = true;
+		inject.tool.ordering_requires_timestamps = true;
+	}
+
 	ret = symbol__init(&inject.session->header.env);
 	if (ret < 0)
 		goto out_delete;

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [tip:perf/core] perf inject: Add jitdump mmap injection support
  2015-11-30  9:02 ` [PATCH v8 2/4] perf inject: add jitdump mmap injection support Stephane Eranian
                     ` (2 preceding siblings ...)
  2016-02-09 12:15   ` [tip:perf/core] perf inject: Make sure mmap records are ordered when injecting build_ids tip-bot for Arnaldo Carvalho de Melo
@ 2016-02-09 12:15   ` tip-bot for Stephane Eranian
  3 siblings, 0 replies; 27+ messages in thread
From: tip-bot for Stephane Eranian @ 2016-02-09 12:15 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: cel, dsahern, johnmccutchan, eranian, ak, jolsa, peterz, acme,
	adrian.hunter, pawel.moll, sonnyrao, namhyung, mingo, hpa,
	sukadev, tglx, linux-kernel

Commit-ID:  9b07e27f88b9cd785cdb23f9a2231c12521dda94
Gitweb:     http://git.kernel.org/tip/9b07e27f88b9cd785cdb23f9a2231c12521dda94
Author:     Stephane Eranian <eranian@google.com>
AuthorDate: Mon, 30 Nov 2015 10:02:21 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 5 Feb 2016 09:46:45 -0300

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>
---
 tools/perf/Documentation/perf-inject.txt |   7 +
 tools/perf/builtin-inject.c              |  98 ++++-
 tools/perf/util/Build                    |   2 +
 tools/perf/util/genelf.c                 | 442 ++++++++++++++++++++
 tools/perf/util/genelf.h                 |  63 +++
 tools/perf/util/jit.h                    |  15 +
 tools/perf/util/jitdump.c                | 670 +++++++++++++++++++++++++++++++
 tools/perf/util/jitdump.h                | 124 ++++++
 8 files changed, 1418 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index 0b1cede..87b2588 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -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]
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 6567bae..b38445f 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -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>
 
@@ -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;
@@ -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
@@ -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,
@@ -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,
@@ -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 = {
@@ -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",
@@ -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",
@@ -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);
 
 	/*
@@ -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;
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index edae107..52a4a80 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -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))"
 
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
new file mode 100644
index 0000000..145f811
--- /dev/null
+++ b/tools/perf/util/genelf.c
@@ -0,0 +1,442 @@
+/*
+ * genelf.c
+ * Copyright (C) 2014, Google, Inc
+ *
+ * Contributed by:
+ * 	Stephane Eranian <eranian@gmail.com>
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <libelf.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <err.h>
+#include <dwarf.h>
+
+#include "perf.h"
+#include "genelf.h"
+#include "../util/jitdump.h"
+
+#define JVMTI
+
+#define BUILD_ID_URANDOM /* different uuid for each run */
+
+#ifdef HAVE_LIBCRYPTO
+
+#define BUILD_ID_MD5
+#undef BUILD_ID_SHA	/* does not seem to work well when linked with Java */
+#undef BUILD_ID_URANDOM /* different uuid for each run */
+
+#ifdef BUILD_ID_SHA
+#include <openssl/sha.h>
+#endif
+
+#ifdef BUILD_ID_MD5
+#include <openssl/md5.h>
+#endif
+#endif
+
+
+typedef struct {
+  unsigned int namesz;  /* Size of entry's owner string */
+  unsigned int descsz;  /* Size of the note descriptor */
+  unsigned int type;    /* Interpretation of the descriptor */
+  char         name[0]; /* Start of the name+desc data */
+} Elf_Note;
+
+struct options {
+	char *output;
+	int fd;
+};
+
+static char shd_string_table[] = {
+	0,
+	'.', 't', 'e', 'x', 't', 0,			/*  1 */
+	'.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /*  7 */
+	'.', 's', 'y', 'm', 't', 'a', 'b', 0,		/* 17 */
+	'.', 's', 't', 'r', 't', 'a', 'b', 0,		/* 25 */
+	'.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */
+	'.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
+	'.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
+	'.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
+};
+
+static struct buildid_note {
+	Elf_Note desc;		/* descsz: size of build-id, must be multiple of 4 */
+	char	 name[4];	/* GNU\0 */
+	char	 build_id[20];
+} bnote;
+
+static Elf_Sym symtab[]={
+	/* symbol 0 MUST be the undefined symbol */
+	{ .st_name  = 0, /* index in sym_string table */
+	  .st_info  = ELF_ST_TYPE(STT_NOTYPE),
+	  .st_shndx = 0, /* for now */
+	  .st_value = 0x0,
+	  .st_other = ELF_ST_VIS(STV_DEFAULT),
+	  .st_size  = 0,
+	},
+	{ .st_name  = 1, /* index in sym_string table */
+	  .st_info  = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
+	  .st_shndx = 1,
+	  .st_value = 0, /* for now */
+	  .st_other = ELF_ST_VIS(STV_DEFAULT),
+	  .st_size  = 0, /* for now */
+	}
+};
+
+#ifdef BUILD_ID_URANDOM
+static void
+gen_build_id(struct buildid_note *note,
+	     unsigned long load_addr __maybe_unused,
+	     const void *code __maybe_unused,
+	     size_t csize __maybe_unused)
+{
+	int fd;
+	size_t sz = sizeof(note->build_id);
+	ssize_t sret;
+
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd == -1)
+		err(1, "cannot access /dev/urandom for builid");
+
+	sret = read(fd, note->build_id, sz);
+
+	close(fd);
+
+	if (sret != (ssize_t)sz)
+		memset(note->build_id, 0, sz);
+}
+#endif
+
+#ifdef BUILD_ID_SHA
+static void
+gen_build_id(struct buildid_note *note,
+	     unsigned long load_addr __maybe_unused,
+	     const void *code,
+	     size_t csize)
+{
+	if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
+		errx(1, "build_id too small for SHA1");
+
+	SHA1(code, csize, (unsigned char *)note->build_id);
+}
+#endif
+
+#ifdef BUILD_ID_MD5
+static void
+gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
+{
+	MD5_CTX context;
+
+	if (sizeof(note->build_id) < 16)
+		errx(1, "build_id too small for MD5");
+
+	MD5_Init(&context);
+	MD5_Update(&context, &load_addr, sizeof(load_addr));
+	MD5_Update(&context, code, csize);
+	MD5_Final((unsigned char *)note->build_id, &context);
+}
+#endif
+
+/*
+ * fd: file descriptor open for writing for the output file
+ * load_addr: code load address (could be zero, just used for buildid)
+ * sym: function name (for native code - used as the symbol)
+ * code: the native code
+ * csize: the code size in bytes
+ */
+int
+jit_write_elf(int fd, uint64_t load_addr, const char *sym,
+	      const void *code, int csize)
+{
+	Elf *e;
+	Elf_Data *d;
+	Elf_Scn *scn;
+	Elf_Ehdr *ehdr;
+	Elf_Shdr *shdr;
+	char *strsym = NULL;
+	int symlen;
+	int retval = -1;
+
+	if (elf_version(EV_CURRENT) == EV_NONE) {
+		warnx("ELF initialization failed");
+		return -1;
+	}
+
+	e = elf_begin(fd, ELF_C_WRITE, NULL);
+	if (!e) {
+		warnx("elf_begin failed");
+		goto error;
+	}
+
+	/*
+	 * setup ELF header
+	 */
+	ehdr = elf_newehdr(e);
+	if (!ehdr) {
+		warnx("cannot get ehdr");
+		goto error;
+	}
+
+	ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
+	ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
+	ehdr->e_machine = GEN_ELF_ARCH;
+	ehdr->e_type = ET_DYN;
+	ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
+	ehdr->e_version = EV_CURRENT;
+	ehdr->e_shstrndx= 2; /* shdr index for section name */
+
+	/*
+	 * setup text section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	d->d_align = 16;
+	d->d_off = 0LL;
+	d->d_buf = (void *)code;
+	d->d_type = ELF_T_BYTE;
+	d->d_size = csize;
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 1;
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
+	shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup section headers string table
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = shd_string_table;
+	d->d_type = ELF_T_BYTE;
+	d->d_size = sizeof(shd_string_table);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
+	shdr->sh_type = SHT_STRTAB;
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup symtab section
+	 */
+	symtab[1].st_size  = csize;
+	symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
+
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	d->d_align = 8;
+	d->d_off = 0LL;
+	d->d_buf = symtab;
+	d->d_type = ELF_T_SYM;
+	d->d_size = sizeof(symtab);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
+	shdr->sh_type = SHT_SYMTAB;
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = sizeof(Elf_Sym);
+	shdr->sh_link = 4; /* index of .strtab section */
+
+	/*
+	 * setup symbols string table
+	 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
+	 */
+	symlen = 2 + strlen(sym);
+	strsym = calloc(1, symlen);
+	if (!strsym) {
+		warnx("cannot allocate strsym");
+		goto error;
+	}
+	strcpy(strsym + 1, sym);
+
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = strsym;
+	d->d_type = ELF_T_BYTE;
+	d->d_size = symlen;
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 25; /* offset in shd_string_table */
+	shdr->sh_type = SHT_STRTAB;
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup build-id section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		goto error;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		goto error;
+	}
+
+	/*
+	 * build-id generation
+	 */
+	gen_build_id(&bnote, load_addr, code, csize);
+	bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
+	bnote.desc.descsz = sizeof(bnote.build_id);
+	bnote.desc.type   = NT_GNU_BUILD_ID;
+	strcpy(bnote.name, "GNU");
+
+	d->d_align = 4;
+	d->d_off = 0LL;
+	d->d_buf = &bnote;
+	d->d_type = ELF_T_BYTE;
+	d->d_size = sizeof(bnote);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		goto error;
+	}
+
+	shdr->sh_name = 33; /* offset in shd_string_table */
+	shdr->sh_type = SHT_NOTE;
+	shdr->sh_addr = 0x0;
+	shdr->sh_flags = SHF_ALLOC;
+	shdr->sh_size = sizeof(bnote);
+	shdr->sh_entsize = 0;
+
+	if (elf_update(e, ELF_C_WRITE) < 0) {
+		warnx("elf_update 4 failed");
+		goto error;
+	}
+
+	retval = 0;
+error:
+	(void)elf_end(e);
+
+	free(strsym);
+
+
+	return retval;
+}
+
+#ifndef JVMTI
+
+static unsigned char x86_code[] = {
+    0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */
+    0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */
+    0xCD, 0x80            /* int $0x80 */
+};
+
+static struct options options;
+
+int main(int argc, char **argv)
+{
+	int c, fd, ret;
+
+	while ((c = getopt(argc, argv, "o:h")) != -1) {
+		switch (c) {
+		case 'o':
+			options.output = optarg;
+			break;
+		case 'h':
+			printf("Usage: genelf -o output_file [-h]\n");
+			return 0;
+		default:
+			errx(1, "unknown option");
+		}
+	}
+
+	fd = open(options.output, O_CREAT|O_TRUNC|O_RDWR, 0666);
+	if (fd == -1)
+		err(1, "cannot create file %s", options.output);
+
+	ret = jit_write_elf(fd, "main", x86_code, sizeof(x86_code));
+	close(fd);
+
+	if (ret != 0)
+		unlink(options.output);
+
+	return ret;
+}
+#endif
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
new file mode 100644
index 0000000..d8e9ece
--- /dev/null
+++ b/tools/perf/util/genelf.h
@@ -0,0 +1,63 @@
+#ifndef __GENELF_H__
+#define __GENELF_H__
+
+/* genelf.c */
+extern int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
+			 const void *code, int csize);
+
+#if   defined(__arm__)
+#define GEN_ELF_ARCH	EM_ARM
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS32
+#elif defined(__aarch64__)
+#define GEN_ELF_ARCH	EM_AARCH64
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#elif defined(__x86_64__)
+#define GEN_ELF_ARCH	EM_X86_64
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#elif defined(__i386__)
+#define GEN_ELF_ARCH	EM_386
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS32
+#elif defined(__ppcle__)
+#define GEN_ELF_ARCH	EM_PPC
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#elif defined(__powerpc__)
+#define GEN_ELF_ARCH	EM_PPC64
+#define GEN_ELF_ENDIAN	ELFDATA2MSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#elif defined(__powerpcle__)
+#define GEN_ELF_ARCH	EM_PPC64
+#define GEN_ELF_ENDIAN	ELFDATA2LSB
+#define GEN_ELF_CLASS	ELFCLASS64
+#else
+#error "unsupported architecture"
+#endif
+
+#if GEN_ELF_CLASS == ELFCLASS64
+#define elf_newehdr	elf64_newehdr
+#define elf_getshdr	elf64_getshdr
+#define Elf_Ehdr	Elf64_Ehdr
+#define Elf_Shdr	Elf64_Shdr
+#define Elf_Sym		Elf64_Sym
+#define ELF_ST_TYPE(a)	ELF64_ST_TYPE(a)
+#define ELF_ST_BIND(a)	ELF64_ST_BIND(a)
+#define ELF_ST_VIS(a)	ELF64_ST_VISIBILITY(a)
+#else
+#define elf_newehdr	elf32_newehdr
+#define elf_getshdr	elf32_getshdr
+#define Elf_Ehdr	Elf32_Ehdr
+#define Elf_Shdr	Elf32_Shdr
+#define Elf_Sym		Elf32_Sym
+#define ELF_ST_TYPE(a)	ELF32_ST_TYPE(a)
+#define ELF_ST_BIND(a)	ELF32_ST_BIND(a)
+#define ELF_ST_VIS(a)	ELF32_ST_VISIBILITY(a)
+#endif
+
+/* The .text section is directly after the ELF header */
+#define GEN_ELF_TEXT_OFFSET sizeof(Elf_Ehdr)
+
+#endif
diff --git a/tools/perf/util/jit.h b/tools/perf/util/jit.h
new file mode 100644
index 0000000..a1e99da
--- /dev/null
+++ b/tools/perf/util/jit.h
@@ -0,0 +1,15 @@
+#ifndef __JIT_H__
+#define __JIT_H__
+
+#include <data.h>
+
+extern int jit_process(struct perf_session *session,
+		       struct perf_data_file *output,
+		       struct machine *machine,
+		       char *filename,
+		       pid_t pid,
+		       u64 *nbytes);
+
+extern int jit_inject_record(const char *filename);
+
+#endif /* __JIT_H__ */
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
new file mode 100644
index 0000000..9f7a012
--- /dev/null
+++ b/tools/perf/util/jitdump.c
@@ -0,0 +1,670 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <byteswap.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "util.h"
+#include "event.h"
+#include "debug.h"
+#include "evlist.h"
+#include "symbol.h"
+#include "strlist.h"
+#include <elf.h>
+
+#include "session.h"
+#include "jit.h"
+#include "jitdump.h"
+#include "genelf.h"
+#include "../builtin.h"
+
+struct jit_buf_desc {
+	struct perf_data_file *output;
+	struct perf_session *session;
+	struct machine *machine;
+	union jr_entry   *entry;
+	void             *buf;
+	uint64_t	 sample_type;
+	size_t           bufsize;
+	FILE             *in;
+	bool		 needs_bswap; /* handles cross-endianess */
+	void		 *debug_data;
+	size_t		 nr_debug_entries;
+	uint32_t         code_load_count;
+	u64		 bytes_written;
+	struct rb_root   code_root;
+	char		 dir[PATH_MAX];
+};
+
+struct debug_line_info {
+	unsigned long vma;
+	unsigned int lineno;
+	/* The filename format is unspecified, absolute path, relative etc. */
+	char const filename[0];
+};
+
+struct jit_tool {
+	struct perf_tool tool;
+	struct perf_data_file	output;
+	struct perf_data_file	input;
+	u64 bytes_written;
+};
+
+#define hmax(a, b) ((a) > (b) ? (a) : (b))
+#define get_jit_tool(t) (container_of(tool, struct jit_tool, tool))
+
+static int
+jit_emit_elf(char *filename,
+	     const char *sym,
+	     uint64_t code_addr,
+	     const void *code,
+	     int csize)
+{
+	int ret, fd;
+
+	if (verbose > 0)
+		fprintf(stderr, "write ELF image %s\n", filename);
+
+	fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
+	if (fd == -1) {
+		pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(errno));
+		return -1;
+	}
+
+        ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize);
+
+        close(fd);
+
+        if (ret)
+                unlink(filename);
+
+	return ret;
+}
+
+static void
+jit_close(struct jit_buf_desc *jd)
+{
+	if (!(jd && jd->in))
+		return;
+	funlockfile(jd->in);
+	fclose(jd->in);
+	jd->in = NULL;
+}
+
+static int
+jit_open(struct jit_buf_desc *jd, const char *name)
+{
+	struct jitheader header;
+	struct jr_prefix *prefix;
+	ssize_t bs, bsz = 0;
+	void *n, *buf = NULL;
+	int ret, retval = -1;
+
+	jd->in = fopen(name, "r");
+	if (!jd->in)
+		return -1;
+
+	bsz = hmax(sizeof(header), sizeof(*prefix));
+
+	buf = malloc(bsz);
+	if (!buf)
+		goto error;
+
+	/*
+	 * protect from writer modifying the file while we are reading it
+	 */
+	flockfile(jd->in);
+
+	ret = fread(buf, sizeof(header), 1, jd->in);
+	if (ret != 1)
+		goto error;
+
+	memcpy(&header, buf, sizeof(header));
+
+	if (header.magic != JITHEADER_MAGIC) {
+		if (header.magic != JITHEADER_MAGIC_SW)
+			goto error;
+		jd->needs_bswap = true;
+	}
+
+	if (jd->needs_bswap) {
+		header.version    = bswap_32(header.version);
+		header.total_size = bswap_32(header.total_size);
+		header.pid	  = bswap_32(header.pid);
+		header.elf_mach   = bswap_32(header.elf_mach);
+		header.timestamp  = bswap_64(header.timestamp);
+		header.flags      = bswap_64(header.flags);
+	}
+
+	if (verbose > 2)
+		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
+			header.version,
+			header.total_size,
+			(unsigned long long)header.timestamp,
+			header.pid,
+			header.elf_mach);
+
+	if (header.flags & JITDUMP_FLAGS_RESERVED) {
+		pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
+		       (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED);
+		goto error;
+	}
+
+	bs = header.total_size - sizeof(header);
+
+	if (bs > bsz) {
+		n = realloc(buf, bs);
+		if (!n)
+			goto error;
+		bsz = bs;
+		buf = n;
+		/* read extra we do not know about */
+		ret = fread(buf, bs - bsz, 1, jd->in);
+		if (ret != 1)
+			goto error;
+	}
+	/*
+	 * keep dirname for generating files and mmap records
+	 */
+	strcpy(jd->dir, name);
+	dirname(jd->dir);
+
+	return 0;
+error:
+	funlockfile(jd->in);
+	fclose(jd->in);
+	return retval;
+}
+
+static union jr_entry *
+jit_get_next_entry(struct jit_buf_desc *jd)
+{
+	struct jr_prefix *prefix;
+	union jr_entry *jr;
+	void *addr;
+	size_t bs, size;
+	int id, ret;
+
+	if (!(jd && jd->in))
+		return NULL;
+
+	if (jd->buf == NULL) {
+		size_t sz = getpagesize();
+		if (sz < sizeof(*prefix))
+			sz = sizeof(*prefix);
+
+		jd->buf = malloc(sz);
+		if (jd->buf == NULL)
+			return NULL;
+
+		jd->bufsize = sz;
+	}
+
+	prefix = jd->buf;
+
+	/*
+	 * file is still locked at this point
+	 */
+	ret = fread(prefix, sizeof(*prefix), 1, jd->in);
+	if (ret  != 1)
+		return NULL;
+
+	if (jd->needs_bswap) {
+		prefix->id   	   = bswap_32(prefix->id);
+		prefix->total_size = bswap_32(prefix->total_size);
+		prefix->timestamp  = bswap_64(prefix->timestamp);
+	}
+	id   = prefix->id;
+	size = prefix->total_size;
+
+	bs = (size_t)size;
+	if (bs < sizeof(*prefix))
+		return NULL;
+
+	if (id >= JIT_CODE_MAX) {
+		pr_warning("next_entry: unknown prefix %d, skipping\n", id);
+		return NULL;
+	}
+	if (bs > jd->bufsize) {
+		void *n;
+		n = realloc(jd->buf, bs);
+		if (!n)
+			return NULL;
+		jd->buf = n;
+		jd->bufsize = bs;
+	}
+
+	addr = ((void *)jd->buf) + sizeof(*prefix);
+
+	ret = fread(addr, bs - sizeof(*prefix), 1, jd->in);
+	if (ret != 1)
+		return NULL;
+
+	jr = (union jr_entry *)jd->buf;
+
+	switch(id) {
+	case JIT_CODE_DEBUG_INFO:
+		if (jd->needs_bswap) {
+			uint64_t n;
+			jr->info.code_addr = bswap_64(jr->info.code_addr);
+			jr->info.nr_entry  = bswap_64(jr->info.nr_entry);
+			for (n = 0 ; n < jr->info.nr_entry; n++) {
+				jr->info.entries[n].addr    = bswap_64(jr->info.entries[n].addr);
+				jr->info.entries[n].lineno  = bswap_32(jr->info.entries[n].lineno);
+				jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
+			}
+		}
+		break;
+	case JIT_CODE_CLOSE:
+		break;
+	case JIT_CODE_LOAD:
+		if (jd->needs_bswap) {
+			jr->load.pid       = bswap_32(jr->load.pid);
+			jr->load.tid       = bswap_32(jr->load.tid);
+			jr->load.vma       = bswap_64(jr->load.vma);
+			jr->load.code_addr = bswap_64(jr->load.code_addr);
+			jr->load.code_size = bswap_64(jr->load.code_size);
+			jr->load.code_index= bswap_64(jr->load.code_index);
+		}
+		jd->code_load_count++;
+		break;
+	case JIT_CODE_MOVE:
+		if (jd->needs_bswap) {
+			jr->move.pid           = bswap_32(jr->move.pid);
+			jr->move.tid           = bswap_32(jr->move.tid);
+			jr->move.vma           = bswap_64(jr->move.vma);
+			jr->move.old_code_addr = bswap_64(jr->move.old_code_addr);
+			jr->move.new_code_addr = bswap_64(jr->move.new_code_addr);
+			jr->move.code_size     = bswap_64(jr->move.code_size);
+			jr->move.code_index    = bswap_64(jr->move.code_index);
+		}
+		break;
+	case JIT_CODE_MAX:
+	default:
+		return NULL;
+	}
+	return jr;
+}
+
+static int
+jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
+{
+	ssize_t size;
+
+	size = perf_data_file__write(jd->output, event, event->header.size);
+	if (size < 0)
+		return -1;
+
+	jd->bytes_written += size;
+	return 0;
+}
+
+static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
+{
+	struct perf_sample sample;
+	union perf_event *event;
+	struct perf_tool *tool = jd->session->tool;
+	uint64_t code, addr;
+	uintptr_t uaddr;
+	char *filename;
+	struct stat st;
+	size_t size;
+	u16 idr_size;
+	const char *sym;
+	uint32_t count;
+	int ret, csize;
+	pid_t pid, tid;
+	struct {
+		u32 pid, tid;
+		u64 time;
+	} *id;
+
+	pid   = jr->load.pid;
+	tid   = jr->load.tid;
+	csize = jr->load.code_size;
+	addr  = jr->load.code_addr;
+	sym   = (void *)((unsigned long)jr + sizeof(jr->load));
+	code  = (unsigned long)jr + jr->load.p.total_size - csize;
+	count = jr->load.code_index;
+	idr_size = jd->machine->id_hdr_size;
+
+	event = calloc(1, sizeof(*event) + idr_size);
+	if (!event)
+		return -1;
+
+	filename = event->mmap2.filename;
+	size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%u.so",
+			jd->dir,
+			pid,
+			count);
+
+	size++; /* for \0 */
+
+	size = PERF_ALIGN(size, sizeof(u64));
+	uaddr = (uintptr_t)code;
+	ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize);
+
+	if (jd->debug_data && jd->nr_debug_entries) {
+		free(jd->debug_data);
+		jd->debug_data = NULL;
+		jd->nr_debug_entries = 0;
+	}
+
+	if (ret) {
+		free(event);
+		return -1;
+	}
+	if (stat(filename, &st))
+		memset(&st, 0, sizeof(stat));
+
+	event->mmap2.header.type = PERF_RECORD_MMAP2;
+	event->mmap2.header.misc = PERF_RECORD_MISC_USER;
+	event->mmap2.header.size = (sizeof(event->mmap2) -
+			(sizeof(event->mmap2.filename) - size) + idr_size);
+
+	event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
+	event->mmap2.start = addr;
+	event->mmap2.len   = csize;
+	event->mmap2.pid   = pid;
+	event->mmap2.tid   = tid;
+	event->mmap2.ino   = st.st_ino;
+	event->mmap2.maj   = major(st.st_dev);
+	event->mmap2.min   = minor(st.st_dev);
+	event->mmap2.prot  = st.st_mode;
+	event->mmap2.flags = MAP_SHARED;
+	event->mmap2.ino_generation = 1;
+
+	id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
+	if (jd->sample_type & PERF_SAMPLE_TID) {
+		id->pid  = pid;
+		id->tid  = tid;
+	}
+	if (jd->sample_type & PERF_SAMPLE_TIME)
+		id->time = jr->load.p.timestamp;
+
+	/*
+	 * create pseudo sample to induce dso hit increment
+	 * use first address as sample address
+	 */
+	memset(&sample, 0, sizeof(sample));
+	sample.pid  = pid;
+	sample.tid  = tid;
+	sample.time = id->time;
+	sample.ip   = addr;
+
+	ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
+	if (ret)
+		return ret;
+
+	ret = jit_inject_event(jd, event);
+	/*
+	 * mark dso as use to generate buildid in the header
+	 */
+	if (!ret)
+		build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
+
+	return ret;
+}
+
+static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
+{
+	struct perf_sample sample;
+	union perf_event *event;
+	struct perf_tool *tool = jd->session->tool;
+	char *filename;
+	size_t size;
+	struct stat st;
+	u16 idr_size;
+	int ret;
+	pid_t pid, tid;
+	struct {
+		u32 pid, tid;
+		u64 time;
+	} *id;
+
+	pid = jr->move.pid;
+	tid =  jr->move.tid;
+	idr_size = jd->machine->id_hdr_size;
+
+	/*
+	 * +16 to account for sample_id_all (hack)
+	 */
+	event = calloc(1, sizeof(*event) + 16);
+	if (!event)
+		return -1;
+
+	filename = event->mmap2.filename;
+	size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%"PRIu64,
+	         jd->dir,
+	         pid,
+		 jr->move.code_index);
+
+	size++; /* for \0 */
+
+	if (stat(filename, &st))
+		memset(&st, 0, sizeof(stat));
+
+	size = PERF_ALIGN(size, sizeof(u64));
+
+	event->mmap2.header.type = PERF_RECORD_MMAP2;
+	event->mmap2.header.misc = PERF_RECORD_MISC_USER;
+	event->mmap2.header.size = (sizeof(event->mmap2) -
+			(sizeof(event->mmap2.filename) - size) + idr_size);
+	event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
+	event->mmap2.start = jr->move.new_code_addr;
+	event->mmap2.len   = jr->move.code_size;
+	event->mmap2.pid   = pid;
+	event->mmap2.tid   = tid;
+	event->mmap2.ino   = st.st_ino;
+	event->mmap2.maj   = major(st.st_dev);
+	event->mmap2.min   = minor(st.st_dev);
+	event->mmap2.prot  = st.st_mode;
+	event->mmap2.flags = MAP_SHARED;
+	event->mmap2.ino_generation = 1;
+
+	id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
+	if (jd->sample_type & PERF_SAMPLE_TID) {
+		id->pid  = pid;
+		id->tid  = tid;
+	}
+	if (jd->sample_type & PERF_SAMPLE_TIME)
+		id->time = jr->load.p.timestamp;
+
+	/*
+	 * create pseudo sample to induce dso hit increment
+	 * use first address as sample address
+	 */
+	memset(&sample, 0, sizeof(sample));
+	sample.pid  = pid;
+	sample.tid  = tid;
+	sample.time = id->time;
+	sample.ip   = jr->move.new_code_addr;
+
+	ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
+	if (ret)
+		return ret;
+
+	ret = jit_inject_event(jd, event);
+	if (!ret)
+		build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
+
+	return ret;
+}
+
+static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
+{
+	void *data;
+	size_t sz;
+
+	if (!(jd && jr))
+		return -1;
+
+	sz  = jr->prefix.total_size - sizeof(jr->info);
+	data = malloc(sz);
+	if (!data)
+		return -1;
+
+	memcpy(data, &jr->info.entries, sz);
+
+	jd->debug_data       = data;
+
+	/*
+	 * we must use nr_entry instead of size here because
+	 * we cannot distinguish actual entry from padding otherwise
+	 */
+	jd->nr_debug_entries = jr->info.nr_entry;
+
+	return 0;
+}
+
+static int
+jit_process_dump(struct jit_buf_desc *jd)
+{
+	union jr_entry *jr;
+	int ret;
+
+	while ((jr = jit_get_next_entry(jd))) {
+		switch(jr->prefix.id) {
+		case JIT_CODE_LOAD:
+			ret = jit_repipe_code_load(jd, jr);
+			break;
+		case JIT_CODE_MOVE:
+			ret = jit_repipe_code_move(jd, jr);
+			break;
+		case JIT_CODE_DEBUG_INFO:
+			ret = jit_repipe_debug_info(jd, jr);
+			break;
+		default:
+			ret = 0;
+			continue;
+		}
+	}
+	return ret;
+}
+
+static int
+jit_inject(struct jit_buf_desc *jd, char *path)
+{
+	int ret;
+
+	if (verbose > 0)
+		fprintf(stderr, "injecting: %s\n", path);
+
+	ret = jit_open(jd, path);
+	if (ret)
+		return -1;
+
+	ret = jit_process_dump(jd);
+
+	jit_close(jd);
+
+	if (verbose > 0)
+		fprintf(stderr, "injected: %s (%d)\n", path, ret);
+
+	return 0;
+}
+
+/*
+ * File must be with pattern .../jit-XXXX.dump
+ * where XXXX is the PID of the process which did the mmap()
+ * as captured in the RECORD_MMAP record
+ */
+static int
+jit_detect(char *mmap_name, pid_t pid)
+ {
+	char *p;
+	char *end = NULL;
+	pid_t pid2;
+
+	if (verbose > 2)
+		fprintf(stderr, "jit marker trying : %s\n", mmap_name);
+	/*
+	 * get file name
+	 */
+	p = strrchr(mmap_name, '/');
+	if (!p)
+		return -1;
+
+	/*
+	 * match prefix
+	 */
+	if (strncmp(p, "/jit-", 5))
+		return -1;
+
+	/*
+	 * skip prefix
+	 */
+	p += 5;
+
+	/*
+	 * must be followed by a pid
+	 */
+	if (!isdigit(*p))
+		return -1;
+
+	pid2 = (int)strtol(p, &end, 10);
+	if (!end)
+		return -1;
+
+	/*
+	 * pid does not match mmap pid
+	 * pid==0 in system-wide mode (synthesized)
+	 */
+	if (pid && pid2 != pid)
+		return -1;
+	/*
+	 * validate suffix
+	 */
+	if (strcmp(end, ".dump"))
+		return -1;
+
+	if (verbose > 0)
+		fprintf(stderr, "jit marker found: %s\n", mmap_name);
+
+	return 0;
+}
+
+int
+jit_process(struct perf_session *session,
+	    struct perf_data_file *output,
+	    struct machine *machine,
+	    char *filename,
+	    pid_t pid,
+	    u64 *nbytes)
+{
+	struct perf_evsel *first;
+	struct jit_buf_desc jd;
+	int ret;
+
+	/*
+	 * first, detect marker mmap (i.e., the jitdump mmap)
+	 */
+	if (jit_detect(filename, pid))
+		return -1;
+
+	memset(&jd, 0, sizeof(jd));
+
+	jd.session = session;
+	jd.output  = output;
+	jd.machine = machine;
+
+	/*
+	 * track sample_type to compute id_all layout
+	 * perf sets the same sample type to all events as of now
+	 */
+	first = perf_evlist__first(session->evlist);
+	jd.sample_type = first->attr.sample_type;
+
+	*nbytes = 0;
+
+	ret = jit_inject(&jd, filename);
+	if (!ret)
+		*nbytes = jd.bytes_written;
+
+	return ret;
+}
diff --git a/tools/perf/util/jitdump.h b/tools/perf/util/jitdump.h
new file mode 100644
index 0000000..b66c1f5
--- /dev/null
+++ b/tools/perf/util/jitdump.h
@@ -0,0 +1,124 @@
+/*
+ * jitdump.h: jitted code info encapsulation file format
+ *
+ * Adapted from OProfile GPLv2 support jidump.h:
+ * Copyright 2007 OProfile authors
+ * Jens Wilke
+ * Daniel Hansel
+ * Copyright IBM Corporation 2007
+ */
+#ifndef JITDUMP_H
+#define JITDUMP_H
+
+#include <sys/time.h>
+#include <time.h>
+#include <stdint.h>
+
+/* JiTD */
+#define JITHEADER_MAGIC		0x4A695444
+#define JITHEADER_MAGIC_SW	0x4454694A
+
+#define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7)
+
+#define JITHEADER_VERSION 1
+
+enum jitdump_flags_bits {
+	JITDUMP_FLAGS_MAX_BIT,
+};
+
+#define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
+				(~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
+
+struct jitheader {
+	uint32_t magic;		/* characters "jItD" */
+	uint32_t version;	/* header version */
+	uint32_t total_size;	/* total size of header */
+	uint32_t elf_mach;	/* elf mach target */
+	uint32_t pad1;		/* reserved */
+	uint32_t pid;		/* JIT process id */
+	uint64_t timestamp;	/* timestamp */
+	uint64_t flags;		/* flags */
+};
+
+enum jit_record_type {
+	JIT_CODE_LOAD		= 0,
+        JIT_CODE_MOVE           = 1,
+	JIT_CODE_DEBUG_INFO	= 2,
+	JIT_CODE_CLOSE		= 3,
+
+	JIT_CODE_MAX,
+};
+
+/* record prefix (mandatory in each record) */
+struct jr_prefix {
+	uint32_t id;
+	uint32_t total_size;
+	uint64_t timestamp;
+};
+
+struct jr_code_load {
+	struct jr_prefix p;
+
+	uint32_t pid;
+	uint32_t tid;
+	uint64_t vma;
+	uint64_t code_addr;
+	uint64_t code_size;
+	uint64_t code_index;
+};
+
+struct jr_code_close {
+	struct jr_prefix p;
+};
+
+struct jr_code_move {
+	struct jr_prefix p;
+
+	uint32_t pid;
+	uint32_t tid;
+	uint64_t vma;
+	uint64_t old_code_addr;
+	uint64_t new_code_addr;
+	uint64_t code_size;
+	uint64_t code_index;
+};
+
+struct debug_entry {
+	uint64_t addr;
+	int lineno;	    /* source line number starting at 1 */
+	int discrim;	    /* column discriminator, 0 is default */
+	const char name[0]; /* null terminated filename, \xff\0 if same as previous entry */
+};
+
+struct jr_code_debug_info {
+	struct jr_prefix p;
+
+	uint64_t code_addr;
+	uint64_t nr_entry;
+	struct debug_entry entries[0];
+};
+
+union jr_entry {
+        struct jr_code_debug_info info;
+        struct jr_code_close close;
+        struct jr_code_load load;
+        struct jr_code_move move;
+        struct jr_prefix prefix;
+};
+
+static inline struct debug_entry *
+debug_entry_next(struct debug_entry *ent)
+{
+	void *a = ent + 1;
+	size_t l = strlen(ent->name) + 1;
+	return a + l;
+}
+
+static inline char *
+debug_entry_file(struct debug_entry *ent)
+{
+	void *a = ent + 1;
+	return a;
+}
+
+#endif /* !JITDUMP_H */

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [tip:perf/core] perf tools: add JVMTI agent library
  2015-11-30  9:02 ` [PATCH v8 3/4] perf tools: add JVMTI agent library Stephane Eranian
@ 2016-02-09 12:16   ` tip-bot for Stephane Eranian
  0 siblings, 0 replies; 27+ messages in thread
From: tip-bot for Stephane Eranian @ 2016-02-09 12:16 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, sukadev, sonnyrao, hpa, mingo, ak, dsahern, peterz,
	adrian.hunter, johnmccutchan, acme, tglx, eranian, cel, jolsa,
	namhyung, pawel.moll

Commit-ID:  209045adc2bbdb2b315fa5539cec54d01cd3e7db
Gitweb:     http://git.kernel.org/tip/209045adc2bbdb2b315fa5539cec54d01cd3e7db
Author:     Stephane Eranian <eranian@google.com>
AuthorDate: Mon, 30 Nov 2015 10:02:22 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 5 Feb 2016 12:26:31 -0300

perf tools: add JVMTI agent library

This is a standalone JVMTI library to help  profile Java jitted code with perf
record/perf report. The library is not installed or compiled automatically by
perf Makefile. It is not used directly by perf. It is arch agnostic and has
been tested on X86 and ARM. It needs to be used with a Java runtime, such as
OpenJDK, as follows:

  $ java -agentpath:libjvmti.so .......

See the "Committer Notes" below on how to build it.

When used this way, java will generate a jitdump binary file in
$HOME/.debug/java/jit/java-jit-*

This binary dump file contains information to help symbolize and
annotate jitted code.

The jitdump information must be injected into the perf.data file
using:

  $ perf inject --jit -i perf.data -o perf.data.jitted

This injects the MMAP records to cover the jitted code and also generates
one ELF image for each jitted function. The ELF images are created in the
same subdir as the jitdump file. The MMAP records point there too.

Then, to visualize the function or asm profile, simply use the regular
perf commands:

  $ perf report -i perf.data.jitted

or

  $ perf annotate -i perf.data.jitted

JVMTI agent code adapted from the OProfile's opagent code.

This version of the JVMTI agent is using the CLOCK_MONOTONIC as the time
source to timestamp jit samples. To correlate with perf_events samples,
it needs to run on kernel 4.0.0-rc5+ or later with the following commit
from Peter Zijlstra:

  34f439278cef ("perf: Add per event clockid support")

With this patch recording jitted code is done as follows:

   $ perf record -k mono -- java -agentpath:libjvmti.so .......

 --------------------------------------------------------------------------

Committer Notes:

Extended testing instructions:

  $ cd tools/perf/jvmti/
  $ dnf install java-devel
  $ make

Then, create some simple java stuff to record some samples:

  $ cat hello.java
  public class hello {
	public static void main(String[] args) {
                 System.out.println("Hello, World");
       	}
  }
  $ javac hello.java
  $ java hello
  Hello, World
  $

And then record it using this jvmti thing:

  $ perf record -k mono java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
  java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jit-1908.dump
  Hello, World
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.030 MB perf.data (268 samples) ]
  $

Now lets insert the PERF_RECORD_MMAP2 records to point jitted mmaps to
files created by the agent:

  $ perf inject --jit -i perf.data -o perf.data.jitted

And finally see that it did its job:

  $ perf report -D -i perf.data.jitted | grep PERF_RECORD_MMAP2 | tail -5
  79197149129422 0xfe10 [0xa0]: PERF_RECORD_MMAP2 1908/1923: [0x7f172428bd60(0x80) @ 0x40 fd:02 1840554 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-283.so
  79197149235701 0xfeb0 [0xa0]: PERF_RECORD_MMAP2 1908/1923: [0x7f172428ba60(0x180) @ 0x40 fd:02 1840555 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-284.so
  79197149250558 0xff50 [0xa0]: PERF_RECORD_MMAP2 1908/1923: [0x7f172428b860(0x180) @ 0x40 fd:02 1840556 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-285.so
  79197149714746 0xfff0 [0xa0]: PERF_RECORD_MMAP2 1908/1923: [0x7f172428b660(0x180) @ 0x40 fd:02 1840557 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-286.so
  79197149806558 0x10090 [0xa0]: PERF_RECORD_MMAP2 1908/1923: [0x7f172428b460(0x180) @ 0x40 fd:02 1840558 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-287.so
  $

So:

  $ perf report -D -i perf.data | grep PERF_RECORD_MMAP2 | wc -l
  Failed to open /tmp/perf-1908.map, continuing without symbols
  21
  $ perf report -D -i perf.data.jitted | grep PERF_RECORD_MMAP2 | wc -l
  307
  $ echo $((307 - 21))
  286
  $

286 extra PERF_RECORD_MMAP2 records.

All for thise tiny, with just one function, ELF files:

  $ file /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-9.so
  /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-9.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), corrupted program header size, BuildID[sha1]=ae54a2ebc3ecf0ba547bfc8cabdea1519df5203f, not stripped
  $ readelf -sw /home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-9.so

  Symbol table '.symtab' contains 2 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000040     9 FUNC    LOCAL  DEFAULT    1 atomic_cmpxchg_long
  $

Inserted into the build-id cache:

  $ ls -la ~/.debug/.build-id/ae/54a2ebc3ecf0ba547bfc8cabdea1519df5203f
  lrwxrwxrwx. 1 acme acme 111 Feb  5 11:30 /home/acme/.debug/.build-id/ae/54a2ebc3ecf0ba547bfc8cabdea1519df5203f -> ../../home/acme/.debug/jit/java-jit-20160205.XXWIEDls/jitted-1908-9.so/ae54a2ebc3ecf0ba547bfc8cabdea1519df5203f

Note: check why 'file' reports that 'corrupted program header size'.

With a stupid java hog to do some profiling:

$ cat hog.java
  public class hog {
	private static double do_something_else(int i) {
		double total = 0;
		while (i > 0) {
			total += Math.log(i--);
		}
		return total;
	}
	private static double do_something(int i) {
		double total = 0;
		while (i > 0) {
			total += Math.sqrt(i--) + do_something_else(i / 100);
		}
		return total;
	}
	public static void main(String[] args) {
		System.out.println(String.format("%s=%f & %f", args[0],
				   do_something(Integer.parseInt(args[0])),
				   do_something_else(Integer.parseInt(args[1]))));
	}
  }
  $ javac hog.java
  $ perf record -F 10000 -g -k mono java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hog 100000 2345000
  java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XX4sqd14/jit-8670.dump
  100000=291561592.669602 & 32050989.778714
  [ perf record: Woken up 6 times to write data ]
  [ perf record: Captured and wrote 1.536 MB perf.data (12538 samples) ]
  $ perf inject --jit -i perf.data -o perf.data.jitted

Looking at the 'perf report' TUI, at one expanded callchain leading
to the jitted code:

  $ perf report --no-children -i perf.data.jitted

Samples: 12K of event 'cycles:pp', Event count (approx.): 3829569932
  Overhead  Comm  Shared Object       Symbol
-   93.38%  java  jitted-8670-291.so  [.] class hog.do_something_else(int)
     class hog.do_something_else(int)
   - Interpreter
      - 75.86% call_stub
           JavaCalls::call_helper
           jni_invoke_static
           jni_CallStaticVoidMethod
           JavaMain
           start_thread
      - 17.52% JavaCalls::call_helper
           jni_invoke_static
           jni_CallStaticVoidMethod
           JavaMain
           start_thread

Signed-off-by: Stephane Eranian <eranian@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.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-4-git-send-email-eranian@google.com
[ Made it build on fedora23, added some build/usage instructions ]
[ Check if filename != NULL in compiled_method_load_cb, fixing segfault ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/jvmti/Makefile      |  76 +++++++
 tools/perf/jvmti/jvmti_agent.c | 465 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/jvmti/jvmti_agent.h |  29 +++
 tools/perf/jvmti/libjvmti.c    | 208 ++++++++++++++++++
 4 files changed, 778 insertions(+)

diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
new file mode 100644
index 0000000..5968f83
--- /dev/null
+++ b/tools/perf/jvmti/Makefile
@@ -0,0 +1,76 @@
+ARCH=$(shell uname -m)
+
+ifeq ($(ARCH), x86_64)
+JARCH=amd64
+endif
+ifeq ($(ARCH), armv7l)
+JARCH=armhf
+endif
+ifeq ($(ARCH), armv6l)
+JARCH=armhf
+endif
+ifeq ($(ARCH), aarch64)
+JARCH=aarch64
+endif
+ifeq ($(ARCH), ppc64)
+JARCH=powerpc
+endif
+ifeq ($(ARCH), ppc64le)
+JARCH=powerpc
+endif
+
+DESTDIR=/usr/local
+
+VERSION=1
+REVISION=0
+AGE=0
+
+LN=ln -sf
+RM=rm
+
+SLIBJVMTI=libjvmti.so.$(VERSION).$(REVISION).$(AGE)
+VLIBJVMTI=libjvmti.so.$(VERSION)
+SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBJVMTI)
+SOLIBEXT=so
+
+# The following works at least on fedora 23, you may need the next
+# line for other distros.
+JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
+#JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
+# -lrt required in 32-bit mode for clock_gettime()
+LIBS=-lelf -lrt
+INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
+
+TARGETS=$(SLIBJVMTI)
+
+SRCS=libjvmti.c jvmti_agent.c
+OBJS=$(SRCS:.c=.o)
+SOBJS=$(OBJS:.o=.lo)
+OPT=-O2 -g -Werror -Wall
+
+CFLAGS=$(INCDIR) $(OPT)
+
+all: $(TARGETS)
+
+.c.o:
+	$(CC) $(CFLAGS) -c $*.c
+.c.lo:
+	$(CC) -fPIC -DPIC $(CFLAGS) -c $*.c -o $*.lo
+
+$(OBJS) $(SOBJS): Makefile jvmti_agent.h ../util/jitdump.h
+
+$(SLIBJVMTI):  $(SOBJS)
+	$(CC) $(CFLAGS) $(SLDFLAGS)  -o $@ $(SOBJS) $(LIBS)
+	$(LN) $@ libjvmti.$(SOLIBEXT)
+
+clean:
+	$(RM) -f *.o *.so.* *.so *.lo
+
+install:
+	-mkdir -p $(DESTDIR)/lib
+	install -m 755 $(SLIBJVMTI) $(DESTDIR)/lib/
+	(cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) $(VLIBJVMTI))
+	(cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) libjvmti.$(SOLIBEXT))
+	ldconfig
+
+.SUFFIXES: .c .S .o .lo
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
new file mode 100644
index 0000000..cbab139
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -0,0 +1,465 @@
+/*
+ * jvmti_agent.c: JVMTI agent interface
+ *
+ * Adapted from the Oprofile code in opagent.c:
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Copyright 2007 OProfile authors
+ * Jens Wilke
+ * Daniel Hansel
+ * Copyright IBM Corporation 2007
+ */
+#include <sys/types.h>
+#include <sys/stat.h> /* for mkdir() */
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <syscall.h> /* for gettid() */
+#include <err.h>
+
+#include "jvmti_agent.h"
+#include "../util/jitdump.h"
+
+#define JIT_LANG "java"
+
+static char jit_path[PATH_MAX];
+static void *marker_addr;
+
+/*
+ * padding buffer
+ */
+static const char pad_bytes[7];
+
+static inline pid_t gettid(void)
+{
+	return (pid_t)syscall(__NR_gettid);
+}
+
+static int get_e_machine(struct jitheader *hdr)
+{
+	ssize_t sret;
+	char id[16];
+	int fd, ret = -1;
+	int m = -1;
+	struct {
+		uint16_t e_type;
+		uint16_t e_machine;
+	} info;
+
+	fd = open("/proc/self/exe", O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	sret = read(fd, id, sizeof(id));
+	if (sret != sizeof(id))
+		goto error;
+
+	/* check ELF signature */
+	if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F')
+		goto error;
+
+	sret = read(fd, &info, sizeof(info));
+	if (sret != sizeof(info))
+		goto error;
+
+	m = info.e_machine;
+	if (m < 0)
+		m = 0; /* ELF EM_NONE */
+
+	hdr->elf_mach = m;
+	ret = 0;
+error:
+	close(fd);
+	return ret;
+}
+
+#define NSEC_PER_SEC	1000000000
+static int perf_clk_id = CLOCK_MONOTONIC;
+
+static inline uint64_t
+timespec_to_ns(const struct timespec *ts)
+{
+        return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
+}
+
+static inline uint64_t
+perf_get_timestamp(void)
+{
+	struct timespec ts;
+	int ret;
+
+	ret = clock_gettime(perf_clk_id, &ts);
+	if (ret)
+		return 0;
+
+	return timespec_to_ns(&ts);
+}
+
+static int
+debug_cache_init(void)
+{
+	char str[32];
+	char *base, *p;
+	struct tm tm;
+	time_t t;
+	int ret;
+
+	time(&t);
+	localtime_r(&t, &tm);
+
+	base = getenv("JITDUMPDIR");
+	if (!base)
+		base = getenv("HOME");
+	if (!base)
+		base = ".";
+
+	strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
+
+	snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base);
+
+	ret = mkdir(jit_path, 0755);
+	if (ret == -1) {
+		if (errno != EEXIST) {
+			warn("jvmti: cannot create jit cache dir %s", jit_path);
+			return -1;
+		}
+	}
+
+	snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base);
+	ret = mkdir(jit_path, 0755);
+	if (ret == -1) {
+		if (errno != EEXIST) {
+			warn("cannot create jit cache dir %s", jit_path);
+			return -1;
+		}
+	}
+
+	snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str);
+
+	p = mkdtemp(jit_path);
+	if (p != jit_path) {
+		warn("cannot create jit cache dir %s", jit_path);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+perf_open_marker_file(int fd)
+{
+	long pgsz;
+
+	pgsz = sysconf(_SC_PAGESIZE);
+	if (pgsz == -1)
+		return -1;
+
+	/*
+	 * we mmap the jitdump to create an MMAP RECORD in perf.data file.
+	 * The mmap is captured either live (perf record running when we mmap)
+	 * or  in deferred mode, via /proc/PID/maps
+	 * the MMAP record is used as a marker of a jitdump file for more meta
+	 * data info about the jitted code. Perf report/annotate detect this
+	 * special filename and process the jitdump file.
+	 *
+	 * mapping must be PROT_EXEC to ensure it is captured by perf record
+	 * even when not using -d option
+	 */
+	marker_addr = mmap(NULL, pgsz, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
+	return (marker_addr == MAP_FAILED) ? -1 : 0;
+}
+
+static void
+perf_close_marker_file(void)
+{
+	long pgsz;
+
+	if (!marker_addr)
+		return;
+
+	pgsz = sysconf(_SC_PAGESIZE);
+	if (pgsz == -1)
+		return;
+
+	munmap(marker_addr, pgsz);
+}
+
+void *jvmti_open(void)
+{
+	int pad_cnt;
+	char dump_path[PATH_MAX];
+	struct jitheader header;
+	int fd;
+	FILE *fp;
+
+	/*
+	 * check if clockid is supported
+	 */
+	if (!perf_get_timestamp())
+		warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
+
+	memset(&header, 0, sizeof(header));
+
+	debug_cache_init();
+
+	/*
+	 * jitdump file name
+	 */
+	snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
+
+	fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
+	if (fd == -1)
+		return NULL;
+
+	/*
+	 * create perf.data maker for the jitdump file
+	 */
+	if (perf_open_marker_file(fd)) {
+		warnx("jvmti: failed to create marker file");
+		return NULL;
+	}
+
+	fp = fdopen(fd, "w+");
+	if (!fp) {
+		warn("jvmti: cannot create %s", dump_path);
+		close(fd);
+		goto error;
+	}
+
+	warnx("jvmti: jitdump in %s", dump_path);
+
+	if (get_e_machine(&header)) {
+		warn("get_e_machine failed\n");
+		goto error;
+	}
+
+	header.magic      = JITHEADER_MAGIC;
+	header.version    = JITHEADER_VERSION;
+	header.total_size = sizeof(header);
+	header.pid        = getpid();
+
+	/* calculate amount of padding '\0' */
+	pad_cnt = PADDING_8ALIGNED(header.total_size);
+	header.total_size += pad_cnt;
+
+	header.timestamp = perf_get_timestamp();
+
+	if (!fwrite(&header, sizeof(header), 1, fp)) {
+		warn("jvmti: cannot write dumpfile header");
+		goto error;
+	}
+
+	/* write padding '\0' if necessary */
+	if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, fp)) {
+		warn("jvmti: cannot write dumpfile header padding");
+		goto error;
+	}
+
+	return fp;
+error:
+	fclose(fp);
+	return NULL;
+}
+
+int
+jvmti_close(void *agent)
+{
+	struct jr_code_close rec;
+	FILE *fp = agent;
+
+	if (!fp) {
+		warnx("jvmti: incalid fd in close_agent");
+		return -1;
+	}
+
+	rec.p.id = JIT_CODE_CLOSE;
+	rec.p.total_size = sizeof(rec);
+
+	rec.p.timestamp = perf_get_timestamp();
+
+	if (!fwrite(&rec, sizeof(rec), 1, fp))
+		return -1;
+
+	fclose(fp);
+
+	fp = NULL;
+
+	perf_close_marker_file();
+
+	return 0;
+}
+
+int
+jvmti_write_code(void *agent, char const *sym,
+	uint64_t vma, void const *code, unsigned int const size)
+{
+	static int code_generation = 1;
+	struct jr_code_load rec;
+	size_t sym_len;
+	size_t padding_count;
+	FILE *fp = agent;
+	int ret = -1;
+
+	/* don't care about 0 length function, no samples */
+	if (size == 0)
+		return 0;
+
+	if (!fp) {
+		warnx("jvmti: invalid fd in write_native_code");
+		return -1;
+	}
+
+	sym_len = strlen(sym) + 1;
+
+	rec.p.id           = JIT_CODE_LOAD;
+	rec.p.total_size   = sizeof(rec) + sym_len;
+	padding_count      = PADDING_8ALIGNED(rec.p.total_size);
+	rec.p. total_size += padding_count;
+	rec.p.timestamp    = perf_get_timestamp();
+
+	rec.code_size  = size;
+	rec.vma        = vma;
+	rec.code_addr  = vma;
+	rec.pid	       = getpid();
+	rec.tid	       = gettid();
+
+	if (code)
+		rec.p.total_size += size;
+
+	/*
+	 * If JVM is multi-threaded, nultiple concurrent calls to agent
+	 * may be possible, so protect file writes
+	 */
+	flockfile(fp);
+
+	/*
+	 * get code index inside lock to avoid race condition
+	 */
+	rec.code_index = code_generation++;
+
+	ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
+	fwrite_unlocked(sym, sym_len, 1, fp);
+
+	if (padding_count)
+		fwrite_unlocked(pad_bytes, padding_count, 1, fp);
+
+	if (code)
+		fwrite_unlocked(code, size, 1, fp);
+
+	funlockfile(fp);
+
+	ret = 0;
+
+	return ret;
+}
+
+int
+jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
+		       jvmtiAddrLocationMap const *map,
+		       jvmtiLineNumberEntry *li, jint num)
+{
+	static const char *prev_str = "\xff";
+	struct jr_code_debug_info rec;
+	size_t sret, len, size, flen;
+	size_t padding_count;
+	FILE *fp = agent;
+	int i;
+
+	/*
+	 * no entry to write
+	 */
+	if (!num)
+		return 0;
+
+	if (!fp) {
+		warnx("jvmti: invalid fd in write_debug_info");
+		return -1;
+	}
+
+	flen = strlen(file) + 1;
+
+	rec.p.id        = JIT_CODE_DEBUG_INFO;
+	size            = sizeof(rec);
+	rec.p.timestamp = perf_get_timestamp();
+	rec.code_addr   = (uint64_t)(uintptr_t)code;
+	rec.nr_entry    = num;
+
+	/*
+	 * on disk source line info layout:
+	 * uint64_t : addr
+	 * int      : line number
+	 * file[]   : source file name
+	 * padding  : pad to multiple of 8 bytes
+	 */
+	size += num * (sizeof(uint64_t) + sizeof(int));
+	size += flen + (num - 1) * 2;
+	/*
+	 * pad to 8 bytes
+	 */
+	padding_count = PADDING_8ALIGNED(size);
+
+	rec.p.total_size = size + padding_count;
+
+	/*
+	 * If JVM is multi-threaded, nultiple concurrent calls to agent
+	 * may be possible, so protect file writes
+	 */
+	flockfile(fp);
+
+	sret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
+	if (sret != 1)
+		goto error;
+
+	for (i = 0; i < num; i++) {
+		uint64_t addr;
+
+		addr = (uint64_t)map[i].start_address;
+		len  = sizeof(addr);
+		sret = fwrite_unlocked(&addr, len, 1, fp);
+		if (sret != 1)
+			goto error;
+
+		len  = sizeof(int);
+		sret = fwrite_unlocked(&li[i].line_number, len, 1, fp);
+		if (sret != 1)
+			goto error;
+
+		if (i == 0) {
+			sret = fwrite_unlocked(file, flen, 1, fp);
+		} else {
+			sret = fwrite_unlocked(prev_str, 2, 1, fp);
+		}
+		if (sret != 1)
+			goto error;
+
+	}
+	if (padding_count)
+		sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp);
+		if (sret != 1)
+			goto error;
+
+	funlockfile(fp);
+	return 0;
+error:
+	funlockfile(fp);
+	return -1;
+}
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h
new file mode 100644
index 0000000..8251a1c
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.h
@@ -0,0 +1,29 @@
+#ifndef __JVMTI_AGENT_H__
+#define __JVMTI_AGENT_H__
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <jvmti.h>
+
+#define __unused __attribute__((unused))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void *jvmti_open(void);
+int   jvmti_close(void *agent);
+int   jvmti_write_code(void *agent, char const *symbol_name,
+		       uint64_t vma, void const *code,
+		       const unsigned int code_size);
+int   jvmti_write_debug_info(void *agent,
+		             uint64_t code,
+			     const char *file,
+			     jvmtiAddrLocationMap const *map,
+			     jvmtiLineNumberEntry *tab, jint nr);
+
+#if defined(__cplusplus)
+}
+
+#endif
+#endif /* __JVMTI_H__ */
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
new file mode 100644
index 0000000..92ffbe4
--- /dev/null
+++ b/tools/perf/jvmti/libjvmti.c
@@ -0,0 +1,208 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+#include <jvmti.h>
+#include <limits.h>
+
+#include "jvmti_agent.h"
+
+static int has_line_numbers;
+void *jvmti_agent;
+
+static void JNICALL
+compiled_method_load_cb(jvmtiEnv *jvmti,
+			jmethodID method,
+			jint code_size,
+			void const *code_addr,
+			jint map_length,
+			jvmtiAddrLocationMap const *map,
+			void const *compile_info __unused)
+{
+	jvmtiLineNumberEntry *tab = NULL;
+	jclass decl_class;
+	char *class_sign = NULL;
+	char *func_name = NULL;
+	char *func_sign = NULL;
+	char *file_name= NULL;
+	char fn[PATH_MAX];
+	uint64_t addr = (uint64_t)(uintptr_t)code_addr;
+	jvmtiError ret;
+	jint nr_lines = 0;
+	size_t len;
+
+	ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
+						&decl_class);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: cannot get declaring class");
+		return;
+	}
+
+	if (has_line_numbers && map && map_length) {
+
+		ret = (*jvmti)->GetLineNumberTable(jvmti, method, &nr_lines, &tab);
+		if (ret != JVMTI_ERROR_NONE) {
+			warnx("jvmti: cannot get line table for method");
+		} else {
+			ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
+			if (ret != JVMTI_ERROR_NONE) {
+				warnx("jvmti: cannot get source filename ret=%d", ret);
+				nr_lines = 0;
+			}
+		}
+	}
+
+	ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
+					  &class_sign, NULL);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: getclassignature failed");
+		goto error;
+	}
+
+	ret = (*jvmti)->GetMethodName(jvmti, method, &func_name,
+				      &func_sign, NULL);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: failed getmethodname");
+		goto error;
+	}
+
+	/*
+	 * Assume path name is class hierarchy, this is a common practice with Java programs
+	 */
+	if (*class_sign == 'L') {
+		int j, i = 0;
+		char *p = strrchr(class_sign, '/');
+		if (p) {
+			/* drop the 'L' prefix and copy up to the final '/' */
+			for (i = 0; i < (p - class_sign); i++)
+				fn[i] = class_sign[i+1];
+		}
+		/*
+		 * append file name, we use loops and not string ops to avoid modifying
+		 * class_sign which is used later for the symbol name
+		 */
+		for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++)
+			fn[i] = file_name[j];
+		fn[i] = '\0';
+	} else {
+		/* fallback case */
+		strcpy(fn, file_name);
+	}
+	/*
+	 * write source line info record if we have it
+	 */
+	if (jvmti_write_debug_info(jvmti_agent, addr, fn, map, tab, nr_lines))
+		warnx("jvmti: write_debug_info() failed");
+
+	len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
+	{
+		char str[len];
+		snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
+		if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
+			warnx("jvmti: write_code() failed");
+	}
+error:
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)tab);
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
+}
+
+static void JNICALL
+code_generated_cb(jvmtiEnv *jvmti,
+		  char const *name,
+		  void const *code_addr,
+		  jint code_size)
+{
+	uint64_t addr = (uint64_t)(unsigned long)code_addr;
+	int ret;
+
+	ret = jvmti_write_code(jvmti_agent, name, addr, code_addr, code_size);
+	if (ret)
+		warnx("jvmti: write_code() failed for code_generated");
+}
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
+{
+	jvmtiEventCallbacks cb;
+	jvmtiCapabilities caps1;
+	jvmtiJlocationFormat format;
+	jvmtiEnv *jvmti = NULL;
+	jint ret;
+
+	jvmti_agent = jvmti_open();
+	if (!jvmti_agent) {
+		warnx("jvmti: open_agent failed");
+		return -1;
+	}
+
+	/*
+	 * Request a JVMTI interface version 1 environment
+	 */
+	ret = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);
+	if (ret != JNI_OK) {
+		warnx("jvmti: jvmti version 1 not supported");
+		return -1;
+	}
+
+	/*
+	 * acquire method_load capability, we require it
+	 * request line numbers (optional)
+	 */
+	memset(&caps1, 0, sizeof(caps1));
+	caps1.can_generate_compiled_method_load_events = 1;
+
+	ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: acquire compiled_method capability failed");
+		return -1;
+	}
+	ret = (*jvmti)->GetJLocationFormat(jvmti, &format);
+        if (ret == JVMTI_ERROR_NONE && format == JVMTI_JLOCATION_JVMBCI) {
+                memset(&caps1, 0, sizeof(caps1));
+                caps1.can_get_line_numbers = 1;
+                caps1.can_get_source_file_name = 1;
+		ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
+                if (ret == JVMTI_ERROR_NONE)
+                        has_line_numbers = 1;
+        }
+
+	memset(&cb, 0, sizeof(cb));
+
+	cb.CompiledMethodLoad   = compiled_method_load_cb;
+	cb.DynamicCodeGenerated = code_generated_cb;
+
+	ret = (*jvmti)->SetEventCallbacks(jvmti, &cb, sizeof(cb));
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: cannot set event callbacks");
+		return -1;
+	}
+
+	ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
+			JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: setnotification failed for method_load");
+		return -1;
+	}
+
+	ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
+			JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: setnotification failed on code_generated");
+		return -1;
+	}
+	return 0;
+}
+
+JNIEXPORT void JNICALL
+Agent_OnUnload(JavaVM *jvm __unused)
+{
+	int ret;
+
+	ret = jvmti_close(jvmti_agent);
+	if (ret)
+		errx(1, "Error: op_close_agent()");
+}

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [tip:perf/core] perf jit: add source line info support
  2015-11-30  9:02 ` [PATCH v8 4/4] perf/jit: add source line info support Stephane Eranian
@ 2016-02-09 12:16   ` tip-bot for Stephane Eranian
  0 siblings, 0 replies; 27+ messages in thread
From: tip-bot for Stephane Eranian @ 2016-02-09 12:16 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, acme, dsahern, namhyung, johnmccutchan, tglx,
	eranian, pawel.moll, sonnyrao, sukadev, cel, peterz, mingo, ak,
	jolsa, adrian.hunter, hpa

Commit-ID:  598b7c6919c7bbcc1243009721a01bc12275ff3e
Gitweb:     http://git.kernel.org/tip/598b7c6919c7bbcc1243009721a01bc12275ff3e
Author:     Stephane Eranian <eranian@google.com>
AuthorDate: Mon, 30 Nov 2015 10:02:23 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 5 Feb 2016 12:33:09 -0300

perf jit: add source line info support

This patch adds source line information support to perf for jitted code.

The source line info must be emitted by the runtime, such as JVMTI.

Perf injects extract the source line info from the jitdump file and adds
the corresponding .debug_lines section in the ELF image generated for
each jitted function.

The source line enables matching any address in the profile with a
source file and line number.

The improvement is visible in perf annotate with the source code
displayed alongside the assembly code.

The dwarf code leverages the support from OProfile which is also
released under GPLv2.  Copyright 2007 OProfile authors.

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-5-git-send-email-eranian@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/jvmti/jvmti_agent.c |  32 +--
 tools/perf/jvmti/jvmti_agent.h |  11 +-
 tools/perf/jvmti/libjvmti.c    | 122 ++++++++-
 tools/perf/util/Build          |   3 +
 tools/perf/util/genelf.c       |  15 +-
 tools/perf/util/genelf.h       |   6 +-
 tools/perf/util/genelf_debug.c | 610 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/jitdump.c      |   8 +-
 8 files changed, 768 insertions(+), 39 deletions(-)

diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
index cbab139..6461e02 100644
--- a/tools/perf/jvmti/jvmti_agent.c
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -374,20 +374,20 @@ jvmti_write_code(void *agent, char const *sym,
 
 int
 jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
-		       jvmtiAddrLocationMap const *map,
-		       jvmtiLineNumberEntry *li, jint num)
+		       jvmti_line_info_t *li, int nr_lines)
 {
-	static const char *prev_str = "\xff";
 	struct jr_code_debug_info rec;
 	size_t sret, len, size, flen;
 	size_t padding_count;
+	uint64_t addr;
+	const char *fn = file;
 	FILE *fp = agent;
 	int i;
 
 	/*
 	 * no entry to write
 	 */
-	if (!num)
+	if (!nr_lines)
 		return 0;
 
 	if (!fp) {
@@ -401,17 +401,18 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
 	size            = sizeof(rec);
 	rec.p.timestamp = perf_get_timestamp();
 	rec.code_addr   = (uint64_t)(uintptr_t)code;
-	rec.nr_entry    = num;
+	rec.nr_entry    = nr_lines;
 
 	/*
 	 * on disk source line info layout:
 	 * uint64_t : addr
 	 * int      : line number
+	 * int      : column discriminator
 	 * file[]   : source file name
 	 * padding  : pad to multiple of 8 bytes
 	 */
-	size += num * (sizeof(uint64_t) + sizeof(int));
-	size += flen + (num - 1) * 2;
+	size += nr_lines * sizeof(struct debug_entry);
+	size += flen * nr_lines;
 	/*
 	 * pad to 8 bytes
 	 */
@@ -429,28 +430,27 @@ jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
 	if (sret != 1)
 		goto error;
 
-	for (i = 0; i < num; i++) {
-		uint64_t addr;
+	for (i = 0; i < nr_lines; i++) {
 
-		addr = (uint64_t)map[i].start_address;
+		addr = (uint64_t)li[i].pc;
 		len  = sizeof(addr);
 		sret = fwrite_unlocked(&addr, len, 1, fp);
 		if (sret != 1)
 			goto error;
 
-		len  = sizeof(int);
+		len  = sizeof(li[0].line_number);
 		sret = fwrite_unlocked(&li[i].line_number, len, 1, fp);
 		if (sret != 1)
 			goto error;
 
-		if (i == 0) {
-			sret = fwrite_unlocked(file, flen, 1, fp);
-		} else {
-			sret = fwrite_unlocked(prev_str, 2, 1, fp);
-		}
+		len  = sizeof(li[0].discrim);
+		sret = fwrite_unlocked(&li[i].discrim, len, 1, fp);
 		if (sret != 1)
 			goto error;
 
+		sret = fwrite_unlocked(fn, flen, 1, fp);
+		if (sret != 1)
+			goto error;
 	}
 	if (padding_count)
 		sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp);
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h
index 8251a1c..bedf5d0 100644
--- a/tools/perf/jvmti/jvmti_agent.h
+++ b/tools/perf/jvmti/jvmti_agent.h
@@ -11,16 +11,23 @@
 extern "C" {
 #endif
 
+typedef struct {
+	unsigned long	pc;
+	int		line_number;
+	int		discrim; /* discriminator -- 0 for now */
+} jvmti_line_info_t;
+
 void *jvmti_open(void);
 int   jvmti_close(void *agent);
 int   jvmti_write_code(void *agent, char const *symbol_name,
 		       uint64_t vma, void const *code,
 		       const unsigned int code_size);
+
 int   jvmti_write_debug_info(void *agent,
 		             uint64_t code,
 			     const char *file,
-			     jvmtiAddrLocationMap const *map,
-			     jvmtiLineNumberEntry *tab, jint nr);
+			     jvmti_line_info_t *li,
+			     int nr_lines);
 
 #if defined(__cplusplus)
 }
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
index 92ffbe4..ac12e4b 100644
--- a/tools/perf/jvmti/libjvmti.c
+++ b/tools/perf/jvmti/libjvmti.c
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <err.h>
 #include <jvmti.h>
+#include <jvmticmlr.h>
 #include <limits.h>
 
 #include "jvmti_agent.h"
@@ -11,6 +12,100 @@
 static int has_line_numbers;
 void *jvmti_agent;
 
+static jvmtiError
+do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
+		    jvmti_line_info_t *tab, jint *nr)
+{
+	jint i, lines = 0;
+	jint nr_lines = 0;
+	jvmtiLineNumberEntry *loc_tab = NULL;
+	jvmtiError ret;
+
+	ret = (*jvmti)->GetLineNumberTable(jvmti, m, &nr_lines, &loc_tab);
+	if (ret != JVMTI_ERROR_NONE)
+		return ret;
+
+	for (i = 0; i < nr_lines; i++) {
+		if (loc_tab[i].start_location < bci) {
+			tab[lines].pc = (unsigned long)pc;
+			tab[lines].line_number = loc_tab[i].line_number;
+			tab[lines].discrim = 0; /* not yet used */
+			lines++;
+		} else {
+			break;
+		}
+	}
+	(*jvmti)->Deallocate(jvmti, (unsigned char *)loc_tab);
+	*nr = lines;
+	return JVMTI_ERROR_NONE;
+}
+
+static jvmtiError
+get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **tab, int *nr_lines)
+{
+	const jvmtiCompiledMethodLoadRecordHeader *hdr;
+	jvmtiCompiledMethodLoadInlineRecord *rec;
+	jvmtiLineNumberEntry *lne = NULL;
+	PCStackInfo *c;
+	jint nr, ret;
+	int nr_total = 0;
+	int i, lines_total = 0;
+
+	if (!(tab && nr_lines))
+		return JVMTI_ERROR_NULL_POINTER;
+
+	/*
+	 * Phase 1 -- get the number of lines necessary
+	 */
+	for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
+		if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
+			rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
+			for (i = 0; i < rec->numpcs; i++) {
+				c = rec->pcinfo + i;
+				nr = 0;
+				/*
+				 * unfortunately, need a tab to get the number of lines!
+				 */
+				ret = (*jvmti)->GetLineNumberTable(jvmti, c->methods[0], &nr, &lne);
+				if (ret == JVMTI_ERROR_NONE) {
+					/* free what was allocated for nothing */
+					(*jvmti)->Deallocate(jvmti, (unsigned char *)lne);
+					nr_total += (int)nr;
+				}
+			}
+		}
+	}
+
+	if (nr_total == 0)
+		return JVMTI_ERROR_NOT_FOUND;
+
+	/*
+	 * Phase 2 -- allocate big enough line table
+	 */
+	*tab = malloc(nr_total * sizeof(**tab));
+	if (!*tab)
+		return JVMTI_ERROR_OUT_OF_MEMORY;
+
+	for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
+		if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
+			rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
+			for (i = 0; i < rec->numpcs; i++) {
+				c = rec->pcinfo + i;
+				nr = 0;
+				ret = do_get_line_numbers(jvmti, c->pc,
+							  c->methods[0],
+							  c->bcis[0],
+							  *tab + lines_total,
+							  &nr);
+				if (ret == JVMTI_ERROR_NONE)
+					lines_total += nr;
+			}
+		}
+	}
+	*nr_lines = lines_total;
+	return JVMTI_ERROR_NONE;
+}
+
 static void JNICALL
 compiled_method_load_cb(jvmtiEnv *jvmti,
 			jmethodID method,
@@ -18,9 +113,9 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 			void const *code_addr,
 			jint map_length,
 			jvmtiAddrLocationMap const *map,
-			void const *compile_info __unused)
+			const void *compile_info)
 {
-	jvmtiLineNumberEntry *tab = NULL;
+	jvmti_line_info_t *line_tab = NULL;
 	jclass decl_class;
 	char *class_sign = NULL;
 	char *func_name = NULL;
@@ -29,7 +124,7 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 	char fn[PATH_MAX];
 	uint64_t addr = (uint64_t)(uintptr_t)code_addr;
 	jvmtiError ret;
-	jint nr_lines = 0;
+	int nr_lines = 0; /* in line_tab[] */
 	size_t len;
 
 	ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
@@ -40,19 +135,19 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 	}
 
 	if (has_line_numbers && map && map_length) {
-
-		ret = (*jvmti)->GetLineNumberTable(jvmti, method, &nr_lines, &tab);
+		ret = get_line_numbers(jvmti, compile_info, &line_tab, &nr_lines);
 		if (ret != JVMTI_ERROR_NONE) {
 			warnx("jvmti: cannot get line table for method");
-		} else {
-			ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
-			if (ret != JVMTI_ERROR_NONE) {
-				warnx("jvmti: cannot get source filename ret=%d", ret);
-				nr_lines = 0;
-			}
+			nr_lines = 0;
 		}
 	}
 
+	ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
+	if (ret != JVMTI_ERROR_NONE) {
+		warnx("jvmti: cannot get source filename ret=%d", ret);
+		goto error;
+	}
+
 	ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
 					  &class_sign, NULL);
 	if (ret != JVMTI_ERROR_NONE) {
@@ -92,13 +187,14 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
 	/*
 	 * write source line info record if we have it
 	 */
-	if (jvmti_write_debug_info(jvmti_agent, addr, fn, map, tab, nr_lines))
+	if (jvmti_write_debug_info(jvmti_agent, addr, fn, line_tab, nr_lines))
 		warnx("jvmti: write_debug_info() failed");
 
 	len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
 	{
 		char str[len];
 		snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
+
 		if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
 			warnx("jvmti: write_code() failed");
 	}
@@ -106,8 +202,8 @@ error:
 	(*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
 	(*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
 	(*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
-	(*jvmti)->Deallocate(jvmti, (unsigned char *)tab);
 	(*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
+	free(line_tab);
 }
 
 static void JNICALL
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 52a4a80..a34752d 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -108,8 +108,11 @@ libperf-$(CONFIG_LZMA) += lzma.o
 libperf-y += demangle-java.o
 libperf-$(CONFIG_LIBELF) += jitdump.o
 libperf-$(CONFIG_LIBELF) += genelf.o
+libperf-$(CONFIG_LIBELF) += genelf_debug.o
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+# avoid compiler warnings in 32-bit mode
+CFLAGS_genelf_debug.o  += -Wno-packed
 
 $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
 	$(call rule_mkdir)
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
index 145f811..c1ef805 100644
--- a/tools/perf/util/genelf.c
+++ b/tools/perf/util/genelf.c
@@ -156,7 +156,8 @@ gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *cod
  */
 int
 jit_write_elf(int fd, uint64_t load_addr, const char *sym,
-	      const void *code, int csize)
+	      const void *code, int csize,
+	      void *debug, int nr_debug_entries)
 {
 	Elf *e;
 	Elf_Data *d;
@@ -385,9 +386,15 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym,
 	shdr->sh_size = sizeof(bnote);
 	shdr->sh_entsize = 0;
 
-	if (elf_update(e, ELF_C_WRITE) < 0) {
-		warnx("elf_update 4 failed");
-		goto error;
+	if (debug && nr_debug_entries) {
+		retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
+		if (retval)
+			goto error;
+	} else {
+		if (elf_update(e, ELF_C_WRITE) < 0) {
+			warnx("elf_update 4 failed");
+			goto error;
+		}
 	}
 
 	retval = 0;
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
index d8e9ece..45bf9c6 100644
--- a/tools/perf/util/genelf.h
+++ b/tools/perf/util/genelf.h
@@ -3,7 +3,11 @@
 
 /* genelf.c */
 extern int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
-			 const void *code, int csize);
+			 const void *code, int csize,
+			 void *debug, int nr_debug_entries);
+/* genelf_debug.c */
+extern int jit_add_debug_info(Elf *e, uint64_t code_addr,
+			      void *debug, int nr_debug_entries);
 
 #if   defined(__arm__)
 #define GEN_ELF_ARCH	EM_ARM
diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c
new file mode 100644
index 0000000..5980f7d
--- /dev/null
+++ b/tools/perf/util/genelf_debug.c
@@ -0,0 +1,610 @@
+/*
+ * genelf_debug.c
+ * Copyright (C) 2015, Google, Inc
+ *
+ * Contributed by:
+ * 	Stephane Eranian <eranian@google.com>
+ *
+ * Released under the GPL v2.
+ *
+ * based on GPLv2 source code from Oprofile
+ * @remark Copyright 2007 OProfile authors
+ * @author Philippe Elie
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <libelf.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <err.h>
+#include <dwarf.h>
+
+#include "perf.h"
+#include "genelf.h"
+#include "../util/jitdump.h"
+
+#define BUFFER_EXT_DFL_SIZE	(4 * 1024)
+
+typedef uint32_t uword;
+typedef uint16_t uhalf;
+typedef int32_t  sword;
+typedef int16_t  shalf;
+typedef uint8_t  ubyte;
+typedef int8_t   sbyte;
+
+struct buffer_ext {
+	size_t cur_pos;
+	size_t max_sz;
+	void *data;
+};
+
+static void
+buffer_ext_dump(struct buffer_ext *be, const char *msg)
+{
+	size_t i;
+	warnx("DUMP for %s", msg);
+	for (i = 0 ; i < be->cur_pos; i++)
+		warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff);
+}
+
+static inline int
+buffer_ext_add(struct buffer_ext *be, void *addr, size_t sz)
+{
+	void *tmp;
+	size_t be_sz = be->max_sz;
+
+retry:
+	if ((be->cur_pos + sz) < be_sz) {
+		memcpy(be->data + be->cur_pos, addr, sz);
+		be->cur_pos += sz;
+		return 0;
+	}
+
+	if (!be_sz)
+		be_sz = BUFFER_EXT_DFL_SIZE;
+	else
+		be_sz <<= 1;
+
+	tmp = realloc(be->data, be_sz);
+	if (!tmp)
+		return -1;
+
+	be->data   = tmp;
+	be->max_sz = be_sz;
+
+	goto retry;
+}
+
+static void
+buffer_ext_init(struct buffer_ext *be)
+{
+	be->data = NULL;
+	be->cur_pos = 0;
+	be->max_sz = 0;
+}
+
+static inline size_t
+buffer_ext_size(struct buffer_ext *be)
+{
+	return be->cur_pos;
+}
+
+static inline void *
+buffer_ext_addr(struct buffer_ext *be)
+{
+	return be->data;
+}
+
+struct debug_line_header {
+	// Not counting this field
+	uword total_length;
+	// version number (2 currently)
+	uhalf version;
+	// relative offset from next field to
+	// program statement
+	uword prolog_length;
+	ubyte minimum_instruction_length;
+	ubyte default_is_stmt;
+	// line_base - see DWARF 2 specs
+	sbyte line_base;
+	// line_range - see DWARF 2 specs
+	ubyte line_range;
+	// number of opcode + 1
+	ubyte opcode_base;
+	/* follow the array of opcode args nr: ubytes [nr_opcode_base] */
+	/* follow the search directories index, zero terminated string
+	 * terminated by an empty string.
+	 */
+	/* follow an array of { filename, LEB128, LEB128, LEB128 }, first is
+	 * the directory index entry, 0 means current directory, then mtime
+	 * and filesize, last entry is followed by en empty string.
+	 */
+	/* follow the first program statement */
+} __attribute__((packed));
+
+/* DWARF 2 spec talk only about one possible compilation unit header while
+ * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not
+ * related to the used arch, an ELF 32 can hold more than 4 Go of debug
+ * information. For now we handle only DWARF 2 32 bits comp unit. It'll only
+ * become a problem if we generate more than 4GB of debug information.
+ */
+struct compilation_unit_header {
+	uword total_length;
+	uhalf version;
+	uword debug_abbrev_offset;
+	ubyte pointer_size;
+} __attribute__((packed));
+
+#define DW_LNS_num_opcode (DW_LNS_set_isa + 1)
+
+/* field filled at run time are marked with -1 */
+static struct debug_line_header const default_debug_line_header = {
+	.total_length = -1,
+	.version = 2,
+	.prolog_length = -1,
+	.minimum_instruction_length = 1,	/* could be better when min instruction size != 1 */
+	.default_is_stmt = 1,	/* we don't take care about basic block */
+	.line_base = -5,	/* sensible value for line base ... */
+	.line_range = -14,     /* ... and line range are guessed statically */
+	.opcode_base = DW_LNS_num_opcode
+};
+
+static ubyte standard_opcode_length[] =
+{
+	0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
+};
+#if 0
+{
+	[DW_LNS_advance_pc]   = 1,
+	[DW_LNS_advance_line] = 1,
+	[DW_LNS_set_file] =  1,
+	[DW_LNS_set_column] = 1,
+	[DW_LNS_fixed_advance_pc] = 1,
+	[DW_LNS_set_isa] = 1,
+};
+#endif
+
+/* field filled at run time are marked with -1 */
+static struct compilation_unit_header default_comp_unit_header = {
+	.total_length = -1,
+	.version = 2,
+	.debug_abbrev_offset = 0,     /* we reuse the same abbrev entries for all comp unit */
+	.pointer_size = sizeof(void *)
+};
+
+static void emit_uword(struct buffer_ext *be, uword data)
+{
+	buffer_ext_add(be, &data, sizeof(uword));
+}
+
+static void emit_string(struct buffer_ext *be, const char *s)
+{
+	buffer_ext_add(be, (void *)s, strlen(s) + 1);
+}
+
+static void emit_unsigned_LEB128(struct buffer_ext *be,
+				 unsigned long data)
+{
+	do {
+		ubyte cur = data & 0x7F;
+		data >>= 7;
+		if (data)
+			cur |= 0x80;
+		buffer_ext_add(be, &cur, 1);
+	} while (data);
+}
+
+static void emit_signed_LEB128(struct buffer_ext *be, long data)
+{
+	int more = 1;
+	int negative = data < 0;
+	int size = sizeof(long) * CHAR_BIT;
+	while (more) {
+		ubyte cur = data & 0x7F;
+		data >>= 7;
+		if (negative)
+			data |= - (1 << (size - 7));
+		if ((data == 0 && !(cur & 0x40)) ||
+		    (data == -1l && (cur & 0x40)))
+			more = 0;
+		else
+			cur |= 0x80;
+		buffer_ext_add(be, &cur, 1);
+	}
+}
+
+static void emit_extended_opcode(struct buffer_ext *be, ubyte opcode,
+				 void *data, size_t data_len)
+{
+	buffer_ext_add(be, (char *)"", 1);
+
+	emit_unsigned_LEB128(be, data_len + 1);
+
+	buffer_ext_add(be, &opcode, 1);
+	buffer_ext_add(be, data, data_len);
+}
+
+static void emit_opcode(struct buffer_ext *be, ubyte opcode)
+{
+	buffer_ext_add(be, &opcode, 1);
+}
+
+static void emit_opcode_signed(struct buffer_ext  *be,
+			       ubyte opcode, long data)
+{
+	buffer_ext_add(be, &opcode, 1);
+	emit_signed_LEB128(be, data);
+}
+
+static void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode,
+				 unsigned long data)
+{
+	buffer_ext_add(be, &opcode, 1);
+	emit_unsigned_LEB128(be, data);
+}
+
+static void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc)
+{
+	emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc);
+}
+
+static void emit_advance_lineno(struct buffer_ext  *be, long delta_lineno)
+{
+	emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno);
+}
+
+static void emit_lne_end_of_sequence(struct buffer_ext *be)
+{
+	emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0);
+}
+
+static void emit_set_file(struct buffer_ext *be, unsigned long idx)
+{
+	emit_opcode_unsigned(be, DW_LNS_set_file, idx);
+}
+
+static void emit_lne_define_filename(struct buffer_ext *be,
+				     const char *filename)
+{
+	buffer_ext_add(be, (void *)"", 1);
+
+	/* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */
+	emit_unsigned_LEB128(be, strlen(filename) + 5);
+	emit_opcode(be, DW_LNE_define_file);
+	emit_string(be, filename);
+	/* directory index 0=do not know */
+        emit_unsigned_LEB128(be, 0);
+	/* last modification date on file 0=do not know */
+        emit_unsigned_LEB128(be, 0);
+	/* filesize 0=do not know */
+        emit_unsigned_LEB128(be, 0);
+}
+
+static void emit_lne_set_address(struct buffer_ext *be,
+				 void *address)
+{
+	emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long));
+}
+
+static ubyte get_special_opcode(struct debug_entry *ent,
+				unsigned int last_line,
+				unsigned long last_vma)
+{
+	unsigned int temp;
+	unsigned long delta_addr;
+
+	/*
+	 * delta from line_base
+	 */
+	temp = (ent->lineno - last_line) - default_debug_line_header.line_base;
+
+	if (temp >= default_debug_line_header.line_range)
+		return 0;
+
+	/*
+	 * delta of addresses
+	 */
+	delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length;
+
+	/* This is not sufficient to ensure opcode will be in [0-256] but
+	 * sufficient to ensure when summing with the delta lineno we will
+	 * not overflow the unsigned long opcode */
+
+	if (delta_addr <= 256 / default_debug_line_header.line_range) {
+		unsigned long opcode = temp +
+			(delta_addr * default_debug_line_header.line_range) +
+			default_debug_line_header.opcode_base;
+
+		return opcode <= 255 ? opcode : 0;
+	}
+	return 0;
+}
+
+static void emit_lineno_info(struct buffer_ext *be,
+			     struct debug_entry *ent, size_t nr_entry,
+			     unsigned long code_addr)
+{
+	size_t i;
+
+	/*
+	 * Machine state at start of a statement program
+	 * address = 0
+	 * file    = 1
+	 * line    = 1
+	 * column  = 0
+	 * is_stmt = default_is_stmt as given in the debug_line_header
+	 * basic block = 0
+	 * end sequence = 0
+	 */
+
+	/* start state of the state machine we take care of */
+	unsigned long last_vma = code_addr;
+	char const  *cur_filename = NULL;
+	unsigned long cur_file_idx = 0;
+	int last_line = 1;
+
+	emit_lne_set_address(be, (void *)code_addr);
+
+	for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) {
+		int need_copy = 0;
+		ubyte special_opcode;
+
+		/*
+		 * check if filename changed, if so add it
+		 */
+		if (!cur_filename || strcmp(cur_filename, ent->name)) {
+			emit_lne_define_filename(be, ent->name);
+			cur_filename = ent->name;
+			emit_set_file(be, ++cur_file_idx);
+			need_copy = 1;
+		}
+
+		special_opcode = get_special_opcode(ent, last_line, last_vma);
+		if (special_opcode != 0) {
+			last_line = ent->lineno;
+			last_vma  = ent->addr;
+			emit_opcode(be, special_opcode);
+		} else {
+			/*
+			 * lines differ, emit line delta
+			 */
+			if (last_line != ent->lineno) {
+				emit_advance_lineno(be, ent->lineno - last_line);
+				last_line = ent->lineno;
+				need_copy = 1;
+			}
+			/*
+			 * addresses differ, emit address delta
+			 */
+			if (last_vma != ent->addr) {
+				emit_advance_pc(be, ent->addr - last_vma);
+				last_vma = ent->addr;
+				need_copy = 1;
+			}
+			/*
+			 * add new row to matrix
+			 */
+			if (need_copy)
+				emit_opcode(be, DW_LNS_copy);
+		}
+	}
+}
+
+static void add_debug_line(struct buffer_ext *be,
+	struct debug_entry *ent, size_t nr_entry,
+	unsigned long code_addr)
+{
+	struct debug_line_header * dbg_header;
+	size_t old_size;
+
+	old_size = buffer_ext_size(be);
+
+	buffer_ext_add(be, (void *)&default_debug_line_header,
+		 sizeof(default_debug_line_header));
+
+	buffer_ext_add(be, &standard_opcode_length,  sizeof(standard_opcode_length));
+
+	// empty directory entry
+	buffer_ext_add(be, (void *)"", 1);
+
+	// empty filename directory
+	buffer_ext_add(be, (void *)"", 1);
+
+	dbg_header = buffer_ext_addr(be) + old_size;
+	dbg_header->prolog_length = (buffer_ext_size(be) - old_size) -
+		offsetof(struct debug_line_header, minimum_instruction_length);
+
+	emit_lineno_info(be, ent, nr_entry, code_addr);
+
+	emit_lne_end_of_sequence(be);
+
+	dbg_header = buffer_ext_addr(be) + old_size;
+	dbg_header->total_length = (buffer_ext_size(be) - old_size) -
+		offsetof(struct debug_line_header, version);
+}
+
+static void
+add_debug_abbrev(struct buffer_ext *be)
+{
+        emit_unsigned_LEB128(be, 1);
+        emit_unsigned_LEB128(be, DW_TAG_compile_unit);
+        emit_unsigned_LEB128(be, DW_CHILDREN_yes);
+        emit_unsigned_LEB128(be, DW_AT_stmt_list);
+        emit_unsigned_LEB128(be, DW_FORM_data4);
+        emit_unsigned_LEB128(be, 0);
+        emit_unsigned_LEB128(be, 0);
+        emit_unsigned_LEB128(be, 0);
+}
+
+static void
+add_compilation_unit(struct buffer_ext *be,
+		     size_t offset_debug_line)
+{
+	struct compilation_unit_header *comp_unit_header;
+	size_t old_size = buffer_ext_size(be);
+
+	buffer_ext_add(be, &default_comp_unit_header,
+		       sizeof(default_comp_unit_header));
+
+	emit_unsigned_LEB128(be, 1);
+	emit_uword(be, offset_debug_line);
+
+	comp_unit_header = buffer_ext_addr(be) + old_size;
+	comp_unit_header->total_length = (buffer_ext_size(be) - old_size) -
+		offsetof(struct compilation_unit_header, version);
+}
+
+static int
+jit_process_debug_info(uint64_t code_addr,
+		       void *debug, int nr_debug_entries,
+		       struct buffer_ext *dl,
+		       struct buffer_ext *da,
+		       struct buffer_ext *di)
+{
+	struct debug_entry *ent = debug;
+	int i;
+
+	for (i = 0; i < nr_debug_entries; i++) {
+		ent->addr = ent->addr - code_addr;
+		ent = debug_entry_next(ent);
+	}
+	add_compilation_unit(di, buffer_ext_size(dl));
+	add_debug_line(dl, debug, nr_debug_entries, 0);
+	add_debug_abbrev(da);
+	if (0) buffer_ext_dump(da, "abbrev");
+
+	return 0;
+}
+
+int
+jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries)
+{
+	Elf_Data *d;
+	Elf_Scn *scn;
+	Elf_Shdr *shdr;
+	struct buffer_ext dl, di, da;
+	int ret;
+
+	buffer_ext_init(&dl);
+	buffer_ext_init(&di);
+	buffer_ext_init(&da);
+
+	ret = jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di);
+	if (ret)
+		return -1;
+	/*
+	 * setup .debug_line section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		return -1;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		return -1;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = buffer_ext_addr(&dl);
+	d->d_type = ELF_T_BYTE;
+	d->d_size = buffer_ext_size(&dl);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		return -1;
+	}
+
+	shdr->sh_name = 52; /* .debug_line */
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup .debug_info section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		return -1;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		return -1;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = buffer_ext_addr(&di);
+	d->d_type = ELF_T_BYTE;
+	d->d_size = buffer_ext_size(&di);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		return -1;
+	}
+
+	shdr->sh_name = 64; /* .debug_info */
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * setup .debug_abbrev section
+	 */
+	scn = elf_newscn(e);
+	if (!scn) {
+		warnx("cannot create section");
+		return -1;
+	}
+
+	d = elf_newdata(scn);
+	if (!d) {
+		warnx("cannot get new data");
+		return -1;
+	}
+
+	d->d_align = 1;
+	d->d_off = 0LL;
+	d->d_buf = buffer_ext_addr(&da);
+	d->d_type = ELF_T_BYTE;
+	d->d_size = buffer_ext_size(&da);
+	d->d_version = EV_CURRENT;
+
+	shdr = elf_getshdr(scn);
+	if (!shdr) {
+		warnx("cannot get section header");
+		return -1;
+	}
+
+	shdr->sh_name = 76; /* .debug_info */
+	shdr->sh_type = SHT_PROGBITS;
+	shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
+	shdr->sh_flags = 0;
+	shdr->sh_entsize = 0;
+
+	/*
+	 * now we update the ELF image with all the sections
+	 */
+	if (elf_update(e, ELF_C_WRITE) < 0) {
+		warnx("elf_update debug failed");
+		return -1;
+	}
+	return 0;
+}
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index 9f7a012..99fa5ee 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -63,7 +63,9 @@ jit_emit_elf(char *filename,
 	     const char *sym,
 	     uint64_t code_addr,
 	     const void *code,
-	     int csize)
+	     int csize,
+	     void *debug,
+	     int nr_debug_entries)
 {
 	int ret, fd;
 
@@ -76,7 +78,7 @@ jit_emit_elf(char *filename,
 		return -1;
 	}
 
-        ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize);
+        ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries);
 
         close(fd);
 
@@ -347,7 +349,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 
 	size = PERF_ALIGN(size, sizeof(u64));
 	uaddr = (uintptr_t)code;
-	ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize);
+	ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries);
 
 	if (jd->debug_data && jd->nr_debug_entries) {
 		free(jd->debug_data);

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-08 18:53                   ` Stephane Eranian
@ 2016-02-11 22:16                     ` Arnaldo Carvalho de Melo
  2016-02-12 20:32                       ` Stephane Eranian
  0 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-11 22:16 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Em Mon, Feb 08, 2016 at 10:53:48AM -0800, Stephane Eranian escreveu:
> Hi Arnaldo,
> 
> Sorry for the delay, I missed your message.
> 
> I tried with openjdk-8 on Ubuntu/Wily and I do not get the crash using
> the same hello world test program.
> In fact, if I print file_name, it is never NULL for me.

All this is already upstream, in tip.git, Ingo merged those patches.

There were still some open questions tho, that I listed on the changelog
comments.

See below for some more things
 
> $ java -agentpath:/home/eranian/tip/tools/perf/jvmti/libjvmti.so hello
> java: jvmti: jitdump in
> /home/eranian/.debug/jit/java-jit-20160208.XX8wCwyY/jit-20156.dump
> java: FILE_NAME: Object.java
> java: FILE_NAME: String.java
> java: FILE_NAME: String.java
> java: FILE_NAME: String.java
> java: FILE_NAME: String.java
> java: FILE_NAME: String.java
> java: FILE_NAME: System.java
> java: FILE_NAME: Math.java
> java: FILE_NAME: Object.java
> java: FILE_NAME: Reference.java
> java: FILE_NAME: AbstractStringBuilder.java
> java: FILE_NAME: ThreadLocal.java
> java: FILE_NAME: AbstractStringBuilder.java
> java: FILE_NAME: String.java
> Hello, World
> 
> So I am not sure what is different in your setup especially if the
> function GetSourceFileName() did not fail.
> Could you print file_name in your code to check?

will try and do it after replying to the other parts of this message,
the patch that went upstream checks it in any case.
 
> 
> As for the MMAP, it is normal to have the extra mmaps pointing to the
> jitted code.
> Event for a simple program as hello world, there are several function
> jitted, including the
> java interpreter itself. There is one MMAP for each jitted function.

Ok, tons of ELF files, wonder if having just one would be better, but
that would be an improvement, not a requirement, I guess.
 
> On Fri, Feb 5, 2016 at 6:24 AM, Arnaldo Carvalho de Melo
> <acme@kernel.org> wrote:
> >
> > Em Fri, Feb 05, 2016 at 10:57:17AM -0300, Arnaldo Carvalho de Melo escreveu:
> > > Duh:
> > >
> > > [acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
> > > java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXFb472a/jit-28966.dump
> > > Hello, World
> > > [acme@jouet java]$
> >
> > Ok, so mucho progress:
> >
> > [acme@jouet java]$ perf record -k 1 java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
> > java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jit-31400.dump
> > Hello, World
> > [ perf record: Woken up 1 times to write data ]
> > [ perf record: Captured and wrote 0.030 MB perf.data (268 samples) ]
> > [acme@jouet java]$ perf inject --jit -i perf.data -o perf.data.jitted
> > [acme@jouet java]$ perf report -D -i perf.data | grep PERF_RECORD_MMAP > mmaps.before
> > Failed to open /tmp/perf-31400.map, continuing without symbols
> > [acme@jouet java]$ perf report -D -i perf.data. | grep PERF_RECORD_MMAP > mmaps.before
> > perf.data.jitted      perf.data.jitted.old  perf.data.old
> > [acme@jouet java]$ perf report -D -i perf.data.jitted | grep PERF_RECORD_MMAP > mmaps.jitted
> > [acme@jouet java]$ diff -u mmaps.before mmaps.jitted
> > --- mmaps.before        2016-02-05 11:01:16.019257683 -0300
> > +++ mmaps.jitted        2016-02-05 11:01:28.966232802 -0300
> > <SNIP>
> > +77539479986521 0xfc80 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102880(0xc0) @ 0x40 fd:02 1840179 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-281.so
> > +77539480189814 0xfd20 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d0fef60(0x80) @ 0x40 fd:02 1840180 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-282.so
> > +77539480541065 0xfdc0 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102560(0x180) @ 0x40 fd:02 1840181 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-283.so
> > +77539480541871 0xfe60 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102360(0x180) @ 0x40 fd:02 1840182 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-284.so
> > +77539480848667 0xff00 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102160(0x180) @ 0x40 fd:02 1840183 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-285.so
> > +77539480910925 0xffa0 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d101f60(0x180) @ 0x40 fd:02 1840184 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-286.so
> > <SNIP>
> >
> > Quite a lot of those, but I noticed this, probably harmless, at the start:
> >
> >  0 0x3fd8 [0x88]: PERF_RECORD_MMAP -1/0: [0xffffffffa0991000(0x5000) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/net/dns_resolver/dns_resolver.ko.xz
> >  0 0x4060 [0x78]: PERF_RECORD_MMAP -1/0: [0xffffffffa0996000(0x7b000) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/fs/nfs/nfsv4.ko.xz
> >  0 0x40d8 [0x88]: PERF_RECORD_MMAP -1/0: [0xffffffffa0a11000(0x5f5eefff) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/drivers/usb/storage/usb-storage.ko.xz
> > -77539437123281 0x6b98 [0xa0]: PERF_RECORD_MMAP2 31400/31400: [0x557b73152000(0x202000) @ 0 fd:00 7858 3897326142]: r-xp /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
> > +77539437123281 0x42a0 [0xa0]: PERF_RECORD_MMAP2 31400/31400: [0x557b73152000(0x202000) @ 0 fd:00 7858 3897326142]: r-xp /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
> >
> > I.e. the MMAP records for the kernel modules comes in ok, humm, because
> > probably you don't hook on PERF_RECORD_MMAP in perf-inject, just on MMAP2, and
> > in those the only difference is the second field, 0x6b98 -> 0x42a0, what is
> > that?
> >
> I have both MMAP and MMAP2 hooks for the jit mode of perf inject.

IIRC the different in the offsets came from 'perf inject' not preserving
FINISHED_ROUND events.
 
> > static void dump_event(struct perf_evlist *evlist, union perf_event *event,
> >                        u64 file_offset, struct perf_sample *sample)
> > {
> >         if (sample)
> >                 perf_evlist__print_tstamp(evlist, event, sample);
> >
> >         printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
> >                event->header.size, perf_event__name(event->header.type));
> >
> > File offset, what changed?
> >
> As for this, the offset is not recorded in the MMAP2 record, this is
> an artifact of the __perf_Session__process_events()
> which passes the file_offset in the perf.data file (read by mmapping).
> The offsets are changed because we inject
> new mmap records, and thus the existing MMAP may be moved to a later
> position in the file.
> 
> Hope this helps.

IIRC it was the missing FINISHED_ROUND, haven't checked if that was on
purpose an oversight or even if so if it ends up being harmless for most
workloads, have you tried this with long running or high sample freq?

 
> >
> > -0x7c18 [0x8]: event: 68
> > -.
> > -. ... raw event: size 8 bytes
> > -.  0000:  44 00 00 00 00 00 08 00                          D.......
> > -.
> > -0x7c18 [0x8]: PERF_RECORD_FINISHED_ROUND
> > -
> > -0x6a80 [0x28]: event: 9
> >
> > Humm, inject doesn't preserves PERF_RECORD_FINISHED_ROUND? Or user events in
> > general? On purpose?

What about this question? Do you know? Oversight?

- Arnaldo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-11 22:16                     ` Arnaldo Carvalho de Melo
@ 2016-02-12 20:32                       ` Stephane Eranian
  2016-02-12 20:43                         ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 27+ messages in thread
From: Stephane Eranian @ 2016-02-12 20:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

On Thu, Feb 11, 2016 at 2:16 PM, Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
> Em Mon, Feb 08, 2016 at 10:53:48AM -0800, Stephane Eranian escreveu:
>> Hi Arnaldo,
>>
>> Sorry for the delay, I missed your message.
>>
>> I tried with openjdk-8 on Ubuntu/Wily and I do not get the crash using
>> the same hello world test program.
>> In fact, if I print file_name, it is never NULL for me.
>
> All this is already upstream, in tip.git, Ingo merged those patches.
>
> There were still some open questions tho, that I listed on the changelog
> comments.
>
> See below for some more things
>
>> $ java -agentpath:/home/eranian/tip/tools/perf/jvmti/libjvmti.so hello
>> java: jvmti: jitdump in
>> /home/eranian/.debug/jit/java-jit-20160208.XX8wCwyY/jit-20156.dump
>> java: FILE_NAME: Object.java
>> java: FILE_NAME: String.java
>> java: FILE_NAME: String.java
>> java: FILE_NAME: String.java
>> java: FILE_NAME: String.java
>> java: FILE_NAME: String.java
>> java: FILE_NAME: System.java
>> java: FILE_NAME: Math.java
>> java: FILE_NAME: Object.java
>> java: FILE_NAME: Reference.java
>> java: FILE_NAME: AbstractStringBuilder.java
>> java: FILE_NAME: ThreadLocal.java
>> java: FILE_NAME: AbstractStringBuilder.java
>> java: FILE_NAME: String.java
>> Hello, World
>>
>> So I am not sure what is different in your setup especially if the
>> function GetSourceFileName() did not fail.
>> Could you print file_name in your code to check?
>
> will try and do it after replying to the other parts of this message,
> the patch that went upstream checks it in any case.
>
>>
>> As for the MMAP, it is normal to have the extra mmaps pointing to the
>> jitted code.
>> Event for a simple program as hello world, there are several function
>> jitted, including the
>> java interpreter itself. There is one MMAP for each jitted function.
>
> Ok, tons of ELF files, wonder if having just one would be better, but
> that would be an improvement, not a requirement, I guess.
>
>> On Fri, Feb 5, 2016 at 6:24 AM, Arnaldo Carvalho de Melo
>> <acme@kernel.org> wrote:
>> >
>> > Em Fri, Feb 05, 2016 at 10:57:17AM -0300, Arnaldo Carvalho de Melo escreveu:
>> > > Duh:
>> > >
>> > > [acme@jouet java]$ java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
>> > > java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXFb472a/jit-28966.dump
>> > > Hello, World
>> > > [acme@jouet java]$
>> >
>> > Ok, so mucho progress:
>> >
>> > [acme@jouet java]$ perf record -k 1 java -agentpath:/home/acme/git/linux/tools/perf/jvmti/libjvmti.so hello
>> > java: jvmti: jitdump in /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jit-31400.dump
>> > Hello, World
>> > [ perf record: Woken up 1 times to write data ]
>> > [ perf record: Captured and wrote 0.030 MB perf.data (268 samples) ]
>> > [acme@jouet java]$ perf inject --jit -i perf.data -o perf.data.jitted
>> > [acme@jouet java]$ perf report -D -i perf.data | grep PERF_RECORD_MMAP > mmaps.before
>> > Failed to open /tmp/perf-31400.map, continuing without symbols
>> > [acme@jouet java]$ perf report -D -i perf.data. | grep PERF_RECORD_MMAP > mmaps.before
>> > perf.data.jitted      perf.data.jitted.old  perf.data.old
>> > [acme@jouet java]$ perf report -D -i perf.data.jitted | grep PERF_RECORD_MMAP > mmaps.jitted
>> > [acme@jouet java]$ diff -u mmaps.before mmaps.jitted
>> > --- mmaps.before        2016-02-05 11:01:16.019257683 -0300
>> > +++ mmaps.jitted        2016-02-05 11:01:28.966232802 -0300
>> > <SNIP>
>> > +77539479986521 0xfc80 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102880(0xc0) @ 0x40 fd:02 1840179 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-281.so
>> > +77539480189814 0xfd20 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d0fef60(0x80) @ 0x40 fd:02 1840180 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-282.so
>> > +77539480541065 0xfdc0 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102560(0x180) @ 0x40 fd:02 1840181 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-283.so
>> > +77539480541871 0xfe60 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102360(0x180) @ 0x40 fd:02 1840182 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-284.so
>> > +77539480848667 0xff00 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d102160(0x180) @ 0x40 fd:02 1840183 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-285.so
>> > +77539480910925 0xffa0 [0xa0]: PERF_RECORD_MMAP2 31400/31413: [0x7f3f7d101f60(0x180) @ 0x40 fd:02 1840184 1]: --xs /home/acme/.debug/jit/java-jit-20160205.XXIiqiq7/jitted-31400-286.so
>> > <SNIP>
>> >
>> > Quite a lot of those, but I noticed this, probably harmless, at the start:
>> >
>> >  0 0x3fd8 [0x88]: PERF_RECORD_MMAP -1/0: [0xffffffffa0991000(0x5000) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/net/dns_resolver/dns_resolver.ko.xz
>> >  0 0x4060 [0x78]: PERF_RECORD_MMAP -1/0: [0xffffffffa0996000(0x7b000) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/fs/nfs/nfsv4.ko.xz
>> >  0 0x40d8 [0x88]: PERF_RECORD_MMAP -1/0: [0xffffffffa0a11000(0x5f5eefff) @ 0]: x /lib/modules/4.3.4-300.fc23.x86_64/kernel/drivers/usb/storage/usb-storage.ko.xz
>> > -77539437123281 0x6b98 [0xa0]: PERF_RECORD_MMAP2 31400/31400: [0x557b73152000(0x202000) @ 0 fd:00 7858 3897326142]: r-xp /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
>> > +77539437123281 0x42a0 [0xa0]: PERF_RECORD_MMAP2 31400/31400: [0x557b73152000(0x202000) @ 0 fd:00 7858 3897326142]: r-xp /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-1.b15.fc23.x86_64/jre/bin/java
>> >
>> > I.e. the MMAP records for the kernel modules comes in ok, humm, because
>> > probably you don't hook on PERF_RECORD_MMAP in perf-inject, just on MMAP2, and
>> > in those the only difference is the second field, 0x6b98 -> 0x42a0, what is
>> > that?
>> >
>> I have both MMAP and MMAP2 hooks for the jit mode of perf inject.
>
> IIRC the different in the offsets came from 'perf inject' not preserving
> FINISHED_ROUND events.
>
That's an oversight. Is there code to repipe this event already?

>> > static void dump_event(struct perf_evlist *evlist, union perf_event *event,
>> >                        u64 file_offset, struct perf_sample *sample)
>> > {
>> >         if (sample)
>> >                 perf_evlist__print_tstamp(evlist, event, sample);
>> >
>> >         printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
>> >                event->header.size, perf_event__name(event->header.type));
>> >
>> > File offset, what changed?
>> >
>> As for this, the offset is not recorded in the MMAP2 record, this is
>> an artifact of the __perf_Session__process_events()
>> which passes the file_offset in the perf.data file (read by mmapping).
>> The offsets are changed because we inject
>> new mmap records, and thus the existing MMAP may be moved to a later
>> position in the file.
>>
>> Hope this helps.
>
> IIRC it was the missing FINISHED_ROUND, haven't checked if that was on
> purpose an oversight or even if so if it ends up being harmless for most
> workloads, have you tried this with long running or high sample freq?
>
Not yet, let me try.

>
>> >
>> > -0x7c18 [0x8]: event: 68
>> > -.
>> > -. ... raw event: size 8 bytes
>> > -.  0000:  44 00 00 00 00 00 08 00                          D.......
>> > -.
>> > -0x7c18 [0x8]: PERF_RECORD_FINISHED_ROUND
>> > -
>> > -0x6a80 [0x28]: event: 9
>> >
>> > Humm, inject doesn't preserves PERF_RECORD_FINISHED_ROUND? Or user events in
>> > general? On purpose?
>
> What about this question? Do you know? Oversight?
>
Oversight.

I pulled tip.git and jvmti does not compile anymore for me because of
the alternative vs.
update-java-alternatives problem.
Is it the case that on Fedora, you do not have
update-java-alternatives? If so, we could
have the Makefile check if it exists and if not default to what you have.

Thanks.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-12 20:32                       ` Stephane Eranian
@ 2016-02-12 20:43                         ` Arnaldo Carvalho de Melo
  2016-02-15  2:16                           ` Stephane Eranian
  0 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-12 20:43 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Em Fri, Feb 12, 2016 at 12:32:53PM -0800, Stephane Eranian escreveu:
> On Thu, Feb 11, 2016 at 2:16 PM, Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> > Em Mon, Feb 08, 2016 at 10:53:48AM -0800, Stephane Eranian escreveu:
> >> > I.e. the MMAP records for the kernel modules comes in ok, humm, because
> >> > probably you don't hook on PERF_RECORD_MMAP in perf-inject, just on MMAP2, and
> >> > in those the only difference is the second field, 0x6b98 -> 0x42a0, what is
> >> > that?

> >> I have both MMAP and MMAP2 hooks for the jit mode of perf inject.

> > IIRC the different in the offsets came from 'perf inject' not preserving
> > FINISHED_ROUND events.

> That's an oversight. Is there code to repipe this event already?

Unsure, please check
 
> >> > static void dump_event(struct perf_evlist *evlist, union perf_event *event,
> >> >                        u64 file_offset, struct perf_sample *sample)
> >> > {
> >> >         if (sample)
> >> >                 perf_evlist__print_tstamp(evlist, event, sample);
> >> >
> >> >         printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
> >> >                event->header.size, perf_event__name(event->header.type));
> >> >
> >> > File offset, what changed?
> >> >
> >> As for this, the offset is not recorded in the MMAP2 record, this is
> >> an artifact of the __perf_Session__process_events()
> >> which passes the file_offset in the perf.data file (read by mmapping).
> >> The offsets are changed because we inject
> >> new mmap records, and thus the existing MMAP may be moved to a later
> >> position in the file.
> >>
> >> Hope this helps.
> >
> > IIRC it was the missing FINISHED_ROUND, haven't checked if that was on
> > purpose an oversight or even if so if it ends up being harmless for most
> > workloads, have you tried this with long running or high sample freq?
> >
> Not yet, let me try.
> 
> >
> >> >
> >> > -0x7c18 [0x8]: event: 68
> >> > -.
> >> > -. ... raw event: size 8 bytes
> >> > -.  0000:  44 00 00 00 00 00 08 00                          D.......
> >> > -.
> >> > -0x7c18 [0x8]: PERF_RECORD_FINISHED_ROUND
> >> > -
> >> > -0x6a80 [0x28]: event: 9
> >> >
> >> > Humm, inject doesn't preserves PERF_RECORD_FINISHED_ROUND? Or user events in
> >> > general? On purpose?
> >
> > What about this question? Do you know? Oversight?
> >
> Oversight.
> 
> I pulled tip.git and jvmti does not compile anymore for me because of
> the alternative vs.
> update-java-alternatives problem.
> Is it the case that on Fedora, you do not have
> update-java-alternatives? If so, we could
> have the Makefile check if it exists and if not default to what you have.

right, we need to make it test and use what is available, here:

[root@jouet ~]# dnf search alternatives
Last metadata expiration check performed 1:01:59 ago on Fri Feb 12
16:38:51 2016.
================================================================= N/S
Matched: alternatives
==================================================================
galternatives.noarch : Alternatives Configurator
ghc-base-unicode-symbols.x86_64 : Unicode alternatives for common
functions and operators
[root@jouet ~]# rpm -qf `which update-alternatives`
chkconfig-1.7-1.fc23.x86_64
[root@jouet ~]# rpm -ql chkconfig | grep alternativ
/etc/alternatives
/usr/sbin/alternatives
/usr/sbin/update-alternatives
/usr/share/man/man8/alternatives.8.gz
/usr/share/man/man8/update-alternatives.8.gz
/var/lib/alternatives

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-12 20:43                         ` Arnaldo Carvalho de Melo
@ 2016-02-15  2:16                           ` Stephane Eranian
  2016-02-15 17:14                             ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 27+ messages in thread
From: Stephane Eranian @ 2016-02-15  2:16 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

On Fri, Feb 12, 2016 at 12:43 PM, Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> Em Fri, Feb 12, 2016 at 12:32:53PM -0800, Stephane Eranian escreveu:
> > On Thu, Feb 11, 2016 at 2:16 PM, Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> > > Em Mon, Feb 08, 2016 at 10:53:48AM -0800, Stephane Eranian escreveu:
> > >> > I.e. the MMAP records for the kernel modules comes in ok, humm, because
> > >> > probably you don't hook on PERF_RECORD_MMAP in perf-inject, just on MMAP2, and
> > >> > in those the only difference is the second field, 0x6b98 -> 0x42a0, what is
> > >> > that?
>
> > >> I have both MMAP and MMAP2 hooks for the jit mode of perf inject.
>
> > > IIRC the different in the offsets came from 'perf inject' not preserving
> > > FINISHED_ROUND events.
>
> > That's an oversight. Is there code to repipe this event already?
>
There is a callback for it already. But now, I remember Adrian
suggesting, to change
it to: perf_event__drop_oe(). In fact, if you look at builtin-inject.c
it has a comment about
this.

>
> right, we need to make it test and use what is available, here:
>
> [root@jouet ~]# dnf search alternatives
> Last metadata expiration check performed 1:01:59 ago on Fri Feb 12
> 16:38:51 2016.
> ================================================================= N/S
> Matched: alternatives
> ==================================================================
> galternatives.noarch : Alternatives Configurator
> ghc-base-unicode-symbols.x86_64 : Unicode alternatives for common
> functions and operators
> [root@jouet ~]# rpm -qf `which update-alternatives`
> chkconfig-1.7-1.fc23.x86_64
> [root@jouet ~]# rpm -ql chkconfig | grep alternativ
> /etc/alternatives
> /usr/sbin/alternatives
> /usr/sbin/update-alternatives
> /usr/share/man/man8/alternatives.8.gz
> /usr/share/man/man8/update-alternatives.8.gz
> /var/lib/alternatives


For me on Ubuntu:
$ dpkg -S /usr/sbin/update-java-alternatives
java-common: /usr/sbin/update-java-alternatives

Could you check on Fedora if you do not have that package or its equivalent?

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
  2016-02-15  2:16                           ` Stephane Eranian
@ 2016-02-15 17:14                             ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-15 17:14 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, Ingo Molnar, Andi Kleen, Jiri Olsa,
	Namhyung Kim, Rose Belcher, Sukadev Bhattiprolu, Sonny Rao,
	John Mccutchan, David Ahern, Adrian Hunter, Pawel Moll

Em Sun, Feb 14, 2016 at 06:16:44PM -0800, Stephane Eranian escreveu:
> On Fri, Feb 12, 2016 at 12:43 PM, Arnaldo Carvalho de Melo
> <acme@kernel.org> wrote:
> >
> > Em Fri, Feb 12, 2016 at 12:32:53PM -0800, Stephane Eranian escreveu:
> > > On Thu, Feb 11, 2016 at 2:16 PM, Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> > > > Em Mon, Feb 08, 2016 at 10:53:48AM -0800, Stephane Eranian escreveu:
> > > >> > I.e. the MMAP records for the kernel modules comes in ok, humm, because
> > > >> > probably you don't hook on PERF_RECORD_MMAP in perf-inject, just on MMAP2, and
> > > >> > in those the only difference is the second field, 0x6b98 -> 0x42a0, what is
> > > >> > that?
> >
> > > >> I have both MMAP and MMAP2 hooks for the jit mode of perf inject.
> >
> > > > IIRC the different in the offsets came from 'perf inject' not preserving
> > > > FINISHED_ROUND events.
> >
> > > That's an oversight. Is there code to repipe this event already?
> >
> There is a callback for it already. But now, I remember Adrian
> suggesting, to change
> it to: perf_event__drop_oe(). In fact, if you look at builtin-inject.c
> it has a comment about
> this.

Right, IIRC that is why I asked about how big were your sessions, as
IIRC without FINISHED_ROUND we will end up having all events in memory,
so that the ordered_events can sort them, no?

The code there now is:

                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;


Ok, there seems to be a limit there, so we end up flushing, i.e. ordering what
is in the queue and delivering the events at that limit, in
ordered_events__queue(). So it probably isn't a problem, IIRC there is even a way
to tune that queue limit, but I haven't looked at that.
 
> > right, we need to make it test and use what is available, here:

> > /usr/sbin/alternatives
 
> For me on Ubuntu:
> $ dpkg -S /usr/sbin/update-java-alternatives
> java-common: /usr/sbin/update-java-alternatives
 
> Could you check on Fedora if you do not have that package or its equivalent?

[root@jouet ~]# dnf search java-common
Last metadata expiration check performed 0:06:00 ago on Mon Feb 15
13:59:22 2016.
Error: No matches found.
[root@jouet ~]# 
[root@jouet ~]# dnf repoquery /usr/sbin/update-java-alternatives
Fedora 23 - x86_64 - Updates                          6.1 MB/s |  18 MB     00:03    
Last metadata expiration check performed 0:00:05 ago on Mon Feb 15 14:08:28 2016.
[root@jouet ~]# dnf repoquery /usr/sbin/update-alternatives
Last metadata expiration check performed 0:00:12 ago on Mon Feb 15 14:08:28 2016.
chkconfig-0:1.6-1.fc23.x86_64
chkconfig-0:1.7-1.fc23.x86_64
[root@jouet ~]# 

There is no such package (or binary) in fedora, I think we better not try to
detect the distro via packages, but just look at what of these binaries is
present, i.e. if /usr/sbin/update-java-alternatives is found, use its variant,
if not fallback to the method I used for fedora, that way we can end up
supporting other distros as a bonus.

- Arnaldo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v8 2/4] perf inject: add jitdump mmap injection support
@ 2016-01-22 22:13 Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-01-22 22:13 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: LKML, Peter Zijlstra, mingo, ak, Jiri Olsa, Namhyung Kim,
	Rose Belcher, Sukadev Bhattiprolu, Sonny Rao, John Mccutchan,
	David Ahern, Adrian Hunter, Pawel Moll

Em Fri, Jan 22, 2016 at 01:22:51PM -0800, Stephane Eranian escreveu:
> On Fri, Jan 22, 2016 at 12:44 PM, Arnaldo Carvalho de Melo
> <acme@redhat.com> wrote:
> > Em Mon, Nov 30, 2015 at 10:02:21AM +0100, Stephane Eranian escreveu:
> >> 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
> >
> > So, it fails 'make -C tools/perf build-test', specifically the one where
> > we ask for a NO_LIBELF build, trying to fix:
> >
> I have rebase to tip.git last night. Will try your branch today.
> Will add a couple of minor adjustments and also better documentation
> on how to use it.

Ok, but please work on top of my branch, that I'll push soon, for
instance, I had to fold the patch below, to fix the NO_LIBELF=1 case,
so, when one builds that way perf inject -h will say:

[acme@jouet linux]$ tools/perf/perf inject -h

 Usage: perf inject [<options>]

    -b, --build-ids       Inject build-ids into the output stream
    -f, --force           don't complain, do it
    -i, --input <file>    input file name
    -j, --jit             merge jitdump files into perf.data file
                          (not built-in because NO_LIBELF=1)
    -o, --output <file>   output file name
    -s, --sched-stat      Merge sched-stat and sched-switch for getting
events where and how long tasks slept
    -v, --verbose         be more verbose (show build ids, etc)
        --itrace[=<opts>]
                          Instruction Tracing options
        --kallsyms <file>
                          kallsyms pathname
        --strip           strip non-synthesized events (use with
--itrace)

[acme@jouet linux]$ 

I did some other changes and carved out two bits into separate patches,
will soon push what I have to a perf/jit branch in my tree so that you
can take a look.

- Arnaldo


---------------------------------------------------------


diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 606653f30759..b38445f08c2f 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -73,12 +73,14 @@ 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,
@@ -243,6 +245,7 @@ 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,
@@ -261,6 +264,7 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
 	}
 	return perf_event__repipe_mmap(tool, event, sample, machine);
 }
+#endif
 
 static int perf_event__repipe_mmap2(struct perf_tool *tool,
 				   union perf_event *event,
@@ -275,6 +279,7 @@ 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,
@@ -293,6 +298,7 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
 	}
 	return perf_event__repipe_mmap2(tool, event, sample, machine);
 }
+#endif
 
 static int perf_event__repipe_fork(struct perf_tool *tool,
 				   union perf_event *event,
@@ -711,6 +717,7 @@ static int __cmd_inject(struct perf_inject *inject)
 	return ret;
 }
 
+#ifdef HAVE_LIBELF_SUPPORT
 static int
 jit_validate_events(struct perf_session *session)
 {
@@ -725,6 +732,7 @@ jit_validate_events(struct perf_session *session)
 	}
 	return 0;
 }
+#endif
 
 int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 {
@@ -765,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",
@@ -792,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);
 
 	/*
@@ -828,7 +838,7 @@ 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
@@ -847,7 +857,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 		 */
 		inject.tool.finished_round = perf_event__drop_oe;
 	}
-
+#endif
 	ret = symbol__init(&inject.session->header.env);
 	if (ret < 0)
 		goto out_delete;
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 9ef707198941..52a4a806ee2f 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -106,8 +106,8 @@ libperf-y += scripting-engines/
 libperf-$(CONFIG_ZLIB) += zlib.o
 libperf-$(CONFIG_LZMA) += lzma.o
 libperf-y += demangle-java.o
-libperf-y += jitdump.o
-libperf-y += genelf.o
+libperf-$(CONFIG_LIBELF) += jitdump.o
+libperf-$(CONFIG_LIBELF) += genelf.o
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 

----- End forwarded message -----

^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2016-02-15 17:14 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-30  9:02 [PATCH v8 0/4] perf: add support for profiling jitted code Stephane Eranian
2015-11-30  9:02 ` [PATCH v8 1/4] perf tools: add Java demangling support Stephane Eranian
2016-02-09 12:14   ` [tip:perf/core] perf symbols: " tip-bot for Stephane Eranian
2015-11-30  9:02 ` [PATCH v8 2/4] perf inject: add jitdump mmap injection support Stephane Eranian
2016-01-22 20:44   ` Arnaldo Carvalho de Melo
2016-01-22 21:22     ` Stephane Eranian
     [not found]       ` <20160122215542.GK4034@kernel.org>
     [not found]         ` <20160122220929.GL4034@kernel.org>
2016-01-22 22:10           ` Arnaldo Carvalho de Melo
2016-02-04 21:53       ` Arnaldo Carvalho de Melo
2016-02-04 23:02         ` Stephane Eranian
2016-02-05 13:47           ` Arnaldo Carvalho de Melo
2016-02-05 13:51             ` Arnaldo Carvalho de Melo
2016-02-05 13:57               ` Arnaldo Carvalho de Melo
2016-02-05 14:24                 ` Arnaldo Carvalho de Melo
2016-02-08 18:53                   ` Stephane Eranian
2016-02-11 22:16                     ` Arnaldo Carvalho de Melo
2016-02-12 20:32                       ` Stephane Eranian
2016-02-12 20:43                         ` Arnaldo Carvalho de Melo
2016-02-15  2:16                           ` Stephane Eranian
2016-02-15 17:14                             ` Arnaldo Carvalho de Melo
2016-02-09 12:14   ` [tip:perf/core] perf build: Add libcrypto feature detection tip-bot for Stephane Eranian
2016-02-09 12:15   ` [tip:perf/core] perf inject: Make sure mmap records are ordered when injecting build_ids tip-bot for Arnaldo Carvalho de Melo
2016-02-09 12:15   ` [tip:perf/core] perf inject: Add jitdump mmap injection support tip-bot for Stephane Eranian
2015-11-30  9:02 ` [PATCH v8 3/4] perf tools: add JVMTI agent library Stephane Eranian
2016-02-09 12:16   ` [tip:perf/core] " tip-bot for Stephane Eranian
2015-11-30  9:02 ` [PATCH v8 4/4] perf/jit: add source line info support Stephane Eranian
2016-02-09 12:16   ` [tip:perf/core] perf jit: " tip-bot for Stephane Eranian
2016-01-22 22:13 [PATCH v8 2/4] perf inject: add jitdump mmap injection support Arnaldo Carvalho de Melo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.