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
@@ -0,0 +1,53 @@
|
|
1
|
+
cmake_minimum_required(VERSION 3.13)
|
2
|
+
project(test)
|
3
|
+
|
4
|
+
# specify the C++ standard
|
5
|
+
set(CMAKE_CXX_STANDARD 11)
|
6
|
+
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
7
|
+
# set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/FindGMock.cmake)
|
8
|
+
|
9
|
+
include(FetchContent)
|
10
|
+
FetchContent_Declare(
|
11
|
+
googletest
|
12
|
+
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
|
13
|
+
# URL https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip
|
14
|
+
)
|
15
|
+
|
16
|
+
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
17
|
+
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
18
|
+
FetchContent_MakeAvailable(googletest)
|
19
|
+
|
20
|
+
include_directories(
|
21
|
+
${gtest_SOURCE_DIR}/include
|
22
|
+
../src/
|
23
|
+
$ENV{RUBY_INC_DIR}
|
24
|
+
$ENV{RUBY_INC_DIR}/x86_64-linux/
|
25
|
+
)
|
26
|
+
|
27
|
+
link_directories(
|
28
|
+
# /usr/lib/
|
29
|
+
$ENV{RUBY_PREFIX}/lib/
|
30
|
+
../../../lib/
|
31
|
+
../lib
|
32
|
+
)
|
33
|
+
|
34
|
+
enable_testing()
|
35
|
+
set (sources
|
36
|
+
test_main.cc
|
37
|
+
frames_test.cc
|
38
|
+
profiling_test.cc
|
39
|
+
)
|
40
|
+
|
41
|
+
## Link runTests with what we want to test and the GTest and pthread library
|
42
|
+
add_executable(runTests ${sources})
|
43
|
+
target_link_libraries(runTests
|
44
|
+
# ${GTEST_LIBRARIES}
|
45
|
+
gtest
|
46
|
+
appoptics_apm.so
|
47
|
+
liboboe.so
|
48
|
+
libruby.so
|
49
|
+
pthread
|
50
|
+
)
|
51
|
+
|
52
|
+
include(GoogleTest)
|
53
|
+
gtest_discover_tests(runTests)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# This content copied from
|
2
|
+
# https://git.simply-life.net/simply-life.net/talltower/-/blob/639293a366da43eb94a72d2e7596242314c9809c/cmake/FindGMock.cmake
|
3
|
+
|
4
|
+
|
5
|
+
# Try to find GMock
|
6
|
+
find_package(GTest)
|
7
|
+
|
8
|
+
# the following issues a warning, but it works nonetheless
|
9
|
+
find_package(PkgConfig)
|
10
|
+
pkg_check_modules(PC_GMOCK QUIET gmock)
|
11
|
+
set(GMOCK_DEFINITIONS ${PC_GMOCK_CFLAGS_OTHER})
|
12
|
+
|
13
|
+
find_path(GMOCK_INCLUDE_DIR gmock.h
|
14
|
+
HINTS ${PC_GMOCK_INCLUDEDIR} ${PC_GMOCK_INCLUDE_DIRS}
|
15
|
+
PATH_SUFFIXES gmock)
|
16
|
+
|
17
|
+
find_library(GMOCK_LIBRARY NAMES gmock libgmock
|
18
|
+
HINTS ${PC_GMOCK_LIBDIR} ${PC_GMOCK_LIBRARY_DIRS} )
|
19
|
+
|
20
|
+
find_library(GMOCK_MAIN_LIBRARY NAMES gmock_main libgmock_main
|
21
|
+
HINTS ${PC_GMOCK_LIBDIR} ${PC_GMOCK_LIBRARY_DIRS} )
|
22
|
+
|
23
|
+
include(FindPackageHandleStandardArgs)
|
24
|
+
# handle the QUIETLY and REQUIRED arguments and set GMOCK_FOUND to TRUE
|
25
|
+
# if all listed variables are TRUE
|
26
|
+
find_package_handle_standard_args(GMock DEFAULT_MSG
|
27
|
+
GMOCK_LIBRARY GMOCK_INCLUDE_DIR GTEST_FOUND)
|
28
|
+
|
29
|
+
mark_as_advanced(GMOCK_INCLUDE_DIR GMOCK_LIBRARY GMOCK_MAIN_LIBRARY)
|
30
|
+
|
31
|
+
set(GMOCK_LIBRARIES ${GMOCK_LIBRARY} )
|
32
|
+
set(GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR} )
|
33
|
+
set(GMOCK_MAIN_LIBRARIES ${GMOCK_MAIN_LIBRARY} )
|
34
|
+
|
35
|
+
if (NOT TARGET GMock)
|
36
|
+
add_library(GMock IMPORTED SHARED)
|
37
|
+
set_property(TARGET GMock PROPERTY IMPORTED_LOCATION ${GMOCK_LIBRARY})
|
38
|
+
set_property(TARGET GMock PROPERTY INTERFACE_INCLUDE_DIRECTORY ${GMOCK_INCLUDE_DIR})
|
39
|
+
|
40
|
+
add_library(GMockMain IMPORTED SHARED)
|
41
|
+
set_property(TARGET GMockMain PROPERTY IMPORTED_LOCATION ${GMOCK_MAIN_LIBRARY})
|
42
|
+
set_property(TARGET GMockMain PROPERTY INTERFACE_LINK_LIBRARIES GMock GTest)
|
43
|
+
endif()
|
@@ -0,0 +1,56 @@
|
|
1
|
+
C-code tests:
|
2
|
+
|
3
|
+
CMakeLists.txt includes downloading and compiling googletest if necessary
|
4
|
+
|
5
|
+
In the ext/oboe_metal/test directory:
|
6
|
+
|
7
|
+
Set an environment variable for the current path:
|
8
|
+
```
|
9
|
+
export TEST_DIR=`pwd`
|
10
|
+
```
|
11
|
+
|
12
|
+
Every time the ruby version changes the appoptics_apm gem needs to be
|
13
|
+
re-installed or its c++-code recompiled and relinked
|
14
|
+
|
15
|
+
These environment variables need to be set every time the ruby version is set:
|
16
|
+
```
|
17
|
+
export RUBY_INC_DIR=$(ruby ruby_inc_dir.rb)
|
18
|
+
export RUBY_PREFIX=$(ruby ruby_prefix.rb)
|
19
|
+
```
|
20
|
+
|
21
|
+
create the Makefile (needs to be remade when the ruby version changes)
|
22
|
+
```
|
23
|
+
cmake -S . -B build
|
24
|
+
```
|
25
|
+
build
|
26
|
+
```
|
27
|
+
cmake --build build
|
28
|
+
```
|
29
|
+
run
|
30
|
+
```
|
31
|
+
cd build && ctest && cd -
|
32
|
+
```
|
33
|
+
|
34
|
+
Most testing of profiling is done via Ruby integration tests
|
35
|
+
|
36
|
+
For example logging is tested in Ruby tests that verify the different
|
37
|
+
KVs and values in the resulting traces, using the same approach as
|
38
|
+
for traces without profiling.
|
39
|
+
|
40
|
+
Gotchas:
|
41
|
+
|
42
|
+
- In alpine the `ruby/config.h` file is in an architecture specific folder and needs
|
43
|
+
to be symlinked to the location set via RUBY_INC_DIR (see: Dockerfile_alpine)
|
44
|
+
|
45
|
+
TODO:
|
46
|
+
|
47
|
+
- write a script for this
|
48
|
+
|
49
|
+
```
|
50
|
+
export TEST_DIR=`pwd`
|
51
|
+
export RUBY_INC_DIR=$(ruby ruby_inc_dir.rb)
|
52
|
+
export RUBY_PREFIX=$(ruby ruby_prefix.rb)
|
53
|
+
cmake -S . -B build
|
54
|
+
cmake --build build
|
55
|
+
cd build && ctest && cd -
|
56
|
+
```
|
@@ -0,0 +1,164 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
#include <string.h>
|
4
|
+
|
5
|
+
#include <algorithm>
|
6
|
+
|
7
|
+
#include "../src/profiling.h"
|
8
|
+
#include "../src/frames.h"
|
9
|
+
#include "gtest/gtest.h"
|
10
|
+
#include "ruby/debug.h"
|
11
|
+
#include "ruby/ruby.h"
|
12
|
+
#include "test.h"
|
13
|
+
|
14
|
+
extern unordered_map<VALUE, FrameData> cached_frames;
|
15
|
+
|
16
|
+
static VALUE test_frames[BUF_SIZE];
|
17
|
+
static int test_lines[BUF_SIZE];
|
18
|
+
int test_num;
|
19
|
+
|
20
|
+
static int ruby_version;
|
21
|
+
|
22
|
+
VALUE RubyCallsFrames::c_get_frames() {
|
23
|
+
test_num = rb_profile_frames(1, sizeof(test_frames) / sizeof(VALUE), test_frames, test_lines);
|
24
|
+
return Qnil;
|
25
|
+
}
|
26
|
+
|
27
|
+
void Init_RubyCallsFrames() {
|
28
|
+
static VALUE cTest = rb_define_module("RubyCalls");
|
29
|
+
rb_define_singleton_method(cTest, "get_frames", reinterpret_cast<VALUE (*)(...)>(RubyCallsFrames::c_get_frames), 0);
|
30
|
+
|
31
|
+
VALUE result;
|
32
|
+
result = rb_eval_string("RUBY_VERSION[0].to_i");
|
33
|
+
ruby_version = NUM2INT(result);
|
34
|
+
};
|
35
|
+
|
36
|
+
TEST(Frames, reserve_cached_frames) {
|
37
|
+
// it should only reserve once used during init
|
38
|
+
// unordered_map grows automatically
|
39
|
+
cached_frames.clear();
|
40
|
+
|
41
|
+
Frames::reserve_cached_frames();
|
42
|
+
int bucket_count = cached_frames.bucket_count();
|
43
|
+
|
44
|
+
Frames::reserve_cached_frames();
|
45
|
+
EXPECT_EQ(bucket_count, cached_frames.bucket_count());
|
46
|
+
}
|
47
|
+
|
48
|
+
TEST(Frames, collect_frame_data) {
|
49
|
+
rb_eval_string("TestMe::Snapshot::all_kinds");
|
50
|
+
|
51
|
+
int num = Frames::remove_garbage(test_frames, test_num);
|
52
|
+
|
53
|
+
vector<FrameData> data;
|
54
|
+
// Ruby 3 reports a <cfunc>, before the "take_snapshot" method
|
55
|
+
// we have to adjust the index of the trace we are checking
|
56
|
+
int i = ruby_version == 2 ? 0 : 1;
|
57
|
+
Frames::collect_frame_data(test_frames, i + 1, data);
|
58
|
+
|
59
|
+
EXPECT_EQ("take_snapshot", data[i].method) << "method name incorrect";
|
60
|
+
EXPECT_EQ("TestMe::Snapshot", data[i].klass) << "klass name incorrect";
|
61
|
+
std::size_t found = data[i].file.find("ext/oboe_metal/test/ruby_test_helper.rb");
|
62
|
+
EXPECT_EQ(data[i].file.length() - 39, found)
|
63
|
+
<< "filename incorrect " << found << " " << data[i].file.length();
|
64
|
+
EXPECT_EQ(7, data[i].lineno) << "line number incorrect";
|
65
|
+
}
|
66
|
+
|
67
|
+
TEST(Frames, remove_garbage) {
|
68
|
+
// run some Ruby code and get a snapshot
|
69
|
+
rb_eval_string("TestMe::Snapshot::all_kinds");
|
70
|
+
|
71
|
+
int num = Frames::remove_garbage(test_frames, test_num);
|
72
|
+
|
73
|
+
int expected = (ruby_version == 2) ? 7 : 9;
|
74
|
+
EXPECT_EQ(expected, num)
|
75
|
+
<< "wrong number of expected frames after remove_garbage";
|
76
|
+
// check no lineno 0 frame at top
|
77
|
+
VALUE val;
|
78
|
+
int i = (ruby_version == 2) ? 0 : 1;
|
79
|
+
val = rb_profile_frame_first_lineno(test_frames[i]); // returns line number
|
80
|
+
if (RB_TYPE_P(val, T_FIXNUM)) {
|
81
|
+
EXPECT_NE(0, NUM2INT(val))
|
82
|
+
<< "the frame with linenumber 0 was not removed";
|
83
|
+
} else {
|
84
|
+
EXPECT_TRUE(false) << " ************ line number not an int **********";
|
85
|
+
}
|
86
|
+
// check no repeated frames
|
87
|
+
for (i = 0; i < num; i++)
|
88
|
+
for (int j = i + 1; j < num; j++)
|
89
|
+
EXPECT_NE(test_frames[i], test_frames[j])
|
90
|
+
<< "not all repeated frames were removed";
|
91
|
+
}
|
92
|
+
|
93
|
+
TEST(Frames, num_matching) {
|
94
|
+
VALUE a[BUF_SIZE];
|
95
|
+
VALUE b[BUF_SIZE];
|
96
|
+
|
97
|
+
int a_num = 0;
|
98
|
+
int b_num = 0;
|
99
|
+
EXPECT_EQ(0, Frames::num_matching(a, a_num, b, b_num))
|
100
|
+
<< "* empty frames array should have 0 matches";
|
101
|
+
|
102
|
+
a[0] = (VALUE)11;
|
103
|
+
a[1] = (VALUE)12;
|
104
|
+
a[2] = (VALUE)13;
|
105
|
+
b[0] = (VALUE)11;
|
106
|
+
b[1] = (VALUE)12;
|
107
|
+
b[2] = (VALUE)13;
|
108
|
+
a_num = 3;
|
109
|
+
b_num = 3;
|
110
|
+
EXPECT_EQ(3, Frames::num_matching(a, a_num, b, b_num))
|
111
|
+
<< "* equal frames array should have matched";
|
112
|
+
|
113
|
+
b[1] = (VALUE)222;
|
114
|
+
EXPECT_EQ(1, Frames::num_matching(a, a_num, b, b_num))
|
115
|
+
<< "* only one should match for same length but different content";
|
116
|
+
|
117
|
+
b[1] = (VALUE)12;
|
118
|
+
a[3] = 14;
|
119
|
+
a_num = 4;
|
120
|
+
EXPECT_EQ(0, Frames::num_matching(a, a_num, b, b_num))
|
121
|
+
<< "* different length, frames NOT matching from the end";
|
122
|
+
|
123
|
+
a[0] = 10;
|
124
|
+
a[1] = 11;
|
125
|
+
a[2] = 12;
|
126
|
+
a[3] = 13;
|
127
|
+
EXPECT_EQ(3, Frames::num_matching(a, a_num, b, b_num))
|
128
|
+
<< "* different length, frames matching from the end";
|
129
|
+
|
130
|
+
b[0] = (VALUE)18;
|
131
|
+
b[1] = (VALUE)19;
|
132
|
+
b[2] = (VALUE)11;
|
133
|
+
b[3] = (VALUE)12;
|
134
|
+
b[4] = (VALUE)13;
|
135
|
+
b_num = 5;
|
136
|
+
|
137
|
+
EXPECT_EQ(3, Frames::num_matching(a, a_num, b, b_num))
|
138
|
+
<< "* different length, frames matching from the end";
|
139
|
+
}
|
140
|
+
|
141
|
+
TEST(Frames, cached_frames) {
|
142
|
+
cached_frames.clear();
|
143
|
+
// run some Ruby code and get a snapshot
|
144
|
+
rb_eval_string("TestMe::Snapshot::all_kinds");
|
145
|
+
|
146
|
+
Frames::remove_garbage(test_frames, test_num);
|
147
|
+
|
148
|
+
// Check the expected size
|
149
|
+
int expected = (ruby_version == 2) ? 8 : 10;
|
150
|
+
EXPECT_EQ(expected, cached_frames.size());
|
151
|
+
|
152
|
+
// check that each frame is cached
|
153
|
+
for (int i = 0; i < test_num; i++)
|
154
|
+
EXPECT_EQ(1, cached_frames.count(test_frames[i]));
|
155
|
+
|
156
|
+
// repeat
|
157
|
+
rb_eval_string("TestMe::Snapshot::all_kinds");
|
158
|
+
Frames::remove_garbage(test_frames, test_num);
|
159
|
+
|
160
|
+
expected = (ruby_version == 2) ? 9 : 11;
|
161
|
+
EXPECT_EQ(expected, cached_frames.size()); // +1 for an extra main frame
|
162
|
+
for (int i = 0; i < test_num; i++)
|
163
|
+
EXPECT_EQ(1, cached_frames.count(test_frames[i]));
|
164
|
+
}
|
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
#include "../src/frames.h"
|
3
|
+
|
4
|
+
#include <string.h>
|
5
|
+
|
6
|
+
#include <algorithm>
|
7
|
+
#include <thread>
|
8
|
+
#include <array>
|
9
|
+
|
10
|
+
#include "../src/profiling.h"
|
11
|
+
#include "gtest/gtest.h"
|
12
|
+
#include "ruby/debug.h"
|
13
|
+
#include "ruby/ruby.h"
|
14
|
+
#include "test.h"
|
15
|
+
|
16
|
+
extern atomic_bool profiling_shut_down;
|
17
|
+
// extern oboe_reporter_t *cur_reporter;
|
18
|
+
|
19
|
+
// FIXME how can I access profiling_shut_down ?
|
20
|
+
TEST(Profiling, try_catch_shutdown) {
|
21
|
+
EXPECT_FALSE(profiling_shut_down);
|
22
|
+
|
23
|
+
int result;
|
24
|
+
result = Profiling::try_catch_shutdown([] {
|
25
|
+
// provoke exception
|
26
|
+
std::string ().replace (100, 1, 1, 'c');
|
27
|
+
return 0;
|
28
|
+
}, "Profiling::try_catch()");
|
29
|
+
|
30
|
+
EXPECT_NE(0, result);
|
31
|
+
EXPECT_TRUE(profiling_shut_down);
|
32
|
+
|
33
|
+
// reset global var
|
34
|
+
profiling_shut_down = false;
|
35
|
+
}
|
36
|
+
|
37
|
+
TEST(Profiling, oboe_0_profiling) {
|
38
|
+
atomic_bool atomic_a1{true};
|
39
|
+
atomic_bool atomic_a2{false};
|
40
|
+
|
41
|
+
atomic_bool running;
|
42
|
+
|
43
|
+
cout << running << endl;
|
44
|
+
cout << running.exchange(true) << endl;
|
45
|
+
cout << running.exchange(true) << endl;
|
46
|
+
|
47
|
+
// cout << "prev val " << atomic_a2.exchange(false) << endl;
|
48
|
+
// cout << atomic_a2 << endl;
|
49
|
+
// cout << "prev val " << atomic_a2.exchange(true) << endl;
|
50
|
+
// cout << atomic_a2 << endl;
|
51
|
+
// cout << "prev val " << atomic_a2.exchange(true) << endl;
|
52
|
+
// cout << atomic_a2 << endl;
|
53
|
+
// cout << "prev val " << atomic_a2.exchange(false) << endl;
|
54
|
+
// cout << atomic_a2 << endl;
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
// static bool b1{true};
|
59
|
+
// static bool b2{false};
|
60
|
+
|
61
|
+
// array<thread, 4> threads;
|
62
|
+
|
63
|
+
// for (auto& t : threads) {
|
64
|
+
// t = thread([] { Profiling::profiler_signal_handler(0, NULL, NULL); });
|
65
|
+
// }
|
66
|
+
|
67
|
+
// cout << "waiting..." << endl;
|
68
|
+
|
69
|
+
// for (auto& t : threads) {
|
70
|
+
// t.join();
|
71
|
+
// }
|
72
|
+
|
73
|
+
// cout << "Done." << endl;
|
74
|
+
|
75
|
+
|
76
|
+
// cout << atomic_a1 << ", " << b1 << endl;
|
77
|
+
// cout << atomic_a1 << ", " << b1 << ", " << atomic_a1.compare_exchange_weak(b1, false) << endl;
|
78
|
+
// cout << atomic_a1 << ", " << b1 << endl;
|
79
|
+
// cout << atomic_a2 << ", " << b2 << endl;
|
80
|
+
// cout << atomic_a2 << ", " << b2 << ", " << atomic_a2.compare_exchange_weak(b2, true) << endl;
|
81
|
+
// cout << atomic_a2 << ", " << b2 << endl;
|
82
|
+
// cout << endl;
|
83
|
+
|
84
|
+
// cout << atomic_a1 << ", " << b1 << endl;
|
85
|
+
// cout << atomic_a1 << ", " << b1 << ", " << atomic_a1.compare_exchange_weak(b1, false) << endl;
|
86
|
+
// cout << atomic_a1 << ", " << b1 << endl;
|
87
|
+
// cout << atomic_a2 << ", " << b2 << endl;
|
88
|
+
// cout << atomic_a2 << ", " << b2 << ", " << atomic_a2.compare_exchange_weak(b2, true) << endl;
|
89
|
+
// cout << atomic_a2 << ", " << b2 << endl;
|
90
|
+
// cout << endl;
|
91
|
+
|
92
|
+
|
93
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class TestMe
|
2
|
+
class Snapshot
|
3
|
+
|
4
|
+
class << self
|
5
|
+
# !!! do not shift the definition of take_snapshot from line 7 !!!
|
6
|
+
# the line number is used to verify a test in frames_test.cc
|
7
|
+
def take_snapshot
|
8
|
+
# puts "getting frames ...."
|
9
|
+
begin
|
10
|
+
::RubyCalls::get_frames
|
11
|
+
rescue => e
|
12
|
+
puts "oops, getting frames didn't work"
|
13
|
+
puts e
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def all_kinds
|
18
|
+
begin
|
19
|
+
Teddy.new.sing do
|
20
|
+
take_snapshot
|
21
|
+
end
|
22
|
+
rescue => e
|
23
|
+
puts "Ruby call did not work"
|
24
|
+
puts e
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Teddy
|
31
|
+
|
32
|
+
attr_accessor :name
|
33
|
+
|
34
|
+
def sing
|
35
|
+
3.times do
|
36
|
+
yodel do
|
37
|
+
html_wrap("title", "Hello") { |_html| yield }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def yodel
|
45
|
+
a_proc = -> (x) { x * x; yield }
|
46
|
+
in_block(&a_proc)
|
47
|
+
end
|
48
|
+
|
49
|
+
def in_block(&block)
|
50
|
+
begin
|
51
|
+
yield 7
|
52
|
+
# puts "block called!"
|
53
|
+
rescue => e
|
54
|
+
puts "no, this should never happen"
|
55
|
+
puts e
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def html_wrap(tag, text)
|
60
|
+
html = "<#{tag}>#{text}</#{tag}>"
|
61
|
+
yield html
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|