Skip to content

Instantly share code, notes, and snippets.

@spikegrobstein
Last active December 18, 2015 02:09
Show Gist options
  • Save spikegrobstein/5709378 to your computer and use it in GitHub Desktop.
Save spikegrobstein/5709378 to your computer and use it in GitHub Desktop.
## Profiler
## A wrapper for the rblineprof library to pretty-print the profile data
## and enable customization of the output
## Based heavily on tmm1's examples
## This assumes that rblineprof lib is installed in Rails.root + 'vendor/rblineprof/ext'
## https://github.com/tmm1/rblineprof
class Profiler
# see docs for self.log_line method
@@logger = Proc.new { |line| Rails.logger.info line }
# see docs for self.format_line method
@@formatter = Proc.new { |file, profile_data, line, num|
wall, cpu, calls = profile_data
if calls && calls > 0
"((( % 8.1fms + % 8.1fms (% 5d) | %s" % [cpu/1000.0, (wall-cpu)/1000.0, calls, line]
else
"((( | %s" % [line]
end
}
# override the default logger for the profiler
# the block should accept an argument signature that matches Profiler.log_line, below.
def self.set_logger( &block )
@@logger = block
end
# override the default formatter
# the block should accept an argument signature that matches Profiler.format_line, below.
def self.set_formatter( &block )
@@formatter = block
end
# accessor for @@logger
def self.logger
@@logger
end
# accessor for @@formatter
def self.formatter
@@formatter
end
# log a line using the @@logger Proc.
# it should take the same method signature as this method
def self.log_line(line)
self.logger.call line
end
# format a given line to be passed to the logger
# file is the full filepath to the file in question
# profile data is an array of wall-time, cpu-time and number-of-calls as integers
# line is the line in question (actual line of code from the file)
# num is the line number
def self.format_line(file, profile_data, line, num)
@@formatter.call file, profile_data, line, num
end
# profile the provided block.
# regex is a regex for which files to include in the profile
# when full_trace is set to false, it will ignore anything inside ~/.rvm directory
# by default this will spit out a profile to the log, which is great when in development mode
def self.profile(regex=/./, full_trace=false, &block)
$:.unshift Rails.root + 'vendor/rblineprof/ext'
require 'rblineprof'
profile = lineprof(regex) do
block.call
end
profile.each do |file, p|
# skip over anything that's a gem:
next if !full_trace && file.match(/\/\.rvm\//) # anything in the .rvm directory
next if file.match(/^\(/) # anything that starts with a paren
# identify the file in the logger
self.log_line "\n/// #{ file } ===>>>"
# log each line from the file with profile data
File.readlines(file).each_with_index do |line, num|
self.log_line( self.format_line(file, profile[file][num+1], line, num) )
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment