rubyperf 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.1.0
data/lib/perf/meter.rb CHANGED
@@ -22,19 +22,48 @@ module Perf
22
22
  attr_accessor :measurements
23
23
  attr_accessor :current_path
24
24
 
25
- def initialize
25
+ @@overhead = nil
26
+
27
+ # Overhead calculation tuning constants
28
+ OVERHEAD_CALC_MAX_REPETITIONS = 1000
29
+ OVERHEAD_CALC_RUNS = 100
30
+ OVERHEAD_CALC_MIN_TIME = 0.1
31
+
32
+ # Creation of a Perf::Meter allows you to specify if you want to consider the overhead in the calculation or not.
33
+ # The overhead is calculated once and stored away. That way it is always the same in a single run.
34
+
35
+ def initialize(options={})
36
+ @options = options.clone
37
+
38
+ @options[:subtract_overhead] = true if @options[:subtract_overhead].nil? # Never use ||= with booleans
39
+
26
40
  @measurements = {} # A hash of Measure
27
41
  @current_path = nil
28
42
  @instrumented_methods = {METHOD_TYPE_INSTANCE=>[],METHOD_TYPE_CLASS=>[]}
29
43
  @class_methods = []
30
- #@overhead = nil
31
- #@overhead = Benchmark.measure do
32
- # measure(:a) {}
33
- #end
34
- #@overhead = nil
44
+ @subtract_overhead = @options[:subtract_overhead]
45
+ @@overhead ||= measure_overhead if @subtract_overhead
35
46
  @measurements = {} # A hash of Measure
36
47
  end
37
48
 
49
+ def overhead
50
+ if @subtract_overhead
51
+ @@overhead.clone
52
+ else
53
+ Benchmark::Tms.new
54
+ end
55
+ end
56
+
57
+ # Returns the total time - expressed with a Benchmark::Tms object - for all the blocks measures
58
+ def blocks_time
59
+ @measurements[PATH_MEASURES].time if @measurements[PATH_MEASURES]
60
+ end
61
+
62
+ # Returns the total time - expressed with a Benchmark::Tms object - for all the methods measures
63
+ def methods_time
64
+ @measurements[PATH_METHODS].time if @measurements[PATH_METHODS]
65
+ end
66
+
38
67
  # Takes a description and a code block and measures the performance of the block.
39
68
  # It returns the value returned by the block
40
69
  #
@@ -93,11 +122,11 @@ module Perf
93
122
  res=code.call
94
123
  else
95
124
  t = Benchmark.measure { res=code.call }
96
- #t -= @overhead if @overhead
97
- #if t.total>=0 && t.real>=0
98
- m.time += t
99
- root.time += t if root
100
- #end
125
+ t -= @@overhead if @subtract_overhead && @@overhead # Factor out the overhead of measure, if we are asked to do so
126
+ if t.total>=0 && t.real>=0
127
+ m.time += t
128
+ root.time += t if root
129
+ end
101
130
  end
102
131
  ensure
103
132
  @current_path=current_path
@@ -273,6 +302,26 @@ module Perf
273
302
 
274
303
  protected
275
304
 
305
+ # This method measures the overhead of calling "measure" on an instace of Perf::Meter.
306
+ # It will run OVERHEAD_CALC_RUNS measures of an empty block until the total time taken
307
+ # exceeds OVERHEAD_CALC_MIN_TIME.
308
+
309
+ def measure_overhead
310
+ t=Benchmark::Tms.new
311
+ cnt=0
312
+ rep=0
313
+ runs=OVERHEAD_CALC_RUNS
314
+ while t.total<OVERHEAD_CALC_MIN_TIME && rep<OVERHEAD_CALC_MAX_REPETITIONS
315
+ t+=Benchmark.measure do
316
+ runs.times {measure(:a) {}}
317
+ end
318
+ rep += 1 # Count the repetitions
319
+ cnt += runs # Count the total runs
320
+ runs *= 2 # Increases the number of runs to quickly adapt to the speed of the machine
321
+ end
322
+ t/cnt
323
+ end
324
+
276
325
  def set_measurement(path,m)
277
326
  @measurements[path]=m if m.is_a? Perf::Measure
278
327
  end
@@ -5,42 +5,112 @@
5
5
 
