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.
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user