gctrack 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []