allocation_tracer 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -1
- data/ext/allocation_tracer/allocation_tracer.c +15 -18
- data/lib/allocation_tracer/allocation_tracer.so +0 -0
- data/lib/allocation_tracer/version.rb +1 -1
- data/spec/allocation_tracer_spec.rb +34 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1f129686d0942e7690ff66568f9af7f50f11148
|
4
|
+
data.tar.gz: fbc17e5b8358996aa55843c8632e15896d14f16d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 886adb15a4f94f3fd9ed2815f9aee9fa524bf48aa853ceafb9bf2ff450a5dcd204ce8b8c483029ba78d1bc81f2124e7bb6662770d253e2aed58262c24a54e8ad
|
7
|
+
data.tar.gz: 69b0c17158f3f8af672296a4868c609a2f12c0c8b8d10d08b7d2309c6357b35b2b9f843986594c62bfad1549a62aeae12f90e9cfe3db3c299ee59f5001b07b00
|
data/README.md
CHANGED
@@ -26,7 +26,16 @@ Or install it yourself as:
|
|
26
26
|
|
27
27
|
### Allocation tracing
|
28
28
|
|
29
|
-
You can trace allocation
|
29
|
+
You can trace allocation and aggregate information. Information includes:
|
30
|
+
|
31
|
+
count - how many objects are created.
|
32
|
+
total_age - total age of objects which created here
|
33
|
+
max_age - age of longest living object created here
|
34
|
+
min_age - age of shortest living object created here
|
35
|
+
|
36
|
+
Age of Object can be calculated by this formula: [current GC count] - [birth time GC count]
|
37
|
+
|
38
|
+
For example:
|
30
39
|
|
31
40
|
```ruby
|
32
41
|
require 'allocation_tracer'
|
@@ -15,7 +15,6 @@ struct allocation_info {
|
|
15
15
|
int living;
|
16
16
|
VALUE flags;
|
17
17
|
VALUE klass;
|
18
|
-
const char *klass_path;
|
19
18
|
size_t generation;
|
20
19
|
|
21
20
|
/* allocation info */
|
@@ -188,7 +187,6 @@ static void
|
|
188
187
|
free_allocation_info(struct traceobj_arg *arg, struct allocation_info *info)
|
189
188
|
{
|
190
189
|
delete_unique_str(arg->str_table, info->path);
|
191
|
-
delete_unique_str(arg->str_table, info->klass_path);
|
192
190
|
ruby_xfree(info);
|
193
191
|
}
|
194
192
|
|
@@ -199,12 +197,9 @@ newobj_i(VALUE tpval, void *data)
|
|
199
197
|
struct allocation_info *info;
|
200
198
|
rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
|
201
199
|
VALUE obj = rb_tracearg_object(tparg);
|
202
|
-
VALUE klass = RBASIC_CLASS(obj);
|
203
200
|
VALUE path = rb_tracearg_path(tparg);
|
204
201
|
VALUE line = rb_tracearg_lineno(tparg);
|
205
|
-
VALUE klass_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_class_path_cached(klass) : Qnil;
|
206
202
|
const char *path_cstr = RTEST(path) ? make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : NULL;
|
207
|
-
const char *klass_path_cstr = RTEST(klass_path) ? make_unique_str(arg->str_table, RSTRING_PTR(klass_path), RSTRING_LEN(klass_path)) : NULL;
|
208
203
|
|
209
204
|
if (st_lookup(arg->object_table, (st_data_t)obj, (st_data_t *)&info)) {
|
210
205
|
if (info->living) {
|
@@ -212,7 +207,6 @@ newobj_i(VALUE tpval, void *data)
|
|
212
207
|
}
|
213
208
|
/* reuse info */
|
214
209
|
delete_unique_str(arg->str_table, info->path);
|
215
|
-
delete_unique_str(arg->str_table, info->klass_path);
|
216
210
|
}
|
217
211
|
else {
|
218
212
|
info = create_allocation_info();
|
@@ -221,8 +215,7 @@ newobj_i(VALUE tpval, void *data)
|
|
221
215
|
info->next = NULL;
|
222
216
|
info->living = 1;
|
223
217
|
info->flags = RBASIC(obj)->flags;
|
224
|
-
info->klass =
|
225
|
-
info->klass_path = klass_path_cstr;
|
218
|
+
info->klass = rb_class_real(RBASIC_CLASS(obj));
|
226
219
|
info->generation = rb_gc_count();
|
227
220
|
|
228
221
|
info->path = path_cstr;
|
@@ -262,7 +255,7 @@ aggregator_i(void *data)
|
|
262
255
|
key_data.data[i++] = (st_data_t)(info->flags & T_MASK);
|
263
256
|
}
|
264
257
|
if (arg->keys & KEY_CLASS) {
|
265
|
-
key_data.data[i++] =
|
258
|
+
key_data.data[i++] = info->klass;
|
266
259
|
}
|
267
260
|
key_data.n = i;
|
268
261
|
key = (st_data_t)&key_data;
|
@@ -282,7 +275,6 @@ aggregator_i(void *data)
|
|
282
275
|
val_buff[2] = val_buff[3] = age;
|
283
276
|
|
284
277
|
if (arg->keys & KEY_PATH) keep_unique_str(arg->str_table, info->path);
|
285
|
-
if (arg->keys & KEY_CLASS) keep_unique_str(arg->str_table, info->klass_path);
|
286
278
|
|
287
279
|
st_insert(arg->aggregate_table, (st_data_t)key_buff, (st_data_t)val_buff);
|
288
280
|
}
|
@@ -301,11 +293,10 @@ aggregator_i(void *data)
|
|
301
293
|
}
|
302
294
|
|
303
295
|
static void
|
304
|
-
move_to_freed_list(struct traceobj_arg *arg,
|
296
|
+
move_to_freed_list(struct traceobj_arg *arg, struct allocation_info *info)
|
305
297
|
{
|
306
298
|
info->next = arg->freed_allocation_info;
|
307
299
|
arg->freed_allocation_info = info;
|
308
|
-
st_delete(arg->object_table, (st_data_t *)&obj, (st_data_t *)&info);
|
309
300
|
}
|
310
301
|
|
311
302
|
static void
|
@@ -321,7 +312,8 @@ freeobj_i(VALUE tpval, void *data)
|
|
321
312
|
}
|
322
313
|
|
323
314
|
if (st_lookup(arg->object_table, (st_data_t)obj, (st_data_t *)&info)) {
|
324
|
-
move_to_freed_list(arg,
|
315
|
+
move_to_freed_list(arg, info);
|
316
|
+
st_delete(arg->object_table, (st_data_t *)&obj, (st_data_t *)&info);
|
325
317
|
}
|
326
318
|
}
|
327
319
|
|
@@ -422,10 +414,12 @@ aggregate_result_i(st_data_t key, st_data_t val, void *data)
|
|
422
414
|
rb_ary_push(k, type_symbols[key_buff->data[i++]]);
|
423
415
|
}
|
424
416
|
if (arg->keys & KEY_CLASS) {
|
425
|
-
|
426
|
-
if (
|
427
|
-
|
428
|
-
|
417
|
+
VALUE klass = key_buff->data[i++];
|
418
|
+
if (BUILTIN_TYPE(klass) == T_CLASS) {
|
419
|
+
klass = rb_class_real(klass);
|
420
|
+
rb_ary_push(k, klass);
|
421
|
+
/* TODO: actually, it is dangerous code because klass can be sweeped */
|
422
|
+
/* So that class specifier is hidden feature */
|
429
423
|
}
|
430
424
|
else {
|
431
425
|
rb_ary_push(k, Qnil);
|
@@ -442,7 +436,7 @@ aggregate_rest_object_i(st_data_t key, st_data_t val, void *data)
|
|
442
436
|
{
|
443
437
|
struct traceobj_arg *arg = (struct traceobj_arg *)data;
|
444
438
|
struct allocation_info *info = (struct allocation_info *)val;
|
445
|
-
move_to_freed_list(arg,
|
439
|
+
move_to_freed_list(arg, info);
|
446
440
|
return ST_CONTINUE;
|
447
441
|
}
|
448
442
|
|
@@ -454,6 +448,7 @@ aggregate_result(struct traceobj_arg *arg)
|
|
454
448
|
aar.arg = arg;
|
455
449
|
|
456
450
|
st_foreach(arg->object_table, aggregate_rest_object_i, (st_data_t)arg);
|
451
|
+
st_clear(arg->object_table);
|
457
452
|
aggregator_i(arg);
|
458
453
|
st_foreach(arg->aggregate_table, aggregate_result_i, (st_data_t)&aar);
|
459
454
|
clear_traceobj_arg();
|
@@ -521,6 +516,8 @@ allocation_tracer_setup(int argc, VALUE *argv, VALUE self)
|
|
521
516
|
int i;
|
522
517
|
VALUE ary = rb_check_array_type(argv[0]);
|
523
518
|
|
519
|
+
arg->keys = 0;
|
520
|
+
|
524
521
|
for (i=0; i<(int)RARRAY_LEN(ary); i++) {
|
525
522
|
if (RARRAY_AREF(ary, i) == ID2SYM(rb_intern("path"))) arg->keys |= KEY_PATH;
|
526
523
|
else if (RARRAY_AREF(ary, i) == ID2SYM(rb_intern("line"))) arg->keys |= KEY_LINE;
|
Binary file
|
@@ -23,5 +23,39 @@ describe ObjectSpace::AllocationTracer do
|
|
23
23
|
expect(result.length).to be >= 1
|
24
24
|
expect(result[[__FILE__, line]]).to eq [1, 0, 0, 0]
|
25
25
|
end
|
26
|
+
|
27
|
+
describe 'with different setup' do
|
28
|
+
it 'should work with type' do
|
29
|
+
line = __LINE__ + 3
|
30
|
+
ObjectSpace::AllocationTracer.setup(%i(path line type))
|
31
|
+
result = ObjectSpace::AllocationTracer.trace do
|
32
|
+
a = [Object.new]
|
33
|
+
b = {Object.new => 'foo'}
|
34
|
+
end
|
35
|
+
|
36
|
+
expect(result.length).to be 5
|
37
|
+
expect(result[[__FILE__, line, :T_OBJECT]]).to eq [1, 0, 0, 0]
|
38
|
+
expect(result[[__FILE__, line, :T_ARRAY]]).to eq [1, 0, 0, 0]
|
39
|
+
expect(result[[__FILE__, line + 1, :T_HASH]]).to eq [1, 0, 0, 0]
|
40
|
+
expect(result[[__FILE__, line + 1, :T_OBJECT]]).to eq [1, 0, 0, 0]
|
41
|
+
expect(result[[__FILE__, line + 1, :T_STRING]]).to eq [1, 0, 0, 0]
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should work with class' do
|
45
|
+
line = __LINE__ + 3
|
46
|
+
ObjectSpace::AllocationTracer.setup(%i(path line class))
|
47
|
+
result = ObjectSpace::AllocationTracer.trace do
|
48
|
+
a = [Object.new]
|
49
|
+
b = {Object.new => 'foo'}
|
50
|
+
end
|
51
|
+
|
52
|
+
expect(result.length).to be 5
|
53
|
+
expect(result[[__FILE__, line, Object]]).to eq [1, 0, 0, 0]
|
54
|
+
expect(result[[__FILE__, line, Array]]).to eq [1, 0, 0, 0]
|
55
|
+
expect(result[[__FILE__, line + 1, Hash]]).to eq [1, 0, 0, 0]
|
56
|
+
expect(result[[__FILE__, line + 1, Object]]).to eq [1, 0, 0, 0]
|
57
|
+
expect(result[[__FILE__, line + 1, String]]).to eq [1, 0, 0, 0]
|
58
|
+
end
|
59
|
+
end
|
26
60
|
end
|
27
61
|
end
|