railsbench 0.9.2 → 0.9.8

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