From 6ef71ebcbd38253c906ef22929bc76a9d19919b2 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 1 Oct 2026 13:01:48 -0500 Subject: [PATCH] reduce the interrupt check rate This PR lowers the rate at which the Lua VM checks to see if it's been asked to die (using the`kill-lua` command) from once every 256 to once every 16384 instructions. Empirical testing indicates that rate still results in the interrupt flag being checked at least once every 10 milliseconds or so, which should be more than fit for purpose. The instrumentation used to gather the testing data is left in place; at the new lowered interrupt frequency, the cost of gathering it is negligible. --- docs/dev/Lua API.rst | 4 ++++ library/LuaTools.cpp | 29 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index ccc3c25e7d..29010b8147 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -681,6 +681,10 @@ Miscellaneous both from the curry call and the closure call itself. I.e., ``curry(func,a,b)(c,d)`` equals ``func(a,b,c,d)``. +* ``dfhack.dump_interrupt_timing_data()`` + + Dumps the internal log of times between interrupt callbacks, as a table of integers. + Each entry is the difference between two consecutive interrupts, in microseconds. Locking and finalization ------------------------ diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index 56c5079838..06051383f0 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -505,11 +505,19 @@ volatile std::sig_atomic_t lstop = 0; static void interrupt_hook (lua_State *L, lua_Debug *ar); static void interrupt_init (lua_State *L) { - lua_sethook(L, interrupt_hook, LUA_MASKCOUNT, 256); + lua_sethook(L, interrupt_hook, LUA_MASKCOUNT, 16384); } +constexpr auto interrupt_log_buffer_size = 64; +using timer = std::chrono::high_resolution_clock; +static std::array interrupt_log_buffer; +static size_t interrupt_log_buffer_index = 0; + static void interrupt_hook (lua_State *L, lua_Debug *ar) { + interrupt_log_buffer[interrupt_log_buffer_index] = timer::now(); + interrupt_log_buffer_index = (interrupt_log_buffer_index + 1) % interrupt_log_buffer_size; + if (lstop) { lstop = 0; @@ -518,6 +526,24 @@ static void interrupt_hook (lua_State *L, lua_Debug *ar) } } +static int dfhack_dump_interrupt_timing_data(lua_State* L) +{ + int base = lua_gettop(L); + lua_createtable(L, interrupt_log_buffer_size-1, 0); + auto last = timer::now(); + for (auto idx = 0; idx < interrupt_log_buffer_size; idx++) + { + auto i = (idx + interrupt_log_buffer_index) % interrupt_log_buffer_size; + auto dur = interrupt_log_buffer[i] - last; + last = interrupt_log_buffer[i]; + if (idx>0) { + lua_pushinteger(L, std::chrono::duration_cast(dur).count()); + lua_rawseti(L, base + 1, idx); + } + } + return 1; +} + bool DFHack::Lua::Interrupt (bool force) { lua_State *L = DFHack::Core::getInstance().getLuaState(true); @@ -1498,6 +1524,7 @@ static const luaL_Reg dfhack_funcs[] = { { "with_suspend", lua_dfhack_with_suspend }, { "open_plugin", dfhack_open_plugin }, { "curry", dfhack_curry }, + { "dump_interrupt_timing_data", dfhack_dump_interrupt_timing_data }, { NULL, NULL } };