Cache compiled templates between requests #43

Merged
merged 8 commits into from Sep 5, 2014

Projects

None yet

2 participants

@MarkusHarmsen
Contributor

Story

I was wondering how the stache gem performs compared to the classical ERB rendering. When digging in the source, it seems that stache does not cache any compiled templates (via mustache) and is maybe therefore slower than expected.

Are there any reasons why the mustache caching has not been utilized?

For testing purposes, I've attached a simple commit which adds caching - the rspec test seem to be successful.

Setup

New clean Rails 4.1.5 application with two nearly identical controllers. One renders an erb-template, the other uses mustache + stache as engine. Thin was used as webserver in production mode and siege via siege http://localhost:3000/mustache -t1m to create load for one minute.

Layout

<!DOCTYPE html>
<html>
<head>
  <title>MustacheTest</title>
</head>
<body>
  ##Mustache#################
  <hr/>
  {{{yield}}}
</body>
</html>

The ERB template is analogue and therefore not shown here

View

hello world<br>

Results

1x "hello world" as seen in View

Engine Trans/sec Speed
Stache (1.0.3) 388 74 %
Stache (1.0.3 + Cache) 463 88 %
ERB 525 100 %

10000x "hello world"

Engine Trans/sec Speed
Stache (1.0.3) 118 33 %
Stache (1.0.3 + Cache) 310 87 %
ERB 357 100 %

1000x {{hello}}, where hello just returns "hello world"

Engine Trans/sec Speed
Stache (1.0.3) 7 5 %
Stache (1.0.3 + Cache) 98 64 %
ERB 153 100 %

Notes

  • A very small layout / view has been used, so that the performance boost might be even more on complex ones
  • This is only tested via the rspec tests, so no guarantee that this may be totally crap ;)
  • The second commit (b4ed8e7) contains some more attempts to speed up stache, here for the 10000x "hello world" stache reaches 367 trans/sec, which results in 103% speed compared to ERB.
  • The commit 7bdfc84 replaces the naive "hash-based-cache" with ActiveSupport::Cache::MemoryStore. This should a) threadsafe, b) could be easily replaced by other storage-types (like Memcached), c) has an upper memory bound and d) a lower memory footprint.
@MarkusHarmsen
Contributor

The commit a483263 adds caching for partials too. Here an interesting benchmark:
Same setup as above, but now the view looks as follows:

hello world<br>
{{>partial}}
hello world<br>
{{>partial}}
[... x 97]
hello world<br>
{{>partial}}

so that we render hello world and the partial partial 100 times (same for ERB).
The partial:

hello world partial<br>
hello world partial<br>
[... x 97]
hello world partial<br>

i.e. render hello world partial 100 times.

Results

Engine Trans/sec Speed
Stache (1.0.3) 21 30 %
Stache (a483263) 174 245 %
ERB 71 100 %

So with caching enabled for Stache (a483263), we are nearly 2.5 as fast as ERB in our artificial example.

@MarkusHarmsen
Contributor

I've already found one little drawback: if you enable cache in development, the templates will be cached too and do not reload automagically. A possible workaround could be applied to config/initializers/stache.rb:

Stache.configure do |c|
  c.template_cache = ActiveSupport::Cache::MemoryStore.new if Rails.env.production?
end
@hypomodern
Contributor

Markus, this is awesome!

I've been on vacation and look forward to reviewing this and getting it merged ASAP.

@hypomodern
Contributor

Looks really nice, Markus. I'm going to investigate whether or not this is something that can/should be done on the handlebars side of things as well. This will be v1.1, out later today!

@hypomodern hypomodern merged commit fb1f10e into agoragames:master Sep 5, 2014

1 check passed

continuous-integration/travis-ci The Travis CI build passed
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment