I shouldn't have said better. :-)
Running against versions of hashCode using value.length > 0 and h != 0
respectively show results that are within the error range of each other.
It's
hard to quantify the cost of one extra branch in the slow path, I guess.
Checking value.length will only avoid the store for the empty string,
but not for other strings with hash==0. For the empty string, we might
do one extra compare compare/branch every time we call hashCode,
The value.length > 0 check does issue an additional getfield op code for
the slow path, avoiding this can be slightly beneficial in some scenarios
(even though it shouldn't matter much in the final asm).
For reference, this patch (doing if (h != 0) { hash = h; }) nets about a
60x speedup on the micro with -t 32 -p valueString="pollinating sandboxes"
on our multi-socket machines over both the 8058643 implementation
and the one before it.
/Claes
On 2015-05-13 14:53, Vitaly Davidovich wrote:
It's interesting that this version performs as good or *better* than
value.length > 0 check. Intuitively, value.length is going to be used
anyway (if h == 0) in the loop and so there should be no penalty of
loading and branching on it (given the change here has a branch
anyway) and compiler can keep that value in a register for the actual
loop.
Looking at the generated asm for current String.hashCode(), it doesn't
look like compiler is actually using the user-written check to skip
its own check (see the two tests at the bottom of this snippet):
0x00007f7e312a0d8c: mov %rsi,%rbx
0x00007f7e312a0d8f: mov 0x10(%rsi),%eax ;*getfield hash
; -
java.lang.String::hashCode@1 (line 1454)
0x00007f7e312a0d92: test %eax,%eax
0x00007f7e312a0d94: jne 0x00007f7e312a0e85 ;*ifne
; -
java.lang.String::hashCode@6 (line 1455)
0x00007f7e312a0d9a: mov 0xc(%rsi),%ebp ;*getfield value
; -
java.lang.String::hashCode@10 (line 1455)
0x00007f7e312a0d9d: mov 0xc(%r12,%rbp,8),%r10d ;*arraylength
; -
java.lang.String::hashCode@13 (line 1455)
; implicit exception:
dispatches to 0x00007f7e312a0ea9
0x00007f7e312a0da2: test %r10d,%r10d
0x00007f7e312a0da5: jle 0x00007f7e312a0e91 ;*ifle
; -
java.lang.String::hashCode@14 (line 1455)
0x00007f7e312a0dab: test %r10d,%r10d
0x00007f7e312a0dae: jbe 0x00007f7e312a0e95
It does however continue using r10.
On Wed, May 13, 2015 at 8:36 AM, Sergey Bylokhov
<sergey.bylok...@oracle.com <mailto:sergey.bylok...@oracle.com>> wrote:
Just curious, what is the difference between this fix and an old
version of the code:
http://cr.openjdk.java.net/~shade/8058643/webrev.01/src/java.base/share/classes/java/lang/String.java.sdiff.html
<http://cr.openjdk.java.net/%7Eshade/8058643/webrev.01/src/java.base/share/classes/java/lang/String.java.sdiff.html>
I meant:
"if (h == 0 && value.length > 0) {}"
vs
"if (h != 0) {hash = h;}"
On 13.05.15 14:51, Claes Redestad wrote:
Hi,
9-b33 introduced a sustained regression in SPECjvm2008
xml.transform on a number of our test setups.
JDK-8058643 removed the check on value.length > 0, which
means repeated calls to "".hashCode() now do a store of the
calculated value (0) to the hash field. This has potential to
cause excessive cache coherence traffic in xml.transform[1]
Extracting the code that showed up in profiles to a micro[2] and
running this in multiple threads is up to 100x slower in 9-b33 on
a dual-socket machine.
Adding back the check that value.length > 0 before entering the
calculation loop recuperates the loss in both micro and
xml.transform, but we're seeing as good or better number by
simply guarding the store:
Webrev:
http://cr.openjdk.java.net/~redestad/8061254/webrev.00/
<http://cr.openjdk.java.net/%7Eredestad/8061254/webrev.00/>
Bug: https://bugs.openjdk.java.net/browse/JDK-8061254
(confidential
due to links to internal systems, sorry!)
This additionally avoids the field store (and potential for
pointless
cache traffic) also on non-empty strings whose hash value happen
to equals 0.
Thanks!
/Claes
[1] See
com.sun.org.apache.xml.internal.dtm.ref.ExpandedNameTable#getExpandedTypeID.
[2]
http://cr.openjdk.java.net/~redestad/8061254/expandedtypeid-micro.zip
<http://cr.openjdk.java.net/%7Eredestad/8061254/expandedtypeid-micro.zip>
--
Best regards, Sergey.