Class: Gitlab::Sherlock::LineProfiler

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/sherlock/line_profiler.rb

Overview

Class for profiling code on a per line basis.

The LineProfiler class can be used to profile code on per line basis without littering your code with Ruby implementation specific profiling methods.

This profiler only includes samples taking longer than a given threshold and those that occur in the actual application (e.g. files from Gems are ignored).

Constant Summary collapse

MINIMUM_DURATION =

The minimum amount of time that has to be spent in a file for it to be included in a list of samples.

10.0

Instance Method Summary collapse

Instance Method Details

#aggregate_rblineprof(lineprof_stats) ⇒ Object

Returns an Array of file samples based on the output of rblineprof.

lineprof_stats - A Hash containing rblineprof statistics on a per file

basis.

Returns an Array of FileSample objects.


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/gitlab/sherlock/line_profiler.rb', line 59

def aggregate_rblineprof(lineprof_stats)
  samples = []

  lineprof_stats.each do |(file, stats)|
    source_lines = File.read(file).each_line.to_a
    line_samples = []

    total_duration = microsec_to_millisec(stats[0][0])
    total_events   = stats[0][2]

    next if total_duration <= MINIMUM_DURATION

    stats[1..-1].each_with_index do |data, index|
      next unless source_lines[index]

      duration = microsec_to_millisec(data[0])
      events   = data[2]

      line_samples << LineSample.new(duration, events)
    end

    samples << FileSample.
      new(file, line_samples, total_duration, total_events)
  end

  samples
end

#profile(&block) ⇒ Object

Profiles the given block.

Example:

profiler = LineProfiler.new

retval, samples = profiler.profile do
  "cats are amazing"
end

retval  # => "cats are amazing"
samples # => [#<Gitlab::Sherlock::FileSample ...>, ...]

Returns an Array containing the block's return value and an Array of FileSample objects.


32
33
34
35
36
37
38
39
# File 'lib/gitlab/sherlock/line_profiler.rb', line 32

def profile(&block)
  if mri?
    profile_mri(&block)
  else
    raise NotImplementedError,
      'Line profiling is not supported on this platform'
  end
end

#profile_mriObject

Profiles the given block using rblineprof (MRI only).


42
43
44
45
46
47
48
49
50
51
# File 'lib/gitlab/sherlock/line_profiler.rb', line 42

def profile_mri
  require 'rblineprof'

  retval  = nil
  samples = lineprof(/^#{Rails.root.to_s}/) { retval = yield }

  file_samples = aggregate_rblineprof(samples)

  [retval, file_samples]
end