Aaron Patterson (@tenderlove) switched over the attribute class feature of ActiveSupport to use define_method rather than class_eval [git commit]. In it, he cites that doing so would "drop memory consumption and (increase) startup speed..."
This is of particular noteworthiness because, actually, this particular feature started out life using define_method. And then circa 2009, Yehuda Katz specifically rewrote the code to use the class_eval style, noting that the class_eval was much easier to comprehend (agreed). When someone says, "Yehuda Katz", think, "smart and prolific" [github]. So, reverting this work was no small move.
Unfortunately, Mr. Patterson didn't leave a crumb as to what led him to the performance difference conclusion. So, I did a little digging. Turns out, this is something that Aaron learned around March of this year (i.e. 2013). And this is the main thing I want to direct your attention to: tenderlove's treatment of the topic:
http://tenderlovemaking.com/2013/03/03/dynamic_method_definitions.htmlIn it, Aaron carefully walks through, step by step, how to compare and detect the causes of the performance differences. Along the way, I was introduced to a number of very helpful tools:
- Benchmark module — makes it easy to get timings of different cases in one run. much more convenient that using the unix "time" command (and slightly more accurate since it doesn't include startup and shutdown operations).
(there's a section in The Ruby Toolbox specifically on Benchmarking, also noteworthy!) - DTrace — a powerful tracing tool, that runs scripts written in the D Language. Not a small diversion; the DTrace book is 1,000+ pages long(!).
- related article where tenderlove shows how he added a DTrace probe to MRI.
- The MRI Library extension to the ObjectSpace module — a set of advanced memory usage inspections features; complete with a warning "if you don't know what you're doing, don't do this."
In his examination, Aaron is not satisfied with the performance of method definition, but digs into the performance of the dynamically generated methods, themselves (who might have thunk they'd be that different?). Lots to learn from this:
- some mechanics of performance tuning in Ruby.
- how to write a high-signal blog post. (great code-to-prose ratio, did I mention that?)
- ways to contribute to Open Source in addition to cutting code: help others level up.
Thank you, @tenderlove!
My teeny tiny OSS contribution? I commented on Aaron's github commit with a link to his own blog post. :)