gc_tracer 1.0.0 → 1.0.1

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: e93e7dfe6c23589a2f0fe11353cffb53dc903632
4
- data.tar.gz: 2cb9278fbf2b4ba77e809b05421e1c5593cb3336
3
+ metadata.gz: 2fd802669a217a30e27978a50adfca22bac7bafd
4
+ data.tar.gz: 02fbf3dbdfe74e7b65a48a0b0c0644e703fb9eda
5
5
  SHA512:
6
- metadata.gz: f9ae74ac0d8577dd8b48b4bfaddaeb85af2aedbf70838b0f796b6eaf65193300d6e41804d28dda93861fb4b211b6bf1c71586850a811b49c390df741b18c0543
7
- data.tar.gz: a1c6d9e8b33f96f664894462750add5481e7ea90ef2420742ecb030b2bd39e5ac9c9dba017e5c58b8ddea99292f9ee9c4b98a2919b23337bc026eec04d0181f3
6
+ metadata.gz: 0a2e58aa4a810b2e6a68d4391e1b9e8a23bba9f4e7e346c880af0c79c04da694e5390371c73985b2695af6f5d3c604059424fab5327db886dac999ece4daad86
7
+ data.tar.gz: 808239ff54643a9b65ccf516db5d3ca24abd26ca7924a260b6e541a6f2394c34fec5b94c1431bf56123617f7f51b718dc120d193a1c356bec33e39ef55f5e29f
data/README.md CHANGED
@@ -95,8 +95,8 @@ Above example means that no details information are not needed. Default
95
95
  setting is "gc_stat: true, gc_latest_gc_info: true, rusage: false".
96
96
 
97
97
  You can specify tick (time stamp) type with keyword parameter
98
- "tick_type". You can choose one of the tick type in :hw_counter, :time,
99
- :user_time and :system_time.
98
+ "tick_type". You can choose one of the tick type in :hw_counter, :time
99
+ and :nano_time.
100
100
 
101
101
  See lib/gc_tracer.rb for more details.
102
102
 
@@ -38,6 +38,10 @@ if have_header('sys/time.h') && have_header('sys/resource.h') && have_func('getr
38
38
  }
39
39
  end
40
40
 
