c4e7302567
- Introduced `civilization_benchmark.gd` and `legacy_quantity_math.gd` for benchmarking and legacy quantity calculations. - Created `test_dynamic_math.gd`, `test_frame_evolution.gd`, and `test_sparse_batches.gd` to validate mathematical operations and frame evolution logic. - Implemented `frame_budget.gd` to manage cooperative work on the main thread, ensuring no partially calculated state is published. - Added UID files for all new scripts to maintain unique identifiers.
75 lines
3.7 KiB
GDScript
75 lines
3.7 KiB
GDScript
extends SceneTree
|
|
const Fixture = preload("res://tests/fixtures/civilization_benchmark.gd")
|
|
|
|
func _initialize(): call_deferred("run")
|
|
|
|
func run():
|
|
var ui: bool = "ui" in OS.get_cmdline_user_args()
|
|
var scenarios: Array = ["mixed", "large", "fragmented"]
|
|
var frames: int = 120
|
|
var step_delta: float = 1.0 / 60.0
|
|
for argument in OS.get_cmdline_user_args():
|
|
if argument.begins_with("scenario="): scenarios = [argument.trim_prefix("scenario=")]
|
|
if argument.begins_with("delta="): step_delta = float(argument.trim_prefix("delta="))
|
|
if argument.begins_with("frames="): frames = maxi(2, int(argument.trim_prefix("frames=")))
|
|
Engine.max_fps = 60
|
|
if ui: DisplayServer.window_set_size(Vector2i(540, 960))
|
|
for scenario in scenarios:
|
|
var scene
|
|
var stage
|
|
var world
|
|
if ui:
|
|
scene = load("res://world/world.tscn").instantiate()
|
|
stage = scene.get_node("Stage")
|
|
stage.owniverse.free()
|
|
stage.set_script(load("res://tests/fixtures/benchmark_ui_stage.gd"))
|
|
root.add_child(scene)
|
|
await process_frame
|
|
await process_frame
|
|
world = stage.owniverse
|
|
else:
|
|
world = load("res://world/owniverse/owniverse.gd").new()
|
|
world.catalog.load_definitions(root.get_node("Global").OwniverseEntities)
|
|
Fixture.seed(world, root.get_node("Global"), scenario == "fragmented", scenario == "large", scenario == "stable")
|
|
world.profile_enabled = "profile" in OS.get_cmdline_user_args()
|
|
var samples: Array = []
|
|
if ui:
|
|
stage.stage_page_scroller.scroll_horizontal = 4 * stage.PAGE_WIDTH
|
|
for item in stage.owniverse_items.values(): item.visible = true
|
|
for page in stage.item_pages: page.visible = true
|
|
stage._set_item_description(stage.owniverse_items["C2.0"])
|
|
stage._refresh_universe_ui()
|
|
for warmup in 10: await process_frame
|
|
stage.measuring = true
|
|
for frame in frames:
|
|
await process_frame
|
|
if (frame + 1) % 10 == 0:
|
|
print("%s: measured %d UI frames" % [scenario, frame + 1])
|
|
stage.measuring = false
|
|
samples = stage.process_samples
|
|
report(scenario + " UI frame", stage.frame_samples)
|
|
else:
|
|
for frame in frames:
|
|
var started: int = Time.get_ticks_usec()
|
|
world.evolute(step_delta)
|
|
samples.append((Time.get_ticks_usec() - started) / 1000.0)
|
|
report(scenario + (" UI handler" if ui else " CPU"), samples)
|
|
if ui:
|
|
print("Completed simulation transactions: ", world.frame_commits, "; published year: ", world.state.time.year, "; requested year: ", world.frame_clock.get("year", 0))
|
|
print("Statistics ", world.state.civilization_stats)
|
|
if world.profile_enabled: print("Profile microseconds/calls: ", world.profile)
|
|
for argument in OS.get_cmdline_user_args():
|
|
if argument.begins_with("snapshot="):
|
|
var file = FileAccess.open(argument.trim_prefix("snapshot=") + "-" + scenario + ".json", FileAccess.WRITE)
|
|
file.store_string(JSON.stringify(world.E.encode(world.state)))
|
|
for entity in world.catalog.entities.values(): entity.free()
|
|
world.free()
|
|
if ui: scene.free()
|
|
quit()
|
|
|
|
func report(label: String, samples: Array):
|
|
var total: float = 0.0
|
|
for sample in samples: total += sample
|
|
samples.sort()
|
|
print("%s: mean %.2f ms, p95 %.2f ms, max %.2f ms, %.1f per second" % [label, total / samples.size(), samples[ceili(samples.size() * 0.95) - 1], samples.back(), samples.size() * 1000 / total])
|