class RuntimeProfiler::Data

Attributes

controller_data[R]
sql_data[R]

Public Class Methods

new(controller_data: nil, sql_data: nil) click to toggle source
# File lib/runtime_profiler/data.rb, line 5
def initialize(controller_data: nil, sql_data: nil)
  @controller_data = controller_data || {}
  @sql_data = sql_data
end

Public Instance Methods

persist!() click to toggle source
# File lib/runtime_profiler/data.rb, line 10
def persist!
  File.open(output_file, 'w') do |f|
    f.write JSON.dump(profiling_data)
  end

  puts "\n"
  puts 'Profiling data written at ' + output_file.to_s
  puts 'You can view profiling data via: bundle exec runtime_profiler view ' + output_file.to_s
  puts "\n"
end

Private Instance Methods

method_calls_data() click to toggle source
# File lib/runtime_profiler/data.rb, line 59
def method_calls_data
  @method_calls_data ||= begin
    profiled_methods = {}

    # TODO: Group methods under a key and under an object
    MethodMeter.measurement.each_pair do |key, data|
      data.each do |d|
        object = d[:method].split(separator = '.')
        object = d[:method].split(separator = '#') if object.length == 1

        d[:method] = separator + object.second

        if profiled_methods[object.first]
          profiled_methods[object.first] << d
        else
          profiled_methods[object.first] = [d]
        end
      end
    end

    profiled_methods = profiled_methods.inject({}) do |hash, (key, value)|
      val = value.sort { |a, b| b[:total_runtime] <=> a[:total_runtime] }
      hash[key] = val
      hash
    end

    slowest_method = {total_runtime: 0}
    mostly_called_method = {total_calls: 0}

    profiled_methods.each do |profiled_object_name, methods|
      # sort using `total_runtime` in DESC order
      _methods = methods.sort { |a, b| b[:total_runtime] <=> a[:total_runtime] }
      slowest = _methods[0]

      if slowest[:total_runtime] > slowest_method[:total_runtime]
        slowest_method[:method]         = [profiled_object_name, slowest[:method]].join
        slowest_method[:total_runtime]  = slowest[:total_runtime]
      end

      # sort using `total_calls` in DESC order and GET first item
      mostly_called = methods.sort { |a, b| b[:total_calls] <=> a[:total_calls] } [0]

      if mostly_called[:total_calls] > mostly_called_method[:total_calls]
        mostly_called_method[:method]         = [profiled_object_name, mostly_called[:method]].join
        mostly_called_method[:total_runtime]  = mostly_called[:total_runtime]
        mostly_called_method[:total_calls]    = mostly_called[:total_calls]
        mostly_called_method[:min]            = mostly_called[:min]
        mostly_called_method[:max]            = mostly_called[:max]
      end
    end

    {
      profiled_methods: profiled_methods,
            slowest_method: slowest_method,
      mostly_called_method: mostly_called_method
    }
  end
end
output_file() click to toggle source
# File lib/runtime_profiler/data.rb, line 23
def output_file
  FileUtils.mkdir_p(RuntimeProfiler.output_path)
  filename = ['rp', Process.pid, Time.now.to_i].join('-') + '.json'
  File.join(RuntimeProfiler.output_path, filename)
end
profiled_api() click to toggle source
# File lib/runtime_profiler/data.rb, line 29
def profiled_api
  return unless controller_data[:payload]
  @profiled_api ||= [
    controller_data[:payload][:controller],
    controller_data[:payload][:action]
  ].join('#')
end
profiling_data() click to toggle source
# File lib/runtime_profiler/data.rb, line 37
def profiling_data
  @profiling_data ||= {
    profiling: {
      profiled_api: profiled_api,
      summary: {
                    db_runtime: controller_data[:db_runtime],
                  view_runtime: controller_data[:view_runtime],
                 total_runtime: controller_data[:total_runtime],
                   slowest_sql: sql_calls_data[:slowest_sql],
             mostly_called_sql: sql_calls_data[:mostly_called_sql],
               total_sql_calls: sql_calls_data[:total_sql_calls],
        total_unique_sql_calls: sql_calls_data[:total_unique_sql_calls],
                slowest_method: method_calls_data[:slowest_method],
          mostly_called_method: method_calls_data[:mostly_called_method]
      },
      profiled_sql_calls: sql_calls_data[:profiled_sql_calls],
      profiled_methods: method_calls_data[:profiled_methods],
      profiled_at: Time.now
    }
  }
end
sql_calls_data() click to toggle source
# File lib/runtime_profiler/data.rb, line 118
def sql_calls_data
  @sql_calls_data ||= begin
    profiled_sql_calls = []

    slowest_sql = {total_runtime: 0}
    mostly_called_sql = {total_calls: 0}

    sql_data.values.each do |value|
      total_calls   = value[:runtimes].size
      total_runtime = value[:runtimes].map { |runtime| runtime[0] }.reduce(:+)
      average       = total_runtime / total_calls

      # sort using `runtimes` in DESC order
      runtimes = value[:runtimes].sort { |a, b| b[0] <=> a[0] }
      slowest = runtimes[0]
      fastest = runtimes[runtimes.size - 1]

      if slowest[0] > slowest_sql[:total_runtime]
        slowest_sql[:sql]           = value[:sql]
        slowest_sql[:total_runtime] = slowest[0]
        slowest_sql[:source]        = slowest[1]
      end

      profiled_sql_calls << {
                  sql: value[:sql],
             runtimes: runtimes,
          total_calls: total_calls,
        total_runtime: total_runtime,
              average: average,
                  min: fastest[0],
                  max: slowest[0]
      }

      if total_calls > mostly_called_sql[:total_calls]
        mostly_called_sql[:sql]           = value[:sql]
        mostly_called_sql[:runtimes]      = value[:runtimes]
        mostly_called_sql[:total_calls]   = total_calls
        mostly_called_sql[:total_runtime] = total_runtime
        mostly_called_sql[:average]       = average
        mostly_called_sql[:min]           = fastest[0]
        mostly_called_sql[:max]           = slowest[0]
      end
    end

    {
      profiled_sql_calls: profiled_sql_calls.sort { |a, b| b[:max] <=> a[:max] },
             total_sql_calls: profiled_sql_calls.map { |sql_call| sql_call[:total_calls] }.reduce(:+),
      total_unique_sql_calls: profiled_sql_calls.size,
                 slowest_sql: slowest_sql,
           mostly_called_sql: mostly_called_sql
    }
  end
end