Last active
June 8, 2023 14:51
-
-
Save benwtrent/29cc0338cd851c345cace5c486095507 to your computer and use it in GitHub Desktop.
Decoding ByteBuffers into Floats microbenchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.openjdk.jmh.annotations.Benchmark; | |
import org.openjdk.jmh.annotations.BenchmarkMode; | |
import org.openjdk.jmh.annotations.Fork; | |
import org.openjdk.jmh.annotations.Measurement; | |
import org.openjdk.jmh.annotations.Mode; | |
import org.openjdk.jmh.annotations.OutputTimeUnit; | |
import org.openjdk.jmh.annotations.Param; | |
import org.openjdk.jmh.annotations.Scope; | |
import org.openjdk.jmh.annotations.Setup; | |
import org.openjdk.jmh.annotations.State; | |
import org.openjdk.jmh.annotations.Warmup; | |
import org.openjdk.jmh.infra.Blackhole; | |
import java.nio.ByteBuffer; | |
import java.nio.FloatBuffer; | |
import java.util.Random; | |
import java.util.concurrent.TimeUnit; | |
@Fork(1) | |
@Warmup(iterations = 3) | |
@Measurement(iterations = 5) | |
@BenchmarkMode(Mode.AverageTime) | |
@OutputTimeUnit(TimeUnit.NANOSECONDS) | |
@SuppressWarnings("unused") // invoked by benchmarking framework | |
@State(Scope.Benchmark) | |
public class ByteBufferFloatDecodeLatencyBenchmark { | |
@Param({ "96", "768", "2048" }) | |
private int floatArraySizes; | |
@Param({ "LE", "BE" }) | |
private String byteOrderString; | |
private ByteOrder byteOrder; | |
private final int numBuffers = 100_000; | |
private final Random random = new Random(0); | |
private float[] decodedArray; | |
private ByteBuffer[] byteBuffers; | |
@Setup | |
public void setupBenchmarks() { | |
byteOrder = "LE".equals(byteOrderString) ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN; | |
decodedArray = new float[floatArraySizes]; | |
byteBuffers = new ByteBuffer[numBuffers]; | |
for (int i = 0; i < numBuffers; i++) { | |
byteBuffers[i] = ByteBuffer.allocate(floatArraySizes * 4).order(byteOrder); | |
for (int j = 0; j < floatArraySizes; j++) { | |
byteBuffers[i].putFloat(random.nextFloat()); | |
} | |
byteBuffers[i].rewind(); | |
} | |
} | |
@Benchmark | |
public void decodeByteBufferDirectRead(Blackhole bh) { | |
for (int i = 0; i < numBuffers; i++) { | |
for (int j = 0; j < floatArraySizes; j++) { | |
decodedArray[j] = byteBuffers[i].getFloat(j * Float.BYTES); | |
} | |
bh.consume(decodedArray); | |
byteBuffers[i].rewind(); | |
} | |
} | |
@Benchmark | |
public void decodeFloatBufferIteration(Blackhole bh) { | |
for (int i = 0; i < numBuffers; i++) { | |
FloatBuffer floatBuffer = byteBuffers[i].asFloatBuffer(); | |
for (int j = 0; j < floatArraySizes; j++) { | |
decodedArray[j] = floatBuffer.get(); | |
} | |
bh.consume(decodedArray); | |
byteBuffers[i].rewind(); | |
} | |
} | |
@Benchmark | |
public void decodeFloatBufferDirectRead(Blackhole bh) { | |
for (int i = 0; i < numBuffers; i++) { | |
FloatBuffer floatBuffer = byteBuffers[i].asFloatBuffer(); | |
for (int j = 0; j < floatArraySizes; j++) { | |
decodedArray[j] = floatBuffer.get(j); | |
} | |
bh.consume(decodedArray); | |
floatBuffer.rewind(); | |
} | |
} | |
@Benchmark | |
public void decodeByteBufferIteration(Blackhole bh) { | |
for (int i = 0; i < numBuffers; i++) { | |
for (int j = 0; j < floatArraySizes; j++) { | |
decodedArray[j] = byteBuffers[i].getFloat(); | |
} | |
bh.consume(decodedArray); | |
byteBuffers[i].rewind(); | |
} | |
} | |
@Benchmark | |
public void decodeFloatBufferBulk(Blackhole bh) { | |
for (int i = 0; i < numBuffers; i++) { | |
FloatBuffer floatBuffer = byteBuffers[i].asFloatBuffer(); | |
floatBuffer.get(decodedArray, 0, floatArraySizes); | |
bh.consume(decodedArray); | |
floatBuffer.rewind(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment