activesupport 3.1.0.beta1 → 3.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- data/CHANGELOG +33 -1
- data/README.rdoc +1 -1
- data/lib/active_support.rb +1 -1
- data/lib/active_support/buffered_logger.rb +9 -4
- data/lib/active_support/configurable.rb +9 -6
- data/lib/active_support/core_ext/array/conversions.rb +2 -2
- data/lib/active_support/core_ext/array/random_access.rb +1 -1
- data/lib/active_support/core_ext/array/uniq_by.rb +2 -3
- data/lib/active_support/core_ext/class/inheritable_attributes.rb +0 -2
- data/lib/active_support/core_ext/date/calculations.rb +3 -3
- data/lib/active_support/core_ext/date/conversions.rb +3 -2
- data/lib/active_support/core_ext/date_time/conversions.rb +8 -8
- data/lib/active_support/core_ext/hash/conversions.rb +2 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +12 -0
- data/lib/active_support/core_ext/hash/slice.rb +1 -1
- data/lib/active_support/core_ext/integer/inflections.rb +7 -4
- data/lib/active_support/core_ext/kernel/reporting.rb +13 -1
- data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +1 -0
- data/lib/active_support/core_ext/module/deprecation.rb +0 -2
- data/lib/active_support/core_ext/numeric/time.rb +2 -0
- data/lib/active_support/core_ext/object/blank.rb +3 -3
- data/lib/active_support/core_ext/object/duplicable.rb +2 -0
- data/lib/active_support/core_ext/object/try.rb +2 -0
- data/lib/active_support/core_ext/object/with_options.rb +8 -5
- data/lib/active_support/core_ext/string/behavior.rb +1 -2
- data/lib/active_support/core_ext/string/exclude.rb +1 -1
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/time/calculations.rb +4 -3
- data/lib/active_support/core_ext/time/marshal.rb +1 -0
- data/lib/active_support/descendants_tracker.rb +9 -7
- data/lib/active_support/duration.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +12 -4
- data/lib/active_support/inflector/methods.rb +5 -3
- data/lib/active_support/json/encoding.rb +4 -1
- data/lib/active_support/log_subscriber/test_helper.rb +1 -0
- data/lib/active_support/ordered_hash.rb +4 -0
- data/lib/active_support/secure_random.rb +3 -202
- data/lib/active_support/testing/performance.rb +227 -335
- data/lib/active_support/testing/performance/jruby.rb +115 -0
- data/lib/active_support/testing/performance/rubinius.rb +113 -0
- data/lib/active_support/testing/performance/ruby.rb +152 -0
- data/lib/active_support/testing/performance/ruby/mri.rb +59 -0
- data/lib/active_support/testing/performance/ruby/yarv.rb +57 -0
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini.rb +4 -1
- metadata +8 -3
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'jruby/profiler'
|
2
|
+
require 'java'
|
3
|
+
import java.lang.management.ManagementFactory
|
4
|
+
|
5
|
+
module ActiveSupport
|
6
|
+
module Testing
|
7
|
+
module Performance
|
8
|
+
DEFAULTS.merge!(
|
9
|
+
if ARGV.include?('--benchmark')
|
10
|
+
{:metrics => [:wall_time, :user_time, :memory, :gc_runs, :gc_time]}
|
11
|
+
else
|
12
|
+
{ :metrics => [:wall_time],
|
13
|
+
:formats => [:flat, :graph] }
|
14
|
+
end).freeze
|
15
|
+
|
16
|
+
protected
|
17
|
+
def run_gc
|
18
|
+
ManagementFactory.memory_mx_bean.gc
|
19
|
+
end
|
20
|
+
|
21
|
+
class Profiler < Performer
|
22
|
+
def initialize(*args)
|
23
|
+
super
|
24
|
+
@supported = @metric.is_a?(Metrics::WallTime)
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
return unless @supported
|
29
|
+
|
30
|
+
@total = time_with_block do
|
31
|
+
@data = JRuby::Profiler.profile do
|
32
|
+
full_profile_options[:runs].to_i.times { run_test(@metric, :profile) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def record
|
38
|
+
return unless @supported
|
39
|
+
|
40
|
+
klasses = full_profile_options[:formats].map { |f| JRuby::Profiler.const_get("#{f.to_s.camelize}ProfilePrinter") }.compact
|
41
|
+
|
42
|
+
klasses.each do |klass|
|
43
|
+
fname = output_filename(klass)
|
44
|
+
FileUtils.mkdir_p(File.dirname(fname))
|
45
|
+
file = File.open(fname, 'wb') do |file|
|
46
|
+
klass.new(@data).printProfile(file)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
def output_filename(printer_class)
|
53
|
+
suffix =
|
54
|
+
case printer_class.name.demodulize
|
55
|
+
when 'FlatProfilePrinter'; 'flat.txt'
|
56
|
+
when 'GraphProfilePrinter'; 'graph.txt'
|
57
|
+
else printer_class.name.sub(/ProfilePrinter$/, '').underscore
|
58
|
+
end
|
59
|
+
|
60
|
+
"#{super()}_#{suffix}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module Metrics
|
65
|
+
class Base
|
66
|
+
def profile
|
67
|
+
yield
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
def with_gc_stats
|
72
|
+
ManagementFactory.memory_mx_bean.gc
|
73
|
+
yield
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class WallTime < Time
|
78
|
+
def measure
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class CpuTime < Time
|
84
|
+
def measure
|
85
|
+
ManagementFactory.thread_mx_bean.get_current_thread_cpu_time / 1000 / 1000 / 1000.0 # seconds
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class UserTime < Time
|
90
|
+
def measure
|
91
|
+
ManagementFactory.thread_mx_bean.get_current_thread_user_time / 1000 / 1000 / 1000.0 # seconds
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Memory < DigitalInformationUnit
|
96
|
+
def measure
|
97
|
+
ManagementFactory.memory_mx_bean.non_heap_memory_usage.used + ManagementFactory.memory_mx_bean.heap_memory_usage.used
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class GcRuns < Amount
|
102
|
+
def measure
|
103
|
+
ManagementFactory.garbage_collector_mx_beans.inject(0) { |total_runs, current_gc| total_runs += current_gc.collection_count }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class GcTime < Time
|
108
|
+
def measure
|
109
|
+
ManagementFactory.garbage_collector_mx_beans.inject(0) { |total_time, current_gc| total_time += current_gc.collection_time } / 1000.0 # seconds
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rubinius/agent'
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module Testing
|
5
|
+
module Performance
|
6
|
+
DEFAULTS.merge!(
|
7
|
+
if ARGV.include?('--benchmark')
|
8
|
+
{:metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time]}
|
9
|
+
else
|
10
|
+
{ :metrics => [:wall_time],
|
11
|
+
:formats => [:flat, :graph] }
|
12
|
+
end).freeze
|
13
|
+
|
14
|
+
protected
|
15
|
+
def run_gc
|
16
|
+
GC.run(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
class Performer; end
|
20
|
+
|
21
|
+
class Profiler < Performer
|
22
|
+
def initialize(*args)
|
23
|
+
super
|
24
|
+
@supported = @metric.is_a?(Metrics::WallTime)
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
return unless @supported
|
29
|
+
|
30
|
+
@profiler = Rubinius::Profiler::Instrumenter.new
|
31
|
+
|
32
|
+
@total = time_with_block do
|
33
|
+
@profiler.profile(false) do
|
34
|
+
full_profile_options[:runs].to_i.times { run_test(@metric, :profile) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def record
|
40
|
+
return unless @supported
|
41
|
+
|
42
|
+
if(full_profile_options[:formats].include?(:flat))
|
43
|
+
create_path_and_open_file(:flat) do |file|
|
44
|
+
@profiler.show(file)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if(full_profile_options[:formats].include?(:graph))
|
49
|
+
create_path_and_open_file(:graph) do |file|
|
50
|
+
@profiler.show(file)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
def create_path_and_open_file(printer_name)
|
57
|
+
fname = "#{output_filename}_#{printer_name}.txt"
|
58
|
+
FileUtils.mkdir_p(File.dirname(fname))
|
59
|
+
File.open(fname, 'wb') do |file|
|
60
|
+
yield(file)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module Metrics
|
66
|
+
class Base
|
67
|
+
attr_reader :loopback
|
68
|
+
|
69
|
+
def profile
|
70
|
+
yield
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
def with_gc_stats
|
75
|
+
@loopback = Rubinius::Agent.loopback
|
76
|
+
GC.run(true)
|
77
|
+
yield
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class WallTime < Time
|
82
|
+
def measure
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Memory < DigitalInformationUnit
|
88
|
+
def measure
|
89
|
+
loopback.get("system.memory.counter.bytes").last
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class Objects < Amount
|
94
|
+
def measure
|
95
|
+
loopback.get("system.memory.counter.objects").last
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class GcRuns < Amount
|
100
|
+
def measure
|
101
|
+
loopback.get("system.gc.full.count").last + loopback.get("system.gc.young.count").last
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class GcTime < Time
|
106
|
+
def measure
|
107
|
+
(loopback.get("system.gc.full.wallclock").last + loopback.get("system.gc.young.wallclock").last) / 1000.0
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
begin
|
2
|
+
require 'ruby-prof'
|
3
|
+
rescue LoadError
|
4
|
+
$stderr.puts 'Specify ruby-prof as application\'s dependency in Gemfile to run benchmarks.'
|
5
|
+
exit
|
6
|
+
end
|
7
|
+
|
8
|
+
module ActiveSupport
|
9
|
+
module Testing
|
10
|
+
module Performance
|
11
|
+
DEFAULTS.merge!(
|
12
|
+
if ARGV.include?('--benchmark')
|
13
|
+
{ :metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time] }
|
14
|
+
else
|
15
|
+
{ :min_percent => 0.01,
|
16
|
+
:metrics => [:process_time, :memory, :objects],
|
17
|
+
:formats => [:flat, :graph_html, :call_tree, :call_stack] }
|
18
|
+
end).freeze
|
19
|
+
|
20
|
+
protected
|
21
|
+
def run_gc
|
22
|
+
GC.start
|
23
|
+
end
|
24
|
+
|
25
|
+
class Profiler < Performer
|
26
|
+
def initialize(*args)
|
27
|
+
super
|
28
|
+
@supported = @metric.measure_mode rescue false
|
29
|
+
end
|
30
|
+
|
31
|
+
def run
|
32
|
+
return unless @supported
|
33
|
+
|
34
|
+
RubyProf.measure_mode = @metric.measure_mode
|
35
|
+
RubyProf.start
|
36
|
+
RubyProf.pause
|
37
|
+
full_profile_options[:runs].to_i.times { run_test(@metric, :profile) }
|
38
|
+
@data = RubyProf.stop
|
39
|
+
@total = @data.threads.values.sum(0) { |method_infos| method_infos.max.total_time }
|
40
|
+
end
|
41
|
+
|
42
|
+
def record
|
43
|
+
return unless @supported
|
44
|
+
|
45
|
+
klasses = full_profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact
|
46
|
+
|
47
|
+
klasses.each do |klass|
|
48
|
+
fname = output_filename(klass)
|
49
|
+
FileUtils.mkdir_p(File.dirname(fname))
|
50
|
+
File.open(fname, 'wb') do |file|
|
51
|
+
klass.new(@data).print(file, full_profile_options.slice(:min_percent))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
def output_filename(printer_class)
|
58
|
+
suffix =
|
59
|
+
case printer_class.name.demodulize
|
60
|
+
when 'FlatPrinter'; 'flat.txt'
|
61
|
+
when 'FlatPrinterWithLineNumbers'; 'flat_line_numbers.txt'
|
62
|
+
when 'GraphPrinter'; 'graph.txt'
|
63
|
+
when 'GraphHtmlPrinter'; 'graph.html'
|
64
|
+
when 'GraphYamlPrinter'; 'graph.yml'
|
65
|
+
when 'CallTreePrinter'; 'tree.txt'
|
66
|
+
when 'CallStackPrinter'; 'stack.html'
|
67
|
+
when 'DotPrinter'; 'graph.dot'
|
68
|
+
else printer_class.name.sub(/Printer$/, '').underscore
|
69
|
+
end
|
70
|
+
|
71
|
+
"#{super()}_#{suffix}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
module Metrics
|
76
|
+
class Base
|
77
|
+
def measure_mode
|
78
|
+
self.class::Mode
|
79
|
+
end
|
80
|
+
|
81
|
+
def profile
|
82
|
+
RubyProf.resume
|
83
|
+
yield
|
84
|
+
ensure
|
85
|
+
RubyProf.pause
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
# overridden by each implementation
|
90
|
+
def with_gc_stats
|
91
|
+
yield
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class ProcessTime < Time
|
96
|
+
Mode = RubyProf::PROCESS_TIME if RubyProf.const_defined?(:PROCESS_TIME)
|
97
|
+
|
98
|
+
def measure
|
99
|
+
RubyProf.measure_process_time
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class WallTime < Time
|
104
|
+
Mode = RubyProf::WALL_TIME if RubyProf.const_defined?(:WALL_TIME)
|
105
|
+
|
106
|
+
def measure
|
107
|
+
RubyProf.measure_wall_time
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class CpuTime < Time
|
112
|
+
Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
|
113
|
+
|
114
|
+
def initialize(*args)
|
115
|
+
# FIXME: yeah my CPU is 2.33 GHz
|
116
|
+
RubyProf.cpu_frequency = 2.33e9 unless RubyProf.cpu_frequency > 0
|
117
|
+
super
|
118
|
+
end
|
119
|
+
|
120
|
+
def measure
|
121
|
+
RubyProf.measure_cpu_time
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class Memory < DigitalInformationUnit
|
126
|
+
Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
|
127
|
+
end
|
128
|
+
|
129
|
+
class Objects < Amount
|
130
|
+
Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
|
131
|
+
end
|
132
|
+
|
133
|
+
class GcRuns < Amount
|
134
|
+
Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
|
135
|
+
end
|
136
|
+
|
137
|
+
class GcTime < Time
|
138
|
+
Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
if RUBY_VERSION.between?('1.9.2', '2.0')
|
146
|
+
require 'active_support/testing/performance/ruby/yarv'
|
147
|
+
elsif RUBY_VERSION.between?('1.8.6', '1.9')
|
148
|
+
require 'active_support/testing/performance/ruby/mri'
|
149
|
+
else
|
150
|
+
$stderr.puts 'Update your ruby interpreter to be able to run benchmarks.'
|
151
|
+
exit
|
152
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module ActiveSupport
|
2
|
+
module Testing
|
3
|
+
module Performance
|
4
|
+
module Metrics
|
5
|
+
class Base
|
6
|
+
protected
|
7
|
+
# Ruby 1.8 + ruby-prof wrapper (enable/disable stats for Benchmarker)
|
8
|
+
if GC.respond_to?(:enable_stats)
|
9
|
+
def with_gc_stats
|
10
|
+
GC.enable_stats
|
11
|
+
GC.start
|
12
|
+
yield
|
13
|
+
ensure
|
14
|
+
GC.disable_stats
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Memory < DigitalInformationUnit
|
20
|
+
# Ruby 1.8 + ruby-prof wrapper
|
21
|
+
if RubyProf.respond_to?(:measure_memory)
|
22
|
+
def measure
|
23
|
+
RubyProf.measure_memory
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Objects < Amount
|
29
|
+
# Ruby 1.8 + ruby-prof wrapper
|
30
|
+
if RubyProf.respond_to?(:measure_allocations)
|
31
|
+
def measure
|
32
|
+
RubyProf.measure_allocations
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class GcRuns < Amount
|
38
|
+
# Ruby 1.8 + ruby-prof wrapper
|
39
|
+
if RubyProf.respond_to?(:measure_gc_runs)
|
40
|
+
def measure
|
41
|
+
RubyProf.measure_gc_runs
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class GcTime < Time
|
47
|
+
# Ruby 1.8 + ruby-prof wrapper
|
48
|
+
if RubyProf.respond_to?(:measure_gc_time)
|
49
|
+
def measure
|
50
|
+
RubyProf.measure_gc_time / 1000.0 / 1000.0
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ActiveSupport
|
2
|
+
module Testing
|
3
|
+
module Performance
|
4
|
+
module Metrics
|
5
|
+
class Base
|
6
|
+
protected
|
7
|
+
# Ruby 1.9 with GC::Profiler
|
8
|
+
if defined?(GC::Profiler)
|
9
|
+
def with_gc_stats
|
10
|
+
GC::Profiler.enable
|
11
|
+
GC.start
|
12
|
+
yield
|
13
|
+
ensure
|
14
|
+
GC::Profiler.disable
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Memory < DigitalInformationUnit
|
20
|
+
# Ruby 1.9 + GCdata patch
|
21
|
+
if GC.respond_to?(:malloc_allocated_size)
|
22
|
+
def measure
|
23
|
+
GC.malloc_allocated_size
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Objects < Amount
|
29
|
+
# Ruby 1.9 + GCdata patch
|
30
|
+
if GC.respond_to?(:malloc_allocations)
|
31
|
+
def measure
|
32
|
+
GC.malloc_allocations
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class GcRuns < Amount
|
38
|
+
# Ruby 1.9
|
39
|
+
if GC.respond_to?(:count)
|
40
|
+
def measure
|
41
|
+
GC.count
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class GcTime < Time
|
47
|
+
# Ruby 1.9 with GC::Profiler
|
48
|
+
if defined?(GC::Profiler) && GC::Profiler.respond_to?(:total_time)
|
49
|
+
def measure
|
50
|
+
GC::Profiler.total_time
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|