Class: Perf::Meter

Inherits:
Object
  • Object
show all
Defined in:
lib/perf/meter.rb

Overview

Measures the runtime execution speed of a block of code, expression or entire methods.

Constant Summary collapse

ACCURACY_UNKNOWN =

Constant for accuracy. The constant represents the upper bound of its description.

0.0
ACCURACY_VERY_POOR =
1.0
ACCURACY_POOR =
50.0
ACCURACY_FAIR =
100.0
ACCURACY_GOOD =
1000.0
ACCURACY_EXCELLENT =
1.0/0
PATH_MEASURES =

Name of the path roots

'\blocks'
PATH_METHODS =
'\methods'
METHOD_TYPE_INSTANCE =

Hash keys for instrumented methods

:instance
METHOD_TYPE_CLASS =
:class
OVERHEAD_CALC_MAX_REPETITIONS =

Overhead calculation tuning constants

1000
OVERHEAD_CALC_RUNS =
10
OVERHEAD_CALC_MIN_TIME =
0.1
@@overhead =
nil

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Meter

Creation of a Perf::Meter allows you to specify if you want to consider the overhead in the calculation or not. The overhead is calculated once and stored away. That way it is always the same in a single run.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/perf/meter.rb', line 44

def initialize(options={})
  @options = options.clone

  @options[:subtract_overhead] = true if @options[:subtract_overhead].nil? # Never use ||= with booleans

  @measurements             = {}      # A hash of Measure
  @current_path             = nil
  @instrumented_methods     = {METHOD_TYPE_INSTANCE=>[],METHOD_TYPE_CLASS=>[]}
  @subtract_overhead        = @options[:subtract_overhead]
  if @@overhead.nil?
    @@overhead              = measure_overhead
    @measurements           = {}      # A hash of Measure; must repeat here to cleanup what measure_overhead did
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_sym, *arguments, &block) ⇒ Object (protected)

You can generate a report using one of the built-in report formats with a simple syntax shortcut

m=Perf::Meter.new
m.report_FORMAT

Where FORMAT is the ending part of one of the ReportFormatFORMAT classes built in.

Examples

m=Perf::Meter.new m.measure(:something) something puts m.report_html puts m.report_simple



473
474
475
476
477
478
479
# File 'lib/perf/meter.rb', line 473

def method_missing(method_sym, *arguments, &block)
  if method_sym.to_s =~ /^report_(.*)$/
    klass=Object.const_get("Perf").const_get("ReportFormat#{camelize($1)}")
    return klass.new.format(self,arguments[0]) if klass
  end
  super
end

Instance Attribute Details

#current_pathObject

Returns the value of attribute current_path.



32
33
34
# File 'lib/perf/meter.rb', line 32

def current_path
  @current_path
end

#measurementsObject

Returns the value of attribute measurements.



31
32
33
# File 'lib/perf/meter.rb', line 31

def measurements
  @measurements
end

Instance Method Details

#accuracy(path) ⇒ Object

Returns an index of accuracy of the measure calculated in relation to the overhead. The larger the accuracy, the more accurate the measure. accuracy < 0 means that it is not possible to calculate; accuracy <= 1 means that the measure is equal or smaller than the overhead.

This makes the measure very inaccurate.

accuracy = X means that the measure is X times the overhead.



346
347
348
349
350
351
352
353
354
355
# File 'lib/perf/meter.rb', line 346

def accuracy(path)
  if @@overhead
    over=@@overhead[:time].total+@@overhead[:time].real
    if over>0
      m=get_measurement(path)
      return ((m.time.total+m.time.real)*@@overhead[:count] / (over*m.count)) if m.count>0
    end
  end
  -1.0
end

#adjust_overheadObject

The overhead cannot be larger that any of the measures taken. If a measure taken is larger than the overhead, than this function takes care of adjusting the overhead. This is called by the ReportFormat class just before rendering the report, so you should not have to call this by hand unless you are interested in getting the overhead.



362
363
364
# File 'lib/perf/meter.rb', line 362

def adjust_overhead
  false
end

#adjusted_time(m) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/perf/meter.rb', line 67

