Archive for 2010

Rails and Merb Merge: Rack (Part 6 of 6)

By Yehuda Katz | March 16th, 2010 at 10:03AM

In this final segment, I’ll talk about how Rails 3 takes advantage of the Rack standard, leveraging it in ways that make sharing code between Ruby web applications easier. There are a ton of good blog posts and presentations on Rack itself, so I won’t go into too much detail beyond a brief summary.

What is Rack?

Rack defines a standard for interaction between web servers and Ruby web applications. It’s based on the CGI standard, but stripped of CGI’s global characteristics (such as its use of environment variables and standard output).

Servers send requests to Rack applications by calling their #call method with an environment Hash containing information as a number of standardized keys. For instance, it provides the requested path in the PATH_INFO variable. Applications send responses back to the server as an Array of three elements: the status code, a Hash of the headers, and the body. Applications may return any object that responds to #each as the body, and each iteration must return a String object.

Here are a couple of simple Rack applications:

# A Proc responds to #call
proc do |env|
  [200, {"Content-Type" => "text/html"}, ["Hello world"]]
end
 
# Other objects that respond to #call work too
class MyApp
  def self.call(env)
    [
      200,
      {"Content-Type" => "text/html"},
      ["Hello world"]
    ]
  end
end

Rails 2.3

In Rails 2.3, Rails became a fully valid Rack application, leveraging Rack in a number of places:

  • ActionController::Dispatcher.new is the top-level Rack application
  • The parameter parser is implemented as middleware
  • The router is a Rack application that dispatches to controllers
  • Each controller is a Rack application

This was a modest step toward leveraging Rack, and made Rails applications work anywhere Rack worked. However, the internals of some of these pieces were messy, and an overhaul would be needed to take full advantage of the Rack ecosystem and the power of Rack’s architecture.

Enter Rails 3: The Application

First, rather than having a global Dispatcher object pointing at a global router, Rails 3 introduces the idea of the Rails Application. The Application, an object holding the router and other configuration, is itself a Rack application.

The following is a valid config.ru.

# Set up load paths as desired
 
require "action_controller/railtie"
 
class FooController < ActionController::Base
  def bar
    self.response_body = "HELLO"
  end
end
 
class MyApp < Rails::Application
   config.session_store :disabled
 
   routes.draw do
     match "/foo" => "foo#bar"
  end
end
 
run MyApp

As you can see, a Rails application is a valid Rack application. The above config.ru file will run with rackup, Passenger, Glassfish, or any other Rack server.

ActionDispatch and Rack Middleware

Rails 3 introduces a new framework called ActionDispatch, a library extending the features of the Rack library for Rails’ use. This library can also be used standalone in any Rack application.

The new ActionDispatch::Request and ActionDispatch::Response objects now inherit from Rack::Request and Rack::Response. Integration tests now use Rack::Test and can now be used to test any Rack application.

Rails now includes a number of new general purpose middlewares:

  • A middleware to run preparation callbacks, which Rails runs once in production mode, or once per request in development mode
  • A middleware to set up and write cookies
  • A middleware to clean up flash notices
  • A middleware to handle HEAD requests
  • A middleware to handle IP spoof checking
  • A middleware to serve static assets
  • Middlewares to handle rescuing exceptions down the stack
  • Middlewares for various session stores

Rails also uses a number of middlewares that ship with the Rack library:

  • A middleware to synchronize non-threadsafe requests
  • A middleware to measure and set the runtime of requests
  • A middleware to implement Send-File semantics in various web servers
  • A middleware to handle PUT and DELETE requests coming in via POST requests

The middleware stack object, available as config.middleware, supports reordering these middlewares, or inserting new middleware relative to default ones.

One nice thing about implementing the functionality as middleware is that it forces them to be simple, standalone objects, and understanding, patching or even replacing them becomes much easier than trying to modify a monolithic controller or request object.

The Router

The Rails 3 router was written from the ground up by Josh Peek as the Rack::Mount project, which provides a general-purpose Rack router. Rack::Mount recognizes URLs and dispatches them to any Rack application. As a result, the router now natively supports matching any URL to any arbitrary Rack application–even a Sintra application.

Rails.application.routes.draw do
  match "/blog" => Rack::Blog # Someone should write it!
end

The router is itself a Rack application, so it’s possible to mount a router inside the main router. Carl Lerche’s Astaire project uses this to provide the Sinatra routing DSL inside a Rails controller. The following is a valid config.ru:

$:.unshift File.expand_path('../../lib', __FILE__)
 
require 'rubygems'
require 'astaire'
 
class OmgController < ActionController::Base
  include Astaire::DSL
  append_view_paths File.expand_path('../views', __FILE__)
 
  get "/goodbye" do
    render :text => "goodbye"
  end
 
  get "/hello" do
    render "hello"
  end
end
 
run OmgController

Astaire uses ActionDispatch::Routing::RouteSet internally, a Rails wrapper around Rack::Mount.

Actions

Because the router dispatches directly to Rack applications, each controller action is its own mini-application. To get a valid Rack application for a controller’s action, use the ArticlesController.action(:index) syntax.

The Rails router uses the syntax match "/articles" => "articles#index" to match a URL to a controller/action pair. That syntax is identical to match "/articles" => ArticlesController.action(:index).

Because actions are their own Rack applications, you can add middleware between the router and controller actions:

class ArticlesController < ApplicationController
  use MyMiddleware
end

This will insert the middleware between the router and the dispatching of an action. The following is a valid config.ru:

class ArticlesController < ActionController::Base
  append_view_path "/path/to/views"
 
  def index
    render
  end
 
  # implicit actions, such as "articles/show" would work here
end
 
run ArticlesController.action(:index)

This endpoint would behave exactly like a normal action, including callbacks and rendering. In fact, it’s roughly identical to what happens internally inside the router.

You can also call into an action using this syntax:

env = Rack::MockRequest.env_for("/articles")
status, headers, body = ArticlesController.action(:index).call(env)
 
# Create a response object, if you want one
response = ActionDispatch::Response.new(status, headers, body)

You could also use Rack::Test:

class TestArticles < Test::Unit::TestCase
  include Rack::Test::Methods
 
  def app
    ArticlesController.action(:index)
  end
 
  def test_get
    get "/articles"
    assert_equal "Hello world", last_response.body
  end
end
 
# This would include the application's middleware,
# which you probably want as it includes sessions
# and cookies
class TestApplication < Test::Unit::TestCase
  include Rack::Test::Methods
 
  def app
    MyApplication
  end
 
  def test_get
    get "/articles"
    assert_equal "Hello world", last_response.body
  end
end

You would probably use Rails integration tests, which wrap Rack::Test with some additional conveniences, in practice. It’s nice to know that there’s very little magic going on, and that all of the individual pieces of Rails are just standard Rack.

Conclusion

While Rails 2 had started down the path of supporting Rack, Rails 3 took a few dozen steps forward, deeply integrating the framework with the Rack standard. In addition to improving the general interaction with servers, Rails 3 takes much more advantage of the Rack library, exposes its own functionality as reusable Rack components, and wires up the stack using the Rack architecture. This means that Rails itself integrates well with tools that work with Rack applications, and can also incorporate other applications or middleware following the Rack standard.

Stay tuned for more Rails 3 content to come—the series may be over, but there’s plenty left to talk about.

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 2% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...

See You At The Hackfest!

By Leah Silber | March 10th, 2010 at 10:03AM

A quick reminder to those of you attending MountainWest RubyConf this weekend: Engine Yard will be hosting its third annual MountainWest RubyConf Hackfest this Thursday night!

We’ll be back at the Hilton Salt Lake City Center, in the spacious and comfy Vice Presidential Suite. We’ll have food, drinks, wireless access, and of course, code, code and more code. If you’ve been to a previous MountainWest Hackfest you know that this is the not-to-miss Hacking event of the year, so be sure to stop in!

Members of the Engine Yard crew will be at the show all day, and hacking in the suite all night, so if you’ve got any questions, find one of us on-site Thursday, or shoot us an email. We’ll see you all there!

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 4% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...

Making Ruby Fast: The Rubinius JIT

By Evan Phoenix | March 9th, 2010 at 3:03PM

In order to execute Ruby code as fast as possible, Rubinius has the ability to compile Ruby code all the way down to machine code when it detects that a method is heavily used. In Rubinius, the system that manages this process is its JIT.

In today’s post, I’ll be giving an overview of the various players involved in the path that code takes to get from source to machine code. Without further ado, I’ll jump right in.

Melbourne Parser

This is the first step. The parser takes Ruby source code as input and calls for each element to create an internal representation of the code: the AST. (lib/ext/melbourne)

Compiler

The compiler takes the AST that the parser created and analyzes it, creating bytecode in the form of a CompiledMethod and InstructionSequence. (lib/compiler)

Bytecode

A CompiledMethod object contains an InstructionSequence object, which is the raw bytecode which will perform the semantic actions of the Ruby source code. (lib/compiler/iseq.rb)

Virtual Machine

The VM itself then executes the bytecode using a simple interpreter. A key data structure used in this evaluation is the VMMethod, which is an internal mirror of a CompiledMethod, but translated into constructs that are easier to interpret. As the VM interprets a VMMethod, it uses InlineCache objects to speed up method dispatch. In addition, these InlineCache objects remember profiling information about what methods they have seen. This information is later used by the JIT.

