开发者

Measure user time or system time in Ruby without Benchmark or time

开发者 https://www.devze.com 2023-03-13 10:00 出处:网络
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.

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
0

精彩评论

暂无评论...
验证码 换一张
取 消