From e8b02570a29d8df0094e096983e31be451b56748 Mon Sep 17 00:00:00 2001 From: veclavtalica Date: Sun, 12 Jan 2025 02:44:41 +0300 Subject: [PATCH] slot based allocator for lua, usage of lua_createtable --- apps/twnlua/bindgen.py | 16 +++++++++----- apps/twnlua/game.c | 48 +++++++++++++++++++++++++++++++++++++++++- src/twn_textures.c | 2 ++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/apps/twnlua/bindgen.py b/apps/twnlua/bindgen.py index 9bc51ae..b6c487d 100755 --- a/apps/twnlua/bindgen.py +++ b/apps/twnlua/bindgen.py @@ -8,6 +8,9 @@ with open(sys.argv[1], 'r') if sys.argv[1] != "-" else sys.stdin as f: api = json.loads(api_source) +# TODO: use lua_to--x functions for defaults, so that fewer function calls are made +# TODO: use lua_createtable for preallocation + def default(parameter): basetype = parameter["type"].rsplit(' *', 1)[0] if parameter["type"] == "float": @@ -32,7 +35,7 @@ def default(parameter): def to_table(typedesc, variable, indent = 0): - binding = ' ' * indent + "lua_newtable(L);\n" + binding = ' ' * indent + "lua_createtable(L, 0, %i);\n" % len(typedesc["fields"]) for field in typedesc["fields"]: if field["type"] == "float": binding += ' ' * indent + "lua_pushnumber(L, (double)(%s));\n" % (variable + ".%s" % field["name"]) @@ -48,7 +51,8 @@ def to_table(typedesc, variable, indent = 0): print('#include "twn_game_api.h"\n') -print('#define STB_DS_IMPLEMENTATION') # TODO: reuse implementation from the engine +# TODO: reuse implementation from the engine, this also breaks with statically compiled build +print('#define STB_DS_IMPLEMENTATION') print('#include ') print('#include ') print('#include ') @@ -88,11 +92,13 @@ for procedure, procedure_desc in api["procedures"].items(): else: raise BaseException("Unhandled parameter type '%s'" % (parameter["type"])) + # binding += " lua_pop(L, %i);\n" % (1 + len(procedure_desc["params"]) if "params" in procedure_desc else 0) + if "return" in procedure_desc: if procedure_desc["return"] == "bool": - binding += " lua_pushboolean(L, (int)%s(%s));\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"])) + binding += " lua_pushboolean(L, (int)(%s(%s)));\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"])) elif procedure_desc["return"] == "float": - binding += " lua_pushnumber(L, (double)%s(%s));\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"])) + binding += " lua_pushnumber(L, (double)(%s(%s)));\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"])) elif procedure_desc["return"] == "char *": binding += " lua_pushstring(L, %s(%s));\n" % (procedure, ", ".join(param["name"] for param in procedure_desc["params"])) elif type(procedure_desc["return"]) is dict or procedure_desc["return"] in api["types"]: @@ -159,7 +165,7 @@ loader = "void bindgen_load_%s(lua_State *L) {\n" % api["name"] modules = set(api["procedures"][procedure]["module"] for procedure in api["procedures"]) for module in modules: loader += " bindgen_init();\n" - loader += " lua_newtable(L);\n" + loader += " lua_createtable(L, 0, %i);\n" % len(api["procedures"]) for procedure, procedure_desc in api["procedures"].items(): if procedure_desc["module"] == module: loader += " lua_pushcfunction(L, binding_%s);\n" % procedure diff --git a/apps/twnlua/game.c b/apps/twnlua/game.c index 8ce97c2..4428024 100644 --- a/apps/twnlua/game.c +++ b/apps/twnlua/game.c @@ -43,6 +43,50 @@ static int physfs_loader(lua_State *L) { } +/* WARN! experimental and will probably be removed */ +/* it was an attempt to ease memory usage problems posed by using lua */ +/* it saved ~100MiB, but it still hogs ~500MiB for no reason on my PC */ +static void *custom_alloc(void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + + /* small allocations are placed in slots, as there's a big chance they will not need to be resized */ + static char slots[1024][64]; + static int16_t free_slots[1024] = { [0] = -1 }; + static size_t free_slot_count = 1024; + + if (free_slots[0] == -1) + for (int i = 0; i < 1024; i++) + free_slots[i] = (int16_t)i; + + if (nsize == 0) { + if (ptr && (char *)ptr >= &slots[0][0] && (char *)ptr <= &slots[1024-1][64-1]) + free_slots[free_slot_count++] = (int16_t)(((uintptr_t)ptr - (uintptr_t)slots) / 64); + else + SDL_free(ptr); + return NULL; + } else { + if (!ptr && nsize <= 64 && free_slot_count > 0) { + /* use a slot */ + return slots[free_slots[--free_slot_count]]; + } + + if ((char *)ptr >= &slots[0][0] && (char *)ptr <= &slots[1024-1][64-1]) { + /* still fits */ + if (nsize <= 64) + return ptr; + + /* move from slot to dynamic memory */ + void *mem = SDL_malloc(nsize); + SDL_memcpy(mem, ptr, osize); + free_slots[free_slot_count++] = (int16_t)(((uintptr_t)ptr - (uintptr_t)slots) / 64); + return mem; + } + + return SDL_realloc(ptr, nsize); + } +} + + void game_tick(void) { if (ctx.initialization_needed) { if (!ctx.udata) @@ -57,6 +101,8 @@ void game_tick(void) { } state->L = luaL_newstate(); + lua_setallocf(state->L, custom_alloc, NULL); + /* fakey version of luaL_openlibs() that excludes file i/o and os stuff */ { static const luaL_Reg loaded_libs[] = { @@ -79,7 +125,7 @@ void game_tick(void) { /* package.searchers = { physfs_loader } */ lua_getglobal(state->L, "package"); - lua_newtable(state->L); + lua_createtable(state->L, 0, 1); lua_setfield(state->L, -2, "searchers"); lua_getfield(state->L, -1, "searchers"); diff --git a/src/twn_textures.c b/src/twn_textures.c index c672717..c64527a 100644 --- a/src/twn_textures.c +++ b/src/twn_textures.c @@ -439,6 +439,8 @@ TextureKey textures_get_key(TextureCache *cache, const char *path) { } } + /* TODO: this will be bad when dynamic strings are involved */ + /* to mitigate that we could free ptr_to_texture each frame */ /* try loading */ last_texture = textures_load(cache, path); hmput(ptr_to_texture, path, last_texture);