Skip to content
This repository has been archived by the owner on Mar 23, 2018. It is now read-only.

skaes/routing_optimizations

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Routing optimization monkey patches for rails 2.1 and 2.2

Overview

The Rails routing module is mainly responsible for

  • parsing urls to turn them into (controller, action, parameter hash) tuples

  • generating urls from (controller, action, parameter hash) tuples

  • generating helper methods for

    • generating hashes for named routes (given additional parameters)

    • generating urls for named routes (given additional parameters)

Ever since Rails started to support routing specifications written in Ruby, both functionality and implementation become more complex with almost each new release. And the routing code wasn’t fast to boot, for sure.

Both Rails 2.1 and Rails 2.2 try to make routing faster by generating code specific to each route at runtime. This results in a speed increase for each individual routing related operation, but inflates the total code size of an application. As a consequence, garbage collection time of a MRI Ruby can be catapulted well above 100ms (this isn’t as much of a problem for jruby, as it uses a much better garbage collection algorithm, but I haven’t had a chance to try it so far).

This plugin improves the situation by generating code only for named routes helpers which are actually used by the application and making the generated code more compact.

Requirements

  • Ruby

  • Rails 2.1 or Rails 2.2

Installation

Install the plugin in the plugin directory of your rails application using one of the well known methods.

Usage

Rails routing will be optimized automatically once the plugin has been installed. There is no API and there are no configuration options.

Well, that’s actually a lie. You can set an environment variable

RAILS_DEBUG_ROUTING_CODE=1

and then the plugin will write all routing related generated code to two files under /tmp:

  • generated_routing_code.rb (code generated for recognition and generation)

  • named_route_helpers_code.rb (code generated for named routes helpers)

Performance

The plugin optimizes the Rails’ routing subsystem in 2 ways:

  • Named route helpers will be generated lazily upon first use. After a helper has been generated, there is no further performance penalty for using it.

  • The generated code is more compact than the code generated by Rails (with negligible performance impact on an individual call).

Both changes aim at reducing the number of live objects after garbage collection. For MRI Ruby, this is important as it uses a simple mark and sweep garbage collector, the performance of which degrades linearly with heap size.

For a complex Rails application with a large number of named route definitions, especially whith restful routing, the reduction in heap size can be enormous. For example, I have measured one application, were 600,000 out of 1,600,000 AST nodes were eliminated by the plugin and garbage collection time was reduced by almost a factor of 2.

Measuring the effectiveness of the plugin

The best way to measure the effects the plugin on your application is to use either bleak_house or a Ruby patched with my garbage collection patches. I do, of course, recommend the second option ;-)

Installing a patched Ruby with support for creating heap dumps

Get the patched Ruby from railsexpress.de/downloads/ruby186pl287.tar.gz

Unpack, cd into it and execute

autoconf
configure --enable-gcdebug --prefix=<some directory>
make
sudo make install

add <some directory>/bin at the beginning of PATH and install all the gems you need.

Congratulations! You now have an additional version of Ruby on your system, with support for creating heap dumps from a running application. It will use somewhat more memory than a Ruby compiled without heap dump support.

Creating heap dumps

You can obtain a heap dump by calling

# clean up heap
GC.start
# clean up potential garbage from running finalizers
GC.start
# dump it, including class names of heap objects
GC.dump_file_and_line_info(filename="heap.dump", include_class_names=true)

The resulting dump can then be analyzed using railsbench’s new analyze_heap_dump command (get the bleeding edge gem “skaes-railsbench” fom github).

railsbench analyze_heap_dump -o wow heap.dump

will create a html visualization of the heap dump and name the file “wow.html” along with two text files listing the memory hotspots (linked from the html file).

The most accurate measurements are of course obtained from a live application server. One way way to do this is to install a signal handler to produce a heap dump whenever you feel like it.

trap("USR2"){ ... }

Another option is to create a dump at the end of running your functional tests, if you have a comprehensive test suite for your application. This avoids having to run one of your application servers with the debug version of Ruby and will create most of the lazily generated helper code.

To follow this route, add code similar to the one given below:

at_exit do
  GCstart; GC.start
  GC.dump_file_and_line_info("heap.dump", true)
end

Be sure to place this code before requiring the test framework, as this installs an exit handler of its own. Adding the handler after requiring the test framework would effectively lead to dumping the heap before running the tests.

License

See LICENSE for license information.

About

A plugin for Rails 2.1 and 2.2 which optimizes routing code generation

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages