Multi-core simulation: grain movement and heat across a worker pool (t88 phase 3)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,20 +13,25 @@ function perfWrap(names, data) {
|
||||
}
|
||||
return () => { for (const name of names) window[name] = originals[name]; };
|
||||
}
|
||||
function perfSim(names, scene, w, h) {
|
||||
async function perfSim(names, scene, w, h) {
|
||||
// Five full periods warm even the 120-tick cold pass without forcing conditional calls.
|
||||
for (let k = 0; k < 600; k++) simTick();
|
||||
perfScene(scene, w, h);
|
||||
await startThreads();
|
||||
const start = perfState(), data = {}, restore = perfWrap(names, data), n = 240;
|
||||
const threadData = {}, restoreThread = perfWrap(['threadWait'], threadData);
|
||||
if (simPool) simPool.activeMax = 0;
|
||||
const t = performance.now();
|
||||
try { for (let k = 0; k < n; k++) simTick(); }
|
||||
finally { restore(); }
|
||||
finally { restore(); restoreThread(); }
|
||||
const total = (performance.now() - t) / n;
|
||||
const steps = {};
|
||||
for (const [name, d] of Object.entries(data)) steps[name] = {
|
||||
ms_per_tick: d.ms / n, ms_per_call: d.calls ? d.ms / d.calls : null, calls: d.calls
|
||||
};
|
||||
return { total_ms: total, ticks: n, start, end: perfState(), steps,
|
||||
return { total_ms: total, main_thread_ms: total, polling_ms: threadData.threadWait.ms / n,
|
||||
main_compute_ms: total - threadData.threadWait.ms / n,
|
||||
workers: simPool ? simPool.workers.length : 0, active_workers: simPool ? simPool.activeMax : 0, ticks: n, start, end: perfState(), steps,
|
||||
rest_ms: total - Object.values(data).reduce((s, d) => s + d.ms / n, 0) };
|
||||
}
|
||||
async function perfRender(lighting, overlays) {
|
||||
|
||||
+4
-1
@@ -74,6 +74,9 @@ def report(result, baseline=None):
|
||||
print(f'{name:24}' + ''.join(f'{v:12.4f}' for v in values))
|
||||
for scene, d in result['scenes'].items():
|
||||
s = d['sim']
|
||||
print(f" {scene}: wall {s['total_ms']:.3f}, main occupied {s.get('main_thread_ms',s['total_ms']):.3f}, "
|
||||
f"main compute {s.get('main_compute_ms',s['total_ms']):.3f}, polling {s.get('polling_ms',0):.3f} ms/tick; "
|
||||
f"workers {s.get('workers',0)} (active peak {s.get('active_workers',0)})")
|
||||
print(f" {scene}: awake {s['start']['awake']} -> {s['end']['awake']}, hot {s['start']['hot']} -> {s['end']['hot']} / {s['end']['chunks']}")
|
||||
print('\nReal loop: frame interval / CPU frame work / sim per frame, p50/p95/p99 ms')
|
||||
for scene, d in result['scenes'].items():
|
||||
@@ -174,7 +177,7 @@ def main():
|
||||
raise RuntimeError('Refusing a software-rendered baseline')
|
||||
result['machine']['browser_version'] = browser.version
|
||||
def setup(scene):
|
||||
return pg.evaluate('([s,w,h]) => perfScene(s,w,h)', [scene, *args.world])
|
||||
return pg.evaluate('async ([s,w,h]) => { const state=perfScene(s,w,h); await startThreads(); return state; }', [scene, *args.world])
|
||||
for scene in scenes:
|
||||
print(f'Measuring {scene}...', file=sys.stderr, flush=True)
|
||||
setup(scene)
|
||||
|
||||
Reference in New Issue
Block a user