mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 22:10:18 +00:00
Idle-aware fallback trial batches
- Fallback trials budget a measured 128 MB each instead of 1 GB - Trial batches grow with idle hydrology workers up to the trial limit
This commit is contained in:
1 parent
c3b3f1d8aa
commit
4703d473cc
7 files changed
+105
-22
No files matched your search
+19
-1
@@ -36,7 +36,8 @@ public class HydrologyFallbackParallelismTest {
|
||||
@Test(timeout = 15000)
|
||||
public void publicationRejectionConsumesTheNextCompletedOutletWithoutRebuildingIt() throws Exception {
|
||||
int parallelism = HydrologyPlanningAdmission.effectiveParallelism(4);
|
||||
int batchSize = parallelism <= 2 ? 1 : Math.min(parallelism, HydrologyPlanningAdmission.maximumTrials());
|
||||
int batchSize = HydrologyCrossTileResolver.fallbackTrialBatch(parallelism, parallelism - 1,
|
||||
HydrologyPlanningAdmission.maximumTrials());
|
||||
AtomicIntegerArray builds = new AtomicIntegerArray(4);
|
||||
Fixture fixture = fixture(outlet -> {
|
||||
builds.incrementAndGet(outlet);
|
||||
@@ -77,6 +78,23 @@ public class HydrologyFallbackParallelismTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fallbackTrialBatchesGrowIntoIdleWorkersWithinTheTrialLimit() {
|
||||
assertEquals(1, HydrologyCrossTileResolver.fallbackTrialBatch(1, 0, 16));
|
||||
assertEquals(1, HydrologyCrossTileResolver.fallbackTrialBatch(2, 1, 16));
|
||||
assertEquals(2, HydrologyCrossTileResolver.fallbackTrialBatch(12, 0, 16));
|
||||
assertEquals(2, HydrologyCrossTileResolver.fallbackTrialBatch(12, 1, 16));
|
||||
assertEquals(6, HydrologyCrossTileResolver.fallbackTrialBatch(12, 5, 16));
|
||||
assertEquals(12, HydrologyCrossTileResolver.fallbackTrialBatch(12, 11, 16));
|
||||
assertEquals(12, HydrologyCrossTileResolver.fallbackTrialBatch(12, 40, 16));
|
||||
assertEquals(16, HydrologyCrossTileResolver.fallbackTrialBatch(32, 31, 16));
|
||||
assertEquals(16, HydrologyCrossTileResolver.fallbackTrialBatch(32, 31, 64));
|
||||
assertEquals(8, HydrologyCrossTileResolver.fallbackTrialBatch(12, 11, 8));
|
||||
assertEquals(2, HydrologyCrossTileResolver.fallbackTrialBatch(12, 11, 2));
|
||||
assertEquals(1, HydrologyCrossTileResolver.fallbackTrialBatch(12, 11, 1));
|
||||
assertEquals(1, HydrologyCrossTileResolver.fallbackTrialBatch(12, 0, 1));
|
||||
}
|
||||
|
||||
@Test(timeout = 15000)
|
||||
public void limitedWorkersStopAfterTheFirstAcceptedOutlet() throws Exception {
|
||||
int[] poolSizes = Runtime.getRuntime().availableProcessors() <= 2 ? new int[]{1, 2, 16} : new int[]{1, 2};
|
||||
|
||||
@@ -5,6 +5,7 @@ import art.arcane.iris.generation.hydrology.policy.SurfaceRiverPolicy;
|
||||
import art.arcane.iris.generation.hydrology.cave.HydrologyCavePlan;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -13,6 +14,9 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -28,12 +32,34 @@ public class HydrologyPlanHashTest {
|
||||
|
||||
@Test
|
||||
public void fullTilePlansAreByteIdentical() {
|
||||
PlanDigest plan = planDigest(planner -> planner);
|
||||
assertTrue("planned courses: " + plan.courses(), plan.courses() > 0);
|
||||
assertTrue("planned columns: " + plan.columns(), plan.columns() > 0);
|
||||
assertEquals(EXPECTED_PLAN_DIGEST, plan.digest());
|
||||
}
|
||||
|
||||
@Test(timeout = 180000)
|
||||
public void fallbackTrialBatchSizeNeverChangesThePlan() throws Exception {
|
||||
for (int trialLimit : new int[]{1, 2, 8, 16}) {
|
||||
ForkJoinPool pool = new ForkJoinPool(16);
|
||||
try {
|
||||
PlanDigest plan = pool.submit(() -> planDigest(planner -> withTrialLimit(planner, trialLimit)))
|
||||
.get(60L, TimeUnit.SECONDS);
|
||||
assertEquals("trial limit " + trialLimit, EXPECTED_PLAN_DIGEST, plan.digest());
|
||||
} finally {
|
||||
pool.shutdownNow();
|
||||
assertTrue(pool.awaitTermination(5L, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PlanDigest planDigest(UnaryOperator<HydrologyPlanner> configure) {
|
||||
MessageDigest canonical = sha256();
|
||||
int courses = 0;
|
||||
int columns = 0;
|
||||
for (long seed : new long[]{77L, 19L}) {
|
||||
HydrologyPlannerSettings settings = planSettings();
|
||||
HydrologyPlanner planner = new HydrologyPlanner(seed, settings, rollingCoast(112));
|
||||
HydrologyPlanner planner = configure.apply(new HydrologyPlanner(seed, settings, rollingCoast(112)));
|
||||
for (HydrologyTileKey key : TILES) {
|
||||
HydrologyTile tile = planner.plan(key);
|
||||
courses += tile.courses().size();
|
||||
@@ -41,9 +67,18 @@ public class HydrologyPlanHashTest {
|
||||
render(tile, canonical);
|
||||
}
|
||||
}
|
||||
assertTrue("planned courses: " + courses, courses > 0);
|
||||
assertTrue("planned columns: " + columns, columns > 0);
|
||||
assertEquals(EXPECTED_PLAN_DIGEST, HexFormat.of().formatHex(canonical.digest()));
|
||||
return new PlanDigest(HexFormat.of().formatHex(canonical.digest()), courses, columns);
|
||||
}
|
||||
|
||||
private static HydrologyPlanner withTrialLimit(HydrologyPlanner planner, int trialLimit) {
|
||||
try {
|
||||
Field crossTile = HydrologyPlanner.class.getDeclaredField("crossTile");
|
||||
crossTile.setAccessible(true);
|
||||
crossTile.set(planner, new HydrologyCrossTileResolver(planner, trialLimit));
|
||||
return planner;
|
||||
} catch (ReflectiveOperationException failure) {
|
||||
throw new IllegalStateException(failure);
|
||||
}
|
||||
}
|
||||
|
||||
private static void render(HydrologyTile tile, MessageDigest digest) {
|
||||
@@ -223,6 +258,9 @@ public class HydrologyPlanHashTest {
|
||||
);
|
||||
}
|
||||
|
||||
private record PlanDigest(String digest, int courses, int columns) {
|
||||
}
|
||||
|
||||
private static final class CanonicalDigest {
|
||||
private final MessageDigest digest;
|
||||
|
||||
|
||||
+10
-6
@@ -50,12 +50,16 @@ public class HydrologyPlanningAdmissionTest {
|
||||
|
||||
@Test
|
||||
public void trialLimitSharesWorkingMemoryBetweenAdmittedRoots() {
|
||||
long gibibyte = 1024L * 1024L * 1024L;
|
||||
assertEquals(1, HydrologyPlanningAdmission.trialLimit(1280L * 1024L * 1024L, 1));
|
||||
assertEquals(2, HydrologyPlanningAdmission.trialLimit(2L * gibibyte, 1));
|
||||
assertEquals(2, HydrologyPlanningAdmission.trialLimit(4L * gibibyte, 2));
|
||||
assertEquals(1, HydrologyPlanningAdmission.trialLimit(gibibyte / 2L, 1));
|
||||
assertEquals(8, HydrologyPlanningAdmission.trialLimit(64L * gibibyte, 8));
|
||||
long mebibyte = 1024L * 1024L;
|
||||
long gibibyte = 1024L * mebibyte;
|
||||
assertEquals(1, HydrologyPlanningAdmission.trialLimit(64L * mebibyte, 1));
|
||||
assertEquals(1, HydrologyPlanningAdmission.trialLimit(128L * mebibyte, 1));
|
||||
assertEquals(4, HydrologyPlanningAdmission.trialLimit(gibibyte / 2L, 1));
|
||||
assertEquals(4, HydrologyPlanningAdmission.trialLimit(gibibyte, 2));
|
||||
assertEquals(10, HydrologyPlanningAdmission.trialLimit(1280L * mebibyte, 1));
|
||||
assertEquals(16, HydrologyPlanningAdmission.trialLimit(2L * gibibyte, 1));
|
||||
assertEquals(16, HydrologyPlanningAdmission.trialLimit(6L * gibibyte, 3));
|
||||
assertEquals(16, HydrologyPlanningAdmission.trialLimit(16L * gibibyte, 8));
|
||||
assertEquals(16, HydrologyPlanningAdmission.trialLimit(Long.MAX_VALUE, 8));
|
||||
assertThrows(IllegalArgumentException.class, () -> HydrologyPlanningAdmission.trialLimit(gibibyte, 0));
|
||||
}
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ public final class HydrologyRegionalFallsTest {
|
||||
SurfaceBounds bounds = new SurfaceBounds(-2, -2, 1, 2);
|
||||
HydrologyFootprintCompiler compiler = new HydrologyFootprintCompiler(SETTINGS, TERRAIN, planner.geometrySampler);
|
||||
compiler.seedRegionalSurface(network, bounds);
|
||||
HydrologyCrossTileResolver.MaterializedHydrology materialized = new HydrologyCrossTileResolver(planner)
|
||||
HydrologyCrossTileResolver.MaterializedHydrology materialized = planner.crossTile
|
||||
.materializeFinalHydrology(new HydrologyCaveCourseFilter.Result(network.nodes(), network.edges(),
|
||||
network.outlets(), network.courses(), plans), new ArrayList<>(), compiler, true);
|
||||
HydrologyCaveCourseFilter.Result clipped = HydrologyCrossTileResolver.clipRegionalPlans(materialized.result(), network, bounds);
|
||||
@@ -108,7 +108,7 @@ public final class HydrologyRegionalFallsTest {
|
||||
compiler.seedRegionalSurface(regional, bounds);
|
||||
HydrologyCaveCourseFilter.Result result = new HydrologyCaveCourseFilter.Result(metadata.nodes(), metadata.edges(),
|
||||
metadata.outlets(), metadata.courses(), plans);
|
||||
HydrologyCrossTileResolver.MaterializedHydrology materialized = new HydrologyCrossTileResolver(planner)
|
||||
HydrologyCrossTileResolver.MaterializedHydrology materialized = planner.crossTile
|
||||
.materializeFinalHydrology(result, new ArrayList<>(), compiler, true);
|
||||
assertEquals("A clipped raster cannot replace the full regional containment proof", 1, validations.get());
|
||||
HydrologyCaveCourseFilter.Result clipped = HydrologyCrossTileResolver.clipRegionalPlans(materialized.result(), regional, bounds);
|
||||
|
||||
Reference in new issue
Block a user