mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 14:00:26 +00:00
SMID
This commit is contained in:
1 parent
6a68884ce9
commit
abfc122171
11 files changed
+374
-5
No files matched your search
@@ -70,6 +70,7 @@ import art.arcane.iris.util.common.plugin.VolmitSender;
|
|||||||
import art.arcane.iris.util.common.plugin.chunk.ChunkTickets;
|
import art.arcane.iris.util.common.plugin.chunk.ChunkTickets;
|
||||||
import art.arcane.iris.util.common.scheduling.J;
|
import art.arcane.iris.util.common.scheduling.J;
|
||||||
import art.arcane.iris.util.common.misc.ServerProperties;
|
import art.arcane.iris.util.common.misc.ServerProperties;
|
||||||
|
import art.arcane.iris.util.simd.SimdSupport;
|
||||||
import art.arcane.volmlib.util.scheduling.Queue;
|
import art.arcane.volmlib.util.scheduling.Queue;
|
||||||
import art.arcane.volmlib.util.scheduling.ShurikenQueue;
|
import art.arcane.volmlib.util.scheduling.ShurikenQueue;
|
||||||
import io.papermc.lib.PaperLib;
|
import io.papermc.lib.PaperLib;
|
||||||
@@ -547,6 +548,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
|||||||
|
|
||||||
private void enable() {
|
private void enable() {
|
||||||
PaperLibBootstrap.install();
|
PaperLibBootstrap.install();
|
||||||
|
SimdSupport.install();
|
||||||
services = new KMap<>();
|
services = new KMap<>();
|
||||||
setupAudience();
|
setupAudience();
|
||||||
Bindings.setupSentry();
|
Bindings.setupSentry();
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ public class IrisSettings {
|
|||||||
public int objectLoaderCacheSize = 4_096;
|
public int objectLoaderCacheSize = 4_096;
|
||||||
public int tectonicPlateSize = -1;
|
public int tectonicPlateSize = -1;
|
||||||
public int mantleCleanupDelay = 200;
|
public int mantleCleanupDelay = 200;
|
||||||
|
public boolean simdKernels = true;
|
||||||
|
|
||||||
public int getTectonicPlateSize() {
|
public int getTectonicPlateSize() {
|
||||||
if (tectonicPlateSize > 0)
|
if (tectonicPlateSize > 0)
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
|
|||||||
int fluidHeight = dimension.getFluidHeight();
|
int fluidHeight = dimension.getFluidHeight();
|
||||||
int clampedFluidHeight = Math.min(chunkHeight, fluidHeight);
|
int clampedFluidHeight = Math.min(chunkHeight, fluidHeight);
|
||||||
boolean bedrockEnabled = dimension.isBedrock();
|
boolean bedrockEnabled = dimension.isBedrock();
|
||||||
|
boolean hideOres = dimension.isHideOresForHiddenOre();
|
||||||
ChunkedDataCache<IrisBiome> biomeCache = context.getBiome();
|
ChunkedDataCache<IrisBiome> biomeCache = context.getBiome();
|
||||||
ChunkedDataCache<IrisRegion> regionCache = context.getRegion();
|
ChunkedDataCache<IrisRegion> regionCache = context.getRegion();
|
||||||
ChunkedDataCache<BlockData> fluidCache = context.getFluid();
|
ChunkedDataCache<BlockData> fluidCache = context.getFluid();
|
||||||
@@ -235,8 +236,8 @@ public class IrisTerrainNormalActuator extends EngineAssignedActuator<BlockData>
|
|||||||
int topY = Math.min(hf, chunkHeight - 1);
|
int topY = Math.min(hf, chunkHeight - 1);
|
||||||
BlockData fluid = fluidCache.get(xf, zf);
|
BlockData fluid = fluidCache.get(xf, zf);
|
||||||
BlockData rock = rockCache.get(xf, zf);
|
BlockData rock = rockCache.get(xf, zf);
|
||||||
boolean hasSurfaceOres = biome.hasSurfaceOres() || region.hasSurfaceOres() || dimension.hasSurfaceOres();
|
boolean hasSurfaceOres = !hideOres && (biome.hasSurfaceOres() || region.hasSurfaceOres() || dimension.hasSurfaceOres());
|
||||||
boolean hasUndergroundOres = biome.hasUndergroundOres() || region.hasUndergroundOres() || dimension.hasUndergroundOres();
|
boolean hasUndergroundOres = !hideOres && (biome.hasUndergroundOres() || region.hasUndergroundOres() || dimension.hasUndergroundOres());
|
||||||
KList<BlockData> blocks = null;
|
KList<BlockData> blocks = null;
|
||||||
KList<BlockData> fblocks = null;
|
KList<BlockData> fblocks = null;
|
||||||
|
|
||||||
|
|||||||
@@ -25,25 +25,61 @@ import art.arcane.iris.util.common.data.B;
|
|||||||
import art.arcane.iris.util.project.hunk.Hunk;
|
import art.arcane.iris.util.project.hunk.Hunk;
|
||||||
import art.arcane.iris.util.common.parallel.BurstExecutor;
|
import art.arcane.iris.util.common.parallel.BurstExecutor;
|
||||||
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.data.Bisected;
|
import org.bukkit.block.data.Bisected;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class IrisPerfectionModifier extends EngineAssignedModifier<BlockData> {
|
public class IrisPerfectionModifier extends EngineAssignedModifier<BlockData> {
|
||||||
private static final BlockData AIR = B.get("AIR");
|
private static final BlockData AIR = B.get("AIR");
|
||||||
private static final BlockData WATER = B.get("WATER");
|
private static final BlockData WATER = B.get("WATER");
|
||||||
|
private static final Map<Material, BlockData> ORE_BASES = buildOreBases();
|
||||||
|
|
||||||
public IrisPerfectionModifier(Engine engine) {
|
public IrisPerfectionModifier(Engine engine) {
|
||||||
super(engine, "Perfection");
|
super(engine, "Perfection");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Map<Material, BlockData> buildOreBases() {
|
||||||
|
Map<Material, BlockData> map = new EnumMap<>(Material.class);
|
||||||
|
BlockData stone = B.get("STONE");
|
||||||
|
BlockData deepslate = B.get("DEEPSLATE");
|
||||||
|
BlockData netherrack = B.get("NETHERRACK");
|
||||||
|
BlockData blackstone = B.get("BLACKSTONE");
|
||||||
|
map.put(Material.COAL_ORE, stone);
|
||||||
|
map.put(Material.COPPER_ORE, stone);
|
||||||
|
map.put(Material.IRON_ORE, stone);
|
||||||
|
map.put(Material.GOLD_ORE, stone);
|
||||||
|
map.put(Material.REDSTONE_ORE, stone);
|
||||||
|
map.put(Material.LAPIS_ORE, stone);
|
||||||
|
map.put(Material.DIAMOND_ORE, stone);
|
||||||
|
map.put(Material.EMERALD_ORE, stone);
|
||||||
|
map.put(Material.DEEPSLATE_COAL_ORE, deepslate);
|
||||||
|
map.put(Material.DEEPSLATE_COPPER_ORE, deepslate);
|
||||||
|
map.put(Material.DEEPSLATE_IRON_ORE, deepslate);
|
||||||
|
map.put(Material.DEEPSLATE_GOLD_ORE, deepslate);
|
||||||
|
map.put(Material.DEEPSLATE_REDSTONE_ORE, deepslate);
|
||||||
|
map.put(Material.DEEPSLATE_LAPIS_ORE, deepslate);
|
||||||
|
map.put(Material.DEEPSLATE_DIAMOND_ORE, deepslate);
|
||||||
|
map.put(Material.DEEPSLATE_EMERALD_ORE, deepslate);
|
||||||
|
map.put(Material.NETHER_GOLD_ORE, netherrack);
|
||||||
|
map.put(Material.NETHER_QUARTZ_ORE, netherrack);
|
||||||
|
map.put(Material.ANCIENT_DEBRIS, netherrack);
|
||||||
|
map.put(Material.GILDED_BLACKSTONE, blackstone);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
|
public void onModify(int x, int z, Hunk<BlockData> output, boolean multicore, ChunkContext context) {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
|
if (getDimension().isHideOresForHiddenOre()) {
|
||||||
|
hideOres(output, multicore);
|
||||||
|
}
|
||||||
AtomicBoolean changed = new AtomicBoolean(true);
|
AtomicBoolean changed = new AtomicBoolean(true);
|
||||||
int passes = 0;
|
int passes = 0;
|
||||||
AtomicInteger changes = new AtomicInteger();
|
AtomicInteger changes = new AtomicInteger();
|
||||||
@@ -123,6 +159,29 @@ public class IrisPerfectionModifier extends EngineAssignedModifier<BlockData> {
|
|||||||
getEngine().getMetrics().getPerfection().put(p.getMilliseconds());
|
getEngine().getMetrics().getPerfection().put(p.getMilliseconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hideOres(Hunk<BlockData> output, boolean multicore) {
|
||||||
|
BurstExecutor burst = burst().burst(multicore);
|
||||||
|
int height = output.getHeight();
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
int finalI = i;
|
||||||
|
burst.queue(() -> {
|
||||||
|
for (int j = 0; j < 16; j++) {
|
||||||
|
for (int k = height - 1; k >= 0; k--) {
|
||||||
|
BlockData block = output.get(finalI, k, j);
|
||||||
|
if (block == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BlockData base = ORE_BASES.get(block.getMaterial());
|
||||||
|
if (base != null) {
|
||||||
|
output.set(finalI, k, j, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
burst.complete();
|
||||||
|
}
|
||||||
|
|
||||||
private int getHeight(Hunk<BlockData> output, int x, int z) {
|
private int getHeight(Hunk<BlockData> output, int x, int z) {
|
||||||
for (int i = output.getHeight() - 1; i >= 0; i--) {
|
for (int i = output.getHeight() - 1; i >= 0; i--) {
|
||||||
BlockData b = output.get(x, i, z);
|
BlockData b = output.get(x, i, z);
|
||||||
|
|||||||
@@ -140,6 +140,8 @@ public class IrisDimension extends IrisRegistrant {
|
|||||||
private boolean debugSmartBore = false;
|
private boolean debugSmartBore = false;
|
||||||
@Desc("Generate decorations or not")
|
@Desc("Generate decorations or not")
|
||||||
private boolean decorate = true;
|
private boolean decorate = true;
|
||||||
|
@Desc("When true, every ore block the generator would place (terrain ores, deposits, ores inside objects) is replaced with its base material such as stone, deepslate or netherrack, so drop-control plugins like HiddenOre can manage ore rewards themselves")
|
||||||
|
private boolean hideOresForHiddenOre = false;
|
||||||
@Desc("Use post processing or not")
|
@Desc("Use post processing or not")
|
||||||
private boolean postProcessing = true;
|
private boolean postProcessing = true;
|
||||||
@Desc("Add slabs in post processing")
|
@Desc("Add slabs in post processing")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package art.arcane.iris.util.project.context;
|
|||||||
|
|
||||||
import art.arcane.iris.util.project.stream.ProceduralStream;
|
import art.arcane.iris.util.project.stream.ProceduralStream;
|
||||||
import art.arcane.iris.util.project.stream.utility.ChunkFillableDoubleStream2D;
|
import art.arcane.iris.util.project.stream.utility.ChunkFillableDoubleStream2D;
|
||||||
|
import art.arcane.iris.util.simd.SimdSupport;
|
||||||
import art.arcane.volmlib.util.documentation.BlockCoordinates;
|
import art.arcane.volmlib.util.documentation.BlockCoordinates;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -56,9 +57,7 @@ public class ChunkedDoubleDataCache {
|
|||||||
if (stream instanceof ChunkFillableDoubleStream2D cachedStream) {
|
if (stream instanceof ChunkFillableDoubleStream2D cachedStream) {
|
||||||
cachedStream.fillChunkDoubles(x, z, data);
|
cachedStream.fillChunkDoubles(x, z, data);
|
||||||
if (roundedTarget != null) {
|
if (roundedTarget != null) {
|
||||||
for (int index = 0; index < 256; index++) {
|
SimdSupport.kernels().roundToInt(data, roundedTarget, 256);
|
||||||
roundedTarget[index] = (int) Math.round(data[index]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package art.arcane.iris.util.simd;
|
||||||
|
|
||||||
|
public final class ScalarSimdKernels implements SimdKernels {
|
||||||
|
@Override
|
||||||
|
public String describe() {
|
||||||
|
return "scalar";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void roundToInt(double[] source, int[] target, int length) {
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
|
target[index] = (int) Math.round(source[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double sum(double[] values, int length) {
|
||||||
|
double total = 0D;
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
|
total += values[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double max(double[] values, int length) {
|
||||||
|
double best = Double.NEGATIVE_INFINITY;
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
|
if (values[index] > best) {
|
||||||
|
best = values[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package art.arcane.iris.util.simd;
|
||||||
|
|
||||||
|
public interface SimdKernels {
|
||||||
|
String describe();
|
||||||
|
|
||||||
|
void roundToInt(double[] source, int[] target, int length);
|
||||||
|
|
||||||
|
double sum(double[] values, int length);
|
||||||
|
|
||||||
|
double max(double[] values, int length);
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package art.arcane.iris.util.simd;
|
||||||
|
|
||||||
|
import art.arcane.iris.Iris;
|
||||||
|
import art.arcane.iris.core.IrisSettings;
|
||||||
|
|
||||||
|
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 SimdKernels KERNELS = selectKernels();
|
||||||
|
|
||||||
|
private SimdSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimdKernels kernels() {
|
||||||
|
return KERNELS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isVectorModulePresent() {
|
||||||
|
return MODULE_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isVectorized() {
|
||||||
|
return !(KERNELS instanceof ScalarSimdKernels);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void install() {
|
||||||
|
if (isVectorized()) {
|
||||||
|
Iris.info("SIMD: vector kernels enabled (" + KERNELS.describe() + ")");
|
||||||
|
} else if (!MODULE_PRESENT) {
|
||||||
|
Iris.info("SIMD: scalar kernels active; add --add-modules " + VECTOR_MODULE + " to JVM flags to enable vectorized generation kernels");
|
||||||
|
} else {
|
||||||
|
Iris.info("SIMD: vector kernels disabled (performance.simdKernels=false)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimdKernels createVectorKernels() {
|
||||||
|
if (!MODULE_PRESENT) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (SimdKernels) Class.forName("art.arcane.iris.util.simd.VectorSimdKernels").getDeclaredConstructor().newInstance();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SimdKernels selectKernels() {
|
||||||
|
if (!simdEnabledInSettings()) {
|
||||||
|
return new ScalarSimdKernels();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimdKernels vector = createVectorKernels();
|
||||||
|
return vector == null ? new ScalarSimdKernels() : vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean simdEnabledInSettings() {
|
||||||
|
try {
|
||||||
|
return IrisSettings.get().getPerformance().isSimdKernels();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package art.arcane.iris.util.simd;
|
||||||
|
|
||||||
|
import jdk.incubator.vector.DoubleVector;
|
||||||
|
import jdk.incubator.vector.IntVector;
|
||||||
|
import jdk.incubator.vector.VectorMask;
|
||||||
|
import jdk.incubator.vector.VectorOperators;
|
||||||
|
import jdk.incubator.vector.VectorShape;
|
||||||
|
import jdk.incubator.vector.VectorSpecies;
|
||||||
|
|
||||||
|
public final class VectorSimdKernels implements SimdKernels {
|
||||||
|
private static final VectorSpecies<Double> DOUBLE_SPECIES = DoubleVector.SPECIES_PREFERRED;
|
||||||
|
private static final VectorSpecies<Integer> INT_SPECIES = VectorSpecies.of(int.class, VectorShape.forBitSize(DOUBLE_SPECIES.length() * Integer.SIZE));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String describe() {
|
||||||
|
return DOUBLE_SPECIES.length() + "x64-bit lanes, " + DOUBLE_SPECIES.vectorShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void roundToInt(double[] source, int[] target, int length) {
|
||||||
|
int lanes = DOUBLE_SPECIES.length();
|
||||||
|
int bound = DOUBLE_SPECIES.loopBound(length);
|
||||||
|
int index = 0;
|
||||||
|
for (; index < bound; index += lanes) {
|
||||||
|
DoubleVector shifted = DoubleVector.fromArray(DOUBLE_SPECIES, source, index).add(0.5D);
|
||||||
|
IntVector truncated = (IntVector) shifted.convertShape(VectorOperators.D2I, INT_SPECIES, 0);
|
||||||
|
DoubleVector truncatedBack = (DoubleVector) truncated.convertShape(VectorOperators.I2D, DOUBLE_SPECIES, 0);
|
||||||
|
VectorMask<Integer> needsDecrement = shifted.lt(truncatedBack).cast(INT_SPECIES);
|
||||||
|
truncated.sub(1, needsDecrement).intoArray(target, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; index < length; index++) {
|
||||||
|
target[index] = (int) Math.round(source[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double sum(double[] values, int length) {
|
||||||
|
int lanes = DOUBLE_SPECIES.length();
|
||||||
|
int bound = DOUBLE_SPECIES.loopBound(length);
|
||||||
|
DoubleVector accumulator = DoubleVector.zero(DOUBLE_SPECIES);
|
||||||
|
int index = 0;
|
||||||
|
for (; index < bound; index += lanes) {
|
||||||
|
accumulator = accumulator.add(DoubleVector.fromArray(DOUBLE_SPECIES, values, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
double total = accumulator.reduceLanes(VectorOperators.ADD);
|
||||||
|
for (; index < length; index++) {
|
||||||
|
total += values[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double max(double[] values, int length) {
|
||||||
|
int lanes = DOUBLE_SPECIES.length();
|
||||||
|
int bound = DOUBLE_SPECIES.loopBound(length);
|
||||||
|
DoubleVector accumulator = DoubleVector.broadcast(DOUBLE_SPECIES, Double.NEGATIVE_INFINITY);
|
||||||
|
int index = 0;
|
||||||
|
for (; index < bound; index += lanes) {
|
||||||
|
accumulator = accumulator.max(DoubleVector.fromArray(DOUBLE_SPECIES, values, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
double best = accumulator.reduceLanes(VectorOperators.MAX);
|
||||||
|
for (; index < length; index++) {
|
||||||
|
if (values[index] > best) {
|
||||||
|
best = values[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package art.arcane.iris.util.simd;
|
||||||
|
|
||||||
|
import org.junit.Assume;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
public class SimdKernelsTest {
|
||||||
|
private static final double[] BOUNDARY_VALUES = {
|
||||||
|
0D, 0.5D, -0.5D, 1.5D, -1.5D, 2.5D, -2.5D, 63.5D, -63.5D, 64.49999D, -64.49999D,
|
||||||
|
0.4999999D, -0.4999999D, 255.5D, -255.5D, 319.999D, -64D, 2031.5D, -2031.5D, 0.0001D, -0.0001D
|
||||||
|
};
|
||||||
|
|
||||||
|
private static double[] terrainLikeValues(int length) {
|
||||||
|
Random random = new Random(42L);
|
||||||
|
double[] values = new double[length];
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
|
values[index] = (random.nextDouble() - 0.5D) * 8192D;
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scalarRoundToIntMatchesMathRound() {
|
||||||
|
ScalarSimdKernels kernels = new ScalarSimdKernels();
|
||||||
|
int[] rounded = new int[BOUNDARY_VALUES.length];
|
||||||
|
kernels.roundToInt(BOUNDARY_VALUES, rounded, BOUNDARY_VALUES.length);
|
||||||
|
for (int index = 0; index < BOUNDARY_VALUES.length; index++) {
|
||||||
|
assertEquals("index " + index + " value " + BOUNDARY_VALUES[index], (int) Math.round(BOUNDARY_VALUES[index]), rounded[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scalarSumAndMaxMatchManualLoop() {
|
||||||
|
ScalarSimdKernels kernels = new ScalarSimdKernels();
|
||||||
|
double[] values = terrainLikeValues(256);
|
||||||
|
double expectedSum = 0D;
|
||||||
|
double expectedMax = Double.NEGATIVE_INFINITY;
|
||||||
|
for (double value : values) {
|
||||||
|
expectedSum += value;
|
||||||
|
if (value > expectedMax) {
|
||||||
|
expectedMax = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(expectedSum, kernels.sum(values, values.length), 0D);
|
||||||
|
assertEquals(expectedMax, kernels.max(values, values.length), 0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void vectorRoundToIntMatchesScalarOnBoundaries() {
|
||||||
|
SimdKernels vector = requireVectorKernels();
|
||||||
|
ScalarSimdKernels scalar = new ScalarSimdKernels();
|
||||||
|
int[] vectorRounded = new int[BOUNDARY_VALUES.length];
|
||||||
|
int[] scalarRounded = new int[BOUNDARY_VALUES.length];
|
||||||
|
vector.roundToInt(BOUNDARY_VALUES, vectorRounded, BOUNDARY_VALUES.length);
|
||||||
|
scalar.roundToInt(BOUNDARY_VALUES, scalarRounded, BOUNDARY_VALUES.length);
|
||||||
|
for (int index = 0; index < BOUNDARY_VALUES.length; index++) {
|
||||||
|
assertEquals("index " + index + " value " + BOUNDARY_VALUES[index], scalarRounded[index], vectorRounded[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void vectorRoundToIntMatchesScalarOnTerrainSweep() {
|
||||||
|
SimdKernels vector = requireVectorKernels();
|
||||||
|
ScalarSimdKernels scalar = new ScalarSimdKernels();
|
||||||
|
for (int length : new int[]{256, 251, 1, 7}) {
|
||||||
|
double[] values = terrainLikeValues(length);
|
||||||
|
int[] vectorRounded = new int[length];
|
||||||
|
int[] scalarRounded = new int[length];
|
||||||
|
vector.roundToInt(values, vectorRounded, length);
|
||||||
|
scalar.roundToInt(values, scalarRounded, length);
|
||||||
|
for (int index = 0; index < length; index++) {
|
||||||
|
assertEquals("length " + length + " index " + index + " value " + values[index], scalarRounded[index], vectorRounded[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void vectorSumMatchesScalarWithinTolerance() {
|
||||||
|
SimdKernels vector = requireVectorKernels();
|
||||||
|
ScalarSimdKernels scalar = new ScalarSimdKernels();
|
||||||
|
for (int length : new int[]{256, 251, 1, 7}) {
|
||||||
|
double[] values = terrainLikeValues(length);
|
||||||
|
double expected = scalar.sum(values, length);
|
||||||
|
double actual = vector.sum(values, length);
|
||||||
|
assertEquals("length " + length, expected, actual, Math.max(1e-9D, Math.abs(expected) * 1e-12D));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void vectorMaxMatchesScalarExactly() {
|
||||||
|
SimdKernels vector = requireVectorKernels();
|
||||||
|
ScalarSimdKernels scalar = new ScalarSimdKernels();
|
||||||
|
for (int length : new int[]{256, 251, 1, 7}) {
|
||||||
|
double[] values = terrainLikeValues(length);
|
||||||
|
assertEquals("length " + length, scalar.max(values, length), vector.max(values, length), 0D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void vectorMaxOfAllZeroWeightsIsZero() {
|
||||||
|
SimdKernels vector = requireVectorKernels();
|
||||||
|
double[] weights = new double[256];
|
||||||
|
assertEquals(0D, vector.max(weights, weights.length), 0D);
|
||||||
|
assertEquals(0D, vector.sum(weights, weights.length), 0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SimdKernels requireVectorKernels() {
|
||||||
|
Assume.assumeTrue("jdk.incubator.vector module not present in test JVM", SimdSupport.isVectorModulePresent());
|
||||||
|
SimdKernels vector = SimdSupport.createVectorKernels();
|
||||||
|
assertNotNull("vector kernels failed to instantiate despite module being present", vector);
|
||||||
|
return vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user