gc_tracer 1.1.0 → 1.2.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/.travis.yml +4 -0
- data/README.md +36 -8
- data/ext/gc_tracer/gc_logging.c +122 -0
- data/lib/gc_tracer.rb +4 -1
- data/lib/gc_tracer/version.rb +1 -1
- data/spec/gc_tracer_spec.rb +72 -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: 08efc028ba431a430f1e0d1ac444b74884e575b4
|
4
|
+
data.tar.gz: 04aa0ea80b8ce757cd32bce97a84644740c6a53c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 299a15128bd5794000a3d631e5ca21132dbe954192f19c71c5b5a18f3332271646375d108be07b516ef7f803dab65fcd932e862e435e9a3ba7ddd3c0329e95af
|
7
|
+
data.tar.gz: b6132a320def13c6161a4dcc7e105c21f167c82e6ad03af303dd4f9f2f9a00b874c8e253bf3f864a0978737d2673e588f946087faae8307e368eca702208e3e6
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -4,6 +4,8 @@ Trace Garbage Collector activities and output statistics information.
|
|
4
4
|
|
5
5
|
This gem only supports MRI 2.1.0 and later.
|
6
6
|
|
7
|
+
[](https://travis-ci.org/ko1/gc_tracer)
|
8
|
+
|
7
9
|
## Installation
|
8
10
|
|
9
11
|
Add this line to your application's Gemfile:
|
@@ -80,7 +82,7 @@ ensure
|
|
80
82
|
end
|
81
83
|
```
|
82
84
|
|
83
|
-
Default events are "start", "end_mark" and "end_sweep". You can specify
|
85
|
+
Default events are "start", "end_mark" and "end_sweep". You can specify
|
84
86
|
what kind of information you want to collect.
|
85
87
|
|
86
88
|
```ruby
|
@@ -93,22 +95,48 @@ ensure
|
|
93
95
|
end
|
94
96
|
```
|
95
97
|
|
96
|
-
Above example means that no details information are not needed. Default
|
98
|
+
Above example means that no details information are not needed. Default
|
97
99
|
setting is "gc_stat: true, gc_latest_gc_info: true, rusage: false".
|
98
100
|
|
99
|
-
You can specify tick (time stamp) type with keyword parameter
|
100
|
-
"tick_type". You can choose one of the tick type in :hw_counter, :time
|
101
|
+
You can specify tick (time stamp) type with keyword parameter
|
102
|
+
"tick_type". You can choose one of the tick type in :hw_counter, :time
|
101
103
|
and :nano_time (if platform supports clock_gettime()).
|
102
104
|
|
103
105
|
See lib/gc_tracer.rb for more details.
|
104
106
|
|
107
|
+
### Custom fields
|
108
|
+
|
109
|
+
You can add custom fields.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
GC::Tracer.start_logging(custom_fields: [:name1, :name2, ...]) do
|
113
|
+
# All fields are cleared by zero.
|
114
|
+
|
115
|
+
# You can increment values of each field.
|
116
|
+
GC::Tracer.custom_field_increment(:name1)
|
117
|
+
# It is equivalent to
|
118
|
+
# GC::Tracer.custom_field_set(:name1, GC::Tracer.custom_field_get(:name1))
|
119
|
+
|
120
|
+
# You can also decrement values
|
121
|
+
GC::Tracer.custom_field_decrement(:name1)
|
122
|
+
|
123
|
+
# Now, you can specify only Fixnum as field value.
|
124
|
+
GC::Tracer.custom_field_set(:name2, 123)
|
125
|
+
|
126
|
+
# You can specify an index instead of field name (faster than actual name)
|
127
|
+
GC::Tracer.custom_field_increment(0) # :name1
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
Custom fields are printed as last columns.
|
132
|
+
|
105
133
|
### Custom events
|
106
134
|
|
107
|
-
You can add custom events by your own. Calling
|
108
|
-
`GC::Tracer.custom_event_logging(event_name)` in your program will puts
|
135
|
+
You can add custom events by your own. Calling
|
136
|
+
`GC::Tracer.custom_event_logging(event_name)` in your program will puts
|
109
137
|
new statistics line into the logging file.
|
110
138
|
|
111
|
-
For example, the following program insert 1000 custom event lines into
|
139
|
+
For example, the following program insert 1000 custom event lines into
|
112
140
|
logging file (stderr for this type).
|
113
141
|
|
114
142
|
```ruby
|
@@ -120,7 +148,7 @@ GC::Tracer.start_logging(events: %i(start), gc_stat: false) do
|
|
120
148
|
end
|
121
149
|
```
|
122
150
|
|
123
|
-
This method is useful to trace where the GC events occur in your
|
151
|
+
This method is useful to trace where the GC events occur in your
|
124
152
|
application.
|
125
153
|
|
126
154
|
|
data/ext/gc_tracer/gc_logging.c
CHANGED
@@ -66,6 +66,8 @@ tick(void)
|
|
66
66
|
#define MAX_HOOKS 5
|
67
67
|
#endif
|
68
68
|
|
69
|
+
#define MAX_CUSTOM_FIELDS 128
|
70
|
+
|
69
71
|
static VALUE tracer_hooks[MAX_HOOKS];
|
70
72
|
static VALUE tracer_acceptable_events[MAX_HOOKS];
|
71
73
|
|
@@ -77,12 +79,16 @@ struct gc_logging {
|
|
77
79
|
int log_gc_stat;
|
78
80
|
int log_gc_latest_gc_info;
|
79
81
|
int log_rusage;
|
82
|
+
int log_custom_fields_count;
|
80
83
|
} config;
|
81
84
|
|
82
85
|
int enabled;
|
83
86
|
VALUE enable_hooks[MAX_HOOKS]; /* Symbols */
|
84
87
|
int enable_hooks_num; /* 0 to MAX_HOOKS */
|
85
88
|
|
89
|
+
ID custom_field_names[MAX_CUSTOM_FIELDS];
|
90
|
+
long custom_field_values[MAX_CUSTOM_FIELDS];
|
91
|
+
|
86
92
|
FILE *out;
|
87
93
|
const char *event;
|
88
94
|
|
@@ -138,6 +144,12 @@ out_sizet(FILE *out, size_t size)
|
|
138
144
|
fprintf(out, "%lu\t", (unsigned long)size);
|
139
145
|
}
|
140
146
|
|
147
|
+
static void
|
148
|
+
out_long(FILE *out, long l)
|
149
|
+
{
|
150
|
+
fprintf(out, "%ld\t", l);
|
151
|
+
}
|
152
|
+
|
141
153
|
static double
|
142
154
|
timeval2double(struct timeval *tv)
|
143
155
|
{
|
@@ -303,6 +315,13 @@ out_stat(struct gc_logging *logging, const char *event)
|
|
303
315
|
#if HAVE_GETRUSAGE
|
304
316
|
if (logging->config.log_rusage) out_rusage(logging);
|
305
317
|
#endif
|
318
|
+
if (logging->config.log_custom_fields_count > 0) {
|
319
|
+
int i;
|
320
|
+
for (i=0; i<logging->config.log_custom_fields_count; i++) {
|
321
|
+
out_long(logging->out, logging->custom_field_values[i]);
|
322
|
+
}
|
323
|
+
}
|
324
|
+
|
306
325
|
out_terminate(logging->out);
|
307
326
|
}
|
308
327
|
|
@@ -335,6 +354,12 @@ out_header(struct gc_logging *logging)
|
|
335
354
|
out_header_each(logging, sym_rusage, sizeof(sym_rusage)/sizeof(VALUE));
|
336
355
|
}
|
337
356
|
#endif
|
357
|
+
if (logging->config.log_custom_fields_count > 0) {
|
358
|
+
int i;
|
359
|
+
for (i=0; i<logging->config.log_custom_fields_count; i++) {
|
360
|
+
out_str(logging->out, rb_id2name(logging->custom_field_names[i]));
|
361
|
+
}
|
362
|
+
}
|
338
363
|
out_terminate(logging->out);
|
339
364
|
}
|
340
365
|
|
@@ -540,6 +565,96 @@ gc_tracer_setup_logging_rusage(VALUE self, VALUE b)
|
|
540
565
|
return self;
|
541
566
|
}
|
542
567
|
|
568
|
+
static VALUE
|
569
|
+
gc_tracer_setup_logging_custom_fields(VALUE self, VALUE b)
|
570
|
+
{
|
571
|
+
struct gc_logging *logging = &trace_logging;
|
572
|
+
|
573
|
+
if (RTEST(b)) {
|
574
|
+
VALUE ary = rb_check_array_type(b);
|
575
|
+
int i;
|
576
|
+
|
577
|
+
logging->config.log_custom_fields_count = RARRAY_LEN(ary);
|
578
|
+
|
579
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
580
|
+
VALUE name = RARRAY_AREF(ary, i);
|
581
|
+
ID field_id = rb_to_id(name);
|
582
|
+
|
583
|
+
if (i >= MAX_CUSTOM_FIELDS) {
|
584
|
+
rb_raise(rb_eRuntimeError, "Number of custome fields exceeds %d", MAX_CUSTOM_FIELDS);
|
585
|
+
}
|
586
|
+
|
587
|
+
logging->custom_field_names[i] = field_id;
|
588
|
+
logging->custom_field_values[i] = 0;
|
589
|
+
}
|
590
|
+
}
|
591
|
+
else {
|
592
|
+
logging->config.log_custom_fields_count = 0;
|
593
|
+
}
|
594
|
+
|
595
|
+
return self;
|
596
|
+
}
|
597
|
+
|
598
|
+
static long *
|
599
|
+
custom_field_value_place(VALUE name)
|
600
|
+
{
|
601
|
+
struct gc_logging *logging = &trace_logging;
|
602
|
+
int index;
|
603
|
+
|
604
|
+
if (FIXNUM_P(name)) {
|
605
|
+
index = FIX2INT(name);
|
606
|
+
if (index >= logging->config.log_custom_fields_count) {
|
607
|
+
rb_raise(rb_eRuntimeError, "Only %d custom fields are available, but %d was specified",
|
608
|
+
logging->config.log_custom_fields_count, index);
|
609
|
+
}
|
610
|
+
}
|
611
|
+
else {
|
612
|
+
int i;
|
613
|
+
ID nid = rb_to_id(name);
|
614
|
+
for (i=0; i<logging->config.log_custom_fields_count; i++) {
|
615
|
+
if (nid == logging->custom_field_names[i]) {
|
616
|
+
index = i;
|
617
|
+
goto found;
|
618
|
+
}
|
619
|
+
}
|
620
|
+
rb_raise(rb_eRuntimeError, "Unkown custom fileds is specified.");
|
621
|
+
}
|
622
|
+
found:
|
623
|
+
return &logging->custom_field_values[index];
|
624
|
+
}
|
625
|
+
|
626
|
+
static VALUE
|
627
|
+
gc_tracer_custom_field_increment(VALUE self, VALUE name)
|
628
|
+
{
|
629
|
+
long *valp = custom_field_value_place(name);
|
630
|
+
(*valp)++;
|
631
|
+
return self;
|
632
|
+
}
|
633
|
+
|
634
|
+
static VALUE
|
635
|
+
gc_tracer_custom_field_decrement(VALUE self, VALUE name)
|
636
|
+
{
|
637
|
+
long *valp = custom_field_value_place(name);
|
638
|
+
(*valp)--;
|
639
|
+
return self;
|
640
|
+
}
|
641
|
+
|
642
|
+
static VALUE
|
643
|
+
gc_tracer_custom_field_get(VALUE self, VALUE name)
|
644
|
+
{
|
645
|
+
long *valp = custom_field_value_place(name);
|
646
|
+
return LONG2NUM(*valp);
|
647
|
+
}
|
648
|
+
|
649
|
+
static VALUE
|
650
|
+
gc_tracer_custom_field_set(VALUE self, VALUE name, VALUE val)
|
651
|
+
{
|
652
|
+
long *valp = custom_field_value_place(name);
|
653
|
+
long lval = NUM2LONG(val);
|
654
|
+
*valp = lval;
|
655
|
+
return val;
|
656
|
+
}
|
657
|
+
|
543
658
|
static VALUE
|
544
659
|
gc_tracer_start_logging(int argc, VALUE *argv, VALUE self)
|
545
660
|
{
|
@@ -597,6 +712,13 @@ Init_gc_tracer_logging(VALUE mod)
|
|
597
712
|
rb_define_module_function(mod, "setup_logging_gc_latest_gc_info=", gc_tracer_setup_logging_gc_latest_gc_info, 1);
|
598
713
|
rb_define_module_function(mod, "setup_logging_rusage=", gc_tracer_setup_logging_rusage, 1);
|
599
714
|
|
715
|
+
/* custom fields */
|
716
|
+
rb_define_module_function(mod, "setup_looging_custom_fields=", gc_tracer_setup_logging_custom_fields, 1);
|
717
|
+
rb_define_module_function(mod, "custom_field_increment", gc_tracer_custom_field_increment, 1);
|
718
|
+
rb_define_module_function(mod, "custom_field_decrement", gc_tracer_custom_field_decrement, 1);
|
719
|
+
rb_define_module_function(mod, "custom_field_set", gc_tracer_custom_field_set, 2);
|
720
|
+
rb_define_module_function(mod, "custom_field_get", gc_tracer_custom_field_get, 1);
|
721
|
+
|
600
722
|
/* custom event */
|
601
723
|
rb_define_module_function(mod, "custom_event_logging", gc_tracer_custom_event_logging, 1);
|
602
724
|
|
data/lib/gc_tracer.rb
CHANGED
@@ -12,7 +12,9 @@ module GC
|
|
12
12
|
# collect information
|
13
13
|
gc_stat: true,
|
14
14
|
gc_latest_gc_info: true,
|
15
|
-
rusage: false
|
15
|
+
rusage: false,
|
16
|
+
custom_fields: nil
|
17
|
+
)
|
16
18
|
# setup
|
17
19
|
raise "do not specify two fienames" if filename && filename_opt
|
18
20
|
setup_logging_out(filename_opt || filename)
|
@@ -22,6 +24,7 @@ module GC
|
|
22
24
|
self.setup_logging_gc_latest_gc_info = gc_latest_gc_info
|
23
25
|
self.setup_logging_rusage = rusage
|
24
26
|
self.setup_logging_tick_type = tick_type
|
27
|
+
self.setup_looging_custom_fields = custom_fields
|
25
28
|
|
26
29
|
if block_given?
|
27
30
|
begin
|
data/lib/gc_tracer/version.rb
CHANGED
data/spec/gc_tracer_spec.rb
CHANGED
@@ -28,6 +28,78 @@ describe GC::Tracer do
|
|
28
28
|
it_behaves_like "logging_test"
|
29
29
|
end
|
30
30
|
|
31
|
+
describe 'custom fields' do
|
32
|
+
describe 'manipulate values' do
|
33
|
+
around 'open' do |example|
|
34
|
+
Dir.mktmpdir('gc_tracer'){|dir|
|
35
|
+
logfile = "#{dir}/logging"
|
36
|
+
GC::Tracer.start_logging(logfile, custom_fields: %i(a b c)) do
|
37
|
+
example.run
|
38
|
+
end
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should raise error for unknown name or index' do
|
43
|
+
expect{GC::Tracer.custom_field_increment(:xyzzy)}.to raise_error RuntimeError
|
44
|
+
expect{GC::Tracer.custom_field_increment(42)}.to raise_error RuntimeError
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should count increments' do
|
48
|
+
GC::Tracer.custom_field_increment(:a)
|
49
|
+
GC::Tracer.custom_field_increment(:a)
|
50
|
+
GC::Tracer.custom_field_increment(:a)
|
51
|
+
GC::Tracer.custom_field_increment(0)
|
52
|
+
GC::Tracer.custom_field_increment(0)
|
53
|
+
GC::Tracer.custom_field_increment(0)
|
54
|
+
|
55
|
+
expect(GC::Tracer.custom_field_get(:a)).to be 6
|
56
|
+
expect(GC::Tracer.custom_field_get(0)).to be 6
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should count decments' do
|
60
|
+
GC::Tracer.custom_field_decrement(:b)
|
61
|
+
GC::Tracer.custom_field_decrement(:b)
|
62
|
+
GC::Tracer.custom_field_decrement(:b)
|
63
|
+
GC::Tracer.custom_field_decrement(1)
|
64
|
+
GC::Tracer.custom_field_decrement(1)
|
65
|
+
GC::Tracer.custom_field_decrement(1)
|
66
|
+
|
67
|
+
expect(GC::Tracer.custom_field_get(:b)).to be -6
|
68
|
+
expect(GC::Tracer.custom_field_get(1)).to be -6
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should set values' do
|
72
|
+
GC::Tracer.custom_field_set(:c, 42)
|
73
|
+
expect(GC::Tracer.custom_field_get(:c)).to be 42
|
74
|
+
GC::Tracer.custom_field_set(2, 43)
|
75
|
+
expect(GC::Tracer.custom_field_get(:c)).to be 43
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'output custome fields' do
|
80
|
+
it 'should output custome fields' do
|
81
|
+
Dir.mktmpdir('gc_tracer'){|dir|
|
82
|
+
logfile = "#{dir}/logging"
|
83
|
+
GC::Tracer.start_logging(logfile, custom_fields: %i(a b c)) do
|
84
|
+
GC::Tracer.custom_field_increment(:a)
|
85
|
+
GC::Tracer.custom_field_decrement(:b)
|
86
|
+
GC::Tracer.custom_event_logging("out")
|
87
|
+
end
|
88
|
+
|
89
|
+
expect(File.exist?(logfile)).to be_true
|
90
|
+
log = File.read(logfile)
|
91
|
+
expect(log.lines[0]).to match /a\tb\tc/
|
92
|
+
log.each_line{|line|
|
93
|
+
if /out/ =~ line
|
94
|
+
expect(line).to match /1\t-1\t0/
|
95
|
+
end
|
96
|
+
}
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
31
103
|
=begin not supported now.
|
32
104
|
shared_examples "objspace_recorder_test" do
|
33
105
|
dirname = "gc_tracer_objspace_recorder_spec.#{$$}"
|
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: 1.
|
4
|
+
version: 1.2.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:
|
11
|
+
date: 2015-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -76,6 +76,7 @@ extensions:
|
|
76
76
|
extra_rdoc_files: []
|
77
77
|
files:
|
78
78
|
- ".gitignore"
|
79
|
+
- ".travis.yml"
|
79
80
|
- Gemfile
|
80
81
|
- LICENSE.txt
|
81
82
|
- README.md
|
@@ -119,4 +120,3 @@ summary: gc_tracer gem adds GC::Tracer module.
|
|
119
120
|
test_files:
|
120
121
|
- spec/gc_tracer_spec.rb
|
121
122
|
- spec/spec_helper.rb
|
122
|
-
has_rdoc:
|