Skip to content

Commit 6a723a6

Browse files
committed
Merge branch 'unfold-inlining-info'
2 parents ce569bd + 7fbc3eb commit 6a723a6

File tree

5 files changed

+105
-25
lines changed

5 files changed

+105
-25
lines changed

AttachOnce.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class AttachOnce {
2929
public static void main(String[] args) throws Exception {
3030
String pid = args[0];
3131
String options = "";
32-
if (args.length > 2) options = args[1];
32+
if (args.length > 1) options = args[1];
3333
loadAgent(pid, options);
3434
}
3535

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,17 @@ Note: If `perf top` still doesn't show any detailled info it's probably because
1717
to run the java program as a regular user with the agent enabled and then run a `chown root /tmp/perf-<pid>.map` to make
1818
the file accessible for the root user. Then run `perf top` as root. The `perf-java` script tries to do that.
1919

20+
## Options
21+
22+
You can add a comma separated list of options to `perf-java` (or the `AttachOnce` runner). These options are currently supported:
23+
24+
- `unfold`: create extra entries for every codeblock inside a method that was inlined from elsewhere (named &lt;inlined_method&gt; in &lt;root_method&gt;)
25+
2026
## Disclaimer
2127

2228
I'm not a professional C code writer. The code is very "experimental", and it is e.g. missing checks for error conditions etc.. Use it at your own risk. You have been warned!
2329

2430
## License
2531

2632
This library is licensed under GPLv2. See the LICENSE file.
33+

perf-java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
PID=$1
2-
PERF_MODE=$2
2+
OPTIONS=$2
33

44
if [ -p $JAVA_HOME ]; then
55
JAVA_HOME=/usr/lib/jvm/default-java
66
fi
77

8-
java -cp attach-main.jar:$JAVA_HOME/lib/tools.jar net.virtualvoid.perf.AttachOnce $PID
8+
java -cp attach-main.jar:$JAVA_HOME/lib/tools.jar net.virtualvoid.perf.AttachOnce $PID $OPTIONS
99
sudo chown root:root /tmp/perf-$PID.map
10-
sudo perf $PERF_MODE -p $PID
10+
sudo perf top -p $PID

perf-map-agent.c

+93-20
Original file line numberDiff line numberDiff line change
@@ -19,52 +19,123 @@
1919
*/
2020

2121
#include <stdio.h>
22+
#include <string.h>
2223

2324
#include <sys/types.h>
2425

2526
#include <jni.h>
2627
#include <jvmti.h>
27-
#include <string.h>
28+
#include <jvmticmlr.h>
2829

2930
#include "perf-map-file.h"
3031

3132
FILE *method_file = NULL;
33+
int unfold_inlined_methods = 0;
3234

3335
void ensure_open() {
3436
if (!method_file)
3537
method_file = perf_map_open(getpid());
3638
}
3739

38-
static void JNICALL
39-
cbCompiledMethodLoad(jvmtiEnv *env,
40-
jmethodID method,
41-
jint code_size,
42-
const void* code_addr,
43-
jint map_length,
44-
const jvmtiAddrLocationMap* map,
45-
const void* compile_info) {
40+
static int get_line_number(jvmtiLineNumberEntry *table, jint entry_count, jlocation loc) {
41+
int i;
42+
for (i = 0; i < entry_count; i++)
43+
if (table[i].start_location > loc) return table[i - 1].line_number;
44+
45+
return -1;
46+
}
47+
48+
static void sig_string(jvmtiEnv *jvmti, jmethodID method, char *output, size_t noutput) {
4649
char *name;
4750
char *msig;
48-
(*env)->GetMethodName(env, method, &name, &msig, NULL);
49-
5051
jclass class;
51-
(*env)->GetMethodDeclaringClass(env, method, &class);
5252
char *csig;
53-
(*env)->GetClassSignature(env, class, &csig, NULL);
5453

55-
char entry[100];
56-
snprintf(entry, sizeof(entry), "%s.%s%s", csig, name, msig);
54+
(*jvmti)->GetMethodName(jvmti, method, &name, &msig, NULL);
55+
(*jvmti)->GetMethodDeclaringClass(jvmti, method, &class);
56+
(*jvmti)->GetClassSignature(jvmti, class, &csig, NULL);
5757

58-
ensure_open();
58+
snprintf(output, noutput, "%s.%s%s", csig, name, msig);
59+
60+
(*jvmti)->Deallocate(jvmti, name);
61+
(*jvmti)->Deallocate(jvmti, msig);
62+
(*jvmti)->Deallocate(jvmti, csig);
63+
}
64+
65+
void generate_single_entry(jvmtiEnv *jvmti, jmethodID method, const void *code_addr, jint code_size) {
66+
char entry[100];
67+
sig_string(jvmti, method, entry, sizeof(entry));
5968
perf_map_write_entry(method_file, code_addr, code_size, entry);
69+
}
6070

61-
(*env)->Deallocate(env, name);
62-
(*env)->Deallocate(env, msig);
63-
(*env)->Deallocate(env, csig);
71+
void generate_unfolded_entries(
72+
jvmtiEnv *jvmti,
73+
jmethodID method,
74+
jint code_size,
75+
const void* code_addr,
76+
jint map_length,
77+
const jvmtiAddrLocationMap* map,
78+
const void* compile_info) {
79+
int i;
80+
const jvmtiCompiledMethodLoadRecordHeader *header = compile_info;
81+
char root_name[1000];
82+
char entry_name[1000];
83+
char entry[1000];
84+
sig_string(jvmti, method, root_name, sizeof(root_name));
85+
if (header->kind == JVMTI_CMLR_INLINE_INFO) {
86+
const char *entry_p;
87+
const jvmtiCompiledMethodLoadInlineRecord *record = (jvmtiCompiledMethodLoadInlineRecord *) header;
88+
89+
const void *start_addr = code_addr;
90+
jmethodID cur_method = method;
91+
for (i = 0; i < record->numpcs; i++) {
92+
PCStackInfo *info = &record->pcinfo[i];
93+
jmethodID top_method = info->methods[0];
94+
if (cur_method != top_method) {
95+
void *end_addr = info->pc;
96+
97+
if (top_method != method) {
98+
sig_string(jvmti, top_method, entry_name, sizeof(entry_name));
99+
snprintf(entry, sizeof(entry), "%s in %s", entry_name, root_name);
100+
entry_p = entry;
101+
} else
102+
entry_p = root_name;
103+
104+
perf_map_write_entry(method_file, start_addr, end_addr - start_addr, entry_p);
105+
106+
start_addr = info->pc;
107+
cur_method = top_method;
108+
}
109+
}
110+
if (start_addr != code_addr + code_size) {
111+
const void *end_addr = code_addr + code_size;
112+
sig_string(jvmti, cur_method, entry_name, sizeof(entry_name));
113+
snprintf(entry, sizeof(entry), "%s in %s", entry_name, root_name);
114+
115+
perf_map_write_entry(method_file, start_addr, end_addr - start_addr, entry_p);
116+
}
117+
} else
118+
generate_single_entry(jvmti, method, code_addr, code_size);
119+
}
120+
121+
static void JNICALL
122+
cbCompiledMethodLoad(
123+
jvmtiEnv *jvmti,
124+
jmethodID method,
125+
jint code_size,
126+
const void* code_addr,
127+
jint map_length,
128+
const jvmtiAddrLocationMap* map,
129+
const void* compile_info) {
130+
ensure_open();
131+
if (unfold_inlined_methods)
132+
generate_unfolded_entries(jvmti, method, code_size, code_addr, map_length, map, compile_info);
133+
else
134+
generate_single_entry(jvmti, method, code_addr, code_size);
64135
}
65136

66137
void JNICALL
67-
cbDynamicCodeGenerated(jvmtiEnv *jvmti_env,
138+
cbDynamicCodeGenerated(jvmtiEnv *jvmti,
68139
const char* name,
69140
const void* address,
70141
jint length) {
@@ -109,6 +180,8 @@ Agent_OnAttach(JavaVM *vm, char *options, void *reserved) {
109180
ensure_open();
110181
ftruncate(fileno(method_file));
111182

183+
unfold_inlined_methods = strstr(options, "unfold") != NULL;
184+
112185
jvmtiEnv *jvmti;
113186
(*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1);
114187
enable_capabilities(jvmti);

perf-map-file.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ FILE *perf_map_open(pid_t pid) {
3030
}
3131

3232
void perf_map_write_entry(FILE *method_file, const void* code_addr, unsigned int code_size, const char* entry) {
33-
fprintf(method_file, "%lx %x %s\n", code_addr, code_size, entry);
33+
fprintf(method_file, "%lx %x %s\n", (unsigned long) code_addr, code_size, entry);
3434
fflush(method_file);
3535
}

0 commit comments

Comments
 (0)