Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Waza 2013

Waza 2013

My Talk at Waza 2013

Aaron Patterson

March 01, 2013
Tweet

More Decks by Aaron Patterson

Other Decks in Technology

Transcript

  1. AT&T, AT&T logo and all AT&T related marks are trademarks

    of AT&T Intellectual Property and/or AT&T affiliated companies.
  2. Job Definition class Job def initialize(user_id) @user_id = user_id end

    def run user = User.find @user_id # .... end end
  3. describe "whatever" do setup do # ... end it "does

    some stuff" do 1.must_equal 1 end describe "some other stuff" do it "does some other stuff" do 'foo'.must_match /foo/ end end end
  4. class SomeTest < ActiveSupport::TestCase setup { # ... } test

    "some thing" do # ... end end Rails Tests
  5. Refactor class SomeTest < MiniTest::Spec class << self alias :test

    :it end setup { # ... } test "some thing" do # ... end end
  6. AS::TestCase class ActiveSupport::TestCase < MiniTest::Spec class << self alias :test

    :it end end class SomeTest < ActiveSupport::TestCase setup { # ... } test "some thing" do # ... end end
  7. Free goodies! describe "whatever" do it "does some stuff" do

    1.must_equal 1 end describe "some other stuff" do it "does some other stuff" do 'foo'.must_match /foo/ end end end
  8. class_eval class Foo end Foo.eval "def bar; :hi; end" #

    => error Foo.class_eval "def bar; :hi; end" # => ok! Foo.new.bar # => :hi
  9. Parser (eval) # test.rb class Foo 10.times { |i| class_eval

    "def b_#{i}; :hi; end", __FILE__, __LINE__ } end # x.d ruby$target:::parse-begin /copyinstr(arg0) == "test.rb"/ { printf("%s:%d\n", copyinstr(arg0), arg1); } R uby 2.0!
  10. DTrace Run $ sudo dtrace -q -s x.d -c'ruby test.rb'

    test.rb:1 test.rb:3 test.rb:3 test.rb:3 test.rb:3 test.rb:3 test.rb:3 test.rb:3 test.rb:3 test.rb:3 test.rb:3 $
  11. Parser (def_m) # test.rb class Foo 10.times { |i| define_method("b_#{i}")

    { :hi } } end # x.d ruby$target:::parse-begin /copyinstr(arg0) == "test.rb"/ { printf("%s:%d\n", copyinstr(arg0), arg1); } R uby 2.0!
  12. Environment class Foo hello = "world!" define_method("foo") { hello }

    class_eval "def bar; hello; end" end x = Foo.new x.foo # => "world!" x.bar # => NameError
  13. Definition Speed class Foo if ENV['CLASS_EVAL'] 100_000.times do |i| class_eval("def

    x_#{i}; end") end else 100_000.times do |i| define_method("x_#{i}") { } end end end
  14. $ DEF_METH=1 time -p ruby test.rb real 0.63 user 0.56

    sys 0.05 $ CLASS_EVAL=1 time -p ruby test.rb real 3.62 user 3.52 sys 0.09
  15. Method Call Speed require 'benchmark/ips' GC.disable class Foo class_eval("def foo;

    end") define_method("bar") { } end Benchmark.ips do |x| F = Foo.new x.report("define_method") { F.bar } x.report("class_eval") { F.foo } end
  16. Calculating ------------------------------------- define_method 100965 i/100ms class_eval 107181 i/100ms ------------------------------------------------- define_method

    4801218.4 (±6.3%) i/s - 23928705 in 5.008944s class_eval 7386563.1 (±8.9%) i/s - 36548721 in 5.003122s Iterations / sec
  17. Call + Work require 'benchmark/ips' GC.disable class Foo class_eval("def foo;

    2.times.map { 'foo' } end") define_method("bar") { 2.times.map { "foo" } } end Benchmark.ips do |x| F = Foo.new x.report("define_method") { F.bar } x.report("class_eval") { F.foo } end
  18. Iterations / sec Calculating ------------------------------------- define_method 42364 i/100ms class_eval 44085

    i/100ms ------------------------------------------------- define_method 612296.0 (±7.1%) i/s - 3050208 in 5.007636s class_eval 558666.2 (±12.1%) i/s - 2689185 in 5.181042s
  19. Memory $ CLASS_EVAL=1 time -l ruby test.rb 3.63 real 3.53

    user 0.08 sys 126648320 maximum resident set size 0 average shared memory size 0 average unshared data size 0 average unshared stack size $ DEFN=1 time -l ruby test.rb 0.63 real 0.57 user 0.06 sys 69734400 maximum resident set size 0 average shared memory size 0 average unshared data size 0 average unshared stack size
  20. Measure ISeq require 'objspace' N = (ENV['N'] || 100_000).to_i class

    Foo N.times do |i| if ENV['CLASS_EVAL'] class_eval("def x_#{i}; end") else define_method("x_#{i}") { } end end end GC.start p ObjectSpace.memsize_of_all(RubyVM::InstructionSequence) R uby 1.9.3+
  21. Results $ CLASS_EVAL=1 ruby test.rb 38659482 $ DEFN=1 ruby test.rb

    259482 $ N=200000 DEFN=1 ruby test.rb 259482
  22. Closure Leaks class Foo x = "X" * 1024 define_method("x")

    { } end class Bar x = "X" * 1024 class_eval("def x; end") end
  23. @module.module_eval <<-END_EVAL def #{name}(*args) if #{optimize_helper?(route)} && args.size == #{route.required_parts.size}

    && !args.last.is_a? (Hash) && optimize_routes_generation? options = #{options.inspect} options.merge!(url_options) if respond_to? (:url_options) options[:path] = "#{optimized_helper(route)}" ActionDispatch::Http::URL.url_for(options) else url_for(handle_positional_args(args, #{options.inspect}, #{route.segment_keys.inspect})) end end END_EVAL
  24. Conditionals @module.module_eval <<-END_EVAL def #{name}(*args) if #{optimize_helper?(route)} && args.size ==

    #{route.required_parts.size} && ! args.last.is_a?(Hash) && optimize_routes_generation? # ... else # ... end end END_EVAL
  25. + def if_#{name}(t, options, path) + options.merge!(url_options) + options[:path] =

    path + ActionDispatch::Http::URL.url_for(options) + end + def #{name}(*args) if #{optimize_helper?(route)} options = #{options.inspect} - options.merge!(url_options) - options[:path] = "#{optimized_helper(route)}" - ActionDispatch::Http::URL.url_for(options) + if_#{name}(self, options, "#{optimized_helper(route)}") else - url_for(...) + UrlHelp.new.url_else(...)
  26. + def if_#{name}(t, options, path) + options.merge!(url_options) + options[:path] =

    path + ActionDispatch::Http::URL.url_for(options) + end + def #{name}(*args) if #{optimize_helper?(route)} options = #{options.inspect} - options.merge!(url_options) - options[:path] = "#{optimized_helper(route)}" - ActionDispatch::Http::URL.url_for(options) + if_#{name}(self, options, "#{optimized_helper(route)}") else - url_for(...) + UrlHelp.new.url_else(...)
  27. + def url_if(t, options, path) + options.merge!(t.url_options) if t.respond_to?(:url_options) +

    options[:path] = path + ActionDispatch::Http::URL.url_for(options) + end + def handle_positional_args(t, args, options, segment_keys) inner_options = args.extract_options! result = options.dup @@ -192,17 +198,10 @@ module ActionDispatch def define_url_helper(route, name, options) @module.remove_possible_method name @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 - - def if_#{name}(t, options, path) - options.merge!(url_options) if t.respond_to?(:url_options) - options[:path] = path - ActionDispatch::Http::URL.url_for(options) - end Remove From Eval eval
  28. class UrlHelper def self.create(options) new options end def initialize @options

    = options end def url_else(t, args, seg) # ... end def url_if(t, path) # ... end end
  29. @module.module_eval <<-END_EVAL def #{name}(*args) if #{optimize_helper?(route)} # ... options =

    #{options.inspect} UrlHelp.new.url_if(self, options, "#{optimized_helper(route)}") else UrlHelp.new.url_else(self, args, # ... ) end end END_EVAL
  30. # * <tt>:terminator</tt> - Determines when a before filter will

    halt the # callback chain, preventing following callbacks from being called and # the event from being triggered. This is a string to be eval'ed. The # result of the callback is available in the +result+ variable. # # define_callbacks :validate, terminator: 'result == false'