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,640 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/benchmark_specs')
2
+
3
+ class RailsBenchmark
4
+
5
+ attr_accessor :gc_frequency, :iterations
6
+ attr_accessor :http_host, :remote_addr, :server_port
7
+ attr_accessor :relative_url_root
8
+ attr_accessor :perform_caching, :cache_template_loading
9
+ attr_accessor :session_data, :session_key, :cookie_data
10
+
11
+ def error_exit(msg)
12
+ STDERR.puts msg
13
+ raise msg
14
+ end
15
+
16
+ def patched_gc?
17
+ @patched_gc
18
+ end
19
+
20
+ def relative_url_root=(value)
21
+ if ActionController::Base.respond_to?(:relative_url_root=)
22
+ if @rails_version < "3"
23
+ # rails 2.3
24
+ ActionController::Base.relative_url_root = value
25
+ else
26
+ ::Rails.application.config.relative_url_root = value
27
+ end
28
+ else
29
+ # earlier railses
30
+ ActionController::AbstractRequest.relative_url_root = value
31
+ end
32
+ @relative_url_root = value
33
+ end
34
+
35
+ def initialize(options={})
36
+ unless @gc_frequency = options[:gc_frequency]
37
+ @gc_frequency = 0
38
+ ARGV.each{|arg| @gc_frequency = $1.to_i if arg =~ /-gc(\d+)/ }
39
+ end
40
+
41
+ @iterations = (options[:iterations] || 100).to_i
42
+
43
+ @remote_addr = options[:remote_addr] || '127.0.0.1'
44
+ @http_host = options[:http_host] || '127.0.0.1'
45
+ @server_port = options[:server_port] || '80'
46
+
47
+ @session_data = options[:session_data] || {}
48
+ @session_key = options[:session_key] || '_session_id'
49
+
50
+ ENV['RAILS_ENV'] = 'benchmarking'
51
+
52
+ begin
53
+ require ENV['RAILS_ROOT'] + "/config/environment"
54
+ @rails_version = Rails::VERSION::STRING
55
+ require 'dispatcher' if @rails_version < "3" # make edge rails happy
56
+
57
+ if @rails_version >= "2.3"
58
+ @rack_middleware = true
59
+ if @rails_version < "3"
60
+ require 'cgi/session'
61
+ CGI.class_eval <<-"end_eval"
62
+ def env_table
63
+ @env_table ||= ENV.to_hash
64
+ end
65
+ end_eval
66
+ end
67
+ else
68
+ @rack_middleware = false
69
+ end
70
+
71
+ rescue => e
72
+ $stderr.puts "failed to load application environment"
73
+ e.backtrace.each{|line| $stderr.puts line}
74
+ $stderr.puts "benchmarking aborted"
75
+ exit(-1)
76
+ end
77
+
78
+ # we don't want local error template output, which crashes anyway, when run under railsbench
79
+ ActionController::Rescue.class_eval "def local_request?; false; end" if @rails_version < "3"
80
+
81
+ # print backtrace and exit if action execution raises an exception
82
+ ActionController::Rescue.class_eval <<-"end_eval" if @rails_version < "3"
83
+ def rescue_action_in_public(exception)
84
+ $stderr.puts "benchmarking aborted due to application error: " + exception.message
85
+ exception.backtrace.each{|line| $stderr.puts line}
86
+ $stderr.print "clearing database connections ..."
87
+ if defined?(ActiveRecord)
88
+ ActiveRecord::Base.send :clear_all_cached_connections! if ActiveRecord::Base.respond_to?(:clear_all_cached_connections)
89
+ ActiveRecord::Base.clear_all_connections! if ActiveRecord::Base.respond_to?(:clear_all_connections)
90
+ end
91
+ $stderr.puts
92
+ exit!(-1)
93
+ end
94
+ end_eval
95
+
96
+ # override rails ActiveRecord::Base#inspect to make profiles more readable
97
+ if defined?(ActiveRecord)
98
+ ActiveRecord::Base.class_eval <<-"end_eval"
99
+ def self.inspect
100
+ super
101
+ end
102
+ end_eval
103
+ end
104
+
105
+ # make sure Rails doesn't try to read post data from stdin
106
+ CGI::QueryExtension.module_eval <<-end_eval if @rails_version < "3"
107
+ def read_body(content_length)
108
+ ENV['RAW_POST_DATA']
109
+ end
110
+ end_eval
111
+
112
+ if ARGV.include?('-path')
113
+ $:.each{|f| STDERR.puts f}
114
+ exit
115
+ end
116
+
117
+ rails_logger = @rails_version > "3" ? Rails.logger : RAILS_DEFAULT_LOGGER
118
+
119
+ logger_module = Logger
120
+ if defined?(Log4r) && rails_logger.is_a?(Log4r::Logger)
121
+ logger_module = Logger
122
+ end
123
+ default_log_level = logger_module.const_get("ERROR")
124
+ log_level = options[:log] || default_log_level
125
+ ARGV.each do |arg|
126
+ case arg
127
+ when '-log'
128
+ log_level = default_log_level
129
+ when '-log=(nil|none)'
130
+ log_level = nil
131
+ when /-log=([a-zA-Z]*)/
132
+ log_level = logger_module.const_get($1.upcase) rescue default_log_level
133
+ end
134
+ end
135
+
136
+ if log_level
137
+ rails_logger.level = log_level
138
+ ActiveRecord::Base.logger.level = log_level if defined?(ActiveRecord)
139
+ ActionController::Base.logger.level = log_level
140
+ ActionMailer::Base.logger.level = log_level if defined?(ActionMailer)
141
+ else
142
+ rails_logger.level = logger_module.const_get "FATAL"
143
+ ActiveRecord::Base.logger = nil if defined?(ActiveRecord)
144
+ ActionController::Base.logger = nil
145
+ ActionMailer::Base.logger = nil if defined?(ActionMailer)
146
+ end
147
+
148
+ if options.has_key?(:perform_caching)
149
+ ActionController::Base.perform_caching = options[:perform_caching]
150
+ else
151
+ ActionController::Base.perform_caching = false if ARGV.include?('-nocache')
152
+ ActionController::Base.perform_caching = true if ARGV.include?('-cache')
153
+ end
154
+
155
+ if ActionView::Base.respond_to?(:cache_template_loading)
156
+ if options.has_key?(:cache_template_loading)
157
+ ActionView::Base.cache_template_loading = options[:cache_template_loading]
158
+ else
159
+ ActionView::Base.cache_template_loading = true
160
+ end
161
+ end
162
+
163
+ self.relative_url_root = options[:relative_url_root] || ''
164
+
165
+ @patched_gc = GC.collections.is_a?(Numeric) rescue false
166
+
167
+ if ARGV.include? '-headers_only'
168
+ require File.dirname(__FILE__) + '/write_headers_only'
169
+ end
170
+
171
+ end
172
+
173
+ def establish_test_session
174
+ if @rack_middleware
175
+ session_options = ActionController::Base.session_options
176
+ @session_id = ActiveSupport::SecureRandom.hex(16)
177
+ do_not_do_much = lambda do |env|
178
+ env["rack.session"] = @session_data
179
+ env["rack.session.options"] = {:id => @session_id}
180
+ [200, {}, ""]
181
+ end
182
+ @session_store = ActionController::Base.session_store.new(do_not_do_much, session_options)
183
+ @session_store.call({})
184
+ else
185
+ session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.stringify_keys
186
+ session_options = session_options.merge('new_session' => true)
187
+ @session = CGI::Session.new(Hash.new, session_options)
188
+ @session_data.each{ |k,v| @session[k] = v }
189
+ @session.update
190
+ @session_id = @session.session_id
191
+ end
192
+ end
193
+
194
+ def update_test_session_data(session_data)
195
+ if @rack_middleware
196
+ session_options = ActionController::Base.session_options
197
+ merge_url_specific_session_data = lambda do |env|
198
+ old_session_data = env["rack.session"]
199
+ # $stderr.puts "data in old session: #{old_session_data.inspect}"
200
+ new_session_data = old_session_data.merge(session_data || {})
201
+ # $stderr.puts "data in new session: #{new_session_data.inspect}"
202
+ env["rack.session"] = new_session_data
203
+ [200, {}, ""]
204
+ end
205
+ @session_store.instance_eval { @app = merge_url_specific_session_data }
206
+ env = {}
207
+ env["HTTP_COOKIE"] = cookie
208
+ # debugger
209
+ @session_store.call(env)
210
+ else
211
+ dbman = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager]
212
+ old_session_data = dbman.new(@session).restore
213
+ # $stderr.puts old_session_data.inspect
214
+ new_session_data = old_session_data.merge(session_data || {})
215
+ new_session_data.each{ |k,v| @session[k] = v }
216
+ @session.update
217
+ end
218
+ end
219
+
220
+ def delete_test_session
221
+ # no way to delete a session by going through the session adpater in rails 2.3
222
+ if @session
223
+ @session.delete
224
+ @session = nil
225
+ end
226
+ end
227
+
228
+ # can be redefined in subclasses to clean out test sessions
229
+ def delete_new_test_sessions
230
+ end
231
+
232
+ def setup_test_urls(name)
233
+ @benchmark = name
234
+ @urls = BenchmarkSpec.load(name)
235
+ end
236
+
237
+ def setup_initial_env
238
+ ENV['REMOTE_ADDR'] = remote_addr
239
+ ENV['HTTP_HOST'] = http_host
240
+ ENV['SERVER_PORT'] = server_port.to_s
241
+ end
242
+
243
+ def setup_request_env(entry)
244
+ # $stderr.puts entry.inspect
245
+ ENV['REQUEST_URI'] = @relative_url_root + entry.uri
246
+ ENV.delete 'RAW_POST_DATA'
247
+ ENV.delete 'QUERY_STRING'
248
+ case ENV['REQUEST_METHOD'] = (entry.method || 'get').upcase
249
+ when 'GET'
250
+ query_data = entry.query_string || ''
251
+ query_data = escape_data(query_data) unless entry.raw_data
252
+ ENV['QUERY_STRING'] = query_data
253
+ when 'POST'
254
+ query_data = entry.post_data || ''
255
+ query_data = escape_data(query_data) unless entry.raw_data
256
+ ENV['RAW_POST_DATA'] = query_data
257
+ end
258
+ ENV['CONTENT_LENGTH'] = query_data.length.to_s
259
+ ENV['HTTP_COOKIE'] = entry.new_session ? '' : cookie
260
+ ENV['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' if entry.xhr
261
+ # $stderr.puts entry.session_data.inspect
262
+ update_test_session_data(entry.session_data) unless entry.new_session
263
+ end
264
+
265
+ def before_dispatch_hook(entry)
266
+ end
267
+
268
+ def cookie
269
+ "#{@session_key}=#{@session_id}#{cookie_data}"
270
+ end
271
+
272
+ def escape_data(str)
273
+ str.split('&').map{|e| e.split('=').map{|e| CGI::escape e}.join('=')}.join('&')
274
+ end
275
+
276
+ def warmup
277
+ error_exit "No urls given for performance test" unless @urls && @urls.size>0
278
+ setup_initial_env
279
+ @urls.each do |entry|
280
+ error_exit "No uri given for benchmark entry: #{entry.inspect}" unless entry.uri
281
+ setup_request_env(entry)
282
+ dispatch(entry)
283
+ end
284
+ end
285
+
286
+ def run_urls_without_benchmark(gc_stats)
287
+ # support for running Ruby Performance Validator
288
+ # or Ruby Memory Validator
289
+ svl = nil
290
+ begin
291
+ if ARGV.include?('-svlPV')
292
+ require 'svlRubyPV'
293
+ svl = SvlRubyPV.new
294
+ elsif ARGV.include?('-svlMV')
295
+ require 'svlRubyMV'
296
+ svl = SvlRubyMV
297
+ end
298
+ rescue LoadError
299
+ # SVL dll not available, do nothing
300
+ end
301
+
302
+ # support ruby-prof
303
+ ruby_prof = nil
304
+ ARGV.each{|arg| ruby_prof=$1 if arg =~ /-ruby_prof=([^ ]*)/ }
305
+ begin
306
+ if ruby_prof
307
+ # redirect stderr (TODO: I can't remember why we don't do this later)
308
+ if benchmark_file = ENV['RAILS_BENCHMARK_FILE']
309
+ $stderr = File.open(benchmark_file, "w")
310
+ end
311
+ require 'ruby-prof'
312
+ measure_mode = "WALL_TIME"
313
+ ARGV.each{|arg| measure_mode=$1.upcase if arg =~ /-measure_mode=([^ ]*)/ }
314
+ if %w(PROCESS_TIME WALL_TIME CPU_TIME ALLOCATIONS MEMORY).include?(measure_mode)
315
+ RubyProf.measure_mode = RubyProf.const_get measure_mode
316
+ else
317
+ $stderr = STDERR
318
+ $stderr.puts "unsupported ruby_prof measure mode: #{measure_mode}"
319
+ exit(-1)
320
+ end
321
+ RubyProf.start
322
+ end
323
+ rescue LoadError
324
+ # ruby-prof not available, do nothing
325
+ $stderr = STDERR
326
+ $stderr.puts "ruby-prof not available: giving up"
327
+ exit(-1)
328
+ end
329
+
330
+ # start profiler and trigger data collection if required
331
+ if svl
332
+ svl.startProfiler
333
+ svl.startDataCollection
334
+ end
335
+
336
+ setup_initial_env
337
+ GC.enable_stats if gc_stats
338
+ if gc_frequency==0
339
+ run_urls_without_benchmark_and_without_gc_control(@urls, iterations)
340
+ else
341
+ run_urls_without_benchmark_but_with_gc_control(@urls, iterations, gc_frequency)
342
+ end
343
+ if gc_stats
344
+ GC.enable if gc_frequency
345
+ GC.start
346
+ GC.dump
347
+ GC.disable_stats
348
+ GC.log "number of requests processed: #{@urls.size * iterations}"
349
+ end
350
+
351
+ # try to detect Ruby interpreter memory leaks (OS X)
352
+ if ARGV.include?('-leaks')
353
+ leaks_log = "#{ENV['RAILS_PERF_DATA']}/leaks.log"
354
+ leaks_command = "leaks -nocontext #{$$} >#{leaks_log}"
355
+ ENV.delete 'MallocStackLogging'
356
+ # $stderr.puts "executing '#{leaks_command}'"
357
+ raise "could not execute leaks command" unless system(leaks_command)
358
+ mallocs, leaks = *`head -n 2 #{leaks_log}`.split("\n").map{|l| l.gsub(/Process #{$$}: /, '')}
359
+ if mem_leaks = (leaks =~ /(\d+) leaks for (\d+) total leaked bytes/)
360
+ $stderr.puts "\n!!!!! memory leaks detected !!!!! (#{leaks_log})"
361
+ $stderr.puts "=" * leaks.length
362
+ end
363
+ if gc_stats
364
+ GC.log mallocs
365
+ GC.log leaks
366
+ end
367
+ $stderr.puts mallocs, leaks
368
+ $stderr.puts "=" * leaks.length if mem_leaks
369
+ end
370
+
371
+ # stop data collection if necessary
372
+ svl.stopDataCollection if svl
373
+
374
+ if defined? RubyProf
375
+ GC.disable #ruby-pof 0.7.x crash workaround
376
+ result = RubyProf.stop
377
+ GC.enable #ruby-pof 0.7.x crash workaround
378
+ min_percent = ruby_prof.split('/')[0].to_f rescue 0.1
379
+ threshold = ruby_prof.split('/')[1].to_f rescue 1.0
380
+ profile_type = nil
381
+ ARGV.each{|arg| profile_type=$1 if arg =~ /-profile_type=([^ ]*)/ }
382
+ profile_type ||= 'stack'
383
+ printer =
384
+ case profile_type
385
+ when 'stack' then RubyProf::CallStackPrinter
386
+ when 'grind' then RubyProf::CallTreePrinter
387
+ when 'flat' then RubyProf::FlatPrinter
388
+ when 'graph' then RubyProf::GraphHtmlPrinter
389
+ when 'multi' then RubyProf::MultiPrinter
390
+ else raise "unknown profile type: #{profile_type}"
391
+ end.new(result)
392
+ if profile_type == 'multi'
393
+ raise "you must specify a benchmark file when using multi printer" unless $stderr.is_a?(File)
394
+ $stderr.close
395
+ $stderr = STDERR
396
+ file_name = ENV['RAILS_BENCHMARK_FILE']
397
+ profile_name = File.basename(file_name).sub('.html','').sub(".#{profile_type}",'')
398
+ printer.print(:path => File.dirname(file_name),
399
+ :profile => profile_name,
400
+ :min_percent => min_percent, :threshold => threshold,
401
+ :title => "call tree/graph for benchmark #{@benchmark}")
402
+ else
403
+ printer.print($stderr, :min_percent => min_percent, :threshold => threshold,
404
+ :title => "call tree for benchmark #{@benchmark}")
405
+ end
406
+ end
407
+
408
+ delete_test_session
409
+ delete_new_test_sessions
410
+ end
411
+
412
+ def run_urls(test)
413
+ setup_initial_env
414
+ if gc_frequency>0
415
+ run_urls_with_gc_control(test, @urls, iterations, gc_frequency)
416
+ else
417
+ run_urls_without_gc_control(test, @urls, iterations)
418
+ end
419
+ delete_test_session
420
+ delete_new_test_sessions
421
+ end
422
+
423
+ def run_url_mix(test)
424
+ if gc_frequency>0
425
+ run_url_mix_with_gc_control(test, @urls, iterations, gc_frequency)
426
+ else
427
+ run_url_mix_without_gc_control(test, @urls, iterations)
428
+ end
429
+ delete_test_session
430
+ delete_new_test_sessions
431
+ end
432
+
433
+ private
434
+
435
+ def dispatch(entry)
436
+ before_dispatch_hook(entry)
437
+ if @rails_version < "3"
438
+ Dispatcher.dispatch(CGI.new)
439
+ else
440
+ status, headers, response = Rails.application.call(rack_request_env(entry))
441
+ body = response.body
442
+ begin
443
+ send_headers status, headers, $stdout
444
+ send_body body, $stdout
445
+ ensure
446
+ body.close if body.respond_to? :close
447
+ end
448
+ end
449
+ end
450
+
451
+ def rack_request_env(entry)
452
+ env = Rack::MockRequest.env_for(ENV['REQUEST_URI'], :method => ENV['REQUEST_METHOD'])
453
+ if qs = ENV['QUERY_STRING']
454
+ env['QUERY_STRING'] = qs
455
+ env['CONTENT_LENGTH'] = ENV['CONTENT_LENGTH']
456
+ end
457
+ if rp = ENV['RAW_POST_DATA']
458
+ env['rack.input'] = StringIO.new(rp)
459
+ end
460
+ if entry.xhr
461
+ env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
462
+ end
463
+ if cs = ENV['HTTP_COOKIE']
464
+ env['HTTP_COOKIE'] = cs
465
+ end
466
+ env
467
+ end
468
+
469
+ def send_headers(status, headers, io)
470
+ io.print "Status: #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n"
471
+ headers.each do |k, vs|
472
+ vs.split("\n").each { |v| io.print "#{k}: #{v}\r\n" }
473
+ end
474
+ io.print "\r\n"
475
+ io.flush
476
+ end
477
+
478
+ def send_body(body, io)
479
+ if body.is_a?(String)
480
+ io.print body
481
+ io.flush
482
+ else
483
+ body.each do |part|
484
+ io.print part
485
+ io.flush
486
+ end
487
+ end
488
+ end
489
+
490
+ def run_urls_without_benchmark_but_with_gc_control(urls, n, gc_frequency)
491
+ urls.each do |entry|
492
+ setup_request_env(entry)
493
+ GC.enable; GC.start; GC.disable
494
+ request_count = 0
495
+ n.times do
496
+ dispatch(entry)
497
+ if (request_count += 1) == gc_frequency
498
+ GC.enable; GC.start; GC.disable
499
+ request_count = 0
500
+ end
501
+ end
502
+ end
503
+ end
504
+
505
+ def run_urls_without_benchmark_and_without_gc_control(urls, n)
506
+ urls.each do |entry|
507
+ setup_request_env(entry)
508
+ n.times do
509
+ dispatch(entry)
510
+ end
511
+ end
512
+ end
513
+
514
+ def run_urls_with_gc_control(test, urls, n, gc_freq)
515
+ gc_stats = patched_gc?
516
+ GC.clear_stats if gc_stats
517
+ urls.each do |entry|
518
+ request_count = 0
519
+ setup_request_env(entry)
520
+ test.report(entry.name) do
521
+ GC.disable_stats if gc_stats
522
+ GC.enable; GC.start; GC.disable
523
+ GC.enable_stats if gc_stats
524
+ n.times do
525
+ dispatch(entry)
526
+ if (request_count += 1) == gc_freq
527
+ GC.enable; GC.start; GC.disable
528
+ request_count = 0
529
+ end
530
+ end
531
+ end
532
+ end
533
+ if gc_stats
534
+ GC.disable_stats
535
+ Benchmark::OUTPUT.puts "GC.collections=#{GC.collections}, GC.time=#{GC.time/1E6}"
536
+ GC.clear_stats
537
+ end
538
+ end
539
+
540
+ def run_urls_without_gc_control(test, urls, n)
541
+ gc_stats = patched_gc?
542
+ GC.clear_stats if gc_stats
543
+ urls.each do |entry|
544
+ setup_request_env(entry)
545
+ GC.disable_stats if gc_stats
546
+ GC.start
547
+ GC.enable_stats if gc_stats
548
+ test.report(entry.name) do
549
+ n.times do
550
+ dispatch(entry)
551
+ end
552
+ end
553
+ end
554
+ if gc_stats
555
+ GC.disable_stats
556
+ Benchmark::OUTPUT.puts "GC.collections=#{GC.collections}, GC.time=#{GC.time/1E6}"
557
+ GC.clear_stats
558
+ end
559
+ end
560
+
561
+ def run_url_mix_without_gc_control(test, urls, n)
562
+ gc_stats = patched_gc?
563
+ GC.start
564
+ if gc_stats
565
+ GC.clear_stats; GC.enable_stats
566
+ end
567
+ test.report("url_mix (#{urls.length} urls)") do
568
+ n.times do
569
+ urls.each do |entry|
570
+ setup_request_env(entry)
571
+ dispatch(entry)
572
+ end
573
+ end
574
+ end
575
+ if gc_stats
576
+ GC.disable_stats
577
+ Benchmark::OUTPUT.puts "GC.collections=#{GC.collections}, GC.time=#{GC.time/1E6}"
578
+ GC.clear_stats
579
+ end
580
+ end
581
+
582
+ def run_url_mix_with_gc_control(test, urls, n, gc_frequency)
583
+ gc_stats = patched_gc?
584
+ GC.enable; GC.start; GC.disable
585
+ if gc_stats
586
+ GC.clear_stats; GC.enable_stats
587
+ end
588
+ test.report("url_mix (#{urls.length} urls)") do
589
+ request_count = 0
590
+ n.times do
591
+ urls.each do |entry|
592
+ setup_request_env(entry)
593
+ dispatch(entry)
594
+ if (request_count += 1) == gc_frequency
595
+ GC.enable; GC.start; GC.disable
596
+ request_count = 0
597
+ end
598
+ end
599
+ end
600
+ end
601
+ if gc_stats
602
+ GC.disable_stats
603
+ Benchmark::OUTPUT.puts "GC.collections=#{GC.collections}, GC.time=#{GC.time/1E6}"
604
+ GC.clear_stats
605
+ end
606
+ end
607
+ end
608
+
609
+
610
+ class RailsBenchmarkWithActiveRecordStore < RailsBenchmark
611
+
612
+ def initialize(options={})
613
+ super(options)
614
+ @session_class = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager].session_class rescue CGI::Session::ActiveRecordStore rescue ActiveRecord::SessionStore
615
+ end
616
+
617
+ def delete_new_test_sessions
618
+ @session_class.delete_all if @session_class.respond_to?(:delete_all)
619
+ end
620
+
621
+ end
622
+
623
+
624
+ __END__
625
+
626
+ # Copyright (C) 2005-2008 Stefan Kaes
627
+ #
628
+ # This program is free software; you can redistribute it and/or modify
629
+ # it under the terms of the GNU General Public License as published by
630
+ # the Free Software Foundation; either version 2 of the License, or
631
+ # (at your option) any later version.
632
+ #
633
+ # This program is distributed in the hope that it will be useful,
634
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
635
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
636
+ # GNU General Public License for more details.
637
+ #
638
+ # You should have received a copy of the GNU General Public License
639
+ # along with this program; if not, write to the Free Software
640
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA