Example 7. Performance

Let's look at Fortitude’s performance.

Real-World Benchmark

This is the time (in milliseconds) required to render a highly realistic, complex Rails view page, creating a total of about 380 KBytes of HTML. (This is a rather large page; by comparison, the entire front page of nytimes.com is, as of this writing, about 270KBytes.)

Engine Time (ms) vs. ERb Garbage (objects) vs. ERb
ERb 31.7 100% 41,000 100%
Slim 30.0 95% 31,000 76%
HAML 95.1 300% 191,000 467%
Erector 649.1 2,048% 241,000 588%
Fortitude 18.1 57% 22,000 55%

Fortitude is nearly twice as fast as ERb, and almost five times as fast as HAML. Fortitude is over half again as fast as Slim.

Further, Fortitude is the fastest general-purpose Rails templating engine available. (By general-purpose, we mean an engine that can include arbitrary logic in views. So-called logicless templating engines move a significant amount of the logic required to render views out of the view file itself, and thus do not consist of a true “apples-to-apples” comparison.)

Fortitude also generates only about half as much garbage as ERb, and less than one-eighth as much as HAML. Though often overlooked, every object created as garbage requires time to collect, and this is also a non-trivial contribution to most applications’ performance.

These results are for a large, complex benchmark, intended to accurately assess a templating engine's performance on a real-world Rails application. Next, let’s look at some microbenchmarks that measure various abstraction penalties — how much slower templating engines get when you use the features they provide to structure your view code better.

Microbenchmarks

Local Variable Passing
Engine Time (ms) vs. ERb Garbage (objects) vs. ERb
ERb 250 100% 500,000 100%
HAML 257 103% 601,000 120%
Slim 93 37% 200,000 40%
Erector 306 122% 864,000 173%
Fortitude 71 28% 100,000 20%
Partial Calls
Engine Time (ms) vs. ERb Garbage (objects) vs. ERb
ERb 287 100% 350,000 100%
HAML 338 118% 505,000 144%
Slim 350 122% 331,000 95%
Erector 52 18% 100,000 29%
Fortitude 23 8% 37,000 11%
HTML Escaping
Engine Time (ms) vs. ERb Garbage (objects) vs. ERb
ERb 57 100% 121,000 100%
HAML 50 88% 131,000 109%
Slim 34 60% 90,000 74%
Erector 55 96% 152,000 125%
Fortitude 5 9% 10,000 8%
Translation Helper
Engine Time (ms) vs. ERb Garbage (objects) vs. ERb
ERb 223 100% 350,000 100%
HAML 191 86% 310,000 89%
Slim 201 90% 310,000 89%
Erector 256 115% 410,000 117%
Fortitude 156 70% 280,000 80%

These are microbenchmarks, designed to carefully measure only one aspect of a templating engine’s performance. While they aren’t necessarily reflective of a templating engine’s overall performance on real-world code, they can be very useful in helping you understand what kinds of things are fast, and what kinds of things are slow, on a particular templating engine.

Briefly, these microbenchmarks measure:

  • Local Variable Passing: How expensive is it to pass local variables to views and partials, and then use them? This is particularly useful because, as in all programming, the use of local variables (as opposed to view-@global variables) is key to encapsulating code properly, which leads to reliability and maintainability.
  • Partial Calls: How expensive is it to extract part of a view as a partial — either for structural or looping reasons — and call it that way? This is obviously a very important part of being able to quickly render well-factored view code.
  • HTML Escaping: All user input needs to be HTML-escaped before sending it to the client, lest your application fall prey to XSS attacks. The speed at which a templating engine can do this is therefore significant, and plays a bigger and bigger role the more user-generated data you have.
  • Translation Helper: This measures the speed at which a view can call Rails’ built-in #t helper, which is used extensively in any internationalized Rails application. For such applications, its speed is key. (Note that the #t helperis actually fairly slow itself, compared to the speed of view code; this causes differences among rendering engines to seem smaller on this test than they are on the other view microbenchmarks.)

