1. 07 10月, 2015 1 次提交
  2. 02 9月, 2015 1 次提交
  3. 26 8月, 2015 1 次提交
  4. 25 8月, 2015 1 次提交
  5. 21 8月, 2015 1 次提交
  6. 19 8月, 2015 2 次提交
    • A
      don't touch internals · 62383dde
      Aaron Patterson 提交于
      We shouldn't be messing with the NamedRouteCollection internals.  Just
      ask the object if the named route is in there.
      62383dde
    • A
      drop array allocations when building paths · d993cb36
      Aaron Patterson 提交于
      ```ruby
      require 'action_pack'
      require 'action_dispatch'
      require 'benchmark/ips'
      
      route_set = ActionDispatch::Routing::RouteSet.new
      routes = ActionDispatch::Routing::Mapper.new route_set
      
      ObjectSpace::AllocationTracer.setup(%i{path line type})
      result = ObjectSpace::AllocationTracer.trace do
        500.times do
          routes.resources :foo
        end
      end
      
      sorted = ObjectSpace::AllocationTracer.allocated_count_table.sort_by(&:last)
      sorted.each do |k,v|
        next if v == 0
        p k => v
      end
      
      __END__
      
      Before:
      
      {:T_SYMBOL=>11}
      {:T_REGEXP=>17}
      {:T_STRUCT=>6500}
      {:T_MATCH=>12004}
      {:T_OBJECT=>99009}
      {:T_DATA=>100088}
      {:T_HASH=>122015}
      {:T_STRING=>159637}
      {:T_IMEMO=>363134}
      {:T_ARRAY=>433056}
      
      After:
      
      {:T_SYMBOL=>11}
      {:T_REGEXP=>17}
      {:T_STRUCT=>6500}
      {:T_MATCH=>12004}
      {:T_OBJECT=>91009}
      {:T_DATA=>100088}
      {:T_HASH=>114013}
      {:T_STRING=>159637}
      {:T_ARRAY=>321056}
      {:T_IMEMO=>351133}
      ```
      d993cb36
  7. 18 8月, 2015 4 次提交
    • A
      use the strategy pattern to match request verbs · 0b476de4
      Aaron Patterson 提交于
      Rather than building a regexp for every route, lets use the strategy
      pattern to select among objects that can match HTTP verbs.  This commit
      introduces strategy objects for each verb that has a predicate method on
      the request object like `get?`, `post?`, etc.
      
      When we build the route object, look up the strategy for the verbs the
      user specified.  If we can't find it, fall back on string matching.
      
      Using a strategy / null object pattern (the `All` VerbMatcher is our
      "null" object in this case) we can:
      
      1) Remove conditionals
      2) Drop boot time allocations
      2) Drop run time allocations
      3) Improve runtime performance
      
      Here is our boot time allocation benchmark:
      
      ```ruby
      require 'action_pack'
      require 'action_dispatch'
      
      route_set = ActionDispatch::Routing::RouteSet.new
      routes = ActionDispatch::Routing::Mapper.new route_set
      
      result = ObjectSpace::AllocationTracer.trace do
        500.times do
          routes.resources :foo
        end
      end
      
      sorted = ObjectSpace::AllocationTracer.allocated_count_table.sort_by(&:last)
      sorted.each do |k,v|
        next if v == 0
        p k => v
      end
      __END__
      
      Before:
      
      $ be ruby -rallocation_tracer route_test.rb
      {:T_SYMBOL=>11}
      {:T_REGEXP=>4017}
      {:T_STRUCT=>6500}
      {:T_MATCH=>12004}
      {:T_DATA=>84092}
      {:T_OBJECT=>99009}
      {:T_HASH=>122015}
      {:T_STRING=>216652}
      {:T_IMEMO=>355137}
      {:T_ARRAY=>441057}
      
      After:
      
      $ be ruby -rallocation_tracer route_test.rb
      {:T_SYMBOL=>11}
      {:T_REGEXP=>17}
      {:T_STRUCT=>6500}
      {:T_MATCH=>12004}
      {:T_DATA=>84092}
      {:T_OBJECT=>99009}
      {:T_HASH=>122015}
      {:T_STRING=>172647}
      {:T_IMEMO=>355136}
      {:T_ARRAY=>433056}
      ```
      
      This benchmark adds 500 resources. Each resource has 8 routes, so it
      adds 4000 routes.  You can see from the results that this patch
      eliminates 4000 Regexp allocations, ~44000 String allocations, and ~8000
      Array allocations.  With that, we can figure out that the previous code
      would allocate 1 regexp, 11 strings, and 2 arrays per route *more* than
      this patch in order to handle verb matching.
      
      Next lets look at runtime allocations:
      
      ```ruby
      require 'action_pack'
      require 'action_dispatch'
      require 'benchmark/ips'
      
      route_set = ActionDispatch::Routing::RouteSet.new
      routes = ActionDispatch::Routing::Mapper.new route_set
      
      routes.resources :foo
      
      route = route_set.routes.first
      request = ActionDispatch::Request.new("REQUEST_METHOD" => "GET")
      
      result = ObjectSpace::AllocationTracer.trace do
        500.times do
          route.matches? request
        end
      end
      
      sorted = ObjectSpace::AllocationTracer.allocated_count_table.sort_by(&:last)
      sorted.each do |k,v|
        next if v == 0
        p k => v
      end
      
      __END__
      
      Before:
      
      $ be ruby -rallocation_tracer route_test.rb
      {:T_MATCH=>500}
      {:T_STRING=>501}
      {:T_IMEMO=>1501}
      
      After:
      
      $ be ruby -rallocation_tracer route_test.rb
      {:T_IMEMO=>1001}
      ```
      
      This benchmark runs 500 calls against the `matches?` method on the route
      object.  We check this method in the case that there are two methods
      that match the same path, but they are differentiated by the verb (or
      other conditionals).  For example `POST /users` vs `GET /users`, same
      path, different action.
      
      Previously, we were using regexps to match against the verb.  You can
      see that doing the regexp match would allocate 1 match object and 1
      string object each time it was called.  This patch eliminates those
      allocations.
      
      Next lets look at runtime performance.
      
      ```ruby
      require 'action_pack'
      require 'action_dispatch'
      require 'benchmark/ips'
      
      route_set = ActionDispatch::Routing::RouteSet.new
      routes = ActionDispatch::Routing::Mapper.new route_set
      
      routes.resources :foo
      
      route = route_set.routes.first
      match = ActionDispatch::Request.new("REQUEST_METHOD" => "GET")
      no_match = ActionDispatch::Request.new("REQUEST_METHOD" => "POST")
      
      Benchmark.ips do |x|
        x.report("match") do
          route.matches? match
        end
      
        x.report("no match") do
          route.matches? no_match
        end
      end
      
      __END__
      
      Before:
      
      $ be ruby -rallocation_tracer runtime.rb
      Calculating -------------------------------------
                     match    17.145k i/100ms
                  no match    24.244k i/100ms
      -------------------------------------------------
                     match    259.708k (± 4.3%) i/s -      1.303M
                  no match    453.376k (± 5.9%) i/s -      2.279M
      
      After:
      
      $ be ruby -rallocation_tracer runtime.rb
      Calculating -------------------------------------
                     match    23.958k i/100ms
                  no match    29.402k i/100ms
      -------------------------------------------------
                     match    465.063k (± 3.8%) i/s -      2.324M
                  no match    691.956k (± 4.5%) i/s -      3.469M
      
      ```
      
      This tests tries to see how many times it can match a request per
      second.  Switching to method calls and string comparison makes the
      successful match case about 79% faster, and the unsuccessful case about
      52% faster.
      
      That was fun!
      0b476de4
    • A
      switch Route constructors and pass in the regexp · c989e2c5
      Aaron Patterson 提交于
      We don't need to add and delete from the conditions hash anymore, just
      pass the regexp directly to the constructor.
      c989e2c5
    • A
      introduce an alternate constructor for Route objects · 1ce74b00
      Aaron Patterson 提交于
      I want to change the real constructor to take a particular parameter for
      matching the request method
      1ce74b00
    • A
      default pattern to use a joined string · e9777ef6
      Aaron Patterson 提交于
      The string we create is almost always the same, so rather than joining
      all the time, lets join once, then reuse that string everywhere.
      e9777ef6
  8. 16 8月, 2015 2 次提交
  9. 15 8月, 2015 12 次提交
  10. 14 8月, 2015 5 次提交
  11. 13 8月, 2015 10 次提交