Measure and Benchmark Time for Ruby Methods
Solution 1
The simplest way:
require 'benchmark'
def foo
time = Benchmark.measure {
code to test
}
puts time.real #or save it to logs
end
Sample output:
2.2.3 :001 > foo
5.230000 0.020000 5.250000 ( 5.274806)
Values are: cpu time, system time, total and real elapsed time.
Source: ruby docs.
Solution 2
You could use the Time
object. (Time Docs)
For example,
start = Time.now
# => 2022-02-07 13:55:06.82975 +0100
# code to time
finish = Time.now
# => 2022-02-07 13:55:09.163182 +0100
diff = finish - start
# => 2.333432
diff
would be in seconds, as a floating point number.
Solution 3
Use Benchmark
's Report
require 'benchmark' # Might be necessary.
def foo
Benchmark.bm( 20 ) do |bm| # The 20 is the width of the first column in the output.
bm.report( "Access Database:" ) do
# Code to access database.
end
bm.report( "Access Redis:" ) do
# Code to access redis.
end
end
end
This will output something like the following:
user system total real
Access Database: 0.020000 0.000000 0.020000 ( 0.475375)
Access Redis: 0.000000 0.000000 0.000000 ( 0.000037)
<------ 20 -------> # This is where the 20 comes in. NOTE: This is not shown in output.
More information can be found here.
Solution 4
Many of the answers suggest the use of Time.now
. But it is worth being aware that Time.now
can change. System clocks can drift and might get corrected by the system's administrator or via NTP. It is therefore possible for Time.now to jump forward or back and give your benchmarking inaccurate results.
A better solution is to use the operating system's monotonic clock, which is always moving forward. Ruby 2.1 and above give access to this via:
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
# code to time
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
diff = finish - start # gets time is seconds as a float
You can read more details here. Also you can see popular Ruby project, Sidekiq, made the switch to monotonic clock.
Solution 5
A second thought, define the measure() function with Ruby code block argument can help simplify the time measure code:
def measure(&block)
start = Time.now
block.call
Time.now - start
end
# t1 and t2 is the executing time for the code blocks.
t1 = measure { sleep(1) }
t2 = measure do
sleep(2)
end
Related videos on Youtube
Phani
Updated on February 08, 2022Comments
-
Phani over 2 years
How can i measure the time taken by a method and the individual statements in that method in Ruby. If you see the below method i want to measure the total time taken by the method and the time taken for database access and redis access. I do not want to write Benchmark.measure before every statement. Does the ruby interpreter gives us any hooks for doing this ?
def foo # code to access database # code to access redis. end
-
reagan almost 12 yearsthere is something similar to the
new Date()
of javascript that ruby has, but I can't remember the correct syntax. should give you a decent google listing though -
Joshua Pinter almost 4 years@Phani Can you select a correct answer please? After 8 years, I think there are some solid answers here. Thanks.
-
-
Jason Kim almost 12 yearsjust a minor correction.
end
is reserved, so use some other variable name. -
jmccure almost 9 yearsYou can also do
Benchmark.realtime { block }
if you just want the realtime -
Joshua Pinter about 7 yearsI just came back to my own answer and was impressed (again) with how Benchmark handles this. Love Ruby.
-
Sandro L almost 6 yearsIn your definition you call it
benchmark
. When you use it it is calledmeasure
. Please fix this. -
thesecretmaster almost 6 yearsThis answer is a (slightly) different way to answer the question. Just because you could figure it out from @wquist's answer doesn't mean it isn't valid.
-
Patrick Brinich-Langlois about 5 years
Time.now
is affected by adjustments to the system clock, so it's a best practice to useProcess.clock_gettime(Process::CLOCK_MONOTONIC)
instead. But for rough calculations this doesn't matter. blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way -
Purplejacket about 5 yearsThis should be the preferred answer: Because, as of Ruby 2.2, the
Benchmark
class uses a monotonic clock, as discussed in other answers. See for instance the following source code, and look for "def measure" on line 286: github.com/ruby/ruby/blob/ruby_2_2/lib/benchmark.rb -
bbenno over 2 yearsOther units than seconds (ms, µs, ns, ...) are available, see core doc