RFR: 8294432: Add provisions to calculate hash values from MemorySegments

Maurizio Cimadamore mcimadamore at openjdk.org
Wed Nov 27 11:24:44 UTC 2024


On Mon, 25 Nov 2024 15:27:13 GMT, Per Minborg <pminborg at openjdk.org> wrote:

> This PR proposes adding a _JDK-internal_ method for calculating hash codes for content in a `MemorySegment`.
> 
> The internal method uses a polynomial 32-bit hash function equivalent to `Arrays::hashCode`. The new method is almost two times faster than naïvely iterating over individual bytes for larger regions. Also, it is more lean on inlining space compared to a naïve loop.
> 
> 
> 
> Benchmark                          (ELEM_SIZE)  Mode  Cnt   Score   Error  Units
> SegmentBulkHash.array                        8  avgt   30   2.645 ? 0.078  ns/op
> SegmentBulkHash.array                       64  avgt   30   6.062 ? 0.171  ns/op
> SegmentBulkHash.heapSegment                  8  avgt   30   4.181 ? 0.145  ns/op
> SegmentBulkHash.heapSegment                 64  avgt   30  25.716 ? 1.043  ns/op
> SegmentBulkHash.nativeSegment                8  avgt   30   3.939 ? 0.150  ns/op
> SegmentBulkHash.nativeSegment               64  avgt   30  23.262 ? 0.694  ns/op
> SegmentBulkHash.nativeSegmentJava            8  avgt   30   5.219 ? 0.183  ns/op    <- Naïve iteration
> SegmentBulkHash.nativeSegmentJava           64  avgt   30  39.668 ? 1.040  ns/op    <- Naïve iteration
> 
> 
> ![image](https://github.com/user-attachments/assets/5646cf21-b202-4dce-9555-e460f9df4cb6)
> 
> 
> If internal JDK code uses this method, it will automatically benefit from future performance improvements that can be implemented once the Vector API becomes available.

src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java line 210:

> 208:             long val = SCOPED_MEMORY_ACCESS.getLongUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + fromOffset, !Architecture.isLittleEndian());
> 209:             result = result * POWERS_OF_31[7]
> 210:                     + ((byte) (val >>> 56)) * POWERS_OF_31[6]

I've manually checked the unrolling, and it seems correct

test/jdk/java/foreign/TestSegmentBulkOperationsContentHash.java line 49:

> 47: import static org.junit.jupiter.api.Assertions.*;
> 48: 
> 49: final class TestSegmentBulkOperationsContentHash {

Should we add a test which checks that the result of the content hash is the same as the polynomial described in the javadoc?

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/22364#discussion_r1860486592
PR Review Comment: https://git.openjdk.org/jdk/pull/22364#discussion_r1860485622


More information about the core-libs-dev mailing list