Skip to content

Instantly share code, notes, and snippets.

@benwtrent
Last active June 8, 2023 14:51
Show Gist options
  • Save benwtrent/29cc0338cd851c345cace5c486095507 to your computer and use it in GitHub Desktop.
Save benwtrent/29cc0338cd851c345cace5c486095507 to your computer and use it in GitHub Desktop.
Decoding ByteBuffers into Floats microbenchmark
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