jruby-async-profiler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.gitmodules +3 -0
  4. data/Gemfile +4 -0
  5. data/README.md +35 -0
  6. data/Rakefile +2 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +8 -0
  9. data/ext/Rakefile +6 -0
  10. data/ext/async-profiler/.gitattributes +1 -0
  11. data/ext/async-profiler/.gitignore +6 -0
  12. data/ext/async-profiler/.travis.yml +11 -0
  13. data/ext/async-profiler/CHANGELOG.md +107 -0
  14. data/ext/async-profiler/JavaHome.class +0 -0
  15. data/ext/async-profiler/LICENSE +201 -0
  16. data/ext/async-profiler/Makefile +66 -0
  17. data/ext/async-profiler/README.md +487 -0
  18. data/ext/async-profiler/demo/SwingSet2.svg +2247 -0
  19. data/ext/async-profiler/docs/cddl1.txt +358 -0
  20. data/ext/async-profiler/profiler.sh +240 -0
  21. data/ext/async-profiler/src/allocTracer.cpp +155 -0
  22. data/ext/async-profiler/src/allocTracer.h +74 -0
  23. data/ext/async-profiler/src/arch.h +69 -0
  24. data/ext/async-profiler/src/arguments.cpp +265 -0
  25. data/ext/async-profiler/src/arguments.h +152 -0
  26. data/ext/async-profiler/src/codeCache.cpp +128 -0
  27. data/ext/async-profiler/src/codeCache.h +99 -0
  28. data/ext/async-profiler/src/engine.cpp +50 -0
  29. data/ext/async-profiler/src/engine.h +38 -0
  30. data/ext/async-profiler/src/flameGraph.cpp +770 -0
  31. data/ext/async-profiler/src/flameGraph.h +118 -0
  32. data/ext/async-profiler/src/flightRecorder.cpp +727 -0
  33. data/ext/async-profiler/src/flightRecorder.h +39 -0
  34. data/ext/async-profiler/src/frameName.cpp +189 -0
  35. data/ext/async-profiler/src/frameName.h +56 -0
  36. data/ext/async-profiler/src/itimer.cpp +49 -0
  37. data/ext/async-profiler/src/itimer.h +43 -0
  38. data/ext/async-profiler/src/jattach/jattach.c +437 -0
  39. data/ext/async-profiler/src/java/one/profiler/AsyncProfiler.java +160 -0
  40. data/ext/async-profiler/src/java/one/profiler/AsyncProfilerMXBean.java +43 -0
  41. data/ext/async-profiler/src/java/one/profiler/Counter.java +25 -0
  42. data/ext/async-profiler/src/java/one/profiler/Events.java +28 -0
  43. data/ext/async-profiler/src/javaApi.cpp +124 -0
  44. data/ext/async-profiler/src/lockTracer.cpp +161 -0
  45. data/ext/async-profiler/src/lockTracer.h +55 -0
  46. data/ext/async-profiler/src/mutex.cpp +33 -0
  47. data/ext/async-profiler/src/mutex.h +49 -0
  48. data/ext/async-profiler/src/os.h +45 -0
  49. data/ext/async-profiler/src/os_linux.cpp +129 -0
  50. data/ext/async-profiler/src/os_macos.cpp +115 -0
  51. data/ext/async-profiler/src/perfEvents.h +60 -0
  52. data/ext/async-profiler/src/perfEvents_linux.cpp +550 -0
  53. data/ext/async-profiler/src/perfEvents_macos.cpp +64 -0
  54. data/ext/async-profiler/src/profiler.cpp +952 -0
  55. data/ext/async-profiler/src/profiler.h +238 -0
  56. data/ext/async-profiler/src/spinLock.h +66 -0
  57. data/ext/async-profiler/src/stackFrame.h +57 -0
  58. data/ext/async-profiler/src/stackFrame_aarch64.cpp +75 -0
  59. data/ext/async-profiler/src/stackFrame_arm.cpp +58 -0
  60. data/ext/async-profiler/src/stackFrame_i386.cpp +82 -0
  61. data/ext/async-profiler/src/stackFrame_x64.cpp +113 -0
  62. data/ext/async-profiler/src/symbols.h +37 -0
  63. data/ext/async-profiler/src/symbols_linux.cpp +354 -0
  64. data/ext/async-profiler/src/symbols_macos.cpp +156 -0
  65. data/ext/async-profiler/src/vmEntry.cpp +173 -0
  66. data/ext/async-profiler/src/vmEntry.h +105 -0
  67. data/ext/async-profiler/src/vmStructs.cpp +104 -0
  68. data/ext/async-profiler/src/vmStructs.h +112 -0
  69. data/ext/async-profiler/src/wallClock.cpp +96 -0
  70. data/ext/async-profiler/src/wallClock.h +56 -0
  71. data/ext/async-profiler/test/AllocatingTarget.java +26 -0
  72. data/ext/async-profiler/test/LoadLibraryTest.java +21 -0
  73. data/ext/async-profiler/test/Target.java +31 -0
  74. data/ext/async-profiler/test/ThreadsTarget.java +35 -0
  75. data/ext/async-profiler/test/alloc-smoke-test.sh +36 -0
  76. data/ext/async-profiler/test/load-library-test.sh +35 -0
  77. data/ext/async-profiler/test/smoke-test.sh +37 -0
  78. data/ext/async-profiler/test/thread-smoke-test.sh +32 -0
  79. data/jruby-async-profiler.gemspec +32 -0
  80. data/lib/jruby/async/profiler.rb +10 -0
  81. data/lib/jruby/async/profiler/version.rb +7 -0
  82. metadata +155 -0
