menu interactive, refactor, perf tests, charge bar, debug menu stuff
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
extends SceneTree
|
||||
## Performance regression test — loads the full scene under a heavy matador load,
|
||||
## samples per-frame times during normal play and during a mass-ragdoll stress
|
||||
## spike, and asserts the frame budget holds.
|
||||
##
|
||||
## Run (headless):
|
||||
## godot --headless --script tests/performance_test.gd
|
||||
##
|
||||
## Exit code 0 = within budget, 1 = a budget was exceeded (or a frame was non-finite).
|
||||
##
|
||||
## Budgets are deliberately generous regression guards, not a target frame rate:
|
||||
## they only trip on a pathological slowdown, so the test stays stable across the
|
||||
## range of machines it runs on. Every run also prints the measured numbers so a
|
||||
## gradual creep is visible even when it doesn't fail.
|
||||
|
||||
const STRESS_MATADORS := 20
|
||||
const WARMUP_SEC := 1.0
|
||||
const SAMPLE_FRAMES := 120
|
||||
|
||||
# Generous ceilings — a healthy build sits far below these.
|
||||
const AVG_BUDGET_MS := 16.0 # sustained cost must leave headroom for 60 fps
|
||||
const MAX_BUDGET_MS := 100.0 # a single hitch this large is a real regression
|
||||
|
||||
var _passed: int = 0
|
||||
var _failed: int = 0
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
print("=".repeat(60))
|
||||
print("PERFORMANCE TEST")
|
||||
print("=".repeat(60))
|
||||
|
||||
var dp: Node = root.get_node_or_null("/root/DP")
|
||||
if dp:
|
||||
dp.set_value("mat_spawn_count", STRESS_MATADORS)
|
||||
|
||||
var scene_res := load("res://scene.tscn")
|
||||
if not scene_res:
|
||||
push_error("performance_test: failed to load scene.tscn")
|
||||
quit(1)
|
||||
return
|
||||
root.add_child(scene_res.instantiate())
|
||||
|
||||
await create_timer(WARMUP_SEC).timeout
|
||||
|
||||
var matadors := get_nodes_in_group(&"matador")
|
||||
print(" matadors alive: %d" % matadors.size())
|
||||
|
||||
var normal := await _sample_frames(SAMPLE_FRAMES)
|
||||
_report_phase("normal play", normal)
|
||||
|
||||
# Stress spike: ragdoll every matador on the same frame.
|
||||
for mat: Node in get_nodes_in_group(&"matador"):
|
||||
if mat.has_method("_enter_ragdoll"):
|
||||
mat._enter_ragdoll(Vector3(randf() - 0.5, 0.0, randf() - 0.5).normalized(), 12.0)
|
||||
|
||||
var stress := await _sample_frames(SAMPLE_FRAMES)
|
||||
_report_phase("mass ragdoll", stress)
|
||||
|
||||
_finish()
|
||||
|
||||
|
||||
# Awaits SAMPLE_FRAMES idle frames, returning [avg_ms, max_ms, all_finite].
|
||||
func _sample_frames(count: int) -> Array:
|
||||
var total_us := 0
|
||||
var max_us := 0
|
||||
var all_finite := true
|
||||
var last := Time.get_ticks_usec()
|
||||
for _i in count:
|
||||
await process_frame
|
||||
var now := Time.get_ticks_usec()
|
||||
var frame_us := now - last
|
||||
last = now
|
||||
total_us += frame_us
|
||||
max_us = maxi(max_us, frame_us)
|
||||
if not is_finite(float(frame_us)):
|
||||
all_finite = false
|
||||
var avg_ms := (total_us / float(count)) / 1000.0
|
||||
return [avg_ms, max_us / 1000.0, all_finite]
|
||||
|
||||
|
||||
func _report_phase(label: String, sample: Array) -> void:
|
||||
var avg_ms: float = sample[0]
|
||||
var max_ms: float = sample[1]
|
||||
var all_finite: bool = sample[2]
|
||||
print("\n-- %s --" % label)
|
||||
print(" avg %.2f ms/frame (~%.0f fps) peak %.2f ms" % [
|
||||
avg_ms, 1000.0 / maxf(avg_ms, 0.001), max_ms])
|
||||
_assert_true(all_finite, "%s: all frame times finite" % label)
|
||||
_assert_true(avg_ms < AVG_BUDGET_MS,
|
||||
"%s: avg %.2f ms under %.0f ms budget" % [label, avg_ms, AVG_BUDGET_MS])
|
||||
_assert_true(max_ms < MAX_BUDGET_MS,
|
||||
"%s: peak %.2f ms under %.0f ms budget" % [label, max_ms, MAX_BUDGET_MS])
|
||||
|
||||
|
||||
func _assert_true(condition: bool, desc: String) -> void:
|
||||
if condition:
|
||||
_passed += 1
|
||||
print(" PASS: %s" % desc)
|
||||
else:
|
||||
_failed += 1
|
||||
print(" FAIL: %s" % desc)
|
||||
|
||||
|
||||
func _finish() -> void:
|
||||
print("")
|
||||
print("=".repeat(60))
|
||||
print("PERFORMANCE TEST: %d passed, %d failed" % [_passed, _failed])
|
||||
print("=".repeat(60))
|
||||
quit(1 if _failed > 0 else 0)
|
||||
Reference in New Issue
Block a user