reduce overhead of profiler when not profiling

This commit is contained in:
dfsek
2022-05-26 12:51:18 -07:00
parent 5275c40c6a
commit 3ec15960cf
6 changed files with 121 additions and 148 deletions
@@ -18,7 +18,6 @@ import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.SamplerProvider;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
@@ -51,56 +50,56 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
public void generateChunkData(@NotNull ProtoChunk chunk, @NotNull WorldProperties world, public void generateChunkData(@NotNull ProtoChunk chunk, @NotNull WorldProperties world,
@NotNull BiomeProvider biomeProvider, @NotNull BiomeProvider biomeProvider,
int chunkX, int chunkZ) { int chunkX, int chunkZ) {
try(ProfileFrame ignore = platform.getProfiler().profile("chunk_base_3d")) { platform.getProfiler().push("chunk_base_3d");
int xOrig = (chunkX << 4); int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4); int zOrig = (chunkZ << 4);
Sampler3D sampler = samplerCache.getChunk(chunkX, chunkZ, world, biomeProvider); Sampler3D sampler = samplerCache.getChunk(chunkX, chunkZ, world, biomeProvider);
long seed = world.getSeed(); long seed = world.getSeed();
LazilyEvaluatedInterpolator carver = new LazilyEvaluatedInterpolator(biomeProvider, LazilyEvaluatedInterpolator carver = new LazilyEvaluatedInterpolator(biomeProvider,
chunkX, chunkX,
chunkZ, chunkZ,
world.getMaxHeight(), world.getMaxHeight(),
world.getMinHeight(), world.getMinHeight(),
carverHorizontalResolution, carverHorizontalResolution,
carverVerticalResolution, carverVerticalResolution,
seed); seed);
for(int x = 0; x < 16; x++) { for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) { for(int z = 0; z < 16; z++) {
int paletteLevel = 0; int paletteLevel = 0;
int cx = xOrig + x; int cx = xOrig + x;
int cz = zOrig + z; int cz = zOrig + z;
Biome biome = biomeProvider.getBiome(cx, cz, seed); Biome biome = biomeProvider.getBiome(cx, cz, seed);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class); PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
int sea = paletteInfo.seaLevel(); int sea = paletteInfo.seaLevel();
Palette seaPalette = paletteInfo.ocean(); Palette seaPalette = paletteInfo.ocean();
BlockState data; BlockState data;
for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) { for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) {
if(sampler.sample(x, y, z) > 0) { if(sampler.sample(x, y, z) > 0) {
if(carver.sample(x, y, z) <= 0) { if(carver.sample(x, y, z) <= 0) {
data = PaletteUtil.getPalette(x, y, z, sampler, paletteInfo, paletteLevel).get(paletteLevel, cx, y, cz, data = PaletteUtil.getPalette(x, y, z, sampler, paletteInfo, paletteLevel).get(paletteLevel, cx, y, cz,
seed); seed);
chunk.setBlock(x, y, z, data); chunk.setBlock(x, y, z, data);
}
paletteLevel++;
} else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed));
paletteLevel = 0;
} else {
paletteLevel = 0;
} }
paletteLevel++;
} else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed));
paletteLevel = 0;
} else {
paletteLevel = 0;
} }
} }
} }
} }
platform.getProfiler().pop("chunk_base_3d");
} }
@Override @Override
@@ -12,7 +12,6 @@ import java.util.Random;
import com.dfsek.terra.addons.generation.feature.config.BiomeFeatures; import com.dfsek.terra.addons.generation.feature.config.BiomeFeatures;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.registry.key.StringIdentifiable; import com.dfsek.terra.api.registry.key.StringIdentifiable;
import com.dfsek.terra.api.util.Rotation; import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.vector.Vector3Int; import com.dfsek.terra.api.util.vector.Vector3Int;
@@ -27,49 +26,52 @@ public class FeatureGenerationStage implements GenerationStage, StringIdentifiab
private final String id; private final String id;
private final String profile;
public FeatureGenerationStage(Platform platform, String id) { public FeatureGenerationStage(Platform platform, String id) {
this.platform = platform; this.platform = platform;
this.id = id; this.id = id;
this.profile = "feature_stage:" + id;
} }
@Override @Override
@SuppressWarnings("try") @SuppressWarnings("try")
public void populate(ProtoWorld world) { public void populate(ProtoWorld world) {
try(ProfileFrame ignore = platform.getProfiler().profile("feature_stage:" + id)) { platform.getProfiler().push(profile);
int cx = world.centerChunkX() << 4; int cx = world.centerChunkX() << 4;
int cz = world.centerChunkZ() << 4; int cz = world.centerChunkZ() << 4;
long seed = world.getSeed(); long seed = world.getSeed();
for(int x = 0; x < 16; x++) { for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) { for(int z = 0; z < 16; z++) {
int tx = cx + x; int tx = cx + x;
int tz = cz + z; int tz = cz + z;
Column<WritableWorld> column = world.column(tx, tz); Column<WritableWorld> column = world.column(tx, tz);
long coordinateSeed = (seed * 31 + tx) * 31 + tz; long coordinateSeed = (seed * 31 + tx) * 31 + tz;
world.getBiomeProvider() world.getBiomeProvider()
.getBiome(tx, tz, seed) .getBiome(tx, tz, seed)
.getContext() .getContext()
.get(BiomeFeatures.class) .get(BiomeFeatures.class)
.getFeatures() .getFeatures()
.getOrDefault(this, Collections.emptyList()) .getOrDefault(this, Collections.emptyList())
.forEach(feature -> { .forEach(feature -> {
try(ProfileFrame ignored = platform.getProfiler().profile(feature.getID())) { platform.getProfiler().push(feature.getID());
if(feature.getDistributor().matches(tx, tz, seed)) { if(feature.getDistributor().matches(tx, tz, seed)) {
feature.getLocator() feature.getLocator()
.getSuitableCoordinates(column) .getSuitableCoordinates(column)
.forEach(y -> .forEach(y ->
feature.getStructure(world, tx, y, tz) feature.getStructure(world, tx, y, tz)
.generate(Vector3Int.of(tx, y, tz), .generate(Vector3Int.of(tx, y, tz),
world, world,
new Random(coordinateSeed * 31 + y), new Random(coordinateSeed * 31 + y),
Rotation.NONE) Rotation.NONE)
); );
} }
} platform.getProfiler().pop(feature.getID());
}); });
}
} }
} }
platform.getProfiler().pop(profile);
} }
@Override @Override
@@ -39,7 +39,6 @@ import com.dfsek.terra.addons.terrascript.script.builders.UnaryNumberFunctionBui
import com.dfsek.terra.addons.terrascript.script.builders.UnaryStringFunctionBuilder; import com.dfsek.terra.addons.terrascript.script.builders.UnaryStringFunctionBuilder;
import com.dfsek.terra.addons.terrascript.script.builders.ZeroArgFunctionBuilder; import com.dfsek.terra.addons.terrascript.script.builders.ZeroArgFunctionBuilder;
import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.registry.Registry; import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.Keyed; import com.dfsek.terra.api.registry.key.Keyed;
import com.dfsek.terra.api.registry.key.RegistryKey; import com.dfsek.terra.api.registry.key.RegistryKey;
@@ -54,6 +53,8 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
private static final Logger LOGGER = LoggerFactory.getLogger(StructureScript.class); private static final Logger LOGGER = LoggerFactory.getLogger(StructureScript.class);
private final Block block; private final Block block;
private final RegistryKey id; private final RegistryKey id;
private final String profile;
private final Platform platform; private final Platform platform;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@@ -67,6 +68,7 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
this.id = id; this.id = id;
this.profile = "terrascript_direct:" + id;
//noinspection unchecked //noinspection unchecked
functionRegistry.forEach((key, function) -> parser.registerFunction(key.getID(), function)); // Register registry functions. functionRegistry.forEach((key, function) -> parser.registerFunction(key.getID(), function)); // Register registry functions.
@@ -129,15 +131,17 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
@Override @Override
@SuppressWarnings("try") @SuppressWarnings("try")
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
try(ProfileFrame ignore = platform.getProfiler().profile("terrascript_direct:" + id)) { platform.getProfiler().push(profile);
return applyBlock(new TerraImplementationArguments(location, rotation, random, world, 0)); boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, 0));
} platform.getProfiler().pop(profile);
return result;
} }
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation, int recursions) { public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation, int recursions) {
try(ProfileFrame ignore = platform.getProfiler().profile("terrascript_direct:" + id)) { platform.getProfiler().push(profile);
return applyBlock(new TerraImplementationArguments(location, rotation, random, world, recursions)); boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, recursions));
} platform.getProfiler().pop(profile);
return result;
} }
private boolean applyBlock(TerraImplementationArguments arguments) { private boolean applyBlock(TerraImplementationArguments arguments) {
@@ -1,21 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the common/api directory.
*/
package com.dfsek.terra.api.profiler;
public class ProfileFrame implements AutoCloseable {
private final Runnable action;
public ProfileFrame(Runnable action) {
this.action = action;
}
@Override
public void close() {
action.run();
}
}
@@ -36,21 +36,6 @@ public interface Profiler {
*/ */
void stop(); void stop();
/**
* Return a {@link AutoCloseable} implementation that
* may be used in a try-with-resources statement for
* more intuitive profiling, with auto-push/pop.
*
* @param frame ID of frame.
*
* @return {@link AutoCloseable} implementation for use
* in try-with-resources.
*/
default ProfileFrame profile(String frame) {
push(frame);
return new ProfileFrame(() -> pop(frame));
}
/** /**
* Clear the profiler data. * Clear the profiler data.
*/ */
@@ -51,38 +51,42 @@ public class ProfilerImpl implements Profiler {
@Override @Override
public void push(String frame) { public void push(String frame) {
STACK_SIZE.get().increment(); if(running) {
if(running && SAFE.get()) { STACK_SIZE.get().increment();
Stack<Frame> stack = THREAD_STACK.get(); if(SAFE.get()) {
stack.push(new Frame(stack.isEmpty() ? frame : stack.peek().getId() + "." + frame)); Stack<Frame> stack = THREAD_STACK.get();
stack.push(new Frame(stack.isEmpty() ? frame : stack.peek().getId() + "." + frame));
} else SAFE.set(false);
} else SAFE.set(false); } else SAFE.set(false);
} }
@Override @Override
public void pop(String frame) { public void pop(String frame) {
MutableInteger size = STACK_SIZE.get(); if(running) {
size.decrement(); MutableInteger size = STACK_SIZE.get();
if(running && SAFE.get()) { size.decrement();
long time = System.nanoTime(); if(SAFE.get()) {
Stack<Frame> stack = THREAD_STACK.get(); long time = System.nanoTime();
Stack<Frame> stack = THREAD_STACK.get();
Map<String, List<Long>> timingsMap = TIMINGS.get(); Map<String, List<Long>> timingsMap = TIMINGS.get();
if(timingsMap.isEmpty()) { if(timingsMap.isEmpty()) {
synchronized(accessibleThreadMaps) { synchronized(accessibleThreadMaps) {
accessibleThreadMaps.add(timingsMap); accessibleThreadMaps.add(timingsMap);
}
} }
Frame top = stack.pop();
if(!stack.isEmpty() ? !top.getId().endsWith("." + frame) : !top.getId().equals(frame))
throw new MalformedStackException("Expected " + frame + ", found " + top);
List<Long> timings = timingsMap.computeIfAbsent(top.getId(), id -> new ArrayList<>());
timings.add(time - top.getStart());
} }
if(size.get() == 0) SAFE.set(true);
Frame top = stack.pop();
if(!stack.isEmpty() ? !top.getId().endsWith("." + frame) : !top.getId().equals(frame))
throw new MalformedStackException("Expected " + frame + ", found " + top);
List<Long> timings = timingsMap.computeIfAbsent(top.getId(), id -> new ArrayList<>());
timings.add(time - top.getStart());
} }
if(size.get() == 0) SAFE.set(true);
} }
@Override @Override