6
6
  module Perf
7
7
 
8
- # Simple Perf::Meter factory and singleton management.
8
+ # Very simple Perf::Meter factory and singleton management.
9
+ #
9
10
  # Useful to not have to pass around Perf::Meter objects and still be able to generate stats in various parts of
10
- # the code.
11
+ # the code. For complex situations where you have multiple Perf::Meter objects you might need to consider
12
+ # either creating a factory that fulfills your needs, or create Perf::Meter objects and pass them around or use
13
+ # this factory will well planned out key values so that you won't have conflicts and overrides.
14
+ #
15
+ # MeterFactory works keeping a global cache of Perf::Meter objects by key. Multiple independent parts
16
+ # of your code using this factory could get into trouble and trample on each other if they use the same key, or the
17
+ # default key.
18
+ #
19
+ # Example of usage where it would be inconvenient to pass around the Perf::Meter object from example to function2:
20
+ #
21
+ # def example
22
+ # Perf::MeterFactory.get.measure(:function1)
23
+ # function1()
24
+ # end
25
+ # end
26
+ #
27
+ # def function1()
28
+ # ..
29
+ # function2()
30
+ # ..
31
+ # end
32
+ #
33
+ # def function2()
34
+ # ..
35
+ # Perf::MeterFactory.get.measure(:some_hot_code_in_function2)
36
+ # ...
37
+ # end
38
+ # ..
39
+ # end
40
+ #
11
41
 
12
42
  class MeterFactory
13
43
 
14
44
  DEFAULT_METER = :default
15
45
 
16
- @@perf_meters=nil
46
+ @@perf_meters = nil
47
+ @@new_meter_options = {}
48
+ @@factory_options = {:noop=>false}
17
49
 
18
- # Returns a Perf::Meter with a given key, and creates it lazly if it doesn't exist'.
19
- def self.get(key=DEFAULT_METER)
50
+ # Returns a Perf::Meter with a given key, and creates it lazily if it doesn't exist'.
51
+ # NOTE: The options are set ONLY the first time that get is called on a specific key.
52
+ # After that the options will be ignored!
53
+
54
+ def self.get(key=DEFAULT_METER,new_meter_options=nil)
20
55
  @@perf_meters ||= {}
21
- @@perf_meters[key] ||= Perf::Meter.new
56
+ if !@@factory_options[:noop]
57
+ # Creates a real meter
58
+ @@perf_meters[key] ||= Perf::Meter.new(new_meter_options || @@new_meter_options)
59
+ else
60
+ # If noop is set, creates a no-nop version of the meter, unless a meter with this key has already been
61
+ # created.
62
+ @@perf_meters[key] ||= Perf::NoOpMeter.new
63
+ end
64
+ end
65
+
66
+ # To set options for new meters created by get, when specific options are not passed, you can do so with this
67
+ # method.
68
+
69
+ def self.set_new_meters_options(options)
70
+ @@new_meter_options.merge(options)
71
+ end
72
+
73
+ # Set options for the factory behaviour.
74
+
75
+ def self.set_factory_options(options)
76
+ @@factory_options.merge!(options)
77
+ end
78
+
79
+ # If you use set_new_meters_options, or if you pass options to Perf::MeterFactory.get, you are setting options
80
+ # only for if the meter is created. For this reason you might need to find out if the meter already exist.
81
+
82
+ def exists?(key=DEFAULT_METER)
83
+ !@@perf_meters[key].nil?
22
84
  end
23
85
 
24
86
  # Pushes a Perf::Meter into a key
87
+
25
88
  def self.set_meter(key,meter)
26
89
  @@perf_meters ||= {}
27
90
  @@perf_meters[key]=meter
28
91
  end
29
92
 
30
93
  # Sets the default meter.
94
+
31
95
  def self.set_default(meter)
32
96
  set_meter(DEFAULT_METER,meter)
33
97
  end
34
98
 
99
+ # Returns a hash of existing meters.
100
+
35
101
  def self.all
36
102
  @@perf_meters ||= {}
37
103
  return @@perf_meters.clone
38
104
  end
39
105
 
106
+ # Removes an existing meter from the cache
107
+
40
108
  def self.clear_meter(key=DEFAULT_METER)
