gc_tracer 0.1.2 → 0.2.0

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: 7ad7a07f89e6474de38728bba4e183173133c727
4
- data.tar.gz: 1be0ad94f2746c7fee8880725827a386cde7ef75
3
+ metadata.gz: 830cc27b4a444096a36db13d0425b920cd87c8e4
4
+ data.tar.gz: a331e1b13ea0f3c61af86c166c1592cb21fb67cd
5
5
  SHA512:
6
- metadata.gz: b3410157161b046b7870da5caae27c0be60968c825f38908a18907e7ee8941effa28240e32f05ce769a5ad459064ec9784b0ec42746c989d486b2b2a65805c45
7
- data.tar.gz: a168bf9cd168fbc5d4c80eacfb44d4b7dcc52053f5ba89bf821bb7a372dd874e9b06ed65073c21a02eda04b34321d6ee484a06513d5d42dac8b4cb95b053200c
6
+ metadata.gz: 61150fdea8743a53a2f2d7954d2cb969e75ff46b23ddb7bbb50afaccb2885632067533b10c5bac91b2fe393d8cd739b59eb3de16b521ed4869cdb6c18dfcdbd0
7
+ data.tar.gz: 66bcc1e1a75d05caf7dc54a655a4ebc657db34fb9fa6410dbef5faebeb0783248851cbf9ea8ae1936a2348d95c0232ceddd22979494516d9268e80818a46287b
data/README.md CHANGED
@@ -20,6 +20,12 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
+ gc_tracer gem adds GC::Tracer module. GC::Tracer module has the following features.
24
+
25
+ - Logging GC statistics information
26
+ - Allocation tracing information
27
+ - ObjectSpace recorder
28
+
23
29
  ### Logging
24
30
 
25
31
  You can get GC statistics information in block form like this:
@@ -54,6 +60,69 @@ at each events, there are one of:
54
60
 
55
61
  For one GC, you can get all three lines.
56
62
 
63
+ ### Allocation tracing
64
+
65
+ You can trace allocation information and you can get aggregated information.
66
+
67
+ ```ruby
68
+ require 'gc_tracer'
69
+ require 'pp'
70
+
71
+ pp GC::Tracer.start_allocation_tracing{
72
+ 50_000.times{|i|
73
+ i.to_s
74
+ i.to_s
75
+ i.to_s
76
+ }
77
+ }
78
+ ```
79
+
80
+ will show
81
+
82
+ ```
83
+ {["test.rb", 6]=>[50000, 44290, 0, 6],
84
+ ["test.rb", 7]=>[50000, 44289, 0, 5],
85
+ ["test.rb", 8]=>[50000, 44295, 0, 6]}
86
+ ```
87
+
88
+ In this case, 50,000 objects are created at `test.rb:6'. 44,290 is total
89
+ age of objects created at this line. Average age of object created at
90
+ this line is 50000/44290 = 0.8858. 0 is minimum age and 6 is maximum age.
91
+
92
+ Simply you can require `gc_tracer/allocation_trace' to start allocation
93
+ tracer and output the aggregated information into stdot at the end of
94
+ program.
95
+
96
+ ```ruby
97
+ require 'gc_tracer/allocation_trace'
98
+
99
+ # Run your program here
100
+ 50_000.times{|i|
101
+ i.to_s
102
+ i.to_s
103
+ i.to_s
104
+ }
105
+ ```
106
+
107
+ and you will see:
108
+
109
+ ```
110
+ file line count total_age max_age min_age
111
+ .../lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb 55 18 23 1 6
112
+ .../gc_tracer/lib/gc_tracer/allocation_trace.rb 5 2 12 6 6
113
+ .../gc_tracer/lib/gc_tracer/allocation_trace.rb 6 2 0 0 0
114
+ test.rb 0 1 0 0 0
115
+ test.rb 5 50000 41574 0 5
116
+ test.rb 6 50000 41566 0 4
117
+ test.rb 7 50000 41574 0 5
118
+ ```
119
+
120
+ (tab separated colums)
121
+
122
+ This feature is similar to https://github.com/SamSaffron/memory_profiler
123
+ and https://github.com/srawlins/allocation_stats. But this feature
124
+ focused on `age' of objects.
125
+
57
126
  ### ObjectSpace recorder
58
127
 
59
128
  You can records objspace snapshots on each events. Snapshots are stored
@@ -77,7 +146,7 @@ You can view all converted png images with "dirname/viewer.html" file in animati
77
146
 
78
147
  This feature is supported only latest Ruby versions (2.2, and later).
79
148
 
80
- #### Examaple
149
+ #### Example
81
150
 
82
151
  ```ruby
