skittles sour Posted November 2, 2021 Share Posted November 2, 2021 (edited) So if a function of a prefab post-init is declared locally like this: AddPrefabPostInit(prefab, function(inst) local function fn() end inst.fn = fn end) Would there be as many fn's saved as there are instances of the prefab, since the function is declared locally, and each new instance would see the function redeclared? How much worse would the above example be, than, say, declaring the function outside of the prefab post init: local function fn() end AddPrefabPostInit(prefab, function(inst) inst.fn = fn end) Since the common way to overwrite a function is to frame it inside another function: AddPrefabPostInit(prefab, function(inst) local old = inst.fn inst.fn = function(...) -- overwrites return old(...) end end) And usually this framing is done locally at the level of the instances, is this a major cause for the lags of mods? And would something like this be substantially better for performance, or would it just unnecessarily complicate the mod? local function overwrite(postinitfn, class, tablefn, name, func) local old local new postinitfn(class, function(self) if old == nil then old = tablefn(self)[name] -- tablefn is a function that locates the function to overwrite, like tablefn = function(inst) return inst.components.combat end, while name = "CanTarget" if old == nil then old = false end new = function(...) func(...) if type(old) == "function" then return old(...) end end end tablefn(self)[name] = new end) end) Edited November 2, 2021 by Bad Willow Link to comment https://forums.kleientertainment.com/forums/topic/135032-memory-cost-of-local-functions/ Share on other sites More sharing options...
CarlZalph Posted November 2, 2021 Share Posted November 2, 2021 38 minutes ago, Bad Willow said: So if a function of a prefab post-init is declared locally like this: AddPrefabPostInit(prefab, function(inst) local function fn() end inst.fn = fn end) Would there be as many fn's saved as there are instances of the prefab, since the function is declared locally, and each new instance would see the function redeclared? How much worse would the above example be, than, say, declaring the function outside of the prefab post init: local function fn() end AddPrefabPostInit(prefab, function(inst) inst.fn = fn end) Yes, each prefab would get its own unique function stored to it in this case. Worse is a relative term. If your code doesn't require the unique instancing of the function and it's okay for it to be shared (generic function), then it would be better in terms of memory usage to pull it out and make it the same function used for every instance like what you did with the second block. 40 minutes ago, Bad Willow said: Since the common way to overwrite a function is to frame it inside another function: AddPrefabPostInit(prefab, function(inst) local old = inst.fn inst.fn = function(...) -- overwrites return old(...) end end) And usually this framing is done locally at the level of the instances, is this a major cause for the lags of mods? You'd only experience runtime hiccups relative to memory if the computer is full and the OS starts paging it to disk. When you invoke a function in LUA it does a series of checks to try to find out what the variable means, first by local scope and cascades up scoping until it hits _G to then look for that. At each level of scope it's a hashmap lookup (as far as I recall) to see if it can't find what it is. This is why people tend to local scope some things before doing tight runloops in LUA- it speeds it up in cache. Mostly mods create performance issues due to poor handling of assets (giant atlases), an overuse of TheSim:FindEntities, very low delay timers everywhere, and mass entity creation. Function hooking is a small overhead that's unavoidable for mods to work with each other nicely. There are other methods done like a more robust event chain system, but they all have their pros and cons for each. 48 minutes ago, Bad Willow said: And would something like this be substantially better for performance, or would it just unnecessarily complicate the mod? local function overwrite(postinitfn, class, tablefn, name, func) local old local new postinitfn(class, function(self) if old == nil then old = tablefn(self)[name] -- tablefn is a function that locates the function to overwrite, like tablefn = function(inst) return inst.components.combat end, while name = "CanTarget" if old == nil then old = false end new = function(...) func(...) if type(old) == "function" then return old(...) end end end tablefn(self)[name] = new end) end) This is definitely a case of overengineering. While you can create some neat systems and get some performance out of it for your use cases, the major road blocks are going to be vastly larger in performance hits elsewhere than some additional functions residing in memory. The work required to make function hooking moot would incur costs elsewhere, as ultimately the system must emplace a priority queue for when two mods interact with the same thing. Whether it be a table that's iterated, or a series of nested function hooks down the line, the data will end up being roughly the same in the end. 1 1 1 Link to comment https://forums.kleientertainment.com/forums/topic/135032-memory-cost-of-local-functions/#findComment-1510155 Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now