The VM also increments a call counter on the VMMethod at a few critical points (on start and on backward branch). This call counter is what controls when the JIT kicks in. When the call counter reaches some predetermined value (controlled via -Xjit.call_til_compile), the first stage of the JIT kicks in.

Method Chooser

Now that a call counter has reached the proper level, the JIT is ready to kick in. The JIT could simply take the method whose counter has hit the level, but instead it starts the search. It’s looking for a good method to JIT, which it finds by looking up the call stack.

The reason it does this is because the JIT has the ability to inline methods into methods that call them. We’re exploiting the fact that the call stack shows not just one method heating up, but a whole chain of them (vm/llvm/jit:compile_callframe). So we walk up the call stack, looking at each method along the way, and asking ourselves: could this method be inlined into the one that called it? If the answer is yes, we move to the next method. By doing this, we’re able to inline methods along hot paths in code, which yields better speeds.

Compiler Thread

Now that we’ve picked a good method at which to start the JIT process, the method is placed into a queue. This queue is then automatically emptied by another native thread, which is always running. It’s in this background thread that the rest of the JIT process takes place.

Using a background thread means that the Ruby code is free to continue to run while the JIT runs in the background. This means that the JIT imposes virtually no slowdown, because it never stands in the way of running Ruby code (vm/llvm/jit:compile_soon).

The JIT thread pops an entry off the queue and begins compiling it. Because the JIT uses LLVM to perform low level optimizations and machine code generation, we need to translate the method into a structure that LLVM understands. This structure is the LLVM IR.

To convert the method, we walk through the bytecode and call methods on a JITVisit object (one for each kind of bytecode). The JITVisit class uses LLVM’s IRBuilder class to build a big tree data structure that represents the actions that should be taken.

A simple example is that a goto bytecode instruction is translated into a Branch object and inserted into the IR. For most bytecode, the process is fairly straight forward, there being a simple set of IR objects to generate per bytecode.

Method Inlining

The most complicated bytecodes to generate IR for are the send instructions. This is because it’s at these points that we have the opportunity to inline a method. When a method is inlined, the code to perform the method is inserted where the send instruction would normally be. This eliminates any calling overhead and allows LLVM to optimize more.

At this stage, control is handled to an Inliner object. The Inliner will only inline a method if it can see that the method was the the primary method called at a particular send instruction. Because Ruby is a dynamic language, any method call can always invoke a brand new method. But in reality, that happens rarely. Instead, most method calls always end up calling the same method over and over again. The profiling information that the InlineCaches have been gathering allows us to see that this is the case and perform inlining.

One constraint that the Inliner has is that it needs to avoid over-inlining. Over-inlining causes the generated function to become extremely large and slower than it would be if there were no inlining. To do this, the Inliner keeps track of the cost of a inlining. For every method that is inlined, the cost increases. When the cost reaches a threshold, no more inlining takes place.

Now that the Inliner has decided to go ahead and inline the method, it must insert a guard before the inlined code. This guard makes sure that the object is still of the type seen in the profiling information, and that therefore the inlined method code is the proper code to run. The generated IR for this looks something like:

if(obj->class == profiled_class) {
 result = inlined_code_for_method_name;
} else {
 result = obj->send method_name, …;
}
This allows Ruby code to continue to be dynamic, but exploits those points in the code where the dispatch is actually static.

After the JITVisit class has finished, control is handed off to optimize and generates machine code.

LLVM Optimization

Up to now, we’ve simply been constructing information to feed to LLVM. Now we actually hand over the IR to LLVM. The first thing LLVM does is run a number of optimization passes over the IR. This cleans up the IR and makes it quite a bit more efficient. At this stage, the IR can be reduced in size by five to ten times by remove redundancies and reordering.

LLVM Code Generation

Finally, the optimized IR is run through LLVMs code generator. This code generator is fairly complex, but its API is extremely simple. When the generator finishes, it returns a function pointer that can be called to execute the code. We put this function pointer into a special slot on the original CompiledMethod.

By default, this slot in the object holds a pointer to the function that implements the interpreter. By swapping them, any future calling of the method automatically uses the new JIT’d version.

Deoptimization

Because Ruby is so dynamic, there are cases where JIT’d code must be discarded. The primary example is where a method that was inlined is redefined. In this case, the VM keeps a table to know all methods that inlined the method being redefined. It resets those methods back to using the interpreter and tags the JIT’d code to be discarded. Because the method has been reset, it can now be JIT’d again later, incorporating the newly redefined method.

So those are the systems that interaction to make speed up Ruby. The process can achieve speeds up by as much as 10x over non JIT’d code. We’ve only begun to scratch the surface of the techniques we can use to strip even more dynamic aspects of the code away and make it faster. 2010 is going to be an exciting year.

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 11% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...

March Madness!

By Leah Silber | March 2nd, 2010 at 10:03AM

Okay, so maybe madness is a strong word, but March is here, and Ruby and Rails events are back in full swing! We’ll be all over the globe talking Ruby, Rails, and for a special treat, Cloud Computing. If you’ll be in any of the areas we’re visiting, be sure to get in touch—we’d love to meet you!

MountainWest RubyConf

March 11-12 | Salt Lake City, UT

We’re back to sponsor MountainWest RubyConf for the third year running, and we couldn’t be happier. It’s a great event, organized by incredible coders, with an all around top-quality and intimate feeling. For the third year running we’ll also be hosting our (now annual) MountainWest RubyConf Hackfest! Food, drinks and code in a huge and comfy open-all-night suite at the Hilton. Surround yourself with top Rubyists and hack on your favorite projects well into the wee hours of the morning; what more can you ask for?

Last but not least, be sure to catch Yehuda Katz’s talk on writing modular code with Rails 3; this close to the release date, it’s sure to put you on the cutting edge.

South by Southwest

March 12-16 | Austin, TX

Yehuda will be hopping straight from MountainWest RubyConf to South by Southwest to represent us all at a ‘Web Frameworks Battle Royale.’ By battle, they mean panel, but still; if you’re at SXSW, be sure to drop in and show your support for Ruby and Rails!

CloudConnect

March 15-18 | Santa Clara, CA

Ezra Zygmuntowicz will be at CloudConnect, talking about what else? Cloud deployment. He’ll be joined by some Engine Yard customers, so do take advantage of the opportunity to get the real scoop!

RubyConf India

March 20-21 | Bangalore, India

This is the inaugural RubyConf India, and we’re glad to be participating! Nick Sieger will be on hand, talking about Rails 3—and JRuby, of course. Ruby luminaries like Chad Fowler, Ola Bini and the one and only Yukihiro Matsumoto will be in attendance; a serious roster for a first time show—congrats, guys!

Scottish Ruby Conference

March 26-27 | Edinburgh, Scotland

Formerly known as Scotland on Rails, the Scottish Ruby Conference is yet another annual calendar fixture. It’s organized by a great group of guys (here’s to you, Paul, Alan and Graham!), in an even greater city. If you’re extending a conference trip, this is the one; you definitely want to take a few days to explore the city!

New Rails Core Team member Carl Lerche will be there, talking about getting the most out of ActiveRecord 3 with Arel; be sure to check it out.

Ruby User Groups

Last but not least, Randall Thomas will be hitting up a few cities this month, talking about Machine Learning and demoing Engine Yard Cloud:

That’s it for March; hope to see you all out there!

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 7% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...

No More Monthly Minimums on Engine Yard Cloud!

By Abheek Anand | March 1st, 2010 at 11:03AM

Moore’s law is a wonderful thing.

Users of cloud computing frequently talk about its advantages; those include lower capital expenditures, programmable infrastructure, and the power of agile deployment. One thing that doesn’t get as much attention though, is how the advantages of Moore’s law are significantly magnified by using the cloud. After all, while buying infrastructure might lock you into using the same equipment for the next few years, using a cloud service means that customers get standardized instance sizes, and the infrastructure provider can refresh the underlying hardware a lot faster.

Here at Engine Yard, we’ve been aggressively passing these savings along to our customers. A few weeks ago we dropped instance prices by aggregating a pool of EC2 reserved instances, and taking advantage of Amazon’s just-released consolidated billing feature to get reduced costs for these instances. Last week, we passed through a savings in outbound bandwidth pricing—upto a 20% decrease across all tiers of usage.

Today we’re announcing that we’ll be dropping the monthly minimum for using Engine Yard Cloud. This is a direct response to feedback from users working on projects that haven’t yet deployed to production. We now know that many of you are using Engine Yard Cloud for development and staging environments pre-launch, where costs don’t quite make it to $25. We agree—things should be different, and so starting today that minimum goes away, and we move to being a completely pay-as-you-go platform.

Run your instances only when you need them, and pay only for what you use, regardless of whether you’re a small group of developers building the next big Rails application, or a production environment serving millions of users.

So there you have it: three price decreases in just the last month. Stay tuned for more—there are exciting new features in the pipeline, and we can’t wait to tell you about them!

Share this post:
  • email
  • Digg
  • del.icio.us
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
  • Google Bookmarks
  • Facebook
  • LinkedIn
Popularity: 8% |
Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars
Loading ... Loading ...