diff --git a/core/src/main/java/art/arcane/iris/util/simd/NoiseKernels2D.java b/core/src/main/java/art/arcane/iris/util/simd/NoiseKernels2D.java deleted file mode 100644 index b781cd784..000000000 --- a/core/src/main/java/art/arcane/iris/util/simd/NoiseKernels2D.java +++ /dev/null @@ -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); -} diff --git a/core/src/main/java/art/arcane/iris/util/simd/ScalarNoiseKernels2D.java b/core/src/main/java/art/arcane/iris/util/simd/ScalarNoiseKernels2D.java deleted file mode 100644 index e2b592d0b..000000000 --- a/core/src/main/java/art/arcane/iris/util/simd/ScalarNoiseKernels2D.java +++ /dev/null @@ -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]); - } - } -} diff --git a/core/src/main/java/art/arcane/iris/util/simd/SimdSupport.java b/core/src/main/java/art/arcane/iris/util/simd/SimdSupport.java index 07347095a..055550867 100644 --- a/core/src/main/java/art/arcane/iris/util/simd/SimdSupport.java +++ b/core/src/main/java/art/arcane/iris/util/simd/SimdSupport.java @@ -9,9 +9,7 @@ public final class SimdSupport { private static final String VECTOR_MODULE = "jdk.incubator.vector"; private static final boolean MODULE_PRESENT = ModuleLayer.boot().findModule(VECTOR_MODULE).isPresent(); private static final AtomicReference KERNEL_FAILURE = new AtomicReference<>(); - private static final AtomicReference NOISE_KERNEL_FAILURE = new AtomicReference<>(); private static final SimdKernels KERNELS = selectKernels(); - private static final NoiseKernels2D NOISE_KERNELS_2D = selectNoiseKernels2D(); private SimdSupport() { } @@ -20,10 +18,6 @@ public final class SimdSupport { return KERNELS; } - public static NoiseKernels2D noiseKernels2D() { - return NOISE_KERNELS_2D; - } - public static boolean isVectorModulePresent() { return MODULE_PRESENT; } @@ -36,19 +30,10 @@ public final class SimdSupport { return KERNEL_FAILURE.get(); } - public static Throwable noiseKernelInitializationFailure() { - return NOISE_KERNEL_FAILURE.get(); - } - public static String kernelStatus() { 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) { if (vectorized) { 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"; } - 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() { IrisLogging.info("SIMD: " + kernelStatus()); - IrisLogging.info("SIMD: " + noiseKernelStatus()); Throwable failure = KERNEL_FAILURE.get(); if (failure != null) { 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() { @@ -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() { if (!simdEnabledInSettings()) { return new ScalarSimdKernels(); @@ -144,15 +85,6 @@ public final class SimdSupport { 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) { Throwable root = failure; while (root.getCause() != null && root.getCause() != root) { diff --git a/core/src/main/java/art/arcane/iris/util/simd/VectorNoiseKernels2D.java b/core/src/main/java/art/arcane/iris/util/simd/VectorNoiseKernels2D.java deleted file mode 100644 index 5db19a260..000000000 --- a/core/src/main/java/art/arcane/iris/util/simd/VectorNoiseKernels2D.java +++ /dev/null @@ -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 DS = DoubleVector.SPECIES_PREFERRED; - private static final VectorSpecies 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_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 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 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 xGreater = x0.compare(VectorOperators.GT, y0); - VectorMask 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]); - } - } -} diff --git a/core/src/test/java/art/arcane/iris/util/simd/NoiseKernels2DParityTest.java b/core/src/test/java/art/arcane/iris/util/simd/NoiseKernels2DParityTest.java deleted file mode 100644 index 69f16f747..000000000 --- a/core/src/test/java/art/arcane/iris/util/simd/NoiseKernels2DParityTest.java +++ /dev/null @@ -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); - } - } - } - } -} diff --git a/core/src/test/java/art/arcane/iris/util/simd/SimdSupportStatusTest.java b/core/src/test/java/art/arcane/iris/util/simd/SimdSupportStatusTest.java index 20a0cc2c7..a6c3ff6d6 100644 --- a/core/src/test/java/art/arcane/iris/util/simd/SimdSupportStatusTest.java +++ b/core/src/test/java/art/arcane/iris/util/simd/SimdSupportStatusTest.java @@ -88,20 +88,19 @@ public class SimdSupportStatusTest { } @Test - public void aNarrowCpuIsReportedAsUnprofitableRatherThanDisabled() { - String status = SimdSupport.noiseKernelStatus(false, "scalar", true, null, true); + public void aCpuWithoutAUsableVectorShapeIsReportedAsSuchRatherThanDisabled() { + 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")); } @Test - public void installStatesTheLiveKernelSelectionForBothKernelSets() { + public void installStatesTheLiveKernelSelection() { 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.noiseKernelStatus())); } @Test @@ -111,6 +110,5 @@ public class SimdSupportStatusTest { } assertFalse(SimdSupport.kernelStatus(), SimdSupport.kernelStatus().contains("performance.simdKernels=false")); - assertFalse(SimdSupport.noiseKernelStatus(), SimdSupport.noiseKernelStatus().contains("performance.simdKernels=false")); } } diff --git a/tools/simd-bench/README.md b/tools/simd-bench/README.md index ae6bd62f0..d5d149559 100644 --- a/tools/simd-bench/README.md +++ b/tools/simd-bench/README.md @@ -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 (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 -`Iris/core/.../util/simd/`. 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. +The three array kernel classes are copied verbatim (logic byte-for-byte) from +`Iris/core/.../util/simd/`. The three 2D noise kernel classes are a candidate +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 @@ -98,7 +102,8 @@ run.bat --mode both (default) throughput will be (cache behavior, allocation, and surrounding code differ in the real engine). - **Effort 1 array kernels** (`roundToInt` / `sum` / `max`) run unconditionally - in real Iris. **Effort 2 noise** (`simplexFractalFBM`) is currently unwired in - Iris and gated to 4+ double lanes; this tool force-measures it regardless. + in real Iris. **Effort 2 noise** (`simplexFractalFBM`) is not part of + 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 CPU. Run on the actual target hardware; do not extrapolate across machines.