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 +4 -4
- data/ext/gc_tracer/gc_logging.c +586 -0
- data/lib/gc_tracer/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e88092e8af66c335eb5b650723f56a691824bd1e
|
4
|
+
data.tar.gz: 19baeffe0a1d32a4630db100ca6f0127a14c4770
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
+
}
|
data/lib/gc_tracer/version.rb
CHANGED
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.
|
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
|