@@ -0,0 +1,118 @@
1
+ /*
2
+ * Copyright 2018 Andrei Pangin
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #ifndef _FLAMEGRAPH_H
18
+ #define _FLAMEGRAPH_H
19
+
20
+ #include <map>
21
+ #include <string>
22
+ #include <iostream>
23
+ #include "arch.h"
24
+ #include "arguments.h"
25
+
26
+
27
+ class Trie {
28
+ public:
29
+ std::map<std::string, Trie> _children;
30
+ u64 _total;
31
+ u64 _self;
32
+
33
+ Trie() : _children(), _total(0), _self(0) {
34
+ }
35
+
36
+ Trie* addChild(const std::string& key, u64 value) {
37
+ _total += value;
38
+ return &_children[key];
39
+ }
40
+
41
+ void addLeaf(u64 value) {
42
+ _total += value;
43
+ _self += value;
44
+ }
45
+
46
+ int depth(u64 cutoff) const {
47
+ if (_total < cutoff) {
48
+ return 0;
49
+ }
50
+
51
+ int max_depth = 0;
52
+ for (std::map<std::string, Trie>::const_iterator it = _children.begin(); it != _children.end(); ++it) {
53
+ int d = it->second.depth(cutoff);
54
+ if (d > max_depth) max_depth = d;
55
+ }
56
+ return max_depth + 1;
57
+ }
58
+ };
59
+
60
+ class Node {
61
+ public:
62
+ std::string _name;
63
+ const Trie* _trie;
64
+
65
+ Node(std::string name, const Trie& trie) : _name(name), _trie(&trie) {
66
+ }
67
+
68
+ bool operator<(const Node& other) const {
69
+ return _trie->_total > other._trie->_total;
70
+ }
71
+ };
72
+
73
+
74
+ class Palette;
75
+
76
+
77
+ class FlameGraph {
78
+ private:
79
+ Trie _root;
80
+ char _buf[4096];
81
+
82
+ const char* _title;
83
+ Counter _counter;
84
+ int _imagewidth;
85
+ int _imageheight;
86
+ int _frameheight;
87
+ double _minwidth;
88
+ double _scale;
89
+ double _pct;
90
+ bool _reverse;
91
+
92
+ void printHeader(std::ostream& out);
93
+ void printFooter(std::ostream& out);
94
+ double printFrame(std::ostream& out, const std::string& name, const Trie& f, double x, double y);
95
+ void printTreeHeader(std::ostream& out);
96
+ void printTreeFooter(std::ostream& out);
97
+ bool printTreeFrame(std::ostream& out, const Trie& f, int depth);
98
+ const Palette& selectFramePalette(std::string& name);
99
+
100
+ public:
101
+ FlameGraph(const char* title, Counter counter, int width, int height, double minwidth, bool reverse) :
102
+ _root(),
103
+ _title(title),
104
+ _counter(counter),
105
+ _imagewidth(width),
106
+ _frameheight(height),
107
+ _minwidth(minwidth),
108
+ _reverse(reverse) {
109
+ }
110
+
111
+ Trie* root() {
112
+ return &_root;
113
+ }
114
+
115
+ void dump(std::ostream& out, bool tree);
116
+ };
117
+
118
+ #endif // _FLAMEGRAPH_H
@@ -0,0 +1,727 @@
1
+ /*
2
+ * Copyright 2018 Andrei Pangin
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include <map>
18
+ #include <string>
19
+ #include <arpa/inet.h>
20
+ #include <cxxabi.h>
21
+ #include <fcntl.h>
22
+ #include <stdint.h>
23
+ #include <stdlib.h>
24
+ #include <string.h>
25
+ #include <sys/types.h>
26
+ #include <unistd.h>
27
+ #include "flightRecorder.h"
28
+ #include "os.h"
29
+ #include "profiler.h"
30
+ #include "vmStructs.h"
31
+
32
+
33
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
34
+
35
+ const int RECORDING_BUFFER_SIZE = 65536;
36
+ const int RECORDING_LIMIT = RECORDING_BUFFER_SIZE - 4096;
37
+
38
+
39
+ enum DataType {
40
+ T_BOOLEAN,
41
+ T_BYTE,
42
+ T_U1,
43
+ T_SHORT,
44
+ T_U2,
45
+ T_INTEGER,
46
+ T_U4,
47
+ T_LONG,
48
+ T_U8,
49
+ T_FLOAT,
50
+ T_DOUBLE,
51
+ T_UTF8,
52
+ T_STRING,
53
+ T_ARRAY,
54
+ T_STRUCT,
55
+ T_STRUCTARRAY,
56
+ };
57
+
58
+ enum EventTypeId {
59
+ EVENT_METADATA = 0,
60
+ EVENT_CHECKPOINT = 1,
61
+ EVENT_RECORDING = 10,
62
+ EVENT_RECORDING_SETTINGS = 11,
63
+ EVENT_EXECUTION_SAMPLE = 20,
64
+ };
65
+
66
+ enum ContentTypeId {
67
+ CONTENT_NONE = 0,
68
+ CONTENT_MEMORY = 1,
69
+ CONTENT_EPOCHMILLIS = 2,
70
+ CONTENT_MILLIS = 3,
71
+ CONTENT_NANOS = 4,
72
+ CONTENT_THREAD = 7,
73
+ CONTENT_STACKTRACE = 9,
74
+ CONTENT_CLASS = 10,
75
+ CONTENT_METHOD = 32,
76
+ CONTENT_SYMBOL = 33,
77
+ CONTENT_STATE = 34,
78
+ CONTENT_FRAME_TYPE = 47,
79
+ };
80
+
81
+ enum FrameTypeId {
82
+ FRAME_INTERPRETED = 1,
83
+ FRAME_JIT_COMPILED = 2,
84
+ FRAME_INLINED = 3,
85
+ FRAME_NATIVE = 4,
86
+ FRAME_CPP = 5,
87
+ FRAME_KERNEL = 6,
88
+ FRAME_TOTAL_COUNT = 6
89
+ };
90
+
91
+ enum ThreadStateId {
92
+ STATE_RUNNABLE = 1,
93
+ STATE_TOTAL_COUNT = 1
94
+ };
95
+
96
+
97
+ struct DataStructure {
98
+ const char* id;
99
+ const char* name;
100
+ DataType data_type;
101
+ ContentTypeId content_type;
102
+ int data_struct_index;
103
+ };
104
+
105
+ struct EventType {
106
+ EventTypeId id;
107
+ const char* name;
108
+ const char* description;
109
+ const char* path;
110
+ bool has_start_time;
111
+ bool has_thread;
112
+ bool can_have_stacktrace;
113
+ bool is_requestable;
114
+ int data_structure;
115
+ };
116
+
117
+ struct ContentType {
118
+ ContentTypeId id;
119
+ const char* name;
120
+ const char* description;
121
+ DataType data_type;
122
+ int data_structure;
123
+ };
124
+
125
+
126
+ const DataStructure
127
+ ds_recording[] = {
128
+ {"id", "Id", T_LONG},
129
+ {"name", "Name", T_STRING},
130
+ {"destination", "Destination", T_STRING},
131
+ {"startTime", "Start Time", T_LONG, CONTENT_EPOCHMILLIS},
132
+ {"duration", "Recording Duration", T_LONG, CONTENT_MILLIS},
133
+ {"maxSize", "Max Size", T_LONG, CONTENT_MEMORY},
134
+ {"maxAge", "Max Age", T_LONG, CONTENT_MILLIS},
135
+ },
136
+ ds_recording_settings[] = {
137
+ {"id", "Id", T_INTEGER},
138
+ {"name", "Name", T_STRING},
139
+ {"path", "Event Path", T_STRING},
140
+ {"enabled", "Enabled", T_BOOLEAN},
141
+ {"stacktrace", "Stack Trace", T_BOOLEAN},
142
+ {"period", "Period", T_LONG, CONTENT_MILLIS},
143
+ {"threshold", "Threshold", T_LONG, CONTENT_NANOS},
144
+ };
145
+
146
+ const EventType et_recording[] = {
147
+ {EVENT_RECORDING, "Flight Recording", "", "recordings/recording", false, false, false, false, 0},
148
+ {EVENT_RECORDING_SETTINGS, "Recording Setting", "", "recordings/recording_setting", false, false, false, true, 1},
149
+ };
150
+
151
+ const DataStructure
152
+ ds_utf8[] = {
153
+ {"utf8", "UTF8 data", T_UTF8},
154
+ },
155
+ ds_thread[] = {
156
+ {"name", "Thread name", T_UTF8},
157
+ },
158
+ ds_frame_type[] = {
159
+ {"desc", "Description", T_UTF8},
160
+ },
161
+ ds_state[] = {
162
+ {"name", "Name", T_UTF8},
163
+ },
164
+ ds_class[] = {
165
+ {"loaderClass", "ClassLoader", T_U8, CONTENT_CLASS},
166
+ {"name", "Name", T_U8, CONTENT_SYMBOL},
167
+ {"modifiers", "Access modifiers", T_SHORT},
168
+ },
169
+ ds_method[] = {
170
+ {"class", "Class", T_U8, CONTENT_CLASS},
171
+ {"name", "Name", T_U8, CONTENT_SYMBOL},
172
+ {"signature", "Signature", T_U8, CONTENT_SYMBOL},
173
+ {"modifiers", "Access modifiers", T_SHORT},
174
+ {"hidden", "Hidden", T_BOOLEAN},
175
+ },
176
+ ds_frame[] = {
177
+ {"method", "Java Method", T_U8, CONTENT_METHOD},
178
+ {"bci", "Byte code index", T_INTEGER},
179
+ {"type", "Frame type", T_U1, CONTENT_FRAME_TYPE},
180
+ },
181
+ ds_stacktrace[] = {
182
+ {"truncated", "Truncated", T_BOOLEAN},
183
+ {"frames", "Stack frames", T_STRUCTARRAY, CONTENT_NONE, /* ds_frame */ 6},
184
+ },
185
+ ds_method_sample[] = {
186
+ {"sampledThread", "Thread", T_U4, CONTENT_THREAD},
187
+ {"stackTrace", "Stack Trace", T_U8, CONTENT_STACKTRACE},
188
+ {"state", "Thread State", T_U2, CONTENT_STATE},
189
+ };
190
+
191
+ const EventType et_profile[] = {
192
+ {EVENT_EXECUTION_SAMPLE, "Method Profiling Sample", "Snapshot of a threads state", "vm/prof/execution_sample", false, false, false, true, /* ds_method_sample */ 8},
193
+ };
194
+
195
+ const ContentType ct_profile[] = {
196
+ {CONTENT_SYMBOL, "UTFConstant", "UTF constant", T_U8, 0},
197
+ {CONTENT_THREAD, "Thread", "Thread", T_U4, 1},
198
+ {CONTENT_FRAME_TYPE, "FrameType", "Frame type", T_U1, 2},
199
+ {CONTENT_STATE, "ThreadState", "Java Thread State", T_U2, 3},
200
+ {CONTENT_CLASS, "Class", "Java class", T_U8, 4},
201
+ {CONTENT_METHOD, "Method", "Java method", T_U8, 5},
202
+ {CONTENT_STACKTRACE, "StackTrace", "Stacktrace", T_U8, 7},
203
+ };
204
+
205
+
206
+ class MethodInfo {
207
+ public:
208
+ MethodInfo() : _key(0) {
209
+ }
210
+
211
+ int _key;
212
+ int _class;
213
+ int _name;
214
+ int _sig;
215
+ short _modifiers;
216
+ FrameTypeId _type;
217
+ };
218
+
219
+
220
+ class Buffer {
221
+ private:
222
+ int _offset;
223
+ char _data[RECORDING_BUFFER_SIZE - sizeof(int)];
224
+
225
+ public:
226
+ Buffer() : _offset(0) {
227
+ }
228
+
229
+ const char* data() const {
230
+ return _data;
231
+ }
232
+
233
+ int offset() const {
234
+ return _offset;
235
+ }
236
+
237
+ void reset() {
238
+ _offset = 0;
239
+ }
240
+
241
+ void put(const char* v, int len) {
242
+ memcpy(_data + _offset, v, len);
243
+ _offset += len;
244
+ }
245
+
246
+ void put8(char v) {
247
+ _data[_offset++] = v;
248
+ }
249
+
250
+ void put16(short v) {
251
+ *(short*)(_data + _offset) = htons(v);
252
+ _offset += 2;
253
+ }
254
+
255
+ void put32(int v) {
256
+ *(int*)(_data + _offset) = htonl(v);
257
+ _offset += 4;
258
+ }
259
+
260
+ void put64(u64 v) {
261
+ *(u64*)(_data + _offset) = OS::hton64(v);
262
+ _offset += 8;
263
+ }
264
+
265
+ void put32(int offset, int v) {
266
+ *(int*)(_data + offset) = htonl(v);
267
+ }
268
+
269
+ void putUtf8(const char* v) {
270
+ putUtf8(v, strlen(v));
271
+ }
272
+
273
+ void putUtf8(const char* v, int len) {
274
+ put16((short)len);
275
+ put(v, len);
276
+ }
277
+
278
+ void putUtf16(const char* v) {
279
+ putUtf16(v, strlen(v));
280
+ }
281
+
282
+ void putUtf16(const char* v, int len) {
283
+ put32(len);
284
+ for (int i = 0; i < len; i++) {
285
+ put16(v[i]);
286
+ }
287
+ }
288
+ };
289
+
290
+
291
+ class Recording {
292
+ private:
293
+ Buffer _buf[CONCURRENCY_LEVEL];
294
+ int _fd;
295
+ std::map<std::string, int> _symbol_map;
296
+ std::map<std::string, int> _class_map;
297
+ std::map<jmethodID, MethodInfo> _method_map;
298
+ u64 _start_time;
299
+ u64 _start_nanos;
300
+ u64 _stop_time;
301
+ u64 _stop_nanos;
302
+
303
+ public:
304
+ Recording(int fd) : _fd(fd), _symbol_map(), _class_map(), _method_map() {
305
+ _start_time = OS::millis();
306
+ _start_nanos = OS::nanotime();
307
+
308
+ writeHeader(_buf);
309
+ flush(_buf);
310
+ }
311
+
312
+ ~Recording() {
313
+ _stop_nanos = OS::nanotime();
314
+ _stop_time = OS::millis();
315
+
316
+ for (int i = 0; i < CONCURRENCY_LEVEL; i++) {
317
+ flush(&_buf[i]);
318
+ }
319
+
320
+ writeRecordingInfo(_buf);
321
+ flush(_buf);
322
+
323
+ off_t checkpoint_offset = lseek(_fd, 0, SEEK_CUR);
324
+ writeCheckpoint(_buf);
325
+ flush(_buf);
326
+
327
+ off_t metadata_offset = lseek(_fd, 0, SEEK_CUR);
328
+ writeMetadata(_buf, checkpoint_offset);
329
+ flush(_buf);
330
+
331
+ // Patch checkpoint size field
332
+ int checkpoint_size = htonl((int)(metadata_offset - checkpoint_offset));
333
+ ssize_t result = pwrite(_fd, &checkpoint_size, sizeof(checkpoint_size), checkpoint_offset);
334
+ (void)result;
335
+
336
+ // Patch metadata offset
337
+ u64 metadata_start = OS::hton64(metadata_offset);
338
+ result = pwrite(_fd, &metadata_start, sizeof(metadata_start), 8);
339
+ (void)result;
340
+
341
+ close(_fd);
342
+ }
343
+
344
+ int lookup(std::map<std::string, int>& map, std::string key) {
345
+ int* value = &map[key];
346
+ if (*value == 0) *value = map.size();
347
+ return *value;
348
+ }
349
+
350
+ FrameTypeId demangle(const char* name, std::string& result) {
351
+ if (name == NULL) {
352
+ result = "unknown";
353
+ return FRAME_NATIVE;
354
+ }
355
+
356
+ if (name[0] == '_' && name[1] == 'Z') {
357
+ int status;
358
+ char* demangled = abi::__cxa_demangle(name, NULL, NULL, &status);
359
+ if (demangled != NULL) {
360
+ char* p = strchr(demangled, '(');
361
+ if (p != NULL) *p = 0;
362
+ result = demangled;
363
+ free(demangled);
364
+ return FRAME_CPP;
365
+ }
366
+ }
367
+
368
+ int len = strlen(name);
369
+ if (len >= 4 && strcmp(name + len - 4, "_[k]") == 0) {
370
+ result = std::string(name, len - 4);
371
+ return FRAME_KERNEL;
372
+ }
373
+
374
+ result = name;
375
+ return FRAME_NATIVE;
376
+ }
377
+
378
+ MethodInfo* resolveMethod(ASGCT_CallFrame& frame) {
379
+ jmethodID method = frame.method_id;
380
+ MethodInfo* mi = &_method_map[method];
381
+
382
+ if (mi->_key == 0) {
383
+ mi->_key = _method_map.size();
384
+
385
+ if (frame.bci == BCI_NATIVE_FRAME || frame.bci == BCI_ERROR || method == NULL) {
386
+ std::string name;
387
+ FrameTypeId type = demangle((const char*)method, name);
388
+ mi->_class = lookup(_class_map, "");
389
+ mi->_name = lookup(_symbol_map, name);
390
+ mi->_sig = lookup(_symbol_map, type == FRAME_KERNEL ? "(Lk;)L;" : "()L;");
391
+ mi->_modifiers = 0x100;
392
+ mi->_type = type;
393
+
394
+ } else if (frame.bci == BCI_SYMBOL || frame.bci == BCI_SYMBOL_OUTSIDE_TLAB) {
395
+ VMSymbol* symbol = (VMSymbol*)((intptr_t)method & ~1);
396
+ mi->_class = lookup(_class_map, std::string(symbol->body(), symbol->length()));
397
+ mi->_name = lookup(_symbol_map, "new");
398
+ mi->_sig = lookup(_symbol_map, "()L;");
399
+ mi->_modifiers = 0x100;
400
+ mi->_type = FRAME_NATIVE;
401
+
402
+ } else {
403
+ jvmtiEnv* jvmti = VM::jvmti();
404
+ jclass method_class;
405
+ char* class_name = NULL;
406
+ char* method_name = NULL;
407
+ char* method_sig = NULL;
408
+ int modifiers = 0;
409
+
410
+ if (jvmti->GetMethodDeclaringClass(method, &method_class) == 0 &&
411
+ jvmti->GetClassSignature(method_class, &class_name, NULL) == 0 &&
412
+ jvmti->GetMethodName(method, &method_name, &method_sig, NULL) == 0) {
413
+ jvmti->GetMethodModifiers(method, &modifiers);
414
+ mi->_class = lookup(_class_map, std::string(class_name + 1, strlen(class_name) - 2));
415
+ mi->_name = lookup(_symbol_map, method_name);
416
+ mi->_sig = lookup(_symbol_map, method_sig);
417
+ } else {
418
+ mi->_class = lookup(_class_map, "");
419
+ mi->_name = lookup(_symbol_map, "jvmtiError");
420
+ mi->_sig = lookup(_symbol_map, "()L;");
421
+ }
422
+
423
+ mi->_modifiers = (short)modifiers;
424
+ mi->_type = FRAME_INTERPRETED;
425
+
426
+ jvmti->Deallocate((unsigned char*)method_sig);
427
+ jvmti->Deallocate((unsigned char*)method_name);
428
+ jvmti->Deallocate((unsigned char*)class_name);
429
+ }
430
+ }
431
+
432
+ return mi;
433
+ }
434
+
435
+ void flush(Buffer* buf) {
436
+ ssize_t result = write(_fd, buf->data(), buf->offset());
437
+ (void)result;
438
+ buf->reset();
439
+ }
440
+
441
+ void flushIfNeeded(Buffer* buf) {
442
+ if (buf->offset() >= RECORDING_LIMIT) {
443
+ flush(buf);
444
+ }
445
+ }
446
+
447
+ void writeHeader(Buffer* buf) {
448
+ buf->put("FLR\0", 4); // magic
449
+ buf->put16(0); // major
450
+ buf->put16(9); // minor
451
+ buf->put64(0); // metadata offset
452
+ }
453
+
454
+ void writeRecordingInfo(Buffer* buf) {
455
+ int recording_start = buf->offset();
456
+ buf->put32(0); // size
457
+ buf->put32(EVENT_RECORDING);
458
+ buf->put64(_stop_nanos);
459
+ buf->put64(1); // id
460
+ buf->putUtf16("Async-profiler");
461
+ buf->putUtf16("async-profiler.jfr");
462
+ buf->put64(_start_time);
463
+ buf->put64(_stop_time - _start_time);
464
+ buf->put64(0x7fffffff);
465
+ buf->put64(0x7fffffff);
466
+ buf->put32(recording_start, buf->offset() - recording_start);
467
+
468
+ int recording_settings_start = buf->offset();
469
+ buf->put32(0); // size
470
+ buf->put32(EVENT_RECORDING_SETTINGS);
471
+ buf->put64(_stop_nanos);
472
+ buf->put32(1); // id
473
+ buf->putUtf16("Method Profiling Sample");
474
+ buf->putUtf16("vm/prof/execution_sample");
475
+ buf->put8(1);
476
+ buf->put8(0);
477
+ buf->put64(1);
478
+ buf->put64(0);
479
+ buf->put32(recording_settings_start, buf->offset() - recording_settings_start);
480
+ }
481
+
482
+ void writeFixedTables(Buffer* buf) {
483
+ // Frame types
484
+ buf->put32(CONTENT_FRAME_TYPE);
485
+ buf->put32(FRAME_TOTAL_COUNT);
486
+ buf->put8(FRAME_INTERPRETED); buf->putUtf8("Interpreted");
487
+ buf->put8(FRAME_JIT_COMPILED); buf->putUtf8("JIT compiled");
488
+ buf->put8(FRAME_INLINED); buf->putUtf8("Inlined");
489
+ buf->put8(FRAME_NATIVE); buf->putUtf8("Native");
490
+ buf->put8(FRAME_CPP); buf->putUtf8("C++");
491
+ buf->put8(FRAME_KERNEL); buf->putUtf8("Kernel");
492
+
493
+ // Thread states
494
+ buf->put32(CONTENT_STATE);
495
+ buf->put32(STATE_TOTAL_COUNT);
496
+ buf->put16(STATE_RUNNABLE); buf->putUtf8("STATE_RUNNABLE");
497
+ }
498
+
499
+ void writeStackTraces(Buffer* buf) {
500
+ CallTraceSample* traces = Profiler::_instance._traces;
501
+ ASGCT_CallFrame* frame_buffer = Profiler::_instance._frame_buffer;
502
+
503
+ int count = 0;
504
+ for (int i = 0; i < MAX_CALLTRACES; i++) {
505
+ if (traces[i]._samples != 0) count++;
506
+ }
507
+
508
+ buf->put32(CONTENT_STACKTRACE);
509
+ buf->put32(count);
510
+ for (int i = 0; i < MAX_CALLTRACES; i++) {
511
+ CallTraceSample& trace = traces[i];
512
+ if (trace._samples != 0) {
513
+ buf->put64(i); // stack trace key
514
+ buf->put8(0); // truncated
515
+ buf->put32(trace._num_frames);
516
+ for (int j = 0; j < trace._num_frames; j++) {
517
+ MethodInfo* mi = resolveMethod(frame_buffer[trace._start_frame + j]);
518
+ buf->put64(mi->_key); // method key
519
+ buf->put32(0); // bci
520
+ buf->put8(mi->_type); // frame type
521
+ flushIfNeeded(buf);
522
+ }
523
+ flushIfNeeded(buf);
524
+ }
525
+ }
526
+ }
527
+
528
+ void writeMethods(Buffer* buf) {
529
+ buf->put32(CONTENT_METHOD);
530
+ buf->put32(_method_map.size());
531
+ for (std::map<jmethodID, MethodInfo>::const_iterator it = _method_map.begin(); it != _method_map.end(); ++it) {
532
+ const MethodInfo& mi = it->second;
533
+ buf->put64(mi._key);
534
+ buf->put64(mi._class);
535
+ buf->put64(mi._name);
536
+ buf->put64(mi._sig);
537
+ buf->put16(mi._modifiers);
538
+ buf->put8(0); // hidden
539
+ flushIfNeeded(buf);
540
+ }
541
+ }
542
+
543
+ void writeClasses(Buffer* buf) {
544
+ buf->put32(CONTENT_CLASS);
545
+ buf->put32(_class_map.size());
546
+ for (std::map<std::string, int>::const_iterator it = _class_map.begin(); it != _class_map.end(); ++it) {
547
+ buf->put64(it->second);
548
+ buf->put64(0); // loader class
549
+ buf->put64(lookup(_symbol_map, it->first));
550
+ buf->put16(0); // access flags
551
+ flushIfNeeded(buf);
552
+ }
553
+ }
554
+
555
+ void writeSymbols(Buffer* buf) {
556
+ buf->put32(CONTENT_SYMBOL);
557
+ buf->put32(_symbol_map.size());
558
+ for (std::map<std::string, int>::const_iterator it = _symbol_map.begin(); it != _symbol_map.end(); ++it) {
559
+ buf->put64(it->second);
560
+ buf->putUtf8(it->first.c_str());
561
+ flushIfNeeded(buf);
562
+ }
563
+ }
564
+
565
+ void writeThreads(Buffer* buf) {
566
+ buf->put32(CONTENT_THREAD);
567
+ buf->put32(0);
568
+ }
569
+
570
+ void writeCheckpoint(Buffer* buf) {
571
+ buf->put32(0); // size will be patched later
572
+ buf->put32(EVENT_CHECKPOINT);
573
+ buf->put64(_stop_nanos);
574
+ buf->put64(0); // previous checkpoint
575
+
576
+ writeFixedTables(buf);
577
+ writeStackTraces(buf);
578
+ writeMethods(buf);
579
+ writeClasses(buf);
580
+ writeSymbols(buf);
581
+ writeThreads(buf);
582
+ }
583
+
584
+ void writeDataStructure(Buffer* buf, int count, const DataStructure* ds) {
585
+ buf->put32(count);
586
+ for (int i = 0; i < count; i++, ds++) {
587
+ buf->putUtf8(ds->id);
588
+ buf->putUtf8(ds->name);
589
+ buf->putUtf8("");
590
+ buf->put8(0);
591
+ buf->put8(ds->data_type);
592
+ buf->put32(ds->content_type);
593
+ buf->put32(ds->data_struct_index);
594
+ buf->put32(0);
595
+ }
596
+ }
597
+
598
+ void writeEventTypes(Buffer* buf, int count, const EventType* et) {
599
+ buf->put32(count);
600
+ for (int i = 0; i < count; i++, et++) {
601
+ buf->put32(et->id);
602
+ buf->putUtf8(et->name);
603
+ buf->putUtf8(et->description);
604
+ buf->putUtf8(et->path);
605
+ buf->put8(et->has_start_time ? 1 : 0);
606
+ buf->put8(et->has_thread ? 1 : 0);
607
+ buf->put8(et->can_have_stacktrace ? 1 : 0);
608
+ buf->put8(et->is_requestable ? 1 : 0);
609
+ buf->put32(et->data_structure);
610
+ buf->put32(0);
611
+ }
612
+ }
613
+
614
+ void writeContentTypes(Buffer* buf, int count, const ContentType* ct) {
615
+ buf->put32(count);
616
+ for (int i = 0; i < count; i++, ct++) {
617
+ buf->put32(ct->id);
618
+ buf->putUtf8(ct->name);
619
+ buf->putUtf8(ct->description);
620
+ buf->put8(ct->data_type);
621
+ buf->put32(ct->data_structure);
622
+ }
623
+ }
624
+
625
+ void writeRecordingMetadata(Buffer* buf) {
626
+ buf->put32(1);
627
+ buf->putUtf8("JFR Metadata");
628
+ buf->putUtf8("Information about Recordings and Settings");
629
+ buf->putUtf8("http://www.oracle.com/hotspot/jfr-info/");
630
+
631
+ // Relations
632
+ buf->put32(0);
633
+
634
+ // Data structures
635
+ buf->put32(2);
636
+ writeDataStructure(buf, ARRAY_SIZE(ds_recording), ds_recording);
637
+ writeDataStructure(buf, ARRAY_SIZE(ds_recording_settings), ds_recording_settings);
638
+
639
+ // Event types and content types
640
+ writeEventTypes(buf, ARRAY_SIZE(et_recording), et_recording);
641
+ writeContentTypes(buf, 0, NULL);
642
+ }
643
+
644
+ void writeProfileMetadata(Buffer* buf) {
645
+ buf->put32(2);
646
+ buf->putUtf8("HotSpot JVM");
647
+ buf->putUtf8("Oracle Hotspot JVM");
648
+ buf->putUtf8("http://www.oracle.com/hotspot/jvm/");
649
+
650
+ // Relations
651
+ buf->put32(0);
652
+
653
+ // Data structures
654
+ buf->put32(9);
655
+ writeDataStructure(buf, ARRAY_SIZE(ds_utf8), ds_utf8);
656
+ writeDataStructure(buf, ARRAY_SIZE(ds_thread), ds_thread);
657
+ writeDataStructure(buf, ARRAY_SIZE(ds_frame_type), ds_frame_type);
658
+ writeDataStructure(buf, ARRAY_SIZE(ds_state), ds_state);
659
+ writeDataStructure(buf, ARRAY_SIZE(ds_class), ds_class);
660
+ writeDataStructure(buf, ARRAY_SIZE(ds_method), ds_method);
661
+ writeDataStructure(buf, ARRAY_SIZE(ds_frame), ds_frame);
662
+ writeDataStructure(buf, ARRAY_SIZE(ds_stacktrace), ds_stacktrace);
663
+ writeDataStructure(buf, ARRAY_SIZE(ds_method_sample), ds_method_sample);
664
+
665
+ // Event types and content types
666
+ writeEventTypes(buf, ARRAY_SIZE(et_profile), et_profile);
667
+ writeContentTypes(buf, ARRAY_SIZE(ct_profile), ct_profile);
668
+ }
669
+
670
+ void writeMetadata(Buffer* buf, off_t checkpoint_offset) {
671
+ int metadata_start = buf->offset();
672
+ buf->put32(0);
673
+ buf->put32(EVENT_METADATA);
674
+
675
+ // Producers
676
+ buf->put32(2);
677
+ writeRecordingMetadata(buf);
678
+ writeProfileMetadata(buf);
679
+
680
+ buf->put64(_start_time);
681
+ buf->put64(_stop_time);
682
+ buf->put64(_start_nanos);
683
+ buf->put64(1000000000); // ticks per second
684
+ buf->put64(checkpoint_offset);
685
+
686
+ buf->put32(metadata_start, buf->offset() - metadata_start);
687
+ }
688
+
689
+ void recordExecutionSample(int lock_index, int tid, int call_trace_id) {
690
+ Buffer* buf = &_buf[lock_index];
691
+ buf->put32(30);
692
+ buf->put32(EVENT_EXECUTION_SAMPLE);
693
+ buf->put64(OS::nanotime());
694
+ buf->put32(tid);
695
+ buf->put64(call_trace_id);
696
+ buf->put16(STATE_RUNNABLE);
697
+ flushIfNeeded(buf);
698
+ }
699
+ };
700
+
701
+
702
+ Error FlightRecorder::start(const char* file) {
703
+ if (file == NULL || file[0] == 0) {
704
+ return Error("Flight Recorder output file is not specified");
705
+ }
706
+
707
+ int fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0644);
708
+ if (fd == -1) {
709
+ return Error("Cannot open Flight Recorder output file");
710
+ }
711
+
712
+ _rec = new Recording(fd);
713
+ return Error::OK;
714
+ }
715
+
716
+ void FlightRecorder::stop() {
717
+ if (_rec != NULL) {
718
+ delete _rec;
719
+ _rec = NULL;
720
+ }
721
+ }
722
+
723
+ void FlightRecorder::recordExecutionSample(int lock_index, int tid, int call_trace_id) {
724
+ if (_rec != NULL && call_trace_id != 0) {
725
+ _rec->recordExecutionSample(lock_index, tid, call_trace_id);
726
+ }
727
+ }