41
109
  @@perf_meters.delete(key) if @@perf_meters
42
110
  end
43
111
 
112
+ # Clears the entire cache of meters.
113
+
44
114
  def self.clear_all!
45
115
  @@perf_meters=nil
46
116
  end
@@ -12,7 +12,7 @@ module Perf
12
12
  #
13
13
  class NoOpMeter
14
14
 
15
- def initialize(logger = nil)
15
+ def initialize(options=nil)
16
16
  end
17
17
 
18
18
  def clear
@@ -33,7 +33,7 @@ module Perf
33
33
  def measure_instance_method(klass,method_name)
34
34
  end
35
35
 
36
- def measure_instance_method(klass,method_name)
36
+ def restore_instance_method(klass,method_name)
37
37
  end
38
38
 
39
39
  def restore_all_instance_methods(klass)
@@ -51,14 +51,24 @@ module Perf
51
51
  def restore_all_methods(klass)
52
52
  end
53
53
 
54
- def measure_full_path(path,&code)
55
- yield
54
+ def overhead
55
+ Benchmark::Tms.new
56
+ end
57
+
58
+ # Returns the total time - expressed with a Benchmark::Tms object - for all the blocks measures
59
+ def blocks_time
60
+ Benchmark::Tms.new
61
+ end
62
+
63
+ # Returns the total time - expressed with a Benchmark::Tms object - for all the methods measures
64
+ def methods_time
65
+ Benchmark::Tms.new
56
66
  end
57
67
 
58
68
  def method_missing(method_sym, *arguments, &block)
59
69
  if method_sym.to_s =~ /^report_(.*)$/
60
70
  klass=Object.const_get("Perf").const_get("ReportFormat#{$1.capitalize}")
61
- return klass.new.format(self) if klass
71
+ return nil if klass
62
72
  end
63
73
  super
64
74
  end
@@ -62,7 +62,7 @@ module Perf
62
62
  end
63
63
 
64
64
  # Header
