alloc_track 0.0.2 → 0.0.3
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/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/alloc_track.gemspec +1 -1
- data/ext/alloc_track/alloc_track.c +34 -19
- data/test/test_alloc_track.rb +22 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 996bfa135ead01bfda01be1bfc01a20eae7e99b8
|
4
|
+
data.tar.gz: 634b89b83837795cac2491ba924ef96a5404856f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c37c97d902cc8c35130169c50807a731d4472a111b53f1204ecf63a9f96b7dc5dce4c54e7dc579636964fe5e7868d9c007b58dd71d419f6df02464ca0e8504d
|
7
|
+
data.tar.gz: 98fee067ef40dfbcf8dc71224b043a13b6974ebd3b4fbe0bcf0cdde03e74629f2d2aaecaaf06e3c0c9d75cb8cc69b5a67f7dab756516e8b2b50f072351ebdeb3
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/alloc_track.gemspec
CHANGED
@@ -2,15 +2,18 @@
|
|
2
2
|
#include "ruby/intern.h"
|
3
3
|
#include "ruby/debug.h"
|
4
4
|
|
5
|
-
#define ALLOCTRACK_OBJ_BIT
|
5
|
+
#define ALLOCTRACK_OBJ_BIT FL_USER19
|
6
|
+
|
7
|
+
#define MAX(_x, _y) ( (_x) > (_y) ? (_x) : (_y) )
|
6
8
|
|
7
9
|
typedef struct stat_collector {
|
8
10
|
struct stat_collector *next; /* not currently used */
|
9
11
|
VALUE thread;
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
int
|
12
|
+
int64_t current_alloc;
|
13
|
+
int64_t current_free;
|
14
|
+
int64_t current_limit;
|
15
|
+
int limit_signal;
|
16
|
+
int64_t max_delta;
|
14
17
|
} stat_collector_t;
|
15
18
|
|
16
19
|
static VALUE mAllocTrack;
|
@@ -124,14 +127,14 @@ static VALUE
|
|
124
127
|
alloc()
|
125
128
|
{
|
126
129
|
validate_started();
|
127
|
-
return
|
130
|
+
return LL2NUM(get_collector(rb_thread_current())->current_alloc);
|
128
131
|
}
|
129
132
|
|
130
133
|
static VALUE
|
131
134
|
_free()
|
132
135
|
{
|
133
136
|
validate_started();
|
134
|
-
return
|
137
|
+
return LL2NUM(get_collector(rb_thread_current())->current_free);
|
135
138
|
}
|
136
139
|
|
137
140
|
static VALUE
|
@@ -140,7 +143,16 @@ delta()
|
|
140
143
|
stat_collector_t *c;
|
141
144
|
validate_started();
|
142
145
|
c = get_collector(rb_thread_current());
|
143
|
-
return
|
146
|
+
return LL2NUM(c->current_alloc - c->current_free);
|
147
|
+
}
|
148
|
+
|
149
|
+
static VALUE
|
150
|
+
max_delta()
|
151
|
+
{
|
152
|
+
stat_collector_t *c;
|
153
|
+
validate_started();
|
154
|
+
c = get_collector(rb_thread_current());
|
155
|
+
return LL2NUM(c->max_delta);
|
144
156
|
}
|
145
157
|
|
146
158
|
static VALUE
|
@@ -173,12 +185,6 @@ limit(VALUE self, VALUE num_allocs)
|
|
173
185
|
return rb_ensure(do_limit, num_allocs, ensure_stopped, Qnil);
|
174
186
|
}
|
175
187
|
|
176
|
-
static int
|
177
|
-
is_collector_enabled(stat_collector_t *c)
|
178
|
-
{
|
179
|
-
return c->limit_signal == 0 ? 1 : 0;
|
180
|
-
}
|
181
|
-
|
182
188
|
static int
|
183
189
|
is_collector_limit_exceeded(stat_collector_t *c)
|
184
190
|
{
|
@@ -194,9 +200,10 @@ tracepoint_hook(VALUE tpval, void *data)
|
|
194
200
|
VALUE obj = rb_tracearg_object(tparg);
|
195
201
|
switch(flag) {
|
196
202
|
case RUBY_INTERNAL_EVENT_NEWOBJ:
|
197
|
-
if ((c = get_collector(rb_thread_current())) != NULL
|
203
|
+
if ((c = get_collector(rb_thread_current())) != NULL) {
|
198
204
|
RBASIC(obj)->flags |= ALLOCTRACK_OBJ_BIT;
|
199
205
|
c->current_alloc++;
|
206
|
+
c->max_delta = MAX( c->current_alloc - c->current_free, c->max_delta);
|
200
207
|
|
201
208
|
if (c->current_limit && (c->current_alloc - c->current_free) > c->current_limit) {
|
202
209
|
c->limit_signal = 1;
|
@@ -212,8 +219,7 @@ tracepoint_hook(VALUE tpval, void *data)
|
|
212
219
|
}
|
213
220
|
break;
|
214
221
|
case RUBY_INTERNAL_EVENT_FREEOBJ:
|
215
|
-
if ((c = get_collector(rb_thread_current())) != NULL &&
|
216
|
-
(RBASIC(obj)->flags & ALLOCTRACK_OBJ_BIT)) {
|
222
|
+
if ((c = get_collector(rb_thread_current())) != NULL && (RBASIC(obj)->flags & ALLOCTRACK_OBJ_BIT)) {
|
217
223
|
c->current_free++;
|
218
224
|
}
|
219
225
|
break;
|
@@ -235,14 +241,22 @@ any_collectors_with_exceeded_limits()
|
|
235
241
|
static void
|
236
242
|
exception_tracepoint_hook(VALUE tpval, void *data)
|
237
243
|
{
|
244
|
+
int should_raise = 0;
|
238
245
|
VALUE th = rb_thread_current();
|
239
246
|
stat_collector_t *c;
|
240
247
|
if ((c = get_collector(th)) != NULL && is_collector_limit_exceeded(c)) {
|
241
|
-
|
248
|
+
rb_gc(); /* try to gc before raising */
|
249
|
+
if ((c->current_alloc - c->current_free) > c->current_limit) {
|
250
|
+
remove_collector(th);
|
251
|
+
should_raise = 1;
|
252
|
+
} else {
|
253
|
+
c->limit_signal = 0;
|
254
|
+
}
|
242
255
|
if (!any_collectors_with_exceeded_limits()) {
|
243
256
|
rb_tracepoint_disable(tpval_exception);
|
244
257
|
}
|
245
|
-
|
258
|
+
|
259
|
+
if (should_raise) rb_raise(eAllocTrackLimitExceeded, "allocation limit exceeded");
|
246
260
|
}
|
247
261
|
}
|
248
262
|
|
@@ -258,6 +272,7 @@ Init_alloc_track()
|
|
258
272
|
rb_define_singleton_method(mAllocTrack, "free", _free, 0);
|
259
273
|
rb_define_singleton_method(mAllocTrack, "delta", delta, 0);
|
260
274
|
rb_define_singleton_method(mAllocTrack, "limit", limit, 1);
|
275
|
+
rb_define_singleton_method(mAllocTrack, "max_delta", max_delta, 0);
|
261
276
|
|
262
277
|
eAllocTrackError = rb_define_class_under(mAllocTrack, "Error", rb_eStandardError);
|
263
278
|
eAllocTrackLimitExceeded = rb_define_class_under(mAllocTrack, "LimitExceeded", rb_eStandardError);
|
data/test/test_alloc_track.rb
CHANGED
@@ -19,6 +19,17 @@ class TestAllocTrack < Test::Unit::TestCase
|
|
19
19
|
AllocTrack.stop
|
20
20
|
end
|
21
21
|
|
22
|
+
def test_max_delta
|
23
|
+
AllocTrack.start
|
24
|
+
max_delta = 0
|
25
|
+
100.times do
|
26
|
+
Object.new
|
27
|
+
max_delta = [max_delta, AllocTrack.delta].max
|
28
|
+
end
|
29
|
+
assert (AllocTrack.max_delta - max_delta ).abs < 10 #close enough
|
30
|
+
AllocTrack.stop
|
31
|
+
end
|
32
|
+
|
22
33
|
def test_thread_not_included
|
23
34
|
AllocTrack.start
|
24
35
|
t = Thread.new do
|
@@ -49,11 +60,22 @@ class TestAllocTrack < Test::Unit::TestCase
|
|
49
60
|
end
|
50
61
|
|
51
62
|
def test_limit_raises
|
63
|
+
vals = []
|
52
64
|
assert_raise AllocTrack::LimitExceeded do
|
53
65
|
AllocTrack.limit 10 do
|
66
|
+
200.times { vals.push(Object.new) }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_limit_invokes_gc
|
72
|
+
stat = GC.stat
|
73
|
+
assert_nothing_raised do
|
74
|
+
AllocTrack.limit 50 do
|
54
75
|
200.times { Object.new }
|
55
76
|
end
|
56
77
|
end
|
78
|
+
assert_operator GC.stat[:count], :>, stat[:count]
|
57
79
|
end
|
58
80
|
|
59
81
|
def test_within_limit
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alloc_track
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Francis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|