gc_tracer 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 830cc27b4a444096a36db13d0425b920cd87c8e4
4
- data.tar.gz: a331e1b13ea0f3c61af86c166c1592cb21fb67cd
3
+ metadata.gz: fe62a5d40bec9e63a7f686a912ad5b7025de0baa
4
+ data.tar.gz: 8103c971df3779bb9d2aa3a57b98208540be98ef
5
5
  SHA512:
6
- metadata.gz: 61150fdea8743a53a2f2d7954d2cb969e75ff46b23ddb7bbb50afaccb2885632067533b10c5bac91b2fe393d8cd739b59eb3de16b521ed4869cdb6c18dfcdbd0
7
- data.tar.gz: 66bcc1e1a75d05caf7dc54a655a4ebc657db34fb9fa6410dbef5faebeb0783248851cbf9ea8ae1936a2348d95c0232ceddd22979494516d9268e80818a46287b
6
+ metadata.gz: 5901c6798b9f33b90e584db043ad102feba487c4206bc1b67b9d7d6570353bb08cf39980130bb767ec89fa22debb3c5ed9543ef531db2a8137bf7ee6e9a128b1
7
+ data.tar.gz: 5ce7a8796a30b4e3f05284a7108043ea942b52878904ec6925cf5def9ad1f4dc114cfee9dec0466f39fb7f5df0f5f82da34123ea511c404d33f4bc785e1e124c
data/README.md CHANGED
@@ -89,6 +89,64 @@ In this case, 50,000 objects are created at `test.rb:6'. 44,290 is total
89
89
  age of objects created at this line. Average age of object created at
90
90
  this line is 50000/44290 = 0.8858. 0 is minimum age and 6 is maximum age.
91
91
 
92
+ You can also specify `type' in GC::Tracer.setup_allocation_tracing() to
93
+ specify what should be keys to aggregate like that.
94
+
95
+ ```ruby
96
+ require 'gc_tracer'
97
+ require 'pp'
98
+
99
+ GC::Tracer.setup_allocation_tracing(%i{path line type})
100
+
101
+ result = GC::Tracer.start_allocation_tracing do
102
+ 50_000.times{|i|
103
+ a = [i.to_s]
104
+ b = {i.to_s => nil}
105
+ c = (i.to_s .. i.to_s)
106
+ }
107
+ end
108
+
109
+ pp result
110
+ ```
111
+
112
+ and you will get:
113
+
114
+ ```
115
+ {["test.rb", 8, :T_STRING]=>[50000, 49067, 0, 17],
116
+ ["test.rb", 8, :T_ARRAY]=>[50000, 49053, 0, 17],
117
+ ["test.rb", 9, :T_STRING]=>[100000, 98146, 0, 17],
118
+ ["test.rb", 9, :T_HASH]=>[50000, 49111, 0, 17],
119
+ ["test.rb", 10, :T_STRING]=>[100000, 98267, 0, 17],
120
+ ["test.rb", 10, :T_STRUCT]=>[50000, 49126, 0, 17]}
121
+ ```
122
+
123
+ Interestingly, you can not see array creations in a middle of block:
124
+
125
+ ```ruby
126
+ require 'gc_tracer'
127
+ require 'pp'
128
+
129
+ GC::Tracer.setup_allocation_tracing(%i{path line type})
130
+
131
+ result = GC::Tracer.start_allocation_tracing do
132
+ 50_000.times{|i|
133
+ [i.to_s]
134
+ nil
135
+ }
136
+ end
137
+
138
+ pp result
139
+ ```
140
+
141
+ and it prints:
142
+
143
+ ```
144
+ {["test.rb", 8, :T_STRING]=>[50000, 38322, 0, 2]}
145
+ ```
146
+
147
+ There are only string creation. This is because unused array creation is
148
+ ommitted by optimizer.
149
+
92
150
  Simply you can require `gc_tracer/allocation_trace' to start allocation
93
151
  tracer and output the aggregated information into stdot at the end of
94
152
  program.
@@ -13,19 +13,29 @@ struct allocation_info {
13
13
  int living;
14
14
  VALUE flags;
15
15
  VALUE klass;
16
+ const char *klass_path;
17
+ size_t generation;
16
18
 
17
19
  /* allocation info */
18
20
  const char *path;
19
21
  unsigned long line;
20
- const char *class_path;
21
- VALUE mid;
22
- size_t generation;
23
22
 
24
23
  struct allocation_info *next;
25
24
  };
26
25
 
26
+ #define KEY_PATH (1<<1)
27
+ #define KEY_LINE (1<<2)
28
+ #define KEY_TYPE (1<<3)
29
+ #define KEY_CLASS (1<<4)
30
+
31
+ #define VAL_COUNT (1<<1)
32
+ #define VAL_TOTAL_AGE (1<<2)
33
+ #define VAL_MAX_AGE (1<<3)
34
+ #define VAL_MIN_AGE (1<<4)
35
+
27
36
  struct traceobj_arg {
28
37
  int running;
38
+ int keys, vals;
29
39
  st_table *aggregate_table; /* user defined key -> [count, total_age, max_age, min_age] */
30
40
  st_table *object_table; /* obj (VALUE) -> allocation_info */
31
41
  st_table *str_table; /* cstr -> refcount */
@@ -39,7 +49,7 @@ keep_unique_str(st_table *tbl, const char *str)
39
49
  {
40
50
  st_data_t n;
41
51
 
42
- if (st_lookup(tbl, (st_data_t)str, &n)) {
52
+ if (str && st_lookup(tbl, (st_data_t)str, &n)) {
43
53
  char *result;
44
54
 
45
55
  st_insert(tbl, (st_data_t)str, n+1);
@@ -88,9 +98,12 @@ delete_unique_str(st_table *tbl, const char *str)
88
98
  }
89
99
  }
90
100
 
101
+ /* file, line, type */
102
+ #define MAX_KEY_DATA 4
103
+
91
104
  struct memcmp_key_data {
92
- const char *path;
93
- int line;
105
+ int n;
106
+ st_data_t data[4];
94
107
  };
95
108
 
96
109
  static int
@@ -98,15 +111,14 @@ memcmp_hash_compare(st_data_t a, st_data_t b)
98
111
  {
99
112
  struct memcmp_key_data *k1 = (struct memcmp_key_data *)a;
100
113
  struct memcmp_key_data *k2 = (struct memcmp_key_data *)b;
101
-
102
- return (k1->path == k2->path && k1->line == k2->line) ? 0 : 1;
114
+ return memcmp(&k1->data[0], &k2->data[0], k1->n * sizeof(st_data_t));
103
115
  }
104
116
 
105
117
  static st_index_t
106
118
  memcmp_hash_hash(st_data_t a)
107
119
  {
108
- struct memcmp_key_data *k1 = (struct memcmp_key_data *)a;
109
- return (((st_index_t)k1->path) << 8) & (st_index_t)k1->line;
120
+ struct memcmp_key_data *k = (struct memcmp_key_data *)a;
121
+ return rb_memhash(k->data, sizeof(st_data_t) * k->n);
110
122
  }
111
123
 
112
124
  static const struct st_hash_type memcmp_hash_type = {
@@ -120,6 +132,9 @@ get_traceobj_arg(void)
120
132
  {
121
133
  if (tmp_trace_arg == 0) {
122
134
  tmp_trace_arg = ALLOC_N(struct traceobj_arg, 1);
135
+ tmp_trace_arg->running = 0;
136
+ tmp_trace_arg->keys = 0;
137
+ tmp_trace_arg->vals = VAL_COUNT | VAL_TOTAL_AGE | VAL_MAX_AGE | VAL_MIN_AGE;
123
138
  tmp_trace_arg->aggregate_table = st_init_table(&memcmp_hash_type);
124
139
  tmp_trace_arg->object_table = st_init_numtable();
125
140
  tmp_trace_arg->str_table = st_init_strtable();
@@ -173,7 +188,7 @@ static void
173
188
  free_allocation_info(struct traceobj_arg *arg, struct allocation_info *info)
174
189
  {
175
190
  delete_unique_str(arg->str_table, info->path);
176
- delete_unique_str(arg->str_table, info->class_path);
191
+ delete_unique_str(arg->str_table, info->klass_path);
177
192
  ruby_xfree(info);
178
193
  }
179
194
 
@@ -181,16 +196,15 @@ static void
181
196
  newobj_i(VALUE tpval, void *data)
182
197
  {
183
198
  struct traceobj_arg *arg = (struct traceobj_arg *)data;
199
+ struct allocation_info *info;
184
200
  rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
185
201
  VALUE obj = rb_tracearg_object(tparg);
202
+ VALUE klass = RBASIC_CLASS(obj);
186
203
  VALUE path = rb_tracearg_path(tparg);
187
204
  VALUE line = rb_tracearg_lineno(tparg);
188
- VALUE mid = rb_tracearg_method_id(tparg);
189
- VALUE klass = rb_tracearg_defined_class(tparg);
190
- struct allocation_info *info;
191
- const char *path_cstr = RTEST(path) ? make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0;
192
- VALUE class_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_class_path_cached(klass) : Qnil;
193
- const char *class_path_cstr = RTEST(class_path) ? make_unique_str(arg->str_table, RSTRING_PTR(class_path), RSTRING_LEN(class_path)) : 0;
205
+ VALUE klass_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_class_path_cached(klass) : Qnil;
206
+ 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;
194
208
 
195
209
  if (st_lookup(arg->object_table, (st_data_t)obj, (st_data_t *)&info)) {
196
210
  if (info->living) {
@@ -198,7 +212,7 @@ newobj_i(VALUE tpval, void *data)
198
212
  }
199
213
  /* reuse info */
200
214
  delete_unique_str(arg->str_table, info->path);
201
- delete_unique_str(arg->str_table, info->class_path);
215
+ delete_unique_str(arg->str_table, info->klass_path);
202
216
  }
203
217
  else {
204
218
  info = create_allocation_info();
@@ -207,16 +221,17 @@ newobj_i(VALUE tpval, void *data)
207
221
  info->next = NULL;
208
222
  info->living = 1;
209
223
  info->flags = RBASIC(obj)->flags;
210
- info->klass = RBASIC_CLASS(obj);
224
+ info->klass = klass;
225
+ info->klass_path = klass_path_cstr;
226
+ info->generation = rb_gc_count();
211
227
 
212
228
  info->path = path_cstr;
213
229
  info->line = NUM2INT(line);
214
- info->mid = mid;
215
- info->class_path = class_path_cstr;
216
- info->generation = rb_gc_count();
230
+
217
231
  st_insert(arg->object_table, (st_data_t)obj, (st_data_t)info);
218
232
  }
219
233
 
234
+ /* file, line, type, klass */
220
235
  #define MAX_KEY_SIZE 4
221
236
 
222
237
  void
@@ -234,15 +249,31 @@ aggregator_i(void *data)
234
249
  struct memcmp_key_data key_data;
235
250
  int *val_buff;
236
251
  int age = (int)(gc_count - info->generation);
252
+ int i;
237
253
 
238
- key_data.path = info->path;
239
- key_data.line = info->line;
254
+ i = 0;
255
+ if (arg->keys & KEY_PATH) {
256
+ key_data.data[i++] = (st_data_t)info->path;
257
+ }
258
+ if (arg->keys & KEY_LINE) {
259
+ key_data.data[i++] = (st_data_t)info->line;
260
+ }
261
+ if (arg->keys & KEY_TYPE) {
262
+ key_data.data[i++] = (st_data_t)(info->flags & T_MASK);
263
+ }
264
+ if (arg->keys & KEY_CLASS) {
265
+ key_data.data[i++] = (st_data_t)info->klass_path;
266
+ }
267
+ key_data.n = i;
240
268
  key = (st_data_t)&key_data;
241
- keep_unique_str(arg->str_table, info->path);
242
269
 
243
270
  if (st_lookup(arg->aggregate_table, key, &val) == 0) {
244
- struct memcmp_key_data *key_buff = ALLOC_N(struct memcmp_key_data, 1);
245
- *key_buff = key_data;
271
+ struct memcmp_key_data *key_buff = ruby_xmalloc(sizeof(int) + sizeof(st_data_t) * key_data.n);
272
+ key_buff->n = key_data.n;
273
+
274
+ for (i=0; i<key_data.n; i++) {
275
+ key_buff->data[i] = key_data.data[i];
276
+ }
246
277
  key = (st_data_t)key_buff;
247
278
 
248
279
  /* count, total age, max age, min age */
@@ -250,6 +281,9 @@ aggregator_i(void *data)
250
281
  val_buff[0] = val_buff[1] = 0;
251
282
  val_buff[2] = val_buff[3] = age;
252
283
 
284
+ 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
+
253
287
  st_insert(arg->aggregate_table, (st_data_t)key_buff, (st_data_t)val_buff);
254
288
  }
255
289
  else {
@@ -309,14 +343,94 @@ start_alloc_hooks(VALUE mod)
309
343
  rb_tracepoint_enable(freeobj_hook);
310
344
  }
311
345
 
346
+ static const char *
347
+ type_name(int type)
348
+ {
349
+ switch (type) {
350
+ #define TYPE_NAME(t) case (t): return #t;
351
+ TYPE_NAME(T_NONE);
352
+ TYPE_NAME(T_OBJECT);
353
+ TYPE_NAME(T_CLASS);
354
+ TYPE_NAME(T_MODULE);
355
+ TYPE_NAME(T_FLOAT);
356
+ TYPE_NAME(T_STRING);
357
+ TYPE_NAME(T_REGEXP);
358
+ TYPE_NAME(T_ARRAY);
359
+ TYPE_NAME(T_HASH);
360
+ TYPE_NAME(T_STRUCT);
361
+ TYPE_NAME(T_BIGNUM);
362
+ TYPE_NAME(T_FILE);
363
+ TYPE_NAME(T_MATCH);
364
+ TYPE_NAME(T_COMPLEX);
365
+ TYPE_NAME(T_RATIONAL);
366
+ TYPE_NAME(T_NIL);
367
+ TYPE_NAME(T_TRUE);
368
+ TYPE_NAME(T_FALSE);
369
+ TYPE_NAME(T_SYMBOL);
370
+ TYPE_NAME(T_FIXNUM);
371
+ TYPE_NAME(T_UNDEF);
372
+ TYPE_NAME(T_NODE);
373
+ TYPE_NAME(T_ICLASS);
374
+ TYPE_NAME(T_ZOMBIE);
375
+ TYPE_NAME(T_DATA);
376
+ #undef TYPE_NAME
377
+ }
378
+ return "unknown";
379
+ }
380
+
381
+ struct arg_and_result {
382
+ struct traceobj_arg *arg;
383
+ VALUE result;
384
+ };
385
+
312
386
  static int
313
387
  aggregate_result_i(st_data_t key, st_data_t val, void *data)
314
388
  {
315
- VALUE result = (VALUE)data;
389
+ struct arg_and_result *aar = (struct arg_and_result *)data;
390
+ struct traceobj_arg *arg = aar->arg;
391
+ VALUE result = aar->result;
392
+
316
393
  int *val_buff = (int *)val;
317
394
  struct memcmp_key_data *key_buff = (struct memcmp_key_data *)key;
318
- VALUE k = rb_ary_new3(2, rb_str_new2(key_buff->path), INT2FIX(key_buff->line));
319
395
  VALUE v = rb_ary_new3(4, INT2FIX(val_buff[0]), INT2FIX(val_buff[1]), INT2FIX(val_buff[2]), INT2FIX(val_buff[3]));
396
+ VALUE k = rb_ary_new();
397
+ int i = 0;
398
+ static VALUE type_symbols[T_MASK] = {0};
399
+
400
+ if (type_symbols[0] == 0) {
401
+ int i;
402
+ for (i=0; i<T_MASK; i++) {
403
+ type_symbols[i] = ID2SYM(rb_intern(type_name(i)));
404
+ }
405
+ }
406
+
407
+ i = 0;
408
+ if (arg->keys & KEY_PATH) {
409
+ const char *path = (const char *)key_buff->data[i++];
410
+ if (path) {
411
+ rb_ary_push(k, rb_str_new2(path));
412
+ delete_unique_str(arg->str_table, path);
413
+ }
414
+ else {
415
+ rb_ary_push(k, Qnil);
416
+ }
417
+ }
418
+ if (arg->keys & KEY_LINE) {
419
+ rb_ary_push(k, INT2FIX((int)key_buff->data[i++]));
420
+ }
421
+ if (arg->keys & KEY_TYPE) {
422
+ rb_ary_push(k, type_symbols[key_buff->data[i++]]);
423
+ }
424
+ if (arg->keys & KEY_CLASS) {
425
+ const char *klass_path = (const char *)key_buff->data[i++];
426
+ if (klass_path) {
427
+
428
+ delete_unique_str(arg->str_table, klass_path);
429
+ }
430
+ else {
431
+ rb_ary_push(k, Qnil);
432
+ }
433
+ }
320
434
 
321
435
  rb_hash_aset(result, k, v);
322
436
 
@@ -335,24 +449,29 @@ aggregate_rest_object_i(st_data_t key, st_data_t val, void *data)
335
449
  static VALUE
336
450
  aggregate_result(struct traceobj_arg *arg)
337
451
  {
338
- VALUE result = rb_hash_new();
452
+ struct arg_and_result aar;
453
+ aar.result = rb_hash_new();
454
+ aar.arg = arg;
455
+
339
456
  st_foreach(arg->object_table, aggregate_rest_object_i, (st_data_t)arg);
340
457
  aggregator_i(arg);
341
- st_foreach(arg->aggregate_table, aggregate_result_i, (st_data_t)result);
458
+ st_foreach(arg->aggregate_table, aggregate_result_i, (st_data_t)&aar);
342
459
  clear_traceobj_arg();
343
- return result;
460
+ return aar.result;
344
461
  }
345
462
 
346
463
  static VALUE
347
464
  stop_allocation_tracing(VALUE self)
348
465
  {
349
- VALUE newobj_hook = rb_ivar_get(rb_mGCTracer, rb_intern("newobj_hook"));
350
- VALUE freeobj_hook = rb_ivar_get(rb_mGCTracer, rb_intern("freeobj_hook"));
466
+ struct traceobj_arg * arg = get_traceobj_arg();
351
467
 
352
- /* stop hooks */
353
- if (newobj_hook && freeobj_hook) {
468
+ if (arg->running) {
469
+ VALUE newobj_hook = rb_ivar_get(rb_mGCTracer, rb_intern("newobj_hook"));
470
+ VALUE freeobj_hook = rb_ivar_get(rb_mGCTracer, rb_intern("freeobj_hook"));
354
471
  rb_tracepoint_disable(newobj_hook);
355
472
  rb_tracepoint_disable(freeobj_hook);
473
+
474
+ arg->running = 0;
356
475
  }
357
476
  else {
358
477
  rb_raise(rb_eRuntimeError, "not started yet.");
@@ -369,12 +488,16 @@ gc_tracer_stop_allocation_tracing(VALUE self)
369
488
  }
370
489
 
371
490
  VALUE
372
- gc_tracer_start_allocation_tracing(int argc, VALUE *argv, VALUE self)
491
+ gc_tracer_start_allocation_tracing(VALUE self)
373
492
  {
374
- if (rb_ivar_get(rb_mGCTracer, rb_intern("allocation_tracer")) != Qnil) {
375
- rb_raise(rb_eRuntimeError, "can't run recursive");
493
+ struct traceobj_arg * arg = get_traceobj_arg();
494
+
495
+ if (arg->running) {
496
+ rb_raise(rb_eRuntimeError, "can't run recursivly");
376
497
  }
377
498
  else {
499
+ arg->running = 1;
500
+ if (arg->keys == 0) arg->keys = KEY_PATH | KEY_LINE;
378
501
  start_alloc_hooks(rb_mGCTracer);
379
502
 
380
503
  if (rb_block_given_p()) {
@@ -386,3 +509,48 @@ gc_tracer_start_allocation_tracing(int argc, VALUE *argv, VALUE self)
386
509
  return Qnil;
387
510
  }
388
511
 
512
+ VALUE
513
+ gc_tracer_setup_allocation_tracing(int argc, VALUE *argv, VALUE self)
514
+ {
515
+ struct traceobj_arg * arg = get_traceobj_arg();
516
+
517
+ if (arg->running) {
518
+ rb_raise(rb_eRuntimeError, "can't change configuration during running");
519
+ }
520
+ else {
521
+ int i;
522
+ VALUE ary = rb_check_array_type(argv[0]);
523
+
524
+ for (i=0; i<(int)RARRAY_LEN(ary); i++) {
525
+ if (RARRAY_AREF(ary, i) == ID2SYM(rb_intern("path"))) arg->keys |= KEY_PATH;
526
+ else if (RARRAY_AREF(ary, i) == ID2SYM(rb_intern("line"))) arg->keys |= KEY_LINE;
527
+ else if (RARRAY_AREF(ary, i) == ID2SYM(rb_intern("type"))) arg->keys |= KEY_TYPE;
528
+ else if (RARRAY_AREF(ary, i) == ID2SYM(rb_intern("class"))) arg->keys |= KEY_CLASS;
529
+ else {
530
+ rb_raise(rb_eArgError, "not supported key type");
531
+ }
532
+ }
533
+ }
534
+
535
+ return Qnil;
536
+ }
537
+
538
+ VALUE
539
+ gc_tracer_header_of_allocation_tracing(VALUE self)
540
+ {
541
+ VALUE ary = rb_ary_new();
542
+ struct traceobj_arg * arg = get_traceobj_arg();
543
+
544
+ if (arg->keys & KEY_PATH) rb_ary_push(ary, ID2SYM(rb_intern("path")));
545
+ if (arg->keys & KEY_LINE) rb_ary_push(ary, ID2SYM(rb_intern("line")));
546
+ if (arg->keys & KEY_TYPE) rb_ary_push(ary, ID2SYM(rb_intern("type")));
547
+ if (arg->keys & KEY_CLASS) rb_ary_push(ary, ID2SYM(rb_intern("class")));
548
+
549
+ if (arg->vals & VAL_COUNT) rb_ary_push(ary, ID2SYM(rb_intern("count")));
550
+ if (arg->vals & VAL_TOTAL_AGE) rb_ary_push(ary, ID2SYM(rb_intern("total_age")));
551
+ if (arg->vals & VAL_MAX_AGE) rb_ary_push(ary, ID2SYM(rb_intern("max_age")));
552
+ if (arg->vals & VAL_MIN_AGE) rb_ary_push(ary, ID2SYM(rb_intern("min_age")));
553
+
554
+ return ary;
555
+ }
556
+
@@ -781,8 +781,11 @@ gc_tracer_start_objspace_recording(int argc, VALUE *argv, VALUE self)
781
781
 
782
782
  #endif /* HAVE_RB_OBJSPACE_EACH_OBJECTS_WITHOUT_SETUP */
783
783
 
784
- VALUE gc_tracer_start_allocation_tracing(int argc, VALUE *argv, VALUE self);
784
+ VALUE gc_tracer_start_allocation_tracing(VALUE self);
785
785
  VALUE gc_tracer_stop_allocation_tracing(VALUE self);
786
+ VALUE gc_tracer_setup_allocation_tracing(int argc, VALUE *argv, VALUE self);
787
+ VALUE gc_tracer_header_of_allocation_tracing(VALUE self);
788
+
786
789
  VALUE rb_mGCTracer;
787
790
 
788
791
  /**
@@ -819,8 +822,10 @@ Init_gc_tracer(void)
819
822
  #endif
820
823
 
821
824
  /* allocation tracer methods */
822
- rb_define_module_function(mod, "start_allocation_tracing", gc_tracer_start_allocation_tracing, -1);
825
+ rb_define_module_function(mod, "start_allocation_tracing", gc_tracer_start_allocation_tracing, 0);
823
826
  rb_define_module_function(mod, "stop_allocation_tracing", gc_tracer_stop_allocation_tracing, 0);
827
+ rb_define_module_function(mod, "setup_allocation_tracing", gc_tracer_setup_allocation_tracing, -1);
828
+ rb_define_module_function(mod, "header_of_allocation_tracing", gc_tracer_header_of_allocation_tracing, 0);
824
829
 
825
830
  /* setup default banners */
826
831
  setup_gc_trace_symbols();
@@ -1,10 +1,12 @@
1
1
  require 'gc_tracer'
2
2
 
3
+ GC::Tracer.setup_allocation_tracing(%i{path line})
3
4
  GC::Tracer.start_allocation_tracing
4
5
 
5
6
  at_exit{
6
- puts "file\tline\tcount\ttotal_age\tmax_age\tmin_age"
7
- GC::Tracer.stop_allocation_tracing.sort_by{|k, v| k}.each{|k, v|
7
+ results = GC::Tracer.stop_allocation_tracing
8
+ puts GC::Tracer.header_of_allocation_tracing.join("\t")
9
+ results.sort_by{|k, v| k}.each{|k, v|
8
10
  puts (k+v).join("\t")
9
11
  }
10
12
  }
@@ -1,3 +1,3 @@
1
1
  module GC::Tracer
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -4,7 +4,7 @@ require 'fileutils'
4
4
 
5
5
  describe GC::Tracer do
6
6
  shared_examples "logging_test" do
7
- it do
7
+ it 'should output correctly into file' do
8
8
  Dir.mktmpdir('gc_tracer'){|dir|
9
9
  logfile = "#{dir}/logging"
10
10
  GC::Tracer.start_logging(logfile){
@@ -31,7 +31,7 @@ describe GC::Tracer do
31
31
  shared_examples "objspace_recorder_test" do
32
32
  dirname = "gc_tracer_objspace_recorder_spec.#{$$}"
33
33
 
34
- it do
34
+ it 'should output snapshots correctly into directory' do
35
35
  begin
36
36
  GC::Tracer.start_objspace_recording(dirname){
37
37
  count.times{
@@ -58,7 +58,17 @@ describe GC::Tracer do
58
58
  end
59
59
 
60
60
  describe 'GC::Tracer.start_allocation_tracing' do
61
- it do
61
+ it 'should includes allocation information' do
62
+ line = __LINE__ + 2
63
+ result = GC::Tracer.start_allocation_tracing do
64
+ Object.new
65
+ end
66
+
67
+ expect(result.length).to be >= 1
68
+ expect(result[[__FILE__, line]]).to eq [1, 0, 0, 0]
69
+ end
70
+
71
+ it 'should run twice' do
62
72
  line = __LINE__ + 2
63
73
  result = GC::Tracer.start_allocation_tracing do
64
74
  Object.new
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gc_tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Sasada
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-16 00:00:00.000000000 Z
11
+ date: 2014-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler