diff --git a/Gemfile b/Gemfile index 52234d9c9..4a9699dd8 100644 --- a/Gemfile +++ b/Gemfile @@ -15,6 +15,7 @@ gem 'pg' # useful for debugging, even in prod gem 'pry-byebug' # Adds step-by-step debugging and stack navigation capabilities to pry using byebug gem 'pry-rails' # use pry as the rails console shell instead of IRB +gem 'ruby-prof' # to profile methods # Use Puma as the app server gem 'puma', '~> 3.7' gem 'rails', '~> 5.1.3' @@ -44,7 +45,6 @@ group :development do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' - gem 'ruby-prof' gem 'hirb' # for db table display via rails console end diff --git a/lib/audit/moab_to_catalog.rb b/lib/audit/moab_to_catalog.rb index ebd56d959..233914aaf 100644 --- a/lib/audit/moab_to_catalog.rb +++ b/lib/audit/moab_to_catalog.rb @@ -49,6 +49,12 @@ def seed_from_disk end end + def seed_from_disk_with_profiling + profiler = Profiler.new + profiler.prof { seed_from_disk } + profiler.print_results_flat('seed_from_disk') + end + # Shameless green. Code duplication with seed_from_disk def check_existence_from_disk Settings.moab.storage_roots.each do |storage_root| diff --git a/lib/profiler.rb b/lib/profiler.rb new file mode 100644 index 000000000..45bb37d15 --- /dev/null +++ b/lib/profiler.rb @@ -0,0 +1,23 @@ +# adapted from argo +# takes a block of code, starts the profiler, runs the code, then +# stops the profiler and returns the results of the profiling. +# example usage: +# profiler = Profiler.new +# profiler.prof { MoabToCatalog.seed_catalog(storage_dir) } +# profiler.print_results_flat(out_file_id) +class Profiler + + attr_accessor :results + + def prof + RubyProf.start + yield + @results = RubyProf.stop + end + + def print_results_flat(out_file_id) + File.open "log/#{out_file_id}#{Time.current.localtime.strftime('%FT%T')}-flat.txt", 'w' do |file| + RubyProf::FlatPrinterWithLineNumbers.new(@results).print(file) + end + end +end diff --git a/spec/lib/audit/moab_to_catalog_spec.rb b/spec/lib/audit/moab_to_catalog_spec.rb index f4fafffe5..61ef65dd8 100644 --- a/spec/lib/audit/moab_to_catalog_spec.rb +++ b/spec/lib/audit/moab_to_catalog_spec.rb @@ -41,6 +41,20 @@ end end + describe "#seed_from_disk_with_profiling" do + let(:m2c) { described_class.new } + + it "spins up a profiler, calling profiling and printing methods on it" do + mock_profiler = instance_double(Profiler) + + expect(Profiler).to receive(:new).and_return(mock_profiler) + expect(mock_profiler).to receive(:prof) + expect(mock_profiler).to receive(:print_results_flat) + + m2c.seed_from_disk_with_profiling + end + end + describe ".check_existence" do let(:subject) { described_class.check_existence(storage_dir, true) } diff --git a/spec/lib/profiler_spec.rb b/spec/lib/profiler_spec.rb new file mode 100644 index 000000000..8cf1accf1 --- /dev/null +++ b/spec/lib/profiler_spec.rb @@ -0,0 +1,34 @@ +require_relative '../../lib/profiler.rb' +require 'ruby-prof' + +RSpec.describe Profiler do + let(:profiler) { described_class.new } + + describe '#prof' do + it 'starts, yields, stops, and returns results' do + rp_profile = instance_double(RubyProf::Profile) + expect(RubyProf).to receive(:start) + expect(RubyProf).to receive(:stop).and_return(rp_profile) + test_value = false + profiler.prof { test_value = true } + expect(test_value).to be true + expect(profiler.results).to eq rp_profile + end + end + + describe '#print_results_flat' do + it 'returns the printer and prints to the path we pass in' do + printer = instance_double(RubyProf::FlatPrinterWithLineNumbers) + profiler.prof { 'we just want #prof to run' } + expected_filepath = "log/test#{Time.current.localtime.strftime('%FT%T')}-flat.txt" + expect(RubyProf::FlatPrinterWithLineNumbers).to receive(:new).with(profiler.results).and_return(printer) + expect(printer).to receive(:print) do |file| + # this expectation might need to relax + # if enough time lags between the timestamps + # in expected_filepath and the file name itself + expect(file.path).to eq expected_filepath + end + profiler.print_results_flat('test') + end + end +end