appoptics_apm 4.12.2 → 4.13.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.
- checksums.yaml +4 -4
- data/.github/workflows/build_and_release_gem.yml +103 -0
- data/.github/workflows/build_for_packagecloud.yml +70 -0
- data/.github/workflows/docker-images.yml +47 -0
- data/.github/workflows/run_cpluplus_tests.yml +73 -0
- data/.github/workflows/run_tests.yml +168 -0
- data/.github/workflows/scripts/test_install.rb +23 -0
- data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
- data/.github/workflows/test_on_4_linux.yml +159 -0
- data/.gitignore +17 -25
- data/.travis.yml +17 -14
- data/Gemfile +1 -25
- data/README.md +4 -6
- data/appoptics_apm.gemspec +11 -5
- data/examples/prepend.rb +13 -0
- data/examples/sdk_examples.rb +16 -0
- data/ext/oboe_metal/extconf.rb +25 -31
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/src/README.md +6 -0
- data/ext/oboe_metal/src/VERSION +2 -1
- data/ext/oboe_metal/src/frames.cc +246 -0
- data/ext/oboe_metal/src/frames.h +40 -0
- data/ext/oboe_metal/src/init_appoptics_apm.cc +5 -4
- data/ext/oboe_metal/src/logging.cc +95 -0
- data/ext/oboe_metal/src/logging.h +35 -0
- data/ext/oboe_metal/src/oboe.h +8 -5
- data/ext/oboe_metal/src/oboe_api.cpp +40 -14
- data/ext/oboe_metal/src/oboe_api.hpp +29 -8
- data/ext/oboe_metal/src/oboe_debug.h +1 -0
- data/ext/oboe_metal/src/oboe_swig_wrap.cc +85 -21
- data/ext/oboe_metal/src/profiling.cc +435 -0
- data/ext/oboe_metal/src/profiling.h +78 -0
- data/ext/oboe_metal/test/CMakeLists.txt +53 -0
- data/ext/oboe_metal/test/FindGMock.cmake +43 -0
- data/ext/oboe_metal/test/README.md +56 -0
- data/ext/oboe_metal/test/frames_test.cc +164 -0
- data/ext/oboe_metal/test/profiling_test.cc +93 -0
- data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
- data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
- data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
- data/ext/oboe_metal/test/test.h +11 -0
- data/ext/oboe_metal/test/test_main.cc +32 -0
- data/lib/appoptics_apm/api/metrics.rb +3 -0
- data/lib/appoptics_apm/base.rb +1 -1
- data/lib/appoptics_apm/config.rb +11 -2
- data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +7 -1
- data/lib/appoptics_apm/inst/rack.rb +13 -6
- data/lib/appoptics_apm/inst/redis.rb +1 -2
- data/lib/appoptics_apm/noop/context.rb +3 -0
- data/lib/appoptics_apm/noop/metadata.rb +4 -1
- data/lib/appoptics_apm/noop/profiling.rb +21 -0
- data/lib/appoptics_apm/oboe_init_options.rb +26 -22
- data/lib/appoptics_apm/support/profiling.rb +18 -0
- data/lib/appoptics_apm/support/transaction_metrics.rb +1 -1
- data/lib/appoptics_apm/support/transaction_settings.rb +2 -2
- data/lib/appoptics_apm/support/x_trace_options.rb +2 -2
- data/lib/appoptics_apm/support_report.rb +2 -2
- data/lib/appoptics_apm/test.rb +4 -3
- data/lib/appoptics_apm/util.rb +1 -1
- data/lib/appoptics_apm/version.rb +3 -3
- data/lib/appoptics_apm/xtrace.rb +1 -1
- data/lib/appoptics_apm.rb +3 -1
- data/lib/oboe_metal.rb +2 -2
- data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +24 -0
- data/log/.keep +0 -0
- metadata +46 -16
- data/.travis/bundle.sh +0 -9
data/ext/oboe_metal/extconf.rb
CHANGED
@@ -22,14 +22,13 @@ ext_dir = File.expand_path(File.dirname(__FILE__))
|
|
22
22
|
|
23
23
|
# Check if we're running in JRuby
|
24
24
|
jruby = defined?(JRUBY_VERSION) ? true : false
|
25
|
-
|
26
25
|
# Set the mkmf lib paths so we have no issues linking to
|
27
26
|
# the AppOpticsAPM libs.
|
28
27
|
ao_lib_dir = File.join(ext_dir, 'lib')
|
29
28
|
ao_include = File.join(ext_dir, 'src')
|
30
29
|
|
31
30
|
# Download the appropriate liboboe from S3(via rake for testing) or files.appoptics.com (production)
|
32
|
-
version = File.read(File.join(ao_include, 'VERSION')).
|
31
|
+
version = File.read(File.join(ao_include, 'VERSION')).strip
|
33
32
|
if ENV['APPOPTICS_FROM_S3'].to_s.downcase == 'true'
|
34
33
|
ao_path = File.join('https://rc-files-t2.s3-us-west-2.amazonaws.com/c-lib/', version)
|
35
34
|
puts 'Fetching c-lib from S3'
|
@@ -39,12 +38,7 @@ end
|
|
39
38
|
|
40
39
|
ao_arch = 'x86_64'
|
41
40
|
if File.exist?('/etc/alpine-release')
|
42
|
-
|
43
|
-
if RUBY_VERSION < '2.5.0'
|
44
|
-
version = open('/etc/alpine-release').read.chomp
|
45
|
-
else
|
46
|
-
version = URI.open('/etc/alpine-release').read.chomp
|
47
|
-
end
|
41
|
+
version = File.read('/etc/alpine-release').strip
|
48
42
|
|
49
43
|
ao_arch =
|
50
44
|
if Gem::Version.new(version) < Gem::Version.new('3.9')
|
@@ -56,34 +50,31 @@ end
|
|
56
50
|
|
57
51
|
ao_clib = "liboboe-1.0-#{ao_arch}.so.0.0.0"
|
58
52
|
ao_item = File.join(ao_path, ao_clib)
|
59
|
-
|
53
|
+
ao_checksum_file = File.join(ao_lib_dir, "#{ao_clib}.sha256")
|
60
54
|
clib = File.join(ao_lib_dir, ao_clib)
|
61
55
|
|
62
56
|
retries = 3
|
63
57
|
success = false
|
64
58
|
while retries > 0
|
65
59
|
begin
|
66
|
-
|
67
|
-
if RUBY_VERSION < '2.5.0'
|
68
|
-
download = open(ao_item, 'rb')
|
69
|
-
checksum = open(ao_checksum_item, 'r').read.chomp
|
70
|
-
else
|
71
|
-
download = URI.open(ao_item, 'rb')
|
72
|
-
checksum = URI.open(ao_checksum_item, 'r').read.chomp
|
73
|
-
end
|
60
|
+
download = RUBY_VERSION < '2.5.0' ? open(ao_item, 'rb') : URI.open(ao_item, 'rb')
|
74
61
|
IO.copy_stream(download, clib)
|
62
|
+
|
75
63
|
clib_checksum = Digest::SHA256.file(clib).hexdigest
|
76
64
|
download.close
|
65
|
+
checksum = File.read(ao_checksum_file).strip
|
77
66
|
|
78
|
-
#
|
67
|
+
# unfortunately these messages only show if the install command is run
|
68
|
+
# with the `--verbose` flag
|
79
69
|
if clib_checksum != checksum
|
80
70
|
$stderr.puts '== ERROR ================================================================='
|
81
|
-
$stderr.puts 'Checksum Verification failed for the c-extension of the appoptics_apm gem
|
82
|
-
$stderr.puts '
|
83
|
-
$stderr.puts
|
71
|
+
$stderr.puts 'Checksum Verification failed for the c-extension of the appoptics_apm gem'
|
72
|
+
$stderr.puts 'Installation cannot continue'
|
73
|
+
$stderr.puts "\nChecksum packaged with gem: #{checksum}"
|
74
|
+
$stderr.puts "Checksum calculated from lib: #{clib_checksum}"
|
75
|
+
$stderr.puts 'Contact technicalsupport@solarwinds.com if the problem persists'
|
84
76
|
$stderr.puts '=========================================================================='
|
85
|
-
|
86
|
-
retries = 0
|
77
|
+
exit 1
|
87
78
|
else
|
88
79
|
success = true
|
89
80
|
retries = 0
|
@@ -95,7 +86,7 @@ while retries > 0
|
|
95
86
|
$stderr.puts '== ERROR =========================================================='
|
96
87
|
$stderr.puts 'Download of the c-extension for the appoptics_apm gem failed.'
|
97
88
|
$stderr.puts 'appoptics_apm will not instrument the code. No tracing will occur.'
|
98
|
-
$stderr.puts 'Contact
|
89
|
+
$stderr.puts 'Contact technicalsupport@solarwinds.com if the problem persists.'
|
99
90
|
$stderr.puts "error: #{ao_item}\n#{e.message}"
|
100
91
|
$stderr.puts '==================================================================='
|
101
92
|
create_makefile('oboe_noop', 'noop')
|
@@ -128,17 +119,20 @@ if success
|
|
128
119
|
$CFLAGS << " #{ENV['CFLAGS']}"
|
129
120
|
# $CPPFLAGS << " #{ENV['CPPFLAGS']} -std=c++11"
|
130
121
|
# TODO for debugging: -pg -gdwarf-2, remove for production
|
131
|
-
#
|
132
|
-
$CPPFLAGS << " #{ENV['CPPFLAGS']} -std=c++11 -I$$ORIGIN/../ext/oboe_metal/include"
|
122
|
+
# -pg does not work on alpine https://www.openwall.com/lists/musl/2014/11/05/2
|
123
|
+
$CPPFLAGS << " #{ENV['CPPFLAGS']} -std=c++11 -gdwarf-2 -I$$ORIGIN/../ext/oboe_metal/include -I$$ORIGIN/../ext/oboe_metal/src"
|
124
|
+
# $CPPFLAGS << " #{ENV['CPPFLAGS']} -std=c++11 -I$$ORIGIN/../ext/oboe_metal/include"
|
133
125
|
$LIBS << " #{ENV['LIBS']}"
|
134
|
-
|
135
|
-
#
|
126
|
+
|
127
|
+
# use "z,defs" to see what happens during linking
|
128
|
+
# $LDFLAGS << " #{ENV['LDFLAGS']} '-Wl,-rpath=$$ORIGIN/../ext/oboe_metal/lib,-z,defs' -lrt"
|
129
|
+
$LDFLAGS << " #{ENV['LDFLAGS']} '-Wl,-rpath=$$ORIGIN/../ext/oboe_metal/lib' -lrt"
|
136
130
|
$CXXFLAGS += " -std=c++11 "
|
137
131
|
|
138
132
|
# ____ include debug info, comment out when not debugging
|
139
133
|
# ____ -pg -> profiling info for gprof
|
140
|
-
|
141
|
-
|
134
|
+
CONFIG["debugflags"] = "-ggdb3 "
|
135
|
+
CONFIG["optflags"] = "-O0"
|
142
136
|
|
143
137
|
create_makefile('libappoptics_apm', 'src')
|
144
138
|
|
@@ -150,7 +144,7 @@ if success
|
|
150
144
|
else
|
151
145
|
$stderr.puts 'Could not find a matching c-library. No tracing will occur.'
|
152
146
|
end
|
153
|
-
$stderr.puts 'Contact
|
147
|
+
$stderr.puts 'Contact technicalsupport@solarwinds.com if the problem persists.'
|
154
148
|
$stderr.puts '=================================================================='
|
155
149
|
create_makefile('oboe_noop', 'noop')
|
156
150
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
af7d764a88cec323940fc6040947f2dcf8041c389744bdfc46b7f2fe0a465dab
|
@@ -0,0 +1 @@
|
|
1
|
+
092e232d0e1aa1826b77c98d96f7bb2db39058c9bec3e2c0387cc6fb51b5b83c
|
data/ext/oboe_metal/src/VERSION
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
10.
|
1
|
+
10.2.0
|
2
|
+
|
@@ -0,0 +1,246 @@
|
|
1
|
+
// Copyright (c) 2021 SolarWinds, LLC.
|
2
|
+
// All rights reserved.
|
3
|
+
|
4
|
+
#include "frames.h"
|
5
|
+
|
6
|
+
using namespace std;
|
7
|
+
|
8
|
+
unordered_map<VALUE, FrameData> cached_frames;
|
9
|
+
|
10
|
+
// in theory the mutex is not needed, because Ruby does not context switch
|
11
|
+
// while executing a foreign function, but will this always hold true?
|
12
|
+
mutex cached_frames_mutex;
|
13
|
+
|
14
|
+
void Frames::reserve_cached_frames() {
|
15
|
+
lock_guard<mutex> guard(cached_frames_mutex);
|
16
|
+
// unordered_maps grow automatically, but it starts at 1 and then
|
17
|
+
// doubles when it is full, so lets avoid the warmup
|
18
|
+
cached_frames.reserve(500); // it will round to a prime number: 503
|
19
|
+
}
|
20
|
+
|
21
|
+
void Frames::clear_cached_frames() {
|
22
|
+
lock_guard<mutex> guard(cached_frames_mutex);
|
23
|
+
// unordered_maps grow automatically, but it starts at 1 and then
|
24
|
+
// doubles when it is full, so lets avoid the warmup
|
25
|
+
cached_frames.clear();
|
26
|
+
}
|
27
|
+
|
28
|
+
// this is a private function
|
29
|
+
int Frames::cache_frame(VALUE frame) {
|
30
|
+
VALUE val;
|
31
|
+
FrameData data;
|
32
|
+
|
33
|
+
// only cache it if it does not exist
|
34
|
+
if (cached_frames.count(frame) == 0) {
|
35
|
+
val = rb_profile_frame_label(frame); // returns method or block
|
36
|
+
if (RB_TYPE_P(val, T_STRING))
|
37
|
+
data.method = RSTRING_PTR(val);
|
38
|
+
|
39
|
+
if (data.method.rfind("block ", 0) == 0) {
|
40
|
+
// we don't need more info if it is a block
|
41
|
+
// we ignore block level info because they make things messy
|
42
|
+
lock_guard<mutex> guard(cached_frames_mutex);
|
43
|
+
cached_frames.insert({frame, data});
|
44
|
+
return 0;
|
45
|
+
}
|
46
|
+
|
47
|
+
val = rb_profile_frame_classpath(frame); // returns class or nil
|
48
|
+
if (RB_TYPE_P(val, T_STRING)) data.klass = RSTRING_PTR(val);
|
49
|
+
|
50
|
+
val = rb_profile_frame_absolute_path(frame); // returns file, use rb_profile_frame_path() if nil
|
51
|
+
if (!RB_TYPE_P(val, T_STRING)) val = rb_profile_frame_path(frame);
|
52
|
+
if (RB_TYPE_P(val, T_STRING)) data.file = RSTRING_PTR(val);
|
53
|
+
|
54
|
+
// Ruby 3 reports <cfunc>, but the linenumbers are bogus
|
55
|
+
// the default line number is 0
|
56
|
+
if (!data.file.compare("<cfunc>") == 0) {
|
57
|
+
val = rb_profile_frame_first_lineno(frame); // returns line number
|
58
|
+
if (RB_TYPE_P(val, T_FIXNUM)) {
|
59
|
+
data.lineno = NUM2INT(val);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
lock_guard<mutex> guard(cached_frames_mutex);
|
63
|
+
cached_frames.insert({frame, data});
|
64
|
+
}
|
65
|
+
return 0;
|
66
|
+
}
|
67
|
+
|
68
|
+
// all frames in frames_buffer must be in cached_frames
|
69
|
+
// before calling this function
|
70
|
+
// we are saving the check for better performance
|
71
|
+
int Frames::collect_frame_data(VALUE *frames_buffer, int num, vector<FrameData> &frame_data) {
|
72
|
+
if (num == 1) {
|
73
|
+
if (frames_buffer[0] == PR_IN_GC) {
|
74
|
+
FrameData data;
|
75
|
+
data.method = "GARBAGE COLLECTION";
|
76
|
+
frame_data.push_back(data);
|
77
|
+
return 0;
|
78
|
+
} else if (frames_buffer[0] == PR_OTHER_THREAD) {
|
79
|
+
FrameData data;
|
80
|
+
data.method = "OTHER THREADS";
|
81
|
+
frame_data.push_back(data);
|
82
|
+
return 0;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
for (int i = 0; i < num; i++) {
|
87
|
+
VALUE frame = frames_buffer[i];
|
88
|
+
frame_data.push_back(cached_frames[frame]);
|
89
|
+
}
|
90
|
+
return 0;
|
91
|
+
}
|
92
|
+
|
93
|
+
/////
|
94
|
+
// For the sake of efficiency this function filters uninteresting frames and
|
95
|
+
// does the caching of frames at the same time
|
96
|
+
//
|
97
|
+
// in-place removal of
|
98
|
+
// - frames with line number == 0
|
99
|
+
// - all but last of repeated frames
|
100
|
+
// - "block" frames (they are confusing) <- revisit
|
101
|
+
// and cache uncached frames
|
102
|
+
int Frames::remove_garbage(VALUE *frames_buffer, int num) {
|
103
|
+
if (num == 1 && (frames_buffer[0] == PR_OTHER_THREAD || frames_buffer[0] == PR_IN_GC))
|
104
|
+
return 1;
|
105
|
+
|
106
|
+
// TODO decide what to do with <cfunc> frames in Ruby 3
|
107
|
+
|
108
|
+
// 1) ignore top frames where the line number is 0
|
109
|
+
// does that mean there is no line number???
|
110
|
+
bool found = true;
|
111
|
+
|
112
|
+
while (found && num > 0) {
|
113
|
+
if (cached_frames.count(frames_buffer[num - 1]) == 1) {
|
114
|
+
found = (cached_frames[frames_buffer[num - 1]].lineno == 0);
|
115
|
+
if (found) num--;
|
116
|
+
} else {
|
117
|
+
VALUE val = rb_profile_frame_first_lineno(frames_buffer[num - 1]);
|
118
|
+
found = (!RB_TYPE_P(val, T_FIXNUM) || !NUM2INT(val));
|
119
|
+
if (found) {
|
120
|
+
lock_guard<mutex> guard(cached_frames_mutex);
|
121
|
+
cached_frames[frames_buffer[num - 1]].lineno = 0;
|
122
|
+
num--;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
// 2) remove all repeated frames, keep the last one
|
128
|
+
int count = 0;
|
129
|
+
int k = 0;
|
130
|
+
found = false;
|
131
|
+
while (count < num - k) {
|
132
|
+
// is this frame repeated ahead?
|
133
|
+
// if so we will replace it with the next one in line
|
134
|
+
for (int j = count + k + 1; j < num; j++) {
|
135
|
+
if (frames_buffer[count] == frames_buffer[j]) {
|
136
|
+
found = true;
|
137
|
+
break;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
if (found) {
|
142
|
+
// if we found this frame again later in the snapshot
|
143
|
+
// we are going to override this one
|
144
|
+
// but not if this is going beyond the boundary
|
145
|
+
k++;
|
146
|
+
if (count + k < num - 1) frames_buffer[count] = frames_buffer[count + k];
|
147
|
+
} else {
|
148
|
+
count++;
|
149
|
+
frames_buffer[count] = frames_buffer[count + k];
|
150
|
+
}
|
151
|
+
found = false;
|
152
|
+
}
|
153
|
+
|
154
|
+
// 3) remove "block" frames, they are reported inconsistently and mess up
|
155
|
+
// the profile in the dashboard
|
156
|
+
// 4) while we are at it we also cache all the frames
|
157
|
+
// these 2 are combined so we don't have to run this loop twice
|
158
|
+
num = count;
|
159
|
+
count = 0, k = 0;
|
160
|
+
string method;
|
161
|
+
|
162
|
+
while (count < num - k) {
|
163
|
+
frames_buffer[count] = frames_buffer[count + k];
|
164
|
+
cache_frame(frames_buffer[count]);
|
165
|
+
method = cached_frames[frames_buffer[count]].method;
|
166
|
+
|
167
|
+
// TODO revisit need to remove block frames, they only appear when the Ruby
|
168
|
+
// ____ script is not started with a method and has blocks outside of the
|
169
|
+
// ____ methods called and sometimes inside of rack
|
170
|
+
if (method.rfind("block ", 0) == 0) {
|
171
|
+
k++;
|
172
|
+
} else {
|
173
|
+
count++;
|
174
|
+
}
|
175
|
+
}
|
176
|
+
return count;
|
177
|
+
}
|
178
|
+
|
179
|
+
// returns the number of the matching frames
|
180
|
+
int Frames::num_matching(VALUE *frames_buffer, int num,
|
181
|
+
VALUE *prev_frames_buffer, int prev_num) {
|
182
|
+
int i;
|
183
|
+
int min = std::min(num, prev_num);
|
184
|
+
|
185
|
+
for (i = 0; i < min; i++) {
|
186
|
+
// we have to start from the "top"
|
187
|
+
if (frames_buffer[num - 1 - i] != prev_frames_buffer[prev_num - 1 - i]) {
|
188
|
+
return i;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
return i;
|
192
|
+
}
|
193
|
+
|
194
|
+
/////////////////////// DEBUGGING HELPER FUNCTIONS /////////////////////////////
|
195
|
+
// helper function to print frame from ruby pointers to frame
|
196
|
+
void Frames::print_raw_frame_info(VALUE frame) {
|
197
|
+
if (frame == PR_IN_GC || frame == PR_OTHER_THREAD) {
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
|
201
|
+
VALUE val;
|
202
|
+
int lineno;
|
203
|
+
string file, klass, method;
|
204
|
+
|
205
|
+
val = rb_profile_frame_first_lineno(frame); // returns line number
|
206
|
+
if (RB_TYPE_P(val, T_FIXNUM)) lineno = NUM2INT(val);
|
207
|
+
|
208
|
+
val = rb_profile_frame_classpath(frame); // returns class or nil
|
209
|
+
if (RB_TYPE_P(val, T_STRING)) klass = RSTRING_PTR(val);
|
210
|
+
|
211
|
+
val = rb_profile_frame_absolute_path(frame); // returns file, use rb_profile_frame_path() if nil
|
212
|
+
if (!RB_TYPE_P(val, T_STRING)) val = rb_profile_frame_path(frame);
|
213
|
+
if (RB_TYPE_P(val, T_STRING)) file = RSTRING_PTR(val);
|
214
|
+
|
215
|
+
val = rb_profile_frame_label(frame); // returns method or block
|
216
|
+
if (RB_TYPE_P(val, T_STRING)) method = RSTRING_PTR(val);
|
217
|
+
|
218
|
+
cout << " " << frame << " "
|
219
|
+
<< "L: " << lineno << " "
|
220
|
+
<< "F: " << file << " "
|
221
|
+
<< "C: " << klass << " "
|
222
|
+
<< "M: " << method << endl;
|
223
|
+
}
|
224
|
+
|
225
|
+
void Frames::print_all_raw_frames(VALUE *frames_buffer, int num) {
|
226
|
+
for (int i = 0; i < num; i++) {
|
227
|
+
print_raw_frame_info(frames_buffer[i]);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
// helper function to print frame info
|
232
|
+
void Frames::print_frame_info(VALUE frame) {
|
233
|
+
if (cached_frames.find(frame) != cached_frames.end())
|
234
|
+
std::cout << cached_frames[frame].lineno << " "
|
235
|
+
<< cached_frames[frame].file << " "
|
236
|
+
<< cached_frames[frame].klass << " "
|
237
|
+
<< cached_frames[frame].method << std::endl;
|
238
|
+
}
|
239
|
+
|
240
|
+
// helper function for printing the cached frames
|
241
|
+
void Frames::print_cached_frames() {
|
242
|
+
std::cout << "cached_frames contains:" << endl;
|
243
|
+
for (auto it = cached_frames.cbegin(); it != cached_frames.cend(); ++it)
|
244
|
+
std::cout << " " << it->first << " - " << it->second.method << ":" << it->second.lineno << endl; // cannot modify *it
|
245
|
+
std::cout << std::endl;
|
246
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
// Copyright (c) 2021 SolarWinds, LLC.
|
2
|
+
// All rights reserved.
|
3
|
+
|
4
|
+
#ifndef FRAMES_H
|
5
|
+
#define FRAMES_H
|
6
|
+
|
7
|
+
#include <vector>
|
8
|
+
|
9
|
+
#include <mutex>
|
10
|
+
#include <unordered_map>
|
11
|
+
|
12
|
+
#include <ruby/ruby.h>
|
13
|
+
#include <ruby/debug.h>
|
14
|
+
|
15
|
+
#include "profiling.h"
|
16
|
+
#include "oboe_api.hpp"
|
17
|
+
|
18
|
+
using namespace std;
|
19
|
+
|
20
|
+
class Frames {
|
21
|
+
public:
|
22
|
+
static void clear_cached_frames();
|
23
|
+
static void reserve_cached_frames();
|
24
|
+
static int collect_frame_data(VALUE *frames_buffer, int num, vector<FrameData> &frame_data);
|
25
|
+
static int remove_garbage(VALUE *frames_buffer, int num);
|
26
|
+
static int num_matching(VALUE *frames_buffer, int num,
|
27
|
+
VALUE *prev_frames_buffer, int prev_num);
|
28
|
+
|
29
|
+
private:
|
30
|
+
static int cache_frame(VALUE frame);
|
31
|
+
|
32
|
+
// Debugging helper functions
|
33
|
+
public:
|
34
|
+
static void print_raw_frame_info(VALUE frame);
|
35
|
+
static void print_all_raw_frames(VALUE *frames_buffer, int num);
|
36
|
+
static void print_frame_info(VALUE frame);
|
37
|
+
static void print_cached_frames();
|
38
|
+
};
|
39
|
+
|
40
|
+
#endif //FRAMES_H
|
@@ -1,3 +1,6 @@
|
|
1
|
+
// Copyright (c) 2019 SolarWinds, LLC.
|
2
|
+
// All rights reserved.
|
3
|
+
|
1
4
|
#include <iostream>
|
2
5
|
|
3
6
|
#ifdef __cplusplus
|
@@ -6,13 +9,11 @@ extern "C" {
|
|
6
9
|
|
7
10
|
void Init_oboe_metal(void);
|
8
11
|
|
9
|
-
|
12
|
+
void Init_profiling(void);
|
10
13
|
|
11
14
|
void Init_libappoptics_apm() {
|
12
15
|
Init_oboe_metal();
|
13
|
-
|
14
|
-
// Init_profiling();
|
15
|
-
// std::cout << "*** profiling intitialized ***" << std::endl;
|
16
|
+
Init_profiling();
|
16
17
|
}
|
17
18
|
|
18
19
|
#ifdef __cplusplus
|