41
+ if have_header('time.h')
42
+ have_func('clock_gettime')
43
+ end
44
+
41
45
  open("gc_tracer.h", 'w'){|f|
42
46
  f.puts '#include "ruby/ruby.h"'
43
47
  f.puts "static VALUE sym_gc_stat[#{GC.stat.keys.size}];"
@@ -5,874 +5,6 @@
5
5
  * created at Wed Feb 26 10:52:59 2014.
6
6
  */
7
7
 
8
- #if 0
9
- #include "ruby/ruby.h"
10
- #include "ruby/debug.h"
11
- #include "gc_tracer.h"
12
- #include <stdio.h>
13
- #include <assert.h>
14
-
15
- #ifdef HAVE_RB_OBJ_GC_FLAGS
16
- size_t rb_obj_gc_flags(VALUE obj, ID* flags, size_t max);
17
- static ID id_young;
18
- #endif
19
-
20
- struct gc_hooks {
21
- VALUE hooks[3];
22
- VALUE enabled;
23
- void (*funcs[3])(FILE *, void *data, int event_index);
24
- void *args[3];
25
- void *data;
26
- FILE *out;
27
- };
28
-
29
- static const char * const event_names[] = {
30
- "gc_start",
31
- "gc_end_m",
32
- "gc_end_s",
33
- "gc_enter",
34
- "gc_exit_"
35
- };
36
-
37
- /* common funcs */
38
-
39
- static void
40
- gc_start_i(VALUE tpval, void *data)
41
- {
42
- struct gc_hooks *hooks = (struct gc_hooks *)data;
43
- (*hooks->funcs[0])(hooks->out, hooks->args[0], 0);
44
- }
45
-
46
- static void
47
- gc_end_mark_i(VALUE tpval, void *data)
48
- {
49
- struct gc_hooks *hooks = (struct gc_hooks *)data;
50
- (*hooks->funcs[1])(hooks->out, hooks->args[1], 1);
51
- }
52
-
53
- static void
54
- gc_end_sweep_i(VALUE tpval, void *data)
55
- {
56
- struct gc_hooks *hooks = (struct gc_hooks *)data;
57
- (*hooks->funcs[2])(hooks->out, hooks->args[2], 2);
58
- }
59
-
60
- static void
61
- create_gc_hooks(struct gc_hooks *hooks)
62
- {
63
- if (hooks->hooks[0] == 0) {
64
- int i;
65
-
66
- hooks->hooks[0] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_START, gc_start_i, hooks);
67
- hooks->hooks[1] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_END_MARK, gc_end_mark_i, hooks);
68
- hooks->hooks[2] = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP, gc_end_sweep_i, hooks);
69
-
70
- /* mark for GC */
71
- for (i=0; i<3; i++) rb_gc_register_mark_object(hooks->hooks[i]);
72
- }
73
- }
74
-
75
- static void
76
- start_gc_hooks(struct gc_hooks *hooks)
77
- {
78
- if (hooks->enabled == Qfalse) {
79
- int i;
80
- hooks->enabled = Qtrue;
81
- for (i=0; i<3; i++) {
82
- rb_tracepoint_enable(hooks->hooks[i]);
83
- }
84
- }
85
- }
86
-
87
- static void
88
- stop_gc_hooks(struct gc_hooks *hooks)
89
- {
90
- hooks->enabled = Qfalse;
91
-
92
- if (hooks->hooks[0] != 0) {
93
- rb_tracepoint_disable(hooks->hooks[0]);
94
- rb_tracepoint_disable(hooks->hooks[1]);
95
- rb_tracepoint_disable(hooks->hooks[2]);
96
- }
97
- }
98
-
99
- /* logger */
100
-
101
- struct gc_hooks logger;
102
- static VALUE gc_trace_items, gc_trace_items_types;
103
-
104
- #ifdef HAVE_GETRUSAGE
105
- #include <sys/time.h>
106
- #include <sys/resource.h>
107
- #endif
108
-
109
- enum gc_key_type {
110
- GC_STAT_KEY,
111
- GC_LATEST_GC_INFO_KEY,
112
- #ifdef HAVE_GETRUSAGE
113
- GC_RUSAGE_TIMEVAL_KEY,
114
- GC_RUSAGE_KEY,
115
- #endif
116
- };
117
-
118
-
119
- static void
120
- out_header(FILE *out, VALUE items, int need_type)
121
- {
122
- int i;
123
-
124
- out_str(out, "tick");
125
- if (need_type) out_str(out, "type");
126
-
127
- for (i=0; i<RARRAY_LEN(items); i++) {
128
- out_str(out, rb_id2name(SYM2ID(RARRAY_AREF(items, i))));
129
- }
130
-
131
- out_terminate(out);
132
- }
133
-
134
- #ifdef HAVE_GETRUSAGE
135
- struct rusage_cache {
136
- int cached;
137
- struct rusage usage;
138
- };
139
-
140
- static void
141
- getursage_fill(struct rusage_cache *rusage_cache)
142
- {
143
- if (!rusage_cache->cached) {
144
- rusage_cache->cached = 1;
145
- getrusage(RUSAGE_SELF, &rusage_cache->usage);
146
- }
147
- }
148
-
149
- static double
150
- timeval2double(struct timeval *tv)
151
- {
152
- return tv->tv_sec * 1000000 + tv->tv_usec;
153
- }
154
-
155
- static double
156
- getrusage_timeval(VALUE sym, struct rusage_cache *rusage_cache)
157
- {
158
- getursage_fill(rusage_cache);
159
-
160
- if (sym == sym_rusage_timeval[0]) {
161
- return timeval2double(&rusage_cache->usage.ru_utime);
162
- }
163
- if (sym == sym_rusage_timeval[1]) {
164
- return timeval2double(&rusage_cache->usage.ru_stime);
165
- }
166
-
167
- rb_raise(rb_eRuntimeError, "getrusage_timeval: unknown symbol");
168
- return 0;
169
- }
170
-
171
- static size_t
172
- getrusage_sizet(VALUE sym, struct rusage_cache *rusage_cache)
173
- {
174
- int i = 0;
175
-
176
- getursage_fill(rusage_cache);
177
-
178
- #if HAVE_ST_RU_MAXRSS
179
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_maxrss;
180
- #endif
181
- #if HAVE_ST_RU_IXRSS
182
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_ixrss;
183
- #endif
184
- #if HAVE_ST_RU_IDRSS
185
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_idrss;
186
- #endif
187
- #if HAVE_ST_RU_ISRSS
188
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_isrss;
189
- #endif
190
- #if HAVE_ST_RU_MINFLT
191
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_minflt;
192
- #endif
193
- #if HAVE_ST_RU_MAJFLT
194
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_majflt;
195
- #endif
196
- #if HAVE_ST_RU_NSWAP
197
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_nswap;
198
- #endif
199
- #if HAVE_ST_RU_INBLOCK
200
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_inblock;
201
- #endif
202
- #if HAVE_ST_RU_OUBLOCK
203
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_oublock;
204
- #endif
205
- #if HAVE_ST_RU_MSGSND
206
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_msgsnd;
207
- #endif
208
- #if HAVE_ST_RU_MSGRCV
209
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_msgrcv;
210
- #endif
211
- #if HAVE_ST_RU_NSIGNALS
212
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_nsignals;
213
- #endif
214
- #if HAVE_ST_RU_NVCSW
215
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_nvcsw;
216
- #endif
217
- #if HAVE_ST_RU_NIVCSW
218
- if (sym == sym_rusage[i++]) return rusage_cache->usage.ru_nivcsw;
219
- #endif
220
-
221
- rb_raise(rb_eRuntimeError, "getrusage_sizet: unknown symbol");
222
- return 0;
223
- }
224
- #endif
225
-
226
- static void
227
- out_items(FILE *out, VALUE items, VALUE items_types)
228
- {
229
- int i;
230
- #ifdef HAVE_GETRUSAGE
231
- struct rusage_cache rusage_cache = {0};
232
- #endif
233
-
234
- for (i=0; i<RARRAY_LEN(items); i++) {
235
- enum gc_key_type type = FIX2INT(RARRAY_AREF(items_types, i));
236
- VALUE sym = RARRAY_AREF(items, i);
237
-
238
- switch (type) {
239
- case GC_STAT_KEY:
240
- out_sizet(out, rb_gc_stat(sym));
241
- break;
242
- case GC_LATEST_GC_INFO_KEY:
243
- out_obj(out, rb_gc_latest_gc_info(sym));
244
- break;
245
- #ifdef HAVE_GETRUSAGE
246
- case GC_RUSAGE_TIMEVAL_KEY:
247
- out_sizet(out, (size_t)getrusage_timeval(sym, &rusage_cache));
248
- break;
249
- case GC_RUSAGE_KEY:
250
- out_sizet(out, getrusage_sizet(sym, &rusage_cache));
251
- break;
252
- #endif
253
- default:
254
- rb_bug("xyzzy");
255
- }
256
- }
257
- }
258
-
259
- static void
260
- trace(FILE *out, void *data, int event_index)
261
- {
262
- const char *type = (const char *)data;
263
-
264
- out_tick(out);
265
- out_str(out, type);
266
- out_items(out, gc_trace_items, gc_trace_items_types);
267
- out_terminate(out);
268
- }
269
-
270
- static void
271
- close_output(FILE *out)
272
- {
273
- fflush(out);
274
- if (out != stderr) {
275
- fclose(out);
276
- }
277
- }
278
-
279
- static FILE *
280
- open_output(int argc, VALUE *argv)
281
- {
282
- FILE *out = NULL;
283
-
284
- /* setup with args */
285
- if (argc == 0) {
286
- out = stderr;
287
- }
288
- else if (argc == 1) {
289
- if (RB_TYPE_P(argv[0], T_STRING)) {
290
- const char *filename = StringValueCStr(argv[0]);
291
- if ((out = fopen(filename, "w")) == NULL) {
292
- rb_raise(rb_eRuntimeError, "can not open file: %s\n", filename);
293
- }
294
- }
295
- }
296
- else {
297
- rb_raise(rb_eArgError, "too many arguments");
298
- }
299
-
300
- return out;
301
- }
302
-
303
- static VALUE
304
- gc_tracer_stop_logging(VALUE self)
305
- {
306
- if (logger.enabled) {
307
- close_output(logger.out);
308
- logger.out = NULL;
309
- stop_gc_hooks(&logger);
310
- }
311
-
312
- return Qnil;
313
- }
314
-
315
- static VALUE
316
- gc_tracer_start_logging(int argc, VALUE *argv, VALUE self)
317
- {
318
- if (logger.enabled == Qfalse) {
319
- int i;
320
-
321
- logger.out = open_output(argc, argv);
322
- out_header(logger.out, gc_trace_items, 1);
323
-
324
- for (i=0; i<3; i++) {
325
- logger.funcs[i] = trace;
326
- logger.args[i] = (void *)event_names[i];
327
- }
328
-
329
- create_gc_hooks(&logger);
330
- start_gc_hooks(&logger);
331
-
332
- if (rb_block_given_p()) {
333
- rb_ensure(rb_yield, Qnil, gc_tracer_stop_logging, Qnil);
334
- }
335
- }
336
-
337
- return Qnil;
338
- }
339
-
340
- static enum gc_key_type
341
- item_type(VALUE sym)
342
- {
343
- int i;
344
- for (i=0; i<(int)(sizeof(sym_gc_stat)/sizeof(VALUE)); i++) {
345
- if (sym_gc_stat[i] == sym) return GC_STAT_KEY;
346
- }
347
- for (i=0; i<(int)(sizeof(sym_latest_gc_info)/sizeof(VALUE)); i++) {
348
- if (sym_latest_gc_info[i] == sym) return GC_LATEST_GC_INFO_KEY;
349
- }
350
- #ifdef HAVE_GETRUSAGE
351
- for (i=0; i<(int)(sizeof(sym_rusage_timeval)/sizeof(VALUE)); i++) {
352
- if (sym_rusage_timeval[i] == sym) return GC_RUSAGE_TIMEVAL_KEY;
353
- }
354
- for (i=0; i<(int)(sizeof(sym_rusage)/sizeof(VALUE)); i++) {
355
- if (sym_rusage[i] == sym) return GC_RUSAGE_KEY;
356
- }
357
- #endif
358
- rb_raise(rb_eArgError, "Unknown key type");
359
- return 0; /* unreachable */
360
- }
361
-
362
- static void
363
- setup_items(VALUE new_items, VALUE items, VALUE types)
364
- {
365
- VALUE is = rb_ary_new();
366
- VALUE ts = rb_ary_new();
367
- int i;
368
-
369
- if (NIL_P(new_items)) {
370
-
371
- #define ADD(syms) for (i=0; i<(int)(sizeof(syms)/sizeof(VALUE));i++) { \
372
- rb_ary_push(is, syms[i]); \
373
- rb_ary_push(ts, INT2FIX(item_type(syms[i]))); \
374
- }
375
- ADD(sym_gc_stat);
376
- ADD(sym_latest_gc_info);
377
- #ifdef HAVE_GETRUSAGE
378
- ADD(sym_rusage_timeval);
379
- ADD(sym_rusage);
380
- #endif
381
- }
382
- else {
383
- if (!RB_TYPE_P(new_items, T_ARRAY)) rb_raise(rb_eArgError, "unsupported argument");
384
-
385
- for (i=0; i<RARRAY_LEN(new_items); i++) {
386
- VALUE sym = RARRAY_AREF(new_items, i);
387
- enum gc_key_type type;
388
- if (!SYMBOL_P(sym)) rb_raise(rb_eArgError, "unsupported type");
389
- type = item_type(sym);
390
- rb_ary_push(is, sym);
391
- rb_ary_push(ts, INT2FIX(type));
392
- }
393
-
394
- }
395
-
396
- rb_ary_replace(items, is);
397
- rb_ary_replace(types, ts);
398
- }
399
-
400
- static VALUE
401
- gc_tracer_setup_logging(VALUE self, VALUE ary)
402
- {
403
- setup_items(Qnil, gc_trace_items, gc_trace_items_types);
404
- return Qnil;
405
- }
406
-
407
- /* slot logger */
408
-
409
- struct slot_logger {
410
- VALUE hook;
411
- VALUE items;
412
- VALUE items_types;
413
- FILE *out;
414
- VALUE enabled;
415
- } slot_logger;
416
-
417
- static void
418
- newobj_i(VALUE tpval, void *data)
419
- {
420
- struct slot_logger *sl = &slot_logger;
421
-
422
- out_tick(sl->out);
423
- out_items(sl->out, sl->items, sl->items_types);
424
- out_terminate(sl->out);
425
- }
426
-
427
- static void
428
- start_newobj_hook(struct slot_logger *sl)
429
- {
430
- if (sl->hook == 0) {
431
- sl->hook = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, NULL);
432
- rb_gc_register_mark_object(sl->hook);
433
- }
434
- rb_tracepoint_enable(sl->hook);
435
- }
436
-
437
- static void
438
- stop_newobj_hook(struct slot_logger *sl)
439
- {
440
- rb_tracepoint_disable(sl->hook);
441
- }
442
- static VALUE
443
- gc_tracer_stop_slot_logging(VALUE self)
444
- {
445
- if (slot_logger.enabled) {
446
- close_output(slot_logger.out);
447
- slot_logger.out = NULL;
448
- stop_newobj_hook(&slot_logger);
449
- }
450
- return Qnil;
451
- }
452
-
453
- static VALUE
454
- gc_tracer_start_slot_logging(int argc, VALUE *argv, VALUE self)
455
- {
456
- if (slot_logger.enabled == Qfalse) {
457
- slot_logger.enabled = Qtrue;
458
- slot_logger.out = open_output(argc, argv);
459
- out_header(slot_logger.out, slot_logger.items, 0);
460
-
461
- start_newobj_hook(&slot_logger);
462
-
463
- if (rb_block_given_p()) {
464
- rb_ensure(rb_yield, Qnil, gc_tracer_stop_slot_logging, Qnil);
465
- }
466
- }
467
-
468
- return Qnil;
469
- }
470
-
471
- #ifdef HAVE_RB_OBJSPACE_EACH_OBJECTS_WITHOUT_SETUP
472
- /* image logging */
473
-
474
- /* secret API */
475
- void rb_objspace_each_objects_without_setup(int (*callback)(void *, void *, size_t, void *), void *data);
476
-
477
- static struct gc_hooks objspace_recorder;
478
- static int (*objspace_recorder_color_picker)(VALUE);
479
- static int HEAP_OBJ_LIMIT;
480
-
481
- struct objspace_recording_data {
482
- FILE *fp;
483
- int width, height;
484
- };
485
-
486
- struct picker_description {
487
- const char *name;
488
- const int color;
489
- };
490
-
491
- static void
492
- set_color(unsigned char *buff, int color)
493
- {
494
- buff[2] = (color >> 0) & 0xff;
495
- buff[1] = (color >> 8) & 0xff;
496
- buff[0] = (color >> 16) & 0xff;
497
- }
498
-
499
- const int categorical_color10_colors[] = {
500
- 0x1f77b4,
501
- 0xff7f0e,
502
- 0x2ca02c,
503
- 0xd62728,
504
- 0x9467bd,
505
- 0x8c564b,
506
- 0xe377c2,
507
- 0x7f7f7f,
508
- 0xbcbd22,
509
- 0x17becf
510
- };
511
-
512
- static int
513
- categorical_color10(int n)
514
- {
515
- assert(n < 10);
516
- return categorical_color10_colors[n];
517
- }
518
-
519
- const int categorical_color20_colors[] = {
520
- 0x1f77b4,
521
- 0xaec7e8,
522
- 0xff7f0e,
523
- 0xffbb78,
524
- 0x2ca02c,
525
- 0x98df8a,
526
- 0xd62728,
527
- 0xff9896,
528
- 0x9467bd,
529
- 0xc5b0d5,
530
- 0x8c564b,
531
- 0xc49c94,
532
- 0xe377c2,
533
- 0xf7b6d2,
534
- 0x7f7f7f,
535
- 0xc7c7c7,
536
- 0xbcbd22,
537
- 0xdbdb8d,
538
- 0x17becf,
539
- 0x9edae5,
540
- };
541
-
542
- static int
543
- categorical_color20(int n)
544
- {
545
- assert(n < 20);
546
- return categorical_color20_colors[n];
547
- }
548
-
549
- static struct picker_description object_age_picker_description[] = {
550
- {"empty slot", 0},
551
- {"infant slot", 0x1f77b4},
552
- {"young slot", 0xff7f0e},
553
- {"old slot", 0x2ca02c},
554
- {"shady slot", 0xd62728}
555
- };
556
-
557
- static int
558
- object_age_picker(VALUE v) {
559
- if (RB_TYPE_P(v, T_NONE)) {
560
- return 0;
561
- }
562
- else {
563
- if (!OBJ_PROMOTED(v)) {
564
- if (OBJ_WB_PROTECTED(v)) {
565
- return categorical_color10(0); /* infant */
566
- }
567
- else {
568
- return categorical_color10(3); /* shady */
569
- }
570
- }
571
- else {
572
- int is_young = 0;
573
- #ifdef HAVE_RB_OBJ_GC_FLAGS
574
- ID ids[8];
575
- size_t i, count = rb_obj_gc_flags(v, ids, 8);
576
-
577
- for (i=0; i<count; i++) {
578
- if (ids[i] == id_young) {
579
- is_young = 1;
580
- break;
581
- }
582
- }
583
- #endif
584
- if (is_young) {
585
- return categorical_color10(1); /* young */
586
- }
587
- else {
588
- return categorical_color10(2); /* old */
589
- }
590
- }
591
- }
592
- }
593
-
594
- static struct picker_description object_type_picker_description[] = {
595
- {"RUBY_T_NONE", 0},
596
- {"RUBY_T_OBJECT", 0x1f77b4},
597
- {"RUBY_T_CLASS", 0xaec7e8},
598
- {"RUBY_T_MODULE", 0xff7f0e},
599
- {"RUBY_T_FLOAT", 0xffbb78},
600
- {"RUBY_T_STRING", 0x2ca02c},
601
- {"RUBY_T_REGEXP", 0x98df8a},
602
- {"RUBY_T_ARRAY", 0xd62728},
603
- {"RUBY_T_HASH", 0xff9896},
604
- {"RUBY_T_STRUCT", 0x9467bd},
605
- {"RUBY_T_BIGNUM", 0xc5b0d5},
606
- {"RUBY_T_FILE", 0x8c564b},
607
- {"RUBY_T_DATA", 0xc49c94},
608
- {"RUBY_T_MATCH", 0xe377c2},
609
- {"RUBY_T_COMPLEX", 0xf7b6d2},
610
- {"RUBY_T_RATIONAL", 0x7f7f7f},
611
- {"RUBY_T_NODE", 0xc7c7c7},
612
- {"RUBY_T_ICLASS", 0xbcbd22},
613
- {"RUBY_T_ZOMBIE", 0xdbdb8d},
614
- };
615
-
616
- static int
617
- object_type_picker(VALUE v) {
618
- int type = BUILTIN_TYPE(v);
619
- int color = 0;
620
- switch (type) {
621
- case RUBY_T_NONE:
622
- return 0;
623
- case RUBY_T_OBJECT:
624
- case RUBY_T_CLASS:
625
- case RUBY_T_MODULE:
626
- case RUBY_T_FLOAT:
627
- case RUBY_T_STRING:
628
- case RUBY_T_REGEXP:
629
- case RUBY_T_ARRAY:
630
- case RUBY_T_HASH:
631
- case RUBY_T_STRUCT:
632
- case RUBY_T_BIGNUM:
633
- case RUBY_T_FILE:
634
- case RUBY_T_DATA:
635
- case RUBY_T_MATCH:
636
- case RUBY_T_COMPLEX:
637
- case RUBY_T_RATIONAL: /* 0x0f */
638
- color = type - 1;
639
- break;
640
- case RUBY_T_NODE:
641
- case RUBY_T_ICLASS:
642
- case RUBY_T_ZOMBIE:
643
- color = type - 12;
644
- break;
645
- default:
646
- rb_bug("object_type_picker: unreachable (type: %d)", type);
647
- }
648
- return categorical_color20(color);
649
- }
650
-
651
- static int
652
- objspace_recording_i(void *start, void *end, size_t stride, void *data)
653
- {
654
- struct objspace_recording_data *rd = (struct objspace_recording_data *)data;
655
- const int size = ((VALUE)end - (VALUE)start) / stride;
656
- unsigned char *buff = ALLOCA_N(unsigned char, size * 3);
657
- int i, write_result;
658
-
659
- for (i=0; i<size; i++) {
660
- VALUE v = (VALUE)start + i * stride;
661
- set_color(&buff[i*3], (*objspace_recorder_color_picker)(v));
662
- }
663
- for (; i<HEAP_OBJ_LIMIT; i++) {
664
- set_color(&buff[i*3], 0);
665
- }
666
-
667
- write_result = fwrite(buff, 3, HEAP_OBJ_LIMIT, rd->fp);
668
- rd->height++;
669
-
670
- if (0) {
671
- fprintf(stderr, "width: %d, write: %d\n", HEAP_OBJ_LIMIT, write_result);
672
- }
673
-
674
- return 0;
675
- }
676
-
677
- static void
678
- objspace_recording(FILE *dmy, void *data, int event_index)
679
- {
680
- /* const char *event_name = (const char *)data; */
681
- const char *dirname = (const char *)objspace_recorder.data;
682
- char filename[1024];
683
- FILE *fp;
684
- struct objspace_recording_data rd;
685
-
686
- snprintf(filename, 1024, "%s/ppm/%08d.%d.ppm", dirname, (int)rb_gc_count(), event_index);
687
-
688
- if ((fp = fopen(filename, "w")) == NULL) {
689
- rb_bug("objspace_recording: unable to open file: %s", filename);
690
- }
691
- rd.fp = fp;
692
-
693
- /* making dummy header */
694
- /* MG width heigt dep */
695
- fprintf(fp, "P6 wwwww hhhhh 255 ");
696
-
697
- rd.width = HEAP_OBJ_LIMIT;
698
- rd.height = 0;
699
- rb_objspace_each_objects_without_setup(objspace_recording_i, &rd);
700
-
701
- /* fill width and height */
702
- fseek(fp, 3, SEEK_SET);
703
- fprintf(fp, "%5d %5d", rd.width, rd.height);
704
- fclose(fp);
705
- }
706
-
707
- static VALUE
708
- gc_tracer_stop_objspace_recording(VALUE self)
709
- {
710
- if (objspace_recorder.enabled) {
711
- ruby_xfree(objspace_recorder.data);
712
- stop_gc_hooks(&objspace_recorder);
713
- }
714
- return Qnil;
715
- }
716
-
717
- static void
718
- puts_color_description(VALUE dirname, struct picker_description desc[], int n)
719
- {
720
- char buff[0x200];
721
- FILE *fp;
722
- int i;
723
-
724
- snprintf(buff, 0x200, "%s/color_description.txt", RSTRING_PTR(dirname));
725
-
726
- if ((fp = fopen(buff, "w")) == NULL) {
727
- rb_raise(rb_eRuntimeError, "puts_color_description: failed to open file");
728
- }
729
-
730
- for (i=0; i<n; i++) {
731
- fprintf(fp, "%s\t#%06x\n", desc[i].name, desc[i].color);
732
- }
733
-
734
- fclose(fp);
735
- }
736
-
737
-
738
- static VALUE
739
- gc_tracer_start_objspace_recording(int argc, VALUE *argv, VALUE self)
740
- {
741
- if (objspace_recorder.enabled == Qfalse) {
742
- int i;
743
- VALUE ppmdir;
744
- VALUE dirname;
745
- VALUE picker_type = ID2SYM(rb_intern("age"));
746
-
747
- switch (argc) {
748
- case 2:
749
- picker_type = argv[1];
750
- case 1:
751
- dirname = argv[0];
752
- break;
753
- default:
754
- rb_raise(rb_eArgError, "expect 1 or 2 arguments, but %d", argc);
755
- }
756
-
757
- /* setup */
758
- if (rb_funcall(rb_cFile, rb_intern("directory?"), 1, dirname) != Qtrue) {
759
- rb_funcall(rb_cDir, rb_intern("mkdir"), 1, dirname);
760
- }
761
- if (rb_funcall(rb_cFile, rb_intern("directory?"), 1, (ppmdir = rb_str_plus(dirname, rb_str_new2("/ppm")))) != Qtrue) {
762
- rb_funcall(rb_cDir, rb_intern("mkdir"), 1, ppmdir);
763
- }
764
-
765
- if (picker_type == ID2SYM(rb_intern("age"))) {
766
- objspace_recorder_color_picker = object_age_picker;
767
- puts_color_description(dirname, &object_age_picker_description[0], sizeof(object_age_picker_description) / sizeof(struct picker_description));
768
- }
769
- else if (picker_type == ID2SYM(rb_intern("type"))) {
770
- objspace_recorder_color_picker = object_type_picker;
771
- puts_color_description(dirname, &object_type_picker_description[0], sizeof(object_type_picker_description) / sizeof(struct picker_description));
772
- }
773
- else {
774
- rb_raise(rb_eArgError, "unsupported picker type: %s", rb_id2name(SYM2ID(picker_type)));
775
- }
776
-
777
- HEAP_OBJ_LIMIT = FIX2INT(rb_hash_aref(
778
- rb_const_get(rb_mGC, rb_intern("INTERNAL_CONSTANTS")),
779
- ID2SYM(rb_intern("HEAP_OBJ_LIMIT"))));
780
-
781
- for (i=0; i<3; i++) {
782
- objspace_recorder.funcs[i] = objspace_recording;
783
- objspace_recorder.args[i] = (void *)event_names[i];
784
- }
785
-
786
- objspace_recorder.data = ruby_xmalloc(RSTRING_LEN(dirname) + 1);
787
- strcpy((char *)objspace_recorder.data, RSTRING_PTR(dirname));
788
-
789
- create_gc_hooks(&objspace_recorder);
790
- start_gc_hooks(&objspace_recorder);
791
-
792
- if (rb_block_given_p()) {
793
- rb_ensure(rb_yield, Qnil, gc_tracer_stop_objspace_recording, Qnil);
794
- }
795
- }
796
- else {
797
- rb_raise(rb_eRuntimeError, "recursive recording is not permitted");
798
- }
799
-
800
- return Qnil;
801
- }
802
-
803
- #endif /* HAVE_RB_OBJSPACE_EACH_OBJECTS_WITHOUT_SETUP */
804
-
805
-
806
-
807
- /**
808
- * GC::Tracer traces GC/ObjectSpace behavior.
809
- *
810
- * == Logging
811
- *
812
- * GC::Tracer.start_logging(filename) prints GC/ObjectSpace
813
- * information such as GC.stat/GC.latest_gc_info and the result
814
- * of getrlimit() (if supported) into specified `filename' on
815
- * each GC events.
816
- *
817
- * GC events are "start marking", "end of marking" and
818
- * "end of sweeping". You should need to care about lazy sweep.
819
- *
820
- * == ObjectSpace recorder
821
- *
822
- * This feature needs latest Ruby versions (2.2, and later).
823
- */
824
- void
825
- Init_gc_tracer(void)
826
- {
827
- VALUE mod = rb_define_module_under(rb_mGC, "Tracer");
828
-
829
- /* logging methods */
830
- rb_define_module_function(mod, "start_logging", gc_tracer_start_logging, -1);
831
- rb_define_module_function(mod, "stop_logging", gc_tracer_stop_logging, 0);
832
- rb_define_module_function(mod, "setup_logging", gc_tracer_setup_logging, 1);
833
-
834
- rb_define_module_function(mod, "start_slot_logging", gc_tracer_start_slot_logging, -1);
835
- rb_define_module_function(mod, "stop_slot_logging", gc_tracer_stop_slot_logging, 0);
836
-
837
- /* recording methods */
838
- #ifdef HAVE_RB_OBJSPACE_EACH_OBJECTS_WITHOUT_SETUP
839
- rb_define_module_function(mod, "start_objspace_recording", gc_tracer_start_objspace_recording, -1);
840
- rb_define_module_function(mod, "stop_objspace_recording", gc_tracer_stop_objspace_recording, 0);
841
- #endif
842
-
843
- /* setup default banners */
844
- setup_gc_trace_symbols();
845
- start_tick = tick();
846
-
847
- /* warm up */
848
- rb_gc_latest_gc_info(ID2SYM(rb_intern("gc_by")));
849
- rb_gc_stat(ID2SYM(rb_intern("count")));
850
- #ifdef HAVE_RB_OBJ_GC_FLAGS
851
- rb_obj_gc_flags(rb_cObject, NULL, 0);
852
- id_young = rb_intern("young");
853
- #endif
854
-
855
- gc_trace_items = rb_ary_new();
856
- gc_trace_items_types = rb_ary_new();
857
- rb_gc_register_mark_object(gc_trace_items);
858
- rb_gc_register_mark_object(gc_trace_items_types);
859
- setup_items(Qnil, gc_trace_items, gc_trace_items_types);
860
-
861
- /* slot */
862
- slot_logger.items = rb_ary_new();
863
- slot_logger.items_types = rb_ary_new();
864
- rb_gc_register_mark_object(slot_logger.items);
865
- rb_gc_register_mark_object(slot_logger.items_types);
866
- setup_items(rb_ary_new3(4,
867
- ID2SYM(rb_intern("count")),
868
- ID2SYM(rb_intern("heap_live_slot")),
869
- ID2SYM(rb_intern("heap_free_slot")),
870
- ID2SYM(rb_intern("old_object"))),
871
- slot_logger.items, slot_logger.items_types);
872
- }
873
-
874
- #endif
875
-
876
8
  #include <ruby/ruby.h>
877
9
 
878
10
  void Init_gc_tracer_logging(VALUE m_gc_tracer); /* in gc_logging.c */
@@ -1,3 +1,3 @@
1
1
  module GC::Tracer
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
data/lib/gc_tracer.rb CHANGED
@@ -8,7 +8,7 @@ module GC
8
8
  # event filter
9
9
  events: %i(start end_mark end_sweep),
10
10
  # tick type (:hw_counter, :time, :user_time, :system_time)
11
- tick_type: :time,
11
+ tick_type: :nano_time,
12
12
  # collect information
13
13
  gc_stat: true,
14
14
  gc_latest_gc_info: true,
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.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Sasada