mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2025-03-11 06:07:44 +01:00
add jit parameter tuning and get_node_raw access
This commit is contained in:
parent
36f5abc4df
commit
9aa35154d2
8 changed files with 184 additions and 1 deletions
mods/CORE
33
mods/CORE/mcl_init/API.md
Normal file
33
mods/CORE/mcl_init/API.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# mcl_init
|
||||
|
||||
Initialization of VoxeLibre, in particular some shared variables exposed via `mcl_vars`.
|
||||
|
||||
|
||||
## Optimized LuaJIT parameters
|
||||
|
||||
As of 2024, the default LuaJIT parameters are not well tuned, *depending on the version you use*.
|
||||
|
||||
According to <https://luajit.org/running.html>, standard LuaJIT uses:
|
||||
|
||||
| maxtrace | 1000 | Max. number of traces in the cache |
|
||||
| maxrecord | 4000 | Max. number of recorded IR instructions |
|
||||
| maxirconst | 500 | Max. number of IR constants of a trace |
|
||||
| minstitch | 0 | Min. # of IR ins for a stitched trace. |
|
||||
| maxmcode | 512 | Max. total size of all machine code areas in KBytes |
|
||||
|
||||
However, the openresty branch uses more sane defaults for a long time <https://github.com/openresty/luajit2/blob/v2.1-agentzh/src/lj_jit.h#L117>:
|
||||
|
||||
| maxtrace | 8000 | Max. number of traces in the cache |
|
||||
| maxrecord | 16000 | Max. number of recorded IR instructions |
|
||||
| maxirconst | 500 | Max. number of IR constants of a trace |
|
||||
| minstitch | 3 | Min. # of IR ins for a stitched trace. |
|
||||
| maxmcode | 40960 | Max. total size of all machine code areas in KBytes |
|
||||
|
||||
Mineclonia contributor "halon" investigated this, and
|
||||
increasing these values appears to be beneficial for improving the performance of Luanti,
|
||||
although users of openresty (e.g., on Debian GNU/Linux) may not notice a difference.
|
||||
|
||||
TODO: every few years, the situation should be re-assessed. For example, Luanti upstream might set improved values.
|
||||
Unfortunately, it does not appear that we can query the values, only set them.
|
||||
|
||||
|
66
mods/CORE/mcl_init/get_node_name.lua
Normal file
66
mods/CORE/mcl_init/get_node_name.lua
Normal file
|
@ -0,0 +1,66 @@
|
|||
-- NOTE: As of Luanti 5.9 and 5.10, the function `core.get_node_raw` is NOT exposed.
|
||||
-- However, via `secure.trusted_mods=vl_trusted` it is possible to expose and use it.
|
||||
-- If <https://github.com/minetest/minetest/issues/15317> is merged, it may become public API.
|
||||
-- For more details, see the vl_trusted module.
|
||||
-- We do not call into vl_trusted directly, but it set `core.get_node_raw` if loaded first.
|
||||
-- Load order hence is important, and this mod should depend on vl_trusted.
|
||||
|
||||
local core_get_node = core.get_node
|
||||
local core_get_node_raw = core.get_node_raw
|
||||
local core_get_name_from_content_id = core.get_name_from_content_id
|
||||
local core_get_content_id = core.get_content_id
|
||||
|
||||
--- Get the node name, param and param2 using `core.get_node_raw` if available, fall back to regular get_node otherwise.
|
||||
---
|
||||
--- @param pos vector: position
|
||||
--- @return (string, number, number): node name, param1 and param2
|
||||
function mcl_vars.get_node_name(pos) -- Fallback version
|
||||
local node = core_get_node(pos)
|
||||
return node.name, node.param1, node.param2
|
||||
end
|
||||
-- optimized version
|
||||
if core_get_node_raw then
|
||||
mcl_vars.get_node_name = function(pos)
|
||||
local content, param1, param2, pos_ok = core_get_node_raw(pos.x, pos.y, pos.z)
|
||||
if not pos_ok then return "ignore", 0, 0 end
|
||||
return core_get_name_from_content_id(content), param1, param2
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the node name, param and param2 using `core.get_node_raw` if available fall back to regular get_node otherwise.
|
||||
--- Note: up to Luanti 5.10 at least, this will create a new vector. If you already have a vector, prefer `get_node_name`.
|
||||
---
|
||||
--- @param x number: coordinate
|
||||
--- @param y number: coordinate
|
||||
--- @param z number: coordinate
|
||||
--- @return (string, number, number): node name, param1, param2
|
||||
function mcl_vars.get_node_name_raw(x, y, z) -- Fallback version
|
||||
local node = core_get_node({x=x,y=y,z=z}) -- raw table, not need for vector
|
||||
return node.name, node.param1, node.param2
|
||||
end
|
||||
-- optimized version
|
||||
if core_get_node_raw then
|
||||
mcl_vars.get_node_name_raw = function(x, y, z)
|
||||
local content, param1, param2, pos_ok = core_get_node_raw(x, y, z)
|
||||
if not pos_ok then return "ignore", 0, 0 end
|
||||
return core_get_name_from_content_id(content), param1, param2
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the node name, param and param2 using `core.get_node_raw` if available, fall back to regular get_node otherwise.
|
||||
--- Note: up to Luanti 5.10 at least, this involves an unnecessary roundtrip via the node name.
|
||||
--- If you use the node name anyway, prefer `get_node_name_raw` or `get_node_name`.
|
||||
---
|
||||
--- @param x number: coordinate
|
||||
--- @param y number: coordinate
|
||||
--- @param z number: coordinate
|
||||
--- @return (number, number, number, boolean): node content id, param1, param2, pos_ok
|
||||
function mcl_vars.get_node_raw(x, y, z) -- Fallback
|
||||
local node = core_get_node({x=x,y=y,z=z}) -- raw table, not need for vector
|
||||
return core_get_content_id(node.name), node.param1, node.param2, node.name ~= "ignore"
|
||||
end
|
||||
-- optimized version
|
||||
if core_get_node_raw then
|
||||
mcl_vars.get_node_raw = core_get_node_raw
|
||||
end
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
-- Some global variables (don't overwrite them!)
|
||||
mcl_vars = {}
|
||||
local modpath = core.get_modpath(core.get_current_modname())
|
||||
|
||||
minetest.log("action", "World seed = " .. minetest.get_mapgen_setting("seed"))
|
||||
|
||||
|
@ -22,7 +23,7 @@ if not map_version then
|
|||
core.set_mapgen_setting("vl_world_version", map_version, true)
|
||||
end
|
||||
mcl_vars.map_version = map_version -- make available
|
||||
core.log("action", "Voxelibre mapgen version = "..map_version)
|
||||
core.log("action", "VoxeLibre mapgen version = "..map_version)
|
||||
|
||||
mcl_vars.redstone_tick = 0.1
|
||||
|
||||
|
@ -216,6 +217,7 @@ minetest.craftitemdef_default.stack_max = 64
|
|||
-- Set random seed for all other mods (Remember to make sure no other mod calls this function)
|
||||
math.randomseed(os.time())
|
||||
|
||||
---DEPRECATED. If you need to ensure the area is emerged, use LVM.
|
||||
---"Trivial" (actually NOT) function to just read the node and some stuff to not just return "ignore", like mt 5.4 does.
|
||||
---@param pos Vector Position, if it's wrong, `{name="error"}` node will return.
|
||||
---@param force? boolean Optional (default: `false`), Do the maximum to still read the node within us_timeout.
|
||||
|
@ -252,3 +254,6 @@ function mcl_vars.get_node(pos, force, us_timeout)
|
|||
-- it still can return "ignore", LOL, even if force = true, but only after time out
|
||||
end
|
||||
|
||||
dofile(modpath.."/tune_jit.lua")
|
||||
dofile(modpath.."/get_node_name.lua")
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
name = mcl_init
|
||||
author = Wuzzy
|
||||
description = Initialization mod of VoxeLibre. Defines some common shared variables and sets up initial default settings which have to be set at the beginning.
|
||||
optional_depends = vl_trusted
|
||||
|
|
23
mods/CORE/mcl_init/tune_jit.lua
Normal file
23
mods/CORE/mcl_init/tune_jit.lua
Normal file
|
@ -0,0 +1,23 @@
|
|||
--- This code is largely based on the work by halon for mineclonia, but encapsulated differently
|
||||
local luajit_present = core.global_exists("jit")
|
||||
|
||||
-- Increased limits for the JIT, as of 2024
|
||||
-- TODO: re-assess this every year or so, as either upstream Luanti may
|
||||
-- eventually increase these limits itself, or the luajit libraries increase
|
||||
-- their parameters - e.g., the openresty version already has increase limits
|
||||
-- because apparently we can not query the JIT parameters
|
||||
if luajit_present then
|
||||
local status, opt = jit.status()
|
||||
if not status then
|
||||
core.log("warning", "[mcl_init] LuaJIT appears to be available, but turned off. This will result in degraded performance.")
|
||||
end
|
||||
jit.opt.start(
|
||||
"maxtrace=24000",
|
||||
"maxrecord=32000",
|
||||
"minstitch=3",
|
||||
"maxmcode=163840"
|
||||
)
|
||||
core.log("action", "[mcl_init] increased LuaJIT parameters. LuaJIT version: "..jit.version.." with flags "..tostring(opt))
|
||||
else
|
||||
core.log("warning", "[mcl_init] LuaJIT not detected - it is strongly recommended to build luanti with LuaJIT for performance reasons!")
|
||||
end
|
22
mods/CORE/vl_trusted/API.md
Normal file
22
mods/CORE/vl_trusted/API.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
# vl_trusted
|
||||
|
||||
This module does not provide a public API.
|
||||
|
||||
The optimized function calls are only available via existing APIs.
|
||||
|
||||
We currently implement one feature that require trusted access:
|
||||
|
||||
## Access to `core.get_node_raw`
|
||||
|
||||
The `core.get_node_raw` function has been added to Luanti in version 5.9.0, but as of 5.10 is not a public API,
|
||||
although we have asked for this to be made public: <https://github.com/minetest/minetest/issues/15317>
|
||||
|
||||
This function is beneficial as it does not create a table for the return, which reduces the amount of garbage collection necessary,
|
||||
in particular as LuaJIT's allocation sinking does not appear to eliminate these, unfortunately.
|
||||
|
||||
For compatibility, we expose this with slightly different semantics, which are a tradeoff between using the new API when available
|
||||
(or exposed via this trusted module), and having to be able to fall back to the regular `core.get_node` call.
|
||||
|
||||
TODO: when the minimum version of Luanti has a public version of the API, these wrappers should likely be removed and the unmodified
|
||||
`core.get_node_raw` should be used where possible.
|
||||
|
30
mods/CORE/vl_trusted/init.lua
Normal file
30
mods/CORE/vl_trusted/init.lua
Normal file
|
@ -0,0 +1,30 @@
|
|||
--- Make `core.get_node_raw` public. It's safe to use and stable.
|
||||
--
|
||||
-- This code is based on the work by halon for mineclonia, but encapsulated differently
|
||||
-- Check if `core.get_node_raw` is public by now.
|
||||
if not core.get_node_raw then
|
||||
-- try to un-hide the function
|
||||
local ie = core.request_insecure_environment()
|
||||
if not ie then
|
||||
core.log("action", "[vl_trusted] cannot unhide get_node_raw, please add vl_trusted to secure.trusted_mods to improve performance (optional).")
|
||||
elseif not ie.debug or not ie.debug.getupvalue then
|
||||
core.log("warning", "[vl_trusted] debug.getupvalue is not available, unhiding does not work. Version: "..dump(core.get_version(),""))
|
||||
else
|
||||
for i=1,5 do -- will not be five levels deep
|
||||
local name, upvalue = ie.debug.getupvalue(core.get_node, i)
|
||||
if not name then break end
|
||||
if name == "get_node_raw" then
|
||||
core.get_node_raw = upvalue
|
||||
break
|
||||
end
|
||||
end
|
||||
if core.get_node_raw then
|
||||
core.log("action", "[vl_trusted] get_node_raw unhiding successful.")
|
||||
else
|
||||
core.log("warning", "[vl_trusted] get_node_raw unhiding NOT successful. Version: "..dump(core.get_version(),""))
|
||||
end
|
||||
end
|
||||
else
|
||||
core.log("verbose", "[vl_trusted] get_node_raw available without workaround.")
|
||||
end
|
||||
|
3
mods/CORE/vl_trusted/mod.conf
Normal file
3
mods/CORE/vl_trusted/mod.conf
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = vl_trusted
|
||||
author = kno10
|
||||
description = Optional - access to some protected Luanti functionality for increased performance
|
Loading…
Reference in a new issue