Issue #5809 has been updated by mame (Yusuke Endoh).

Status changed from Open to Assigned
Assignee set to naruse (Yui NARUSE)

Naruse-san, what does this ticket need?  A better new name?
Could you please create a patch?

-- 
Yusuke Endoh <mame / tsg.ne.jp>
----------------------------------------
Feature #5809: Benchmark#bm: remove the label_width parameter
https://bugs.ruby-lang.org/issues/5809#change-25310

Author: Eregon (Benoit Daloze)
Status: Assigned
Priority: Normal
Assignee: naruse (Yui NARUSE)
Category: lib
Target version: 


Hello,

I would like to keep on improving the benchmark library.
Feature #4197 was mostly a clean-up, this intend to improve the existing methods.

First, I would like to make Benchmark#bm smarter.
I think than having to specify the maximum width of the labels as an argument is not natural, and probably not the best API.
An easy way to calculate the maximum width is to store all blocks and labels and run them after the #bm block is yielded.
That's the way #bmbm does it (although some people don't know #bmbm can calculate the width itself).
It would also avoid the duplication between the Report and Job classes, and make #bm more consistent with #bmbm.

There is however a good reason it is not done this way:
It lets #report return immediately the Benchmark::Tms, which can then be assigned to a variable, and be used to easily display the total, average, etc:

Benchmark.bm(7, ">total:", ">avg:") do |x|
  tf = x.report("for:")   { for i in 1..n; a = "1"; end }
  tt = x.report("times:") { n.times do   ; a = "1"; end }
 [tf+tt, (tf+tt)/3]
end
# =>
             user     system      total        real
for:     0.000000   0.000000   0.000000 (  0.000054)
times:   0.000000   0.000000   0.000000 (  0.000027)
>total:  0.000000   0.000000   0.000000 (  0.000081)
>avg:    0.000000   0.000000   0.000000 (  0.000027)

I am not sure this is worth having to give the width.
I think this feature is very rarely used (I actually never saw a code using it, except the code in the documentation). Please show me if I'm wrong.

There are some workarounds.

First, I made Benchmark#benchmark returns the times of the #reports (an Array of Tms).
One can then easily store the results of #bm and print them (however it will not indent them automatically, but that could be fixed).

tf,tt = Benchmark.bm { ... }
puts ">total: #{(tf+tt)}"
puts ">avg:  #{(tf+tt)/3}"

Second, it is actually possible to support the same feature, even when the #report blocks are executed after.
This is done by creating "delay-able"/lazy objects, which remember the calls, and make the real calls by calling #compute on them.
Benchmark#benchmark could then execute them when the #bm block is yielded, and it would be transparent to the user (except if he prints the result of #report inside the #bm block).

The second is not small to implement, and might not belong to the benchmark library, but could be useful in general. It also adds some significant complexity.

What do you think?



-- 
http://bugs.ruby-lang.org/