83
152
  require 'gc_tracer'
@@ -0,0 +1,388 @@
1
+ /*
2
+ * allocation tracer: adds GC::Tracer::start_allocation_tracing
3
+ *
4
+ * By Koichi Sasada
5
+ * created at Thu Apr 17 03:50:38 2014.
6
+ */
7
+
8
+ #include "ruby/ruby.h"
9
+ #include "ruby/debug.h"
10
+
11
+ struct allocation_info {
12
+ /* all of information don't need marking. */
13
+ int living;
14
+ VALUE flags;
15
+ VALUE klass;
16
+
17
+ /* allocation info */
18
+ const char *path;
19
+ unsigned long line;
20
+ const char *class_path;
21
+ VALUE mid;
22
+ size_t generation;
23
+
24
+ struct allocation_info *next;
25
+ };
26
+
27
+ struct traceobj_arg {
28
+ int running;
29
+ st_table *aggregate_table; /* user defined key -> [count, total_age, max_age, min_age] */
30
+ st_table *object_table; /* obj (VALUE) -> allocation_info */
31
+ st_table *str_table; /* cstr -> refcount */
32
+ struct allocation_info *freed_allocation_info;
33
+ };
34
+
35
+ extern VALUE rb_mGCTracer;
36
+
37
+ static char *
38
+ keep_unique_str(st_table *tbl, const char *str)
39
+ {
40
+ st_data_t n;
41
+
42
+ if (st_lookup(tbl, (st_data_t)str, &n)) {
43
+ char *result;
44
+
45
+ st_insert(tbl, (st_data_t)str, n+1);
46
+ st_get_key(tbl, (st_data_t)str, (st_data_t *)&result);
47
+
48
+ return result;
49
+ }
50
+ else {
51
+ return NULL;
52
+ }
53
+ }
54
+
55
+ static const char *
56
+ make_unique_str(st_table *tbl, const char *str, long len)
57
+ {
58
+ if (!str) {
59
+ return NULL;
60
+ }
61
+ else {
62
+ char *result;
63
+
64
+ if ((result = keep_unique_str(tbl, str)) == NULL) {
65
+ result = (char *)ruby_xmalloc(len+1);
66
+ strncpy(result, str, len);
67
+ result[len] = 0;
68
+ st_add_direct(tbl, (st_data_t)result, 1);
69
+ }
70
+ return result;
71
+ }
72
+ }
73
+
74
+ static void
75
+ delete_unique_str(st_table *tbl, const char *str)
76
+ {
77
+ if (str) {
78
+ st_data_t n;
79
+
80
+ st_lookup(tbl, (st_data_t)str, &n);
81
+ if (n == 1) {
82
+ st_delete(tbl, (st_data_t *)&str, 0);
83
+ ruby_xfree((char *)str);
84
+ }
85
+ else {
86
+ st_insert(tbl, (st_data_t)str, n-1);
87
+ }
88
+ }
89
+ }
90
+
91
+ struct memcmp_key_data {
92
+ const char *path;
93
+ int line;
94
+ };
95
+
96
+ static int
97
+ memcmp_hash_compare(st_data_t a, st_data_t b)
98
+ {
99
+ struct memcmp_key_data *k1 = (struct memcmp_key_data *)a;
100
+ struct memcmp_key_data *k2 = (struct memcmp_key_data *)b;
101
+
102
+ return (k1->path == k2->path && k1->line == k2->line) ? 0 : 1;
103
+ }
104
+
105
+ static st_index_t
106
+ memcmp_hash_hash(st_data_t a)
107
+ {
108
+ struct memcmp_key_data *k1 = (struct memcmp_key_data *)a;
109
+ return (((st_index_t)k1->path) << 8) & (st_index_t)k1->line;
110
+ }
111
+
112
+ static const struct st_hash_type memcmp_hash_type = {
113
+ memcmp_hash_compare, memcmp_hash_hash
114
+ };
115
+
116
+ static struct traceobj_arg *tmp_trace_arg; /* TODO: Do not use global variables */
117
+
118
+ static struct traceobj_arg *
119
+ get_traceobj_arg(void)
120
+ {
121
+ if (tmp_trace_arg == 0) {
122
+ tmp_trace_arg = ALLOC_N(struct traceobj_arg, 1);
123
+ tmp_trace_arg->aggregate_table = st_init_table(&memcmp_hash_type);
124
+ tmp_trace_arg->object_table = st_init_numtable();
125
+ tmp_trace_arg->str_table = st_init_strtable();
126
+ tmp_trace_arg->freed_allocation_info = NULL;
127
+ }
128
+ return tmp_trace_arg;
129
+ }
130
+
131
+ static int
132
+ free_keys_i(st_data_t key, st_data_t value, void *data)
133
+ {
134
+ ruby_xfree((void *)key);
135
+ return ST_CONTINUE;
136
+ }
137
+
138
+ static int
139
+ free_values_i(st_data_t key, st_data_t value, void *data)
140
+ {
141
+ ruby_xfree((void *)value);
142
+ return ST_CONTINUE;
143
+ }
144
+
145
+ static int
146
+ free_key_values_i(st_data_t key, st_data_t value, void *data)
147
+ {
148
+ ruby_xfree((void *)key);
149
+ ruby_xfree((void *)value);
150
+ return ST_CONTINUE;
151
+ }
152
+
153
+ static void
154
+ clear_traceobj_arg(void)
155
+ {
156
+ struct traceobj_arg * arg = get_traceobj_arg();
157
+
158
+ st_foreach(arg->aggregate_table, free_key_values_i, 0);
159
+ st_clear(arg->aggregate_table);
160
+ st_foreach(arg->object_table, free_values_i, 0);
161
+ st_clear(arg->object_table);
162
+ st_foreach(arg->str_table, free_keys_i, 0);
163
+ st_clear(arg->str_table);
164
+ }
165
+
166
+ static struct allocation_info *
167
+ create_allocation_info(void)
168
+ {
169
+ return (struct allocation_info *)ruby_xmalloc(sizeof(struct allocation_info));
170
+ }
171
+
172
+ static void
173
+ free_allocation_info(struct traceobj_arg *arg, struct allocation_info *info)
174
+ {
175
+ delete_unique_str(arg->str_table, info->path);
176
+ delete_unique_str(arg->str_table, info->class_path);
177
+ ruby_xfree(info);
178
+ }
179
+
180
+ static void
181
+ newobj_i(VALUE tpval, void *data)
182
+ {
183
+ struct traceobj_arg *arg = (struct traceobj_arg *)data;
184
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
185
+ VALUE obj = rb_tracearg_object(tparg);
186
+ VALUE path = rb_tracearg_path(tparg);
187
+ 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;
194
+
195
+ if (st_lookup(arg->object_table, (st_data_t)obj, (st_data_t *)&info)) {
196
+ if (info->living) {
197
+ /* do nothing. there is possibility to keep living if FREEOBJ events while suppressing tracing */
198
+ }
199
+ /* reuse info */
200
+ delete_unique_str(arg->str_table, info->path);
201
+ delete_unique_str(arg->str_table, info->class_path);
202
+ }
203
+ else {
204
+ info = create_allocation_info();
205
+ }
206
+
207
+ info->next = NULL;
208
+ info->living = 1;
209
+ info->flags = RBASIC(obj)->flags;
210
+ info->klass = RBASIC_CLASS(obj);
211
+
212
+ info->path = path_cstr;
213
+ info->line = NUM2INT(line);
214
+ info->mid = mid;
215
+ info->class_path = class_path_cstr;
216
+ info->generation = rb_gc_count();
217
+ st_insert(arg->object_table, (st_data_t)obj, (st_data_t)info);
218
+ }
219
+
220
+ #define MAX_KEY_SIZE 4
221
+
222
+ void
223
+ aggregator_i(void *data)
224
+ {
225
+ size_t gc_count = rb_gc_count();
226
+ struct traceobj_arg *arg = (struct traceobj_arg *)data;
227
+ struct allocation_info *info = arg->freed_allocation_info;
228
+
229
+ arg->freed_allocation_info = NULL;
230
+
231
+ while (info) {
232
+ struct allocation_info *next_info = info->next;
233
+ st_data_t key, val;
234
+ struct memcmp_key_data key_data;
235
+ int *val_buff;
236
+ int age = (int)(gc_count - info->generation);
237
+
238
+ key_data.path = info->path;
239
+ key_data.line = info->line;
240
+ key = (st_data_t)&key_data;
241
+ keep_unique_str(arg->str_table, info->path);
242
+
243
+ 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;
246
+ key = (st_data_t)key_buff;
247
+
248
+ /* count, total age, max age, min age */
249
+ val_buff = ALLOC_N(int, 4);
250
+ val_buff[0] = val_buff[1] = 0;
251
+ val_buff[2] = val_buff[3] = age;
252
+
253
+ st_insert(arg->aggregate_table, (st_data_t)key_buff, (st_data_t)val_buff);
254
+ }
255
+ else {
256
+ val_buff = (int *)val;
257
+ }
258
+
259
+ val_buff[0] += 1;
260
+ val_buff[1] += age;
261
+ if (val_buff[2] > age) val_buff[2] = age;
262
+ if (val_buff[3] < age) val_buff[3] = age;
263
+
264
+ free_allocation_info(arg, info);
265
+ info = next_info;
266
+ }
267
+ }
268
+
269
+ static void
270
+ move_to_freed_list(struct traceobj_arg *arg, VALUE obj, struct allocation_info *info)
271
+ {
272
+ info->next = arg->freed_allocation_info;
273
+ arg->freed_allocation_info = info;
274
+ st_delete(arg->object_table, (st_data_t *)&obj, (st_data_t *)&info);
275
+ }
276
+
277
+ static void
278
+ freeobj_i(VALUE tpval, void *data)
279
+ {
280
+ struct traceobj_arg *arg = (struct traceobj_arg *)data;
281
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
282
+ VALUE obj = rb_tracearg_object(tparg);
283
+ struct allocation_info *info;
284
+
285
+ if (arg->freed_allocation_info == NULL) {
286
+ rb_postponed_job_register_one(0, aggregator_i, arg);
287
+ }
288
+
289
+ if (st_lookup(arg->object_table, (st_data_t)obj, (st_data_t *)&info)) {
290
+ move_to_freed_list(arg, obj, info);
291
+ }
292
+ }
293
+
294
+ static void
295
+ start_alloc_hooks(VALUE mod)
296
+ {
297
+ VALUE newobj_hook, freeobj_hook;
298
+ struct traceobj_arg *arg = get_traceobj_arg();
299
+
300
+ if ((newobj_hook = rb_ivar_get(rb_mGCTracer, rb_intern("newobj_hook"))) == Qnil) {
301
+ rb_ivar_set(rb_mGCTracer, rb_intern("newobj_hook"), newobj_hook = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, arg));
302
+ rb_ivar_set(rb_mGCTracer, rb_intern("freeobj_hook"), freeobj_hook = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, arg));
303
+ }
304
+ else {
305
+ freeobj_hook = rb_ivar_get(rb_mGCTracer, rb_intern("freeobj_hook"));
306
+ }
307
+
308
+ rb_tracepoint_enable(newobj_hook);
309
+ rb_tracepoint_enable(freeobj_hook);
310
+ }
311
+
312
+ static int
313
+ aggregate_result_i(st_data_t key, st_data_t val, void *data)
314
+ {
315
+ VALUE result = (VALUE)data;
316
+ int *val_buff = (int *)val;
317
+ 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
+ VALUE v = rb_ary_new3(4, INT2FIX(val_buff[0]), INT2FIX(val_buff[1]), INT2FIX(val_buff[2]), INT2FIX(val_buff[3]));
320
+
321
+ rb_hash_aset(result, k, v);
322
+
323
+ return ST_CONTINUE;
324
+ }
325
+
326
+ static int
327
+ aggregate_rest_object_i(st_data_t key, st_data_t val, void *data)
328
+ {
329
+ struct traceobj_arg *arg = (struct traceobj_arg *)data;
330
+ struct allocation_info *info = (struct allocation_info *)val;
331
+ move_to_freed_list(arg, (VALUE)key, info);
332
+ return ST_CONTINUE;
333
+ }
334
+
335
+ static VALUE
336
+ aggregate_result(struct traceobj_arg *arg)
337
+ {
338
+ VALUE result = rb_hash_new();
339
+ st_foreach(arg->object_table, aggregate_rest_object_i, (st_data_t)arg);
340
+ aggregator_i(arg);
341
+ st_foreach(arg->aggregate_table, aggregate_result_i, (st_data_t)result);
342
+ clear_traceobj_arg();
343
+ return result;
344
+ }
345
+
346
+ static VALUE
347
+ stop_allocation_tracing(VALUE self)
348
+ {
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"));
351
+
352
+ /* stop hooks */
353
+ if (newobj_hook && freeobj_hook) {
354
+ rb_tracepoint_disable(newobj_hook);
355
+ rb_tracepoint_disable(freeobj_hook);
356
+ }
357
+ else {
358
+ rb_raise(rb_eRuntimeError, "not started yet.");
359
+ }
360
+
361
+ return Qnil;
362
+ }
363
+
364
+ VALUE
365
+ gc_tracer_stop_allocation_tracing(VALUE self)
366
+ {
367
+ stop_allocation_tracing(self);
368
+ return aggregate_result(get_traceobj_arg());
369
+ }
370
+
371
+ VALUE
372
+ gc_tracer_start_allocation_tracing(int argc, VALUE *argv, VALUE self)
373
+ {
374
+ if (rb_ivar_get(rb_mGCTracer, rb_intern("allocation_tracer")) != Qnil) {
375
+ rb_raise(rb_eRuntimeError, "can't run recursive");
376
+ }
377
+ else {
378
+ start_alloc_hooks(rb_mGCTracer);
379
+
380
+ if (rb_block_given_p()) {
381
+ rb_ensure(rb_yield, Qnil, stop_allocation_tracing, Qnil);
382
+ return aggregate_result(get_traceobj_arg());
383
+ }
384
+ }
385
+
386
+ return Qnil;
387
+ }
388
+
@@ -781,6 +781,10 @@ 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);
785
+ VALUE gc_tracer_stop_allocation_tracing(VALUE self);
786
+ VALUE rb_mGCTracer;
787
+
784
788
  /**
785
789
  * GC::Tracer traces GC/ObjectSpace behavior.
786
790
  *
@@ -801,7 +805,7 @@ gc_tracer_start_objspace_recording(int argc, VALUE *argv, VALUE self)
801
805
  void
802
806
  Init_gc_tracer(void)
803
807
  {
804
- VALUE mod = rb_define_module_under(rb_mGC, "Tracer");
808
+ VALUE mod = rb_mGCTracer = rb_define_module_under(rb_mGC, "Tracer");
805
809
 
806
810
  /* logging methods */
