kamal-railsbench 0.9.9.pre

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 (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