Skip to content

Instantly share code, notes, and snippets.

@naitoh
Created April 16, 2025 20:07
Show Gist options
  • Select an option

  • Save naitoh/234a3cdf994d6d0f67a15f60839cf5f4 to your computer and use it in GitHub Desktop.

Select an option

Save naitoh/234a3cdf994d6d0f67a15f60839cf5f4 to your computer and use it in GitHub Desktop.
$ ruby -v
ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [arm64-darwin24]
$ gem list strscan
*** LOCAL GEMS ***
strscan (default: 3.1.2)
$ benchmark-driver benchmark/rubykaigi_p39_check.yaml
Warming up --------------------------------------
re.match(str) 5.347M i/s - 5.660M times in 1.058437s (187.01ns/i)
s.check(/\w+/) 8.263M i/s - 8.434M times in 1.020708s (121.02ns/i)
s.check("test") 9.621M i/s - 9.923M times in 1.031413s (103.94ns/i)
Calculating -------------------------------------
re.match(str) 5.675M i/s - 16.042M times in 2.826802s (176.21ns/i)
s.check(/\w+/) 8.800M i/s - 24.790M times in 2.816973s (113.63ns/i)
s.check("test") 10.267M i/s - 28.864M times in 2.811429s (97.40ns/i)
Comparison:
s.check("test"): 10266546.7 i/s
s.check(/\w+/): 8800117.4 i/s - 1.17x slower
re.match(str): 5675083.7 i/s - 1.81x slower
$ benchmark-driver benchmark/rubykaigi_p42_match.yaml
Warming up --------------------------------------
re.match?(str) 12.985M i/s - 13.043M times in 1.004457s (77.01ns/i)
StringScanner#match?(/\w+/) 12.430M i/s - 12.726M times in 1.023753s (80.45ns/i)
Calculating -------------------------------------
re.match?(str) 14.707M i/s - 38.956M times in 2.648802s (67.99ns/i)
StringScanner#match?(/\w+/) 14.282M i/s - 37.291M times in 2.611122s (70.02ns/i)
Comparison:
re.match?(str): 14706993.2 i/s
StringScanner#match?(/\w+/): 14281632.2 i/s - 1.03x slower
$ benchmark-driver benchmark/rubykaigi_p51_check_tag_scan.yaml
Warming up --------------------------------------
Regexp 1.181M i/s - 1.285M times in 1.087747s (846.61ns/i)
StringScanner 2.192M i/s - 2.256M times in 1.028952s (456.11ns/i)
Calculating -------------------------------------
Regexp 1.210M i/s - 3.544M times in 2.928038s (826.30ns/i)
StringScanner 2.225M i/s - 6.577M times in 2.956756s (449.53ns/i)
Comparison:
StringScanner: 2224529.5 i/s
Regexp: 1210212.4 i/s - 1.84x slower
$ benchmark-driver benchmark/rubykaigi_p55_scan_until_10_100.yaml
Warming up --------------------------------------
s.pos = 0 and s.skip("<!") and s.skip("[CDATA[") and s.scan_until("]]>").chomp!("]]>") 4.388M i/s - 4.569M times in 1.041343s (227.91ns/i)
t.pos = 0 and t.skip("<!") and t.skip("[CDATA[") and t.scan_until("]]>").chomp!("]]>") 3.385M i/s - 3.534M times in 1.044026s (295.41ns/i)
s.check(/<!\[CDATA\[(.*?)\]\]>/um) and s[1] 3.915M i/s - 4.209M times in 1.075174s (255.43ns/i)
t.check(/<!\[CDATA\[(.*?)\]\]>/um) and s[1] 1.136M i/s - 1.158M times in 1.019305s (879.94ns/i)
md = xml_10.match(/\A<!\[CDATA\[(.*?)\]\]>/um) and md[1] 2.801M i/s - 2.998M times in 1.070313s (356.98ns/i)
md = xml_100.match(/\A<!\[CDATA\[(.*?)\]\]>/um) and md[1] 966.705k i/s - 1.049M times in 1.084774s (1.03μs/i)
Calculating -------------------------------------
s.pos = 0 and s.skip("<!") and s.skip("[CDATA[") and s.scan_until("]]>").chomp!("]]>") 4.513M i/s - 13.163M times in 2.916964s (221.60ns/i)
t.pos = 0 and t.skip("<!") and t.skip("[CDATA[") and t.scan_until("]]>").chomp!("]]>") 3.574M i/s - 10.155M times in 2.841638s (279.82ns/i)
s.check(/<!\[CDATA\[(.*?)\]\]>/um) and s[1] 4.146M i/s - 11.745M times in 2.833134s (241.22ns/i)
t.check(/<!\[CDATA\[(.*?)\]\]>/um) and s[1] 1.137M i/s - 3.409M times in 2.999636s (879.84ns/i)
md = xml_10.match(/\A<!\[CDATA\[(.*?)\]\]>/um) and md[1] 2.856M i/s - 8.404M times in 2.942041s (350.09ns/i)
md = xml_100.match(/\A<!\[CDATA\[(.*?)\]\]>/um) and md[1] 975.608k i/s - 2.900M times in 2.972622s (1.03μs/i)
Comparison:
s.pos = 0 and s.skip("<!") and s.skip("[CDATA[") and s.scan_until("]]>").chomp!("]]>"): 4512653.2 i/s
s.check(/<!\[CDATA\[(.*?)\]\]>/um) and s[1]: 4145534.2 i/s - 1.09x slower
md = xml_10.match(/\A<!\[CDATA\[(.*?)\]\]>/um) and md[1]: 2856436.7 i/s - 1.58x slower
t.pos = 0 and t.skip("<!") and t.skip("[CDATA[") and t.scan_until("]]>").chomp!("]]>"): 3573730.7 i/s - 1.26x slower
t.check(/<!\[CDATA\[(.*?)\]\]>/um) and s[1]: 1136575.9 i/s - 3.97x slower
md = xml_100.match(/\A<!\[CDATA\[(.*?)\]\]>/um) and md[1]: 975607.7 i/s - 4.63x slower
$ benchmark-driver benchmark/rubykaigi_p60_check_space.yaml
Warming up --------------------------------------
s.check(/\s+/um) 6.374M i/s - 6.453M times in 1.012421s (156.90ns/i)
s.match?(/\s+/um) 8.436M i/s - 8.909M times in 1.055988s (118.53ns/i)
Calculating -------------------------------------
s.check(/\s+/um) 6.686M i/s - 19.121M times in 2.859704s (149.56ns/i)
s.match?(/\s+/um) 8.925M i/s - 25.309M times in 2.835913s (112.05ns/i)
Comparison:
s.match?(/\s+/um): 8924590.1 i/s
s.check(/\s+/um): 6686326.3 i/s - 1.33x slower
$ benchmark-driver benchmark/rubykaigi_p62_check_string.yaml
Warming up --------------------------------------
s.check(/<!/um) 10.082M i/s - 10.495M times in 1.040942s (99.18ns/i)
s.match?(/<!/um) 15.963M i/s - 16.579M times in 1.038542s (62.64ns/i)
s.check('<!') 12.612M i/s - 13.223M times in 1.048417s (79.29ns/i)
s.match?('<!') 25.218M i/s - 25.459M times in 1.009555s (39.65ns/i)
Calculating -------------------------------------
s.check(/<!/um) 10.525M i/s - 30.247M times in 2.873949s (95.02ns/i)
s.match?(/<!/um) 18.731M i/s - 47.890M times in 2.556766s (53.39ns/i)
s.check('<!') 14.450M i/s - 37.837M times in 2.618448s (69.20ns/i)
s.match?('<!') 31.900M i/s - 75.653M times in 2.371546s (31.35ns/i)
Comparison:
s.match?('<!'): 31900196.7 i/s
s.match?(/<!/um): 18730840.1 i/s - 1.70x slower
s.check('<!'): 14450157.5 i/s - 2.21x slower
s.check(/<!/um): 10524624.8 i/s - 3.03x slower
$ benchmark-driver benchmark/rubykaigi_p65_peek_byte.yaml
Warming up --------------------------------------
s.check(/(['"])/) 9.423M i/s - 9.550M times in 1.013485s (106.12ns/i)
s.peek_byte 24.472M i/s - 25.087M times in 1.025146s (40.86ns/i)
Calculating -------------------------------------
s.check(/(['"])/) 10.385M i/s - 28.269M times in 2.722173s (96.29ns/i)
s.peek_byte 32.000M i/s - 73.416M times in 2.294275s (31.25ns/i)
Comparison:
s.peek_byte: 31999687.0 i/s
s.check(/(['"])/): 10384796.3 i/s - 3.08x slower
$ benchmark-driver benchmark/rubykaigi_p68_check_until_cache.yaml
Warming up --------------------------------------
s.check_until(scan_reg) 9.034M i/s - 9.071M times in 1.004088s (110.69ns/i)
s.check_until(/#{Regexp.escape("'")}/) 1.371M i/s - 1.491M times in 1.087829s (729.49ns/i)
Calculating -------------------------------------
s.check_until(scan_reg) 9.660M i/s - 27.102M times in 2.805671s (103.52ns/i)
s.check_until(/#{Regexp.escape("'")}/) 1.393M i/s - 4.112M times in 2.951715s (717.74ns/i)
Comparison:
s.check_until(scan_reg): 9659554.9 i/s
s.check_until(/#{Regexp.escape("'")}/): 1393253.8 i/s - 6.93x slower
****
$ git chckout d78118dcfc6c5604dcf8dd5b5d19462993a34c12
$ grep "VERSION =" lib/rexml/rexml.rb
VERSION = "3.2.7-lt"
$ rake build
$ gem install pkg/rexml-3.2.7.pre.lt.gem
$ benchmark-driver benchmark/rubykaigi_p14_parse_all.yaml
Calculating -------------------------------------
rexml 3.2.6 rexml 3.2.7.pre.lt rexml 3.2.7 rexml 3.2.9 rexml 3.4.0 rexml 3.4.1 3.2.6(YJIT) 3.2.7.pre.lt(YJIT) 3.2.7(YJIT) 3.2.9(YJIT) 3.4.0(YJIT) 3.4.1(YJIT)
dom 18.185 20.651 16.599 17.636 18.843 19.467 25.896 34.815 26.797 31.415 31.579 33.928 i/s - 100.000 times in 5.499040s 4.842292s 6.024545s 5.670330s 5.307142s 5.136999s 3.861646s 2.872300s 3.731749s 3.183211s 3.166637s 2.947429s
sax 25.821 30.129 23.239 24.997 28.594 30.209 36.569 55.620 37.652 45.746 50.662 53.175 i/s - 100.000 times in 3.872860s 3.319057s 4.303192s 4.000543s 3.497219s 3.310222s 2.734541s 1.797926s 2.655907s 2.185969s 1.973847s 1.880586s
pull 29.941 34.895 26.478 29.179 33.083 34.366 42.711 69.831 45.819 59.013 59.881 65.892 i/s - 100.000 times in 3.339950s 2.865756s 3.776729s 3.427162s 3.022703s 2.909826s 2.341330s 1.432032s 2.182495s 1.694539s 1.669972s 1.517628s
stream 28.111 34.416 25.769 28.715 32.626 34.250 39.024 61.916 41.705 52.552 57.250 61.869 i/s - 100.000 times in 3.557312s 2.905654s 3.880609s 3.482455s 3.065067s 2.919709s 2.562515s 1.615089s 2.397799s 1.902872s 1.746724s 1.616321s
Comparison:
dom
3.2.7.pre.lt(YJIT): 34.8 i/s
3.4.1(YJIT): 33.9 i/s - 1.03x slower
3.4.0(YJIT): 31.6 i/s - 1.10x slower
3.2.9(YJIT): 31.4 i/s - 1.11x slower
3.2.7(YJIT): 26.8 i/s - 1.30x slower
3.2.6(YJIT): 25.9 i/s - 1.34x slower
rexml 3.2.7.pre.lt: 20.7 i/s - 1.69x slower
rexml 3.4.1: 19.5 i/s - 1.79x slower
rexml 3.4.0: 18.8 i/s - 1.85x slower
rexml 3.2.6: 18.2 i/s - 1.91x slower
rexml 3.2.9: 17.6 i/s - 1.97x slower
rexml 3.2.7: 16.6 i/s - 2.10x slower
sax
3.2.7.pre.lt(YJIT): 55.6 i/s
3.4.1(YJIT): 53.2 i/s - 1.05x slower
3.4.0(YJIT): 50.7 i/s - 1.10x slower
3.2.9(YJIT): 45.7 i/s - 1.22x slower
3.2.7(YJIT): 37.7 i/s - 1.48x slower
3.2.6(YJIT): 36.6 i/s - 1.52x slower
rexml 3.4.1: 30.2 i/s - 1.84x slower
rexml 3.2.7.pre.lt: 30.1 i/s - 1.85x slower
rexml 3.4.0: 28.6 i/s - 1.95x slower
rexml 3.2.6: 25.8 i/s - 2.15x slower
rexml 3.2.9: 25.0 i/s - 2.23x slower
rexml 3.2.7: 23.2 i/s - 2.39x slower
pull
3.2.7.pre.lt(YJIT): 69.8 i/s
3.4.1(YJIT): 65.9 i/s - 1.06x slower
3.4.0(YJIT): 59.9 i/s - 1.17x slower
3.2.9(YJIT): 59.0 i/s - 1.18x slower
3.2.7(YJIT): 45.8 i/s - 1.52x slower
3.2.6(YJIT): 42.7 i/s - 1.63x slower
rexml 3.2.7.pre.lt: 34.9 i/s - 2.00x slower
rexml 3.4.1: 34.4 i/s - 2.03x slower
rexml 3.4.0: 33.1 i/s - 2.11x slower
rexml 3.2.6: 29.9 i/s - 2.33x slower
rexml 3.2.9: 29.2 i/s - 2.39x slower
rexml 3.2.7: 26.5 i/s - 2.64x slower
stream
3.2.7.pre.lt(YJIT): 61.9 i/s
3.4.1(YJIT): 61.9 i/s - 1.00x slower
3.4.0(YJIT): 57.3 i/s - 1.08x slower
3.2.9(YJIT): 52.6 i/s - 1.18x slower
3.2.7(YJIT): 41.7 i/s - 1.48x slower
3.2.6(YJIT): 39.0 i/s - 1.59x slower
rexml 3.2.7.pre.lt: 34.4 i/s - 1.80x slower
rexml 3.4.1: 34.2 i/s - 1.81x slower
rexml 3.4.0: 32.6 i/s - 1.90x slower
rexml 3.2.9: 28.7 i/s - 2.16x slower
rexml 3.2.6: 28.1 i/s - 2.20x slower
rexml 3.2.7: 25.8 i/s - 2.40x slower
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment