152 | Chapter 6: Performance
else super
end
end
end
t = Test.new
Benchmark.bmbm do |b|
b.report("Direct method call") do
1_000_000.times { t.test_one }
end
b.report("method_missing") do
1_000_000.times { t.test_unknown }
end
end
Note what we are not testing: we are not comparing the raw speed of ordinary
method dispatch versus a bare call tomethod_missing. We are comparing an ordi-
nary method call to the standard Ruby practice of usingmethod_missingto answer for
one method name. This gives us answers that are more relevant to our question:
“How much willmethod_missing hurt me in this particular piece of code?”
We use theBenchmark.bmbmmethod, which runs the entire benchmark suite once (the
“rehearsal”) to minimize startup costs and give the measured code a “warm start.”
To get the most accurate numbers possible, each trial runs one million method calls.
The Benchmark library starts garbage collection before each run, because garbage
collection during the measured run would alter the results. Here is the output of that
benchmark on my computer:
Rehearsal ------------------------------------------------------
Direct method call 0.350000 0.000000 0.350000 ( 0.352929)
method_missing 0.480000 0.000000 0.480000 ( 0.476009)
--------------------------------------------- total: 0.830000sec
user system total real
Direct method call 0.320000 0.000000 0.320000 ( 0.324030)
method_missing 0.480000 0.000000 0.480000 ( 0.477420)
The rehearsal numbers come first, followed by the actual measurement. We can see
that under this environment, the average cost of a normal method call is 320 nano-
seconds (0.32 seconds per million calls), while amethod_missingcall andcasestate-
ment take 480 nanoseconds. Modulo the accuracy of our measurement, this is a 50%
performance penalty for using method_missing. Balanced against the additional
power we get frommethod_missing, this certainly seems to be a good trade.
Benchmark is a powerful tool, but it can quickly amount to guesswork and black
magic. There is no use optimizing method dispatch unless it is a bottleneck.*
- Here’s a hint: at more than two million method calls per second, method dispatch is probably not your
bottleneck.