gc_tracer 0.3.3 → 1.0.0
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 +4 -4
- data/README.md +27 -37
- data/Rakefile +5 -0
- data/ext/gc_tracer/gc_tracer.c +187 -158
- data/lib/gc_tracer/version.rb +1 -1
- data/lib/gc_tracer.rb +35 -0
- data/spec/gc_tracer_spec.rb +2 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e93e7dfe6c23589a2f0fe11353cffb53dc903632
|
4
|
+
data.tar.gz: 2cb9278fbf2b4ba77e809b05421e1c5593cb3336
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9ae74ac0d8577dd8b48b4bfaddaeb85af2aedbf70838b0f796b6eaf65193300d6e41804d28dda93861fb4b211b6bf1c71586850a811b49c390df741b18c0543
|
7
|
+
data.tar.gz: a1c6d9e8b33f96f664894462750add5481e7ea90ef2420742ecb030b2bd39e5ac9c9dba017e5c58b8ddea99292f9ee9c4b98a2919b23337bc026eec04d0181f3
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ Or install it yourself as:
|
|
23
23
|
gc_tracer gem adds GC::Tracer module. GC::Tracer module has the following features.
|
24
24
|
|
25
25
|
- Logging GC statistics information
|
26
|
-
- ObjectSpace recorder
|
26
|
+
- ObjectSpace recorder (not supported yet)
|
27
27
|
|
28
28
|
### Logging
|
29
29
|
|
@@ -56,59 +56,49 @@ In the stored file (filename), you can get tab separated values of:
|
|
56
56
|
|
57
57
|
at each events, there are one of:
|
58
58
|
|
59
|
-
* GC starting time
|
60
|
-
* End of marking time
|
61
|
-
* End of sweeping time
|
59
|
+
* GC starting time (start)
|
60
|
+
* End of marking time (end_mark)
|
61
|
+
* End of sweeping time (end_sweep)
|
62
|
+
* GC enter (enter)
|
63
|
+
* GC exit (exit)
|
64
|
+
* newobj (newobj)
|
65
|
+
* freeobj (freeobj)
|
62
66
|
|
63
67
|
For one GC, you can get all three lines.
|
64
68
|
|
65
|
-
|
66
|
-
|
67
|
-
You can records objspace snapshots on each events. Snapshots are stored
|
68
|
-
in the [PPM (P6) format] (http://en.wikipedia.org/wiki/Netpbm_format).
|
69
|
+
You can specify events by event name symbols you want to show.
|
69
70
|
|
70
71
|
```ruby
|
71
72
|
require 'gc_tracer'
|
72
|
-
|
73
|
+
begin
|
74
|
+
GC::Tracer.start_logging(filename, events: %i(enter exit))
|
73
75
|
# do something
|
76
|
+
ensure
|
77
|
+
GC::Tracer.stop_logging
|
74
78
|
end
|
75
79
|
```
|
76
80
|
|
77
|
-
|
78
|
-
|
79
|
-
If you have netpbm package and pnmtopng command,
|
80
|
-
bin/objspace_recorder_convert.rb converts all ppm images into png files.
|
81
|
-
Converted png images stored into dirname/png/.
|
82
|
-
|
83
|
-
To view converted images, "dirname/viewer.html" is created.
|
84
|
-
You can view all converted png images with "dirname/viewer.html" file in animation.
|
85
|
-
|
86
|
-
This feature is supported only latest Ruby versions (2.2, and later).
|
87
|
-
|
88
|
-
#### Example
|
81
|
+
Default events are "start", "end_mark" and "end_sweep". You can specify
|
82
|
+
what kind of information you want to collect.
|
89
83
|
|
90
84
|
```ruby
|
91
85
|
require 'gc_tracer'
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
m.times{
|
99
|
-
ary << ''
|
100
|
-
}
|
101
|
-
}
|
102
|
-
}
|
86
|
+
begin
|
87
|
+
GC::Tracer.start_logging(filename, gc_stat: false, gc_latest_gc_info: false, rusage: false)
|
88
|
+
# do something
|
89
|
+
ensure
|
90
|
+
GC::Tracer.stop_logging
|
91
|
+
end
|
103
92
|
```
|
104
93
|
|
105
|
-
|
94
|
+
Above example means that no details information are not needed. Default
|
95
|
+
setting is "gc_stat: true, gc_latest_gc_info: true, rusage: false".
|
106
96
|
|
107
|
-
|
108
|
-
|
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.
|
109
100
|
|
110
|
-
|
111
|
-
a [type example] (http://www.atdot.net/~ko1/gc_tracer/objspace_recorded_type_example/viewer.html).
|
101
|
+
See lib/gc_tracer.rb for more details.
|
112
102
|
|
113
103
|
## Contributing
|
114
104
|
|
data/Rakefile
CHANGED
data/ext/gc_tracer/gc_tracer.c
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
* created at Wed Feb 26 10:52:59 2014.
|
6
6
|
*/
|
7
7
|
|
8
|
+
#if 0
|
8
9
|
#include "ruby/ruby.h"
|
9
10
|
#include "ruby/debug.h"
|
10
11
|
#include "gc_tracer.h"
|
@@ -19,15 +20,18 @@ static ID id_young;
|
|
19
20
|
struct gc_hooks {
|
20
21
|
VALUE hooks[3];
|
21
22
|
VALUE enabled;
|
22
|
-
void (*funcs[3])(void *data, int event_index);
|
23
|
+
void (*funcs[3])(FILE *, void *data, int event_index);
|
23
24
|
void *args[3];
|
24
25
|
void *data;
|
26
|
+
FILE *out;
|
25
27
|
};
|
26
28
|
|
27
|
-
static const char *event_names[] = {
|
29
|
+
static const char * const event_names[] = {
|
28
30
|
"gc_start",
|
29
31
|
"gc_end_m",
|
30
|
-
"gc_end_s"
|
32
|
+
"gc_end_s",
|
33
|
+
"gc_enter",
|
34
|
+
"gc_exit_"
|
31
35
|
};
|
32
36
|
|
33
37
|
/* common funcs */
|
@@ -36,21 +40,21 @@ static void
|
|
36
40
|
gc_start_i(VALUE tpval, void *data)
|
37
41
|
{
|
38
42
|
struct gc_hooks *hooks = (struct gc_hooks *)data;
|
39
|
-
(*hooks->funcs[0])(hooks->args[0], 0);
|
43
|
+
(*hooks->funcs[0])(hooks->out, hooks->args[0], 0);
|
40
44
|
}
|
41
45
|
|
42
46
|
static void
|
43
47
|
gc_end_mark_i(VALUE tpval, void *data)
|
44
48
|
{
|
45
49
|
struct gc_hooks *hooks = (struct gc_hooks *)data;
|
46
|
-
(*hooks->funcs[1])(hooks->args[1], 1);
|
50
|
+
(*hooks->funcs[1])(hooks->out, hooks->args[1], 1);
|
47
51
|
}
|
48
52
|
|
49
53
|
static void
|
50
54
|
gc_end_sweep_i(VALUE tpval, void *data)
|
51
55
|
{
|
52
56
|
struct gc_hooks *hooks = (struct gc_hooks *)data;
|
53
|
-
(*hooks->funcs[2])(hooks->args[2], 2);
|
57
|
+
(*hooks->funcs[2])(hooks->out, hooks->args[2], 2);
|
54
58
|
}
|
55
59
|
|
56
60
|
static void
|
@@ -95,7 +99,6 @@ stop_gc_hooks(struct gc_hooks *hooks)
|
|
95
99
|
/* logger */
|
96
100
|
|
97
101
|
struct gc_hooks logger;
|
98
|
-
static FILE *gc_trace_out = NULL;
|
99
102
|
static VALUE gc_trace_items, gc_trace_items_types;
|
100
103
|
|
101
104
|
#ifdef HAVE_GETRUSAGE
|
@@ -112,113 +115,20 @@ enum gc_key_type {
|
|
112
115
|
#endif
|
113
116
|
};
|
114
117
|
|
115
|
-
/* the following code is only for internal tuning. */
|
116
|
-
|
117
|
-
/* Source code to use RDTSC is quoted and modified from
|
118
|
-
* http://www.mcs.anl.gov/~kazutomo/rdtsc.html
|
119
|
-
* written by Kazutomo Yoshii <kazutomo@mcs.anl.gov>
|
120
|
-
*/
|
121
|
-
|
122
|
-
#if defined(__GNUC__) && defined(__i386__)
|
123
|
-
typedef unsigned long long tick_t;
|
124
|
-
|
125
|
-
static inline tick_t
|
126
|
-
tick(void)
|
127
|
-
{
|
128
|
-
unsigned long long int x;
|
129
|
-
__asm__ __volatile__ ("rdtsc" : "=A" (x));
|
130
|
-
return x;
|
131
|
-
}
|
132
|
-
|
133
|
-
#elif defined(__GNUC__) && defined(__x86_64__)
|
134
|
-
typedef unsigned long long tick_t;
|
135
|
-
|
136
|
-
static __inline__ tick_t
|
137
|
-
tick(void)
|
138
|
-
{
|
139
|
-
unsigned long hi, lo;
|
140
|
-
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
|
141
|
-
return ((unsigned long long)lo)|( ((unsigned long long)hi)<<32);
|
142
|
-
}
|
143
|
-
|
144
|
-
#elif defined(_WIN32) && defined(_MSC_VER)
|
145
|
-
#include <intrin.h>
|
146
|
-
typedef unsigned __int64 tick_t;
|
147
|
-
|
148
|
-
static inline tick_t
|
149
|
-
tick(void)
|
150
|
-
{
|
151
|
-
return __rdtsc();
|
152
|
-
}
|
153
|
-
|
154
|
-
#else /* use clock */
|
155
|
-
typedef clock_t tick_t;
|
156
|
-
static inline tick_t
|
157
|
-
tick(void)
|
158
|
-
{
|
159
|
-
return clock();
|
160
|
-
}
|
161
|
-
#endif
|
162
|
-
|
163
|
-
static tick_t start_tick;
|
164
118
|
|
165
119
|
static void
|
166
|
-
|
167
|
-
{
|
168
|
-
fprintf(gc_trace_out, "%s\t", str);
|
169
|
-
}
|
170
|
-
|
171
|
-
static void
|
172
|
-
out_terminate(void)
|
173
|
-
{
|
174
|
-
fprintf(gc_trace_out, "\n");
|
175
|
-
}
|
176
|
-
|
177
|
-
static void
|
178
|
-
out_sizet(size_t size)
|
179
|
-
{
|
180
|
-
fprintf(gc_trace_out, "%lu\t", (unsigned long)size);
|
181
|
-
}
|
182
|
-
|
183
|
-
static void
|
184
|
-
out_tick(void)
|
185
|
-
{
|
186
|
-
out_sizet(tick() - start_tick);
|
187
|
-
}
|
188
|
-
|
189
|
-
static void
|
190
|
-
out_obj(VALUE obj)
|
191
|
-
{
|
192
|
-
if (NIL_P(obj) || obj == Qfalse) {
|
193
|
-
out_sizet(0);
|
194
|
-
}
|
195
|
-
else if (obj == Qtrue) {
|
196
|
-
out_sizet(1);
|
197
|
-
}
|
198
|
-
else if (SYMBOL_P(obj)) {
|
199
|
-
out_str(rb_id2name(SYM2ID(obj)));
|
200
|
-
}
|
201
|
-
else if (FIXNUM_P(obj)) {
|
202
|
-
out_sizet(FIX2INT(obj));
|
203
|
-
}
|
204
|
-
else {
|
205
|
-
rb_bug("out_obj: unknown object to output");
|
206
|
-
}
|
207
|
-
}
|
208
|
-
|
209
|
-
static void
|
210
|
-
out_header(void)
|
120
|
+
out_header(FILE *out, VALUE items, int need_type)
|
211
121
|
{
|
212
122
|
int i;
|
213
123
|
|
214
|
-
out_str("tick");
|
215
|
-
out_str("type");
|
124
|
+
out_str(out, "tick");
|
125
|
+
if (need_type) out_str(out, "type");
|
216
126
|
|
217
|
-
for (i=0; i<RARRAY_LEN(
|
218
|
-
out_str(rb_id2name(SYM2ID(RARRAY_AREF(
|
127
|
+
for (i=0; i<RARRAY_LEN(items); i++) {
|
128
|
+
out_str(out, rb_id2name(SYM2ID(RARRAY_AREF(items, i))));
|
219
129
|
}
|
220
130
|
|
221
|
-
out_terminate();
|
131
|
+
out_terminate(out);
|
222
132
|
}
|
223
133
|
|
224
134
|
#ifdef HAVE_GETRUSAGE
|
@@ -314,54 +224,88 @@ getrusage_sizet(VALUE sym, struct rusage_cache *rusage_cache)
|
|
314
224
|
#endif
|
315
225
|
|
316
226
|
static void
|
317
|
-
|
227
|
+
out_items(FILE *out, VALUE items, VALUE items_types)
|
318
228
|
{
|
319
|
-
const char *type = (const char *)data;
|
320
229
|
int i;
|
321
230
|
#ifdef HAVE_GETRUSAGE
|
322
231
|
struct rusage_cache rusage_cache = {0};
|
323
232
|
#endif
|
324
233
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
for (i=0; i<RARRAY_LEN(gc_trace_items); i++) {
|
329
|
-
enum gc_key_type type = FIX2INT(RARRAY_AREF(gc_trace_items_types, i));
|
330
|
-
VALUE sym = RARRAY_AREF(gc_trace_items, i);
|
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);
|
331
237
|
|
332
238
|
switch (type) {
|
333
239
|
case GC_STAT_KEY:
|
334
|
-
out_sizet(rb_gc_stat(sym));
|
240
|
+
out_sizet(out, rb_gc_stat(sym));
|
335
241
|
break;
|
336
242
|
case GC_LATEST_GC_INFO_KEY:
|
337
|
-
out_obj(rb_gc_latest_gc_info(sym));
|
243
|
+
out_obj(out, rb_gc_latest_gc_info(sym));
|
338
244
|
break;
|
339
245
|
#ifdef HAVE_GETRUSAGE
|
340
246
|
case GC_RUSAGE_TIMEVAL_KEY:
|
341
|
-
out_sizet((size_t)getrusage_timeval(sym, &rusage_cache));
|
247
|
+
out_sizet(out, (size_t)getrusage_timeval(sym, &rusage_cache));
|
342
248
|
break;
|
343
249
|
case GC_RUSAGE_KEY:
|
344
|
-
out_sizet(getrusage_sizet(sym, &rusage_cache));
|
250
|
+
out_sizet(out, getrusage_sizet(sym, &rusage_cache));
|
345
251
|
break;
|
346
252
|
#endif
|
347
253
|
default:
|
348
254
|
rb_bug("xyzzy");
|
349
255
|
}
|
350
256
|
}
|
257
|
+
}
|
351
258
|
|
352
|
-
|
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;
|
353
301
|
}
|
354
302
|
|
355
303
|
static VALUE
|
356
304
|
gc_tracer_stop_logging(VALUE self)
|
357
305
|
{
|
358
306
|
if (logger.enabled) {
|
359
|
-
|
360
|
-
|
361
|
-
fclose(gc_trace_out);
|
362
|
-
}
|
363
|
-
gc_trace_out = NULL;
|
364
|
-
|
307
|
+
close_output(logger.out);
|
308
|
+
logger.out = NULL;
|
365
309
|
stop_gc_hooks(&logger);
|
366
310
|
}
|
367
311
|
|
@@ -374,23 +318,8 @@ gc_tracer_start_logging(int argc, VALUE *argv, VALUE self)
|
|
374
318
|
if (logger.enabled == Qfalse) {
|
375
319
|
int i;
|
376
320
|
|
377
|
-
|
378
|
-
|
379
|
-
gc_trace_out = stderr;
|
380
|
-
}
|
381
|
-
else if (argc == 1) {
|
382
|
-
if (RB_TYPE_P(argv[0], T_STRING)) {
|
383
|
-
const char *filename = StringValueCStr(argv[0]);
|
384
|
-
if ((gc_trace_out = fopen(filename, "w")) == NULL) {
|
385
|
-
rb_raise(rb_eRuntimeError, "can not open file: %s\n", filename);
|
386
|
-
}
|
387
|
-
}
|
388
|
-
}
|
389
|
-
else {
|
390
|
-
rb_raise(rb_eArgError, "too many arguments");
|
391
|
-
}
|
392
|
-
|
393
|
-
out_header();
|
321
|
+
logger.out = open_output(argc, argv);
|
322
|
+
out_header(logger.out, gc_trace_items, 1);
|
394
323
|
|
395
324
|
for (i=0; i<3; i++) {
|
396
325
|
logger.funcs[i] = trace;
|
@@ -430,18 +359,18 @@ item_type(VALUE sym)
|
|
430
359
|
return 0; /* unreachable */
|
431
360
|
}
|
432
361
|
|
433
|
-
static
|
434
|
-
|
362
|
+
static void
|
363
|
+
setup_items(VALUE new_items, VALUE items, VALUE types)
|
435
364
|
{
|
365
|
+
VALUE is = rb_ary_new();
|
366
|
+
VALUE ts = rb_ary_new();
|
436
367
|
int i;
|
437
|
-
VALUE keys = rb_ary_new(), types = rb_ary_new();
|
438
368
|
|
439
|
-
if (NIL_P(
|
440
|
-
int i;
|
369
|
+
if (NIL_P(new_items)) {
|
441
370
|
|
442
371
|
#define ADD(syms) for (i=0; i<(int)(sizeof(syms)/sizeof(VALUE));i++) { \
|
443
|
-
rb_ary_push(
|
444
|
-
rb_ary_push(
|
372
|
+
rb_ary_push(is, syms[i]); \
|
373
|
+
rb_ary_push(ts, INT2FIX(item_type(syms[i]))); \
|
445
374
|
}
|
446
375
|
ADD(sym_gc_stat);
|
447
376
|
ADD(sym_latest_gc_info);
|
@@ -451,23 +380,94 @@ gc_tracer_setup_logging(VALUE self, VALUE ary)
|
|
451
380
|
#endif
|
452
381
|
}
|
453
382
|
else {
|
454
|
-
if (!RB_TYPE_P(
|
383
|
+
if (!RB_TYPE_P(new_items, T_ARRAY)) rb_raise(rb_eArgError, "unsupported argument");
|
455
384
|
|
456
|
-
for (i=0; i<RARRAY_LEN(
|
457
|
-
VALUE sym = RARRAY_AREF(
|
385
|
+
for (i=0; i<RARRAY_LEN(new_items); i++) {
|
386
|
+
VALUE sym = RARRAY_AREF(new_items, i);
|
458
387
|
enum gc_key_type type;
|
459
388
|
if (!SYMBOL_P(sym)) rb_raise(rb_eArgError, "unsupported type");
|
460
389
|
type = item_type(sym);
|
461
|
-
rb_ary_push(
|
462
|
-
rb_ary_push(
|
390
|
+
rb_ary_push(is, sym);
|
391
|
+
rb_ary_push(ts, INT2FIX(type));
|
463
392
|
}
|
464
393
|
|
465
|
-
|
466
|
-
|
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);
|
467
449
|
}
|
468
450
|
return Qnil;
|
469
451
|
}
|
470
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
471
|
#ifdef HAVE_RB_OBJSPACE_EACH_OBJECTS_WITHOUT_SETUP
|
472
472
|
/* image logging */
|
473
473
|
|
@@ -675,7 +675,7 @@ objspace_recording_i(void *start, void *end, size_t stride, void *data)
|
|
675
675
|
}
|
676
676
|
|
677
677
|
static void
|
678
|
-
objspace_recording(void *data, int event_index)
|
678
|
+
objspace_recording(FILE *dmy, void *data, int event_index)
|
679
679
|
{
|
680
680
|
/* const char *event_name = (const char *)data; */
|
681
681
|
const char *dirname = (const char *)objspace_recorder.data;
|
@@ -802,6 +802,8 @@ gc_tracer_start_objspace_recording(int argc, VALUE *argv, VALUE self)
|
|
802
802
|
|
803
803
|
#endif /* HAVE_RB_OBJSPACE_EACH_OBJECTS_WITHOUT_SETUP */
|
804
804
|
|
805
|
+
|
806
|
+
|
805
807
|
/**
|
806
808
|
* GC::Tracer traces GC/ObjectSpace behavior.
|
807
809
|
*
|
@@ -829,6 +831,9 @@ Init_gc_tracer(void)
|
|
829
831
|
rb_define_module_function(mod, "stop_logging", gc_tracer_stop_logging, 0);
|
830
832
|
rb_define_module_function(mod, "setup_logging", gc_tracer_setup_logging, 1);
|
831
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
|
+
|
832
837
|
/* recording methods */
|
833
838
|
#ifdef HAVE_RB_OBJSPACE_EACH_OBJECTS_WITHOUT_SETUP
|
834
839
|
rb_define_module_function(mod, "start_objspace_recording", gc_tracer_start_objspace_recording, -1);
|
@@ -851,6 +856,30 @@ Init_gc_tracer(void)
|
|
851
856
|
gc_trace_items_types = rb_ary_new();
|
852
857
|
rb_gc_register_mark_object(gc_trace_items);
|
853
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
|
+
}
|
854
873
|
|
855
|
-
|
874
|
+
#endif
|
875
|
+
|
876
|
+
#include <ruby/ruby.h>
|
877
|
+
|
878
|
+
void Init_gc_tracer_logging(VALUE m_gc_tracer); /* in gc_logging.c */
|
879
|
+
|
880
|
+
void
|
881
|
+
Init_gc_tracer(void)
|
882
|
+
{
|
883
|
+
VALUE mod = rb_define_module_under(rb_mGC, "Tracer");
|
884
|
+
Init_gc_tracer_logging(mod);
|
856
885
|
}
|
data/lib/gc_tracer/version.rb
CHANGED
data/lib/gc_tracer.rb
CHANGED
@@ -1,3 +1,38 @@
|
|
1
1
|
require "gc_tracer/version"
|
2
2
|
require 'gc_tracer/gc_tracer'
|
3
3
|
|
4
|
+
module GC
|
5
|
+
module Tracer
|
6
|
+
def self.start_logging(filename_opt = nil,
|
7
|
+
filename: nil,
|
8
|
+
# event filter
|
9
|
+
events: %i(start end_mark end_sweep),
|
10
|
+
# tick type (:hw_counter, :time, :user_time, :system_time)
|
11
|
+
tick_type: :time,
|
12
|
+
# collect information
|
13
|
+
gc_stat: true,
|
14
|
+
gc_latest_gc_info: true,
|
15
|
+
rusage: false)
|
16
|
+
# setup
|
17
|
+
raise "do not specify two fienames" if filename && filename_opt
|
18
|
+
setup_logging_out(filename_opt || filename)
|
19
|
+
setup_logging_events(*events)
|
20
|
+
|
21
|
+
self.setup_logging_gc_stat = gc_stat
|
22
|
+
self.setup_logging_gc_latest_gc_info = gc_latest_gc_info
|
23
|
+
self.setup_logging_rusage = rusage
|
24
|
+
self.setup_logging_tick_type = tick_type
|
25
|
+
|
26
|
+
if block_given?
|
27
|
+
begin
|
28
|
+
start_logging_
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
stop_logging
|
32
|
+
end
|
33
|
+
else
|
34
|
+
start_logging_
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/gc_tracer_spec.rb
CHANGED
@@ -28,6 +28,7 @@ describe GC::Tracer do
|
|
28
28
|
it_behaves_like "logging_test"
|
29
29
|
end
|
30
30
|
|
31
|
+
=begin not supported now.
|
31
32
|
shared_examples "objspace_recorder_test" do
|
32
33
|
dirname = "gc_tracer_objspace_recorder_spec.#{$$}"
|
33
34
|
|
@@ -56,4 +57,5 @@ describe GC::Tracer do
|
|
56
57
|
let(:count){2}
|
57
58
|
it_behaves_like "objspace_recorder_test"
|
58
59
|
end
|
60
|
+
=end
|
59
61
|
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.
|
4
|
+
version: 1.0.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-
|
11
|
+
date: 2014-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -111,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
111
|
version: '0'
|
112
112
|
requirements: []
|
113
113
|
rubyforge_project:
|
114
|
-
rubygems_version: 2.
|
114
|
+
rubygems_version: 2.4.5
|
115
115
|
signing_key:
|
116
116
|
specification_version: 4
|
117
117
|
summary: gc_tracer gem adds GC::Tracer module.
|