aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/jvmti/libjvmti.c
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2015-11-30 04:02:23 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-02-05 10:33:09 -0500
commit598b7c6919c7bbcc1243009721a01bc12275ff3e (patch)
treea774366184bc50f78d124bdb597965b378ec9a9d /tools/perf/jvmti/libjvmti.c
parent209045adc2bbdb2b315fa5539cec54d01cd3e7db (diff)
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>
Diffstat (limited to 'tools/perf/jvmti/libjvmti.c')
-rw-r--r--tools/perf/jvmti/libjvmti.c122
1 files changed, 109 insertions, 13 deletions
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
index 92ffbe4ff160..ac12e4b91a92 100644
--- a/tools/perf/jvmti/libjvmti.c
+++ b/tools/perf/jvmti/libjvmti.c
@@ -4,6 +4,7 @@
4#include <stdlib.h> 4#include <stdlib.h>
5#include <err.h> 5#include <err.h>
6#include <jvmti.h> 6#include <jvmti.h>
7#include <jvmticmlr.h>
7#include <limits.h> 8#include <limits.h>
8 9
9#include "jvmti_agent.h" 10#include "jvmti_agent.h"
@@ -11,6 +12,100 @@
11static int has_line_numbers; 12static int has_line_numbers;
12void *jvmti_agent; 13void *jvmti_agent;
13 14
15static jvmtiError
16do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
17 jvmti_line_info_t *tab, jint *nr)
18{
19 jint i, lines = 0;
20 jint nr_lines = 0;
21 jvmtiLineNumberEntry *loc_tab = NULL;
22 jvmtiError ret;
23
24 ret = (*jvmti)->GetLineNumberTable(jvmti, m, &nr_lines, &loc_tab);
25 if (ret != JVMTI_ERROR_NONE)
26 return ret;
27
28 for (i = 0; i < nr_lines; i++) {
29 if (loc_tab[i].start_location < bci) {
30 tab[lines].pc = (unsigned long)pc;
31 tab[lines].line_number = loc_tab[i].line_number;
32 tab[lines].discrim = 0; /* not yet used */
33 lines++;
34 } else {
35 break;
36 }
37 }
38 (*jvmti)->Deallocate(jvmti, (unsigned char *)loc_tab);
39 *nr = lines;
40 return JVMTI_ERROR_NONE;
41}
42
43static jvmtiError
44get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **tab, int *nr_lines)
45{
46 const jvmtiCompiledMethodLoadRecordHeader *hdr;
47 jvmtiCompiledMethodLoadInlineRecord *rec;
48 jvmtiLineNumberEntry *lne = NULL;
49 PCStackInfo *c;
50 jint nr, ret;
51 int nr_total = 0;
52 int i, lines_total = 0;
53
54 if (!(tab && nr_lines))
55 return JVMTI_ERROR_NULL_POINTER;
56
57 /*
58 * Phase 1 -- get the number of lines necessary
59 */
60 for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
61 if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
62 rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
63 for (i = 0; i < rec->numpcs; i++) {
64 c = rec->pcinfo + i;
65 nr = 0;
66 /*
67 * unfortunately, need a tab to get the number of lines!
68 */
69 ret = (*jvmti)->GetLineNumberTable(jvmti, c->methods[0], &nr, &lne);
70 if (ret == JVMTI_ERROR_NONE) {
71 /* free what was allocated for nothing */
72 (*jvmti)->Deallocate(jvmti, (unsigned char *)lne);
73 nr_total += (int)nr;
74 }
75 }
76 }
77 }
78
79 if (nr_total == 0)
80 return JVMTI_ERROR_NOT_FOUND;
81
82 /*
83 * Phase 2 -- allocate big enough line table
84 */
85 *tab = malloc(nr_total * sizeof(**tab));
86 if (!*tab)
87 return JVMTI_ERROR_OUT_OF_MEMORY;
88
89 for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
90 if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
91 rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
92 for (i = 0; i < rec->numpcs; i++) {
93 c = rec->pcinfo + i;
94 nr = 0;
95 ret = do_get_line_numbers(jvmti, c->pc,
96 c->methods[0],
97 c->bcis[0],
98 *tab + lines_total,
99 &nr);
100 if (ret == JVMTI_ERROR_NONE)
101 lines_total += nr;
102 }
103 }
104 }
105 *nr_lines = lines_total;
106 return JVMTI_ERROR_NONE;
107}
108
14static void JNICALL 109static void JNICALL
15compiled_method_load_cb(jvmtiEnv *jvmti, 110compiled_method_load_cb(jvmtiEnv *jvmti,
16 jmethodID method, 111 jmethodID method,
@@ -18,9 +113,9 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
18 void const *code_addr, 113 void const *code_addr,
19 jint map_length, 114 jint map_length,
20 jvmtiAddrLocationMap const *map, 115 jvmtiAddrLocationMap const *map,
21 void const *compile_info __unused) 116 const void *compile_info)
22{ 117{
23 jvmtiLineNumberEntry *tab = NULL; 118 jvmti_line_info_t *line_tab = NULL;
24 jclass decl_class; 119 jclass decl_class;
25 char *class_sign = NULL; 120 char *class_sign = NULL;
26 char *func_name = NULL; 121 char *func_name = NULL;
@@ -29,7 +124,7 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
29 char fn[PATH_MAX]; 124 char fn[PATH_MAX];
30 uint64_t addr = (uint64_t)(uintptr_t)code_addr; 125 uint64_t addr = (uint64_t)(uintptr_t)code_addr;
31 jvmtiError ret; 126 jvmtiError ret;
32 jint nr_lines = 0; 127 int nr_lines = 0; /* in line_tab[] */
33 size_t len; 128 size_t len;
34 129
35 ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method, 130 ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
@@ -40,19 +135,19 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
40 } 135 }
41 136
42 if (has_line_numbers && map && map_length) { 137 if (has_line_numbers && map && map_length) {
43 138 ret = get_line_numbers(jvmti, compile_info, &line_tab, &nr_lines);
44 ret = (*jvmti)->GetLineNumberTable(jvmti, method, &nr_lines, &tab);
45 if (ret != JVMTI_ERROR_NONE) { 139 if (ret != JVMTI_ERROR_NONE) {
46 warnx("jvmti: cannot get line table for method"); 140 warnx("jvmti: cannot get line table for method");
47 } else { 141 nr_lines = 0;
48 ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
49 if (ret != JVMTI_ERROR_NONE) {
50 warnx("jvmti: cannot get source filename ret=%d", ret);
51 nr_lines = 0;
52 }
53 } 142 }
54 } 143 }
55 144
145 ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
146 if (ret != JVMTI_ERROR_NONE) {
147 warnx("jvmti: cannot get source filename ret=%d", ret);
148 goto error;
149 }
150
56 ret = (*jvmti)->GetClassSignature(jvmti, decl_class, 151 ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
57 &class_sign, NULL); 152 &class_sign, NULL);
58 if (ret != JVMTI_ERROR_NONE) { 153 if (ret != JVMTI_ERROR_NONE) {
@@ -92,13 +187,14 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
92 /* 187 /*
93 * write source line info record if we have it 188 * write source line info record if we have it
94 */ 189 */
95 if (jvmti_write_debug_info(jvmti_agent, addr, fn, map, tab, nr_lines)) 190 if (jvmti_write_debug_info(jvmti_agent, addr, fn, line_tab, nr_lines))
96 warnx("jvmti: write_debug_info() failed"); 191 warnx("jvmti: write_debug_info() failed");
97 192
98 len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2; 193 len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
99 { 194 {
100 char str[len]; 195 char str[len];
101 snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign); 196 snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
197
102 if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size)) 198 if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
103 warnx("jvmti: write_code() failed"); 199 warnx("jvmti: write_code() failed");
104 } 200 }
@@ -106,8 +202,8 @@ error:
106 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_name); 202 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
107 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign); 203 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
108 (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign); 204 (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
109 (*jvmti)->Deallocate(jvmti, (unsigned char *)tab);
110 (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name); 205 (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
206 free(line_tab);
111} 207}
112 208
113static void JNICALL 209static void JNICALL