From 0c3371b29e5464c917421fef6d271a5cb08676d4 Mon Sep 17 00:00:00 2001 From: asmhatre Date: Sun, 26 Jul 2026 11:47:07 +0000 Subject: [PATCH] Add JMH benchmark for the square-and-add kernel --- .../com/ankurm/vectorapi/VectorBench.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 jmh/src/main/java/com/ankurm/vectorapi/VectorBench.java diff --git a/jmh/src/main/java/com/ankurm/vectorapi/VectorBench.java b/jmh/src/main/java/com/ankurm/vectorapi/VectorBench.java new file mode 100644 index 0000000..c617532 --- /dev/null +++ b/jmh/src/main/java/com/ankurm/vectorapi/VectorBench.java @@ -0,0 +1,63 @@ +package com.ankurm.vectorapi; + +import jdk.incubator.vector.*; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(1) +public class VectorBench { + static final VectorSpecies SP = FloatVector.SPECIES_PREFERRED; + float[] a, b, c; + + @Setup + public void setup() { + int n = 8192; + a = new float[n]; b = new float[n]; c = new float[n]; + Random r = new Random(42); + for (int i = 0; i < n; i++) { a[i] = r.nextFloat(); b[i] = r.nextFloat(); } + } + + // The result array is written, then handed to JMH's Blackhole so neither the + // stores nor the arithmetic can be eliminated as dead code. + @Benchmark + public void scalar(Blackhole bh) { + for (int i = 0; i < a.length; i++) c[i] = -(a[i]*a[i] + b[i]*b[i]); + bh.consume(c); + } + + @Benchmark + public void vector(Blackhole bh) { + int i = 0, bound = SP.loopBound(a.length); + for (; i < bound; i += SP.length()) { + var va = FloatVector.fromArray(SP, a, i); + var vb = FloatVector.fromArray(SP, b, i); + va.mul(va).add(vb.mul(vb)).neg().intoArray(c, i); + } + for (; i < a.length; i++) c[i] = -(a[i]*a[i] + b[i]*b[i]); + bh.consume(c); + } + + // Same kernel, but returning a value derived from the output. Returned values + // are consumed by JMH automatically. Note what this costs: the checksum loop is + // itself measured, which is why this variant reports ~9x the time of vector(). + @Benchmark + public float vectorChecksum() { + int i = 0, bound = SP.loopBound(a.length); + for (; i < bound; i += SP.length()) { + var va = FloatVector.fromArray(SP, a, i); + var vb = FloatVector.fromArray(SP, b, i); + va.mul(va).add(vb.mul(vb)).neg().intoArray(c, i); + } + for (; i < a.length; i++) c[i] = -(a[i]*a[i] + b[i]*b[i]); + float sum = 0; + for (float v : c) sum += v; + return sum; + } +}