807
811
  rb_define_module_function(mod, "start_logging", gc_tracer_start_logging, -1);
@@ -814,6 +818,10 @@ Init_gc_tracer(void)
814
818
  rb_define_module_function(mod, "stop_objspace_recording", gc_tracer_stop_objspace_recording, 0);
815
819
  #endif
816
820
 
821
+ /* allocation tracer methods */
822
+ rb_define_module_function(mod, "start_allocation_tracing", gc_tracer_start_allocation_tracing, -1);
823
+ rb_define_module_function(mod, "stop_allocation_tracing", gc_tracer_stop_allocation_tracing, 0);
824
+
817
825
  /* setup default banners */
818
826
  setup_gc_trace_symbols();
819
827
  start_tick = tick();
@@ -0,0 +1,10 @@
1
+ require 'gc_tracer'
2
+
3
+ GC::Tracer.start_allocation_tracing
4
+
5
+ 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|
8
+ puts (k+v).join("\t")
9
+ }
10
+ }
@@ -1,3 +1,3 @@
1
1
  module GC::Tracer
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -29,20 +29,20 @@ describe GC::Tracer do
29
29
  end
30
30
 
31
31
  shared_examples "objspace_recorder_test" do
32
- DIRNAME = "gc_tracer_objspace_recorder_spec.#{$$}"
32
+ dirname = "gc_tracer_objspace_recorder_spec.#{$$}"
33
33
 
