Skip to content

Commit 3e1e292

Browse files
authored
Merge pull request #62 from nitsanw/frame-annotation
Add option to explicitly annotate Java frames with _[j]/_[i]
2 parents a615063 + 349f1c2 commit 3e1e292

File tree

1 file changed

+66
-40
lines changed

1 file changed

+66
-40
lines changed

src/c/perf-map-agent.c

Lines changed: 66 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
#include <string.h>
2424
#include <unistd.h>
2525

26-
#include <sys/types.h>
27-
2826
#include <jni.h>
2927
#include <jvmti.h>
3028
#include <jvmticmlr.h>
@@ -39,10 +37,17 @@ bool unfold_simple = false;
3937
bool unfold_all = false;
4038
bool print_method_signatures = false;
4139
bool print_source_loc = false;
40+
4241
bool clean_class_names = false;
42+
bool dotted_class_names = false;
43+
bool annotate_java_frames = false;
44+
char *unfold_delimiter = "->";
45+
4346
bool debug_dump_unfold_entries = false;
4447

4548
FILE *method_file = NULL;
49+
50+
4651
void open_map_file() {
4752
if (!method_file)
4853
method_file = perf_map_open(getpid());
@@ -52,6 +57,14 @@ void close_map_file() {
5257
method_file = NULL;
5358
}
5459

60+
void deallocate(jvmtiEnv *jvmti, void *string) {
61+
if (string != NULL) (*jvmti)->Deallocate(jvmti, (unsigned char *) string);
62+
}
63+
64+
char *frame_annotation(bool inlined) {
65+
return annotate_java_frames ? (inlined ? "_[i]" : "_[j]") : "";
66+
}
67+
5568
static int get_line_number(jvmtiLineNumberEntry *table, jint entry_count, jlocation loc) {
5669
int i;
5770
for (i = 0; i < entry_count; i++)
@@ -61,21 +74,21 @@ static int get_line_number(jvmtiLineNumberEntry *table, jint entry_count, jlocat
6174
}
6275

6376
void class_name_from_sig(char *dest, size_t dest_size, const char *sig) {
64-
if (clean_class_names && sig[0] == 'L') {
65-
const char *src = sig + 1;
77+
if ((clean_class_names || dotted_class_names) && sig[0] == 'L') {
78+
const char *src = clean_class_names ? sig + 1 : sig;
6679
int i;
6780
for(i = 0; i < (dest_size - 1) && src[i]; i++) {
6881
char c = src[i];
69-
if (c == '/') c = '.';
70-
if (c == ';') c = 0;
82+
if (dotted_class_names && c == '/') c = '.';
83+
if (clean_class_names && c == ';') break;
7184
dest[i] = c;
7285
}
7386
dest[i] = 0;
7487
} else
7588
strncpy(dest, sig, dest_size);
7689
}
7790

78-
static void sig_string(jvmtiEnv *jvmti, jmethodID method, char *output, size_t noutput) {
91+
static void sig_string(jvmtiEnv *jvmti, jmethodID method, char *output, size_t noutput, char *annotation) {
7992
char *sourcefile = NULL;
8093
char *method_name = NULL;
8194
char *msig = NULL;
@@ -101,9 +114,9 @@ static void sig_string(jvmtiEnv *jvmti, jmethodID method, char *output, size_t n
101114
if(entrycount > 0) lineno = lines[0].line_number;
102115
snprintf(source_info, sizeof(source_info), "(%s:%d)", sourcefile, lineno);
103116

104-
if (lines != NULL) (*jvmti)->Deallocate(jvmti, (unsigned char *) lines);
117+
deallocate(jvmti, lines);
105118
}
106-
if (sourcefile != NULL) (*jvmti)->Deallocate(jvmti, (unsigned char *) sourcefile);
119+
deallocate(jvmti, (unsigned char *) sourcefile);
107120
}
108121
}
109122

@@ -112,28 +125,38 @@ static void sig_string(jvmtiEnv *jvmti, jmethodID method, char *output, size_t n
112125

113126
char class_name[STRING_BUFFER_SIZE];
114127
class_name_from_sig(class_name, sizeof(class_name), csig);
115-
snprintf(output, noutput, "%s::%s%s%s", class_name, method_name, method_signature, source_info);
128+
snprintf(output, noutput, "%s::%s%s%s%s",
129+
class_name, method_name, method_signature, source_info, annotation);
116130

117-
if (csig != NULL) (*jvmti)->Deallocate(jvmti, (unsigned char *) csig);
131+
deallocate(jvmti, (unsigned char *) csig);
118132
}
119-
if (method_name != NULL) (*jvmti)->Deallocate(jvmti, (unsigned char *) method_name);
120-
if (msig != NULL) (*jvmti)->Deallocate(jvmti, (unsigned char *) msig);
133+
deallocate(jvmti, (unsigned char *) method_name);
134+
deallocate(jvmti, (unsigned char *) msig);
121135
}
122136
}
123137

124-
void generate_single_entry(jvmtiEnv *jvmti, jmethodID method, const void *code_addr, jint code_size) {
138+
void generate_single_entry(
139+
jvmtiEnv *jvmti,
140+
jmethodID method,
141+
const void *code_addr,
142+
jint code_size) {
125143
char entry[STRING_BUFFER_SIZE];
126-
sig_string(jvmti, method, entry, sizeof(entry));
144+
sig_string(jvmti, method, entry, sizeof(entry), frame_annotation(false));
127145
perf_map_write_entry(method_file, code_addr, (unsigned int) code_size, entry);
128146
}
129147

130148
/* Generates either a simple or a complex unfolded entry. */
131-
void generate_unfolded_entry(jvmtiEnv *jvmti, jmethodID method, char *buffer, size_t buffer_size, const char *root_name) {
149+
void generate_unfolded_entry(
150+
jvmtiEnv *jvmti,
151+
jmethodID method,
152+
char *buffer,
153+
size_t buffer_size,
154+
const char *root_name) {
132155
if (unfold_simple)
133-
sig_string(jvmti, method, buffer, buffer_size);
156+
sig_string(jvmti, method, buffer, buffer_size, "");
134157
else {
135158
char entry_name[STRING_BUFFER_SIZE];
136-
sig_string(jvmti, method, entry_name, sizeof(entry_name));
159+
sig_string(jvmti, method, entry_name, sizeof(entry_name), "");
137160
snprintf(buffer, buffer_size, "%s in %s", entry_name, root_name);
138161
}
139162
}
@@ -154,20 +177,22 @@ void write_unfolded_entry(
154177
char full_name[BIG_STRING_BUFFER_SIZE];
155178
full_name[0] = '\0';
156179
int i;
157-
for (i = info->numstackframes - 1; i >= 0; i--) {
158-
//printf("At %d method is %d len %d remaining %d\n", i, info->methods[i], strlen(full_name), sizeof(full_name) - 1 - strlen(full_name));
159-
sig_string(jvmti, info->methods[i], inlined_name, sizeof(inlined_name));
180+
// the stack is ordered from leaf@[0] to root@[length-1], so we traverse backwards to construct the unfolded string
181+
const jint first_frame = info->numstackframes - 1;
182+
for (i = first_frame; i >= 0; i--) {
183+
sig_string(jvmti, info->methods[i], inlined_name, sizeof(inlined_name), frame_annotation(i != first_frame));
160184
strncat(full_name, inlined_name, sizeof(full_name) - 1 - strlen(full_name)); // TODO optimize
161-
if (i != 0) strncat(full_name, "->", sizeof(full_name) -1 - strlen(full_name));
185+
if (i != 0) strncat(full_name, unfold_delimiter, sizeof(full_name) -1 - strlen(full_name));
162186
}
163187
entry_p = full_name;
164188
} else {
165189
jmethodID cur_method = info->methods[0]; // top of stack
166190
if (cur_method != root_method) {
167191
generate_unfolded_entry(jvmti, cur_method, inlined_name, sizeof(inlined_name), root_name);
168192
entry_p = inlined_name;
169-
} else
193+
} else {
170194
entry_p = root_name;
195+
}
171196
}
172197

173198
perf_map_write_entry(method_file, start_addr, (unsigned int) (end_addr - start_addr), entry_p);
@@ -177,13 +202,11 @@ void dump_entries(
177202
jvmtiEnv *jvmti,
178203
jmethodID root_method,
179204
jint code_size,
180-
const void* code_addr,
181-
jint map_length,
182-
const jvmtiAddrLocationMap* map,
183-
const void* compile_info) {
205+
const void *code_addr,
206+
const void *compile_info) {
184207
const jvmtiCompiledMethodLoadRecordHeader *header = compile_info;
185208
char root_name[STRING_BUFFER_SIZE];
186-
sig_string(jvmti, root_method, root_name, sizeof(root_name));
209+
sig_string(jvmti, root_method, root_name, sizeof(root_name), "");
187210
printf("At %s size %x from %p to %p", root_name, code_size, code_addr, code_addr + code_size);
188211
if (header->kind == JVMTI_CMLR_INLINE_INFO) {
189212
const jvmtiCompiledMethodLoadInlineRecord *record = (jvmtiCompiledMethodLoadInlineRecord *) header;
@@ -197,7 +220,7 @@ void dump_entries(
197220
int j;
198221
for (j = 0; j < info->numstackframes; j++) {
199222
char buf[2000];
200-
sig_string(jvmti, info->methods[j], buf, sizeof(buf));
223+
sig_string(jvmti, info->methods[j], buf, sizeof(buf), "");
201224
printf(" %s\n", buf);
202225
}
203226
}
@@ -209,16 +232,14 @@ void generate_unfolded_entries(
209232
jmethodID root_method,
210233
jint code_size,
211234
const void* code_addr,
212-
jint map_length,
213-
const jvmtiAddrLocationMap* map,
214235
const void* compile_info) {
215236
const jvmtiCompiledMethodLoadRecordHeader *header = compile_info;
216237
char root_name[STRING_BUFFER_SIZE];
217238

218-
sig_string(jvmti, root_method, root_name, sizeof(root_name));
239+
sig_string(jvmti, root_method, root_name, sizeof(root_name), "");
219240

220241
if (debug_dump_unfold_entries)
221-
dump_entries(jvmti, root_method, code_size, code_addr, map_length, map, compile_info);
242+
dump_entries(jvmti, root_method, code_size, code_addr, compile_info);
222243

223244
if (header->kind == JVMTI_CMLR_INLINE_INFO) {
224245
const jvmtiCompiledMethodLoadInlineRecord *record = (jvmtiCompiledMethodLoadInlineRecord *) header;
@@ -258,8 +279,9 @@ void generate_unfolded_entries(
258279
else
259280
generate_single_entry(jvmti, root_method, start_addr, (unsigned int) (end_addr - start_addr));
260281
}
261-
} else
282+
} else {
262283
generate_single_entry(jvmti, root_method, code_addr, code_size);
284+
}
263285
}
264286

265287
static void JNICALL
@@ -272,7 +294,7 @@ cbCompiledMethodLoad(
272294
const jvmtiAddrLocationMap* map,
273295
const void* compile_info) {
274296
if (unfold_inlined_methods && compile_info != NULL)
275-
generate_unfolded_entries(jvmti, method, code_size, code_addr, map_length, map, compile_info);
297+
generate_unfolded_entries(jvmti, method, code_size, code_addr, compile_info);
276298
else
277299
generate_single_entry(jvmti, method, code_addr, code_size);
278300
}
@@ -286,10 +308,8 @@ cbDynamicCodeGenerated(jvmtiEnv *jvmti,
286308
}
287309

288310
void set_notification_mode(jvmtiEnv *jvmti, jvmtiEventMode mode) {
289-
(*jvmti)->SetEventNotificationMode(jvmti, mode,
290-
JVMTI_EVENT_COMPILED_METHOD_LOAD, (jthread)NULL);
291-
(*jvmti)->SetEventNotificationMode(jvmti, mode,
292-
JVMTI_EVENT_DYNAMIC_CODE_GENERATED, (jthread)NULL);
311+
(*jvmti)->SetEventNotificationMode(jvmti, mode, JVMTI_EVENT_COMPILED_METHOD_LOAD, (jthread)NULL);
312+
(*jvmti)->SetEventNotificationMode(jvmti, mode, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, (jthread)NULL);
293313
}
294314

295315
jvmtiError enable_capabilities(jvmtiEnv *jvmti) {
@@ -326,7 +346,13 @@ Agent_OnAttach(JavaVM *vm, char *options, void *reserved) {
326346
unfold_inlined_methods = strstr(options, "unfold") != NULL || unfold_simple || unfold_all;
327347
print_method_signatures = strstr(options, "msig") != NULL;
328348
print_source_loc = strstr(options, "sourcepos") != NULL;
329-
clean_class_names = strstr(options, "dottedclass") != NULL;
349+
dotted_class_names = strstr(options, "dottedclass") != NULL;
350+
clean_class_names = strstr(options, "cleanclass") != NULL;
351+
annotate_java_frames = strstr(options, "annotate_java_frames") != NULL;
352+
353+
bool use_semicolon_unfold_delimiter = strstr(options, "use_semicolon_unfold_delimiter") != NULL;
354+
unfold_delimiter = use_semicolon_unfold_delimiter ? ";" : "->";
355+
330356
debug_dump_unfold_entries = strstr(options, "debug_dump_unfold_entries") != NULL;
331357

332358
jvmtiEnv *jvmti;

0 commit comments

Comments
 (0)