profiling ruby
TRANSCRIPT
![Page 1: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/1.jpg)
Profiling RubyWhere and what to optimize in your code
/
Nasir Jamal work@HouseTrip
@_nasj
![Page 2: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/2.jpg)
profiling helps you to narrow down towhere optimization would be most useful
![Page 3: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/3.jpg)
benchmarking allows you to easily isolateoptimizations and cross-compare them
![Page 4: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/4.jpg)
Benchmarking
![Page 5: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/5.jpg)
Realtime
puts Benchmark.realtime { 4000.times { |x| x**x } }
#=> 0.905972957611084
![Page 6: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/6.jpg)
1. User CPU time2. System CPU time3. (1 + 2) i.e. User + System CPU time4. Realtime
puts Benchmark.measure { 4000.times { |x| x**x } }
# => 0.890000 0.020000 0.910000 (0.909118)
![Page 7: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/7.jpg)
Benchmark.bm do |bm| bm.report { first_algorithm } bm.report { second_algorithm} …..end
#=> user system total real 0.940000 0.010000 0.950000 ( 0.956572) 0.430000 0.010000 0.440000 ( 0.423467)
![Page 8: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/8.jpg)
Benchmark.bm(14) do |bm| bm.report(“first header”) { first_algorithm } bm.report(“second header”) { second_algorithm} …..end
#=> user system total realfirst header 0.940000 0.010000 0.950000 (0.956572)second header 0.430000 0.010000 0.440000 (0.423467)
![Page 9: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/9.jpg)
examples ...
![Page 10: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/10.jpg)
Benchmark.bmbm(20) do |bm| bm.report('append') do str1, str2, str3, str4 = 'string1', 'string2', 'string3', 'string4' 1_000_000.times { y = str1 << str2 << str3 << str4 } end
bm.report('concat') do str1, str2, str3, str4 = 'string1', 'string2', 'string3', 'string4' 1_000_000.times { y = str1 + str2 + str3 + str4 } end
bm.report('interpolate') do str1, str2, str3, str4 = 'string1', 'string2', 'string3', 'string4' 1_000_000.times { y = "#{str1}#{str2}#{str3}#{str4}" } end
bm.report('interpolate one') do str1, str2, str3, str4 = 'string1', 'string2', 'string3', 'string4' 1_000_000.times { y = "string1string2string3#{str4}" } endend
.bmbm prevents result skewing
![Page 11: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/11.jpg)
bmbm does rehearsal which includes any initialisation and GC runthen it does the real benchmark
#=> Rehearsal ---------------------------------------------append 0.280000 0.000000 0.280000 ( 0.294505)concat 0.470000 0.020000 0.490000 ( 0.481748)interpolate 0.430000 0.010000 0.440000 ( 0.433404)interpolate one 0.320000 0.000000 0.320000 ( 0.323479)--------------------------------------- total: 1.530000sec
| Tests | user | system | total | real ||:---------------|:--------:|:--------:|:---------:|-----------:||append | 0.260000 | 0.010000 | 0.270000 | (0.265732) ||concat | 0.400000 | 0.010000 | 0.410000 | (0.396115) ||interpolate | 0.400000 | 0.000000 | 0.400000 | (0.408096) ||interpolate one | 0.280000 | 0.010000 | 0.290000 | (0.286443) |
![Page 12: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/12.jpg)
Benchmark.bmbm(20) do |bm| bm.report('gsub') do 1_0_000.times { Date.today.to_s.gsub!('-','') } end bm.report('strftime') do 1_0_000.times { Date.today.strftime("%Y%m%d") } endend
#=> Rehearsal -------------------------------------------gsub 0.750000 0.000000 0.750000 ( 0.751547)strftime 1.320000 0.000000 1.320000 ( 1.320621)------------------------------------ total: 2.070000sec
| | user | system | total | real ||:--------|:--------:|:---------:|:--------:|:-----------||gsub | 0.710000 | 0.000000 | 0.710000 | (0.709918) ||strftime | 1.320000 | 0.000000 | 1.320000 | (1.315345) |
![Page 13: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/13.jpg)
module Extendable def name @name endend
class Person attr_accessor :nameend
require 'ostruct'Benchmark.bmbm(20) do |bm| bm.report('Class') do 1_00_000.times { p = Person.new; p.name='Joe'; p.name } end bm.report('Extends') do 1_00_000.times { p = Person1.new; p.extend Extendable; p.name='Joe'; p.name } end bm.report('Struct') do 1_00_000.times { person2 = Struct.new(:name); p = person2.new('Joe'); p.name } end bm.report('OpenStruct') do 1_00_000.times { p = OpenStruct.new(:name => 'Joe'); p.name } endend
![Page 14: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/14.jpg)
#=> Rehearsal ---------------------------------------------Class 0.080000 0.000000 0.080000 (0.086261)Extends 0.410000 0.000000 0.410000 (0.407723)Struct 1.490000 0.000000 1.490000 (1.490557)OpenStruct 1.980000 0.010000 1.990000 (1.990507)------------------------------------ total: 3.970000sec
| | user | system | total | real ||:----------|:--------:|:--------:|:---------:|:-----------||Class | 0.080000 | 0.000000 | 0.080000 | (0.082448) ||Extends | 0.400000 | 0.000000 | 0.400000 | (0.410884) ||Struct | 1.480000 | 0.000000 | 1.480000 | (1.490531) ||OpenStruct | 1.960000 | 0.010000 | 1.970000 | (1.965923) |
![Page 15: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/15.jpg)
Profiling
![Page 16: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/16.jpg)
perftools.rban adaptation of Google's perftools library to the Ruby land by Aman
Guptahttps://github.com/tmm1/perftools.rb
$gem install perftools.rb
![Page 17: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/17.jpg)
does profiling via sampling method, where by default it takes100 samples a second
![Page 18: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/18.jpg)
examples ...
![Page 19: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/19.jpg)
to see results
Interpreting the above columns:
1. Number of profiling samples in this function2. Percentage of profiling samples in this function3. Percentage of profiling samples in the functions printed so far4. Number of profiling samples in this function and its callees5. Percentage of profiling samples in this function and its callees6. Function name
a = ''PerfTools::CpuProfiler.start("/tmp/profiling/string_concat") do 100_000.times {|x| a += x.to_s}end
$pprof.rb --text --ignore=Gem /tmp/profiling/string_concatTotal: 2939 samples 1497 50.9% 50.9% 1501 51.1% Object#irb_binding 1438 48.9% 99.9% 1438 48.9% garbage_collector 4 0.1% 100.0% 1500 51.0% Integer#times
![Page 20: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/20.jpg)
to see results as graph
bigger the box, the more time spent there
1. Class Name2. Method Name3. local (percentage)4. of cumulative (percentage)
brew install graphviz$pprof.rb --gif --ignore=Gem /tmp/profiling/string_concat > /tmp/profiling/string_concat.gif
![Page 21: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/21.jpg)
slightly hairy method
And on on ....
PerfTools::CpuProfiler.start("/tmp/profiling/property_search") do 100.times { PropertySearch.new.search }end
$pprof.rb --text --ignore=Gem /tmp/profiling/property_search
Total: 6799 samples 2598 38.2% 38.2% 2598 38.2% garbage_collector 1761 25.9% 64.1% 3966 58.3% PropertySearch#set_price_filter_counts 390 5.7% 69.8% 1632 24.0% Object#detect 389 5.7% 75.6% 503 7.4% PropertySearch::PriceRange#contains? 358 5.3% 80.8% 358 5.3% Mysql2::Result#each 263 3.9% 84.7% 768 11.3% Object#select_values 199 2.9% 87.6% 236 3.5% ActiveRecord::ConnectionAdapters::Mysql2Adapter#execute 187 2.8% 90.4% 640 9.4% Property.collect_column 148 2.2% 92.6% 148 2.2% ActiveSupport::BufferedLogger#flush 114 1.7% 94.2% 114 1.7% Fixnum#<= 75 1.1% 95.3% 75 1.1% Array#join 67 1.0% 96.3% 76 1.1% Array#map 47 0.7% 97.0% 47 0.7% ActiveRecord::ConnectionAdapters::Column#type_cast 44 0.6% 97.7% 295 4.3% Array#collect 32 0.5% 98.1% 388 5.7% Object#to_a 28 0.4% 98.5% 28 0.4% PropertySearch#day_count 15 0.2% 98.8% 140 2.1% ActiveRecord::ConnectionAdapters::Mysql2Adapter#select 9 0.1% 98.9% 4199 61.8% PropertySearch#search
![Page 22: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/22.jpg)
![Page 23: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/23.jpg)
$pprof.rb --help
![Page 24: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/24.jpg)
QcachegrindHow to setup?
http://langui.sh/2011/06/16/how-to-install-qcachegrind-
kcachegrind-on-mac-osx-snow-leopard/
![Page 25: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/25.jpg)
$pprof.rb --callgrind /tmp/profiling/property_search > /tmp/profiling/property_search.callgrind
![Page 26: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/26.jpg)
graph
![Page 27: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/27.jpg)
To use with Rails
Valid default_printer values are pdf, text, raw, gif, callgrind
# Gemfilegem 'rack-perftools_profiler', :require => false
# config/environment.rbconfig.middleware.use ::Rack::PerftoolsProfiler, :default_printer => 'gif', :bundler => true, :mode => :cputime, :frequency => 250
![Page 28: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/28.jpg)
profile=true will enable profilingtimes=10 will hit the page for 10 timeswill store the results in profile_ppp_page.txt
RACK_PROFILER=true script/server
curl -o profile_ppp_page.txt \"http://localhost:3000/en/rentals/107605?profile=true×=10"
![Page 29: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/29.jpg)
![Page 30: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/30.jpg)
ruby-prof
OR
$gem install ruby-prof
#Gemfile gem 'ruby-prof', :require => false
![Page 31: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/31.jpg)
types of measuresRubyProf.measure_mode = RubyProf::PROCESS_TIMERubyProf.measure_mode = RubyProf::WALL_TIMERubyProf.measure_mode = RubyProf::CPU_TIMERubyProf.measure_mode = RubyProf::ALLOCATIONSRubyProf.measure_mode = RubyProf::MEMORYRubyProf.measure_mode = RubyProf::GC_RUNSRubyProf.measure_mode = RubyProf::GC_TIME
![Page 32: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/32.jpg)
types of printersRubyProf::FlatPrinterRubyProf::FlatPrinterWithLineNumbersRubyProf::GraphPrinterRubyProf::GraphHtmlPrinterRubyProf::CallTreePrinterRubyProf::CallStackPrinterRubyProf::MultiPrinter
![Page 33: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/33.jpg)
examples ...
![Page 34: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/34.jpg)
GraphHtmlPrinterresult = RubyProf.profile { PropertySearch.new.search }
printer = RubyProf::GraphHtmlPrinter.new(result)
File.open("tmp/profile_data.html", 'w') { |file| printer.print(file)}
![Page 35: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/35.jpg)
profile_data.html
![Page 36: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/36.jpg)
CallStackPrinterresult = RubyProf.profile { PropertySearch.new.search }
printer = RubyProf::CallStackPrinter.new(result)
File.open("tmp/profile_data.html", 'w') { |file| printer.print(file)}
![Page 37: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/37.jpg)
profile_data.html
![Page 38: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/38.jpg)
CallTreePrinterresult = RubyProf.profile { PropertySearch.new.search }
printer = RubyProf::CallTreePrinter.new(result)
File.open("tmp/profile_data", 'w') { |file| printer.print(file)}
![Page 39: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/39.jpg)
profile_data (qcachegrind)
![Page 40: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/40.jpg)
In Rails2.x.x
3.x.x
Or just use rake tasks
script/performance/benchmarker 10 'Class.method_name' 'AnotherClass.method_name'
script/performance/profiler 'Class.method_name' 10 graph
script/performance/profiler 'Class.method_name' 10 graph_html 2> property.html && open property.html
rails benchmarker 'Class.method_name'
rails profiler 'Class.method_name' --runs 3 --metrics cpu_time,memory
rake test:benchmarkrake test:profile
rake test:profile TEST=test/performance/home_page_test.rb
![Page 41: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/41.jpg)
But from Rails 4.0performance tests are no longer part of the default
stackhttps://github.com/rails/rails-perftest
![Page 42: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/42.jpg)
Questions?
![Page 43: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/43.jpg)
[email protected] are hiring
![Page 44: Profiling ruby](https://reader034.vdocuments.mx/reader034/viewer/2022052321/554f64dbb4c905c8088b4cc0/html5/thumbnails/44.jpg)
Thank you