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,152 @@
1
+ /*
2
+ * Copyright 2017 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 _ARGUMENTS_H
18
+ #define _ARGUMENTS_H
19
+
20
+ #include <stddef.h>
21
+
22
+
23
+ const long DEFAULT_INTERVAL = 10000000; // 10 ms
24
+ const int DEFAULT_FRAMEBUF = 1000000;
25
+ const int DEFAULT_JSTACKDEPTH = 2048;
26
+
27
+ const char* const EVENT_CPU = "cpu";
28
+ const char* const EVENT_ALLOC = "alloc";
29
+ const char* const EVENT_LOCK = "lock";
30
+ const char* const EVENT_WALL = "wall";
31
+ const char* const EVENT_ITIMER = "itimer";
32
+
33
+ enum Action {
34
+ ACTION_NONE,
35
+ ACTION_START,
36
+ ACTION_RESUME,
37
+ ACTION_STOP,
38
+ ACTION_STATUS,
39
+ ACTION_LIST,
40
+ ACTION_VERSION,
41
+ ACTION_DUMP
42
+ };
43
+
44
+ enum Counter {
45
+ COUNTER_SAMPLES,
46
+ COUNTER_TOTAL
47
+ };
48
+
49
+ enum Ring {
50
+ RING_ANY,
51
+ RING_KERNEL,
52
+ RING_USER
53
+ };
54
+
55
+ enum Style {
56
+ STYLE_SIMPLE = 1,
57
+ STYLE_DOTTED = 2,
58
+ STYLE_SIGNATURES = 4,
59
+ STYLE_ANNOTATE = 8
60
+ };
61
+
62
+ enum Output {
63
+ OUTPUT_NONE,
64
+ OUTPUT_TEXT,
65
+ OUTPUT_COLLAPSED,
66
+ OUTPUT_FLAMEGRAPH,
67
+ OUTPUT_TREE,
68
+ OUTPUT_JFR
69
+ };
70
+
71
+
72
+ class Error {
73
+ private:
74
+ const char* _message;
75
+
76
+ public:
77
+ static const Error OK;
78
+
79
+ explicit Error(const char* message) : _message(message) {
80
+ }
81
+
82
+ const char* message() {
83
+ return _message;
84
+ }
85
+
86
+ operator bool() {
87
+ return _message != NULL;
88
+ }
89
+ };
90
+
91
+
92
+ class Arguments {
93
+ private:
94
+ char* _buf;
95
+
96
+ static const char* expandFilePattern(char* dest, size_t max_size, const char* pattern);
97
+ static Output detectOutputFormat(const char* file);
98
+ static long parseUnits(const char* str);
99
+
100
+ public:
101
+ Action _action;
102
+ Counter _counter;
103
+ Ring _ring;
104
+ const char* _event;
105
+ long _interval;
106
+ int _jstackdepth;
107
+ int _framebuf;
108
+ bool _threads;
109
+ bool _sync_walk;
110
+ int _style;
111
+ const char* _file;
112
+ Output _output;
113
+ int _dump_traces;
114
+ int _dump_flat;
115
+ // FlameGraph parameters
116
+ const char* _title;
117
+ int _width;
118
+ int _height;
119
+ double _minwidth;
120
+ bool _reverse;
121
+
122
+ Arguments() :
123
+ _buf(NULL),
124
+ _action(ACTION_NONE),
125
+ _counter(COUNTER_SAMPLES),
126
+ _ring(RING_ANY),
127
+ _event(EVENT_CPU),
128
+ _interval(0),
129
+ _jstackdepth(DEFAULT_JSTACKDEPTH),
130
+ _framebuf(DEFAULT_FRAMEBUF),
131
+ _threads(false),
132
+ _sync_walk(false),
133
+ _style(0),
134
+ _file(NULL),
135
+ _output(OUTPUT_NONE),
136
+ _dump_traces(0),
137
+ _dump_flat(0),
138
+ _title("Flame Graph"),
139
+ _width(1200),
140
+ _height(16),
141
+ _minwidth(0.25),
142
+ _reverse(false) {
143
+ }
144
+
145
+ ~Arguments();
146
+
147
+ void save(Arguments& other);
148
+
149
+ Error parse(const char* args);
150
+ };
151
+
152
+ #endif // _ARGUMENTS_H
@@ -0,0 +1,128 @@
1
+ /*
2
+ * Copyright 2016 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 <stdlib.h>
18
+ #include <string.h>
19
+ #include "codeCache.h"
20
+
21
+
22
+ void CodeCache::expand() {
23
+ CodeBlob* old_blobs = _blobs;
24
+ CodeBlob* new_blobs = new CodeBlob[_capacity * 2];
25
+ memcpy(new_blobs, old_blobs, _capacity * sizeof(CodeBlob));
26
+ _capacity *= 2;
27
+ _blobs = new_blobs;
28
+ delete[] old_blobs;
29
+ }
30
+
31
+ void CodeCache::add(const void* start, int length, jmethodID method) {
32
+ if (_count >= _capacity) {
33
+ expand();
34
+ }
35
+
36
+ _blobs[_count]._start = start;
37
+ _blobs[_count]._end = (const char*)start + length;
38
+ _blobs[_count]._method = method;
39
+ _count++;
40
+ }
41
+
42
+ void CodeCache::remove(const void* start, jmethodID method) {
43
+ for (int i = 0; i < _count; i++) {
44
+ if (_blobs[i]._start == start && _blobs[i]._method == method) {
45
+ _blobs[i]._method = NULL;
46
+ return;
47
+ }
48
+ }
49
+ }
50
+
51
+ jmethodID CodeCache::find(const void* address) {
52
+ for (int i = 0; i < _count; i++) {
53
+ if (address >= _blobs[i]._start && address < _blobs[i]._end) {
54
+ return _blobs[i]._method;
55
+ }
56
+ }
57
+ return NULL;
58
+ }
59
+
60
+
61
+ NativeCodeCache::NativeCodeCache(const char* name, const void* min_address, const void* max_address) {
62
+ _name = strdup(name);
63
+ _min_address = min_address;
64
+ _max_address = max_address;
65
+ }
66
+
67
+ NativeCodeCache::~NativeCodeCache() {
68
+ for (int i = 0; i < _count; i++) {
69
+ free(_blobs[i]._method);
70
+ }
71
+ free(_name);
72
+ }
73
+
74
+ void NativeCodeCache::add(const void* start, int length, const char* name) {
75
+ CodeCache::add(start, length, (jmethodID)strdup(name));
76
+ }
77
+
78
+ void NativeCodeCache::sort() {
79
+ if (_count == 0) return;
80
+
81
+ qsort(_blobs, _count, sizeof(CodeBlob), CodeBlob::comparator);
82
+
83
+ if (_min_address == NULL) _min_address = _blobs[0]._start;
84
+ if (_max_address == NULL) _max_address = _blobs[_count - 1]._end;
85
+ }
86
+
87
+ const char* NativeCodeCache::binarySearch(const void* address) {
88
+ int low = 0;
89
+ int high = _count - 1;
90
+
91
+ while (low <= high) {
92
+ int mid = (unsigned int)(low + high) >> 1;
93
+ if (_blobs[mid]._end <= address) {
94
+ low = mid + 1;
95
+ } else if (_blobs[mid]._start > address) {
96
+ high = mid - 1;
97
+ } else {
98
+ return (const char*)_blobs[mid]._method;
99
+ }
100
+ }
101
+
102
+ // Symbols with zero size can be valid functions: e.g. ASM entry points or kernel code
103
+ if (low > 0 && _blobs[low - 1]._start == _blobs[low - 1]._end) {
104
+ return (const char*)_blobs[low - 1]._method;
105
+ }
106
+ return _name;
107
+ }
108
+
109
+ const void* NativeCodeCache::findSymbol(const char* name) {
110
+ for (int i = 0; i < _count; i++) {
111
+ const char* blob_name = (const char*)_blobs[i]._method;
112
+ if (blob_name != NULL && strcmp(blob_name, name) == 0) {
113
+ return _blobs[i]._start;
114
+ }
115
+ }
116
+ return NULL;
117
+ }
118
+
119
+ const void* NativeCodeCache::findSymbolByPrefix(const char* prefix) {
120
+ int prefix_len = strlen(prefix);
121
+ for (int i = 0; i < _count; i++) {
122
+ const char* blob_name = (const char*)_blobs[i]._method;
123
+ if (blob_name != NULL && strncmp(blob_name, prefix, prefix_len) == 0) {
124
+ return _blobs[i]._start;
125
+ }
126
+ }
127
+ return NULL;
128
+ }
@@ -0,0 +1,99 @@
1
+ /*
2
+ * Copyright 2017 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 _CODECACHE_H
18
+ #define _CODECACHE_H
19
+
20
+ #include <jvmti.h>
21
+
22
+
23
+ const int INITIAL_CODE_CACHE_CAPACITY = 1000;
24
+
25
+
26
+ class CodeBlob {
27
+ public:
28
+ const void* _start;
29
+ const void* _end;
30
+ jmethodID _method;
31
+
32
+ static int comparator(const void* c1, const void* c2) {
33
+ CodeBlob* cb1 = (CodeBlob*)c1;
34
+ CodeBlob* cb2 = (CodeBlob*)c2;
35
+ if (cb1->_start < cb2->_start) {
36
+ return -1;
37
+ } else if (cb1->_start > cb2->_start) {
38
+ return 1;
39
+ } else if (cb1->_end == cb2->_end) {
40
+ return 0;
41
+ } else {
42
+ return cb1->_end > cb2->_end ? -1 : 1;
43
+ }
44
+ }
45
+ };
46
+
47
+
48
+ class CodeCache {
49
+ protected:
50
+ int _capacity;
51
+ int _count;
52
+ CodeBlob* _blobs;
53
+
54
+ void expand();
55
+
56
+ public:
57
+ CodeCache() {
58
+ _capacity = INITIAL_CODE_CACHE_CAPACITY;
59
+ _count = 0;
60
+ _blobs = new CodeBlob[_capacity];
61
+ }
62
+
63
+ ~CodeCache() {
64
+ delete[] _blobs;
65
+ }
66
+
67
+ void add(const void* start, int length, jmethodID method);
68
+ void remove(const void* start, jmethodID method);
69
+ jmethodID find(const void* address);
70
+ };
71
+
72
+
73
+ class NativeCodeCache : public CodeCache {
74
+ private:
75
+ char* _name;
76
+ const void* _min_address;
77
+ const void* _max_address;
78
+
79
+ public:
80
+ NativeCodeCache(const char* name, const void* min_address = NULL, const void* max_address = NULL);
81
+
82
+ ~NativeCodeCache();
83
+
84
+ const char* name() {
85
+ return _name;
86
+ }
87
+
88
+ bool contains(const void* address) {
89
+ return address >= _min_address && address < _max_address;
90
+ }
91
+
92
+ void add(const void* start, int length, const char* name);
93
+ void sort();
94
+ const char* binarySearch(const void* address);
95
+ const void* findSymbol(const char* name);
96
+ const void* findSymbolByPrefix(const char* prefix);
97
+ };
98
+
99
+ #endif // _CODECACHE_H
@@ -0,0 +1,50 @@
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 "engine.h"
18
+ #include "stackFrame.h"
19
+
20
+
21
+ int Engine::getNativeTrace(void* ucontext, int tid, const void** callchain, int max_depth,
22
+ const void* jit_min_address, const void* jit_max_address) {
23
+ StackFrame frame(ucontext);
24
+ const void* pc = (const void*)frame.pc();
25
+ uintptr_t fp = frame.fp();
26
+ uintptr_t prev_fp = (uintptr_t)&fp;
27
+
28
+ int depth = 0;
29
+ const void* const valid_pc = (const void*)0x1000;
30
+
31
+ // Walk until the bottom of the stack or until the first Java frame
32
+ while (depth < max_depth && pc >= valid_pc) {
33
+ callchain[depth++] = pc;
34
+
35
+ if (pc >= jit_min_address && pc < jit_max_address) {
36
+ break;
37
+ }
38
+
39
+ // Check if the next frame is below on the current stack
40
+ if (fp <= prev_fp || fp >= prev_fp + 0x40000) {
41
+ break;
42
+ }
43
+
44
+ prev_fp = fp;
45
+ pc = ((const void**)fp)[1];
46
+ fp = ((uintptr_t*)fp)[0];
47
+ }
48
+
49
+ return depth;
50
+ }
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright 2017 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 _ENGINE_H
18
+ #define _ENGINE_H
19
+
20
+ #include "arguments.h"
21
+
22
+
23
+ class Engine {
24
+ public:
25
+ virtual const char* name() = 0;
26
+ virtual const char* units() = 0;
27
+
28
+ virtual Error start(Arguments& args) = 0;
29
+ virtual void stop() = 0;
30
+
31
+ virtual void onThreadStart() {}
32
+ virtual void onThreadEnd() {}
33
+
34
+ virtual int getNativeTrace(void* ucontext, int tid, const void** callchain, int max_depth,
35
+ const void* jit_min_address, const void* jit_max_address);
36
+ };
37
+
38
+ #endif // _ENGINE_H