Profiling and benchmarking tools like perftools.rb, Benchmark, and ruby-prof can help optimize Ruby code by identifying slow parts. These tools sample programs to measure CPU time, memory usage, and other metrics. Benchmark allows basic timing comparisons, while profilers like perftools.rb and ruby-prof provide call graphs and other visualizations to pinpoint where to optimize. These techniques help focus optimization efforts on the most impactful areas.
6. 1. User CPU time
2. System CPU time
3. (1 + 2) i.e. User + System CPU time
4. Realtime
puts Benchmark.measure { 4000.times { |x| x**x } }
# => 0.890000 0.020000 0.910000 (0.909118)
7. 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)
8. Benchmark.bm(14) do |bm|
bm.report(“first header”) { first_algorithm }
bm.report(“second header”) { second_algorithm}
…..
end
#=> user system total real
first header 0.940000 0.010000 0.950000 (0.956572)
second header 0.430000 0.010000 0.440000 (0.423467)
10. 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}" }
end
end
.bmbm prevents result skewing
11. bmbm does rehearsal which includes any initialisation and GC run
then 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) |
12. 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") }
end
end
#=> 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) |
13. module Extendable
def name
@name
end
end
class Person
attr_accessor :name
end
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 }
end
end
16. perftools.rb
an adaptation of Google's perftools library to the Ruby land by Aman
Gupta
https://github.com/tmm1/perftools.rb
$gem install perftools.rb
17. does profiling via sampling method, where by default it takes
100 samples a second
19. to see results
Interpreting the above columns:
1. Number of profiling samples in this function
2. Percentage of profiling samples in this function
3. Percentage of profiling samples in the functions printed so far
4. Number of profiling samples in this function and its callees
5. Percentage of profiling samples in this function and its callees
6. 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_concat
Total: 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
20. to see results as graph
bigger the box, the more time spent there
1. Class Name
2. Method Name
3. local (percentage)
4. of cumulative (percentage)
brew install graphviz
$pprof.rb --gif --ignore=Gem /tmp/profiling/string_concat > /tmp/profiling/string_concat.gif
27. To use with Rails
Valid default_printer values are pdf, text, raw, gif, callgrind
# Gemfile
gem 'rack-perftools_profiler', :require => false
# config/environment.rb
config.middleware.use ::Rack::PerftoolsProfiler,
:default_printer => 'gif',
:bundler => true,
:mode => :cputime,
:frequency => 250
28. profile=true will enable profiling
times=10 will hit the page for 10 times
will 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"