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,9 @@
1
+ module Railsbench #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 9
5
+ TINY = 7
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +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
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+ if ARGV.include?('--dry-run')
5
+ include FileUtils::DryRun
6
+ else
7
+ include FileUtils::Verbose
8
+ end
9
+
10
+ RAILSBENCH_BASE = File.expand_path(File.dirname(__FILE__)) unless defined?(RAILSBENCH_BASE)
11
+
12
+ chmod 0755, Dir["#{RAILSBENCH_BASE}/script/*"]
@@ -0,0 +1,516 @@
1
+ --- gc.c.orig 2005-12-16 05:58:51.000000000 +0100
2
+ +++ gc.c 2006-07-16 14:46:55.890625000 +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
+ @@ -175,8 +183,17 @@
21
+ RUBY_CRITICAL(free(x));
22
+ }
23
+
24
+ +#if HAVE_LONG_LONG
25
+ +#define GC_TIME_TYPE LONG_LONG
26
+ +#else
27
+ +#define GC_TIME_TYPE long
28
+ +#endif
29
+ +
30
+ extern int ruby_in_compile;
31
+ static int dont_gc;
32
+ +static int gc_statistics = 0;
33
+ +static GC_TIME_TYPE gc_time = 0;
34
+ +static int gc_collections = 0;
35
+ static int during_gc;
36
+ static int need_call_final = 0;
37
+ static st_table *finalizer_table = 0;
38
+ @@ -211,7 +228,7 @@
39
+ * Disables garbage collection, returning <code>true</code> if garbage
40
+ * collection was already disabled.
41
+ *
42
+ - * GC.disable #=> false
43
+ + * GC.disable #=> false or true
44
+ * GC.disable #=> true
45
+ *
46
+ */
47
+ @@ -225,6 +242,104 @@
48
+ return old;
49
+ }
50
+
51
+ +/*
52
+ + * call-seq:
53
+ + * GC.enable_stats => true or false
54
+ + *
55
+ + * Enables garbage collection statistics, returning <code>true</code> if garbage
56
+ + * collection statistics was already enabled.
57
+ + *
58
+ + * GC.enable_stats #=> false or true
59
+ + * GC.enable_stats #=> true
60
+ + *
61
+ + */
62
+ +
63
+ +VALUE
64
+ +rb_gc_enable_stats()
65
+ +{
66
+ + int old = gc_statistics;
67
+ + gc_statistics = Qtrue;
68
+ + return old;
69
+ +}
70
+ +
71
+ +/*
72
+ + * call-seq:
73
+ + * GC.disable_stats => true or false
74
+ + *
75
+ + * Disables garbage collection statistics, returning <code>true</code> if garbage
76
+ + * collection statistics was already disabled.
77
+ + *
78
+ + * GC.disable_stats #=> false or true
79
+ + * GC.disable_stats #=> true
80
+ + *
81
+ + */
82
+ +
83
+ +VALUE
84
+ +rb_gc_disable_stats()
85
+ +{
86
+ + int old = gc_statistics;
87
+ + gc_statistics = Qfalse;
88
+ + return old;
89
+ +}
90
+ +
91
+ +/*
92
+ + * call-seq:
93
+ + * GC.clear_stats => nil
94
+ + *
95
+ + * Clears garbage collection statistics, returning nil. This resets the number
96
+ + * of collections (GC.collections) and the time used (GC.time) to 0.
97
+ + *
98
+ + * GC.clear_stats #=> nil
99
+ + *
100
+ + */
101
+ +
102
+ +VALUE
103
+ +rb_gc_clear_stats()
104
+ +{
105
+ + gc_collections = 0;
106
+ + gc_time = 0;
107
+ + return Qnil;
108
+ +}
109
+ +
110
+ +/*
111
+ + * call-seq:
112
+ + * GC.collections => Integer
113
+ + *
114
+ + * Returns the number of garbage collections performed while GC statistics collection
115
+ + * was enabled.
116
+ + *
117
+ + * GC.collections #=> 35
118
+ + *
119
+ + */
120
+ +
121
+ +VALUE
122
+ +rb_gc_collections()
123
+ +{
124
+ + return INT2NUM(gc_collections);
125
+ +}
126
+ +
127
+ +/*
128
+ + * call-seq:
129
+ + * GC.time => Integer
130
+ + *
131
+ + * Returns the time spent during garbage collection while GC statistics collection
132
+ + * was enabled (in micro seconds).
133
+ + *
134
+ + * GC.time #=> 20000
135
+ + *
136
+ + */
137
+ +
138
+ +VALUE
139
+ +rb_gc_time()
140
+ +{
141
+ +#if HAVE_LONG_LONG
142
+ + return LL2NUM(gc_time);
143
+ +#else
144
+ + return LONG2NUM(gc_time);
145
+ +#endif
146
+ +}
147
+ +
148
+ +
149
+ VALUE rb_mGC;
150
+
151
+ static struct gc_list {
152
+ @@ -308,7 +423,7 @@
153
+ static RVALUE *freelist = 0;
154
+ static RVALUE *deferred_final_list = 0;
155
+
156
+ -#define HEAPS_INCREMENT 10
157
+ +static int heaps_increment = 10;
158
+ static struct heaps_slot {
159
+ RVALUE *slot;
160
+ int limit;
161
+ @@ -316,13 +431,141 @@
162
+ static int heaps_length = 0;
163
+ static int heaps_used = 0;
164
+
165
+ -#define HEAP_MIN_SLOTS 10000
166
+ -static int heap_slots = HEAP_MIN_SLOTS;
167
+ +static int heap_min_slots = 10000;
168
+ +static int heap_slots = 10000;
169
+
170
+ -#define FREE_MIN 4096
171
+ +static int heap_free_min = 4096;
172
+ +
173
+ +static long initial_malloc_limit = GC_MALLOC_LIMIT;
174
+ +
175
+ +static int verbose_gc_stats = Qfalse;
176
+ +
177
+ +static FILE* gc_data_file = NULL;
178
+
179
+ static RVALUE *himem, *lomem;
180
+
181
+ +static void set_gc_parameters()
182
+ +{
183
+ + char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr,
184
+ + *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr;
185
+ +
186
+ + gc_data_file = stderr;
187
+ +
188
+ + gc_stats_ptr = getenv("RUBY_GC_STATS");
189
+ + if (gc_stats_ptr != NULL) {
190
+ + int gc_stats_i = atoi(gc_stats_ptr);
191
+ + if (gc_stats_i > 0) {
192
+ + verbose_gc_stats = Qtrue;
193
+ + }
194
+ + }
195
+ +
196
+ + gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE");
197
+ + if (gc_heap_file_ptr != NULL) {
198
+ + FILE* data_file = fopen(gc_heap_file_ptr, "w");
199
+ + if (data_file != NULL) {
200
+ + gc_data_file = data_file;
201
+ + }
202
+ + else {
203
+ + fprintf(stderr,
204
+ + "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr);
205
+ + }
206
+ + }
207
+ +
208
+ + min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
209
+ + if (min_slots_ptr != NULL) {
210
+ + int min_slots_i = atoi(min_slots_ptr);
211
+ + if (verbose_gc_stats) {
212
+ + fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr);
213
+ + }
214
+ + if (min_slots_i > 0) {
215
+ + heap_slots = min_slots_i;
216
+ + heap_min_slots = min_slots_i;
217
+ + }
218
+ + }
219
+ +
220
+ + free_min_ptr = getenv("RUBY_HEAP_FREE_MIN");
221
+ + if (free_min_ptr != NULL) {
222
+ + int free_min_i = atoi(free_min_ptr);
223
+ + if (verbose_gc_stats) {
224
+ + fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr);
225
+ + }
226
+ + if (free_min_i > 0) {
227
+ + heap_free_min = free_min_i;
228
+ + }
229
+ + }
230
+ +
231
+ + heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT");
232
+ + if (heap_incr_ptr != NULL) {
233
+ + int heap_incr_i = atoi(heap_incr_ptr);
234
+ + if (verbose_gc_stats) {
235
+ + fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr);
236
+ + }
237
+ + if (heap_incr_i > 0) {
238
+ + heaps_increment = heap_incr_i;
239
+ + }
240
+ + }
241
+ +
242
+ + malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
243
+ + if (malloc_limit_ptr != NULL) {
244
+ + int malloc_limit_i = atol(malloc_limit_ptr);
245
+ + if (verbose_gc_stats) {
246
+ + fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr);
247
+ + }
248
+ + if (malloc_limit_i > 0) {
249
+ + initial_malloc_limit = malloc_limit_i;
250
+ + }
251
+ + }
252
+ +}
253
+ +
254
+ +/*
255
+ + * call-seq:
256
+ + * GC.dump => nil
257
+ + *
258
+ + * dumps information about the current GC data structures to the GC log file
259
+ + *
260
+ + * GC.dump #=> nil
261
+ + *
262
+ + */
263
+ +
264
+ +VALUE
265
+ +rb_gc_dump()
266
+ +{
267
+ + int i;
268
+ +
269
+ + for (i = 0; i < heaps_used; i++) {
270
+ + int heap_size = heaps[i].limit;
271
+ + fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size);
272
+ + }
273
+ +
274
+ + return Qnil;
275
+ +}
276
+ +
277
+ +/*
278
+ + * call-seq:
279
+ + * GC.log String => String
280
+ + *
281
+ + * Logs string to the GC data file and returns it.
282
+ + *
283
+ + * GC.log "manual GC call" #=> "manual GC call"
284
+ + *
285
+ + */
286
+ +
287
+ +VALUE
288
+ +rb_gc_log(self, original_str)
289
+ + VALUE self, original_str;
290
+ +{
291
+ + if (original_str == Qnil) {
292
+ + fprintf(gc_data_file, "\n");
293
+ + }
294
+ + else {
295
+ + VALUE str = StringValue(original_str);
296
+ + char *p = RSTRING(str)->ptr;
297
+ + fprintf(gc_data_file, "%s\n", p);
298
+ + }
299
+ + return original_str;
300
+ +}
301
+ +
302
+ +
303
+ static void
304
+ add_heap()
305
+ {
306
+ @@ -333,7 +576,7 @@
307
+ struct heaps_slot *p;
308
+ int length;
309
+
310
+ - heaps_length += HEAPS_INCREMENT;
311
+ + heaps_length += heaps_increment;
312
+ length = heaps_length*sizeof(struct heaps_slot);
313
+ RUBY_CRITICAL(
314
+ if (heaps_used > 0) {
315
+ @@ -350,10 +593,10 @@
316
+ RUBY_CRITICAL(p = heaps[heaps_used].slot = (RVALUE*)malloc(sizeof(RVALUE)*heap_slots));
317
+ heaps[heaps_used].limit = heap_slots;
318
+ if (p == 0) {
319
+ - if (heap_slots == HEAP_MIN_SLOTS) {
320
+ + if (heap_slots == heap_min_slots) {
321
+ rb_memerror();
322
+ }
323
+ - heap_slots = HEAP_MIN_SLOTS;
324
+ + heap_slots = heap_min_slots;
325
+ continue;
326
+ }
327
+ break;
328
+ @@ -1031,6 +1274,39 @@
329
+ }
330
+ }
331
+
332
+ +static char* obj_type(int tp)
333
+ +{
334
+ + switch (tp) {
335
+ + case T_NIL : return "NIL";
336
+ + case T_OBJECT : return "OBJECT";
337
+ + case T_CLASS : return "CLASS";
338
+ + case T_ICLASS : return "ICLASS";
339
+ + case T_MODULE : return "MODULE";
340
+ + case T_FLOAT : return "FLOAT";
341
+ + case T_STRING : return "STRING";
342
+ + case T_REGEXP : return "REGEXP";
343
+ + case T_ARRAY : return "ARRAY";
344
+ + case T_FIXNUM : return "FIXNUM";
345
+ + case T_HASH : return "HASH";
346
+ + case T_STRUCT : return "STRUCT";
347
+ + case T_BIGNUM : return "BIGNUM";
348
+ + case T_FILE : return "FILE";
349
+ +
350
+ + case T_TRUE : return "TRUE";
351
+ + case T_FALSE : return "FALSE";
352
+ + case T_DATA : return "DATA";
353
+ + case T_MATCH : return "MATCH";
354
+ + case T_SYMBOL : return "SYMBOL";
355
+ +
356
+ + case T_BLKTAG : return "BLKTAG";
357
+ + case T_UNDEF : return "UNDEF";
358
+ + case T_VARMAP : return "VARMAP";
359
+ + case T_SCOPE : return "SCOPE";
360
+ + case T_NODE : return "NODE";
361
+ + default: return "____";
362
+ + }
363
+ +}
364
+ +
365
+ static void
366
+ gc_sweep()
367
+ {
368
+ @@ -1039,6 +1315,15 @@
369
+ int i;
370
+ unsigned long live = 0;
371
+
372
+ + unsigned long really_freed = 0;
373
+ + int free_counts[256];
374
+ + int live_counts[256];
375
+ + int do_gc_stats = gc_statistics & verbose_gc_stats;
376
+ +
377
+ + if (do_gc_stats) {
378
+ + for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; }
379
+ + }
380
+ +
381
+ if (ruby_in_compile && ruby_parser_stack_on_heap()) {
382
+ /* should not reclaim nodes during compilation
383
+ if yacc's semantic stack is not allocated on machine stack */
384
+ @@ -1070,6 +1355,9 @@
385
+ if (!(p->as.basic.flags & FL_MARK)) {
386
+ if (p->as.basic.flags) {
387
+ obj_free((VALUE)p);
388
+ + if (do_gc_stats) {
389
+ + really_freed++;
390
+ + }
391
+ }
392
+ if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
393
+ p->as.free.flags = FL_MARK; /* remain marked */
394
+ @@ -1077,6 +1365,12 @@
395
+ final_list = p;
396
+ }
397
+ else {
398
+ + if (do_gc_stats) {
399
+ + int obt = p->as.basic.flags & T_MASK;
400
+ + if (obt) {
401
+ + free_counts[obt]++;
402
+ + }
403
+ + }
404
+ p->as.free.flags = 0;
405
+ p->as.free.next = freelist;
406
+ freelist = p;
407
+ @@ -1090,10 +1384,13 @@
408
+ else {
409
+ RBASIC(p)->flags &= ~FL_MARK;
410
+ live++;
411
+ + if (do_gc_stats) {
412
+ + live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++;
413
+ + }
414
+ }
415
+ p++;
416
+ }
417
+ - if (n == heaps[i].limit && freed > FREE_MIN) {
418
+ + if (n == heaps[i].limit && freed > heap_free_min) {
419
+ RVALUE *pp;
420
+
421
+ heaps[i].limit = 0;
422
+ @@ -1108,14 +1405,28 @@
423
+ }
424
+ if (malloc_increase > malloc_limit) {
425
+ malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
426
+ - if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
427
+ + if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
428
+ }
429
+ malloc_increase = 0;
430
+ - if (freed < FREE_MIN) {
431
+ + if (freed < heap_free_min) {
432
+ add_heap();
433
+ }
434
+ during_gc = 0;
435
+
436
+ + if (do_gc_stats) {
437
+ + fprintf(gc_data_file, "objects processed: %.7d\n", live+freed);
438
+ + fprintf(gc_data_file, "live objects : %.7d\n", live);
439
+ + fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed);
440
+ + fprintf(gc_data_file, "freed objects : %.7d\n", really_freed);
441
+ + for(i=0; i<256; i++) {
442
+ + if (free_counts[i]>0) {
443
+ + fprintf(gc_data_file,
444
+ + "kept %.7d / freed %.7d objects of type %s\n",
445
+ + live_counts[i], free_counts[i], obj_type(i));
446
+ + }
447
+ + }
448
+ + }
449
+ +
450
+ /* clear finalization list */
451
+ if (final_list) {
452
+ deferred_final_list = final_list;
453
+ @@ -1311,6 +1622,7 @@
454
+ struct gc_list *list;
455
+ struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
456
+ jmp_buf save_regs_gc_mark;
457
+ + struct timeval gctv1, gctv2;
458
+ SET_STACK_END;
459
+
460
+ #ifdef HAVE_NATIVETHREAD
461
+ @@ -1327,6 +1639,14 @@
462
+ if (during_gc) return;
463
+ during_gc++;
464
+
465
+ + if (gc_statistics) {
466
+ + gc_collections++;
467
+ + gettimeofday(&gctv1, NULL);
468
+ + if (verbose_gc_stats) {
469
+ + fprintf(gc_data_file, "Garbage collection started\n");
470
+ + }
471
+ + }
472
+ +
473
+ init_mark_stack();
474
+
475
+ /* mark frame stack */
476
+ @@ -1409,6 +1729,17 @@
477
+ }
478
+ }
479
+ gc_sweep();
480
+ +
481
+ + if (gc_statistics) {
482
+ + GC_TIME_TYPE musecs_used;
483
+ + gettimeofday(&gctv2, NULL);
484
+ + musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec);
485
+ + gc_time += musecs_used;
486
+ +
487
+ + if (verbose_gc_stats) {
488
+ + fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000);
489
+ + }
490
+ + }
491
+ }
492
+
493
+ void
494
+ @@ -1522,6 +1853,7 @@
495
+ if (!rb_gc_stack_start) {
496
+ Init_stack(0);
497
+ }
498
+ + set_gc_parameters();
499
+ add_heap();
500
+ }
501
+
502
+ @@ -1920,6 +2252,14 @@
503
+ rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
504
+ rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
505
+
506
+ + rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0);
507
+ + rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0);
508
+ + rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0);
509
+ + rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0);
510
+ + rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0);
511
+ + rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0);
512
+ + rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1);
513
+ +
514
+ rb_mObSpace = rb_define_module("ObjectSpace");
515
+ rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
516
+ rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);