OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / autoloads / sim_stats.gd

41 lines · gd ref:
class_name SimStats extends RefCounted
## SIMULATION COST counters (hyper-games #114 §7: the bot / creature benchmark) — STATIC,
## not an autoload, because creatures and bot brains are compiled by `--script` gates
## BEFORE autoloads exist, where a bare `PerfMetrics` identifier is a compile error
## (gate_creature_target / gate_bot_object broke on exactly that; #113 §6 is the same
## trap with Keymap). PerfMetrics exposes these over /global/perf.
##
## Per KEY ("creature.crawler", "bot.nav", ...): the ticks, the CPU microseconds inside
## them and the ground/nav QUERIES they made. Accumulated, never sampled; two
## get_ticks_usec per tick is the whole overhead.

static var _sim: Dictionary = {}          # key -> PackedInt64Array [calls, usec, queries]
static var _t0_ms: int = 0


static func add(key: String, usec: int, queries: int = 0) -> void:
	var a: PackedInt64Array = _sim.get(key, PackedInt64Array([0, 0, 0]))
	a[0] += 1
	a[1] += usec
	a[2] += queries
	_sim[key] = a


static func reset() -> void:
	_sim.clear()
	_t0_ms = Time.get_ticks_msec()


## Per key: totals since reset(), and the rates a benchmark compares — us_per_call,
## ms_per_s (CPU per wall second; 100 ms/s is 10 % of a core), queries_per_s.
static func snapshot() -> Dictionary:
	var window_s := maxf(float(Time.get_ticks_msec() - _t0_ms) / 1000.0, 0.001)
	var out: Dictionary = {"window_s": window_s}
	for k: String in _sim:
		var a: PackedInt64Array = _sim[k]
		out[k] = {"calls": a[0], "usec": a[1], "queries": a[2],
			"us_per_call": float(a[1]) / maxf(float(a[0]), 1.0),
			"ms_per_s": float(a[1]) / 1000.0 / window_s,
			"queries_per_s": float(a[2]) / window_s}
	return out