Speeding up Ruby-GetText November 3rd
While I’ve been previously singing praises about Ruby-GetText versions beyond 1.1, we’ve recently seen a severe problem with it: Speed.
Past version 1.4.0 (released in April of 2006), speed was miserable, to say the least. At version 1.8.0 (which already came with a 1.5 times speed increase when compared to 1.7.0), the following simple script was used to perform a speed comparison against the known good (read: fast) version 1.4.0.
require 'gettext'
include GetText
bindtextdomain("hello", "locale")
(1..100000).each do |it|
str = _("Hello World #{it}")
end
The same script that took 76 seconds to run with version 1.4.0 took a whopping 335 seconds with version 1.8.0.
Using Ruby Profiler to look inside at what actually took its sweet time there we found that GetText#bound_targets was the method that had a share of 25% of the execution time. This method deals with class ancestry of the class that you call the _() method in. And it does so with every invocation of _(). It also shoots calls out to various non-trivial each loops and eval calls.
What we did then was patch the Ruby-GetText code to cache the result of the GetText#bound_targets call, like so:
module GetText
@@__bound_targets = {}
alias :uncached_bound_targets :bound_targets
def bound_targets(klass)
@@__bound_targets[klass] ||= uncached_bound_targets(klass)
end
end
After this patch, the test script above ran in 70 seconds, which is even a few seconds quicker than version 1.4.0.
This override is stored in a separate file in the lib/ sub-directory and included from environment.rb.
require_gem 'gettext'
require 'gettext/rails'
require 'gettext_optimizer'
Since especially in the production environment, nothing in the class ancestry should change, this patch should not yield any surprises. We’ve had this code in production for 6 weeks now.

0 comments
Jump to comment form