65
- rep << format_header(:title => "measure path", :max_title => max_title,
65
+ rep << format_header(:title => "measure", :max_title => max_title,
66
66
  :percent => "percent",
67
67
  :count => "count", :max_count => max_count,
68
68
  :time => Benchmark::Tms::CAPTION,
data/rubyperf.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rubyperf}
8
- s.version = "1.0.1"
8
+ s.version = "1.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["lpasqualis"]
@@ -43,14 +43,13 @@ Gem::Specification.new do |s|
43
43
  s.homepage = %q{http://github.com/lpasqualis/rubyperf}
44
44
  s.licenses = ["MIT"]
45
45
  s.require_paths = ["lib"]
46
- s.rubygems_version = %q{1.3.6}
46
+ s.rubygems_version = %q{1.4.2}
47
47
  s.summary = %q{rubyperf helps you measure ruby code performance}
48
48
 
49
49
  if s.respond_to? :specification_version then
50
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
50
  s.specification_version = 3
52
51
 
53
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
53
  s.add_development_dependency(%q<shoulda>, [">= 0"])
55
54
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
56
55
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
@@ -14,6 +14,74 @@ require 'perf_test_example'
14
14
 
15
15
  class TestMeterFactory < Test::Unit::TestCase
16
16
 
17
+ def setup()
18
+ Perf::MeterFactory.clear_all!
19
+ end
20
+
21
+ def teardown()
22
+ Perf::MeterFactory.clear_all!
23
+ Perf::MeterFactory.set_factory_options(:noop=>false)
24
+ end
25
+
26
+ def test_noop
27
+ Perf::MeterFactory.set_factory_options(:noop=>true)
28
+ m1=Perf::MeterFactory.get()
29
+ assert m1.is_a? Perf::NoOpMeter
30
+ m1.measure(:something) do
31
+ # ...
32
+ end
33
+ assert m1.report_simple.nil?
34
+ end
35
+
36
+ def test_noop2
37
+ Perf::MeterFactory.set_factory_options(:noop=>true)
38
+ m=Perf::MeterFactory.get()
39
+ assert m.is_a? Perf::NoOpMeter
40
+ m.measure(:string_operations) do
41
+ m.measure(:ciao) do
42
+ 10.times do; "CIAO"*100; end
43
+ end
44
+ end
45
+ m.measure(:string_operations) do
46
+ m.measure(:help) do
47
+ 10.times do; "HELP"*100; end
48
+ end
49
+ end
50
+ m.measure(:emtpy_loop) do
51
+ 500.times do; end;
52
+ end
53
+ m.measure(:rough_overhead_x10000) do
54
+ 10.times do
55
+ m.measure(:block_1) do
56
+ m.measure(:block_1_1) do
57
+ end
58
+ m.measure(:block_1_2) do
59
+ m.measure(:block_1_2_1) do
60
+ end
61
+ m.measure(:block_1_2_2) do
62
+ end
63
+ m.measure(:block_1_2_3) do
64
+ assert_equal false,m.measure_result(:bool_exp_1_2_3) { false }
65
+ m.measure_result(:bool_exp_1_2_3) { true }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ m.measure(:empty) do
73
+ end
74
+ m.measure_result("test") { "something" }
75
+ m.measure_result("test") { false }
76
+ m.measure_result("test") { false }
77
+
78
+ m.method_meters(Array,[:sort,:reverse],[:new]) do
79
+ Array.new(1000000,"abc").reverse.sort
80
+ end
81
+ assert_equal 123,m.measure(:blah) {123}
82
+ assert m.report_simple.nil?
83
+ end
84
+
17
85
  def test_basic
18
86
  Perf::MeterFactory.clear_all!
19
87
  m1=Perf::MeterFactory.get()
@@ -107,25 +107,8 @@ class TestPerfMeter < Test::Unit::TestCase
107
107
  assert PerfTestExample.methods.sort == cmethods
108
108
  assert PerfTestExample.new.methods.sort == imethods
109
109
 
110
- assert_equal ['\methods,0',
111
- '\methods\#<Class:PerfTestExample>.static_method,1',
112
- '\methods\PerfTestExample.test,1',
113
- '\methods\PerfTestExample.test_np,1'],
114
- m.report_list_of_measures
115
-
116
110
  assert_equal 6,m.report_simple.length
117
111
  assert_equal 6,m.report_html.length
118
- end
119
-
120
- def test_method_metering
121
- m=Perf::Meter.new
122
- m.method_meters(PerfTestExample,[:test,:test_np],[:static_method]) do
123
- a=PerfTestExample.new
124
- a.test(1,2,3)
125
- a.test_np
126
- PerfTestExample.static_method
127
- end
128
-
129
112
  assert_equal ['\methods,0',
130
113
  '\methods\#<Class:PerfTestExample>.static_method,1',
131
114
  '\methods\PerfTestExample.test,1',
@@ -285,13 +268,34 @@ class TestPerfMeter < Test::Unit::TestCase
285
268
  def test_overhead
286
269
  runs=1_000
287
270
  a=(1..100_000).to_a
288
- m=Perf::Meter.new
289
- b1=Benchmark.measure { runs.times { m.measure(:a) { a.reverse! } } }
290
- b2=Benchmark.measure { runs.times { a.reverse! } }
271
+ m_no_overhead=Perf::Meter.new(:subtract_overhead=>true)
272
+ b1_no_overhead=Benchmark.measure { runs.times { m_no_overhead.measure(:a) { a.reverse! } } }
273
+ b2_no_overhead=Benchmark.measure { runs.times { a.reverse! } }
274
+
275
+ m_yes_overhead=Perf::Meter.new(:subtract_overhead=>false)
276
+ b1_yes_overhead=Benchmark.measure { runs.times { m_yes_overhead.measure(:a) { a.reverse! } } }
277
+ b2_yes_overhead=Benchmark.measure { runs.times { a.reverse! } }
278
+
279
+
291
280
  assert_equal ['\blocks,0',
292
281
  '\blocks\a,1000'],
293
- m.report_list_of_measures
294
- # Here we should assert if the overhead is > a certain percentage.
295
- # puts "Measurement overhead x 1000 = #{b1-b2}"
282
+ m_no_overhead.report_list_of_measures
283
+
284
+ assert_equal m_no_overhead.report_list_of_measures,
285
+ m_yes_overhead.report_list_of_measures
286
+
287
+ # TODO: find the magic assert that ensures that the overhead calculation is correct. Ensure that such assert
288
+ # is machine independent and that will pass the test of time (new hardware getting faster and faster)
289
+
290
+ #calculated_overhead_1= (b1_no_overhead-b2_no_overhead)/runs
291
+ #calculated_overhead_2= (b1_yes_overhead-b2_yes_overhead)/runs
292
+ #
293
+ #puts (calculated_overhead_1-m_no_overhead.overhead)
294
+ #puts (calculated_overhead_2-m_yes_overhead.overhead)
295
+ #
296
+ #puts m_no_overhead.report_simple
297
+ #puts m_yes_overhead.report_simple
298
+ #
299
+ #assert m_no_overhead.blocks_time.total > m_yes_overhead.blocks_time.total
296
300
  end
297
301
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyperf
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
4
+ hash: 19
5
+ prerelease:
5
6
  segments:
6
7
  - 1
7
- - 0
8
8
  - 1
9
- segments_generated: true
10
- version: 1.0.1
9
+ - 0
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - lpasqualis
@@ -20,60 +20,64 @@ default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  prerelease: false
23
- type: :development
24
- name: shoulda
25
- version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
28
+ hash: 3
29
29
  segments:
30
30
  - 0
31
- segments_generated: true
32
31
  version: "0"
33
- requirement: *id001
32
+ type: :development
33
+ name: shoulda
34
+ version_requirements: *id001
34
35
  - !ruby/object:Gem::Dependency
35
36
  prerelease: false
36
- type: :development
37
- name: bundler
38
- version_requirements: &id002 !ruby/object:Gem::Requirement
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
39
  requirements:
40
40
  - - ~>
41
41
  - !ruby/object:Gem::Version
42
+ hash: 23
42
43
  segments:
43
44
  - 1
44
45
  - 0
45
46
  - 0
46
- segments_generated: true
47
47
  version: 1.0.0
48
- requirement: *id002
48
+ type: :development
49
+ name: bundler
50
+ version_requirements: *id002
49
51
  - !ruby/object:Gem::Dependency
50
52
  prerelease: false
51
- type: :development
52
- name: jeweler
53
- version_requirements: &id003 !ruby/object:Gem::Requirement
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
54
55
  requirements:
55
56
  - - ~>
56
57
  - !ruby/object:Gem::Version
58
+ hash: 7
57
59
  segments:
58
60
  - 1
59
61
  - 6
60
62
  - 4
61
- segments_generated: true
62
63
  version: 1.6.4
63
- requirement: *id003
64
+ type: :development
65
+ name: jeweler
66
+ version_requirements: *id003
64
67
  - !ruby/object:Gem::Dependency
65
68
  prerelease: false
66
- type: :development
67
- name: rcov
68
- version_requirements: &id004 !ruby/object:Gem::Requirement
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
69
71
  requirements:
70
72
  - - ">="
71
73
  - !ruby/object:Gem::Version
74
+ hash: 3
72
75
  segments:
73
76
  - 0
74
- segments_generated: true
75
77
  version: "0"
76
- requirement: *id004
78
+ type: :development
79
+ name: rcov
80
+ version_requirements: *id004
77
81
  description: Used to easily measure the performance of blocks of Ruby code, expressions and methods; provides reporting in various formats
78
82
  email: lpasqualis@gmail.com
79
83
  executables: []
@@ -116,25 +120,27 @@ rdoc_options: []
116
120
  require_paths:
117
121
  - lib
118
122
  required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
119
124
  requirements:
120
125
  - - ">="
121
126
  - !ruby/object:Gem::Version
127
+ hash: 3
122
128
  segments:
123
129
  - 0
124
- segments_generated: true
125
130
  version: "0"
126
131
  required_rubygems_version: !ruby/object:Gem::Requirement
132
+ none: false
127
133
  requirements:
128
134
  - - ">="
129
135
  - !ruby/object:Gem::Version
136
+ hash: 3
130
137
  segments:
131
138
  - 0
132
- segments_generated: true
133
139
  version: "0"
134
140
  requirements: []
135
141
 
136
142
  rubyforge_project:
137
- rubygems_version: 1.3.6
143
+ rubygems_version: 1.4.2
138
144
  signing_key:
139
145
  specification_version: 3
140
146
  summary: rubyperf helps you measure ruby code performance