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,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