def adjusted_time(m)
  return m.time if !@subtract_overhead || !@overhead

  utime,stime,cutime,cstime,real = nil,nil,nil,nil,nil

  adj=m.time-((@overhead[:time]*m.count)/@overhead[:count])

  utime  = 0.0 if adj.utime  < 0.0
  stime  = 0.0 if adj.stime  < 0.0
  cutime = 0.0 if adj.cutime < 0.0
  cstime = 0.0 if adj.cstime < 0.0
  real   = 0.0 if adj.real   < 0.0

  if utime || stime || cutime || cstime || real
    Benchmark::Tms.new(utime  || adj.utime,
                       stime  || adj.stime,
                       cutime || adj.cutime,
                       cstime || adj.cstime,
                       real   || adj.real)
  else
    adj
  end
end

#blocks_timeObject

Returns the total time - expressed with a Benchmark::Tms object - for all the blocks measures



96
97
98
# File 'lib/perf/meter.rb', line 96

def blocks_time
  @measurements[PATH_MEASURES].time if @measurements[PATH_MEASURES]
end

#has_measures?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/perf/meter.rb', line 91

def has_measures?
  @measurements.length > 0
end

#measure(what, root_path = PATH_MEASURES, &code) ⇒ Object

Takes a description and a code block and measures the performance of the block. It returns the value returned by the block

Attributes

  • what - The title that will identify of the block

  • code - Block of code to measure

Examples

Measures the time taken by the code in the block

perf = Perf::Meter.new
perf.measure(:func) do
   some code here
end

Measure the time taken to compute “some_expression”

if perf.measure(:some_expression) { some_expression }
  ...
end

Measure a bunch of things, and divides the measures in sub blocks that get measures separately

perf.measure(:bunch_of_stuff) do
   perf.measure(:thing1)  do
     ...
   end
   perf.measure(:thing2) do
      perf.measure(:thing2_part1) do
        ...
      end
      perf.measure(:thing2_part2) do
        ...
      end
   end
end


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/perf/meter.rb', line 145

def measure(what,root_path=PATH_MEASURES,&code)
  current_path=@current_path
  if @current_path.nil?
    @current_path=root_path
    root=get_measurement(@current_path)
  else
    root=nil
  end
  @current_path+= "\\#{what}"
  res=nil
  begin
    m=get_measurement(@current_path)
    m.count     += 1
    root.count  += 1 if root
    m.measuring +=1
    if m.measuring>1
      res=code.call
    else
      t = Benchmark.measure { res=code.call }
      root.time  += t if root
      m.time     += t
    end
  ensure
    @current_path=current_path
    m.measuring-=1
  end
  res
end

#measure_class_method(klass, method_name) ⇒ Object

Puts a wrapper around class methods of a specific class to measure their performance Remember to use restore_class_method when you are done, otherwise the class method will stay instrumented.

Use sparingly!

Attributes

  • klass - The Class containing the instance method that you want to measure

  • method_name - The name of the class method that you want to measure

Examples

Instruments the class find so that the execution of the class method “static_method” will be measures every time that is used.

perf = Perf::Meter.new
perf.measure_class_method(SomeClass,:static_method)
..

Removes the instrumentation (important!)

perf.restore_class_method(SomeClass,:static_method)

Removes all instrumentation from class SomeClass

perf.restore_all_class_methods(SomeClass)


313
314
315
# File 'lib/perf/meter.rb', line 313

def measure_class_method(klass,method_name)
  measure_method_by_type(class << klass; self end,method_name,METHOD_TYPE_CLASS)
end

#measure_instance_method(klass, method_name) ⇒ Object

Puts a wrapper around instance methods of a specific class to measure their performance Remember to use restore_instance_method when you are done, otherwise the method will stay instrumented.

Use sparingly!

Attributes

  • klass - The Class containing the instance method that you want to measure

  • method_name - The name of the method that you want to measure

Examples

Instruments the class find so that the execution of the method “find” will be measures every time that is used.

perf = Perf::Meter.new
perf.measure_instance_method(User,:find)
..

Removes the instrumentation (important!)

perf.restore_instance_method(User,:find)

Removes all instrumentation from class User

perf.restore_all_instance_methods(User)


268
269
270
# File 'lib/perf/meter.rb', line 268

def measure_instance_method(klass,method_name)
  measure_method_by_type(klass,method_name,METHOD_TYPE_INSTANCE)
