Since I'm doing some time measurements at the moment, I wondered if it is possible to measure the user time or system time without using the Benchmark
class or the command line utility time
.
Using the Time
class only reveals the wall clock time, not system and user time, however I'm looking for a solution which has the same flexibility, e.g.
time = TimeUtility.now
# some code
user, system, real = TimeUtility.now - time
The reason is that I somehow dislike Benchmark
, since it ca开发者_Python百科nnot return numbers only (EDIT: I was wrong - it can. See answers below.). Sure, I could parse the output, but that doesn't feels right. The time
utility from *NIX systems should solve my problem as well, but I wanted to know if there already is some kind of wrapper implemented in Ruby so I don't need to make these system calls by myself.
Thanks a lot!
I re-read the Benchmark documentation and saw that it has a method named measure
. This method does exactly what I want: Measure the time your code needs and returning an object which contains user time, system time, system time of childrens etc. It is as easy as
require 'benchmark'
measurement = Benchmark.measure do
# your code goes here
end
In the process I found out that you can add custom rows to the Benchmark output. You can use this to get the best of both worlds (custom time measurements and a nice output at the end) as follows:
require 'benchmark'
measurements = []
10.times { measurements << Benchmark.measure { 1_000_000.times { a = "1" } } }
# measurements.sum or measurements.inject(0){...} does not work, since the
# array contains Benchmark instances, which cannot be coerced into Fixnum's
# Array#sum will work if you are using Rails
sum = measurements.inject(nil) { |sum, t| sum.nil? ? sum = t : sum += t }
avg = sum / measurements.size
# 7 is the width reserved for the description "sum:" and "avg:"
Benchmark.bm(7, "sum:", "avg:") do |b|
[sum, avg]
end
The result will look like the following:
user system total real
sum: 2.700000 0.000000 2.700000 ( 2.706234)
avg: 0.270000 0.000000 0.270000 ( 0.270623)
You could use the Process::times
function, which returns user time/system time. (It does not report wall clock time, you'll need something else for that). Seems to be a bit version or OS dependent though.
This is what it reports on my system (linux, ruby 1.8.7):
$ irb
irb(main):001:0> t = Process.times
=> #<struct Struct::Tms utime=0.01, stime=0.0, cutime=0.0, cstime=0.0>
The docs show this though, so some versions/implementations might only have the first two:
t = Process.times
[ t.utime, t.stime ] #=> [0.0, 0.02]
See times
for the underlying call on Linux.
Here's a really crappy wrapper that kind of supports -
:
class SysTimes
attr_accessor :user, :system
def initialize
times = Process.times
@user = times.utime
@system = times.stime
end
def -(other)
diff = SysTimes.new
diff.user = @user - other.user
diff.system = @system - other.system
diff
end
end
Should give you ideas to make it work nicely in your context.
This gem might help: https://github.com/igorkasyanchuk/benchmark_methods
No more code like this:
t = Time.now
user.calculate_report
puts Time.now - t
Now you can do:
benchmark :calculate_report # in class
And just call your method
user.calculate_report
精彩评论