mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8345465: Fix performance regression on x64 after JDK-8345120
Reviewed-by: mcimadamore
This commit is contained in:
parent
2979806c72
commit
06c44dd568
2 changed files with 29 additions and 24 deletions
|
@ -130,8 +130,8 @@ public final class StringSupport {
|
||||||
final long toOffset) {
|
final long toOffset) {
|
||||||
final long length = toOffset - fromOffset;
|
final long length = toOffset - fromOffset;
|
||||||
segment.checkBounds(fromOffset, length);
|
segment.checkBounds(fromOffset, length);
|
||||||
if (length == 0) {
|
if (length < Byte.BYTES) {
|
||||||
// The state has to be checked explicitly for zero-length segments
|
// There can be no null terminator present
|
||||||
segment.scope.checkValidState();
|
segment.scope.checkValidState();
|
||||||
throw nullNotFound(segment, fromOffset, toOffset);
|
throw nullNotFound(segment, fromOffset, toOffset);
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,8 @@ public final class StringSupport {
|
||||||
final long toOffset) {
|
final long toOffset) {
|
||||||
final long length = toOffset - fromOffset;
|
final long length = toOffset - fromOffset;
|
||||||
segment.checkBounds(fromOffset, length);
|
segment.checkBounds(fromOffset, length);
|
||||||
if (length == 0) {
|
if (length < Short.BYTES) {
|
||||||
|
// There can be no null terminator present
|
||||||
segment.scope.checkValidState();
|
segment.scope.checkValidState();
|
||||||
throw nullNotFound(segment, fromOffset, toOffset);
|
throw nullNotFound(segment, fromOffset, toOffset);
|
||||||
}
|
}
|
||||||
|
@ -199,13 +200,16 @@ public final class StringSupport {
|
||||||
final long toOffset) {
|
final long toOffset) {
|
||||||
final long length = toOffset - fromOffset;
|
final long length = toOffset - fromOffset;
|
||||||
segment.checkBounds(fromOffset, length);
|
segment.checkBounds(fromOffset, length);
|
||||||
if (length == 0) {
|
if (length < Integer.BYTES) {
|
||||||
|
// There can be no null terminator present
|
||||||
segment.scope.checkValidState();
|
segment.scope.checkValidState();
|
||||||
throw nullNotFound(segment, fromOffset, toOffset);
|
throw nullNotFound(segment, fromOffset, toOffset);
|
||||||
}
|
}
|
||||||
|
long offset = fromOffset;
|
||||||
|
// For quad byte strings, it does not pay off to use long scanning on x64
|
||||||
|
if (!Architecture.isX64()) {
|
||||||
final long longBytes = length & LONG_MASK;
|
final long longBytes = length & LONG_MASK;
|
||||||
final long longLimit = fromOffset + longBytes;
|
final long longLimit = fromOffset + longBytes;
|
||||||
long offset = fromOffset;
|
|
||||||
for (; offset < longLimit; offset += Long.BYTES) {
|
for (; offset < longLimit; offset += Long.BYTES) {
|
||||||
long val = SCOPED_MEMORY_ACCESS.getLongUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + offset, !Architecture.isLittleEndian());
|
long val = SCOPED_MEMORY_ACCESS.getLongUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + offset, !Architecture.isLittleEndian());
|
||||||
if (mightContainZeroInt(val)) {
|
if (mightContainZeroInt(val)) {
|
||||||
|
@ -216,6 +220,7 @@ public final class StringSupport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Handle the tail
|
// Handle the tail
|
||||||
// Prevent over scanning as we step by 4
|
// Prevent over scanning as we step by 4
|
||||||
final long endScan = toOffset & ~3; // The last two bit are zero
|
final long endScan = toOffset & ~3; // The last two bit are zero
|
||||||
|
|
|
@ -55,10 +55,10 @@ import static java.lang.foreign.ValueLayout.*;
|
||||||
"--enable-native-access=ALL-UNNAMED"})
|
"--enable-native-access=ALL-UNNAMED"})
|
||||||
public class InternalStrLen {
|
public class InternalStrLen {
|
||||||
|
|
||||||
private AbstractMemorySegmentImpl singleByteSegment;
|
private MemorySegment singleByteSegment;
|
||||||
private AbstractMemorySegmentImpl singleByteSegmentMisaligned;
|
private MemorySegment singleByteSegmentMisaligned;
|
||||||
private AbstractMemorySegmentImpl doubleByteSegment;
|
private MemorySegment doubleByteSegment;
|
||||||
private AbstractMemorySegmentImpl quadByteSegment;
|
private MemorySegment quadByteSegment;
|
||||||
|
|
||||||
@Param({"1", "4", "16", "251", "1024"})
|
@Param({"1", "4", "16", "251", "1024"})
|
||||||
int size;
|
int size;
|
||||||
|
@ -66,9 +66,9 @@ public class InternalStrLen {
|
||||||
@Setup
|
@Setup
|
||||||
public void setup() {
|
public void setup() {
|
||||||
var arena = Arena.ofAuto();
|
var arena = Arena.ofAuto();
|
||||||
singleByteSegment = (AbstractMemorySegmentImpl) arena.allocate((size + 1L) * Byte.BYTES);
|
singleByteSegment = arena.allocate((size + 1L) * Byte.BYTES);
|
||||||
doubleByteSegment = (AbstractMemorySegmentImpl) arena.allocate((size + 1L) * Short.BYTES);
|
doubleByteSegment = arena.allocate((size + 1L) * Short.BYTES);
|
||||||
quadByteSegment = (AbstractMemorySegmentImpl) arena.allocate((size + 1L) * Integer.BYTES);
|
quadByteSegment = arena.allocate((size + 1L) * Integer.BYTES);
|
||||||
Stream.of(singleByteSegment, doubleByteSegment, quadByteSegment)
|
Stream.of(singleByteSegment, doubleByteSegment, quadByteSegment)
|
||||||
.forEach(s -> IntStream.range(0, (int) s.byteSize() - 1)
|
.forEach(s -> IntStream.range(0, (int) s.byteSize() - 1)
|
||||||
.forEach(i -> s.set(
|
.forEach(i -> s.set(
|
||||||
|
@ -79,7 +79,7 @@ public class InternalStrLen {
|
||||||
singleByteSegment.set(ValueLayout.JAVA_BYTE, singleByteSegment.byteSize() - Byte.BYTES, (byte) 0);
|
singleByteSegment.set(ValueLayout.JAVA_BYTE, singleByteSegment.byteSize() - Byte.BYTES, (byte) 0);
|
||||||
doubleByteSegment.set(ValueLayout.JAVA_SHORT, doubleByteSegment.byteSize() - Short.BYTES, (short) 0);
|
doubleByteSegment.set(ValueLayout.JAVA_SHORT, doubleByteSegment.byteSize() - Short.BYTES, (short) 0);
|
||||||
quadByteSegment.set(ValueLayout.JAVA_INT, quadByteSegment.byteSize() - Integer.BYTES, 0);
|
quadByteSegment.set(ValueLayout.JAVA_INT, quadByteSegment.byteSize() - Integer.BYTES, 0);
|
||||||
singleByteSegmentMisaligned = (AbstractMemorySegmentImpl) arena.allocate(singleByteSegment.byteSize() + 1).
|
singleByteSegmentMisaligned = arena.allocate(singleByteSegment.byteSize() + 1).
|
||||||
asSlice(1);
|
asSlice(1);
|
||||||
MemorySegment.copy(singleByteSegment, 0, singleByteSegmentMisaligned, 0, singleByteSegment.byteSize());
|
MemorySegment.copy(singleByteSegment, 0, singleByteSegmentMisaligned, 0, singleByteSegment.byteSize());
|
||||||
}
|
}
|
||||||
|
@ -106,22 +106,22 @@ public class InternalStrLen {
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public int chunkedSingle() {
|
public int chunkedSingle() {
|
||||||
return StringSupport.strlenByte(singleByteSegment, 0, singleByteSegment.byteSize());
|
return StringSupport.strlenByte((AbstractMemorySegmentImpl) singleByteSegment, 0, singleByteSegment.byteSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public int chunkedSingleMisaligned() {
|
public int chunkedSingleMisaligned() {
|
||||||
return StringSupport.strlenByte(singleByteSegmentMisaligned, 0, singleByteSegment.byteSize());
|
return StringSupport.strlenByte((AbstractMemorySegmentImpl) singleByteSegmentMisaligned, 0, singleByteSegment.byteSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public int chunkedDouble() {
|
public int chunkedDouble() {
|
||||||
return StringSupport.strlenShort(doubleByteSegment, 0, doubleByteSegment.byteSize());
|
return StringSupport.strlenShort((AbstractMemorySegmentImpl) doubleByteSegment, 0, doubleByteSegment.byteSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public int changedElementQuad() {
|
public int changedElementQuad() {
|
||||||
return StringSupport.strlenInt(quadByteSegment, 0, quadByteSegment.byteSize());
|
return StringSupport.strlenInt((AbstractMemorySegmentImpl) quadByteSegment, 0, quadByteSegment.byteSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are the legacy methods
|
// These are the legacy methods
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue