jruby-async-profiler 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }