kamal-railsbench 0.9.9.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/BUGS +2 -0
  2. data/CHANGELOG +2124 -0
  3. data/GCPATCH +73 -0
  4. data/INSTALL +75 -0
  5. data/LICENSE +222 -0
  6. data/Manifest.txt +53 -0
  7. data/PROBLEMS +56 -0
  8. data/README +337 -0
  9. data/Rakefile +51 -0
  10. data/bin/railsbench +80 -0
  11. data/config/benchmarking.rb +21 -0
  12. data/config/benchmarks.rb +21 -0
  13. data/config/benchmarks.yml +2 -0
  14. data/images/empty.png +0 -0
  15. data/images/minus.png +0 -0
  16. data/images/plus.png +0 -0
  17. data/install.rb +70 -0
  18. data/latest_changes.txt +18 -0
  19. data/lib/benchmark.rb +576 -0
  20. data/lib/railsbench/benchmark.rb +576 -0
  21. data/lib/railsbench/benchmark_specs.rb +63 -0
  22. data/lib/railsbench/gc_info.rb +158 -0
  23. data/lib/railsbench/perf_info.rb +146 -0
  24. data/lib/railsbench/perf_utils.rb +202 -0
  25. data/lib/railsbench/railsbenchmark.rb +640 -0
  26. data/lib/railsbench/version.rb +9 -0
  27. data/lib/railsbench/write_headers_only.rb +15 -0
  28. data/postinstall.rb +12 -0
  29. data/ruby184gc.patch +516 -0
  30. data/ruby185gc.patch +562 -0
  31. data/ruby186gc.patch +564 -0
  32. data/ruby19gc.patch +2425 -0
  33. data/script/convert_raw_data_files +49 -0
  34. data/script/generate_benchmarks +171 -0
  35. data/script/perf_bench +74 -0
  36. data/script/perf_comp +151 -0
  37. data/script/perf_comp_gc +113 -0
  38. data/script/perf_diff +48 -0
  39. data/script/perf_diff_gc +53 -0
  40. data/script/perf_html +103 -0
  41. data/script/perf_plot +225 -0
  42. data/script/perf_plot_gc +254 -0
  43. data/script/perf_prof +87 -0
  44. data/script/perf_run +39 -0
  45. data/script/perf_run_gc +40 -0
  46. data/script/perf_table +104 -0
  47. data/script/perf_tex +58 -0
  48. data/script/perf_times +66 -0
  49. data/script/perf_times_gc +94 -0
  50. data/script/run_urls +57 -0
  51. data/setup.rb +1585 -0
  52. data/test/railsbench_test.rb +11 -0
  53. data/test/test_helper.rb +2 -0
  54. metadata +133 -0
@@ -0,0 +1,562 @@
1
+ --- gc.c.orig 2006-08-25 10:12:46.000000000 +0200
2
+ +++ gc.c 2007-05-06 10:55:19.000000000 +0200
3
+ @@ -22,8 +22,16 @@
4
+ #include <setjmp.h>
5
+ #include <sys/types.h>
6
+
7
+ +#ifdef _WIN32
8
+ +#include <string.h>
9
+ +#else
10
+ +#include <strings.h>
11
+ +#endif
12
+ +
13
+ #ifdef HAVE_SYS_TIME_H
14
+ #include <sys/time.h>
15
+ +#elif defined(_WIN32)
16
+ +#include <time.h>
17
+ #endif
18
+
19
+ #ifdef HAVE_SYS_RESOURCE_H
20
+ @@ -54,7 +62,6 @@
21
+ #if !defined(setjmp) && defined(HAVE__SETJMP)
22
+ #define setjmp(env) _setjmp(env)
23
+ #endif
24
+ -
25
+ /* Make alloca work the best possible way. */
26
+ #ifdef __GNUC__
27
+ # ifndef atarist
28
+ @@ -173,8 +180,17 @@
29
+ RUBY_CRITICAL(free(x));
30
+ }
31
+
32
+ +#if HAVE_LONG_LONG
33
+ +#define GC_TIME_TYPE LONG_LONG
34
+ +#else
35
+ +#define GC_TIME_TYPE long
36
+ +#endif
37
+ +
38
+ extern int ruby_in_compile;
39
+ static int dont_gc;
40
+ +static int gc_statistics = 0;
41
+ +static GC_TIME_TYPE gc_time = 0;
42
+ +static int gc_collections = 0;
43
+ static int during_gc;
44
+ static int need_call_final = 0;
45
+ static st_table *finalizer_table = 0;
46
+ @@ -209,7 +225,7 @@
47
+ * Disables garbage collection, returning <code>true</code> if garbage
48
+ * collection was already disabled.
49
+ *
50
+ - * GC.disable #=> false
51
+ + * GC.disable #=> false or true
52
+ * GC.disable #=> true
53
+ *
54
+ */
55
+ @@ -223,6 +239,104 @@
56
+ return old;
57
+ }
58
+
59
+ +/*
60
+ + * call-seq:
61
+ + * GC.enable_stats => true or false
62
+ + *
63
+ + * Enables garbage collection statistics, returning <code>true</code> if garbage
64
+ + * collection statistics was already enabled.
65
+ + *
66
+ + * GC.enable_stats #=> false or true
67
+ + * GC.enable_stats #=> true
68
+ + *
69
+ + */
70
+ +
71
+ +VALUE
72
+ +rb_gc_enable_stats()
73
+ +{
74
+ + int old = gc_statistics;
75
+ + gc_statistics = Qtrue;
76
+ + return old;
77
+ +}
78
+ +
79
+ +/*
80
+ + * call-seq:
81
+ + * GC.disable_stats => true or false
82
+ + *
83
+ + * Disables garbage collection statistics, returning <code>true</code> if garbage
84
+ + * collection statistics was already disabled.
85
+ + *
86
+ + * GC.disable_stats #=> false or true
87
+ + * GC.disable_stats #=> true
88
+ + *
89
+ + */
90
+ +
91
+ +VALUE
92
+ +rb_gc_disable_stats()
93
+ +{
94
+ + int old = gc_statistics;
95
+ + gc_statistics = Qfalse;
96
+ + return old;
97
+ +}
98
+ +
99
+ +/*
100
+ + * call-seq:
101
+ + * GC.clear_stats => nil
102
+ + *
103
+ + * Clears garbage collection statistics, returning nil. This resets the number
104
+ + * of collections (GC.collections) and the time used (GC.time) to 0.
105
+ + *
106
+ + * GC.clear_stats #=> nil
107
+ + *
108
+ + */
109
+ +
110
+ +VALUE
111
+ +rb_gc_clear_stats()
112
+ +{
113
+ + gc_collections = 0;
114
+ + gc_time = 0;
115
+ + return Qnil;
116
+ +}
117
+ +
118
+ +/*
119
+ + * call-seq:
120
+ + * GC.collections => Integer
121
+ + *
122
+ + * Returns the number of garbage collections performed while GC statistics collection
123
+ + * was enabled.
124
+ + *
125
+ + * GC.collections #=> 35
126
+ + *
127
+ + */
128
+ +
129
+ +VALUE
130
+ +rb_gc_collections()
131
+ +{
132
+ + return INT2NUM(gc_collections);
133
+ +}
134
+ +
135
+ +/*
136
+ + * call-seq:
137
+ + * GC.time => Integer
138
+ + *
139
+ + * Returns the time spent during garbage collection while GC statistics collection
140
+ + * was enabled (in micro seconds).
141
+ + *
142
+ + * GC.time #=> 20000
143
+ + *
144
+ + */
145
+ +
146
+ +VALUE
147
+ +rb_gc_time()
148
+ +{
149
+ +#if HAVE_LONG_LONG
150
+ + return LL2NUM(gc_time);
151
+ +#else
152
+ + return LONG2NUM(gc_time);
153
+ +#endif
154
+ +}
155
+ +
156
+ +
157
+ VALUE rb_mGC;
158
+
159
+ static struct gc_list {
160
+ @@ -314,7 +428,7 @@
161
+ static RVALUE *freelist = 0;
162
+ static RVALUE *deferred_final_list = 0;
163
+
164
+ -#define HEAPS_INCREMENT 10
165
+ +static int heaps_increment = 10;
166
+ static struct heaps_slot {
167
+ void *membase;
168
+ RVALUE *slot;
169
+ @@ -323,13 +437,165 @@
170
+ static int heaps_length = 0;
171
+ static int heaps_used = 0;
172
+
173
+ -#define HEAP_MIN_SLOTS 10000
174
+ -static int heap_slots = HEAP_MIN_SLOTS;
175
+ +static int heap_min_slots = 10000;
176
+ +static int heap_slots = 10000;
177
+ +
178
+ +static int heap_free_min = 4096;
179
+ +static int heap_slots_increment = 10000;
180
+ +static double heap_slots_growth_factor = 1.8;
181
+ +
182
+ +static long initial_malloc_limit = GC_MALLOC_LIMIT;
183
+
184
+ -#define FREE_MIN 4096
185
+ +static int verbose_gc_stats = Qfalse;
186
+ +
187
+ +static FILE* gc_data_file = NULL;
188
+
189
+ static RVALUE *himem, *lomem;
190
+
191
+ +static void set_gc_parameters()
192
+ +{
193
+ + char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr,
194
+ + *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr;
195
+ +
196
+ + gc_data_file = stderr;
197
+ +
198
+ + gc_stats_ptr = getenv("RUBY_GC_STATS");
199
+ + if (gc_stats_ptr != NULL) {
200
+ + int gc_stats_i = atoi(gc_stats_ptr);
201
+ + if (gc_stats_i > 0) {
202
+ + verbose_gc_stats = Qtrue;
203
+ + }
204
+ + }
205
+ +
206
+ + gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE");
207
+ + if (gc_heap_file_ptr != NULL) {
208
+ + FILE* data_file = fopen(gc_heap_file_ptr, "w");
209
+ + if (data_file != NULL) {
210
+ + gc_data_file = data_file;
211
+ + }
212
+ + else {
213
+ + fprintf(stderr,
214
+ + "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr);
215
+ + }
216
+ + }
217
+ +
218
+ + min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
219
+ + if (min_slots_ptr != NULL) {
220
+ + int min_slots_i = atoi(min_slots_ptr);
221
+ + if (verbose_gc_stats) {
222
+ + fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr);
223
+ + }
224
+ + if (min_slots_i > 0) {
225
+ + heap_slots = min_slots_i;
226
+ + heap_min_slots = min_slots_i;
227
+ + }
228
+ + }
229
+ +
230
+ + free_min_ptr = getenv("RUBY_HEAP_FREE_MIN");
231
+ + if (free_min_ptr != NULL) {
232
+ + int free_min_i = atoi(free_min_ptr);
233
+ + if (verbose_gc_stats) {
234
+ + fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr);
235
+ + }
236
+ + if (free_min_i > 0) {
237
+ + heap_free_min = free_min_i;
238
+ + }
239
+ + }
240
+ +
241
+ + heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT");
242
+ + if (heap_incr_ptr != NULL) {
243
+ + int heap_incr_i = atoi(heap_incr_ptr);
244
+ + if (verbose_gc_stats) {
245
+ + fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr);
246
+ + }
247
+ + if (heap_incr_i > 0) {
248
+ + heaps_increment = heap_incr_i;
249
+ + }
250
+ + }
251
+ +
252
+ + heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT");
253
+ + if (heap_slots_incr_ptr != NULL) {
254
+ + int heap_slots_incr_i = atoi(heap_slots_incr_ptr);
255
+ + if (verbose_gc_stats) {
256
+ + fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr);
257
+ + }
258
+ + if (heap_slots_incr_i > 0) {
259
+ + heap_slots_increment = heap_slots_incr_i;
260
+ + }
261
+ + }
262
+ +
263
+ + heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR");
264
+ + if (heap_slots_growth_factor_ptr != NULL) {
265
+ + double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr);
266
+ + if (verbose_gc_stats) {
267
+ + fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr);
268
+ + }
269
+ + if (heap_slots_growth_factor_d > 0) {
270
+ + heap_slots_growth_factor = heap_slots_growth_factor_d;
271
+ + }
272
+ + }
273
+ +
274
+ + malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
275
+ + if (malloc_limit_ptr != NULL) {
276
+ + int malloc_limit_i = atol(malloc_limit_ptr);
277
+ + if (verbose_gc_stats) {
278
+ + fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr);
279
+ + }
280
+ + if (malloc_limit_i > 0) {
281
+ + initial_malloc_limit = malloc_limit_i;
282
+ + }
283
+ + }
284
+ +}
285
+ +
286
+ +/*
287
+ + * call-seq:
288
+ + * GC.dump => nil
289
+ + *
290
+ + * dumps information about the current GC data structures to the GC log file
291
+ + *
292
+ + * GC.dump #=> nil
293
+ + *
294
+ + */
295
+ +
296
+ +VALUE
297
+ +rb_gc_dump()
298
+ +{
299
+ + int i;
300
+ +
301
+ + for (i = 0; i < heaps_used; i++) {
302
+ + int heap_size = heaps[i].limit;
303
+ + fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size);
304
+ + }
305
+ +
306
+ + return Qnil;
307
+ +}
308
+ +
309
+ +/*
310
+ + * call-seq:
311
+ + * GC.log String => String
312
+ + *
313
+ + * Logs string to the GC data file and returns it.
314
+ + *
315
+ + * GC.log "manual GC call" #=> "manual GC call"
316
+ + *
317
+ + */
318
+ +
319
+ +VALUE
320
+ +rb_gc_log(self, original_str)
321
+ + VALUE self, original_str;
322
+ +{
323
+ + if (original_str == Qnil) {
324
+ + fprintf(gc_data_file, "\n");
325
+ + }
326
+ + else {
327
+ + VALUE str = StringValue(original_str);
328
+ + char *p = RSTRING(str)->ptr;
329
+ + fprintf(gc_data_file, "%s\n", p);
330
+ + }
331
+ + return original_str;
332
+ +}
333
+ +
334
+ +
335
+ static void
336
+ add_heap()
337
+ {
338
+ @@ -340,7 +606,7 @@
339
+ struct heaps_slot *p;
340
+ int length;
341
+
342
+ - heaps_length += HEAPS_INCREMENT;
343
+ + heaps_length += heaps_increment;
344
+ length = heaps_length*sizeof(struct heaps_slot);
345
+ RUBY_CRITICAL(
346
+ if (heaps_used > 0) {
347
+ @@ -356,10 +622,10 @@
348
+ for (;;) {
349
+ RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
350
+ if (p == 0) {
351
+ - if (heap_slots == HEAP_MIN_SLOTS) {
352
+ + if (heap_slots == heap_min_slots) {
353
+ rb_memerror();
354
+ }
355
+ - heap_slots = HEAP_MIN_SLOTS;
356
+ + heap_slots = heap_min_slots;
357
+ continue;
358
+ }
359
+ heaps[heaps_used].membase = p;
360
+ @@ -375,8 +641,9 @@
361
+ if (lomem == 0 || lomem > p) lomem = p;
362
+ if (himem < pend) himem = pend;
363
+ heaps_used++;
364
+ - heap_slots *= 1.8;
365
+ - if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
366
+ + heap_slots += heap_slots_increment;
367
+ + heap_slots_increment *= heap_slots_growth_factor;
368
+ + if (heap_slots <= 0) heap_slots = heap_min_slots;
369
+
370
+ while (p < pend) {
371
+ p->as.free.flags = 0;
372
+ @@ -1026,6 +1293,39 @@
373
+ }
374
+ }
375
+
376
+ +static char* obj_type(int tp)
377
+ +{
378
+ + switch (tp) {
379
+ + case T_NIL : return "NIL";
380
+ + case T_OBJECT : return "OBJECT";
381
+ + case T_CLASS : return "CLASS";
382
+ + case T_ICLASS : return "ICLASS";
383
+ + case T_MODULE : return "MODULE";
384
+ + case T_FLOAT : return "FLOAT";
385
+ + case T_STRING : return "STRING";
386
+ + case T_REGEXP : return "REGEXP";
387
+ + case T_ARRAY : return "ARRAY";
388
+ + case T_FIXNUM : return "FIXNUM";
389
+ + case T_HASH : return "HASH";
390
+ + case T_STRUCT : return "STRUCT";
391
+ + case T_BIGNUM : return "BIGNUM";
392
+ + case T_FILE : return "FILE";
393
+ +
394
+ + case T_TRUE : return "TRUE";
395
+ + case T_FALSE : return "FALSE";
396
+ + case T_DATA : return "DATA";
397
+ + case T_MATCH : return "MATCH";
398
+ + case T_SYMBOL : return "SYMBOL";
399
+ +
400
+ + case T_BLKTAG : return "BLKTAG";
401
+ + case T_UNDEF : return "UNDEF";
402
+ + case T_VARMAP : return "VARMAP";
403
+ + case T_SCOPE : return "SCOPE";
404
+ + case T_NODE : return "NODE";
405
+ + default: return "____";
406
+ + }
407
+ +}
408
+ +
409
+ static void
410
+ free_unused_heaps()
411
+ {
412
+ @@ -1056,12 +1356,21 @@
413
+ unsigned long live = 0;
414
+ unsigned long free_min = 0;
415
+
416
+ + unsigned long really_freed = 0;
417
+ + int free_counts[256];
418
+ + int live_counts[256];
419
+ + int do_gc_stats = gc_statistics & verbose_gc_stats;
420
+ +
421
+ for (i = 0; i < heaps_used; i++) {
422
+ free_min += heaps[i].limit;
423
+ }
424
+ free_min = free_min * 0.2;
425
+ - if (free_min < FREE_MIN)
426
+ - free_min = FREE_MIN;
427
+ + if (free_min < heap_free_min)
428
+ + free_min = heap_free_min;
429
+ +
430
+ + if (do_gc_stats) {
431
+ + for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; }
432
+ + }
433
+
434
+ if (ruby_in_compile && ruby_parser_stack_on_heap()) {
435
+ /* should not reclaim nodes during compilation
436
+ @@ -1094,6 +1403,9 @@
437
+ if (!(p->as.basic.flags & FL_MARK)) {
438
+ if (p->as.basic.flags) {
439
+ obj_free((VALUE)p);
440
+ + if (do_gc_stats) {
441
+ + really_freed++;
442
+ + }
443
+ }
444
+ if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
445
+ p->as.free.flags = FL_MARK; /* remain marked */
446
+ @@ -1101,6 +1413,12 @@
447
+ final_list = p;
448
+ }
449
+ else {
450
+ + if (do_gc_stats) {
451
+ + int obt = p->as.basic.flags & T_MASK;
452
+ + if (obt) {
453
+ + free_counts[obt]++;
454
+ + }
455
+ + }
456
+ p->as.free.flags = 0;
457
+ p->as.free.next = freelist;
458
+ freelist = p;
459
+ @@ -1114,6 +1432,9 @@
460
+ else {
461
+ RBASIC(p)->flags &= ~FL_MARK;
462
+ live++;
463
+ + if (do_gc_stats) {
464
+ + live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++;
465
+ + }
466
+ }
467
+ p++;
468
+ }
469
+ @@ -1132,7 +1453,7 @@
470
+ }
471
+ if (malloc_increase > malloc_limit) {
472
+ malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
473
+ - if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
474
+ + if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
475
+ }
476
+ malloc_increase = 0;
477
+ if (freed < free_min) {
478
+ @@ -1140,6 +1461,20 @@
479
+ }
480
+ during_gc = 0;
481
+
482
+ + if (do_gc_stats) {
483
+ + fprintf(gc_data_file, "objects processed: %.7d\n", live+freed);
484
+ + fprintf(gc_data_file, "live objects : %.7d\n", live);
485
+ + fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed);
486
+ + fprintf(gc_data_file, "freed objects : %.7d\n", really_freed);
487
+ + for(i=0; i<256; i++) {
488
+ + if (free_counts[i]>0) {
489
+ + fprintf(gc_data_file,
490
+ + "kept %.7d / freed %.7d objects of type %s\n",
491
+ + live_counts[i], free_counts[i], obj_type(i));
492
+ + }
493
+ + }
494
+ + }
495
+ +
496
+ /* clear finalization list */
497
+ if (final_list) {
498
+ deferred_final_list = final_list;
499
+ @@ -1334,6 +1669,7 @@
500
+ struct gc_list *list;
501
+ struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
502
+ jmp_buf save_regs_gc_mark;
503
+ + struct timeval gctv1, gctv2;
504
+ SET_STACK_END;
505
+
506
+ #ifdef HAVE_NATIVETHREAD
507
+ @@ -1350,6 +1686,14 @@
508
+ if (during_gc) return;
509
+ during_gc++;
510
+
511
+ + if (gc_statistics) {
512
+ + gc_collections++;
513
+ + gettimeofday(&gctv1, NULL);
514
+ + if (verbose_gc_stats) {
515
+ + fprintf(gc_data_file, "Garbage collection started\n");
516
+ + }
517
+ + }
518
+ +
519
+ init_mark_stack();
520
+
521
+ gc_mark((VALUE)ruby_current_node, 0);
522
+ @@ -1438,6 +1782,17 @@
523
+ } while (!MARK_STACK_EMPTY);
524
+
525
+ gc_sweep();
526
+ +
527
+ + if (gc_statistics) {
528
+ + GC_TIME_TYPE musecs_used;
529
+ + gettimeofday(&gctv2, NULL);
530
+ + musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec);
531
+ + gc_time += musecs_used;
532
+ +
533
+ + if (verbose_gc_stats) {
534
+ + fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000);
535
+ + }
536
+ + }
537
+ }
538
+
539
+ void
540
+ @@ -1551,6 +1906,7 @@
541
+ if (!rb_gc_stack_start) {
542
+ Init_stack(0);
543
+ }
544
+ + set_gc_parameters();
545
+ add_heap();
546
+ }
547
+
548
+ @@ -2020,6 +2376,14 @@
549
+ rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
550
+ rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
551
+
552
+ + rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0);
553
+ + rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0);
554
+ + rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0);
555
+ + rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0);
556
+ + rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0);
557
+ + rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0);
558
+ + rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1);
559
+ +
560
+ rb_mObSpace = rb_define_module("ObjectSpace");
561
+ rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
562
+ rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);