objspace-age 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: 9aec62c2286763310ddf21e6c01b5d80139e4abf
4
+ data.tar.gz: 4ed882bc9f19a4d9a16b31ab93350ffef263aeee
5
+ SHA512:
6
+ metadata.gz: 5d8c99f697121384817637fd074c1031383388b2cfeec60730fee09ca4cfbba2cb89c71b6129daea8db0836aace23be4b80fa394ae4672738e46b77f2271ff8c
7
+ data.tar.gz: 57609b00df37902ffc6aa19a368a3266145fa70a0e0c5b8b46fe5fcc9c56ff8fbc1c4e4c61f1a669dd72b3ac017ff18187577532a1c0dd353e12076814be4623
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,10 @@
1
+ rvm:
2
+ - head
3
+
4
+ script: rake test
5
+
6
+ gemfile:
7
+ - Gemfile
8
+
9
+ notifications:
10
+ email: authornari+travis@gmail.com
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in objspace_age.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'test-unit', '~> 2.5.2'
8
+ end
@@ -0,0 +1,59 @@
1
+ = ObjectSpace::Age
2
+
3
+ * https://github.com/authorNari/objspace-age
4
+
5
+ == DESCRIPTION:
6
+
7
+ Show stats on object's age.
8
+ An age is how many time an object survive from GarbageCollect.
9
+
10
+ == INSTALL:
11
+
12
+ gem install objspace-age
13
+
14
+ == FEATURES/PROBLEMS:
15
+
16
+ * Support Ruby *2.1.0* or later
17
+
18
+ == USAGE:
19
+
20
+ # /tmp/a.rb
21
+ require 'objspace/age'
22
+
23
+ ObjectSpace::Age.enable
24
+ a = []
25
+ 1_000_000.times{ a << 'b' }
26
+ ObjectSpace::Age.stats_on(:class) # an array index indicates an age
27
+ # => [nil, nil, nil, nil, {String=>30309} ...
28
+ ObjectSpace::Age.stats_on(:line)
29
+ # => [nil, nil, ... , nil, {"/tmp/a.rb:6"=>617}, ... {"/tmp/a.rb:6"=>278271},
30
+ ObjectSpace::Age.how_old(a)
31
+ # => 58
32
+ ObjectSpace::Age.where(a)
33
+ # => '/tmp/a.rb:5'
34
+ ObjectSpace::Age.disable
35
+
36
+ == LICENSE:
37
+
38
+ (The MIT License)
39
+
40
+ Copyright (c) 2013 Narihiro Nakamura
41
+
42
+ Permission is hereby granted, free of charge, to any person obtaining
43
+ a copy of this software and associated documentation files (the
44
+ 'Software'), to deal in the Software without restriction, including
45
+ without limitation the rights to use, copy, modify, merge, publish,
46
+ distribute, sublicense, and/or sell copies of the Software, and to
47
+ permit persons to whom the Software is furnished to do so, subject to
48
+ the following conditions:
49
+
50
+ The above copyright notice and this permission notice shall be
51
+ included in all copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
54
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
55
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
56
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
57
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
58
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
59
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :compile do
4
+ sh "cd ext/objspace_age/ && ruby extconf.rb && make"
5
+ end
6
+
7
+ task :clean do
8
+ sh "cd ext/objspace_age/ && rm -f *.o *.so"
9
+ end
10
+
11
+ task :test => [:clean, :compile] do
12
+ sh "/usr/bin/env ruby test/run-test.rb"
13
+ end
@@ -0,0 +1,10 @@
1
+ require 'mkmf'
2
+
3
+ if with_config("test")
4
+ $defs << "-DOBJSPACE_HISTGRAM_TEST"
5
+ $CFLAGS << " -O0"
6
+ end
7
+
8
+ dir_config("objspace_age_ext")
9
+ create_header
10
+ create_makefile("objspace_age_ext")
@@ -0,0 +1,10 @@
1
+ #ifndef OBJSPACE_AGE_H
2
+
3
+ #include "ruby.h"
4
+ #include "ruby/re.h"
5
+ #include "extconf.h"
6
+ #include <assert.h>
7
+
8
+ void Init_objspace_age_ext(void);
9
+
10
+ #endif
@@ -0,0 +1,277 @@
1
+ /**********************************************************************
2
+
3
+ object_age_ext.c
4
+
5
+ This file is covered under the Ruby's license.
6
+ Original file is ruby/ext/objspace/object_tracing.c
7
+ Some parts in this file are modified by Narihiro Nakamura.
8
+
9
+ **********************************************************************/
10
+
11
+ #include "ruby/ruby.h"
12
+ #include "ruby/debug.h"
13
+
14
+ size_t rb_gc_count(void); /* from gc.c */
15
+
16
+ struct traceobj_age_arg {
17
+ VALUE newobj_trace;
18
+ VALUE freeobj_trace;
19
+ st_table *object_table;
20
+ st_table *str_table;
21
+ };
22
+
23
+ /* TODO: do not use GLOBAL VARIABLE!!! */
24
+ struct traceobj_age_arg traceobj_age_arg;
25
+
26
+ struct allocation_info {
27
+ const char *path;
28
+ unsigned long line;
29
+ size_t generation;
30
+ };
31
+
32
+ static const char *
33
+ make_unique_str(st_table *tbl, const char *str, long len)
34
+ {
35
+ if (!str) {
36
+ return NULL;
37
+ }
38
+ else {
39
+ st_data_t n;
40
+ char *result;
41
+
42
+ if (st_lookup(tbl, (st_data_t)str, &n)) {
43
+ st_insert(tbl, (st_data_t)str, n+1);
44
+ st_get_key(tbl, (st_data_t)str, (st_data_t *)&result);
45
+ }
46
+ else {
47
+ result = (char *)ruby_xmalloc(len+1);
48
+ strncpy(result, str, len);
49
+ result[len] = 0;
50
+ st_add_direct(tbl, (st_data_t)result, 1);
51
+ }
52
+ return result;
53
+ }
54
+ }
55
+
56
+ static void
57
+ delete_unique_str(st_table *tbl, const char *str)
58
+ {
59
+ if (str) {
60
+ st_data_t n;
61
+
62
+ st_lookup(tbl, (st_data_t)str, &n);
63
+ if (n == 1) {
64
+ st_delete(tbl, (st_data_t *)&str, 0);
65
+ ruby_xfree((char *)str);
66
+ }
67
+ else {
68
+ st_insert(tbl, (st_data_t)str, n-1);
69
+ }
70
+ }
71
+ }
72
+
73
+ static void
74
+ newobj_i(VALUE tpval, void *data)
75
+ {
76
+ struct traceobj_age_arg *arg = (struct traceobj_age_arg *)data;
77
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
78
+ VALUE obj = rb_tracearg_object(tparg);
79
+ VALUE path = rb_tracearg_path(tparg);
80
+ VALUE line = rb_tracearg_lineno(tparg);
81
+ struct allocation_info *info = (struct allocation_info *)ruby_xmalloc(sizeof(struct allocation_info));
82
+ const char *path_cstr = RTEST(path) ? make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0;
83
+
84
+ info->path = path_cstr;
85
+ info->line = NUM2INT(line);
86
+ info->generation = rb_gc_count();
87
+ st_insert(arg->object_table, (st_data_t)obj, (st_data_t)info);
88
+ }
89
+
90
+ static void
91
+ freeobj_i(VALUE tpval, void *data)
92
+ {
93
+ struct traceobj_age_arg *arg = (struct traceobj_age_arg *)data;
94
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
95
+ VALUE obj = rb_tracearg_object(tparg);
96
+ struct allocation_info *info;
97
+
98
+ if (st_delete(arg->object_table, (st_data_t *)&obj, (st_data_t *)&info)) {
99
+ delete_unique_str(arg->str_table, info->path);
100
+ ruby_xfree(info);
101
+ }
102
+ }
103
+
104
+ static int
105
+ free_keys_i(st_data_t key, st_data_t value, void *data)
106
+ {
107
+ ruby_xfree((void *)key);
108
+ return ST_CONTINUE;
109
+ }
110
+
111
+ static int
112
+ free_values_i(st_data_t key, st_data_t value, void *data)
113
+ {
114
+ ruby_xfree((void *)value);
115
+ return ST_CONTINUE;
116
+ }
117
+
118
+ static VALUE
119
+ stop_age_trace_object_allocations(VALUE objspace)
120
+ {
121
+ struct traceobj_age_arg *arg = (struct traceobj_age_arg *)&traceobj_age_arg;
122
+ rb_tracepoint_disable(arg->newobj_trace);
123
+ rb_tracepoint_disable(arg->freeobj_trace);
124
+ st_foreach(arg->object_table, free_values_i, 0);
125
+ st_foreach(arg->str_table, free_keys_i, 0);
126
+ st_free_table(arg->object_table);
127
+ st_free_table(arg->str_table);
128
+
129
+ arg->newobj_trace = NULL;
130
+
131
+ return Qnil;
132
+ }
133
+
134
+ static VALUE
135
+ start_age_trace_object_allocations(VALUE objspace)
136
+ {
137
+ traceobj_age_arg.newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, &traceobj_age_arg);
138
+ traceobj_age_arg.freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, &traceobj_age_arg);
139
+ traceobj_age_arg.object_table = st_init_numtable();
140
+ traceobj_age_arg.str_table = st_init_strtable();
141
+
142
+ rb_tracepoint_enable(traceobj_age_arg.newobj_trace);
143
+ rb_tracepoint_enable(traceobj_age_arg.freeobj_trace);
144
+
145
+ return Qnil;
146
+ }
147
+
148
+ struct allocation_info *
149
+ allocation_info(VALUE obj)
150
+ {
151
+ if (traceobj_age_arg.newobj_trace) {
152
+ struct allocation_info *info;
153
+ if (st_lookup(traceobj_age_arg.object_table, obj, (st_data_t *)&info)) {
154
+ return info;
155
+ }
156
+ }
157
+ return NULL;
158
+ }
159
+
160
+ static VALUE
161
+ allocation_sourceline(VALUE objspace, VALUE obj)
162
+ {
163
+ struct allocation_info *info = allocation_info(obj);
164
+ if (info) {
165
+ return INT2FIX(info->line);
166
+ }
167
+ else {
168
+ return Qnil;
169
+ }
170
+ }
171
+
172
+ static VALUE
173
+ allocation_sourcefile_and_line(VALUE objspace, VALUE obj)
174
+ {
175
+ struct allocation_info *info = allocation_info(obj);
176
+ if (info) {
177
+ if (info->path) {
178
+ return rb_str_plus(rb_str_new2(info->path),
179
+ rb_str_plus(rb_str_new_cstr(":"),
180
+ rb_fix2str(allocation_sourceline(objspace, obj), 10)));
181
+ }
182
+ return Qnil;
183
+ }
184
+ else {
185
+ return Qnil;
186
+ }
187
+ }
188
+
189
+ static VALUE
190
+ allocation_old(VALUE objspace, VALUE obj)
191
+ {
192
+ struct allocation_info *info = allocation_info(obj);
193
+ if (info) {
194
+ return SIZET2NUM(rb_gc_count() - info->generation);
195
+ }
196
+ else {
197
+ return Qnil;
198
+ }
199
+ }
200
+
201
+ struct arg_stat_data {
202
+ VALUE result;
203
+ };
204
+
205
+ static int
206
+ age_stat_line_i(VALUE obj, struct allocation_info *info, st_data_t data)
207
+ {
208
+ struct arg_stat_data *arg = (void*)data;
209
+ long age = rb_gc_count() - info->generation;
210
+ VALUE hash, cnt, path;
211
+
212
+ hash = rb_ary_entry(arg->result, age);
213
+ if (hash == Qnil) {
214
+ hash = rb_hash_new();
215
+ rb_ary_store(arg->result, age, hash);
216
+ }
217
+ path = allocation_sourcefile_and_line(Qnil, obj);
218
+ cnt = rb_hash_aref(hash, path);
219
+ if (cnt == Qnil) {
220
+ cnt = INT2NUM(0);
221
+ }
222
+ rb_hash_aset(hash, path, LONG2NUM(NUM2LONG(cnt)+1));
223
+ return ST_CONTINUE;
224
+ }
225
+
226
+ static int
227
+ age_stat_class_i(VALUE obj, struct allocation_info *info, st_data_t data)
228
+ {
229
+ struct arg_stat_data *arg = (void*)data;
230
+ long age = rb_gc_count() - info->generation;
231
+ VALUE hash, cnt, klass;
232
+
233
+ hash = rb_ary_entry(arg->result, age);
234
+ if (hash == Qnil) {
235
+ hash = rb_hash_new();
236
+ rb_ary_store(arg->result, age, hash);
237
+ }
238
+ klass = rb_obj_class(obj);
239
+ cnt = rb_hash_aref(hash, klass);
240
+ if (cnt == Qnil) {
241
+ cnt = INT2NUM(0);
242
+ }
243
+ rb_hash_aset(hash, rb_obj_class(obj), LONG2NUM(NUM2LONG(cnt)+1));
244
+ return ST_CONTINUE;
245
+ }
246
+
247
+ static VALUE
248
+ age_stats(VALUE objspace, VALUE type)
249
+ {
250
+ struct arg_stat_data data;
251
+ st_table *table = st_copy(traceobj_age_arg.object_table);
252
+ VALUE result = rb_ary_new();
253
+
254
+ data.result = result;
255
+ if (type == ID2SYM(rb_intern("class"))) {
256
+ st_foreach(table, age_stat_class_i, (st_data_t)&data);
257
+ }
258
+ else if (type == ID2SYM(rb_intern("line"))) {
259
+ st_foreach(table, age_stat_line_i, (st_data_t)&data);
260
+ }
261
+
262
+ st_free_table(table);
263
+ return result;
264
+ }
265
+
266
+ void
267
+ Init_objspace_age_ext(void)
268
+ {
269
+ VALUE rb_mObjSpace = rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
270
+ VALUE rb_mObjSpaceAge = rb_const_get(rb_mObjSpace, rb_intern("Age"));
271
+
272
+ rb_define_module_function(rb_mObjSpaceAge, "enable", start_age_trace_object_allocations, 0);
273
+ rb_define_module_function(rb_mObjSpaceAge, "disable", stop_age_trace_object_allocations, 0);
274
+ rb_define_module_function(rb_mObjSpaceAge, "where", allocation_sourcefile_and_line, 1);
275
+ rb_define_module_function(rb_mObjSpaceAge, "how_old", allocation_old, 1);
276
+ rb_define_module_function(rb_mObjSpaceAge, "stats_on", age_stats, 1);
277
+ }
@@ -0,0 +1,7 @@
1
+ require "objspace/age/version"
2
+
3
+ module ObjectSpace::Age
4
+ # Your code goes here...
5
+ end
6
+
7
+ require "objspace_age/objspace_age_ext"
@@ -0,0 +1,3 @@
1
+ module ObjectSpace::Age
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'objspace/age/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "objspace-age"
8
+ gem.version = ObjectSpace::Age::VERSION
9
+ gem.authors = ["Narihiro Nakamura"]
10
+ gem.email = ["authornari@gmail.com"]
11
+ gem.description = %q{Show stats on object's age}
12
+ gem.summary = %q{Show stats on object's age}
13
+ gem.homepage = "https://github.com/authorNari/objspace-age"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib", "ext"]
19
+ end
@@ -0,0 +1,55 @@
1
+ require 'minitest/unit'
2
+ $: << File.join(__dir__, '../lib')
3
+ $: << File.join(__dir__, '../ext')
4
+ $: << __dir__
5
+
6
+ require 'objspace/age'
7
+
8
+ MiniTest::Unit.autorun
9
+
10
+ class TestObjectSpaceAge < MiniTest::Unit::TestCase
11
+ def test_enable
12
+ assert_equal nil, ObjectSpace::Age.enable
13
+ ensure
14
+ ObjectSpace::Age.disable
15
+ end
16
+
17
+ def test_where
18
+ ObjectSpace::Age.enable
19
+ a = ''
20
+ assert_equal 'test/run-test.rb:19', ObjectSpace::Age.where(a)
21
+ ensure
22
+ ObjectSpace::Age.disable
23
+ end
24
+
25
+ def test_how_old
26
+ ObjectSpace::Age.enable
27
+ a = ''
28
+ GC.start
29
+ assert_equal 1, ObjectSpace::Age.how_old(a)
30
+ ensure
31
+ ObjectSpace::Age.disable
32
+ end
33
+
34
+ def test_stats_on_class
35
+ expect = [nil, nil, {Array=>1, String=>10}]
36
+ ObjectSpace::Age.enable
37
+ a = []
38
+ 10.times{ a << '' }
39
+ 2.times{ GC.start }
40
+ assert_equal expect, ObjectSpace::Age.stats_on(:class)
41
+ ensure
42
+ ObjectSpace::Age.disable
43
+ end
44
+
45
+ def test_stats_on_line
46
+ expect = [nil, nil, {"test/run-test.rb:48"=>1, "test/run-test.rb:49"=>10}]
47
+ ObjectSpace::Age.enable
48
+ a = []
49
+ 10.times{ a << '' }
50
+ 2.times{ GC.start }
51
+ assert_equal expect, ObjectSpace::Age.stats_on(:line)
52
+ ensure
53
+ ObjectSpace::Age.disable
54
+ end
55
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: objspace-age
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Narihiro Nakamura
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Show stats on object's age
14
+ email:
15
+ - authornari@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .gitignore
21
+ - .travis.yml
22
+ - Gemfile
23
+ - README.rdoc
24
+ - Rakefile
25
+ - ext/objspace_age/extconf.rb
26
+ - ext/objspace_age/objspace_age.h
27
+ - ext/objspace_age/objspace_age_ext.c
28
+ - lib/objspace/age.rb
29
+ - lib/objspace/age/version.rb
30
+ - objspace-age.gemspec
31
+ - test/run-test.rb
32
+ homepage: https://github.com/authorNari/objspace-age
33
+ licenses: []
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ - ext
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 2.0.3
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: Show stats on object's age
56
+ test_files:
57
+ - test/run-test.rb