gc_tracer 1.0.1 → 1.0.2

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: 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