From b3628f3fcc41e819ef8c1619f78460504b5d6fa2 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 26 Feb 2024 11:22:08 -0600 Subject: [PATCH] Optimize scan_byte and peek_byte A few simple changes: * Fields accessed more than once should be loaded into a local variable (curr, byteList, runtime). * str.getBytes makes a copy of the visible range of the underlying ByteList; use ByteList.get(index) to access directly. Performance is nearly 2x better, mostly because we've eliminated the copy: BEFORE: [] strscan $ jruby -Xcompile.invokedynamic -Ilib -rstrscan -rbenchmark -e 'ss = StringScanner.new("x"); 10.times { puts Benchmark.measure { i = 0; while i < 100_000_000; i+=1; ss.peek_byte; end } }' 1.870000 0.080000 1.950000 ( 1.393004) 1.300000 0.020000 1.320000 ( 1.221120) 1.210000 0.000000 1.210000 ( 1.201006) 1.220000 0.010000 1.230000 ( 1.188845) 1.240000 0.000000 1.240000 ( 1.226052) 1.230000 0.010000 1.240000 ( 1.203179) 1.490000 0.000000 1.490000 ( 1.254489) 1.230000 0.010000 1.240000 ( 1.218346) 1.230000 0.000000 1.230000 ( 1.206789) 1.300000 0.010000 1.310000 ( 1.237078) AFTER: [] strscan $ jruby -Xcompile.invokedynamic -Ilib -rstrscan -rbenchmark -e 'ss = StringScanner.new("x"); 10.times { puts Benchmark.measure { i = 0; while i < 100_000_000; i+=1; ss.peek_byte; end } }' 1.250000 0.080000 1.330000 ( 0.937111) 0.740000 0.000000 0.740000 ( 0.707315) 0.710000 0.010000 0.720000 ( 0.701804) 0.710000 0.000000 0.710000 ( 0.697933) 0.710000 0.000000 0.710000 ( 0.704491) 0.730000 0.010000 0.740000 ( 0.712514) 0.710000 0.000000 0.710000 ( 0.701410) 0.740000 0.000000 0.740000 ( 0.715182) 0.720000 0.010000 0.730000 ( 0.703247) 0.770000 0.000000 0.770000 ( 0.768175) --- .../jruby/ext/strscan/RubyStringScanner.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index df08af63ce..07bb1fa2a4 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -513,26 +513,27 @@ public IRubyObject scan_byte(ThreadContext context) { Ruby runtime = context.runtime; check(context); clearMatched(); - if (curr >= str.getByteList().getRealSize()) return context.nil; - - byte[] bytes = str.getBytes(); + ByteList byteList = str.getByteList(); + int curr = this.curr; + if (curr >= byteList.getRealSize()) return context.nil; - byte bite = bytes[curr]; + int bite = byteList.get(curr); prev = curr; - curr++; + this.curr++; setMatched(); adjustRegisters(); - return RubyFixnum.newFixnum(context.runtime, bite & 0xff); + return RubyFixnum.newFixnum(runtime, bite); } @JRubyMethod(name = "peek_byte") public IRubyObject peek_byte(ThreadContext context) { - Ruby runtime = context.runtime; check(context); - if (curr >= str.getByteList().getRealSize()) return context.nil; + ByteList byteList = str.getByteList(); + int curr = this.curr; + if (curr >= byteList.getRealSize()) return context.nil; - return RubyFixnum.newFixnum(context.runtime, (str.getBytes()[curr]) & 0xff); + return RubyFixnum.newFixnum(context.runtime, byteList.get(curr)); } @JRubyMethod(name = "peek")