34
34
  it do
35
35
  begin
36
- GC::Tracer.start_objspace_recording(DIRNAME){
36
+ GC::Tracer.start_objspace_recording(dirname){
37
37
  count.times{
38
38
  GC.start
39
39
  }
40
40
  }
41
- expect(Dir.glob("#{DIRNAME}/ppm/*.ppm").size).to be >= count * 3
41
+ expect(Dir.glob("#{dirname}/ppm/*.ppm").size).to be >= count * 3
42
42
  rescue NoMethodError
43
43
  pending "start_objspace_recording requires MRI >= 2.2"
44
44
  ensure
45
- FileUtils.rm_rf(DIRNAME) if File.directory?(DIRNAME)
45
+ FileUtils.rm_rf(dirname) if File.directory?(dirname)
46
46
  end
47
47
  end
48
48
  end
@@ -56,4 +56,16 @@ describe GC::Tracer do
56
56
  let(:count){2}
57
57
  it_behaves_like "objspace_recorder_test"
58
58
  end
59
+
60
+ describe 'GC::Tracer.start_allocation_tracing' do
61
+ it 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
+ end
59
71
  end
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.1.2
4
+ version: 0.2.0
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-06 00:00:00.000000000 Z
11
+ date: 2014-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,10 +81,12 @@ files:
81
81
  - README.md
82
82
  - Rakefile
83
83
  - bin/objspace_recorder_convert.rb
84
+ - ext/gc_tracer/allocation_tracer.c
84
85
  - ext/gc_tracer/extconf.rb
85
86
  - ext/gc_tracer/gc_tracer.c
86
87
  - gc_tracer.gemspec
87
88
  - lib/gc_tracer.rb
89
+ - lib/gc_tracer/allocation_trace.rb
88
90
  - lib/gc_tracer/version.rb
89
91
  - lib/gc_tracer/viewer.html.erb
90
92
  - public/jquery-2.1.0.min.js