Class: Benchin::Wrap

Inherits:
Object
  • Object
show all
Defined in:
lib/benchin/wrap.rb,
lib/benchin/wrap/report.rb,
lib/benchin/wrap/report/node.rb,
lib/benchin/wrap/report/node_printer.rb

Overview

Benchmark tool for high-level nested measurement. Check out Report#to_h for an example of the report structure.

It's designed to use when:

  • you have some slow code (even one execution takes significant time)

  • you know which blocks of code you have to measure

  • you have to measure:

    • total time spend in each block

    • time spend in blocks executed inside a concrete block (child time)

    • time spend in a concrete block minus child block's time (self time)

By using this information you can discover which block of slow code is the slowest one.

Measurement uses WALL time.

One of the most common possible examples of usage is to investigate slow requests in legacy and big codebases. In this case more classic instruments like stack profiling can be too focused on particular methods instead of logic chunks in your code.

It can be inconvenient to 'drill' Wrap instance to all the places where we have to wrap some code. To address this issue we have helper wrap which uses global Wrap instance.

Examples:

Measure request timings in controller

class SomeDirtyController < SomeWebFramework::Controller
  def create(params)
    @bench = Benchin::Wrap.new('CREATE REQUEST')

    data = @bench.call('Create Operation') do
      do_create(params)
    end

    @bench.call('Rendering') do
      render data
    end

    File.write('report.txt', @bench.to_s)
  end

  private

  def do_create(params)
    do_something(params)
    @bench.call('Event Logging') do
      log_events
    end
  end
end
# Report saved to a file will look like:
#
# CREATE REQUEST ->
# |   time(all):       22.0
# |   Create Operation ->
# |   |   calls:              1
# |   |   time(all):       15.0
# |   |   time(self):       5.0
# |   |   time(childs):    10.0
# |   |   Event Logging ->
# |   |   |   calls:              1
# |   |   |   time(all):       10.0
# |   |   |   time(self):      10.0
# |   |   |   time(childs):     0.0
# |   Rendering ->
# |   |   calls:              1
# |   |   time(all):        7.0
# |   |   time(self):       7.0
# |   |   time(childs):     0.0

Defined Under Namespace

Classes: Report

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Wrap

Returns a new instance of Wrap.

Parameters:

  • name (String)

    report name


76
77
78
79
80
81
# File 'lib/benchin/wrap.rb', line 76

def initialize(name)
  @name = name

  @report = Report.new(@name)
  @current_path = []
end

Instance Attribute Details

#reportReport (readonly)

Returns collected measurement data.

Returns:

  • (Report)

    collected measurement data.


73
74
75
# File 'lib/benchin/wrap.rb', line 73

def report
  @report
end

Instance Method Details

#call(name) { ... } ⇒ Object

Wraps code block with WALL time measurement and returns the block result.

Can be used in a nested way.

Examples:

Simple measurement

wrap = Benchin::Wrap.new
wrap.call('Sum of strings') do
  ['aa', 'bb', 'cc'].sum
end
#=> 'aabbcc'

Nested measurement

wrap = Benchin::Wrap.new
wrap.call('Big calcultation') do
  array = some_expensive_code
  processed = array.map do |data|
    wrap.call('Nested calcultation') do
      some_tranformation(data)
    end
  end
  send_somewhere(processed)
end

Parameters:

  • name (String)

    name for code block in reporting.

Yields:

  • code block to execute.

Returns:

  • result of provided block execution.


119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/benchin/wrap.rb', line 119

def call(name)
  @current_path.push name
  starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  result = yield
  ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  elapsed = ending - starting

  report.add_time(@current_path, elapsed)
  @current_path.pop

  result
end

#resetWrap

Resets the #report to an empty state.

Returns:


86
87
88
89
90
91
# File 'lib/benchin/wrap.rb', line 86

def reset
  @report = Report.new(@name)
  @current_path = []

  self
end

#to_hHash

Shortcut for `report.to_h`.

Returns:

  • (Hash)

See Also:

  • Benchin::Wrap.{Report{Report.to_s}

144
145
146
# File 'lib/benchin/wrap.rb', line 144

def to_h
  report.to_s
end

#to_sString

Shortcut for `report.to_s`.

Returns:

  • (String)

See Also:

  • Benchin::Wrap.{Report{Report.to_s}

136
137
138
# File 'lib/benchin/wrap.rb', line 136

def to_s
  report.to_s
end