Drop unwired 2D noise kernels

- Delete NoiseKernels2D, ScalarNoiseKernels2D and VectorNoiseKernels2D after measuring the vector kernel at 0.07x scalar on 2-lane NEON with no production call site
- Delete the 2D noise parity test and the SimdSupport plumbing that selected between the two kernel sets
- State in the simd-bench README that its 2D noise classes are a candidate Iris does not ship
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-08 04:33:32 -04:00
1 parent 79af11c435
commit 45b9ff8e11
7 files changed
+15 -436

No files matched your search

@@ -1,8 +0,0 @@
package art.arcane.iris.util.simd;
public interface NoiseKernels2D {
String describe();
void simplexFractalFBM(long seed, int octaves, double frequency, double lacunarity, double gain,
double fractalBounding, double[] xs, double[] zs, double[] out, int length);
}
@@ -1,99 +0,0 @@
package art.arcane.iris.util.simd;
public final class ScalarNoiseKernels2D implements NoiseKernels2D {
static final double F2 = 0.5D * (Math.sqrt(3.0D) - 1.0D);
static final double G2 = (3.0D - Math.sqrt(3.0D)) / 6.0D;
static final long X_PRIME = 1619L;
static final long Y_PRIME = 31337L;
static final double[] GRAD_2D = {-1D, -1D, 1D, -1D, -1D, 1D, 1D, 1D, 0D, -1D, -1D, 0D, 0D, 1D, 1D, 0D};
@Override
public String describe() {
return "scalar";
}
static long fastFloor(double f) {
return f >= 0D ? (long) f : (long) f - 1L;
}
static double gradCoord2D(long seed, long x, long y, double xd, double yd) {
long hash = seed;
hash ^= X_PRIME * x;
hash ^= Y_PRIME * y;
hash = hash * hash * hash * 60493L;
hash = (hash >> 13) ^ hash;
int gradientIndex = ((int) hash & 7) << 1;
return (xd * GRAD_2D[gradientIndex]) + (yd * GRAD_2D[gradientIndex + 1]);
}
static double singleSimplex(long seed, double x, double y) {
double t = (x + y) * F2;
long i = fastFloor(x + t);
long j = fastFloor(y + t);
t = (i + j) * G2;
double x0 = x - (i - t);
double y0 = y - (j - t);
long i1;
long j1;
if (x0 > y0) {
i1 = 1L;
j1 = 0L;
} else {
i1 = 0L;
j1 = 1L;
}
double x1 = x0 - i1 + G2;
double y1 = y0 - j1 + G2;
double x2 = x0 - 1D + (2D * G2);
double y2 = y0 - 1D + (2D * G2);
double n0;
double n1;
double n2;
double a = 0.5D - x0 * x0 - y0 * y0;
if (a < 0D) {
n0 = 0D;
} else {
a *= a;
n0 = a * a * gradCoord2D(seed, i, j, x0, y0);
}
double b = 0.5D - x1 * x1 - y1 * y1;
if (b < 0D) {
n1 = 0D;
} else {
b *= b;
n1 = b * b * gradCoord2D(seed, i + i1, j + j1, x1, y1);
}
double c = 0.5D - x2 * x2 - y2 * y2;
if (c < 0D) {
n2 = 0D;
} else {
c *= c;
n2 = c * c * gradCoord2D(seed, i + 1L, j + 1L, x2, y2);
}
return 50D * (n0 + n1 + n2);
}
static double simplexFractalFBMScalar(long seed, int octaves, double frequency, double lacunarity, double gain,
double fractalBounding, double xIn, double yIn) {
double x = xIn * frequency;
double y = yIn * frequency;
long s = seed;
double sum = singleSimplex(s, x, y);
double amp = 1D;
for (int o = 1; o < octaves; o++) {
x *= lacunarity;
y *= lacunarity;
amp *= gain;
sum += singleSimplex(++s, x, y) * amp;
}
return sum * fractalBounding;
}
@Override
public void simplexFractalFBM(long seed, int octaves, double frequency, double lacunarity, double gain,
double fractalBounding, double[] xs, double[] zs, double[] out, int length) {
for (int k = 0; k < length; k++) {
out[k] = simplexFractalFBMScalar(seed, octaves, frequency, lacunarity, gain, fractalBounding, xs[k], zs[k]);
}
}
}
@@ -9,9 +9,7 @@ public final class SimdSupport {
private static final String VECTOR_MODULE = "jdk.incubator.vector"; private static final String VECTOR_MODULE = "jdk.incubator.vector";
private static final boolean MODULE_PRESENT = ModuleLayer.boot().findModule(VECTOR_MODULE).isPresent(); private static final boolean MODULE_PRESENT = ModuleLayer.boot().findModule(VECTOR_MODULE).isPresent();
private static final AtomicReference<Throwable> KERNEL_FAILURE = new AtomicReference<>(); private static final AtomicReference<Throwable> KERNEL_FAILURE = new AtomicReference<>();
private static final AtomicReference<Throwable> NOISE_KERNEL_FAILURE = new AtomicReference<>();
private static final SimdKernels KERNELS = selectKernels(); private static final SimdKernels KERNELS = selectKernels();
private static final NoiseKernels2D NOISE_KERNELS_2D = selectNoiseKernels2D();
private SimdSupport() { private SimdSupport() {
} }
@@ -20,10 +18,6 @@ public final class SimdSupport {
return KERNELS; return KERNELS;
} }
public static NoiseKernels2D noiseKernels2D() {
return NOISE_KERNELS_2D;
}
public static boolean isVectorModulePresent() { public static boolean isVectorModulePresent() {
return MODULE_PRESENT; return MODULE_PRESENT;
} }
@@ -36,19 +30,10 @@ public final class SimdSupport {
return KERNEL_FAILURE.get(); return KERNEL_FAILURE.get();
} }
public static Throwable noiseKernelInitializationFailure() {
return NOISE_KERNEL_FAILURE.get();
}
public static String kernelStatus() { public static String kernelStatus() {
return kernelStatus(isVectorized(), KERNELS.describe(), MODULE_PRESENT, KERNEL_FAILURE.get(), simdEnabledInSettings()); return kernelStatus(isVectorized(), KERNELS.describe(), MODULE_PRESENT, KERNEL_FAILURE.get(), simdEnabledInSettings());
} }
public static String noiseKernelStatus() {
return noiseKernelStatus(!(NOISE_KERNELS_2D instanceof ScalarNoiseKernels2D), NOISE_KERNELS_2D.describe(),
MODULE_PRESENT, NOISE_KERNEL_FAILURE.get(), simdEnabledInSettings());
}
static String kernelStatus(boolean vectorized, String description, boolean modulePresent, Throwable failure, boolean settingEnabled) { static String kernelStatus(boolean vectorized, String description, boolean modulePresent, Throwable failure, boolean settingEnabled) {
if (vectorized) { if (vectorized) {
return "vector kernels enabled (" + description + ")"; return "vector kernels enabled (" + description + ")";
@@ -69,39 +54,13 @@ public final class SimdSupport {
return "scalar kernels active; the Vector API reported no usable vector shape on this CPU"; return "scalar kernels active; the Vector API reported no usable vector shape on this CPU";
} }
static String noiseKernelStatus(boolean vectorized, String description, boolean modulePresent, Throwable failure, boolean settingEnabled) {
if (vectorized) {
return "2D noise vector kernels enabled (" + description + ")";
}
if (!modulePresent) {
return "2D noise scalar kernels active; the " + VECTOR_MODULE + " module is not on this JVM";
}
if (failure != null) {
return "2D noise scalar kernels active; vector kernel initialization failed: " + describe(failure);
}
if (!settingEnabled) {
return "2D noise vector kernels disabled (performance.simdKernels=false)";
}
return "2D noise scalar kernels active; this CPU has fewer than the 4 double lanes the vector kernel needs to pay for itself";
}
public static void install() { public static void install() {
IrisLogging.info("SIMD: " + kernelStatus()); IrisLogging.info("SIMD: " + kernelStatus());
IrisLogging.info("SIMD: " + noiseKernelStatus());
Throwable failure = KERNEL_FAILURE.get(); Throwable failure = KERNEL_FAILURE.get();
if (failure != null) { if (failure != null) {
IrisLogging.reportError("Iris could not initialize its Vector API kernels; generation runs on the scalar kernels instead.", failure); IrisLogging.reportError("Iris could not initialize its Vector API kernels; generation runs on the scalar kernels instead.", failure);
} }
Throwable noiseFailure = NOISE_KERNEL_FAILURE.get();
if (noiseFailure != null) {
IrisLogging.reportError("Iris could not initialize its Vector API 2D noise kernels; noise runs on the scalar kernels instead.", noiseFailure);
}
} }
public static SimdKernels createVectorKernels() { public static SimdKernels createVectorKernels() {
@@ -117,24 +76,6 @@ public final class SimdSupport {
} }
} }
public static NoiseKernels2D createVectorNoiseKernels2D() {
if (!MODULE_PRESENT) {
return null;
}
try {
Class<?> cls = Class.forName("art.arcane.iris.util.simd.VectorNoiseKernels2D");
boolean profitable = (boolean) cls.getMethod("profitable").invoke(null);
if (!profitable) {
return null;
}
return (NoiseKernels2D) cls.getDeclaredConstructor().newInstance();
} catch (Throwable e) {
NOISE_KERNEL_FAILURE.set(e);
return null;
}
}
private static SimdKernels selectKernels() { private static SimdKernels selectKernels() {
if (!simdEnabledInSettings()) { if (!simdEnabledInSettings()) {
return new ScalarSimdKernels(); return new ScalarSimdKernels();
@@ -144,15 +85,6 @@ public final class SimdSupport {
return vector == null ? new ScalarSimdKernels() : vector; return vector == null ? new ScalarSimdKernels() : vector;
} }
private static NoiseKernels2D selectNoiseKernels2D() {
if (!simdEnabledInSettings()) {
return new ScalarNoiseKernels2D();
}
NoiseKernels2D vector = createVectorNoiseKernels2D();
return vector == null ? new ScalarNoiseKernels2D() : vector;
}
private static String describe(Throwable failure) { private static String describe(Throwable failure) {
Throwable root = failure; Throwable root = failure;
while (root.getCause() != null && root.getCause() != root) { while (root.getCause() != null && root.getCause() != root) {
@@ -1,129 +0,0 @@
package art.arcane.iris.util.simd;
import jdk.incubator.vector.DoubleVector;
import jdk.incubator.vector.LongVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
public final class VectorNoiseKernels2D implements NoiseKernels2D {
private static final VectorSpecies<Double> DS = DoubleVector.SPECIES_PREFERRED;
private static final VectorSpecies<Long> LS = LongVector.SPECIES_PREFERRED;
private static final boolean ALIGNED = DS.length() == LS.length();
private static final int MIN_PROFITABLE_LANES = 4;
private static final boolean PROFITABLE = ALIGNED && DS.length() >= MIN_PROFITABLE_LANES;
private static final double[] GRAD_X = {-1D, 1D, -1D, 1D, 0D, -1D, 0D, 1D};
private static final double[] GRAD_Y = {-1D, -1D, 1D, 1D, -1D, 0D, 1D, 0D};
private static final double F2 = ScalarNoiseKernels2D.F2;
private static final double G2 = ScalarNoiseKernels2D.G2;
private static final long X_PRIME = ScalarNoiseKernels2D.X_PRIME;
private static final long Y_PRIME = ScalarNoiseKernels2D.Y_PRIME;
private static final ThreadLocal<long[]> LONG_SCRATCH = ThreadLocal.withInitial(() -> new long[LS.length()]);
public static boolean lanesAligned() {
return ALIGNED;
}
public static boolean profitable() {
return PROFITABLE;
}
@Override
public String describe() {
return DS.length() + "x64 lanes, " + DS.vectorShape();
}
private static LongVector floorToLong(DoubleVector f) {
LongVector truncated = (LongVector) f.convertShape(VectorOperators.D2L, LS, 0);
VectorMask<Long> negative = f.compare(VectorOperators.LT, 0D).cast(LS);
return truncated.sub(1L, negative);
}
private static DoubleVector toDouble(LongVector v) {
return (DoubleVector) v.convertShape(VectorOperators.L2D, DS, 0);
}
private static DoubleVector gradCoord(long seed, LongVector i, LongVector j, DoubleVector xd, DoubleVector yd,
int[] idxScratch) {
LongVector hash = LongVector.broadcast(LS, seed)
.lanewise(VectorOperators.XOR, i.mul(X_PRIME))
.lanewise(VectorOperators.XOR, j.mul(Y_PRIME));
hash = hash.mul(hash).mul(hash).mul(60493L);
LongVector shifted = hash.lanewise(VectorOperators.ASHR, 13);
hash = shifted.lanewise(VectorOperators.XOR, hash);
LongVector idx = hash.lanewise(VectorOperators.AND, 7L);
long[] tmp = LONG_SCRATCH.get();
idx.intoArray(tmp, 0);
for (int l = 0; l < idxScratch.length; l++) {
idxScratch[l] = (int) tmp[l];
}
DoubleVector gx = DoubleVector.fromArray(DS, GRAD_X, 0, idxScratch, 0);
DoubleVector gy = DoubleVector.fromArray(DS, GRAD_Y, 0, idxScratch, 0);
return xd.mul(gx).add(yd.mul(gy));
}
private static DoubleVector corner(DoubleVector xk, DoubleVector yk, DoubleVector grad) {
DoubleVector t = DoubleVector.broadcast(DS, 0.5D).sub(xk.mul(xk)).sub(yk.mul(yk));
VectorMask<Double> negative = t.compare(VectorOperators.LT, 0D);
DoubleVector t2 = t.mul(t);
DoubleVector t4 = t2.mul(t2);
return t4.mul(grad).blend(0D, negative);
}
private static DoubleVector singleSimplexVector(long seed, DoubleVector x, DoubleVector y, int[] idxScratch) {
DoubleVector t = x.add(y).mul(F2);
LongVector i = floorToLong(x.add(t));
LongVector j = floorToLong(y.add(t));
DoubleVector skew = toDouble(i.add(j)).mul(G2);
DoubleVector x0 = x.sub(toDouble(i).sub(skew));
DoubleVector y0 = y.sub(toDouble(j).sub(skew));
VectorMask<Double> xGreater = x0.compare(VectorOperators.GT, y0);
VectorMask<Long> xGreaterL = xGreater.cast(LS);
LongVector i1 = LongVector.zero(LS).blend(1L, xGreaterL);
LongVector j1 = LongVector.broadcast(LS, 1L).blend(0L, xGreaterL);
DoubleVector x1 = x0.sub(toDouble(i1)).add(G2);
DoubleVector y1 = y0.sub(toDouble(j1)).add(G2);
DoubleVector x2 = x0.sub(1D).add(2D * G2);
DoubleVector y2 = y0.sub(1D).add(2D * G2);
DoubleVector n0 = corner(x0, y0, gradCoord(seed, i, j, x0, y0, idxScratch));
DoubleVector n1 = corner(x1, y1, gradCoord(seed, i.add(i1), j.add(j1), x1, y1, idxScratch));
DoubleVector n2 = corner(x2, y2, gradCoord(seed, i.add(1L), j.add(1L), x2, y2, idxScratch));
return n0.add(n1).add(n2).mul(50D);
}
@Override
public void simplexFractalFBM(long seed, int octaves, double frequency, double lacunarity, double gain,
double fractalBounding, double[] xs, double[] zs, double[] out, int length) {
if (!ALIGNED) {
tailScalar(seed, octaves, frequency, lacunarity, gain, fractalBounding, xs, zs, out, 0, length);
return;
}
int lanes = DS.length();
int bound = DS.loopBound(length);
int[] idxScratch = new int[lanes];
int k = 0;
for (; k < bound; k += lanes) {
DoubleVector x = DoubleVector.fromArray(DS, xs, k).mul(frequency);
DoubleVector y = DoubleVector.fromArray(DS, zs, k).mul(frequency);
long s = seed;
DoubleVector sum = singleSimplexVector(s, x, y, idxScratch);
double amp = 1D;
for (int o = 1; o < octaves; o++) {
x = x.mul(lacunarity);
y = y.mul(lacunarity);
amp *= gain;
sum = sum.add(singleSimplexVector(++s, x, y, idxScratch).mul(amp));
}
sum.mul(fractalBounding).intoArray(out, k);
}
tailScalar(seed, octaves, frequency, lacunarity, gain, fractalBounding, xs, zs, out, k, length);
}
private static void tailScalar(long seed, int octaves, double frequency, double lacunarity, double gain,
double fractalBounding, double[] xs, double[] zs, double[] out, int from, int length) {
for (int k = from; k < length; k++) {
out[k] = ScalarNoiseKernels2D.simplexFractalFBMScalar(seed, octaves, frequency, lacunarity, gain,
fractalBounding, xs[k], zs[k]);
}
}
}
@@ -1,120 +0,0 @@
package art.arcane.iris.util.simd;
import art.arcane.iris.util.project.noise.FastNoiseDouble;
import art.arcane.iris.util.project.noise.FastNoiseDouble.FractalType;
import art.arcane.iris.util.project.noise.FastNoiseDouble.NoiseType;
import art.arcane.volmlib.util.math.RNG;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class NoiseKernels2DParityTest {
private static FastNoiseDouble oracle(long seed, int octaves) {
FastNoiseDouble n = new FastNoiseDouble(seed);
n.setNoiseType(NoiseType.SimplexFractal);
n.setFractalType(FractalType.FBM);
n.setFractalOctaves(octaves);
return n;
}
private static void assertKernelMatchesOracle(NoiseKernels2D kernel) {
RNG rng = new RNG(99L);
for (int octaves = 1; octaves <= 8; octaves++) {
FastNoiseDouble n = oracle(1337L + octaves, octaves);
int length = 256;
double[] xs = new double[length];
double[] zs = new double[length];
double[] expected = new double[length];
double[] out = new double[length];
for (int k = 0; k < length; k++) {
double x = (rng.nextDouble() - 0.5D) * 1_000_000D;
double z = (rng.nextDouble() - 0.5D) * 1_000_000D;
xs[k] = x;
zs[k] = z;
expected[k] = n.GetSimplexFractal(x, z);
}
kernel.simplexFractalFBM(1337L + octaves, octaves, n.getFrequency(), 2.0D, 0.5D, n.getFractalBounding(), xs, zs, out, length);
for (int k = 0; k < length; k++) {
assertEquals("octaves=" + octaves + " idx=" + k, expected[k], out[k], 0D);
}
}
}
@Test
public void scalarKernelIsBitExactToOracle() {
assertKernelMatchesOracle(new ScalarNoiseKernels2D());
}
@Test
public void vectorKernelSingleOctaveIsBitExactToOracle() {
org.junit.Assume.assumeTrue(VectorNoiseKernels2D.lanesAligned());
FastNoiseDouble n = oracle(202020L, 1);
RNG rng = new RNG(7L);
int length = 333;
double[] xs = new double[length];
double[] zs = new double[length];
double[] expected = new double[length];
double[] out = new double[length];
for (int k = 0; k < length; k++) {
double x = (rng.nextDouble() - 0.5D) * 800_000D;
double z = (rng.nextDouble() - 0.5D) * 800_000D;
xs[k] = x;
zs[k] = z;
expected[k] = n.GetSimplexFractal(x, z);
}
new VectorNoiseKernels2D().simplexFractalFBM(202020L, 1, n.getFrequency(), 2.0D, 0.5D, n.getFractalBounding(), xs, zs, out, length);
for (int k = 0; k < length; k++) {
assertEquals("idx=" + k, expected[k], out[k], 0D);
}
}
@Test
public void vectorKernelAllOctavesAreBitExactToOracle() {
org.junit.Assume.assumeTrue(VectorNoiseKernels2D.lanesAligned());
assertKernelMatchesOracle(new VectorNoiseKernels2D());
}
@Test
public void simdSupportReturnsBitExactNoiseKernel() {
NoiseKernels2D kernel = SimdSupport.noiseKernels2D();
org.junit.Assert.assertNotNull(kernel);
assertKernelMatchesOracle(kernel);
}
@Test
public void simdSupportNeverSelectsVectorBelowProfitableLanes() {
if (VectorNoiseKernels2D.profitable()) {
org.junit.Assert.assertTrue(SimdSupport.createVectorNoiseKernels2D() instanceof VectorNoiseKernels2D);
} else {
org.junit.Assert.assertTrue(SimdSupport.noiseKernels2D() instanceof ScalarNoiseKernels2D);
}
}
@Test
public void vectorMatchesScalarAcrossEdgeCases() {
org.junit.Assume.assumeTrue(VectorNoiseKernels2D.lanesAligned());
NoiseKernels2D scalar = new ScalarNoiseKernels2D();
NoiseKernels2D vector = new VectorNoiseKernels2D();
RNG rng = new RNG(31337L);
int[] lengths = {1, 3, 7, 8, 9, 255, 256, 257};
double[] edgeCoords = {-4.0D, -3.0D, -1.0D, -0.0D, 0.0D, 1.0D, 4.0D, 1_000_000.0D, -1_000_000.0D};
for (int octaves = 1; octaves <= 8; octaves++) {
for (int length : lengths) {
double[] xs = new double[length];
double[] zs = new double[length];
double[] a = new double[length];
double[] b = new double[length];
for (int k = 0; k < length; k++) {
boolean edge = (k % 3) == 0;
xs[k] = edge ? edgeCoords[k % edgeCoords.length] : (rng.nextDouble() - 0.5D) * 2_000_000D;
zs[k] = edge ? edgeCoords[(k + 1) % edgeCoords.length] : (rng.nextDouble() - 0.5D) * 2_000_000D;
}
scalar.simplexFractalFBM(77L, octaves, 0.01D, 2.0D, 0.5D, 0.6667D, xs, zs, a, length);
vector.simplexFractalFBM(77L, octaves, 0.01D, 2.0D, 0.5D, 0.6667D, xs, zs, b, length);
for (int k = 0; k < length; k++) {
assertEquals("oct=" + octaves + " len=" + length + " idx=" + k, a[k], b[k], 0D);
}
}
}
}
}
@@ -88,20 +88,19 @@ public class SimdSupportStatusTest {
} }
@Test @Test
public void aNarrowCpuIsReportedAsUnprofitableRatherThanDisabled() { public void aCpuWithoutAUsableVectorShapeIsReportedAsSuchRatherThanDisabled() {
String status = SimdSupport.noiseKernelStatus(false, "scalar", true, null, true); String status = SimdSupport.kernelStatus(false, "scalar", true, null, true);
assertTrue(status, status.contains("4 double lanes")); assertTrue(status, status.contains("no usable vector shape"));
assertFalse(status, status.contains("performance.simdKernels=false")); assertFalse(status, status.contains("performance.simdKernels=false"));
} }
@Test @Test
public void installStatesTheLiveKernelSelectionForBothKernelSets() { public void installStatesTheLiveKernelSelection() {
SimdSupport.install(); SimdSupport.install();
assertTrue(emitted.toString(), emitted.size() >= 2); assertTrue(emitted.toString(), emitted.size() >= 1);
assertTrue(emitted.toString(), emitted.contains("SIMD: " + SimdSupport.kernelStatus())); assertTrue(emitted.toString(), emitted.contains("SIMD: " + SimdSupport.kernelStatus()));
assertTrue(emitted.toString(), emitted.contains("SIMD: " + SimdSupport.noiseKernelStatus()));
} }
@Test @Test
@@ -111,6 +110,5 @@ public class SimdSupportStatusTest {
} }
assertFalse(SimdSupport.kernelStatus(), SimdSupport.kernelStatus().contains("performance.simdKernels=false")); assertFalse(SimdSupport.kernelStatus(), SimdSupport.kernelStatus().contains("performance.simdKernels=false"));
assertFalse(SimdSupport.noiseKernelStatus(), SimdSupport.noiseKernelStatus().contains("performance.simdKernels=false"));
} }
} }
+10 -5
View File
@@ -6,9 +6,13 @@ on**. The Volmit dev/test machines are Apple Silicon, where the wide-SIMD path
(4+ double lanes) does not exist. Copy the built artifact to a Windows/x86 box (4+ double lanes) does not exist. Copy the built artifact to a Windows/x86 box
(AVX2 = 4 lanes, AVX-512 = 8 lanes) and run it to get real numbers for that CPU. (AVX2 = 4 lanes, AVX-512 = 8 lanes) and run it to get real numbers for that CPU.
The six kernel classes are copied verbatim (logic byte-for-byte) from The three array kernel classes are copied verbatim (logic byte-for-byte) from
`Iris/core/.../util/simd/`. This tool is intentionally a duplicate so it builds `Iris/core/.../util/simd/`. The three 2D noise kernel classes are a candidate
and runs on its own with no Gradle, no VolmLib, and no Iris on the classpath. implementation that Iris does not ship: it measured 0.07x against scalar on
2-lane NEON and was removed, and this harness keeps it so the same question can be
answered on a wider CPU before anyone rebuilds it. This tool is intentionally a
duplicate so it builds and runs on its own with no Gradle, no VolmLib, and no Iris
on the classpath.
## Requirements ## Requirements
@@ -98,7 +102,8 @@ run.bat --mode both (default)
throughput will be (cache behavior, allocation, and surrounding code differ in throughput will be (cache behavior, allocation, and surrounding code differ in
the real engine). the real engine).
- **Effort 1 array kernels** (`roundToInt` / `sum` / `max`) run unconditionally - **Effort 1 array kernels** (`roundToInt` / `sum` / `max`) run unconditionally
in real Iris. **Effort 2 noise** (`simplexFractalFBM`) is currently unwired in in real Iris. **Effort 2 noise** (`simplexFractalFBM`) is not part of
Iris and gated to 4+ double lanes; this tool force-measures it regardless. Iris; this tool force-measures the candidate kernel regardless of the 4+ double
lane gate.
- Vector-API auto-vectorization and cost depend heavily on the JDK version and - Vector-API auto-vectorization and cost depend heavily on the JDK version and
CPU. Run on the actual target hardware; do not extrapolate across machines. CPU. Run on the actual target hardware; do not extrapolate across machines.