railsbench 0.9.2 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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);