scrym 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
18
+ lib/scrym_ext.so
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in scrym.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'test-unit', '~> 2.5.2'
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Narihiro Nakamura
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # Scrym: Self-collecting Ruby Mutators
2
+
3
+ A explicit Ruby's memory management system on programmer-controlled time without malloc/free way.
4
+
5
+ ## Usage
6
+
7
+ Usually Ruby's garbage collector manages all object on the heap.
8
+ However, if you use ``Scrym::Mutator.mark(obj)``, GC doesn't care ``obj`` at all time.
9
+ Instead, we explicitly collect those on a mutator at one's own risk.
10
+
11
+ ```ruby
12
+ require "scrym"
13
+ include Scrym
14
+
15
+ a = "a"
16
+ 10_000.times do |i|
17
+ a = a.succ
18
+ Mutator.mark(a)
19
+ Mutator.collect if (i % 10).zero?
20
+ end
21
+ p a #=> "ntq"
22
+ ```
23
+ Scrym collector's targets are only marked objects by Scrym.
24
+
25
+ ## Improvement of performance
26
+
27
+ ```zsh
28
+ % time ruby benchmark/bm_app_mandelbrot.rb
29
+ GC.count = 1785 : total time 0.7400470000000003(sec)
30
+ 2.14s user 0.04s system 99% cpu 2.185 total
31
+
32
+ % time ruby benchmark/bm_app_mandelbrot_with_scrym.rb
33
+ GC.count = 1092 : total time 0.40402999999999956(sec)
34
+ 1.92s user 0.04s system 99% cpu 1.963 total
35
+ ```
36
+
37
+ ## Installation
38
+
39
+ Add this line to your application's Gemfile:
40
+
41
+ gem 'scrym'
42
+
43
+ And then execute:
44
+
45
+ $ bundle
46
+
47
+ Or install it yourself as:
48
+
49
+ $ gem install scrym
50
+
51
+ ## Supported
52
+
53
+ * Ruby 1.9.3 or later
54
+
55
+ ## Not supported
56
+
57
+ * Finalizer (All programmers should not use any finalizer)
58
+
59
+ ## Acknowledgment
60
+
61
+ This product's idea is based on [Self-collecting Mutators](http://tiptoe.cs.uni-salzburg.at/short-term-memory/).
62
+ Thanks a lot!
63
+
64
+ ## Contributing
65
+
66
+ 1. Fork it
67
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
68
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
69
+ 4. Push to the branch (`git push origin my-new-feature`)
70
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/clean'
4
+
5
+ require 'rake/extensiontask'
6
+ Rake::ExtensionTask.new('scrym_ext') do |ext|
7
+ ext.ext_dir = 'ext/scrym'
8
+ if ENV["EXT_TEST"]
9
+ ext.config_options << '--with-test'
10
+ end
11
+ end
12
+
13
+ task :default => %w(test)
14
+
15
+ task :test => [:clean, :compile] do
16
+ sh "/usr/bin/env ruby test/run-test.rb"
17
+ end
18
+
19
+ CLEAN.include "**/*.o", "**/*.so", "**/*.bundle"
@@ -0,0 +1,26 @@
1
+ require 'complex'
2
+
3
+ GC::Profiler.enable
4
+
5
+ def mandelbrot? z
6
+ i = 0
7
+ while i<100
8
+ i += 1
9
+ z = z * z
10
+ return false if z.abs > 2
11
+ end
12
+ true
13
+ end
14
+
15
+ ary = []
16
+
17
+ (0..1000).each{|dx|
18
+ (0..1000).each{|dy|
19
+ x = dx / 50.0
20
+ y = dy / 50.0
21
+ c = Complex(x, y)
22
+ ary << c if mandelbrot?(c)
23
+ }
24
+ }
25
+
26
+ puts "GC.count = #{GC.count} : total time #{GC::Profiler.total_time}(sec)"
@@ -0,0 +1,34 @@
1
+ base_dir = File.expand_path(File.dirname(__FILE__))
2
+ top_dir = File.expand_path("..", base_dir)
3
+ $LOAD_PATH.unshift(File.join(top_dir, "lib"))
4
+
5
+ require 'scrym'
6
+ require 'complex'
7
+
8
+ include Scrym
9
+ GC::Profiler.enable
10
+
11
+ def mandelbrot? z
12
+ i = 0
13
+ while i<100
14
+ i += 1
15
+ z = z * z
16
+ return false if z.abs > 2
17
+ end
18
+ true
19
+ end
20
+
21
+ ary = []
22
+
23
+ (0..1000).each{|dx|
24
+ (0..1000).each{|dy|
25
+ x = dx / 50.0
26
+ y = dy / 50.0
27
+ c = Complex(x, y)
28
+ Mutator.mark(c)
29
+ ary << c if mandelbrot?(c)
30
+ Mutator.collect if (dy % 10) == 0
31
+ }
32
+ }
33
+
34
+ puts "GC.count = #{GC.count} : total time #{GC::Profiler.total_time}(sec)"
@@ -0,0 +1,14 @@
1
+ base_dir = File.expand_path(File.dirname(__FILE__))
2
+ top_dir = File.expand_path("..", base_dir)
3
+ $LOAD_PATH.unshift(File.join(top_dir, "lib"))
4
+
5
+ require "scrym"
6
+ include Scrym
7
+
8
+ a = "a"
9
+ 10_000.times do |i|
10
+ a = a.succ
11
+ Mutator.mark(a)
12
+ Mutator.collect if (i % 10).zero?
13
+ end
14
+ p a #=> "ntq"
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ if with_config("test")
4
+ $defs << "-DSCRYM_TEST"
5
+ $CFLAGS << " -O0"
6
+ end
7
+
8
+ if have_macro("FL_RESERVED2")
9
+ $defs << "-DHAVE_FL_RESERVED2"
10
+ end
11
+
12
+ dir_config("scrym_ext")
13
+ create_header
14
+ create_makefile("scrym_ext")
data/ext/scrym/scrym.h ADDED
@@ -0,0 +1,10 @@
1
+ #ifndef SCRYM_H
2
+
3
+ #include "ruby.h"
4
+ #include "ruby/re.h"
5
+ #include "extconf.h"
6
+ #include <assert.h>
7
+
8
+ void Init_scrym_ext(void);
9
+
10
+ #endif
@@ -0,0 +1,458 @@
1
+ #include "scrym.h"
2
+
3
+ #ifdef HAVE_FL_RESERVED2
4
+ #define SCRYM_MARK_PART_1 FL_RESERVED1
5
+ #define SCRYM_MARK_PART_2 FL_RESERVED2
6
+ #else
7
+ #define SCRYM_MARK_PART_1 FL_RESERVED
8
+ #define SCRYM_MARK_PART_2 FL_FINALIZE
9
+ #endif
10
+ #define SCRYM_MARK (SCRYM_MARK_PART_1 | SCRYM_MARK_PART_2)
11
+ #define SCRYM_DESCRIPTOR_CHUNK_SIZE 4000
12
+ #define SCRYM_CACHE_MIN 4
13
+
14
+ #define other_mark_part(mask) (mask ^ SCRYM_MARK)
15
+
16
+ typedef struct scrym_descriptor_chunk {
17
+ struct scrym_descriptor_chunk *next;
18
+ size_t index;
19
+ int mark_mask;
20
+ VALUE descriptors[SCRYM_DESCRIPTOR_CHUNK_SIZE];
21
+ } scrym_descriptor_chunk_t;
22
+
23
+ typedef struct scrym_descriptor {
24
+ scrym_descriptor_chunk_t *marked;
25
+ scrym_descriptor_chunk_t *expired;
26
+ scrym_descriptor_chunk_t *cache;
27
+ size_t cache_size;
28
+ size_t unused_cache_size;
29
+ int mark_mask;
30
+ } scrym_descriptor_t;
31
+
32
+ static scrym_descriptor_t * global_desc = NULL;
33
+ static VALUE rb_mScrym = Qnil;
34
+ static VALUE rb_cScrymMutator = Qnil;
35
+ static VALUE rb_cScrymDescriptor = Qnil;
36
+
37
+ /*---- descriptor ----*/
38
+
39
+ static scrym_descriptor_chunk_t *
40
+ scrym_alloc_descriptor_chunk(void)
41
+ {
42
+ scrym_descriptor_chunk_t *res;
43
+
44
+ res = xmalloc(sizeof(scrym_descriptor_chunk_t));
45
+ return res;
46
+ }
47
+
48
+ static void
49
+ scrym_cache_descriptor_chunk(scrym_descriptor_t *desc, scrym_descriptor_chunk_t *chunk)
50
+ {
51
+ chunk->next = desc->cache;
52
+ desc->cache = chunk;
53
+ desc->cache_size++;
54
+ }
55
+
56
+ static void
57
+ scrym_shrink_descriptor_chunk_cache(scrym_descriptor_t *desc)
58
+ {
59
+ scrym_descriptor_chunk_t *chunk;
60
+
61
+ if (desc->unused_cache_size > (desc->cache_size/2) &&
62
+ desc->unused_cache_size > SCRYM_CACHE_MIN) {
63
+ chunk = desc->cache;
64
+ desc->cache = desc->cache->next;
65
+ desc->cache_size--;
66
+ free(chunk);
67
+ }
68
+ desc->unused_cache_size = desc->cache_size;
69
+ }
70
+
71
+ static void
72
+ scrym_new_descriptor_chunk(scrym_descriptor_t *desc)
73
+ {
74
+ scrym_descriptor_chunk_t *next;
75
+
76
+ assert(desc->marked == NULL ||
77
+ desc->marked->index == SCRYM_DESCRIPTOR_CHUNK_SIZE);
78
+ if (desc->cache_size > 0) {
79
+ next = desc->cache;
80
+ desc->cache = desc->cache->next;
81
+ desc->cache_size--;
82
+ if (desc->unused_cache_size > desc->cache_size)
83
+ desc->unused_cache_size = desc->cache_size;
84
+ }
85
+ else {
86
+ next = scrym_alloc_descriptor_chunk();
87
+ }
88
+ next->next = desc->marked;
89
+ next->mark_mask = desc->mark_mask;
90
+ next->index = 0;
91
+ desc->marked = next;
92
+ }
93
+
94
+ static void
95
+ scrym_add_descriptor(scrym_descriptor_t *desc, VALUE data)
96
+ {
97
+ if (desc->marked == NULL ||
98
+ desc->marked->index == SCRYM_DESCRIPTOR_CHUNK_SIZE) {
99
+ scrym_new_descriptor_chunk(desc);
100
+ }
101
+ desc->marked->descriptors[desc->marked->index++] = data;
102
+ }
103
+
104
+ static void
105
+ scrym_descriptor_chunk_foreach(scrym_descriptor_chunk_t *chunk,
106
+ void (*func)(scrym_descriptor_chunk_t *, VALUE))
107
+ {
108
+ size_t i;
109
+
110
+ for(i=0; i < chunk->index; i++) {
111
+ func(chunk, chunk->descriptors[i]);
112
+ }
113
+ }
114
+
115
+ static void
116
+ scrym_init(scrym_descriptor_t *desc)
117
+ {
118
+ int i;
119
+
120
+ desc->mark_mask = SCRYM_MARK_PART_1;
121
+
122
+ for(i=0; i < SCRYM_CACHE_MIN; i++) {
123
+ scrym_cache_descriptor_chunk(desc, scrym_alloc_descriptor_chunk());
124
+ }
125
+ desc->unused_cache_size = desc->cache_size;
126
+ }
127
+
128
+
129
+ /* ---- mark for avoiding garbage collect ---- */
130
+
131
+ static void
132
+ scrym_descriptor_obj_mark(scrym_descriptor_chunk_t *chunk, VALUE obj)
133
+ {
134
+ rb_gc_mark(obj);
135
+ }
136
+
137
+ static void
138
+ scrym_descriptor_mark(scrym_descriptor_t *desc)
139
+ {
140
+ scrym_descriptor_chunk_t *tmp;
141
+
142
+ tmp = desc->marked;
143
+ while (tmp != NULL) {
144
+ scrym_descriptor_chunk_foreach(tmp, scrym_descriptor_obj_mark);
145
+ tmp = tmp->next;
146
+ }
147
+
148
+ tmp = desc->expired;
149
+ while (tmp != NULL) {
150
+ scrym_descriptor_chunk_foreach(tmp, scrym_descriptor_obj_mark);
151
+ tmp = tmp->next;
152
+ }
153
+ }
154
+
155
+ static void
156
+ scrym_descriptor_free(scrym_descriptor_t *desc)
157
+ {
158
+ scrym_descriptor_chunk_t *free, *tmp;
159
+
160
+ tmp = desc->marked;
161
+ while (tmp != NULL) {
162
+ free = tmp;
163
+ tmp = tmp->next;
164
+ xfree(free);
165
+ }
166
+
167
+ tmp = desc->expired;
168
+ while (tmp != NULL) {
169
+ free = tmp;
170
+ tmp = tmp->next;
171
+ xfree(free);
172
+ }
173
+
174
+ tmp = desc->cache;
175
+ while (tmp != NULL) {
176
+ free = tmp;
177
+ tmp = tmp->next;
178
+ xfree(free);
179
+ }
180
+
181
+ xfree(desc);
182
+ }
183
+
184
+
185
+ /* ---- mark ---- */
186
+
187
+ static VALUE
188
+ scrym_mark(VALUE self, VALUE obj)
189
+ {
190
+ if (IMMEDIATE_P(obj)) {
191
+ rb_raise(rb_eArgError, "can not accept an immediate value");
192
+ return;
193
+ }
194
+ if (BUILTIN_TYPE(obj) == T_NONE) {
195
+ rb_raise(rb_eArgError, "can not accept an node");
196
+ return;
197
+ }
198
+ if (FL_TEST(obj, FL_FINALIZE)) {
199
+ rb_raise(rb_eArgError, "defined a finalizer");
200
+ return;
201
+ }
202
+ if (RBASIC(obj)->flags & global_desc->mark_mask) {
203
+ return;
204
+ }
205
+ scrym_add_descriptor(global_desc, obj);
206
+ RBASIC(obj)->flags |= global_desc->mark_mask;
207
+ return Qnil;
208
+ }
209
+
210
+ /* ---- collect ---- */
211
+
212
+
213
+ /* The original code is gc.c on trunk */
214
+ static void
215
+ scrym_obj_free(VALUE obj)
216
+ {
217
+ switch (BUILTIN_TYPE(obj)) {
218
+ case T_NIL:
219
+ case T_FIXNUM:
220
+ case T_TRUE:
221
+ case T_FALSE:
222
+ rb_bug("scrym_obj_free() called for broken object");
223
+ break;
224
+ }
225
+
226
+ if (FL_TEST(obj, FL_EXIVAR)) {
227
+ rb_free_generic_ivar((VALUE)obj);
228
+ FL_UNSET(obj, FL_EXIVAR);
229
+ }
230
+
231
+ switch (BUILTIN_TYPE(obj)) {
232
+ case T_OBJECT:
233
+ if (!(RBASIC(obj)->flags & ROBJECT_EMBED) &&
234
+ ROBJECT(obj)->as.heap.ivptr) {
235
+ xfree(ROBJECT(obj)->as.heap.ivptr);
236
+ }
237
+ break;
238
+ case T_MODULE:
239
+ case T_CLASS:
240
+ rb_clear_cache_by_class((VALUE)obj);
241
+ if (RCLASS(obj)->m_tbl) {
242
+ rb_free_m_table(RCLASS(obj)->m_tbl);
243
+ }
244
+ if (RCLASS_IV_TBL(obj)) {
245
+ st_free_table(RCLASS_IV_TBL(obj));
246
+ }
247
+ if (RCLASS_CONST_TBL(obj)) {
248
+ rb_free_const_table(RCLASS_CONST_TBL(obj));
249
+ }
250
+ if (RCLASS_IV_INDEX_TBL(obj)) {
251
+ st_free_table(RCLASS_IV_INDEX_TBL(obj));
252
+ }
253
+ xfree(RCLASS(obj)->ptr);
254
+ break;
255
+ case T_STRING:
256
+ rb_str_free(obj);
257
+ break;
258
+ case T_ARRAY:
259
+ rb_ary_free(obj);
260
+ break;
261
+ case T_HASH:
262
+ if (RHASH(obj)->ntbl) {
263
+ st_free_table(RHASH(obj)->ntbl);
264
+ }
265
+ break;
266
+ case T_REGEXP:
267
+ if (RREGEXP(obj)->ptr) {
268
+ onig_free(RREGEXP(obj)->ptr);
269
+ }
270
+ break;
271
+ case T_DATA:
272
+ if (DATA_PTR(obj)) {
273
+ if (RTYPEDDATA_P(obj)) {
274
+ RDATA(obj)->dfree = RTYPEDDATA(obj)->type->function.dfree;
275
+ }
276
+ if (RDATA(obj)->dfree == (RUBY_DATA_FUNC)-1) {
277
+ xfree(DATA_PTR(obj));
278
+ }
279
+ }
280
+ break;
281
+ case T_MATCH:
282
+ if ((R_CAST(RMatch)(obj))->rmatch) {
283
+ struct rmatch *rm = (R_CAST(RMatch)(obj))->rmatch;
284
+ onig_region_free(&rm->regs, 0);
285
+ if (rm->char_offset)
286
+ xfree(rm->char_offset);
287
+ xfree(rm);
288
+ }
289
+ break;
290
+ case T_FILE:
291
+ if (RFILE(obj)->fptr) {
292
+ rb_io_fptr_finalize(RFILE(obj)->fptr);
293
+ }
294
+ break;
295
+ case T_RATIONAL:
296
+ case T_COMPLEX:
297
+ break;
298
+ case T_ICLASS:
299
+ /* iClass shares table with the module */
300
+ xfree(RCLASS(obj)->ptr);
301
+ break;
302
+
303
+ case T_FLOAT:
304
+ break;
305
+
306
+ case T_BIGNUM:
307
+ if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
308
+ xfree(RBIGNUM_DIGITS(obj));
309
+ }
310
+ break;
311
+
312
+ case T_STRUCT:
313
+ if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
314
+ RSTRUCT(obj)->as.heap.ptr) {
315
+ xfree(RSTRUCT(obj)->as.heap.ptr);
316
+ }
317
+ break;
318
+
319
+ default:
320
+ rb_bug("scrym_collect(): unknown data type 0x%x(%p) 0x%"PRIxVALUE,
321
+ BUILTIN_TYPE(obj), (void*)obj, RBASIC(obj)->flags);
322
+ }
323
+
324
+ return 0;
325
+ }
326
+
327
+
328
+ static void
329
+ scrym_expire(scrym_descriptor_chunk_t *chunk, VALUE obj)
330
+ {
331
+ RBASIC(obj)->flags &= ~(chunk->mark_mask);
332
+ if (!(RBASIC(obj)->flags & other_mark_part(chunk->mark_mask))) {
333
+ scrym_obj_free(obj);
334
+ rb_gc_force_recycle(obj);
335
+ }
336
+ }
337
+
338
+ static int
339
+ scrym_expire_chunk(void)
340
+ {
341
+ scrym_descriptor_chunk_t *next;
342
+
343
+ if (global_desc->expired == NULL) {
344
+ return NULL;
345
+ }
346
+ scrym_descriptor_chunk_foreach(global_desc->expired, scrym_expire);
347
+ next = global_desc->expired->next;
348
+ scrym_cache_descriptor_chunk(global_desc, global_desc->expired);
349
+ global_desc->expired = next;
350
+ return Qtrue;
351
+ }
352
+
353
+ static VALUE
354
+ scrym_collect(VALUE self)
355
+ {
356
+ while(scrym_expire_chunk());
357
+ global_desc->expired = global_desc->marked;
358
+ global_desc->marked = NULL;
359
+ global_desc->mark_mask = other_mark_part(global_desc->mark_mask);
360
+ scrym_shrink_descriptor_chunk_cache(global_desc);
361
+ return Qnil;
362
+ }
363
+
364
+ #ifdef SCRYM_TEST
365
+ static VALUE
366
+ scrym_test(VALUE self) {
367
+ size_t i;
368
+
369
+ {
370
+ puts("scrym_init");
371
+ assert(global_desc->expired == NULL);
372
+ assert(global_desc->marked == NULL);
373
+ assert(global_desc->cache != NULL);
374
+ }
375
+
376
+ {
377
+ size_t j;
378
+ puts("scrym_add_descriptor");
379
+ for(i = 0; i < SCRYM_CACHE_MIN; i++) {
380
+ for(j = 0; j < SCRYM_DESCRIPTOR_CHUNK_SIZE; j++) {
381
+ scrym_add_descriptor(global_desc, j);
382
+ }
383
+ }
384
+ for(j = 0; j < SCRYM_DESCRIPTOR_CHUNK_SIZE; j++) {
385
+ assert(global_desc->marked->descriptors[j] == (VALUE)j);
386
+ }
387
+ assert(global_desc->marked->next->next->next != NULL);
388
+ assert(global_desc->marked->next->next->next->descriptors[SCRYM_DESCRIPTOR_CHUNK_SIZE] != SCRYM_DESCRIPTOR_CHUNK_SIZE-1);
389
+ assert(global_desc->marked->next->next->next->next == NULL);
390
+ assert(global_desc->expired == NULL);
391
+ assert(global_desc->cache == NULL);
392
+ assert(global_desc->cache_size == 0);
393
+ assert(global_desc->unused_cache_size == 0);
394
+ global_desc->cache = global_desc->marked;
395
+ global_desc->marked = NULL;
396
+ global_desc->cache_size = SCRYM_CACHE_MIN;
397
+ }
398
+
399
+ {
400
+ VALUE str = rb_str_new_cstr("test");
401
+ VALUE str2 = rb_str_new_cstr("test2");
402
+ puts("scrym_collect");
403
+ assert(scrym_expire_chunk() == Qfalse);
404
+ assert((RBASIC(str)->flags & SCRYM_MARK) == 0);
405
+
406
+ puts(" scrym_mark1");
407
+ scrym_mark(Qnil, str);
408
+ scrym_mark(Qnil, str);
409
+ assert(global_desc->marked->index == 1);
410
+ assert(RBASIC(str)->flags & global_desc->marked->mark_mask);
411
+ assert(!(RBASIC(str)->flags & other_mark_part(global_desc->marked->mark_mask)));
412
+
413
+ puts(" scrym_mark2");
414
+ scrym_mark(Qnil, str2);
415
+ assert(global_desc->marked->index == 2);
416
+ assert(RBASIC(str2)->flags & global_desc->marked->mark_mask);
417
+
418
+ puts(" collect1");
419
+ scrym_collect(Qnil);
420
+ scrym_mark(Qnil, str2);
421
+
422
+ puts(" collect2");
423
+ scrym_collect(Qnil);
424
+ assert(RBASIC(str)->flags == 0);
425
+ assert(RBASIC(str2)->flags != 0);
426
+ assert(global_desc->marked == NULL);
427
+ assert(global_desc->expired != NULL);
428
+
429
+ puts(" collect3");
430
+ scrym_collect(Qnil);
431
+ assert(RBASIC(str2)->flags == 0);
432
+ assert(global_desc->expired == NULL);
433
+ assert(global_desc->cache_size == SCRYM_CACHE_MIN);
434
+ }
435
+ }
436
+ #endif
437
+
438
+ void
439
+ Init_scrym_ext(void)
440
+ {
441
+ VALUE desc;
442
+
443
+ rb_mScrym = rb_define_module("Scrym");
444
+ rb_cScrymMutator = rb_define_class_under(rb_mScrym, "Mutator", rb_cObject);
445
+ rb_define_singleton_method(rb_cScrymMutator, "mark", scrym_mark, 1);
446
+ rb_define_singleton_method(rb_cScrymMutator, "collect", scrym_collect, 0);
447
+ rb_cScrymDescriptor = rb_define_class_under(rb_mScrym, "Descriptor", rb_cObject);
448
+
449
+ global_desc = (scrym_descriptor_t *)xmalloc(sizeof(scrym_descriptor_t));
450
+ MEMZERO(global_desc, scrym_descriptor_t, 1);
451
+ scrym_init(global_desc);
452
+ desc = Data_Wrap_Struct(rb_cScrymDescriptor, scrym_descriptor_mark, scrym_descriptor_free, global_desc);
453
+ rb_iv_set(rb_cScrymMutator, "@__descriptor", desc);
454
+
455
+ #ifdef SCRYM_TEST
456
+ rb_define_singleton_method(rb_cScrymMutator, "test", scrym_test, 0);
457
+ #endif
458
+ }
@@ -0,0 +1,3 @@
1
+ module Scrym
2
+ VERSION = "0.0.1"
3
+ end
data/lib/scrym.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "scrym/version"
2
+ require "scrym_ext"
3
+
4
+ module Scrym
5
+ end
data/lib/scrym_ext.so ADDED
Binary file
data/scrym.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/scrym/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Narihiro Nakamura"]
6
+ gem.email = ["authornari@gmail.com"]
7
+ gem.description = %q{A explicit Ruby's memory management system on programmer-controlled time without malloc/free way.}
8
+ gem.summary = %q{A explicit Ruby's memory management system on programmer-controlled time without malloc/free way.}
9
+ gem.homepage = "https://github.com/authorNari/scrym"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "scrym"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Scrym::VERSION
17
+
18
+ gem.add_development_dependency "rake-compiler", "~> 0.8.1"
19
+ end
data/test/run-test.rb ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ base_dir = File.expand_path(File.dirname(__FILE__))
5
+ top_dir = File.expand_path("..", base_dir)
6
+ $LOAD_PATH.unshift(File.join(top_dir, "lib"))
7
+ $LOAD_PATH.unshift(File.join(top_dir, "test"))
8
+
9
+ require "rubygems"
10
+ require "bundler"
11
+ Bundler.require(:default, :test)
12
+ require "test/unit"
13
+
14
+ require "scrym"
15
+ require "./test/test_scrym_ext"
16
+ test_file = "./test/test_*.rb"
17
+ Dir.glob(test_file) do |file|
18
+ require file
19
+ end
@@ -0,0 +1,12 @@
1
+ class TestScm < Test::Unit::TestCase
2
+ include Scrym
3
+
4
+ def test_mark
5
+ str = "mark"
6
+ Mutator.mark(str)
7
+ assert_raise ArgumentError do
8
+ Mutator.mark(1)
9
+ end
10
+ Mutator.collect
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ if defined?(Scrym::Mutator.test)
2
+ class TestScmExt < Test::Unit::TestCase
3
+ def test_ext
4
+ puts "--- C extension test start ---"
5
+ Scrym::Mutator.test
6
+ puts "--- C extension test end ---"
7
+ end
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scrym
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Narihiro Nakamura
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake-compiler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.1
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.8.1
30
+ description: A explicit Ruby's memory management system on programmer-controlled time
31
+ without malloc/free way.
32
+ email:
33
+ - authornari@gmail.com
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - Gemfile
40
+ - LICENSE
41
+ - README.md
42
+ - Rakefile
43
+ - benchmark/bm_app_mandelbrot.rb
44
+ - benchmark/bm_app_mandelbrot_with_scrym.rb
45
+ - benchmark/bm_succ_with_scrym.rb
46
+ - ext/scrym/extconf.rb
47
+ - ext/scrym/scrym.h
48
+ - ext/scrym/scrym_ext.c
49
+ - lib/scrym.rb
50
+ - lib/scrym/version.rb
51
+ - lib/scrym_ext.so
52
+ - scrym.gemspec
53
+ - test/run-test.rb
54
+ - test/test_scrym.rb
55
+ - test/test_scrym_ext.rb
56
+ homepage: https://github.com/authorNari/scrym
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.23
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: A explicit Ruby's memory management system on programmer-controlled time
80
+ without malloc/free way.
81
+ test_files:
82
+ - test/run-test.rb
83
+ - test/test_scrym.rb
84
+ - test/test_scrym_ext.rb