end

#measure_result(what, &code) ⇒ Object

Takes a description and an expression returning a value and measures the performance of the expression storing the result by returned value. Should be used only for expressions that can return only a small discrete number of unique values, such a flag for example.

It returns the value returned by the block

Attributes

  • what - The title that will identify of the block

  • code - Block of code to measure

Examples

Measures the time take to compute the existence of user xyz and will give you stats for the case in which the result is true and false.

perf = Perf::Meter.new
if perf.measure_result(:long_epression) { User.find(xyz).nil? }
end


195
196
197
198
199
# File 'lib/perf/meter.rb', line 195

def measure_result(what,&code)
  res=measure(what,PATH_MEASURES,&code)
  merge_measures(what,"#{what} = \"#{res.to_s}\"")
  res
end

#method_meters(klass, imethods = [], cmethods = []) ⇒ Object

Puts a wrapper around a set of methods of a specific class to measure their performance. The set is provided with an array of instance methods, and one of class methods.

The method defines the wrapper, yields to the block, and then restores the instrumented class. This ensures that the instrumented class is restored, and that the instrumentation occurs only in the context of the block

Attributes

  • klass - The Class containing the instance method that you want to measure

  • imethods - An array of instance methods that you want to measure

  • cmethods - An array of class methods that you want to measure

Examples

perf = Perf::Meter.new
m.method_meters(PerfTestExample,[:test,:test_np],[:static_method]) do
  a=PerfTestExample.new
  a.test(1,2,3)
  a.test_np
  PerfTestExample.static_method
end

After this m contains measures for the executions of the instance methods test, test_np and the class methods static_method



228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/perf/meter.rb', line 228

def method_meters(klass,imethods=[],cmethods=[])
  res=nil
  begin
    imethods.each {|m| measure_instance_method(klass,m) }
    cmethods.each {|m| measure_class_method(klass,m) }
    res=yield
  ensure
    imethods.each {|m| restore_instance_method(klass,m) }
    cmethods.each {|m| restore_class_method(klass,m) }
  end
  res
end

#methods_timeObject

Returns the total time - expressed with a Benchmark::Tms object - for all the methods measures



101
102
103
# File 'lib/perf/meter.rb', line 101

def methods_time
  @measurements[PATH_METHODS].time if @measurements[PATH_METHODS]
end

#overheadObject



59
60
61
62
63
64
65
# File 'lib/perf/meter.rb', line 59

def overhead
  if @subtract_overhead
    @@overhead.dup
  else
    {:time=>Benchmark::Tms.new,:count=>0}
  end
end

#restore_all_class_methods(klass) ⇒ Object

Removes the instrumentation of all class methods in a given class. See measure_class_method for more information.



327
328
329
# File 'lib/perf/meter.rb', line 327

def restore_all_class_methods(klass)
  restore_all_methods_by_type(class << klass; self end,METHOD_TYPE_CLASS)
end

#restore_all_instance_methods(klass) ⇒ Object

Removes all instrumentation of instance methods in a given class. See measure_instance_method for more information.



282
283
284
# File 'lib/perf/meter.rb', line 282

def restore_all_instance_methods(klass)
  restore_all_methods_by_type(klass,METHOD_TYPE_INSTANCE)
end

#restore_all_methods(klass) ⇒ Object

Removes all instrumentation of class methods and instance methods in a given class. See measure_class_method for more information.



334
335
336
337
# File 'lib/perf/meter.rb', line 334

def restore_all_methods(klass)
  restore_all_instance_methods(klass)
  restore_all_class_methods(klass)
end

#restore_class_method(klass, method_name) ⇒ Object

Removes the instrumentation of a class method in a given class. See measure_class_method for more information.



320
321
322
# File 'lib/perf/meter.rb', line 320

def restore_class_method(klass,method_name)
  restore_method_by_type(class << klass; self end,method_name,METHOD_TYPE_CLASS)
end

#restore_instance_method(klass, method_name) ⇒ Object

Removes the instrumentation of a instance method in a given class. See measure_instance_method for more information.



275
276
277
# File 'lib/perf/meter.rb', line 275

def restore_instance_method(klass,method_name)
  restore_method_by_type(klass,method_name,METHOD_TYPE_INSTANCE)
end