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

Waza 2013

Waza 2013

My Talk at Waza 2013

Avatar for Aaron Patterson

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'