gctrack 0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 92838d06f2819fc114876a76cb748508d1d1468d
4
+ data.tar.gz: 403295552c868ce6284861af1071cb14350f6bd8
5
+ SHA512:
6
+ metadata.gz: 5942ef39807b64f69e448325265f9bb2b6a7575de22534073c11d58f19525bc6641beb10b0996a66d758c62e60becfcfa191bddd0a6527c706b640aee3b7ff5e
7
+ data.tar.gz: 9f9e5f8c6bb6b976b15d9e09f85e34492245bc7d040b0a6bbe1b167d3854d53d15af4a472d7e4a97631e27a59516980657535b0a7ba3ed7b838f853ed806e7a7
@@ -0,0 +1,5 @@
1
+ /.bundle/
2
+ /lib/gctrack/*.so
3
+ /lib/gctrack/*.bundle
4
+ /tmp/*
5
+ *.gem
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - '2.3.3'
5
+ - '2.4.1'
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :deployment do
5
+ gem 'package_cloud'
6
+ gem 'rake'
7
+ end
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gctrack (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ highline (1.6.20)
10
+ json_pure (1.8.1)
11
+ mime-types (1.25.1)
12
+ package_cloud (0.2.44)
13
+ highline (= 1.6.20)
14
+ json_pure (= 1.8.1)
15
+ rainbow (= 2.1.0)
16
+ rest-client (~> 1.6.7)
17
+ thor (~> 0.18)
18
+ power_assert (1.0.2)
19
+ rainbow (2.1.0)
20
+ rake (12.0.0)
21
+ rake-compiler (1.0.4)
22
+ rake
23
+ rest-client (1.6.9)
24
+ mime-types (~> 1.16)
25
+ test-unit (3.2.5)
26
+ power_assert
27
+ thor (0.20.0)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ gctrack!
34
+ package_cloud
35
+ rake
36
+ rake-compiler (~> 1.0)
37
+ test-unit
38
+
39
+ BUNDLED WITH
40
+ 1.15.3
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Scott Francis <scott.francis@shopify.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ ## GCTrack
2
+
@@ -0,0 +1,34 @@
1
+ task :default => :test
2
+
3
+ # ==========================================================
4
+ # Packaging
5
+ # ==========================================================
6
+
7
+ GEMSPEC = eval(File.read('gctrack.gemspec'))
8
+
9
+ require 'rubygems/package_task'
10
+ Gem::PackageTask.new(GEMSPEC) do |pkg|
11
+ end
12
+
13
+ # ==========================================================
14
+ # Ruby Extension
15
+ # ==========================================================
16
+
17
+ require 'rake/extensiontask'
18
+ Rake::ExtensionTask.new('gctrack', GEMSPEC) do |ext|
19
+ ext.ext_dir = 'ext/gctrack'
20
+ ext.lib_dir = 'lib/gctrack'
21
+ end
22
+ task :build => :compile
23
+
24
+ # ==========================================================
25
+ # Testing
26
+ # ==========================================================
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new 'test' do |t|
30
+ t.test_files = FileList['test/test_*.rb']
31
+ end
32
+ task :test => :build
33
+
34
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS = "-O3 -Wall"
4
+
5
+ create_makefile('gctrack/gctrack')
@@ -0,0 +1,170 @@
1
+ #include <ruby.h>
2
+ #include <ruby/debug.h>
3
+ #include <ruby/intern.h>
4
+ #include <stdbool.h>
5
+ #include <errno.h>
6
+ #include <time.h>
7
+ #include <stdlib.h>
8
+
9
+ typedef struct record_t record_t;
10
+
11
+ struct record_t {
12
+ uint32_t cycles;
13
+ uint64_t duration;
14
+ record_t *parent;
15
+ };
16
+
17
+ static VALUE tracepoint = Qnil;
18
+
19
+ static record_t *last_record = NULL;
20
+ static uint64_t last_enter = 0;
21
+
22
+ static uint64_t
23
+ nanotime()
24
+ {
25
+ struct timespec ts;
26
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
27
+ rb_sys_fail("clock_gettime");
28
+ }
29
+ return ts.tv_sec * (uint64_t) 1000000000 + ts.tv_nsec;
30
+ }
31
+
32
+ static inline void
33
+ add_gc_cycle(uint64_t duration)
34
+ {
35
+ record_t *record = last_record;
36
+ while (record) {
37
+ record->cycles = record->cycles + 1;
38
+ record->duration = record->duration + duration;
39
+ record = record->parent;
40
+ }
41
+ }
42
+
43
+ static inline bool
44
+ gctracker_enabled()
45
+ {
46
+ return !NIL_P(tracepoint) && rb_tracepoint_enabled_p(tracepoint);
47
+ }
48
+
49
+ static void
50
+ gctracker_hook(VALUE tpval, void *data)
51
+ {
52
+ if (!gctracker_enabled()) {
53
+ return;
54
+ }
55
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
56
+ switch (rb_tracearg_event_flag(tparg)) {
57
+ case RUBY_INTERNAL_EVENT_GC_ENTER: {
58
+ last_enter = nanotime();
59
+ }
60
+ break;
61
+ case RUBY_INTERNAL_EVENT_GC_EXIT: {
62
+ if (last_enter) {
63
+ add_gc_cycle(nanotime() - last_enter);
64
+ }
65
+ last_enter = 0;
66
+ }
67
+ break;
68
+ }
69
+ }
70
+
71
+ static void
72
+ create_tracepoint()
73
+ {
74
+ rb_event_flag_t events;
75
+ events = RUBY_INTERNAL_EVENT_GC_ENTER | RUBY_INTERNAL_EVENT_GC_EXIT;
76
+ tracepoint = rb_tracepoint_new(0, events, gctracker_hook, (void *) NULL);
77
+ if (NIL_P(tracepoint)) {
78
+ rb_raise(rb_eRuntimeError, "GCTracker: Couldn't create tracepoint!");
79
+ }
80
+ rb_global_variable(&tracepoint);
81
+ }
82
+
83
+ static VALUE
84
+ gctracker_start_record(int argc, VALUE *argv, VALUE klass)
85
+ {
86
+ if(!gctracker_enabled()) {
87
+ return Qfalse;
88
+ }
89
+
90
+ record_t *record = (record_t *) calloc(1, sizeof(record_t));
91
+ if (!record) {
92
+ return Qfalse;
93
+ }
94
+
95
+ record->parent = last_record;
96
+ last_record = record;
97
+ return Qtrue;
98
+ }
99
+
100
+ static VALUE
101
+ gctracker_end_record(int argc, VALUE *argv, VALUE klass)
102
+ {
103
+ if (!last_record) {
104
+ return Qnil;
105
+ }
106
+ record_t *record = last_record;
107
+ last_record = record->parent;
108
+
109
+ VALUE stats = rb_ary_new2(2);
110
+ rb_ary_store(stats, 0, ULONG2NUM(record->cycles));
111
+ rb_ary_store(stats, 1, ULONG2NUM(record->duration));
112
+
113
+ free(record);
114
+
115
+ return stats;
116
+ }
117
+
118
+ static VALUE
119
+ gctracker_enable(int argc, VALUE *argv, VALUE klass)
120
+ {
121
+ if (NIL_P(tracepoint)) {
122
+ create_tracepoint();
123
+ }
124
+
125
+ if (gctracker_enabled()) {
126
+ return Qtrue;
127
+ }
128
+
129
+ rb_tracepoint_enable(tracepoint);
130
+ if (!gctracker_enabled()) {
131
+ rb_raise(rb_eRuntimeError, "GCTracker: Couldn't enable tracepoint!");
132
+ }
133
+
134
+ return Qtrue;
135
+ }
136
+
137
+ static VALUE
138
+ gctracker_disable(VALUE self)
139
+ {
140
+ if (!gctracker_enabled()) {
141
+ return Qfalse;
142
+ }
143
+
144
+ rb_tracepoint_disable(tracepoint);
145
+ if (gctracker_enabled()) {
146
+ rb_raise(rb_eRuntimeError, "GCTracker: Couldn't disable tracepoint!");
147
+ }
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
+
156
+ return Qtrue;
157
+ }
158
+
159
+ void
160
+ Init_gctrack()
161
+ {
162
+ VALUE mGC = rb_define_module("GC");
163
+ VALUE cTracker = rb_define_module_under(mGC, "Tracker");
164
+
165
+ rb_define_module_function(cTracker, "enable", gctracker_enable, 0);
166
+ rb_define_module_function(cTracker, "disable", gctracker_disable, 0);
167
+
168
+ rb_define_module_function(cTracker, "start_record", gctracker_start_record, 0);
169
+ rb_define_module_function(cTracker, "end_record", gctracker_end_record, 0);
170
+ }
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'gctrack'
3
+ s.version = '0.0.1'
4
+ s.summary = 'Track Ruby GC events'
5
+ s.description = <<-DOC
6
+ This gem can be used to track Ruby GC tracepoints that are normally only visible through GC extensions.
7
+ DOC
8
+ s.homepage = 'https://github.com/Shopify/gctrack'
9
+ s.authors = ['Scott Francis', 'Alex Snaps']
10
+ s.email = ['scott.francis@shopify.com', 'alex.snaps@shopify.com']
11
+ s.license = 'MIT'
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.extensions = ['ext/gctrack/extconf.rb']
15
+ s.add_development_dependency 'rake-compiler', '~> 1.0'
16
+ s.add_development_dependency 'test-unit'
17
+ end
@@ -0,0 +1,63 @@
1
+ require 'test/unit'
2
+ require 'gctrack/gctrack'
3
+
4
+ class TestGctrack < Test::Unit::TestCase
5
+ def test_enable
6
+ assert GC::Tracker.enable
7
+ ensure
8
+ GC::Tracker.disable
9
+ end
10
+
11
+ def test_disable
12
+ assert !GC::Tracker.disable
13
+ assert GC::Tracker.enable
14
+ assert GC::Tracker.disable
15
+ end
16
+
17
+ def test_returns_false_when_not_enabled
18
+ assert_equal false, GC::Tracker.disable
19
+ end
20
+
21
+ def test_enabled_generates_events
22
+ assert GC::Tracker.enable
23
+ assert GC::Tracker.start_record
24
+ GC.start
25
+ cycles, duration = GC::Tracker.end_record
26
+ assert cycles > 0
27
+ assert duration > 0
28
+ ensure
29
+ GC::Tracker.disable
30
+ end
31
+
32
+ def test_recurses
33
+ assert GC::Tracker.enable
34
+ assert GC::Tracker.start_record
35
+ a = "a"
36
+ 10.times { |i| a += a * i }
37
+ GC.start
38
+ assert GC::Tracker.start_record
39
+ a = "a"
40
+ 10.times { |i| a += a * i }
41
+ cycles_c, duration_c = GC::Tracker.end_record
42
+ cycles_p, duration_p = GC::Tracker.end_record
43
+ assert cycles_p > cycles_c
44
+ assert duration_p > duration_c
45
+ ensure
46
+ GC::Tracker.disable
47
+ end
48
+
49
+ def test_no_data_when_disabled
50
+ assert !GC::Tracker.start_record
51
+ assert GC::Tracker.end_record.nil?
52
+ end
53
+
54
+ def test_no_data_for_started_records_on_disable
55
+ assert GC::Tracker.enable
56
+ assert GC::Tracker.start_record
57
+ assert GC::Tracker.disable
58
+ assert GC::Tracker.end_record.nil?
59
+ ensure
60
+ GC::Tracker.disable
61
+ end
62
+ end
63
+
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gctrack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Scott Francis
8
+ - Alex Snaps
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-09-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake-compiler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: test-unit
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ description: " This gem can be used to track Ruby GC tracepoints that are normally
43
+ only visible through GC extensions.\n"
44
+ email:
45
+ - scott.francis@shopify.com
46
+ - alex.snaps@shopify.com
47
+ executables: []
48
+ extensions:
49
+ - ext/gctrack/extconf.rb
50
+ extra_rdoc_files: []
51
+ files:
52
+ - ".gitignore"
53
+ - ".travis.yml"
54
+ - Gemfile
55
+ - Gemfile.lock
56
+ - LICENSE.md
57
+ - README.md
58
+ - Rakefile
59
+ - ext/gctrack/extconf.rb
60
+ - ext/gctrack/gctrack.c
61
+ - gctrack.gemspec
62
+ - test/test_gctrack.rb
63
+ homepage: https://github.com/Shopify/gctrack
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.5.2
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Track Ruby GC events
87
+ test_files: []