gvltools 0.2.0 → 0.4.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/.rubocop.yml +9 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -3
- data/Gemfile.lock +22 -17
- data/README.md +20 -0
- data/ext/gvltools/extconf.rb +2 -1
- data/ext/gvltools/instrumentation.c +121 -28
- data/gvltools.gemspec +0 -2
- data/lib/gvltools/version.rb +1 -1
- data/lib/gvltools.rb +20 -1
- metadata +4 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5b6af92049391130d2248c5d14ec3c93e859f4ab92d6af9842e2a88c289b3e50
|
|
4
|
+
data.tar.gz: 4681a32780409d180b6727a791cdc122a9a03d21eba7f28f2070c8de6e52ddb1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 005a90c02765c716c97f9165f777dd6b26b3853037e6c64f13e3255278db5a7c5d378855850758a7e391d9957389d18db7edb24a3658a46a5ec6105668238fa7
|
|
7
|
+
data.tar.gz: e16793a8f452f958cd0dde468c5aff337a78719485c8657bc9f5e1e91bd393b0bc1a523e56b5a1e06246c963e8661ed34707ef49e05cb15d6e94e57865c9932c
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
- Fixed compatibility with Ruby 3.3.0.
|
|
4
|
+
- Added `GVLTools::LocalTimer.for(thread)` to access another thread counter (Ruby 3.3+ only).
|
|
5
|
+
|
|
6
|
+
## [0.3.0] - 2023-04-11
|
|
7
|
+
|
|
8
|
+
- Automatically reset the `WaitingThreads` counter when enabling it (#7).
|
|
9
|
+
- Disallow resetting the `WaitingThreads` counter when it is active (#7).
|
|
10
|
+
|
|
3
11
|
## [0.2.0] - 2023-03-28
|
|
4
12
|
|
|
5
13
|
- Use C11 atomics instead of MRI's `rb_atomic_t`.
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,46 +1,51 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
gvltools (0.
|
|
4
|
+
gvltools (0.4.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
9
|
ast (2.4.2)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
json (2.7.1)
|
|
11
|
+
language_server-protocol (3.17.0.3)
|
|
12
|
+
minitest (5.21.2)
|
|
13
|
+
parallel (1.24.0)
|
|
14
|
+
parser (3.3.0.2)
|
|
13
15
|
ast (~> 2.4.1)
|
|
16
|
+
racc
|
|
17
|
+
racc (1.7.3)
|
|
14
18
|
rainbow (3.1.1)
|
|
15
19
|
rake (13.0.6)
|
|
16
20
|
rake-compiler (1.2.0)
|
|
17
21
|
rake
|
|
18
|
-
regexp_parser (2.
|
|
19
|
-
rexml (3.2.
|
|
20
|
-
rubocop (1.
|
|
22
|
+
regexp_parser (2.9.0)
|
|
23
|
+
rexml (3.2.6)
|
|
24
|
+
rubocop (1.59.0)
|
|
25
|
+
json (~> 2.3)
|
|
26
|
+
language_server-protocol (>= 3.17.0)
|
|
21
27
|
parallel (~> 1.10)
|
|
22
|
-
parser (>= 3.
|
|
28
|
+
parser (>= 3.2.2.4)
|
|
23
29
|
rainbow (>= 2.2.2, < 4.0)
|
|
24
30
|
regexp_parser (>= 1.8, < 3.0)
|
|
25
31
|
rexml (>= 3.2.5, < 4.0)
|
|
26
|
-
rubocop-ast (>= 1.
|
|
32
|
+
rubocop-ast (>= 1.30.0, < 2.0)
|
|
27
33
|
ruby-progressbar (~> 1.7)
|
|
28
|
-
unicode-display_width (>=
|
|
29
|
-
rubocop-ast (1.
|
|
30
|
-
parser (>= 3.
|
|
31
|
-
ruby-progressbar (1.
|
|
32
|
-
unicode-display_width (2.
|
|
34
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
35
|
+
rubocop-ast (1.30.0)
|
|
36
|
+
parser (>= 3.2.1.0)
|
|
37
|
+
ruby-progressbar (1.13.0)
|
|
38
|
+
unicode-display_width (2.5.0)
|
|
33
39
|
|
|
34
40
|
PLATFORMS
|
|
35
41
|
aarch64-linux
|
|
36
|
-
arm64-darwin
|
|
37
|
-
arm64-darwin-22
|
|
42
|
+
arm64-darwin
|
|
38
43
|
x86_64-linux
|
|
39
44
|
|
|
40
45
|
DEPENDENCIES
|
|
41
46
|
gvltools!
|
|
42
47
|
minitest (~> 5.0)
|
|
43
|
-
rake
|
|
48
|
+
rake
|
|
44
49
|
rake-compiler
|
|
45
50
|
rubocop (~> 1.21)
|
|
46
51
|
|
data/README.md
CHANGED
|
@@ -59,6 +59,26 @@ class GVLInstrumentationMiddleware
|
|
|
59
59
|
end
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
Starting from Ruby 3.3, a thread local timer can be accessed from another thread:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
def fibonacci(n)
|
|
66
|
+
if n < 2
|
|
67
|
+
n
|
|
68
|
+
else
|
|
69
|
+
fibonacci(n - 1) + fibonacci(n - 2)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
GVLTools::LocalTimer.enable
|
|
74
|
+
thread = Thread.new do
|
|
75
|
+
fibonacci(20)
|
|
76
|
+
end
|
|
77
|
+
thread.join(1)
|
|
78
|
+
local_timer = GVLTools::LocalTimer.for(thread)
|
|
79
|
+
local_timer.monotonic_time # => 127000
|
|
80
|
+
```
|
|
81
|
+
|
|
62
82
|
### GlobalTimer
|
|
63
83
|
|
|
64
84
|
`GlobalTimer` records the overall time spent waiting on the GVL by all threads combined.
|
data/ext/gvltools/extconf.rb
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
require "mkmf"
|
|
4
4
|
if RUBY_ENGINE == "ruby" &&
|
|
5
5
|
have_header("stdatomic.h") &&
|
|
6
|
-
have_func("rb_internal_thread_add_event_hook", ["ruby/thread.h"])
|
|
6
|
+
have_func("rb_internal_thread_add_event_hook", ["ruby/thread.h"]) # 3.1+
|
|
7
7
|
|
|
8
8
|
$CFLAGS << " -O3 -Wall "
|
|
9
|
+
have_func("rb_internal_thread_specific_get", "ruby/thread.h") # 3.3+
|
|
9
10
|
create_makefile("gvltools/instrumentation")
|
|
10
11
|
else
|
|
11
12
|
File.write("Makefile", dummy_makefile($srcdir).join)
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
typedef unsigned long long counter_t;
|
|
7
7
|
|
|
8
|
+
VALUE rb_cLocalTimer = Qnil;
|
|
9
|
+
|
|
8
10
|
// Metrics
|
|
9
11
|
static rb_internal_thread_event_hook_t *gt_hook = NULL;
|
|
10
12
|
|
|
@@ -15,6 +17,44 @@ static unsigned int enabled_mask = 0;
|
|
|
15
17
|
|
|
16
18
|
#define ENABLED(metric) (enabled_mask & (metric))
|
|
17
19
|
|
|
20
|
+
typedef struct {
|
|
21
|
+
bool was_ready;
|
|
22
|
+
_Atomic counter_t timer_total;
|
|
23
|
+
_Atomic counter_t waiting_threads_ready_generation;
|
|
24
|
+
struct timespec timer_ready_at;
|
|
25
|
+
} thread_local_state;
|
|
26
|
+
|
|
27
|
+
#ifdef HAVE_RB_INTERNAL_THREAD_SPECIFIC_GET // 3.3+
|
|
28
|
+
static int thread_storage_key = 0;
|
|
29
|
+
|
|
30
|
+
static size_t thread_local_state_memsize(const void *data) {
|
|
31
|
+
return sizeof(thread_local_state);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static const rb_data_type_t thread_local_state_type = {
|
|
35
|
+
.wrap_struct_name = "GVLTools::ThreadLocal",
|
|
36
|
+
.function = {
|
|
37
|
+
.dmark = NULL,
|
|
38
|
+
.dfree = RUBY_DEFAULT_FREE,
|
|
39
|
+
.dsize = thread_local_state_memsize,
|
|
40
|
+
},
|
|
41
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
static inline thread_local_state *GT_LOCAL_STATE(VALUE thread, bool allocate) {
|
|
45
|
+
thread_local_state *state = rb_internal_thread_specific_get(thread, thread_storage_key);
|
|
46
|
+
if (!state && allocate) {
|
|
47
|
+
VALUE wrapper = TypedData_Make_Struct(rb_cLocalTimer, thread_local_state, &thread_local_state_type, state);
|
|
48
|
+
rb_thread_local_aset(thread, rb_intern("__gvltools_local_state"), wrapper);
|
|
49
|
+
RB_GC_GUARD(wrapper);
|
|
50
|
+
rb_internal_thread_specific_set(thread, thread_storage_key, state);
|
|
51
|
+
}
|
|
52
|
+
return state;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#define GT_EVENT_LOCAL_STATE(event_data, allocate) GT_LOCAL_STATE(event_data->thread, allocate)
|
|
56
|
+
#define GT_CURRENT_THREAD_LOCAL_STATE() GT_LOCAL_STATE(rb_thread_current(), true)
|
|
57
|
+
#else
|
|
18
58
|
#if __STDC_VERSION__ >= 201112
|
|
19
59
|
#define THREAD_LOCAL_SPECIFIER _Thread_local
|
|
20
60
|
#elif defined(__GNUC__) && !defined(RB_THREAD_LOCAL_SPECIFIER_IS_UNSUPPORTED)
|
|
@@ -22,11 +62,17 @@ static unsigned int enabled_mask = 0;
|
|
|
22
62
|
#define THREAD_LOCAL_SPECIFIER __thread
|
|
23
63
|
#endif
|
|
24
64
|
|
|
65
|
+
static THREAD_LOCAL_SPECIFIER thread_local_state __thread_local_state = {0};
|
|
66
|
+
#undef THREAD_LOCAL_SPECIFIER
|
|
67
|
+
|
|
68
|
+
#define GT_LOCAL_STATE(thread) (&__thread_local_state)
|
|
69
|
+
#define GT_EVENT_LOCAL_STATE(event_data, allocate) (&__thread_local_state)
|
|
70
|
+
#define GT_CURRENT_THREAD_LOCAL_STATE() (&__thread_local_state)
|
|
71
|
+
#endif
|
|
72
|
+
|
|
25
73
|
// Common
|
|
26
74
|
#define SECONDS_TO_NANOSECONDS (1000 * 1000 * 1000)
|
|
27
75
|
|
|
28
|
-
static THREAD_LOCAL_SPECIFIER bool was_ready = 0;
|
|
29
|
-
|
|
30
76
|
static inline void gt_gettime(struct timespec *time) {
|
|
31
77
|
if (clock_gettime(CLOCK_MONOTONIC, time) == -1) {
|
|
32
78
|
rb_sys_fail("clock_gettime");
|
|
@@ -50,7 +96,7 @@ static VALUE gt_enable_metric(VALUE module, VALUE metric) {
|
|
|
50
96
|
if (!gt_hook) {
|
|
51
97
|
gt_hook = rb_internal_thread_add_event_hook(
|
|
52
98
|
gt_thread_callback,
|
|
53
|
-
RUBY_INTERNAL_THREAD_EVENT_EXITED | RUBY_INTERNAL_THREAD_EVENT_READY | RUBY_INTERNAL_THREAD_EVENT_RESUMED,
|
|
99
|
+
RUBY_INTERNAL_THREAD_EVENT_STARTED | RUBY_INTERNAL_THREAD_EVENT_EXITED | RUBY_INTERNAL_THREAD_EVENT_READY | RUBY_INTERNAL_THREAD_EVENT_RESUMED,
|
|
54
100
|
NULL
|
|
55
101
|
);
|
|
56
102
|
}
|
|
@@ -70,8 +116,6 @@ static VALUE gt_disable_metric(VALUE module, VALUE metric) {
|
|
|
70
116
|
|
|
71
117
|
// GVLTools::LocalTimer and GVLTools::GlobalTimer
|
|
72
118
|
static _Atomic counter_t global_timer_total = 0;
|
|
73
|
-
static THREAD_LOCAL_SPECIFIER counter_t local_timer_total = 0;
|
|
74
|
-
static THREAD_LOCAL_SPECIFIER struct timespec timer_ready_at = {0};
|
|
75
119
|
|
|
76
120
|
static VALUE global_timer_monotonic_time(VALUE module) {
|
|
77
121
|
return ULL2NUM(global_timer_total);
|
|
@@ -82,68 +126,106 @@ static VALUE global_timer_reset(VALUE module) {
|
|
|
82
126
|
return Qtrue;
|
|
83
127
|
}
|
|
84
128
|
|
|
85
|
-
static VALUE
|
|
86
|
-
return ULL2NUM(
|
|
129
|
+
static VALUE local_timer_m_monotonic_time(VALUE module) {
|
|
130
|
+
return ULL2NUM(GT_CURRENT_THREAD_LOCAL_STATE()->timer_total);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static VALUE local_timer_m_reset(VALUE module) {
|
|
134
|
+
GT_CURRENT_THREAD_LOCAL_STATE()->timer_total = 0;
|
|
135
|
+
return Qtrue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
#ifdef HAVE_RB_INTERNAL_THREAD_SPECIFIC_GET
|
|
139
|
+
static VALUE local_timer_for(VALUE module, VALUE thread) {
|
|
140
|
+
GT_LOCAL_STATE(thread, true);
|
|
141
|
+
return rb_thread_local_aref(thread, rb_intern("__gvltools_local_state"));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static VALUE local_timer_monotonic_time(VALUE timer) {
|
|
145
|
+
thread_local_state *state;
|
|
146
|
+
TypedData_Get_Struct(timer, thread_local_state, &thread_local_state_type, state);
|
|
147
|
+
return ULL2NUM(state->timer_total);
|
|
87
148
|
}
|
|
88
149
|
|
|
89
|
-
static VALUE local_timer_reset(VALUE
|
|
90
|
-
|
|
150
|
+
static VALUE local_timer_reset(VALUE timer) {
|
|
151
|
+
thread_local_state *state;
|
|
152
|
+
TypedData_Get_Struct(timer, thread_local_state, &thread_local_state_type, state);
|
|
153
|
+
state->timer_total = 0;
|
|
91
154
|
return Qtrue;
|
|
92
155
|
}
|
|
156
|
+
#endif
|
|
93
157
|
|
|
94
158
|
// Thread counts
|
|
95
159
|
static _Atomic counter_t waiting_threads_total = 0;
|
|
160
|
+
static _Atomic counter_t waiting_threads_current_generation = 1;
|
|
96
161
|
|
|
97
162
|
static VALUE waiting_threads_count(VALUE module) {
|
|
98
163
|
return ULL2NUM(waiting_threads_total);
|
|
99
164
|
}
|
|
100
165
|
|
|
101
166
|
static VALUE waiting_threads_reset(VALUE module) {
|
|
167
|
+
waiting_threads_current_generation++;
|
|
102
168
|
waiting_threads_total = 0;
|
|
103
169
|
return Qtrue;
|
|
104
170
|
}
|
|
105
171
|
|
|
106
172
|
// General callback
|
|
107
|
-
static void gt_reset_thread_local_state(void) {
|
|
108
|
-
// MRI can re-use native threads, so we need to reset thread local state,
|
|
109
|
-
// otherwise it will leak from one Ruby thread from another.
|
|
110
|
-
was_ready = false;
|
|
111
|
-
local_timer_total = 0;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
173
|
static void gt_thread_callback(rb_event_flag_t event, const rb_internal_thread_event_data_t *event_data, void *user_data) {
|
|
115
174
|
switch(event) {
|
|
116
|
-
case RUBY_INTERNAL_THREAD_EVENT_STARTED:
|
|
175
|
+
case RUBY_INTERNAL_THREAD_EVENT_STARTED: {
|
|
176
|
+
// The STARTED event is triggered from the parent thread with the GVL held
|
|
177
|
+
// so we can allocate the struct.
|
|
178
|
+
GT_EVENT_LOCAL_STATE(event_data, true);
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
117
181
|
case RUBY_INTERNAL_THREAD_EVENT_EXITED: {
|
|
118
|
-
|
|
182
|
+
#ifndef HAVE_RB_INTERNAL_THREAD_SPECIFIC_GET
|
|
183
|
+
thread_local_state *state = GT_EVENT_LOCAL_STATE(event_data, false);
|
|
184
|
+
if (state) {
|
|
185
|
+
// MRI can re-use native threads, so we need to reset thread local state,
|
|
186
|
+
// otherwise it will leak from one Ruby thread from another.
|
|
187
|
+
state->was_ready = false;
|
|
188
|
+
state->timer_total = 0;
|
|
189
|
+
}
|
|
190
|
+
#endif
|
|
119
191
|
}
|
|
120
192
|
break;
|
|
121
193
|
case RUBY_INTERNAL_THREAD_EVENT_READY: {
|
|
122
|
-
|
|
194
|
+
thread_local_state *state = GT_EVENT_LOCAL_STATE(event_data, false);
|
|
195
|
+
if (!state) {
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
state->was_ready = true;
|
|
123
199
|
|
|
124
200
|
if (ENABLED(WAITING_THREADS)) {
|
|
201
|
+
state->waiting_threads_ready_generation = waiting_threads_current_generation;
|
|
125
202
|
waiting_threads_total++;
|
|
126
203
|
}
|
|
127
204
|
|
|
128
205
|
if (ENABLED(TIMER_GLOBAL | TIMER_LOCAL)) {
|
|
129
|
-
gt_gettime(&timer_ready_at);
|
|
206
|
+
gt_gettime(&state->timer_ready_at);
|
|
130
207
|
}
|
|
131
208
|
}
|
|
132
209
|
break;
|
|
133
210
|
case RUBY_INTERNAL_THREAD_EVENT_RESUMED: {
|
|
134
|
-
|
|
211
|
+
thread_local_state *state = GT_EVENT_LOCAL_STATE(event_data, true);
|
|
212
|
+
if (!state->was_ready) {
|
|
213
|
+
break; // In case we registered the hook while some threads were already waiting on the GVL
|
|
214
|
+
}
|
|
135
215
|
|
|
136
216
|
if (ENABLED(WAITING_THREADS)) {
|
|
137
|
-
|
|
217
|
+
if (state->waiting_threads_ready_generation == waiting_threads_current_generation) {
|
|
218
|
+
waiting_threads_total--;
|
|
219
|
+
}
|
|
138
220
|
}
|
|
139
221
|
|
|
140
222
|
if (ENABLED(TIMER_GLOBAL | TIMER_LOCAL)) {
|
|
141
223
|
struct timespec current_time;
|
|
142
224
|
gt_gettime(¤t_time);
|
|
143
|
-
counter_t diff = gt_time_diff_ns(timer_ready_at, current_time);
|
|
225
|
+
counter_t diff = gt_time_diff_ns(state->timer_ready_at, current_time);
|
|
144
226
|
|
|
145
227
|
if (ENABLED(TIMER_LOCAL)) {
|
|
146
|
-
|
|
228
|
+
state->timer_total += diff;
|
|
147
229
|
}
|
|
148
230
|
|
|
149
231
|
if (ENABLED(TIMER_GLOBAL)) {
|
|
@@ -156,6 +238,10 @@ static void gt_thread_callback(rb_event_flag_t event, const rb_internal_thread_e
|
|
|
156
238
|
}
|
|
157
239
|
|
|
158
240
|
void Init_instrumentation(void) {
|
|
241
|
+
#ifdef HAVE_RB_INTERNAL_THREAD_SPECIFIC_GET // 3.3+
|
|
242
|
+
thread_storage_key = rb_internal_thread_specific_key_create();
|
|
243
|
+
#endif
|
|
244
|
+
|
|
159
245
|
VALUE rb_mGVLTools = rb_const_get(rb_cObject, rb_intern("GVLTools"));
|
|
160
246
|
|
|
161
247
|
VALUE rb_mNative = rb_const_get(rb_mGVLTools, rb_intern("Native"));
|
|
@@ -167,11 +253,18 @@ void Init_instrumentation(void) {
|
|
|
167
253
|
rb_define_singleton_method(rb_mGlobalTimer, "reset", global_timer_reset, 0);
|
|
168
254
|
rb_define_singleton_method(rb_mGlobalTimer, "monotonic_time", global_timer_monotonic_time, 0);
|
|
169
255
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
256
|
+
rb_global_variable(&rb_cLocalTimer);
|
|
257
|
+
rb_cLocalTimer = rb_const_get(rb_mGVLTools, rb_intern("LocalTimer"));
|
|
258
|
+
rb_undef_alloc_func(rb_cLocalTimer);
|
|
259
|
+
rb_define_singleton_method(rb_cLocalTimer, "reset", local_timer_m_reset, 0);
|
|
260
|
+
rb_define_singleton_method(rb_cLocalTimer, "monotonic_time", local_timer_m_monotonic_time, 0);
|
|
261
|
+
#ifdef HAVE_RB_INTERNAL_THREAD_SPECIFIC_GET
|
|
262
|
+
rb_define_singleton_method(rb_cLocalTimer, "for", local_timer_for, 1);
|
|
263
|
+
rb_define_method(rb_cLocalTimer, "reset", local_timer_reset, 0);
|
|
264
|
+
rb_define_method(rb_cLocalTimer, "monotonic_time", local_timer_monotonic_time, 0);
|
|
265
|
+
#endif
|
|
173
266
|
|
|
174
267
|
VALUE rb_mWaitingThreads = rb_const_get(rb_mGVLTools, rb_intern("WaitingThreads"));
|
|
175
|
-
rb_define_singleton_method(rb_mWaitingThreads, "
|
|
268
|
+
rb_define_singleton_method(rb_mWaitingThreads, "_reset", waiting_threads_reset, 0);
|
|
176
269
|
rb_define_singleton_method(rb_mWaitingThreads, "count", waiting_threads_count, 0);
|
|
177
270
|
}
|
data/gvltools.gemspec
CHANGED
data/lib/gvltools/version.rb
CHANGED
data/lib/gvltools.rb
CHANGED
|
@@ -70,7 +70,7 @@ module GVLTools
|
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
class LocalTimer
|
|
74
74
|
extend AbstractInstrumenter
|
|
75
75
|
|
|
76
76
|
class << self
|
|
@@ -96,8 +96,27 @@ module GVLTools
|
|
|
96
96
|
end
|
|
97
97
|
alias_method :count, :count
|
|
98
98
|
|
|
99
|
+
def enable
|
|
100
|
+
unless enabled?
|
|
101
|
+
reset
|
|
102
|
+
end
|
|
103
|
+
super
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def reset
|
|
107
|
+
if enabled?
|
|
108
|
+
raise Error, "can't reset WaitingThreads counter while it is active"
|
|
109
|
+
else
|
|
110
|
+
_reset
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
99
114
|
private
|
|
100
115
|
|
|
116
|
+
def _reset
|
|
117
|
+
end
|
|
118
|
+
alias_method :_reset, :_reset # to be redefined from C.
|
|
119
|
+
|
|
101
120
|
def metric
|
|
102
121
|
WAITING_THREADS
|
|
103
122
|
end
|
metadata
CHANGED
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gvltools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jean Boussier
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: rake-compiler
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - ">="
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0'
|
|
20
|
-
type: :development
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - ">="
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0'
|
|
11
|
+
date: 2024-01-19 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
27
13
|
description:
|
|
28
14
|
email:
|
|
29
15
|
- jean.boussier@gmail.com
|
|
@@ -67,7 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
67
53
|
- !ruby/object:Gem::Version
|
|
68
54
|
version: '0'
|
|
69
55
|
requirements: []
|
|
70
|
-
rubygems_version: 3.
|
|
56
|
+
rubygems_version: 3.5.3
|
|
71
57
|
signing_key:
|
|
72
58
|
specification_version: 4
|
|
73
59
|
summary: Set of GVL instrumentation tools
|