Files
owniverse/tests/benchmark_large_star_cohorts.gd
T

131 lines
7.1 KiB
GDScript
Raw Normal View History

extends SceneTree
## Paired old/new cohort timing on separate generated large diagnostic saves.
const E = preload("res://world/owniverse/math/exact.gd")
var cycles: int = 50
var repeats: int = 2
var artifact_prefix: String = "large_star_cohorts"
func _initialize(): call_deferred("run")
func restore_json_integers(value):
if value is float and value == floorf(value) and absf(value) <= 9007199254740991: return int(value)
if value is Dictionary:
for key in value: value[key] = restore_json_integers(value[key])
elif value is Array:
for i in value.size(): value[i] = restore_json_integers(value[i])
return value
func dispose(world):
for entity in world.catalog.entities.values(): entity.free()
world.free()
func world_from(state: Dictionary, use_cycles: bool):
var world = load("res://world/owniverse/owniverse.gd").new()
world.catalog.load_definitions(root.get_node("Global").OwniverseEntities)
world.state = state.duplicate(true)
world.speed = 6
world.batches.cycle_stars = use_cycles
return world
func cohort_count(world) -> int:
var total: int = 0
for id in world.state.batches:
if world.catalog.entities[id].group_as == "Star": total += world.state.batches[id].size()
return total
func make_state(initial: Dictionary, use_cycles: bool) -> Dictionary:
var world = world_from(initial, use_cycles)
var anchor: Variant = E.of("1e12")
var shift: Variant = E.subtract(anchor, world.state.time.datetime)
for id in world.state.batches:
for batch: Dictionary in world.state.batches[id]:
for field in ["created_from", "created_to", "start_year", "end_year", "processed_until"]:
if batch.has(field): batch[field] = E.add(batch[field], shift)
for id in world.state.batch_origins:
world.state.batch_origins[id] = E.add(world.state.batch_origins[id], shift)
world.state.time = {"datetime": anchor, "year": anchor}
var physical: Dictionary = world.ledger.physical_amounts(world.state)
var populations: Dictionary = {}
for id in world.catalog.entities:
var entity = world.catalog.entities[id]
if entity.group_as != "Star" or E.le(entity.lifespan, 0) or E.le(physical.get(id, 0), 0): continue
world.state.batches[id] = []
world.state.batch_origins.erase(id)
var lifespan: Variant = world.batches.effective_lifespan(world.state, id)
var birth_from: Variant = E.subtract(anchor, lifespan)
var duration: Variant = E.minimum(lifespan, 2000000)
world.batches.append_batch(world.state, id, physical[id], birth_from, E.add(birth_from, duration))
populations[id] = E.fixed(physical[id])
var payload: Dictionary = {"format_version": 6, "app_version": "0.7.0", "ui": {"current_page": 0}, "state": world.state,
"simulation": {"active_clock": {}, "requested_clock": {}, "productions": [], "speed": 6}}
var error: String = root.get_node("SaveManager").validate_data(payload)
assert(error.is_empty(), error)
var suffix: String = "cycle" if use_cycles else "legacy"
var path: String = "res://tests/artifacts/%s_%s.adventure.json" % [artifact_prefix, suffix]
var output = FileAccess.open(path, FileAccess.WRITE)
assert(output != null)
output.store_string(JSON.stringify(E.encode(payload), " ", true, true))
output.close()
print("Generated %s: star_types=%d stellar_cohorts=%d populations=%s" % [suffix, populations.size(), cohort_count(world), str(populations)])
var restored: Dictionary = E.decode(restore_json_integers(JSON.parse_string(FileAccess.get_file_as_string(path))))
assert(E.eq(restored.state, world.state), "Diagnostic file roundtrip changed initial state")
dispose(world)
return restored.state
func measure(initial: Dictionary, use_cycles: bool, run_index: int) -> Dictionary:
var world = world_from(initial, use_cycles)
world.profile_enabled = true
var samples: Array = []
var total_usec: int = 0
var initial_year: Variant = world.state.time.datetime
var peak_cohorts: int = cohort_count(world)
for cycle in cycles:
var started: int = Time.get_ticks_usec()
world.evolute(0.2)
var elapsed: int = Time.get_ticks_usec() - started
total_usec += elapsed
samples.append(elapsed / 1000.0)
peak_cohorts = maxi(peak_cohorts, cohort_count(world))
var applied: Variant = E.subtract(world.state.time.datetime, initial_year)
assert(E.eq(applied, cycles * 20000))
var error: String = root.get_node("SaveManager").validate_data({"format_version": 6, "app_version": "0.7.0", "ui": {"current_page": 0}, "state": world.state})
assert(error.is_empty(), error)
samples.sort()
var result: Dictionary = {"model": "cycle" if use_cycles else "legacy", "repeat": run_index, "cycles": cycles,
"mean_ms": total_usec / (1000.0 * cycles), "min_ms": samples.front(), "max_ms": samples.back(), "p95_ms": samples[int(ceil(samples.size() * 0.95)) - 1],
"cycles_per_second": cycles * 1000000.0 / total_usec, "throughput": cycles * 200000.0 / total_usec,
"game_years": E.fixed(applied), "peak_stellar_cohorts": peak_cohorts, "final_stellar_cohorts": cohort_count(world), "profile": world.profile.duplicate(true)}
print("PAIRED_RESULT ", JSON.stringify(result))
dispose(world)
return result
func run():
for arg in OS.get_cmdline_user_args():
if arg.begins_with("cycles="): cycles = maxi(1, arg.trim_prefix("cycles=").to_int())
if arg.begins_with("repeats="): repeats = maxi(1, arg.trim_prefix("repeats=").to_int())
var raw = JSON.parse_string(FileAccess.get_file_as_string("res://tests/artifacts/all_objects_speed6.adventure.json"))
var payload: Dictionary = E.decode(restore_json_integers(raw))
assert(root.get_node("SaveManager").validate_data(payload).is_empty())
var legacy: Dictionary = make_state(payload.state, false)
var current: Dictionary = make_state(payload.state, true)
var reference = world_from(legacy, false)
var candidate = world_from(current, true)
assert(E.eq(reference.ledger.physical_amounts(reference.state), candidate.ledger.physical_amounts(candidate.state)))
assert(E.eq(reference.state.ethics, candidate.state.ethics))
assert(cohort_count(candidate) <= cohort_count(reference), "Dynamic widening increased the fixture cohort count")
dispose(reference)
dispose(candidate)
if OS.get_cmdline_user_args().has("generate_only"):
print("Generated states validate and survive disk roundtrip; physical amounts and ethics match")
quit()
return
var results: Array = []
for repeat_index in repeats:
var order: Array = [false, true] if repeat_index % 2 == 0 else [true, false]
for use_cycles in order:
results.append(measure(current if use_cycles else legacy, use_cycles, repeat_index + 1))
var output = FileAccess.open("res://tests/artifacts/%s_results.json" % artifact_prefix, FileAccess.WRITE)
output.store_string(JSON.stringify({"delta_seconds": 0.2, "speed": 6, "cycles_per_run": cycles, "repeats": repeats, "profile_enabled": true, "runs": results}, " "))
output.close()
quit()