gctrack 0.0.1 → 0.1.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/Gemfile.lock +1 -1
- data/README.md +53 -0
- data/ext/gctrack/gctrack.c +99 -18
- data/gctrack.gemspec +1 -1
- data/lib/gctrack.rb +1 -0
- data/test/test_gctrack.rb +13 -7
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4388d6afd81b4cfb83867cb06a566660b460142d
|
4
|
+
data.tar.gz: b8f4b6ed72cee918d87ad60161b08eeae4875645
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e52f68e61eab3e758420725acf7f23b124b4c7230e03529291e2710bc53a509ddd5006636c63f885c41971e8a6a6b4911b60a9f59480ad6b339bed0e54fdd61
|
7
|
+
data.tar.gz: c138d07a3ac9685280b1bde07397e82d31ba5402a434c0c5ee543841dbe5d8ebbff5a882989c60145a06520cf82a2b0bc944aa007500111c4b41ae33ba0d964a
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,2 +1,55 @@
|
|
1
|
+
[](https://badge.fury.io/rb/gctrack)
|
2
|
+
[](https://travis-ci.org/Shopify/gctrack)
|
3
|
+
|
1
4
|
## GCTrack
|
2
5
|
|
6
|
+
The GCTrack extension lets you monitor incremental Garbage Collector (GC) information, the GC introduced in Ruby v2.2.
|
7
|
+
|
8
|
+
### Getting started
|
9
|
+
|
10
|
+
#### #1 Add the dependency
|
11
|
+
|
12
|
+
GCTrack is published to [rubygems.org](https://rubygems.org/gems/gctrack).
|
13
|
+
Simply add it as a dependency to your `Gemfile`
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'gctrack', '~> 0.1.0'
|
17
|
+
```
|
18
|
+
|
19
|
+
#### #2 Enable the extension
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'gctrack'
|
23
|
+
|
24
|
+
GC::Tracker.enable # returns true, if the Tracker is now enabled
|
25
|
+
```
|
26
|
+
|
27
|
+
#### #3 Record data
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
GC::Tracker.start_record # returns true, if a new record was started
|
31
|
+
# DO ACTUAL WORK
|
32
|
+
gc_cycles, gc_duration_ns = GC::Tracker.end_record
|
33
|
+
```
|
34
|
+
|
35
|
+
`#end_record` will return the `gc_cycles` (the amount of gc cycles observed) and `gc_duration_ns` (their cumulative duration in
|
36
|
+
nanoseconds), since the last invocation of `#start_record`. You can also invoke `#start_record` recursively as so:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
GC::Tracker.start_record # Start a first record
|
40
|
+
do_work_on(one)
|
41
|
+
GC::Tracker.start_record # Start a second record
|
42
|
+
do_work_on(two)
|
43
|
+
inner_data = GC::Tracker.end_record # Collect results from second record
|
44
|
+
do_work_on(three)
|
45
|
+
outter_data = GC::Tracker.end_record # Collect results from first record
|
46
|
+
```
|
47
|
+
|
48
|
+
In this example, the Array `inner_data` will only contain the GC information resulted of executing `do_work_on(two)`, while
|
49
|
+
`outter_data` will contain the GC information resulted from the three exectutions: `do_work_on` `one`, `two` and `three`.
|
50
|
+
|
51
|
+
Effectively, records are stacked and data from a GC cycle will be added to all "currently" records.
|
52
|
+
|
53
|
+
## License
|
54
|
+
|
55
|
+
[The MIT License (MIT)](LICENSE.md)
|
data/ext/gctrack/gctrack.c
CHANGED
@@ -49,13 +49,15 @@ gctracker_enabled()
|
|
49
49
|
static void
|
50
50
|
gctracker_hook(VALUE tpval, void *data)
|
51
51
|
{
|
52
|
-
if (!gctracker_enabled()) {
|
52
|
+
if (!gctracker_enabled() && !last_record) {
|
53
53
|
return;
|
54
54
|
}
|
55
55
|
rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
|
56
56
|
switch (rb_tracearg_event_flag(tparg)) {
|
57
57
|
case RUBY_INTERNAL_EVENT_GC_ENTER: {
|
58
|
-
|
58
|
+
if (gctracker_enabled()) {
|
59
|
+
last_enter = nanotime();
|
60
|
+
}
|
59
61
|
}
|
60
62
|
break;
|
61
63
|
case RUBY_INTERNAL_EVENT_GC_EXIT: {
|
@@ -68,18 +70,40 @@ gctracker_hook(VALUE tpval, void *data)
|
|
68
70
|
}
|
69
71
|
}
|
70
72
|
|
71
|
-
static
|
73
|
+
static bool
|
72
74
|
create_tracepoint()
|
73
75
|
{
|
74
76
|
rb_event_flag_t events;
|
75
77
|
events = RUBY_INTERNAL_EVENT_GC_ENTER | RUBY_INTERNAL_EVENT_GC_EXIT;
|
76
78
|
tracepoint = rb_tracepoint_new(0, events, gctracker_hook, (void *) NULL);
|
77
79
|
if (NIL_P(tracepoint)) {
|
78
|
-
|
80
|
+
return false;
|
79
81
|
}
|
80
82
|
rb_global_variable(&tracepoint);
|
83
|
+
return true;
|
81
84
|
}
|
82
85
|
|
86
|
+
/*
|
87
|
+
* call-seq:
|
88
|
+
* GC::Tracker.start_record -> true or false
|
89
|
+
*
|
90
|
+
* Starts recording GC cycles and their duration. Returns +true+ if the
|
91
|
+
* recording was started, +false+ otherwise. If the record could be started
|
92
|
+
* an GC::Tracker#end_record invocation will always return data for the record,
|
93
|
+
* otherwise that invocation would return +nil+.
|
94
|
+
* One case where +false+ would be returned is if the Tracker isn't enabled.
|
95
|
+
* #start_record can be nested. These records will have a parent-child relationship,
|
96
|
+
* where the parent will contain all GC data of the child.
|
97
|
+
*
|
98
|
+
* GC::Tracker.enabled? # true
|
99
|
+
* GC::Tracker.start_record # true
|
100
|
+
* GC::Tracker.start_record # true
|
101
|
+
* GC::Tracker.end_record # [2, 12654] from the second #start_record
|
102
|
+
* GC::Tracker.disable # true
|
103
|
+
* GC::Tracker.start_record # false
|
104
|
+
* GC::Tracker.end_record # [3, 15782] from the first #start_record, contains the data from the first record
|
105
|
+
* GC::Tracker.end_record # nil from the last #start_record, that returned false
|
106
|
+
*/
|
83
107
|
static VALUE
|
84
108
|
gctracker_start_record(int argc, VALUE *argv, VALUE klass)
|
85
109
|
{
|
@@ -97,6 +121,26 @@ gctracker_start_record(int argc, VALUE *argv, VALUE klass)
|
|
97
121
|
return Qtrue;
|
98
122
|
}
|
99
123
|
|
124
|
+
/*
|
125
|
+
* call-seq:
|
126
|
+
* GC::Tracker.end_record -> Array or nil
|
127
|
+
*
|
128
|
+
* Ends the recording of the last started record and return the
|
129
|
+
* the collected information.
|
130
|
+
* The array contains two numbers: The amount of GC cycles observed and
|
131
|
+
* the cumulative duration in nanoseconds of these cycles. If multiple recordings
|
132
|
+
* were started they will be be popped from the stack of records and their
|
133
|
+
* values will be returned.
|
134
|
+
* GC data gathered is in all records of the stack.
|
135
|
+
*
|
136
|
+
* GC::Tracker.start_record # true
|
137
|
+
* GC::Tracker.start_record # true
|
138
|
+
* GC::Tracker.end_record # [2, 12654] amount of cycles and duration since the second #start_record
|
139
|
+
* GC::Tracker.end_record # [3, 15782] GC data since the first #start_record, including the data above
|
140
|
+
* GC::Tracker.disable # true
|
141
|
+
* GC::Tracker.start_record # false
|
142
|
+
* GC::Tracker.end_record # nil
|
143
|
+
*/
|
100
144
|
static VALUE
|
101
145
|
gctracker_end_record(int argc, VALUE *argv, VALUE klass)
|
102
146
|
{
|
@@ -115,43 +159,79 @@ gctracker_end_record(int argc, VALUE *argv, VALUE klass)
|
|
115
159
|
return stats;
|
116
160
|
}
|
117
161
|
|
162
|
+
/*
|
163
|
+
* call-seq:
|
164
|
+
* GC::Tracker.enabled? -> true or false
|
165
|
+
*
|
166
|
+
* Returns +true+ if the Tracker is enabled, +false+ otherwise.
|
167
|
+
*
|
168
|
+
* GC::Tracker.enabled? # false
|
169
|
+
* GC::Tracker.enable # true
|
170
|
+
* GC::Tracker.enabled? # true
|
171
|
+
* GC::Tracker.enable # true
|
172
|
+
*/
|
173
|
+
static VALUE
|
174
|
+
gctracker_enabled_p(int argc, VALUE *argv, VALUE klass)
|
175
|
+
{
|
176
|
+
return gctracker_enabled() ? Qtrue : Qfalse;
|
177
|
+
}
|
178
|
+
|
179
|
+
/*
|
180
|
+
* call-seq:
|
181
|
+
* GC::Tracker.enable -> true or false
|
182
|
+
*
|
183
|
+
* Globally enables the tracker. Returns +true+ if the Tracker is
|
184
|
+
* enabled after this call (whether it enabled it or not), +false+ otherwise.
|
185
|
+
*
|
186
|
+
* GC::Tracker.disable # true
|
187
|
+
* GC::Tracker.enabled? # false
|
188
|
+
* GC::Tracker.enable # true
|
189
|
+
* GC::Tracker.enabled? # true
|
190
|
+
*/
|
118
191
|
static VALUE
|
119
192
|
gctracker_enable(int argc, VALUE *argv, VALUE klass)
|
120
193
|
{
|
121
|
-
if (NIL_P(tracepoint)) {
|
122
|
-
create_tracepoint();
|
123
|
-
}
|
124
|
-
|
125
194
|
if (gctracker_enabled()) {
|
126
195
|
return Qtrue;
|
127
196
|
}
|
128
197
|
|
198
|
+
if (NIL_P(tracepoint)) {
|
199
|
+
if(!create_tracepoint()) {
|
200
|
+
return Qfalse;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
129
204
|
rb_tracepoint_enable(tracepoint);
|
130
205
|
if (!gctracker_enabled()) {
|
131
|
-
|
206
|
+
return Qfalse;
|
132
207
|
}
|
133
208
|
|
134
209
|
return Qtrue;
|
135
210
|
}
|
136
211
|
|
212
|
+
/*
|
213
|
+
* call-seq:
|
214
|
+
* GC::Tracker.disable -> true or false
|
215
|
+
*
|
216
|
+
* Globally disables the tracker. Returns +true+ if the Tracker is
|
217
|
+
* disabled after this call (whether it disabled it or not), +false+ otherwise.
|
218
|
+
*
|
219
|
+
* GC::Tracker.enabled? # true
|
220
|
+
* GC::Tracker.disable # true
|
221
|
+
* GC::Tracker.enabled? # false
|
222
|
+
* GC::Tracker.disable # true
|
223
|
+
*/
|
137
224
|
static VALUE
|
138
225
|
gctracker_disable(VALUE self)
|
139
226
|
{
|
140
227
|
if (!gctracker_enabled()) {
|
141
|
-
return
|
228
|
+
return Qtrue;
|
142
229
|
}
|
143
230
|
|
144
231
|
rb_tracepoint_disable(tracepoint);
|
145
232
|
if (gctracker_enabled()) {
|
146
|
-
|
233
|
+
return Qfalse;
|
147
234
|
}
|
148
|
-
|
149
|
-
while (last_record) {
|
150
|
-
record_t *record = last_record;
|
151
|
-
last_record = record->parent;
|
152
|
-
free(record);
|
153
|
-
}
|
154
|
-
last_record = NULL;
|
155
235
|
|
156
236
|
return Qtrue;
|
157
237
|
}
|
@@ -163,6 +243,7 @@ Init_gctrack()
|
|
163
243
|
VALUE cTracker = rb_define_module_under(mGC, "Tracker");
|
164
244
|
|
165
245
|
rb_define_module_function(cTracker, "enable", gctracker_enable, 0);
|
246
|
+
rb_define_module_function(cTracker, "enabled?", gctracker_enabled_p, 0);
|
166
247
|
rb_define_module_function(cTracker, "disable", gctracker_disable, 0);
|
167
248
|
|
168
249
|
rb_define_module_function(cTracker, "start_record", gctracker_start_record, 0);
|
data/gctrack.gemspec
CHANGED
data/lib/gctrack.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'gctrack/gctrack'
|
data/test/test_gctrack.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'test/unit'
|
2
|
-
require 'gctrack
|
2
|
+
require 'gctrack'
|
3
3
|
|
4
4
|
class TestGctrack < Test::Unit::TestCase
|
5
5
|
def test_enable
|
@@ -9,15 +9,11 @@ class TestGctrack < Test::Unit::TestCase
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def test_disable
|
12
|
-
assert
|
12
|
+
assert GC::Tracker.disable
|
13
13
|
assert GC::Tracker.enable
|
14
14
|
assert GC::Tracker.disable
|
15
15
|
end
|
16
16
|
|
17
|
-
def test_returns_false_when_not_enabled
|
18
|
-
assert_equal false, GC::Tracker.disable
|
19
|
-
end
|
20
|
-
|
21
17
|
def test_enabled_generates_events
|
22
18
|
assert GC::Tracker.enable
|
23
19
|
assert GC::Tracker.start_record
|
@@ -51,10 +47,20 @@ class TestGctrack < Test::Unit::TestCase
|
|
51
47
|
assert GC::Tracker.end_record.nil?
|
52
48
|
end
|
53
49
|
|
54
|
-
def
|
50
|
+
def test_enabled_returns_accrodingly
|
51
|
+
assert !GC::Tracker.enabled?
|
52
|
+
GC::Tracker.enable
|
53
|
+
assert GC::Tracker.enabled?
|
54
|
+
ensure
|
55
|
+
GC::Tracker.disable
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_data_for_started_records_on_disable
|
55
59
|
assert GC::Tracker.enable
|
56
60
|
assert GC::Tracker.start_record
|
57
61
|
assert GC::Tracker.disable
|
62
|
+
assert !GC::Tracker.start_record
|
63
|
+
assert !GC::Tracker.end_record.nil?
|
58
64
|
assert GC::Tracker.end_record.nil?
|
59
65
|
ensure
|
60
66
|
GC::Tracker.disable
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gctrack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Francis
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-09-
|
12
|
+
date: 2017-09-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake-compiler
|
@@ -59,6 +59,7 @@ files:
|
|
59
59
|
- ext/gctrack/extconf.rb
|
60
60
|
- ext/gctrack/gctrack.c
|
61
61
|
- gctrack.gemspec
|
62
|
+
- lib/gctrack.rb
|
62
63
|
- test/test_gctrack.rb
|
63
64
|
homepage: https://github.com/Shopify/gctrack
|
64
65
|
licenses:
|