Now its slow

This commit is contained in:
cyberpwn 2022-06-27 12:01:49 -04:00
parent 9d4caa7be4
commit 5e2438d6f6
16 changed files with 301 additions and 44 deletions

View File

@ -29,9 +29,6 @@ public class IrisBukkit extends JavaPlugin implements IrisPlatform {
getServer().getScheduler().scheduleSyncDelayedTask(this, () -> {
World world = Bukkit.createWorld(new WorldCreator("iristests/" + UUID.randomUUID()).generator(new IrisBukkitChunkGenerator(this, EngineConfiguration.builder()
.threads(4)
.mutable(true)
.timings(true)
.build())));
}, 10);
}

View File

@ -7,16 +7,16 @@ import com.volmit.iris.engine.EngineConfiguration;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.feature.IrisFeatureSizedTarget;
import com.volmit.iris.engine.feature.IrisFeatureTarget;
import com.volmit.iris.engine.feature.standard.FeatureTerrain;
import com.volmit.iris.engine.feature.features.FeatureTerrain;
import com.volmit.iris.engine.pipeline.PipedHunkStack;
import com.volmit.iris.platform.IrisPlatform;
import com.volmit.iris.platform.PlatformBlock;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
import com.volmit.iris.platform.bukkit.util.ChunkDataHunkView;
import org.bukkit.generator.WorldInfo;
import java.nio.channels.Pipe;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@ -46,6 +46,8 @@ public class IrisBukkitChunkGenerator extends ChunkGenerator {
initEngine(world);
ChunkData data = Bukkit.createChunkData(world);
Hunk<PlatformBlock> chunk = new ChunkDataHunkView(data);
PipedHunkStack stack = new PipedHunkStack();
stack.register(PlatformBlock.class, chunk);
IrisFeatureSizedTarget targetSize = IrisFeatureSizedTarget.builder()
.width(chunk.getWidth())
.height(chunk.getHeight())
@ -54,8 +56,7 @@ public class IrisBukkitChunkGenerator extends ChunkGenerator {
.offsetZ(z << 4)
.offsetY(0)
.build();
FeatureTerrain.TerrainFeatureState state = engine.get().getTerrainFeature().prepare(engine.get(), targetSize);
engine.get().getTerrainFeature().generate(engine.get(), state, new IrisFeatureTarget<>(chunk, targetSize));
engine.get().getPlumbing().generate(engine.get(), targetSize, stack);
perSecond.incrementAndGet();
a.put(pp.getMilliseconds());

View File

@ -18,5 +18,8 @@ public class EngineConfiguration {
private boolean timings = false;
@Builder.Default
private int threads = 4;
private int threads = Runtime.getRuntime().availableProcessors();
@Builder.Default
private int threadPriority = 3;
}

View File

@ -0,0 +1,37 @@
package com.volmit.iris.engine;
import lombok.Data;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;
@Data
public class EngineExecutor implements ForkJoinPool.ForkJoinWorkerThreadFactory, Thread.UncaughtExceptionHandler, Closeable {
private final IrisEngine engine;
private final ForkJoinPool forks;
public EngineExecutor(IrisEngine engine)
{
this.engine = engine;
forks = new ForkJoinPool(engine.getConfiguration().getThreads(), this, this, false);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace();
}
@Override
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
worker.setName("Iris " + engine.getWorld().getName() + " Executor " + worker.getPoolIndex());
return worker;
}
@Override
public void close() throws IOException {
forks.shutdownNow().forEach(Runnable::run);
}
}

View File

@ -1,7 +1,10 @@
package com.volmit.iris.engine;
import com.volmit.iris.engine.feature.IrisFeature;
import com.volmit.iris.engine.feature.standard.FeatureTerrain;
import com.volmit.iris.engine.feature.features.FeatureTerrain;
import com.volmit.iris.engine.pipeline.EnginePipeline;
import com.volmit.iris.engine.pipeline.EnginePlumbing;
import com.volmit.iris.engine.pipeline.PipelinePhase;
import com.volmit.iris.engine.pipeline.PipelineTask;
import com.volmit.iris.platform.IrisPlatform;
import com.volmit.iris.platform.PlatformBlock;
import com.volmit.iris.platform.PlatformNamespaceKey;
@ -10,35 +13,40 @@ import com.volmit.iris.platform.PlatformWorld;
import lombok.Data;
import manifold.util.concurrent.ConcurrentWeakHashMap;
import java.io.Closeable;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ForkJoinPool;
@Data
public class IrisEngine {
public class IrisEngine implements Closeable {
private static final Map<Thread, WeakReference<IrisEngine>> engineContext = new ConcurrentWeakHashMap<>();
private final IrisPlatform platform;
private final EngineRegistry registry;
private final EngineConfiguration configuration;
private final PlatformWorld world;
private final EngineBlockCache blockCache;
private final ForkJoinPool forks;
private final FeatureTerrain terrainFeature;
private final EngineExecutor executor;
private final EnginePlumbing plumbing;
public IrisEngine(IrisPlatform platform, PlatformWorld world, EngineConfiguration configuration) {
this.configuration = configuration;
this.forks = new ForkJoinPool(configuration.getThreads());
this.platform = platform;
this.world = world;
this.blockCache = new EngineBlockCache(this);
this.registry = EngineRegistry.builder()
.blockRegistry(new PlatformRegistry<>(platform.getBlocks()))
.biomeRegistry(new PlatformRegistry<>(platform.getBiomes()))
.build();
terrainFeature = new FeatureTerrain(this);
this.blockCache = new EngineBlockCache(this);
this.executor = new EngineExecutor(this);
this.plumbing = EnginePlumbing.builder().engine(this)
.pipeline(EnginePipeline.builder()
.phase(PipelinePhase.builder()
.task(PipelineTask.<PlatformBlock>builder().target(PlatformBlock.class).feature(new FeatureTerrain(this)).build())
.build())
.build())
.build();
}
public PlatformBlock block(String block)
@ -62,4 +70,9 @@ public class IrisEngine {
return Optional.empty();
}
@Override
public void close() throws IOException {
getExecutor().close();
}
}

View File

@ -7,25 +7,27 @@ import lombok.Data;
@Data
public abstract class IrisFeature<T extends PlatformNamespaced, S extends IrisFeatureState> {
private final String name;
private final IrisEngine engine;
private boolean heightAgnostic;
public IrisFeature(String name, IrisEngine engine)
{
this.engine = engine;
this.name = name;
this.heightAgnostic = true;
}
public S prepare(IrisEngine engine, IrisFeatureSizedTarget target)
public IrisFeatureTask<T, S> task(IrisFeatureSizedTarget target, int verticalExecutionSize, int horizontalExecutionSize)
{
return onPrepare(engine, target);
return new IrisFeatureTask<>(engine, this, target, verticalExecutionSize, horizontalExecutionSize, heightAgnostic);
}
public void generate(IrisEngine engine, S state, IrisFeatureTarget<T> target)
public IrisFeatureTask<T, S> task(IrisFeatureSizedTarget target, int horizontalExecutionSize)
{
onGenerate(engine, state, target);
return new IrisFeatureTask<>(engine, this, target, Integer.MAX_VALUE, horizontalExecutionSize, heightAgnostic);
}
public abstract S onPrepare(IrisEngine engine, IrisFeatureSizedTarget target);
public abstract S prepare(IrisEngine engine, IrisFeatureSizedTarget target);
public abstract void onGenerate(IrisEngine engine, S state, IrisFeatureTarget<T> target);
public abstract void generate(IrisEngine engine, S state, IrisFeatureTarget<T> target);
}

View File

@ -1,6 +1,7 @@
package com.volmit.iris.engine.feature;
import art.arcane.amulet.collections.hunk.Hunk;
import art.arcane.amulet.collections.hunk.storage.ArrayHunk;
import art.arcane.amulet.geometry.Vec;
import art.arcane.amulet.range.IntegerRange;
import com.volmit.iris.platform.PlatformNamespaced;
@ -10,6 +11,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Builder
@ -30,8 +32,12 @@ public class IrisFeatureSizedTarget {
@Builder.Default
private final int offsetZ = 0;
Stream<IrisFeatureSizedTarget> splitX()
public <T extends PlatformNamespaced> IrisFeatureTarget<T> hunked()
{
return new IrisFeatureTarget<>(new ArrayHunk<>(width, height, depth), this);
}
Stream<IrisFeatureSizedTarget> splitX() {
if(width <= 1) {
return Stream.of(this);
}
@ -44,8 +50,7 @@ public class IrisFeatureSizedTarget {
.offsetX(offsetX + (width/2)).offsetY(offsetY).offsetZ(offsetZ).build());
}
Stream<IrisFeatureSizedTarget> splitY()
{
Stream<IrisFeatureSizedTarget> splitY() {
if(height <= 1) {
return Stream.of(this);
}
@ -58,8 +63,7 @@ public class IrisFeatureSizedTarget {
.offsetX(offsetX).offsetY(offsetY + (height/2)).offsetZ(offsetZ).build());
}
Stream<IrisFeatureSizedTarget> splitZ()
{
Stream<IrisFeatureSizedTarget> splitZ() {
if(depth <= 1) {
return Stream.of(this);
}
@ -116,4 +120,16 @@ public class IrisFeatureSizedTarget {
{
return new IntegerRange(0, getDepth() - 1);
}
public static IrisFeatureSizedTarget mergedSize(Stream<IrisFeatureSizedTarget> targets) {
List<IrisFeatureSizedTarget> t = targets.toList();
return IrisFeatureSizedTarget.builder()
.width(t.stream().mapToInt(IrisFeatureSizedTarget::getWidth).sum())
.height(t.stream().mapToInt(IrisFeatureSizedTarget::getHeight).sum())
.depth(t.stream().mapToInt(IrisFeatureSizedTarget::getDepth).sum())
.offsetX(t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetX).min().orElse(0))
.offsetY(t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetY).min().orElse(0))
.offsetZ(t.stream().mapToInt(IrisFeatureSizedTarget::getOffsetZ).min().orElse(0))
.build();
}
}

View File

@ -7,6 +7,11 @@ import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
@Data
@EqualsAndHashCode(callSuper = true)
public class IrisFeatureTarget<T extends PlatformNamespaced> extends IrisFeatureSizedTarget {
@ -22,4 +27,16 @@ public class IrisFeatureTarget<T extends PlatformNamespaced> extends IrisFeature
{
this(hunk, target.getOffsetX(), target.getOffsetY(), target.getOffsetZ());
}
public static <V extends PlatformNamespaced> IrisFeatureTarget<V> mergedTarget(Stream<IrisFeatureTarget<V>> targets)
{
List<IrisFeatureTarget<V>> t = targets.toList();
IrisFeatureSizedTarget mergedSize = IrisFeatureSizedTarget.mergedSize(t.stream().map(i -> i));
Hunk<V> hunk = Hunk.newArrayHunk(mergedSize.getWidth(), mergedSize.getHeight(), mergedSize.getDepth());
t.forEach(i -> hunk.insert(
i.getOffsetX() - mergedSize.getOffsetX(),
i.getOffsetY() - mergedSize.getOffsetY(),
i.getOffsetZ() - mergedSize.getOffsetZ(), i.getHunk()));
return new IrisFeatureTarget<>(hunk, mergedSize);
}
}

View File

@ -1,10 +1,12 @@
package com.volmit.iris.engine.feature;
import art.arcane.amulet.collections.hunk.Hunk;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.platform.PlatformNamespaced;
import lombok.AllArgsConstructor;
import lombok.Builder;
import java.util.concurrent.Callable;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;
@ -16,7 +18,7 @@ import java.util.stream.Collectors;
*/
@Builder
@AllArgsConstructor
public class IrisFeatureTask<T extends PlatformNamespaced, S extends IrisFeatureState> extends RecursiveTask<IrisPreparedFeature<T, S>> {
public class IrisFeatureTask<T extends PlatformNamespaced, S extends IrisFeatureState> extends RecursiveTask<IrisFeatureTarget<T>> implements Callable<IrisFeatureTarget<T>> {
private final IrisEngine engine;
private final IrisFeature<T, S> feature;
private final IrisFeatureSizedTarget size;
@ -25,28 +27,30 @@ public class IrisFeatureTask<T extends PlatformNamespaced, S extends IrisFeature
private final boolean heightAgnostic;
@Override
protected IrisPreparedFeature<T, S> compute() {
protected IrisFeatureTarget<T> compute() {
if(!heightAgnostic && size.getHeight() > verticalPrepareSize * 2) {
invokeAll(size.splitY().map(this::with).collect(Collectors.toList()));
return IrisFeatureTarget.mergedTarget(size.splitY().map(i -> engine.getExecutor().getForks().invoke(with(i))));
}
else if(size.getWidth() > horizontalPrepareSize * 2) {
invokeAll(size.splitX().map(this::with).collect(Collectors.toList()));
return IrisFeatureTarget.mergedTarget(size.splitX().map(i -> engine.getExecutor().getForks().invoke(with(i))));
}
else if(size.getDepth() > horizontalPrepareSize * 2) {
invokeAll(size.splitZ().map(this::with).collect(Collectors.toList()));
return IrisFeatureTarget.mergedTarget(size.splitZ().map(i -> engine.getExecutor().getForks().invoke(with(i))));
}
else {
return new IrisPreparedFeature<>(feature, size, feature.prepare(engine, size));
}
return null;
IrisPreparedFeature<T, S> preparedFeature = new IrisPreparedFeature<>(engine, feature, size, feature.prepare(engine, size));
return preparedFeature.generate();
}
private IrisFeatureTask<T, S> with(IrisFeatureSizedTarget size)
{
return new IrisFeatureTask<>(engine, feature, size, verticalPrepareSize, horizontalPrepareSize, heightAgnostic);
}
@Override
public IrisFeatureTarget<T> call() throws Exception {
return compute();
}
}

View File

@ -1,5 +1,6 @@
package com.volmit.iris.engine.feature;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.platform.PlatformNamespaced;
import lombok.Builder;
import lombok.Data;
@ -7,7 +8,20 @@ import lombok.Data;
@Builder
@Data
public class IrisPreparedFeature<T extends PlatformNamespaced, S extends IrisFeatureState> {
private final IrisEngine engine;
private final IrisFeature<T, S> feature;
private final IrisFeatureSizedTarget size;
private final S state;
public IrisFeatureTarget<T> generate()
{
IrisFeatureTarget<T> target = size.hunked();
if(Math.r(0.25))
{
feature.generate(engine, state, target);
}
return target;
}
}

View File

@ -1,4 +1,4 @@
package com.volmit.iris.engine.feature.standard;
package com.volmit.iris.engine.feature.features;
import art.arcane.amulet.range.IntegerRange;
import art.arcane.source.api.noise.Generator;
@ -29,7 +29,7 @@ public class FeatureTerrain extends IrisFeature<PlatformBlock, FeatureTerrain.Te
}
@Override
public TerrainFeatureState onPrepare(IrisEngine engine, IrisFeatureSizedTarget target) {
public TerrainFeatureState prepare(IrisEngine engine, IrisFeatureSizedTarget target) {
final ShortNoiseCache noise = new ShortNoiseCache(target.getWidth(), target.getDepth());
int cx,cz;
@ -48,7 +48,7 @@ public class FeatureTerrain extends IrisFeature<PlatformBlock, FeatureTerrain.Te
}
@Override
public void onGenerate(IrisEngine engine, TerrainFeatureState state, IrisFeatureTarget<PlatformBlock> target) {
public void generate(IrisEngine engine, TerrainFeatureState state, IrisFeatureTarget<PlatformBlock> target) {
for(int x : target.localX()) {
for(int z : target.localZ()) {
int h = state.getNoise().get(x, z);

View File

@ -0,0 +1,29 @@
package com.volmit.iris.engine.pipeline;
import com.volmit.iris.engine.EngineExecutor;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.feature.IrisFeatureSizedTarget;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Singular;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@Builder
public class EnginePipeline
{
@Singular
private final List<PipelinePhase> phases;
public void generate(IrisEngine engine,IrisFeatureSizedTarget target, PipedHunkStack stack)
{
for(PipelinePhase i : phases)
{
i.generate(engine, target, stack);
}
}
}

View File

@ -0,0 +1,29 @@
package com.volmit.iris.engine.pipeline;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.feature.IrisFeatureSizedTarget;
import com.volmit.iris.engine.pipeline.EnginePipeline;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Singular;
import java.util.ArrayList;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
public class EnginePlumbing {
private final IrisEngine engine;
@Singular
private final List<EnginePipeline> pipelines;
public void generate(IrisEngine engine, IrisFeatureSizedTarget target, PipedHunkStack stack)
{
for(EnginePipeline i : pipelines)
{
i.generate(engine, target, stack);
}
}
}

View File

@ -0,0 +1,27 @@
package com.volmit.iris.engine.pipeline;
import art.arcane.amulet.collections.hunk.Hunk;
import com.volmit.iris.platform.PlatformNamespaced;
import java.util.HashMap;
import java.util.Map;
public class PipedHunkStack {
private final Map<Class<? extends PlatformNamespaced>, Hunk<? extends PlatformNamespaced>> hunks;
public PipedHunkStack()
{
this.hunks = new HashMap<>();
}
public void register(Class<? extends PlatformNamespaced> clazz, Hunk<? extends PlatformNamespaced> hunk)
{
hunks.put(clazz, hunk);
}
@SuppressWarnings("unchecked")
public <T extends PlatformNamespaced> Hunk<T> hunk(Class<?> hunk)
{
return (Hunk<T>) hunks.get(hunk);
}
}

View File

@ -0,0 +1,46 @@
package com.volmit.iris.engine.pipeline;
import art.arcane.amulet.collections.ObjectBiset;
import art.arcane.amulet.collections.hunk.Hunk;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.feature.IrisFeature;
import com.volmit.iris.engine.feature.IrisFeatureSizedTarget;
import com.volmit.iris.engine.feature.IrisFeatureTarget;
import com.volmit.iris.engine.feature.IrisFeatureTask;
import com.volmit.iris.platform.PlatformNamespaced;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Singular;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static art.arcane.amulet.MagicalSugar.*;
@Data
@Builder
@AllArgsConstructor
public class PipelinePhase
{
@Singular
private final List<PipelineTask<?>> tasks;
@SuppressWarnings({"unchecked"})
public void generate(IrisEngine engine, IrisFeatureSizedTarget target, PipedHunkStack stack) {
List<IrisFeatureTarget<?>> targets = engine.getExecutor().getForks().invokeAll(tasks.stream().map(i -> i.task(target)).collect(Collectors.toList())).stream().map(i -> {
try {
return i.get();
} catch(InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
for(int i : index targets)
{
IrisFeatureTarget<?> targetResult = targets[i];
stack.hunk(tasks[i].getTarget()).insert((Hunk<PlatformNamespaced>) targetResult.getHunk());
}
}
}

View File

@ -0,0 +1,22 @@
package com.volmit.iris.engine.pipeline;
import com.volmit.iris.engine.feature.IrisFeature;
import com.volmit.iris.engine.feature.IrisFeatureSizedTarget;
import com.volmit.iris.engine.feature.IrisFeatureTask;
import com.volmit.iris.platform.PlatformNamespaced;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@AllArgsConstructor
@Builder
@Data
public class PipelineTask<T extends PlatformNamespaced>
{
private final IrisFeature<T, ?> feature;
private final Class<T> target;
public IrisFeatureTask<T, ?> task(IrisFeatureSizedTarget target){
return feature.task(target, 1000, 4);
}
}