<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">On Apr 19, 2016, at 10:13 AM, Tobias Hartmann <<a href="mailto:tobias.hartmann@oracle.com" class="">tobias.hartmann@oracle.com</a>> wrote:<br class=""><div><blockquote type="cite" class=""><br class="Apple-interchange-newline"><div class=""><span style="font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Okay, I'll push the basic version.</span><br style="font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 16px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote></div><div class=""><div class=""><br class=""></div><div class="">So I started looking at your code and my inner SPARC junkie took over.</div><div class=""><br class=""></div><div class="">This is what happened:</div><div class="">  <a href="http://cr.openjdk.java.net/~jrose/draft/sparc/6941938/" class="">http://cr.openjdk.java.net/~jrose/draft/sparc/6941938/</a></div><div class=""><br class=""></div><div class="">Perhaps there are some ideas that might be helpful:</div><div class="">- The rampdown logic can lose a couple of instructions by using xorcc and movr.</div><div class="">- It's possible to work with 64-bit loads in more cases (both-odd and one-odd).</div><div class="">- Perhaps the 32-bit version only makes sense for sizes of 16 bytes or less?</div><div class=""><br class=""></div><div class="">On the other hand, what you wrote is nice and simple.</div><div class=""><br class=""></div><div class="">HTH</div><div class="">— John</div><div class=""><br class=""></div><div class="">P.S. On the otherest hand, I wish we could cover the mismatch intrinsic, and more</div><div class="">versions of misalignment, still with vectorization, as with the arraycopy stubs.</div><div class="">But that's neither nice nor simple.</div><br class=""><div><blockquote type="cite" class=""><div class="">On Apr 19, 2016, at 10:13 AM, Tobias Hartmann <<a href="mailto:tobias.hartmann@oracle.com" class="">tobias.hartmann@oracle.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">Thanks, Vladimir!<br class=""><br class="">On 19.04.2016 18:06, Vladimir Kozlov wrote:<br class=""><blockquote type="cite" class="">Very good. Go with basic. We can do SPU special improvements later if needed.<br class=""></blockquote><br class="">Okay, I'll push the basic version.<br class=""><br class="">For reference, here are the results on a SPARC T4:<br class=""><a href="http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/byte_equal_basic_T4.png" class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/byte_equal_basic_T4.png</a><br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/byte_unequal_basic_T4.png<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/char_equal_basic_T4.png<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/char_unequal_basic_T4.png<br class=""><br class=""><blockquote type="cite" class="">"I also noticed that we don't use prefetching for arraycopy and other intrinsics on SPARC."<br class="">We do have arraycopy code for it but by default we don't use it:<br class=""> product(uintx,  ArraycopySrcPrefetchDistance, 0,<br class=""> product(uintx,  ArraycopyDstPrefetchDistance, 0,<br class=""><br class="">Experiments back then did not show improvement on JBB benchmarks but some workloads may have benefit. that is why we keep the code.<br class=""></blockquote><br class="">Right but currently it's not possible to enable prefetching, because "ArraycopySrcPrefetchDistanceConstraintFunc" enforces the prefetch distance to be 0:<br class=""><br class="">java -XX:ArraycopySrcPrefetchDistance=42 -version<br class="">ArraycopySrcPrefetchDistance (42) must be 0<br class="">Error: Could not create the Java Virtual Machine.<br class="">Error: A fatal exception has occurred. Program will exit<br class=""><br class="">Thanks,<br class="">Tobias<br class=""><br class=""><blockquote type="cite" class=""><br class="">Thanks,<br class="">Vladimir<br class=""><br class="">On 4/19/16 5:35 AM, Tobias Hartmann wrote:<br class=""><blockquote type="cite" class="">Hi,<br class=""><br class="">please review the following enhancement:<br class="">https://bugs.openjdk.java.net/browse/JDK-6941938<br class=""><br class="">MacroAssembler::array_equals() currently emits a 4-byte array comparison loop on SPARC but we can do a 8-byte comparison if the array addresses are doubleword aligned. The intrinsic is used for byte/char Arrays.equals() and String.equals().<br class=""><br class="">I added the method MacroAssembler::array_equals_loop() that loads and compares array elements of size 'byte_width' until the elements are not equal or we reached the end of the arrays. Instead of first comparing trailing characters if the array sizes are not a multiple of 'byte_width', we simply read over the end of the arrays, bail out and compare the remaining elements by shifting out the garbage bits.<br class=""><br class="">We use a width of 8 bytes if the array addresses are doubleword aligned, or fall back to 4 bytes if they are only word aligned (which is always guaranteed). I also refactored MacroAssembler::string_compare() to use load_sized_value().<br class=""><br class="">Performance evaluation showed an improvement of up to 65% with the microbenchmarks on a SPARC M7. I used a slightly modified version of the "EqualsBench" [1] from Aleksey's compact string microbenchmark suite [2] that exercises the intrinsic on two equal/unequal char/byte arrays. Larger benchmarks (SPECjbb, SPECjvm) show no significant difference in performance.<br class=""><br class="">I evaluated the following three versions of the patch.<br class=""><br class="">-- Basic --<br class="">http://cr.openjdk.java.net/~thartmann/6941938/webrev.basic/<br class="">The basic version implements the algorithm described above. Microbenchmark evaluation [3] shows a great improvement for all array sizes except for size 16 where the performance suddenly drops: http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/char_equal_basic.png<br class=""><br class="">I figured out that this is due to caching. It seems that with 8 byte steps, the processor notices later in the loop that we are going to access the subsequent array elements, causing the reads to trigger costly cache misses that degrade overall performance. With 4 byte reads, fetching is triggered earlier and the subsequent reads are very fast. I executed the same benchmark on a SPARC T4 and there is no performance problem. Version "prefetching" tries to improve this.<br class=""><br class="">There is also a regression for sizes 1 and 2 if the arrays are not equal because the baseline version explicitly checks those sizes before the loop: http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/char_unequal_basic.png<br class="">Version "small" tries to improve this.<br class=""><br class="">-- Prefetching --<br class="">http://cr.openjdk.java.net/~thartmann/6941938/webrev.prefetch/<br class="">This version adds explicit prefetching before the loop to make sure the first array elements are always in the cache. This helps to avoid the cache misses with 16 bytes: http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/byte_unequal_prefetch.png<br class=""><br class="">However, prefetching negatively affects overall performance in the other cases (see [4]). Zoltan suggested that this may be because software prefetching temporarily disables or affects the hardware prefetcher. I also experimented with adding incremental prefetching to the loop body but this does not improve performance.<br class=""><br class="">-- Small --<br class="">http://cr.openjdk.java.net/~thartmann/6941938/webrev.small/<br class="">This version includes special handling of arrays of size <= 4 by emitting a single load without a loop and the corresponding checks. Performance evaluation showed that this does not pay off because the additional check induces an overhead for small arrays > 4 elements (see sheet "small arrays").<br class=""><br class="">The numbers can be found here:<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/microbenchmark_results_6941938.xlsx<br class=""><br class="">I would prefer to use the basic version because explicit prefetching is highly dependent on the processor and behavior may change. I also noticed that we don't use prefetching for arraycopy and other intrinsics on SPARC.<br class=""><br class="">What do you think?<br class=""><br class="">Tested with all hotspot tests on RBT (-Xmixed/-Xcomp). Links are attached to the bug.<br class=""><br class="">Thanks,<br class="">Tobias<br class=""><br class="">[1] https://bugs.openjdk.java.net/secure/attachment/58697/EqualsBench.java<br class="">[2] http://cr.openjdk.java.net/~shade/density/string-density-bench.zip<br class="">[3] Microbenchmark results for the "basic" implementation<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/byte_equal_basic.png<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/byte_unequal_basic.png<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/char_unequal_basic.png<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/char_equal_basic.png<br class="">[4] Microbenchmark results for the "prefetching" implementation<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/byte_equal_prefetch.png<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/byte_unequal_prefetch.png<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/char_equal_prefetch.png<br class="">http://cr.openjdk.java.net/~thartmann/6941938/benchmarks/char_unequal_prefetch.png<br class=""><br class=""></blockquote></blockquote></div></blockquote></div></div></body></html>