diff --git a/bench/src/main/scala/perfio/BufferedInputNumBenchmark.scala b/bench/src/main/scala/perfio/BufferedInputNumBenchmark.scala index f472942..c7ecea6 100644 --- a/bench/src/main/scala/perfio/BufferedInputNumBenchmark.scala +++ b/bench/src/main/scala/perfio/BufferedInputNumBenchmark.scala @@ -1,5 +1,7 @@ package perfio +import com.esotericsoftware.kryo.io.{ByteBufferInput, Input} +import com.esotericsoftware.kryo.unsafe.UnsafeByteBufferInput import org.openjdk.jmh.annotations.* import org.openjdk.jmh.infra.* @@ -8,7 +10,10 @@ import java.nio.{ByteBuffer, ByteOrder} import java.util.concurrent.TimeUnit @BenchmarkMode(Array(Mode.AverageTime)) -@Fork(value = 1, jvmArgsAppend = Array("-Xmx12g", "-Xss32M", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseZGC", "--enable-native-access=ALL-UNNAMED", "--add-modules", "jdk.incubator.vector")) +@Fork(value = 1, jvmArgsAppend = Array("-Xmx12g", "-Xss32M", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseZGC", + "--enable-native-access=ALL-UNNAMED", "--add-modules", "jdk.incubator.vector", + "--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED" // for KryoUnsafe +)) @Threads(1) @Warmup(iterations = 7, time = 1) @Measurement(iterations = 7, time = 1) @@ -47,6 +52,7 @@ class BufferedInputNumBenchmark extends BenchUtil { bin.close() } + // JDK: always big endian def run(bh: Blackhole, din: DataInputStream): Unit = { var i = 0 while(i < count) { @@ -58,6 +64,18 @@ class BufferedInputNumBenchmark extends BenchUtil { din.close() } + // Kryo: little endian (safe) or native endian (unsafe) + def run(bh: Blackhole, din: Input): Unit = { + var i = 0 + while(i < count) { + bh.consume(din.readByte()) + bh.consume(din.readInt()) + bh.consume(din.readLong()) + i += 1 + } + din.close() + } + def run(bh: Blackhole, buf: ByteBuffer): Unit = { buf.order(ByteOrder.BIG_ENDIAN) var i = 0 @@ -72,6 +90,10 @@ class BufferedInputNumBenchmark extends BenchUtil { @Benchmark def array_DataInputStream(bh: Blackhole): Unit = run(bh, new DataInputStream(new ByteArrayInputStream(testData))) @Benchmark + def array_Kryo(bh: Blackhole): Unit = run(bh, new ByteBufferInput(testData)) + @Benchmark + def array_KryoUnsafe(bh: Blackhole): Unit = run(bh, new UnsafeByteBufferInput(testData)) + @Benchmark def array_ByteBuffer(bh: Blackhole): Unit = run(bh, ByteBuffer.wrap(testData)) @Benchmark def array_BufferedInput(bh: Blackhole): Unit = run(bh, BufferedInput.of(new ByteArrayInputStream(testData))) diff --git a/bench/src/main/scala/perfio/BufferedOutputNumBenchmark.scala b/bench/src/main/scala/perfio/BufferedOutputNumBenchmark.scala index df6cab7..0db9f7e 100644 --- a/bench/src/main/scala/perfio/BufferedOutputNumBenchmark.scala +++ b/bench/src/main/scala/perfio/BufferedOutputNumBenchmark.scala @@ -1,5 +1,7 @@ package perfio +import com.esotericsoftware.kryo.io.{ByteBufferOutput, Output} +import com.esotericsoftware.kryo.unsafe.UnsafeByteBufferOutput import org.openjdk.jmh.annotations.* import org.openjdk.jmh.infra.* import perfio.internal.BufferUtil @@ -10,7 +12,10 @@ import java.nio.file.Paths import java.util.concurrent.TimeUnit @BenchmarkMode(Array(Mode.AverageTime)) -@Fork(value = 1, jvmArgsAppend = Array("-Xmx12g", "-Xss32M", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseZGC", "--enable-native-access=ALL-UNNAMED", "--add-modules", "jdk.incubator.vector")) +@Fork(value = 1, jvmArgsAppend = Array("-Xmx12g", "-Xss32M", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseZGC", + "--enable-native-access=ALL-UNNAMED", "--add-modules", "jdk.incubator.vector", + "--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED" // for KryoUnsafe +)) @Threads(1) @Warmup(iterations = 15, time = 1) @Measurement(iterations = 15, time = 1) @@ -21,6 +26,7 @@ class BufferedOutputNumBenchmark extends BenchUtil: val count = 20000000 val byteSize = count * 13 + // JDK: always big endian private def writeTo(out: DataOutputStream): Unit = var i = 0 while i < count do @@ -30,6 +36,16 @@ class BufferedOutputNumBenchmark extends BenchUtil: i += 1 out.close() + // Kryo: little endian (safe) or native endian (unsafe) + private def writeTo(out: Output): Unit = + var i = 0 + while i < count do + out.writeByte(i) + out.writeInt(i+100) + out.writeLong(i+101) + i += 1 + out.close() + private def writeTo(out: BufferedOutput): Unit = var i = 0 while i < count do @@ -65,6 +81,36 @@ class BufferedOutputNumBenchmark extends BenchUtil: bh.consume(bout.getSize) bh.consume(bout.getBuffer) + @Benchmark + def array_Kryo_growing(bh: Blackhole): Unit = + val bout = new MyByteArrayOutputStream + val out = new ByteBufferOutput(bout) + writeTo(out) + bh.consume(bout.getSize) + bh.consume(bout.getBuffer) + + @Benchmark + def array_Kryo_preallocated(bh: Blackhole): Unit = + val bb = ByteBuffer.allocate(count * 13) + val out = new ByteBufferOutput(bb) + writeTo(out) + bh.consume(out.position()) + + @Benchmark + def array_KryoUnsafe_growing(bh: Blackhole): Unit = + val bout = new MyByteArrayOutputStream + val out = new UnsafeByteBufferOutput(bout) + writeTo(out) + bh.consume(bout.getSize) + bh.consume(bout.getBuffer) + + @Benchmark + def array_KryoUnsafe_preallocated(bh: Blackhole): Unit = + val bb = ByteBuffer.allocate(count * 13) + val out = new UnsafeByteBufferOutput(count * 13) + writeTo(out) + bh.consume(out.position()) + @Benchmark def array_FlushingBufferedOutput_growing(bh: Blackhole): Unit = val bout = new MyByteArrayOutputStream diff --git a/build.sbt b/build.sbt index d71cb1d..7164e03 100644 --- a/build.sbt +++ b/build.sbt @@ -93,7 +93,8 @@ lazy val bench = (project in file("bench")) .settings( scalacOptions ++= Seq("-feature", "-opt:l:inline", "-opt-inline-from:perfio.*"), libraryDependencies ++= Seq( - "com.google.guava" % "guava" % "33.3.0-jre" + "com.google.guava" % "guava" % "33.3.0-jre", + "com.esotericsoftware" % "kryo" % "5.6.2", ), name := "perfio-bench", publish / skip := true,