Thanks Claes.  I think there's some room for improvement in the JIT to
piggyback on the user check, but that's a side topic.

Out of curiosity, have you tried moving the slow path (computation of the
hash) into an out-of-line method? What's the bytecode size if you do that?
This shouldn't matter for C2, but I wonder if it may somehow tickle the
JIT/register allocator into better codegen.

On Wed, May 13, 2015 at 9:06 AM, Claes Redestad <claes.redes...@oracle.com>
wrote:

>  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> 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
>>
>> 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/
>>> 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
>>>
>>
>>
>>   --
>> Best regards, Sergey.
>>
>>
>
>

Reply via email to