Skip to content
  • Jonathan Hefner's avatar
    e5693c56
    Add AS::ParameterFilter.precompile_filters · e5693c56
    Jonathan Hefner authored
    `ActiveSupport::ParameterFilter.precompile_filters` precompiles filters
    that otherwise would be passed directly to `ParameterFilter.new`.
    Depending on the quantity and types of filters, precompilation can
    improve filtering performance, especially in the case where the
    `ParameterFilter` instance cannot be retained, such as with per-request
    instances in `ActionDispatch::Http::FilterParameters`.
    
    **Benchmark script**
    
      ```ruby
      # frozen_string_literal: true
      require "benchmark/ips"
      require "benchmark/memory"
      require "active_support"
      require "active_support/parameter_filter"
    
      ootb = [:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn]
      mixed = [:passw, "secret", /token/, :crypt, "salt", /certificate/, "user.otp", /user\.ssn/, proc {}]
      precompiled_ootb = ActiveSupport::ParameterFilter.precompile_filters(ootb)
      precompiled_mixed = ActiveSupport::ParameterFilter.precompile_filters(mixed)
    
      params = {
        "user" => {
          "name" => :name,
          "email" => :email,
          "password" => :password,
          "ssn" => :ssn,
          "locations" => [
            { "city" => :city, "country" => :country },
            { "city" => :city, "country" => :country },
          ],
        }
      }
    
      Benchmark.ips do |x|
        x.report("ootb") do
          ActiveSupport::ParameterFilter.new(ootb).filter(params)
        end
        x.report("precompiled ootb") do
          ActiveSupport::ParameterFilter.new(precompiled_ootb).filter(params)
        end
        x.compare!
      end
    
      Benchmark.ips do |x|
        x.report("mixed") do
          ActiveSupport::ParameterFilter.new(mixed).filter(params)
        end
        x.report("precompiled mixed") do
          ActiveSupport::ParameterFilter.new(precompiled_mixed).filter(params)
        end
        x.compare!
      end
    
      Benchmark.memory do |x|
        x.report("ootb") do
          ActiveSupport::ParameterFilter.new(ootb).filter(params)
        end
        x.report("precompiled ootb") do
          ActiveSupport::ParameterFilter.new(precompiled_ootb).filter(params)
        end
      end
    
      Benchmark.memory do |x|
        x.report("mixed") do
          ActiveSupport::ParameterFilter.new(mixed).filter(params)
        end
        x.report("precompiled mixed") do
          ActiveSupport::ParameterFilter.new(precompiled_mixed).filter(params)
        end
      end
      ```
    
    **Results**
    
      ```
      Warming up --------------------------------------
                      ootb     2.151k i/100ms
          precompiled ootb     4.251k i/100ms
      Calculating -------------------------------------
                      ootb     21.567k (± 1.1%) i/s -    109.701k in   5.086983s
          precompiled ootb     42.840k (± 0.8%) i/s -    216.801k in   5.061022s
    
      Comparison:
          precompiled ootb:    42840.4 i/s
                      ootb:    21567.5 i/s - 1.99x  (± 0.00) slower
      ```
    
      ```
      Warming up --------------------------------------
                     mixed     1.622k i/100ms
         precompiled mixed     2.455k i/100ms
      Calculating -------------------------------------
                     mixed     16.085k (± 1.3%) i/s -     81.100k in   5.042764s
         precompiled mixed     24.640k (± 1.0%) i/s -    125.205k in   5.081988s
    
      Comparison:
         precompiled mixed:    24639.6 i/s
                     mixed:    16085.0 i/s - 1.53x  (± 0.00) slower
      ```
    
      ```
      Calculating -------------------------------------
                      ootb     2.684k memsize (     0.000  retained)
                              30.000  objects (     0.000  retained)
                              10.000  strings (     0.000  retained)
          precompiled ootb     1.104k memsize (     0.000  retained)
                               9.000  objects (     0.000  retained)
                               1.000  strings (     0.000  retained)
      ```
    
      ```
      Calculating -------------------------------------
                     mixed     3.541k memsize (     0.000  retained)
                              46.000  objects (     0.000  retained)
                              20.000  strings (     0.000  retained)
         precompiled mixed     1.856k memsize (     0.000  retained)
                              29.000  objects (     0.000  retained)
                              13.000  strings (     0.000  retained)
      ```
    
    This commit also adds `config.precompile_filter_parameters`, which
    enables precompilation of `config.filter_parameters`.  It defaults to
    `true` for `config.load_defaults 7.1` and above.
    e5693c56
    Add AS::ParameterFilter.precompile_filters
    Jonathan Hefner authored
    `ActiveSupport::ParameterFilter.precompile_filters` precompiles filters
    that otherwise would be passed directly to `ParameterFilter.new`.
    Depending on the quantity and types of filters, precompilation can
    improve filtering performance, especially in the case where the
    `ParameterFilter` instance cannot be retained, such as with per-request
    instances in `ActionDispatch::Http::FilterParameters`.
    
    **Benchmark script**
    
      ```ruby
      # frozen_string_literal: true
      require "benchmark/ips"
      require "benchmark/memory"
      require "active_support"
      require "active_support/parameter_filter"
    
      ootb = [:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn]
      mixed = [:passw, "secret", /token/, :crypt, "salt", /certificate/, "user.otp", /user\.ssn/, proc {}]
      precompiled_ootb = ActiveSupport::ParameterFilter.precompile_filters(ootb)
      precompiled_mixed = ActiveSupport::ParameterFilter.precompile_filters(mixed)
    
      params = {
        "user" => {
          "name" => :name,
          "email" => :email,
          "password" => :password,
          "ssn" => :ssn,
          "locations" => [
            { "city" => :city, "country" => :country },
            { "city" => :city, "country" => :country },
          ],
        }
      }
    
      Benchmark.ips do |x|
        x.report("ootb") do
          ActiveSupport::ParameterFilter.new(ootb).filter(params)
        end
        x.report("precompiled ootb") do
          ActiveSupport::ParameterFilter.new(precompiled_ootb).filter(params)
        end
        x.compare!
      end
    
      Benchmark.ips do |x|
        x.report("mixed") do
          ActiveSupport::ParameterFilter.new(mixed).filter(params)
        end
        x.report("precompiled mixed") do
          ActiveSupport::ParameterFilter.new(precompiled_mixed).filter(params)
        end
        x.compare!
      end
    
      Benchmark.memory do |x|
        x.report("ootb") do
          ActiveSupport::ParameterFilter.new(ootb).filter(params)
        end
        x.report("precompiled ootb") do
          ActiveSupport::ParameterFilter.new(precompiled_ootb).filter(params)
        end
      end
    
      Benchmark.memory do |x|
        x.report("mixed") do
          ActiveSupport::ParameterFilter.new(mixed).filter(params)
        end
        x.report("precompiled mixed") do
          ActiveSupport::ParameterFilter.new(precompiled_mixed).filter(params)
        end
      end
      ```
    
    **Results**
    
      ```
      Warming up --------------------------------------
                      ootb     2.151k i/100ms
          precompiled ootb     4.251k i/100ms
      Calculating -------------------------------------
                      ootb     21.567k (± 1.1%) i/s -    109.701k in   5.086983s
          precompiled ootb     42.840k (± 0.8%) i/s -    216.801k in   5.061022s
    
      Comparison:
          precompiled ootb:    42840.4 i/s
                      ootb:    21567.5 i/s - 1.99x  (± 0.00) slower
      ```
    
      ```
      Warming up --------------------------------------
                     mixed     1.622k i/100ms
         precompiled mixed     2.455k i/100ms
      Calculating -------------------------------------
                     mixed     16.085k (± 1.3%) i/s -     81.100k in   5.042764s
         precompiled mixed     24.640k (± 1.0%) i/s -    125.205k in   5.081988s
    
      Comparison:
         precompiled mixed:    24639.6 i/s
                     mixed:    16085.0 i/s - 1.53x  (± 0.00) slower
      ```
    
      ```
      Calculating -------------------------------------
                      ootb     2.684k memsize (     0.000  retained)
                              30.000  objects (     0.000  retained)
                              10.000  strings (     0.000  retained)
          precompiled ootb     1.104k memsize (     0.000  retained)
                               9.000  objects (     0.000  retained)
                               1.000  strings (     0.000  retained)
      ```
    
      ```
      Calculating -------------------------------------
                     mixed     3.541k memsize (     0.000  retained)
                              46.000  objects (     0.000  retained)
                              20.000  strings (     0.000  retained)
         precompiled mixed     1.856k memsize (     0.000  retained)
                              29.000  objects (     0.000  retained)
                              13.000  strings (     0.000  retained)
      ```
    
    This commit also adds `config.precompile_filter_parameters`, which
    enables precompilation of `config.filter_parameters`.  It defaults to
    `true` for `config.load_defaults 7.1` and above.
Loading