As you can see from Fortitude’s results, not only is it a very-high-performance templating engine across the board, but it’s particularly strong in areas of abstraction — the very features, like breaking views into partials and passing local variables, that allow you to best build very well-factored view code. Compared to ERb, it’s over ten times as fast at invoking a partial, and generates almost a tenth as much garbage. Over a large application’s codebase, this can make a very significant difference in how fast your users see pages rendered to them — which is what really matters.

The Fortitude Benchmark Suite

All of the benchmarks above are brand-new — they were developed in conjunction with Fortitude. (They are, of course, all available as open source in the rails_view_benchmarks GitHub repository.)

Why develop a new benchmark suite? When we started development of Fortitude, the goal was to use an existing set of benchmarks for views — after all, using something the community was familiar with is generally better.

However, it immediately became apparent that all of the existing benchmarks for Ruby or Rails templating engines were so small as to be unrealistic. They typically rendered very small amounts of HTML, in a single view, while interpolating minimal user data. Now, if your application consists entirely of single-file views with very small amounts of HTML and minimal user data, those are accurate benchmarks — but, then, if that’s the kind of application you have, view performance probably is pretty irrelevant to you in the first place.

Instead, we developed rails_view_benchmarks, with particular attention given to the real-world benchmark called place_page whose results are listed at the top of this page.

How different is this from previous view benchmarks? How real-world is it? We’ll once again let the numbers tell the tale:

Slim Benchmark Crowd Interactive Comparison Steve Iannopollo’s Benchmark Place Page
View Files 1 1 1 34
Lines of Code 23 7 55 915
Bytes of HTML Generated < 300 < 300 2,600 380,000

In fact, this place_page benchmark is reverse-engineered from a real-world, large-scale Rails application (that renders that same view hundreds of thousands of times a day), and it‘s by far the largest and most realistic view benchmark available for Ruby or Rails now. It reflects the performance of a non-trivial, real application much, much better than any previous benchmark.

Does View Performance Matter?

It’s completely fair to ask: does this stuff matter? And, of course, the answer is: it depends.

If you have an application that uniformly renders simple views with very little HTML in them, then, no, view performance probably doesn’t matter a great deal to you — and neither does all of the wonderful factoring of view code that you can do with Fortitude. You certainly can still use it and may enjoy it, but its real advantages aren’t nearly so big in such a situation. On the other hand, applications that are this way and stay this way, even if they’re successful, are pretty rare, outside of API clients rendering JSON and other such microservices.

If, on the other hand, you have an application with significant amounts of view code in it, or one that renders any non-trivial amount of HTML to the user, then, yes, view performance absolutely matters. It’s a cost that users have to pay on every single page they view, no matter what. And the choice of templating engine in particular is important because:

  • It’s very difficult to optimize: If your database is slowing down a critical part of your application, you’ll typically find a very small number — often just one or two — queries are the real bottleneck. Optimize them, and things are suddenly fast again. But a slow templating engine is more akin to a slow database driver: it costs you speed not in one single place, but spread out all over your application, and that’s really, really hard to optimize.
  • Once you choose, you’re stuck with it: Views often consist of a very large number of lines of code. They start growing from the beginning of your application, and effectively never stop. By the time you’re concerned about performance, you may have tens or hundreds of thousands of lines of view code. At this point, switching to a new templating engine is somewhere between extremely difficult and impossible. (Yes, there are automated tools available, but they’re invariably imperfect and require human attention to each converted file anyway.)

In the end, performance of a templating engine is one of those mundane things you never really think much about until you’re running at serious scale — and suddenly this tax that you pay on every single page hit starts to be significant. With Fortitude, you don’t have to worry: it’s the single fastest choice you can make for any Ruby or Rails application’s view layer.

You should choose Fortitude for its incredibly powerful code-factoring tools — but it’s good to know that it’s also extraordinarily fast, too.