From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id DDD391F5AE; Mon, 20 Jul 2020 10:55:38 +0000 (UTC) Date: Mon, 20 Jul 2020 10:55:38 +0000 From: Eric Wong To: Jean Boussier Cc: unicorn-public@yhbt.net Subject: Re: [PATCH] Add early hints support Message-ID: <20200720105538.GA13340@dcvr> References: <058BA238-BEB3-4E54-9DE6-DC59BCB86246@shopify.com> <20200716105037.GA26605@dcvr> <242F0859-0F83-4F14-A0FF-5BE392BB01E6@shopify.com> <20200716121643.GA26942@dcvr> <20200717011955.GA23522@dcvr> <624157B8-884C-42EB-8515-AFC6807D6F8D@shopify.com> <20200720100958.GA7043@dcvr> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: Jean Boussier wrote: > > `match?' is Ruby 2.4+, which is probably too big a jump since > > we're still on Ruby 1.9.3 at the moment... > > That's what I figured. > > > String comparison as in `==' and `!='? Would be interested to know > > where and what improvements can be had. Thanks for the benchmarks. > One place that jumped to mind when I saw it is http_response_write. > But there are many other places where Regexp are used to do case > insensitive comparisons. > > ``` > require 'benchmark/ips' > > def http_response_write(headers) > headers.each do |key, value| > case key > when %r{\A(?:Date|Connection)\z}i > next > end > end > end > > def http_response_write_upcase(headers) > headers.each do |key, value| > case key.upcase > when 'DATE'.freeze, 'CONNECTION'.freeze > next > end > end > end > > def http_response_write_casecmp(headers) > headers.each do |key, value| > case key > when key.casecmp?('Date'.freeze) || key.casecmp?('Connection'.freeze) > next > end > end > end > > HEADERS = { > 'Foo' => 'bar', > 'Date' => 'plop', > 'User-Agent' => 'blah', > } > > Benchmark.ips do |x| > x.report('original') { http_response_write(HEADERS) } > x.report('upcase') { http_response_write_upcase(HEADERS) } > x.report('casecmp?') { http_response_write_casecmp(HEADERS) } > x.compare! > end > ``` > > ``` > Warming up -------------------------------------- > original 82.066k i/100ms > upcase 177.429k i/100ms > casecmp? 96.288k i/100ms > Calculating ------------------------------------- > original 831.610k (± 1.6%) i/s - 4.185M in 5.034146s > upcase 1.770M (± 1.6%) i/s - 8.871M in 5.013796s > casecmp? 979.618k (± 1.3%) i/s - 4.911M in 5.013678s > > Comparison: > upcase: 1769883.2 i/s > casecmp?: 979618.3 i/s - 1.81x (± 0.00) slower > original: 831610.2 i/s - 2.13x (± 0.00) slower > ``` upcase seems VERY compelling in a micro benchmark since it can go straight into opt_case_dispatch. But I worry the extra garbage might have a different effect in a real app, especially with more headers. > Similarly, that method use `value =~ /\n/` which could be replaced > favorably for `value.include?("\n".freeze)` Yes, we tried that a few years ago and broke existing code that had `nil' value, so it was promptly reverted: https://yhbt.net/unicorn-public/CAO47=rJa=zRcLn_Xm4v2cHPr6c0UswaFC_omYFEH+baSxHOWKQ@mail.gmail.com/ Maybe: (val || ''.freeze).include?("\n".freeze) Can work for those buggy apps, though... > ``` > VAL = "foobar" > Benchmark.ips do |x| > x.report('=~') { VAL =~ /\n/ } > x.report('include?') { VAL.include?("\n".freeze) } > x.compare! > end > > Ruby just seems hopeless performance-wise > > Well, the gap between 1.9.3 and 2.5+ is pretty big performance-wise. True, but it's still pretty slow :>