gc_tracer 1.0.1 → 1.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2fd802669a217a30e27978a50adfca22bac7bafd
4
- data.tar.gz: 02fbf3dbdfe74e7b65a48a0b0c0644e703fb9eda
3
+ metadata.gz: e88092e8af66c335eb5b650723f56a691824bd1e
4
+ data.tar.gz: 19baeffe0a1d32a4630db100ca6f0127a14c4770
5
5
  SHA512:
6
- metadata.gz: 0a2e58aa4a810b2e6a68d4391e1b9e8a23bba9f4e7e346c880af0c79c04da694e5390371c73985b2695af6f5d3c604059424fab5327db886dac999ece4daad86
7
- data.tar.gz: 808239ff54643a9b65ccf516db5d3ca24abd26ca7924a260b6e541a6f2394c34fec5b94c1431bf56123617f7f51b718dc120d193a1c356bec33e39ef55f5e29f
6
+ metadata.gz: 8c6fd1751d1e264920e79af7b3465fd767c4d36290317b444d902d416eef1a61fd8ec374bb406a1522e0ec2f705bf850ad14508967be2ea3acd7a7cfbbfd0c0f
7
+ data.tar.gz: 291863722be9cdc26e7df65e4836f285b9ac1e513d41acdb2a1a1fa1583a624e1dedba70d55378562047aa0ec50704ab8dc5d930fb1288b34bc9755bb907c697
@@ -0,0 +1,586 @@
1
+ /*
2
+ * GC::Tracer::*_logging methods
3
+ */
4
+
5
+ #include <ruby/ruby.h>
6
+ #include <ruby/debug.h>
7
+
8
+ #include <time.h>
9
+
10
+ #ifdef HAVE_GETRUSAGE
11
+ #include <sys/time.h>
12
+ #include <sys/resource.h>
13
+ #endif
14
+
15
+ #include "gc_tracer.h"
16
+
17
+ #if defined(__GNUC__) && defined(__i386__)
18
+ typedef unsigned long long tick_t;
19
+ #define PRItick "llu"
20
+
21
+ static inline tick_t
22
+ tick(void)
23
+ {
24
+ unsigned long long int x;
25
+ __asm__ __volatile__ ("rdtsc" : "=A" (x));
26
+ return x;
27
+ }
28
+
29
+ #elif defined(__GNUC__) && defined(__x86_64__)
30
+ typedef unsigned long long tick_t;
31
+ #define PRItick "llu"
32
+
33
+ static __inline__ tick_t
34
+ tick(void)
35
+ {
36
+ unsigned long hi, lo;
37
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
38
+ return ((unsigned long long)lo)|( ((unsigned long long)hi)<<32);
39
+ }
40
+
41
+ #elif defined(_WIN32) && defined(_MSC_VER)
42
+ #include <intrin.h>
43
+ typedef unsigned __int64 tick_t;
44
+ #define PRItick "llu"
45
+
46
+ static inline tick_t
47
+ tick(void)
48
+ {
49
+ return __rdtsc();
50
+ }
51
+
52
+ #else /* use clock */
53
+ typedef clock_t tick_t;
54
+ static inline tick_t
55
+ #define PRItick "llu"
56
+
57
+ tick(void)
58
+ {
59
+ return clock();
60
+ }
61
+ #endif
62
+
63
+ #ifdef RUBY_INTERNAL_EVENT_GC_ENTER
64
+ #define MAX_HOOKS 7
65
+ #else
66
+ #define MAX_HOOKS 5
67
+ #endif
68
+
69
+ static VALUE tracer_hooks[MAX_HOOKS];
70
+ static VALUE tracer_acceptable_events[MAX_HOOKS];
71
+
72
+ typedef void (*out_time_func_t)(FILE *);
73
+
74
+ struct gc_logging {
75
+ struct config {
76
+ out_time_func_t out_time_func;
77
+ int log_gc_stat;
78
+ int log_gc_latest_gc_info;
79
+ int log_rusage;
80
+ } config;
81
+
82
+ int enabled;
83
+ VALUE enable_hooks[MAX_HOOKS]; /* Symbols */
84
+ int enable_hooks_num; /* 0 to MAX_HOOKS */
85
+
86
+ FILE *out;
87
+ const char *event;
88
+
89
+ #if HAVE_GETRUSAGE
90
+ int filled_rusage;
91
+ struct rusage rusage;
92
+ #endif
93
+ } trace_logging;
94
+
95
+ static void logging_start_i(VALUE tpval, struct gc_logging *logging);
96
+
97
+ #define TRACE_FUNC(name) trace_func_##name
98
+
99
+ #define DEFINE_TRACE_FUNC(name) \
100
+ static void TRACE_FUNC(name)(VALUE tpval, void *data) { \
101
+ struct gc_logging *logging = (struct gc_logging *)data; \
102
+ logging->event = #name; \
103
+ logging_start_i(tpval, logging);\
104
+ }
105
+
106
+ DEFINE_TRACE_FUNC(start);
107
+ DEFINE_TRACE_FUNC(end_mark);
108
+ DEFINE_TRACE_FUNC(end_sweep);
109
+ DEFINE_TRACE_FUNC(newobj);
110
+ DEFINE_TRACE_FUNC(freeobj);
111
+ #ifdef RUBY_INTERNAL_EVENT_GC_ENTER
112
+ DEFINE_TRACE_FUNC(enter);
113
+ DEFINE_TRACE_FUNC(exit);
114
+ #endif
115
+
116
+ /* the following code is only for internal tuning. */
117
+
118
+ /* Source code to use RDTSC is quoted and modified from
119
+ * http://www.mcs.anl.gov/~kazutomo/rdtsc.html
120
+ * written by Kazutomo Yoshii <kazutomo@mcs.anl.gov>
121
+ */
122
+
123
+ static void
124
+ out_str(FILE *out, const char *str)
125
+ {
126
+ fprintf(out, "%s\t", str);
127
+ }
128
+
129
+ static void
130
+ out_terminate(FILE *out)
131
+ {
132
+ fprintf(out, "\n");
133
+ }
134
+
135
+ static void
136
+ out_sizet(FILE *out, size_t size)
137
+ {
138
+ fprintf(out, "%lu\t", (unsigned long)size);
139
+ }
140
+
141
+ static double
142
+ timeval2double(struct timeval *tv)
143
+ {
144
+ return tv->tv_sec * 1000000LL + tv->tv_usec;
145
+ }
146
+
147
+ static void
148
+ fill_rusage(struct gc_logging *logging)
149
+ {
150
+ if (logging->filled_rusage == 0) {
151
+ logging->filled_rusage = 1;
152
+ getrusage(RUSAGE_SELF, &logging->rusage);
153
+ }
154
+ }
155
+
156
+ static void
157
+ out_time_none(FILE *out)
158
+ {
159
+ out_sizet(out, 0);
160
+ }
161
+
162
+ static void
163
+ out_time_hw_counter(FILE *out)
164
+ {
165
+ out_sizet(out, (size_t)tick());
166
+ }
167
+
168
+ static void
169
+ out_time_time(FILE *out)
170
+ {
171
+ struct timeval tv = {0, 0};
172
+ gettimeofday(&tv, NULL);
173
+
174
+ if (tv.tv_sec != 0) {
175
+ fprintf(out, "%lu%06lu\t", (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec);
176
+ }
177
+ else {
178
+ fprintf(out, "%lu\t", (unsigned long)tv.tv_usec);
179
+ }
180
+ }
181
+
182
+ static void
183
+ out_time_nano_time(FILE *out)
184
+ {
185
+ struct timespec ts = {0, 0};
186
+ clock_gettime(CLOCK_MONOTONIC, &ts);
187
+
188
+ if (ts.tv_sec != 0) {
189
+ fprintf(out, "%lu%09lu\t", (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec);
190
+ }
191
+ else {
192
+ fprintf(out, "%lu\t", (unsigned long)ts.tv_nsec);
193
+ }
194
+ }
195
+
196
+ static void
197
+ out_obj(FILE *out, VALUE obj)
198
+ {
199
+ if (NIL_P(obj) || obj == Qfalse) {
200
+ out_sizet(out, 0);
201
+ }
202
+ else if (obj == Qtrue) {
203
+ out_sizet(out, 1);
204
+ }
205
+ else if (SYMBOL_P(obj)) {
206
+ out_str(out, rb_id2name(SYM2ID(obj)));
207
+ }
208
+ else if (FIXNUM_P(obj)) {
209
+ out_sizet(out, FIX2INT(obj));
210
+ }
211
+ else {
212
+ rb_bug("out_obj: unknown object to output");
213
+ }
214
+ }
215
+
216
+ static void
217
+ out_gc_stat(struct gc_logging *logging)
218
+ {
219
+ int i;
220
+ for (i=0; i<(int)(sizeof(sym_gc_stat)/sizeof(VALUE)); i++) {
221
+ VALUE sym = sym_gc_stat[i];
222
+ out_sizet(logging->out, rb_gc_stat(sym));
223
+ }
224
+ }
225
+
226
+ static void
227
+ out_gc_latest_gc_info(struct gc_logging *logging)
228
+ {
229
+ int i;
230
+ for (i=0; i<(int)(sizeof(sym_latest_gc_info)/sizeof(VALUE)); i++) {
231
+ VALUE sym = sym_latest_gc_info[i];
232
+ out_obj(logging->out, rb_gc_latest_gc_info(sym));
233
+ }
234
+ }
235
+
236
+ static void
237
+ out_rusage(struct gc_logging *logging)
238
+ {
239
+ fill_rusage(logging);
240
+
241
+ out_sizet(logging->out, (size_t)timeval2double(&logging->rusage.ru_utime));
242
+ out_sizet(logging->out, (size_t)timeval2double(&logging->rusage.ru_stime));
243
+
244
+ #if HAVE_ST_RU_MAXRSS
245
+ out_sizet(logging->out, logging->rusage.ru_maxrss);
246
+ #endif
247
+ #if HAVE_ST_RU_IXRSS
248
+ out_sizet(logging->out, logging->rusage.ru_ixrss);
249
+ #endif
250
+ #if HAVE_ST_RU_IDRSS
251
+ out_sizet(logging->out, logging->rusage.ru_idrss);
252
+ #endif
253
+ #if HAVE_ST_RU_ISRSS
254
+ out_sizet(logging->out, logging->rusage.ru_isrss);
255
+ #endif
256
+ #if HAVE_ST_RU_MINFLT
257
+ out_sizet(logging->out, logging->rusage.ru_minflt);
258
+ #endif
259
+ #if HAVE_ST_RU_MAJFLT
260
+ out_sizet(logging->out, logging->rusage.ru_majflt);
261
+ #endif
262
+ #if HAVE_ST_RU_NSWAP
263
+ out_sizet(logging->out, logging->rusage.ru_nswap);
264
+ #endif
265
+ #if HAVE_ST_RU_INBLOCK
266
+ out_sizet(logging->out, logging->rusage.ru_inblock);
267
+ #endif
268
+ #if HAVE_ST_RU_OUBLOCK
269
+ out_sizet(logging->out, logging->rusage.ru_oublock);
270
+ #endif
271
+ #if HAVE_ST_RU_MSGSND
272
+ out_sizet(logging->out, logging->rusage.ru_msgsnd);
273
+ #endif
274
+ #if HAVE_ST_RU_MSGRCV
275
+ out_sizet(logging->out, logging->rusage.ru_msgrcv);
276
+ #endif
277
+ #if HAVE_ST_RU_NSIGNALS
278
+ out_sizet(logging->out, logging->rusage.ru_nsignals);
279
+ #endif
280
+ #if HAVE_ST_RU_NVCSW
281
+ out_sizet(logging->out, logging->rusage.ru_nvcsw);
282
+ #endif
283
+ #if HAVE_ST_RU_NIVCSW
284
+ out_sizet(logging->out, logging->rusage.ru_nivcsw);
285
+ #endif
286
+
287
+ }
288
+
289
+ static void
290
+ logging_start_i(VALUE tpval, struct gc_logging *logging)
291
+ {
292
+ #if HAVE_GETRUSAGE
293
+ logging->filled_rusage = 0;
294
+ #endif
295
+
296
+ out_str(logging->out, logging->event);
297
+ (logging->config.out_time_func)(logging->out);
298
+
299
+ if (logging->config.log_gc_stat) out_gc_stat(logging);
300
+ if (logging->config.log_gc_latest_gc_info) out_gc_latest_gc_info(logging);
301
+ #if HAVE_GETRUSAGE
302
+ if (logging->config.log_rusage) out_rusage(logging);
303
+ #endif
304
+ out_terminate(logging->out);
305
+ }
306
+
307
+ static void
308
+ out_header_each(struct gc_logging *logging, VALUE *syms, int n)
309
+ {
310
+ int i;
311
+ for (i=0; i<n; i++) {
312
+ out_obj(logging->out, syms[i]);
313
+ }
314
+ }
315
+
316
+ static void
317
+ out_header(struct gc_logging *logging)
318
+ {
319
+ out_str(logging->out, "type");
320
+ out_str(logging->out, "tick");
321
+
322
+ if (logging->config.log_gc_stat) out_header_each(logging, sym_gc_stat, sizeof(sym_gc_stat)/sizeof(VALUE));
323
+ if (logging->config.log_gc_latest_gc_info) out_header_each(logging, sym_latest_gc_info, sizeof(sym_latest_gc_info)/sizeof(VALUE));
324
+ #if HAVE_GETRUSAGE
325
+ if (logging->config.log_rusage) {
326
+ out_header_each(logging, sym_rusage_timeval, sizeof(sym_rusage_timeval)/sizeof(VALUE));
327
+ out_header_each(logging, sym_rusage, sizeof(sym_rusage)/sizeof(VALUE));
328
+ }
329
+ #endif
330
+ out_terminate(logging->out);
331
+ }
332
+
333
+ static void
334
+ close_output(FILE *out)
335
+ {
336
+ fflush(out);
337
+ if (out != stderr) {
338
+ fclose(out);
339
+ }
340
+ }
341
+
342
+ static void
343
+ create_gc_hooks(void)
344
+ {
345
+ int i = 0;
346
+ struct gc_logging *logging = &trace_logging;
347
+
348
+ tracer_hooks[0] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_START, TRACE_FUNC(start), logging);
349
+ tracer_hooks[1] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_END_MARK, TRACE_FUNC(end_mark), logging);
350
+ tracer_hooks[2] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP, TRACE_FUNC(end_sweep), logging);
351
+ tracer_hooks[3] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, TRACE_FUNC(newobj), logging);
352
+ tracer_hooks[4] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, TRACE_FUNC(freeobj), logging);
353
+
354
+ #ifdef RUBY_INTERNAL_EVENT_GC_ENTER
355
+ tracer_hooks[5] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_ENTER, TRACE_FUNC(enter), logging);
356
+ tracer_hooks[6] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_EXIT, TRACE_FUNC(exit), logging);
357
+ #endif
358
+
359
+ /* mark for GC */
360
+ for (i=0; i<MAX_HOOKS; i++) rb_gc_register_mark_object(tracer_hooks[i]);
361
+
362
+ tracer_acceptable_events[0] = ID2SYM(rb_intern("start"));
363
+ tracer_acceptable_events[1] = ID2SYM(rb_intern("end_mark"));
364
+ tracer_acceptable_events[2] = ID2SYM(rb_intern("end_sweep"));
365
+ tracer_acceptable_events[3] = ID2SYM(rb_intern("newobj"));
366
+ tracer_acceptable_events[4] = ID2SYM(rb_intern("freeobj"));
367
+ #ifdef RUBY_INTERNAL_EVENT_GC_ENTER
368
+ tracer_acceptable_events[5] = ID2SYM(rb_intern("enter"));
369
+ tracer_acceptable_events[6] = ID2SYM(rb_intern("exit"));
370
+ #endif
371
+ }
372
+
373
+ static void
374
+ enable_gc_hooks(struct gc_logging *logging)
375
+ {
376
+ int i;
377
+ for (i=0; i<logging->enable_hooks_num; i++) {
378
+ rb_tracepoint_enable(logging->enable_hooks[i]);
379
+ }
380
+ }
381
+
382
+ static void
383
+ disable_gc_hooks(struct gc_logging *logging)
384
+ {
385
+ int i;
386
+ for (i=0; i<logging->enable_hooks_num; i++) {
387
+ rb_tracepoint_disable(logging->enable_hooks[i]);
388
+ }
389
+ }
390
+
391
+ static VALUE
392
+ gc_tracer_setup_logging_out(VALUE self, VALUE filename)
393
+ {
394
+ struct gc_logging *logging = &trace_logging;
395
+
396
+ if (NIL_P(filename)) {
397
+ logging->out = stderr;
398
+ }
399
+ else {
400
+ filename = rb_check_string_type(filename);
401
+ {
402
+ const char *fname = StringValueCStr(filename);
403
+ FILE *out;
404
+
405
+ if ((out = fopen(fname, "w")) == NULL) {
406
+ rb_raise(rb_eRuntimeError, "can not open file: %s\n", fname);
407
+ }
408
+ logging->out = out;
409
+ }
410
+ }
411
+
412
+ return self;
413
+ }
414
+
415
+ static VALUE
416
+ gc_tracer_setup_logging_events(int argc, VALUE *argv, VALUE self)
417
+ {
418
+ struct gc_logging *logging = &trace_logging;
419
+ int i, n;
420
+ int event_bits = 0;
421
+
422
+ if (argc == 0) {
423
+ /* deafult: start, end_mark, end_sweep */
424
+ for (i=0; i<3; i++) {
425
+ event_bits = 0x07; /* 0b0111 */
426
+ }
427
+ }
428
+ else {
429
+ int j;
430
+ for (i=0; i<argc; i++) {
431
+ for (j=0; j<MAX_HOOKS; j++) {
432
+ if (tracer_acceptable_events[j] == argv[i]) {
433
+ event_bits |= 0x01 << j;
434
+ goto found;
435
+ }
436
+ }
437
+ rb_raise(rb_eArgError, "unsupported GC trace event: %"PRIsVALUE, argv[i]);
438
+ found:;
439
+ }
440
+ }
441
+
442
+ for (n=0, i=0; i<MAX_HOOKS; i++) {
443
+ if (event_bits & (0x01 << i)) {
444
+ logging->enable_hooks[n++] = tracer_hooks[i];
445
+ }
446
+ }
447
+ logging->enable_hooks_num = n;
448
+
449
+ return self;
450
+ }
451
+
452
+ static VALUE
453
+ gc_tracer_setup_logging_tick_type(VALUE self, VALUE sym)
454
+ {
455
+ struct gc_logging *logging = &trace_logging;
456
+ static const char *names[] = {
457
+ "none",
458
+ "hw_counter",
459
+ "time",
460
+ "nano_time"
461
+ };
462
+ static const out_time_func_t funcs[] = {
463
+ out_time_none,
464
+ out_time_hw_counter,
465
+ out_time_time,
466
+ out_time_nano_time
467
+ };
468
+ int i;
469
+
470
+ for (i=0; i<4; i++) {
471
+ if (sym == ID2SYM(rb_intern(names[i]))) {
472
+ logging->config.out_time_func = funcs[i];
473
+ return self;
474
+ }
475
+ }
476
+
477
+ rb_raise(rb_eArgError, "unknown tick type: %"PRIsVALUE, sym);
478
+ return self; /* unreachable */
479
+ }
480
+
481
+ static VALUE
482
+ gc_tracer_setup_logging_gc_stat(VALUE self, VALUE b)
483
+ {
484
+ struct gc_logging *logging = &trace_logging;
485
+
486
+
487
+ if (RTEST(b)) {
488
+ logging->config.log_gc_stat = Qtrue;
489
+ }
490
+ else {
491
+ logging->config.log_gc_stat = Qfalse;
492
+ }
493
+
494
+ return self;
495
+ }
496
+
497
+ static VALUE
498
+ gc_tracer_setup_logging_gc_latest_gc_info(VALUE self, VALUE b)
499
+ {
500
+ struct gc_logging *logging = &trace_logging;
501
+
502
+
503
+ if (RTEST(b)) {
504
+ logging->config.log_gc_latest_gc_info = Qtrue;
505
+ }
506
+ else {
507
+ logging->config.log_gc_latest_gc_info = Qfalse;
508
+ }
509
+
510
+ return self;
511
+ }
512
+
513
+ static VALUE
514
+ gc_tracer_setup_logging_rusage(VALUE self, VALUE b)
515
+ {
516
+ struct gc_logging *logging = &trace_logging;
517
+
518
+
519
+ if (RTEST(b)) {
520
+ logging->config.log_rusage = Qtrue;
521
+ }
522
+ else {
523
+ logging->config.log_rusage = Qfalse;
524
+ }
525
+
526
+ return self;
527
+ }
528
+
529
+ static VALUE
530
+ gc_tracer_start_logging(int argc, VALUE *argv, VALUE self)
531
+ {
532
+ struct gc_logging *logging = &trace_logging;
533
+
534
+ if (logging->enabled == 0) {
535
+ logging->enabled = 1;
536
+ out_header(logging);
537
+ enable_gc_hooks(logging);
538
+ }
539
+
540
+ return self;
541
+ }
542
+
543
+ static VALUE
544
+ gc_tracer_stop_logging(VALUE self)
545
+ {
546
+ struct gc_logging *logging = &trace_logging;
547
+
548
+ if (logging->enabled) {
549
+ close_output(logging->out);
550
+ disable_gc_hooks(logging);
551
+ logging->enabled = 0;
552
+ }
553
+
554
+ return self;
555
+ }
556
+
557
+ void
558
+ Init_gc_tracer_logging(VALUE mod)
559
+ {
560
+ rb_define_module_function(mod, "start_logging_", gc_tracer_start_logging, 0);
561
+ rb_define_module_function(mod, "stop_logging", gc_tracer_stop_logging, 0);
562
+
563
+ /* setup */
564
+ rb_define_module_function(mod, "setup_logging_out", gc_tracer_setup_logging_out, 1);
565
+ rb_define_module_function(mod, "setup_logging_events", gc_tracer_setup_logging_events, -1);
566
+ rb_define_module_function(mod, "setup_logging_tick_type=", gc_tracer_setup_logging_tick_type, 1);
567
+ rb_define_module_function(mod, "setup_logging_gc_stat=", gc_tracer_setup_logging_gc_stat, 1);
568
+ rb_define_module_function(mod, "setup_logging_gc_latest_gc_info=", gc_tracer_setup_logging_gc_latest_gc_info, 1);
569
+ rb_define_module_function(mod, "setup_logging_rusage=", gc_tracer_setup_logging_rusage, 1);
570
+
571
+ /* setup data */
572
+ setup_gc_trace_symbols();
573
+ create_gc_hooks();
574
+ /* warm up */
575
+ rb_gc_latest_gc_info(ID2SYM(rb_intern("gc_by")));
576
+ rb_gc_stat(ID2SYM(rb_intern("count")));
577
+
578
+
579
+ /* default setup */
580
+ gc_tracer_setup_logging_out(Qnil, Qnil);
581
+ gc_tracer_setup_logging_events(0, 0, Qnil);
582
+ gc_tracer_setup_logging_gc_stat(Qnil, Qtrue);
583
+ gc_tracer_setup_logging_gc_latest_gc_info(Qnil, Qtrue);
584
+ gc_tracer_setup_logging_rusage(Qnil, Qfalse);
585
+ trace_logging.config.out_time_func = out_time_nano_time;
586
+ }
@@ -1,3 +1,3 @@
1
1
  module GC::Tracer
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gc_tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Sasada
@@ -82,6 +82,7 @@ files:
82
82
  - Rakefile
83
83
  - bin/objspace_recorder_convert.rb
84
84
  - ext/gc_tracer/extconf.rb
85
+ - ext/gc_tracer/gc_logging.c
85
86
  - ext/gc_tracer/gc_tracer.c
86
87
  - gc_tracer.gemspec
87
88
  - lib/gc_tracer.rb