Run Lua GC in parallel with the rest of the frame
Closes #9043 (closed).
LuaManager::update() ran a fixed lua_gc(LUA_GCSTEP, 100) at its start. GC now runs on the Lua worker thread :
- GC step is split out of
update()intoLuaManager::gcStep() MWLua::Workerhas a newgc()andfinishGc()pair of methods.gc()starts a loop of small steps (10 units perlua_gccall) on the worker thread; the loop stops atfinishGc()or when a full collection cycle completes. No behaviour change if there's no Lua thread- collection starts in
engine.cppjust afterfinishUpdate()and stops it at the top of the next frame's synchronized update; collection overlaps the frame tail, the framerate-limiter sleep and the next frame's input and sound updates.finishGc()waits only for the step in flight
gc steps per frame = 0 still disables collection entirely; docs updated.
I ran a sweep to check if the arbitrary "10 loops" value changed anything if increased/decreased, but it appears bounded by the collector's atomic phase rather than by the step size.
With a fresh save in Balmora, 1080p on an laptop with i5-8365U and Intel UHD 620 (Mesa), A = master and B = this change :
Synthetic pressure (global script allocating 1500 tables + unique strings per frame):
| metric | A | B |
|---|---|---|
| Lua update p99 | 7.68 ms | 6.11 ms |
| frame p95 | 10.4 ms | 9.7 ms |
| frame p99 | 11.5 ms | 11.0 ms |
Real mods from #9043 (closed) (MercyCAO, AnimatedLanterns, SneakIsGoodNow, DynamicCamera, ReAnimation, LuaPhysics):
| metric | A | B |
|---|---|---|
| Lua update p99 | 9.64 ms | 3.44 ms |
| average fps | 101.0 | 105.4 |
| frame p99 | 14.6 ms | 14.3 ms |
Testing done :
-
The A/B/A/B benches, on Linux w/ KWin Wayland.
-
Repeated save loads, menu idle and clean shutdowns on both binaries across runs; no issues seen.
-
Wandering around a bit, loading new cells, talking to NPCs, etc.
-
Checked runtime logs for new errors, nothing to report.
-
I have read the CONTRIBUTING guidelines
-
My code runs locally
-
My code passes CI on my fork
Open point: if the background loop cannot complete cycles under extreme allocation rates, I assume LuaJIT will force collection during script allocations. I didnt implement a fallback (like forcing steps when no cycle completes for N frames) because I couldn't repro that case; happy to add it here if you'd prefer.