Skip to content

Instantly share code, notes, and snippets.

@palkan
Last active March 21, 2024 00:29
Show Gist options
  • Star 28 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save palkan/73395cc201a565ecd3ff61aac44ad5ae to your computer and use it in GitHub Desktop.
Save palkan/73395cc201a565ecd3ff61aac44ad5ae to your computer and use it in GitHub Desktop.
RSpec profiling with RubyProf and StackProf

Profile your specs

Instructions

  • Ensure that you have required gems ('ruby-prof' >= 0.16, 'stackprof')

  • Require spec_profiling.rb in your spec_helper.rb (or whereever you like)

  • To profile the whole suite run:

# Profile with ruby-prof
RUBYPROF=1 rspec ...

# Profile with stackprof
STACKPROF=1 rspec ...
  • To profile a separate example mark it with the corresponding tag:
# Profile with StackProf
it "is too slow", :sprof do
 ...
end

# Profile with RubyProf
it "is too slow", :rprof do
  ...
end
gem 'stackprof', require: false
gem 'ruby-prof', require: false
module SpecProfiling
class << self
def init
ruby_prof if ENV['RUBYPROF']
stack_prof if ENV['STACKPROF']
end
def ruby_prof
require 'ruby-prof'
$stdout.puts "RubyProf enabled"
profiler = RubyProf::Profile.new(
merge_fibers: true,
include_threads: [Thread.current]
)
profiler.start
at_exit do
result = profiler.stop
# Common RSpec methods
result.eliminate_methods!(
[
/instance_exec/,
/Example(Group)?>?#run(_examples)?/,
/Procsy/,
/AroundHook#execute_with/,
/HookCollections/,
/Array#(map|each)/
]
)
printer_type = ENV['RPRINTER'] || 'call_stack'
printer = "RubyProf::#{printer_type.camelize}Printer".constantize
path = Rails.root.join("tmp", "ruby-prof-report-#{printer_type}-#{RubyProf.measure_mode}-total.html")
File.open(path.to_s, 'w') { |f| printer.new(result).print(f, min_percent: 1) }
end
end
def stack_prof
require 'stackprof'
mode = ENV['RMODE'] || 'wall'
$stdout.puts "StackProf enabled (mode: #{mode})"
path = Rails.root.join("tmp", "stackprof-#{mode}-test-total.dump")
# we use raw to make it possible to generate flamegraphs
StackProf.start(mode: mode.to_sym, raw: true)
at_exit do
StackProf.stop
StackProf.results path.to_s
end
end
end
end
RSpec.configure do |config|
config.around(:each, :sprof) do |ex|
require 'stackprof'
mode = ENV['RMODE'] || 'wall'
path = Rails.root.join("tmp", "stackprof-#{mode}-test-#{ex.full_description.parameterize}.dump")
StackProf.run(mode: mode, out: path.to_s, raw: true) do
ex.run
end
end
config.around(:each, :rprof) do |ex|
require 'ruby-prof'
result = RubyProf.profile { ex.run }
printer_type = ENV['RPRINTER'] || 'call_stack'
printer = "RubyProf::#{printer_type.camelize}Printer".constantize
path = Rails.root.join("tmp", "ruby-prof-report-#{printer_type}-#{RubyProf.measure_mode}-#{ex.full_description.parameterize}.html")
File.open(path.to_s, 'w') { |f| printer.new(result).print(f, min_percent: 1) }
end
end
SpecProfiling.init
@matkoniecz
Copy link

matkoniecz commented May 28, 2017

See https://choosealicense.com/ for tl;dr

Please, please add a license. The fact none is listed makes using this software a legal quagmire. Currently it is not legal to use this code or its derivatives in any useful software. I may be mistaken but hopefully this is not the intended effect.

Currently no license is mentioned anywhere, what makes this code fully copyrighted, like any other creative work.

It limits usefulness of this project - and I hope that it is unintentional. For example it seems that it would solve my problem of profiling hilariously slow rspec tests (2036.33 seconds ./spec/word_processor_spec.rb:43), in current situation I would be unable to legally publish project that would use this solution.

Obviously, please do not release it under any license if you are not the author (that would be even worse legal quagmire)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment