Integrated: 8302863: Speed up String::encodeASCII using countPositives

2023-02-21 Thread Claes Redestad
On Sat, 18 Feb 2023 23:26:08 GMT, Claes Redestad  wrote:

> When encoding Strings to US-ASCII we can speed up the happy path 
> significantly by using `StringCoding.countPositives` as a speculative check 
> for whether there are any chars that needs to be replaced by `'?'`. Once a 
> non-ASCII char is encountered we fall back to the slow loop and replace as 
> needed.
> 
> An alternative could be unrolling or using a byte array VarHandle, as 
> show-cased by Brett Okken here: 
> https://mail.openjdk.org/pipermail/core-libs-dev/2023-February/100573.html 
> Having to replace chars with `?` is essentially an encoding error so it might 
> be safe to assume this case is exceptional in practice.

This pull request has now been integrated.

Changeset: 92dfa117
Author:Claes Redestad 
URL:   
https://git.openjdk.org/jdk/commit/92dfa1175e4898fc491115e004380780b6862473
Stats: 24 lines in 1 file changed: 11 ins; 2 del; 11 mod

8302863: Speed up String::encodeASCII using countPositives

Reviewed-by: alanb

-

PR: https://git.openjdk.org/jdk/pull/12640


Re: RFR: 8302863: Speed up String::encodeASCII using countPositives

2023-02-21 Thread Claes Redestad
On Mon, 20 Feb 2023 21:40:41 GMT, Brett Okken  wrote:

>> When encoding Strings to US-ASCII we can speed up the happy path 
>> significantly by using `StringCoding.countPositives` as a speculative check 
>> for whether there are any chars that needs to be replaced by `'?'`. Once a 
>> non-ASCII char is encountered we fall back to the slow loop and replace as 
>> needed.
>> 
>> An alternative could be unrolling or using a byte array VarHandle, as 
>> show-cased by Brett Okken here: 
>> https://mail.openjdk.org/pipermail/core-libs-dev/2023-February/100573.html 
>> Having to replace chars with `?` is essentially an encoding error so it 
>> might be safe to assume this case is exceptional in practice.
>
> For the happy path of no encoding failures, this "trivial" change is a great 
> improvement.

Thanks for reviewing - and thanks @bokken for inspiring this change.

-

PR: https://git.openjdk.org/jdk/pull/12640


Re: RFR: 8302863: Speed up String::encodeASCII using countPositives

2023-02-20 Thread Brett Okken
On Sat, 18 Feb 2023 23:26:08 GMT, Claes Redestad  wrote:

> When encoding Strings to US-ASCII we can speed up the happy path 
> significantly by using `StringCoding.countPositives` as a speculative check 
> for whether there are any chars that needs to be replaced by `'?'`. Once a 
> non-ASCII char is encountered we fall back to the slow loop and replace as 
> needed.
> 
> An alternative could be unrolling or using a byte array VarHandle, as 
> show-cased by Brett Okken here: 
> https://mail.openjdk.org/pipermail/core-libs-dev/2023-February/100573.html 
> Having to replace chars with `?` is essentially an encoding error so it might 
> be safe to assume this case is exceptional in practice.

For the happy path of no encoding failures, this "trivial" change is a great 
improvement.

-

Marked as reviewed by bok...@github.com (no known OpenJDK username).

PR: https://git.openjdk.org/jdk/pull/12640


Re: RFR: 8302863: Speed up String::encodeASCII using countPositives

2023-02-20 Thread Alan Bateman
On Sat, 18 Feb 2023 23:26:08 GMT, Claes Redestad  wrote:

> When encoding Strings to US-ASCII we can speed up the happy path 
> significantly by using `StringCoding.countPositives` as a speculative check 
> for whether there are any chars that needs to be replaced by `'?'`. Once a 
> non-ASCII char is encountered we fall back to the slow loop and replace as 
> needed.
> 
> An alternative could be unrolling or using a byte array VarHandle, as 
> show-cased by Brett Okken here: 
> https://mail.openjdk.org/pipermail/core-libs-dev/2023-February/100573.html 
> Having to replace chars with `?` is essentially an encoding error so it might 
> be safe to assume this case is exceptional in practice.

Marked as reviewed by alanb (Reviewer).

-

PR: https://git.openjdk.org/jdk/pull/12640


Re: RFR: 8302863: Speed up String::encodeASCII using countPositives

2023-02-20 Thread Claes Redestad
On Sat, 18 Feb 2023 23:26:08 GMT, Claes Redestad  wrote:

> When encoding Strings to US-ASCII we can speed up the happy path 
> significantly by using `StringCoding.countPositives` as a speculative check 
> for whether there are any chars that needs to be replaced by `'?'`. Once a 
> non-ASCII char is encountered we fall back to the slow loop and replace as 
> needed.
> 
> An alternative could be unrolling or using a byte array VarHandle, as 
> show-cased by Brett Okken here: 
> https://mail.openjdk.org/pipermail/core-libs-dev/2023-February/100573.html 
> Having to replace chars with `?` is essentially an encoding error so it might 
> be safe to assume this case is exceptional in practice.

Baseline:

Benchmark  (charsetName)  Mode  Cnt  Score Error  
Units
StringEncode.encodeAsciiLongUS-ASCII  avgt5  26626,025 ± 448,307  
ns/op
StringEncode.encodeAsciiShort   US-ASCII  avgt5 33,336 ±   2,032  
ns/op


Patch:

Benchmark  (charsetName)  Mode  Cnt ScoreError  
Units
StringEncode.encodeAsciiLongUS-ASCII  avgt5  5492,985 ± 40,066  
ns/op
StringEncode.encodeAsciiShort   US-ASCII  avgt528,545 ±  4,883  
ns/op

-

PR: https://git.openjdk.org/jdk/pull/12640


Re: RFR: 8302863: Speed up String::encodeASCII using countPositives

2023-02-20 Thread Claes Redestad
On Sun, 19 Feb 2023 07:24:30 GMT, David Schlosnagle  wrote:

>> When encoding Strings to US-ASCII we can speed up the happy path 
>> significantly by using `StringCoding.countPositives` as a speculative check 
>> for whether there are any chars that needs to be replaced by `'?'`. Once a 
>> non-ASCII char is encountered we fall back to the slow loop and replace as 
>> needed.
>> 
>> An alternative could be unrolling or using a byte array VarHandle, as 
>> show-cased by Brett Okken here: 
>> https://mail.openjdk.org/pipermail/core-libs-dev/2023-February/100573.html 
>> Having to replace chars with `?` is essentially an encoding error so it 
>> might be safe to assume this case is exceptional in practice.
>
> src/java.base/share/classes/java/lang/String.java line 976:
> 
>> 974: private static byte[] encodeASCII(byte coder, byte[] val) {
>> 975: if (coder == LATIN1) {
>> 976: byte[] dst = Arrays.copyOf(val, val.length);
> 
> Given the tweaks in https://git.openjdk.org/jdk/pull/12613 should this use 
> `val.clone()` (would skip the length check)
> 
> Suggestion:
> 
> byte[] dst = val.clone();

Yeah, probably makes sense. On that note I found that `val.clone()` 
underperform `Arrays.copyOf(val, val.length)` in C1 compiled code: 
https://bugs.openjdk.org/browse/JDK-8302850 - while this shouldn't affect peak 
performance it might be cause for a warmup regression.

> src/java.base/share/classes/java/lang/String.java line 982:
> 
>> 980: if (dst[i] < 0) {
>> 981: dst[i] = '?';
>> 982: }
> 
> I'm curious if using countPositives (and vectorization) to scan forward would 
> be valuable for long (mostly ASCII) strings or if the method call 
> overhead/non-constant stride is not a win for shorter strings or heavily 
> non-ascii inputs. 
> 
> Suggestion:
> 
> for (int i = positives; i < dst.length; i = 
> StringCoding.countPositives(dst, i + 1, dst.length - i);) {
> if (dst[i] < 0) {
> dst[i] = '?';
> }

There's some overhead doing countPositives calls, and doing it in a loop might 
provoke poor worst case performance. Im sure you can find inputs for which this 
is a win, though.

-

PR: https://git.openjdk.org/jdk/pull/12640


RFR: 8302863: Speed up String::encodeASCII using countPositives

2023-02-20 Thread Claes Redestad
When encoding Strings to US-ASCII we can speed up the happy path significantly 
by using `StringCoding.countPositives` as a speculative check for whether there 
are any chars that needs to be replaced by `'?'`. Once a non-ASCII char is 
encountered we fall back to the slow loop and replace as needed.

An alternative could be unrolling or using a byte array VarHandle, as 
show-cased by Brett Okken here: 
https://mail.openjdk.org/pipermail/core-libs-dev/2023-February/100573.html 
Having to replace chars with `?` is essentially an encoding error so it might 
be safe to assume this case is exceptional in practice.

-

Commit messages:
 - Cleanup, clone
 - Merge branch 'master' into encodeASCII
 - Improve encodeASCII by leveraging countPositives

Changes: https://git.openjdk.org/jdk/pull/12640/files
 Webrev: https://webrevs.openjdk.org/?repo=jdk=12640=00
  Issue: https://bugs.openjdk.org/browse/JDK-8302863
  Stats: 24 lines in 1 file changed: 11 ins; 2 del; 11 mod
  Patch: https://git.openjdk.org/jdk/pull/12640.diff
  Fetch: git fetch https://git.openjdk.org/jdk pull/12640/head:pull/12640

PR: https://git.openjdk.org/jdk/pull/12640


Re: RFR: 8302863: Speed up String::encodeASCII using countPositives

2023-02-20 Thread David Schlosnagle
On Sat, 18 Feb 2023 23:26:08 GMT, Claes Redestad  wrote:

> When encoding Strings to US-ASCII we can speed up the happy path 
> significantly by using `StringCoding.countPositives` as a speculative check 
> for whether there are any chars that needs to be replaced by `'?'`. Once a 
> non-ASCII char is encountered we fall back to the slow loop and replace as 
> needed.
> 
> An alternative could be unrolling or using a byte array VarHandle, as 
> show-cased by Brett Okken here: 
> https://mail.openjdk.org/pipermail/core-libs-dev/2023-February/100573.html 
> Having to replace chars with `?` is essentially an encoding error so it might 
> be safe to assume this case is exceptional in practice.

src/java.base/share/classes/java/lang/String.java line 976:

> 974: private static byte[] encodeASCII(byte coder, byte[] val) {
> 975: if (coder == LATIN1) {
> 976: byte[] dst = Arrays.copyOf(val, val.length);

Given the tweaks in https://git.openjdk.org/jdk/pull/12613 should this use 
`val.clone()` (would skip the length check)

Suggestion:

byte[] dst = val.clone();

src/java.base/share/classes/java/lang/String.java line 982:

> 980: if (dst[i] < 0) {
> 981: dst[i] = '?';
> 982: }

I'm curious if using countPositives (and vectorization) to scan forward would 
be valuable for long (mostly ASCII) strings or if the method call 
overhead/non-constant stride is not a win for shorter strings or heavily 
non-ascii inputs. 

Suggestion:

for (int i = positives; i < dst.length; i = 
StringCoding.countPositives(dst, i + 1, dst.length - i);) {
if (dst[i] < 0) {
dst[i] = '?';
}

-

PR: https://git.openjdk.org/jdk/pull/12640


Re: String encodeASCII

2023-02-20 Thread Claes Redestad
Unsafe might be similarly tricky dependency-wise, but perhaps less so. Either 
solution might work fine if we extract the code for encoding to a utility class 
that isn’t initialized eagerly with String.class itself.

I’ll file an RFE and get the ”trivial” fix to use StringCoding.countPositives 
in to establish a better baseline. I’m sure there are ways to beat this, for 
example with a fused loop. An unrolled and/or VH-based solution like you’ve 
proposed could at the very least be used to speedup the case of Strings for 
which we need to replace with ’?’.

/Claes

19 feb. 2023 kl. 02:54 skrev Brett Okken 
mailto:brett.okken...@gmail.com>>:

Thanks for taking a look at this.
That is a pretty good improvement with a much smaller change.
I recognize the intricacies of bootstrapping, but have no expertise. Would 
using Unsafe directly be easier? Particularly for shorter strings, doing the 
copying and checking together rather than as separate loops seems to speed 
things up considerably, even for happy-path of no failures.

Brett

On Sat, Feb 18, 2023 at 5:49 PM Claes Redestad 
mailto:claes.redes...@oracle.com>> wrote:
Hi,

general comment: String might be one of the trickier places to add a VarHandle 
dependency, since String is used very early in the bootstrap and depended upon 
by everything else, so I’d expect such a solution would have to navigate 
potential circularity issues carefully. It’d be good to experiment with changes 
to java.lang.String proper to see that the solution that works nice externally 
is or can be made feasible within String.

Specifically on the performance opportunity then while US-ASCII encoding is 
probably on the way out we shouldn’t neglect it.

One way to go about this without pulling VarHandles into String might be to use 
what other encode methods in String does and leverage 
StringCoding.countPositives:

https://github.com/openjdk/jdk/pull/12640

Testing this on the existing StringEncode microbenchmark, shows a promising 
speed-up when the input is ASCII-encodable:

Baseline
Benchmark  (charsetName)  Mode  Cnt  Score Error  
Units
StringEncode.encodeAsciiLongUS-ASCII  avgt5  26626,025 ± 448,307  
ns/op
StringEncode.encodeAsciiShort   US-ASCII  avgt5 33,336 ±   2,032  
ns/op

Patch:
Benchmark  (charsetName)  Mode  Cnt ScoreError  
Units
StringEncode.encodeAsciiLongUS-ASCII  avgt5  5492,985 ± 40,066  
ns/op
StringEncode.encodeAsciiShort   US-ASCII  avgt528,545 ±  4,883  
ns/op

(You might see that this will go back into a scalar loop on encoding failures. 
That loop could still benefit from unrolling or byteArrayViewVarHandle, but I 
think you have a bigger problem in an app than raw performance if you have a 
lot of encoding failures...)

WDYT?

/Claes

18 feb. 2023 kl. 19:36 skrev Brett Okken 
mailto:brett.okken...@gmail.com>>:

https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/String.java#L976-L981

For String.encodeASCII, with the LATIN1 coder is there any interest in
exploring the performance impacts of utilizing a
byteArrayViewVarHandle to read/write as longs and utilize a bitmask to
identify if negative values are present?

A simple jmh benchmark covering either 0 or 1 non-ascii (negative)
values shows times cut in half (or more) for most scenarios with
strings ranging in length from 3 - ~2000.
VM version: JDK 17.0.6, OpenJDK 64-Bit Server VM, 17.0.6+10
Windows 10 Intel(R) Core(TM) i7-9850H

Hand unrolling the loops shows noted improvement, but does make for
less aesthetically pleasing code.


Benchmark  (nonascii)  (size)  Mode
CntScore Error  Units
AsciiEncodeBenchmark.jdk none   3  avgt
4   15.531 ±   1.122  ns/op
AsciiEncodeBenchmark.jdk none  10  avgt
4   17.350 ±   0.473  ns/op
AsciiEncodeBenchmark.jdk none  16  avgt
4   18.277 ±   0.421  ns/op
AsciiEncodeBenchmark.jdk none  23  avgt
4   20.139 ±   0.350  ns/op
AsciiEncodeBenchmark.jdk none  33  avgt
4   22.008 ±   0.656  ns/op
AsciiEncodeBenchmark.jdk none  42  avgt
4   24.393 ±   1.155  ns/op
AsciiEncodeBenchmark.jdk none 201  avgt
4   55.884 ±   0.645  ns/op
AsciiEncodeBenchmark.jdk none 511  avgt
4  120.817 ±   2.917  ns/op
AsciiEncodeBenchmark.jdk none2087  avgt
4 

Re: String encodeASCII

2023-02-18 Thread Brett Okken
Thanks for taking a look at this.
That is a pretty good improvement with a much smaller change.
I recognize the intricacies of bootstrapping, but have no expertise. Would
using Unsafe directly be easier? Particularly for shorter strings, doing
the copying and checking together rather than as separate loops seems to
speed things up considerably, even for happy-path of no failures.

Brett

On Sat, Feb 18, 2023 at 5:49 PM Claes Redestad 
wrote:

> Hi,
>
> general comment: String might be one of the trickier places to add a
> VarHandle dependency, since String is used very early in the bootstrap and
> depended upon by everything else, so I’d expect such a solution would have
> to navigate potential circularity issues carefully. It’d be good to
> experiment with changes to java.lang.String proper to see that the solution
> that works nice externally is or can be made feasible within String.
>
> Specifically on the performance opportunity then while US-ASCII encoding
> is probably on the way out we shouldn’t neglect it.
>
> One way to go about this without pulling VarHandles into String might be
> to use what other encode methods in String does and leverage
> StringCoding.countPositives:
>
> https://github.com/openjdk/jdk/pull/12640
>
> Testing this on the existing StringEncode microbenchmark, shows a
> promising speed-up when the input is ASCII-encodable:
>
> Baseline
> Benchmark  (charsetName)  Mode  Cnt  Score
> Error  Units
> StringEncode.encodeAsciiLongUS-ASCII  avgt5  26626,025 ±
> 448,307  ns/op
> StringEncode.encodeAsciiShort   US-ASCII  avgt5 33,336 ±
> 2,032  ns/op
>
> Patch:
> Benchmark  (charsetName)  Mode  Cnt ScoreError
>  Units
> StringEncode.encodeAsciiLongUS-ASCII  avgt5  5492,985 ± 40,066
>  ns/op
> StringEncode.encodeAsciiShort   US-ASCII  avgt528,545 ±  4,883
>  ns/op
>
> (You might see that this will go back into a scalar loop on encoding
> failures. That loop could still benefit from unrolling or
> byteArrayViewVarHandle, but I think you have a bigger problem in an app
> than raw performance if you have a lot of encoding failures...)
>
> WDYT?
>
> /Claes
>
> 18 feb. 2023 kl. 19:36 skrev Brett Okken :
>
>
> https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/String.java#L976-L981
>
> For String.encodeASCII, with the LATIN1 coder is there any interest in
> exploring the performance impacts of utilizing a
> byteArrayViewVarHandle to read/write as longs and utilize a bitmask to
> identify if negative values are present?
>
> A simple jmh benchmark covering either 0 or 1 non-ascii (negative)
> values shows times cut in half (or more) for most scenarios with
> strings ranging in length from 3 - ~2000.
> VM version: JDK 17.0.6, OpenJDK 64-Bit Server VM, 17.0.6+10
> Windows 10 Intel(R) Core(TM) i7-9850H
>
> Hand unrolling the loops shows noted improvement, but does make for
> less aesthetically pleasing code.
>
>
> Benchmark  (nonascii)  (size)  Mode
> CntScore Error  Units
> AsciiEncodeBenchmark.jdk none   3  avgt
> 4   15.531 ±   1.122  ns/op
> AsciiEncodeBenchmark.jdk none  10  avgt
> 4   17.350 ±   0.473  ns/op
> AsciiEncodeBenchmark.jdk none  16  avgt
> 4   18.277 ±   0.421  ns/op
> AsciiEncodeBenchmark.jdk none  23  avgt
> 4   20.139 ±   0.350  ns/op
> AsciiEncodeBenchmark.jdk none  33  avgt
> 4   22.008 ±   0.656  ns/op
> AsciiEncodeBenchmark.jdk none  42  avgt
> 4   24.393 ±   1.155  ns/op
> AsciiEncodeBenchmark.jdk none 201  avgt
> 4   55.884 ±   0.645  ns/op
> AsciiEncodeBenchmark.jdk none 511  avgt
> 4  120.817 ±   2.917  ns/op
> AsciiEncodeBenchmark.jdk none2087  avgt
> 4  471.039 ±  13.329  ns/op
> AsciiEncodeBenchmark.jdkfirst   3  avgt
> 4   15.794 ±   1.494  ns/op
> AsciiEncodeBenchmark.jdkfirst  10  avgt
> 4   18.446 ±   0.780  ns/op
> AsciiEncodeBenchmark.jdkfirst  16  avgt
> 4   20.458 ±   0.394  ns/op
> AsciiEncodeBenchmark.jdkfirst  23  avgt
> 4   22.934 ±   0.422  ns/op
> AsciiEncodeBenchmark.jdkfirst  33  avgt
> 4   25.367 ±   0.178  ns/op
> AsciiEncodeBenchmark.jdkfirst  42  avgt
> 4   28.620 ±   0.678  ns/op
> AsciiEncodeBenchmark.jdkfirst 201  avgt
> 4   80.250 ±   4.376  ns/op
> AsciiEncodeBenchmark.jdkfirst 511  avgt
> 4  185.518 ±   6.370  ns/op
> AsciiEncodeBenchmark.jdkfirst2087  avgt
> 4  713.213 ±  13.488  ns/op
> AsciiEncodeBenchmark.jdk last   3  avgt
> 4   14.991 ±   0.190  

Re: String encodeASCII

2023-02-18 Thread Claes Redestad
Hi,

general comment: String might be one of the trickier places to add a VarHandle 
dependency, since String is used very early in the bootstrap and depended upon 
by everything else, so I’d expect such a solution would have to navigate 
potential circularity issues carefully. It’d be good to experiment with changes 
to java.lang.String proper to see that the solution that works nice externally 
is or can be made feasible within String.

Specifically on the performance opportunity then while US-ASCII encoding is 
probably on the way out we shouldn’t neglect it.

One way to go about this without pulling VarHandles into String might be to use 
what other encode methods in String does and leverage 
StringCoding.countPositives:

https://github.com/openjdk/jdk/pull/12640

Testing this on the existing StringEncode microbenchmark, shows a promising 
speed-up when the input is ASCII-encodable:

Baseline
Benchmark  (charsetName)  Mode  Cnt  Score Error  
Units
StringEncode.encodeAsciiLongUS-ASCII  avgt5  26626,025 ± 448,307  
ns/op
StringEncode.encodeAsciiShort   US-ASCII  avgt5 33,336 ±   2,032  
ns/op

Patch:
Benchmark  (charsetName)  Mode  Cnt ScoreError  
Units
StringEncode.encodeAsciiLongUS-ASCII  avgt5  5492,985 ± 40,066  
ns/op
StringEncode.encodeAsciiShort   US-ASCII  avgt528,545 ±  4,883  
ns/op

(You might see that this will go back into a scalar loop on encoding failures. 
That loop could still benefit from unrolling or byteArrayViewVarHandle, but I 
think you have a bigger problem in an app than raw performance if you have a 
lot of encoding failures...)

WDYT?

/Claes

18 feb. 2023 kl. 19:36 skrev Brett Okken 
mailto:brett.okken...@gmail.com>>:

https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/String.java#L976-L981

For String.encodeASCII, with the LATIN1 coder is there any interest in
exploring the performance impacts of utilizing a
byteArrayViewVarHandle to read/write as longs and utilize a bitmask to
identify if negative values are present?

A simple jmh benchmark covering either 0 or 1 non-ascii (negative)
values shows times cut in half (or more) for most scenarios with
strings ranging in length from 3 - ~2000.
VM version: JDK 17.0.6, OpenJDK 64-Bit Server VM, 17.0.6+10
Windows 10 Intel(R) Core(TM) i7-9850H

Hand unrolling the loops shows noted improvement, but does make for
less aesthetically pleasing code.


Benchmark  (nonascii)  (size)  Mode
CntScore Error  Units
AsciiEncodeBenchmark.jdk none   3  avgt
4   15.531 ±   1.122  ns/op
AsciiEncodeBenchmark.jdk none  10  avgt
4   17.350 ±   0.473  ns/op
AsciiEncodeBenchmark.jdk none  16  avgt
4   18.277 ±   0.421  ns/op
AsciiEncodeBenchmark.jdk none  23  avgt
4   20.139 ±   0.350  ns/op
AsciiEncodeBenchmark.jdk none  33  avgt
4   22.008 ±   0.656  ns/op
AsciiEncodeBenchmark.jdk none  42  avgt
4   24.393 ±   1.155  ns/op
AsciiEncodeBenchmark.jdk none 201  avgt
4   55.884 ±   0.645  ns/op
AsciiEncodeBenchmark.jdk none 511  avgt
4  120.817 ±   2.917  ns/op
AsciiEncodeBenchmark.jdk none2087  avgt
4  471.039 ±  13.329  ns/op
AsciiEncodeBenchmark.jdkfirst   3  avgt
4   15.794 ±   1.494  ns/op
AsciiEncodeBenchmark.jdkfirst  10  avgt
4   18.446 ±   0.780  ns/op
AsciiEncodeBenchmark.jdkfirst  16  avgt
4   20.458 ±   0.394  ns/op
AsciiEncodeBenchmark.jdkfirst  23  avgt
4   22.934 ±   0.422  ns/op
AsciiEncodeBenchmark.jdkfirst  33  avgt
4   25.367 ±   0.178  ns/op
AsciiEncodeBenchmark.jdkfirst  42  avgt
4   28.620 ±   0.678  ns/op
AsciiEncodeBenchmark.jdkfirst 201  avgt
4   80.250 ±   4.376  ns/op
AsciiEncodeBenchmark.jdkfirst 511  avgt
4  185.518 ±   6.370  ns/op
AsciiEncodeBenchmark.jdkfirst2087  avgt
4  713.213 ±  13.488  ns/op
AsciiEncodeBenchmark.jdk last   3  avgt
4   14.991 ±   0.190  ns/op
AsciiEncodeBenchmark.jdk last  10  avgt
4   18.284 ±   0.317  ns/op
AsciiEncodeBenchmark.jdk last  16  avgt
4   20.591 ±   1.002  ns/op
AsciiEncodeBenchmark.jdk last  23  avgt
4   22.560 ±   0.963  ns/op
AsciiEncodeBenchmark.jdk last  33  avgt
4   25.521 ±   0.554  ns/op
AsciiEncodeBenchmark.jdk last  42  avgt
4   28.484 ±   0.446  ns/op
AsciiEncodeBenchmark.jdk last 201  avgt
4   79.434 ±   2.256  ns/op

String encodeASCII

2023-02-18 Thread Brett Okken
https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/String.java#L976-L981

For String.encodeASCII, with the LATIN1 coder is there any interest in
exploring the performance impacts of utilizing a
byteArrayViewVarHandle to read/write as longs and utilize a bitmask to
identify if negative values are present?

A simple jmh benchmark covering either 0 or 1 non-ascii (negative)
values shows times cut in half (or more) for most scenarios with
strings ranging in length from 3 - ~2000.
VM version: JDK 17.0.6, OpenJDK 64-Bit Server VM, 17.0.6+10
Windows 10 Intel(R) Core(TM) i7-9850H

Hand unrolling the loops shows noted improvement, but does make for
less aesthetically pleasing code.


Benchmark  (nonascii)  (size)  Mode
CntScore Error  Units
AsciiEncodeBenchmark.jdk none   3  avgt
4   15.531 ±   1.122  ns/op
AsciiEncodeBenchmark.jdk none  10  avgt
4   17.350 ±   0.473  ns/op
AsciiEncodeBenchmark.jdk none  16  avgt
4   18.277 ±   0.421  ns/op
AsciiEncodeBenchmark.jdk none  23  avgt
4   20.139 ±   0.350  ns/op
AsciiEncodeBenchmark.jdk none  33  avgt
4   22.008 ±   0.656  ns/op
AsciiEncodeBenchmark.jdk none  42  avgt
4   24.393 ±   1.155  ns/op
AsciiEncodeBenchmark.jdk none 201  avgt
4   55.884 ±   0.645  ns/op
AsciiEncodeBenchmark.jdk none 511  avgt
4  120.817 ±   2.917  ns/op
AsciiEncodeBenchmark.jdk none2087  avgt
4  471.039 ±  13.329  ns/op
AsciiEncodeBenchmark.jdkfirst   3  avgt
4   15.794 ±   1.494  ns/op
AsciiEncodeBenchmark.jdkfirst  10  avgt
4   18.446 ±   0.780  ns/op
AsciiEncodeBenchmark.jdkfirst  16  avgt
4   20.458 ±   0.394  ns/op
AsciiEncodeBenchmark.jdkfirst  23  avgt
4   22.934 ±   0.422  ns/op
AsciiEncodeBenchmark.jdkfirst  33  avgt
4   25.367 ±   0.178  ns/op
AsciiEncodeBenchmark.jdkfirst  42  avgt
4   28.620 ±   0.678  ns/op
AsciiEncodeBenchmark.jdkfirst 201  avgt
4   80.250 ±   4.376  ns/op
AsciiEncodeBenchmark.jdkfirst 511  avgt
4  185.518 ±   6.370  ns/op
AsciiEncodeBenchmark.jdkfirst2087  avgt
4  713.213 ±  13.488  ns/op
AsciiEncodeBenchmark.jdk last   3  avgt
4   14.991 ±   0.190  ns/op
AsciiEncodeBenchmark.jdk last  10  avgt
4   18.284 ±   0.317  ns/op
AsciiEncodeBenchmark.jdk last  16  avgt
4   20.591 ±   1.002  ns/op
AsciiEncodeBenchmark.jdk last  23  avgt
4   22.560 ±   0.963  ns/op
AsciiEncodeBenchmark.jdk last  33  avgt
4   25.521 ±   0.554  ns/op
AsciiEncodeBenchmark.jdk last  42  avgt
4   28.484 ±   0.446  ns/op
AsciiEncodeBenchmark.jdk last 201  avgt
4   79.434 ±   2.256  ns/op
AsciiEncodeBenchmark.jdk last 511  avgt
4  186.639 ±   4.258  ns/op
AsciiEncodeBenchmark.jdk last2087  avgt
4  725.196 ± 149.416  ns/op
AsciiEncodeBenchmark.longCheckCopy   none   3  avgt
47.222 ±   0.428  ns/op
AsciiEncodeBenchmark.longCheckCopy   none  10  avgt
48.070 ±   0.171  ns/op
AsciiEncodeBenchmark.longCheckCopy   none  16  avgt
46.711 ±   0.409  ns/op
AsciiEncodeBenchmark.longCheckCopy   none  23  avgt
4   12.906 ±   3.633  ns/op
AsciiEncodeBenchmark.longCheckCopy   none  33  avgt
4   10.414 ±   0.447  ns/op
AsciiEncodeBenchmark.longCheckCopy   none  42  avgt
4   11.935 ±   1.235  ns/op
AsciiEncodeBenchmark.longCheckCopy   none 201  avgt
4   29.538 ±   3.265  ns/op
AsciiEncodeBenchmark.longCheckCopy   none 511  avgt
4  106.228 ±  68.475  ns/op
AsciiEncodeBenchmark.longCheckCopy   none2087  avgt
4  494.845 ± 890.985  ns/op
AsciiEncodeBenchmark.longCheckCopy  first   3  avgt
47.775 ±   0.278  ns/op
AsciiEncodeBenchmark.longCheckCopy  first  10  avgt
4   13.396 ±   2.072  ns/op
AsciiEncodeBenchmark.longCheckCopy  first  16  avgt
4   13.528 ±   0.702  ns/op
AsciiEncodeBenchmark.longCheckCopy  first  23  avgt
4   17.376 ±   0.360  ns/op
AsciiEncodeBenchmark.longCheckCopy  first  33  avgt
4   16.251 ±   0.203  ns/op
AsciiEncodeBenchmark.longCheckCopy  first  42  avgt
4   17.932 ±   1.773  ns/op
AsciiEncodeBenchmark.longCheckCopy  first 201  avgt
4   39.028 ±   4.699  ns/op
AsciiEncodeBenchmark.longCheckCopy  first