Files
owniverse/tests/test_simulation_optimizations.gd
T
Kirill e48d4bbe88 Add comprehensive tests and optimizations for simulation and UI performance
- Introduced a new benchmark save script to create a stress test scenario with extreme values for simulation performance.
- Added a full UI benchmark script to measure frame rates and performance metrics during UI interactions.
- Implemented tests for coarse generations to ensure population transitions are handled correctly.
- Created tests for extra parameters to validate the loading and application of configuration settings.
- Developed simulation optimization tests to verify the efficiency of population drift and rounding mechanisms.
- Added split optimization tests to ensure accurate allocation and rounding behavior in population management.
- Included startup parameter tests to confirm the correct initialization of global parameters before scene readiness.
- Enhanced the audit rounding ledger to compare selective and full rounding results for consistency.
2026-10-05 22:16:59 +03:00

113 lines
6.9 KiB
GDScript

extends SceneTree
const E = preload("res://world/owniverse/math/exact.gd")
const Civ = preload("res://world/owniverse/civilization_evolution.gd")
const Fixture = preload("res://tests/fixtures/civilization_benchmark.gd")
var checks: int = 0
var failures: int = 0
func _initialize(): call_deferred("run")
func check(value: bool, message: String):
checks += 1
if not value:
failures += 1
push_error(message)
func reference_drift(target: Dictionary, pop: Dictionary, rows: Dictionary, diplomacy: bool, colony: bool) -> Dictionary:
var weights: Dictionary = {}
for other in Civ.ETHICS: weights[other] = 0
for ethic in pop:
var contribution: Variant = E.multiply(pop[ethic], E.of(rows[ethic].diplomacy_rate) if diplomacy else 1)
if E.eq(contribution, 0): continue
for other in Civ.ETHICS:
var weight: int = 9 if colony else 1
if other == ethic: weight = 960 if colony else 196
elif other == Civ.OPPOSITE[ethic]: weight = 4 if colony else 0
weights[other] = E.add(weights[other], E.multiply(contribution, weight))
if E.le(Civ.total(weights), 0): return pop.duplicate()
return Civ.split(target, "test", Civ.total(pop), weights)
func run():
var rows: Dictionary = {}
for ethic in Civ.ETHICS: rows[ethic] = {"diplomacy_rate": "0.125" if ethic == "m" else "1.75"}
for count in [0, 1, 7, 999999999, E.of("1e40")]:
for diplomacy in [false, true]:
for colony in [false, true]:
var actual: Dictionary = {}
var reference: Dictionary = {}
for round_index in 5:
var pop: Dictionary = {"m": count, "l": round_index, "w": 9, "d": 0, "c": 137, "b": 2}
var result: Dictionary = Civ.drift(actual, "test", pop, rows, diplomacy, colony)
if diplomacy:
check(E.eq(result, reference_drift(reference, pop, rows, diplomacy, colony)), "Diplomatic drift preserves allocation")
var carries_valid: bool = true
for value in actual.get("civilization_remainders", {}).values():
carries_valid = carries_valid and E.ge(value, -1) and E.le(value, 1)
check(carries_valid, "Diplomatic drift carries stay bounded")
else:
check(E.eq(Civ.total(result), Civ.total(pop)), "Integer flow drift conserves population")
var valid_whole: bool = true
for ethic in Civ.ETHICS:
valid_whole = valid_whole and E.ge(result[ethic], 0) and E.eq(result[ethic], E.floor_value(result[ethic]))
check(valid_whole, "Integer flow drift has nonnegative whole counts")
var decimal_rows: Dictionary = {}
for ethic in Civ.ETHICS: decimal_rows[ethic] = {"diplomacy_rate": "0.333333333333" if ethic == "m" else "0.017"}
var decimal_target: Dictionary = {}
for round_index in 20:
var pop: Dictionary = {"m": E.of("1e40"), "l": round_index, "w": 17, "d": 4, "c": 91, "b": 2}
var result: Dictionary = Civ.drift(decimal_target, "decimal", pop, decimal_rows, true)
check(E.eq(Civ.total(result), Civ.total(pop)), "Decimal diplomatic drift preserves whole population")
for ethic in result:
check(E.ge(result[ethic], 0) and E.eq(result[ethic], E.floor_value(result[ethic])), "Decimal drift returns nonnegative whole counts")
for speed in [1, 4, 6]:
var world = load("res://world/owniverse/owniverse.gd").new()
world.catalog.load_definitions(root.get_node("Global").OwniverseEntities)
Fixture.seed(world, root.get_node("Global"), true, true)
var rules: Dictionary = root.get_node("Global").CivilizationRules
var id: String = rules.keys()[0]
var modifiers: Dictionary = {"progress": 1, "degradation": 1, "war": 1, "colonization": 1}
var original: Dictionary = Civ.coefficients(world, rules, id, modifiers).duplicate(true)
modifiers.progress = 2
var changed: Dictionary = Civ.coefficients(world, rules, id, modifiers)
var row: Dictionary = rules[id].ethics.m
var p: Variant = E.maximum(0, E.multiply(E.of(row.progress), 2))
var d: Variant = E.maximum(0, E.of(row.degradation))
check(E.eq(changed.m.pro, E.divide(p, E.maximum(1, E.add(p, d)))), "Coefficient cache follows modifiers")
modifiers.progress = 1
check(E.eq(Civ.coefficients(world, rules, id, modifiers), original), "Coefficient cache restores original rates")
var local_rules: Dictionary = rules.duplicate(true)
local_rules[id].ethics.m.progress = "0.375"
changed = Civ.coefficients(world, local_rules, id, modifiers)
check(E.eq(changed.m.pro, E.divide(E.of("0.375"), E.maximum(1, E.add(E.of("0.375"), d)))), "Coefficient cache follows rule edits")
var target: Dictionary = {"ethics": {}}
Civ.State.reconcile(world, target, rules, {id: 60})
target.ethics[id].m = 100
Civ.State.reconcile(world, target, rules, {id: 60})
check(E.eq(Civ.total(target.ethics[id]), 60), "Reconcile cache detects changed ethics")
Civ.State.reconcile(world, target, rules, {id: 120})
check(E.eq(Civ.total(target.ethics[id]), 120), "Reconcile cache detects changed population")
Civ.worship(world, target, rules)
target.ethics[id].m = E.add(target.ethics[id].m, 5)
var expected: Variant = 0
for stage in rules:
if rules[stage].worships:
for ethic in target.ethics[stage]:
expected = E.add(expected, E.multiply(target.ethics[stage][ethic], E.of(rules[stage].ethics[ethic].worship)))
check(E.eq(Civ.worship(world, target, rules), expected), "Worship cache detects changed ethics")
var worship_rules: Dictionary = rules.duplicate(true)
for stage in worship_rules:
if worship_rules[stage].worships:
worship_rules[stage].ethics.m.worship = "0.375"
expected = 0
for stage in worship_rules:
if worship_rules[stage].worships:
for ethic in target.ethics[stage]:
expected = E.add(expected, E.multiply(target.ethics[stage][ethic], E.of(worship_rules[stage].ethics[ethic].worship)))
check(E.eq(Civ.worship(world, target, worship_rules), expected), "Worship cache detects changed rules")
world.ledger = load("res://tests/fixtures/audit_rounding_ledger.gd").new(world)
world.speed = speed
for i in 3: world.evolute(1.0 if speed == 1 else 0.1)
check(world.ledger.checks > 0 and world.ledger.failures == 0, "Selective and full rounding agree at speed %d" % speed)
for entity in world.catalog.entities.values(): entity.free()
world.free()
print("Simulation optimizations: %d checks, %d failures" % [checks, failures])
quit(1 if failures else 0)