Merge remote-tracking branch 'origin/master' into feature/vec2-friendly-api

This commit is contained in:
Max Cahill 2021-07-23 11:04:23 +10:00
commit 635bf506dc
2 changed files with 46 additions and 29 deletions

View File

@ -4,28 +4,43 @@
specify a time budget and a memory ceiling per call.
called once per frame, this will spread any big collections
over a couple of frames, and "catch up" when there is. This
keeps GC burden much more predictable.
over several frames, and "catch up" when there is too much
work to do.
The memory ceiling provides some level of "relief valve" - if
exceeded it will trigger a "full" collection, but this is
likely to hurt performance. If you hit the ceiling, it
indicates you likely need to either generate less garbage
or spent more time each frame collecting.
This keeps GC time burden much more predictable.
1ms (1e-3) is a good place to start for the budget, adjust
down or up as needed. games that generate more garbage will
need to spend longer on gc each frame.
The memory ceiling provides a safety backstop.
if exceeded it will trigger a "full" collection, and this will
hurt performance - you'll notice the hitch. If you hit your ceiling,
it indicates you likely need to either find a way to generate less
garbage, or spend more time each frame collecting.
64mb is a good place to start for the memory ceiling, though
some games will need much more.
the function instructs the garbage collector only as small a step
as possible each iteration. this prevents the "spiky" collection
patterns, though with particularly large sets of tiny objects,
the start of a collection can still take longer than you might like.
the function steps the garbage collector only do a small step
each time. this prevents the start of collection from "spiking",
though it still causes some with particularly large sets
default values:
time_budget - 1ms (1e-3)
adjust down or up as needed. games that generate more garbage
will need to spend longer on gc each frame.
memory_ceiling - 64mb
a good place to start, though some games will need much more.
remember, this is lua memory, not the total memory consumption
of your game.
disable_otherwise - false
disabling the gc completely is dangerous - any big allocation
event (eg - level gen) could push you to an out of memory
situation and crash your game. test extensively before you
ship a game with this set true.
]]
return function(time_budget, safetynet_megabytes, disable_otherwise)
return function(time_budget, memory_ceiling, disable_otherwise)
time_budget = time_budget or 1e-3
memory_ceiling = memory_ceiling or 64
local max_steps = 1000
local steps = 0
local start_time = love.timer.getTime()
@ -37,7 +52,7 @@ return function(time_budget, safetynet_megabytes, disable_otherwise)
steps = steps + 1
end
--safety net
if collectgarbage("count") / 1024 > safetynet_megabytes then
if collectgarbage("count") / 1024 > memory_ceiling then
collectgarbage("collect")
end
--don't collect gc outside this margin

View File

@ -123,15 +123,17 @@ Endless, of course :)
## Export Globals
You are strongly encouraged to use the library in a "fire and forget" manner through `require("batteries"):export()` (or whatever appropriate module path), which will modify builtin lua modules (such as `table` and `math`) and expose all the other modules directly as globals for convenience.
You are strongly encouraged to use the library in a "fire and forget" manner through `require("batteries"):export()` (or whatever appropriate module path), which will modify builtin lua modules (such as `table` and `math`), and expose all the other modules directly as globals for your convenience.
This eases consumption later on - you don't have to remember if say, `table.remove_value` is built in to lua or not, or get used to accessing the builtin table functions through `batteries.table` or `tablex`.
This eases consumption across your project - you don't have to require modules everywhere, or remember if say, `table.remove_value` is built in to lua or not, or get used to accessing the builtin table functions through `batteries.table` or `tablex`.
While this will likely sit badly with anyone who's had "no globals!" hammered into them, I believe for `batteries` (and many foundational libraries) it makes sense to just import once at boot. You're going to be pulling it in almost everywhere anyway; why bother making yourself jump through more hoops?
While this will likely sit badly with anyone who's had "no globals! ever!" hammered into them, I believe that for `batteries` (and many foundational libraries) it makes sense to just import once at boot. You're going to be pulling it in almost everywhere anyway; why bother making yourself jump through more hoops?
You can of course use the separate modules on their own, either with a single require for all of `batteries`, with use through something like `batteries.functional.map`; or requiring individual modules explicitly. This more careful approach _will_ let you be more clear about your dependencies, at the cost of more setup work needing to re-require batteries everywhere, or expose it as a global in the first place.
You can, of course, use the separate modules on their own, either requiring individual modules explicitly, or a single require for all of `batteries` and use through something like `batteries.functional.map`. This more involved approach _will_ let you be more clear about your dependencies, if you care deeply about that - at the cost of more setup work needing to re-require batteries everywhere you use it, or expose it as a global in the first place.
I'd strongly recommend that if you find yourself frustrated with the above, stop and think why/if you really want to avoid globals for a library intended to be commonly used across your entire codebase! You may wish to reconsider, and save yourself typing `batteries` a few hundred times :)
I'd strongly recommend that if you find yourself frustrated with the above, stop and think why/if you really want to avoid globals for something intended to be commonly used across your entire codebase! Are you explicitly `require`ing `math` and `table` everywhere you use it too? Are you just as ideologically opposed to `require` being a global?
You may wish to reconsider, and save yourself typing `batteries` a few hundred times :)
## Git Submodule or Static Install?
@ -141,13 +143,13 @@ A static install is harder to update, but easier to trim down if you only need s
## Stripping down `batteries`
Many of the modules "just work" on their own if you just want to grab something specific.
Many of the modules "just work" on their own, if you just want to grab something specific.
Many of them depend on `class`, which can be included alongside pretty easily.
Some of them depend on `class`, which can be included alongside pretty easily.
There are some other inter-dependencies in the larger modules, which should be straightforward to detect and figure out the best course of action (include or strip out) if you want to make a stripped-down version for distribution.
There are some other inter-dependencies in the larger modules, which should be straightforward to detect and figure out the best course of action (either include the dependency or strip out dependent functionality), if you want to make a stripped-down version for your specific use case.
Currently (july 2021) the lib is 40kb or so compressed, including this readme, so do think carefully whether you really need to worry!
Currently (july 2021) the lib is 40kb or so compressed, including this readme, so do think carefully whether you really need to worry about it!
## Versioning?
@ -159,9 +161,9 @@ If there is a large enough user base in the future to make a versioning scheme +
## snake_case? Why?
I personally prefer it, but I accept that it's a matter of taste and puts people off.
I personally prefer it, but I accept that it's a matter of taste and puts some people off.
I've implemented experimental automatic lowerCamelCase API conversion that you can opt in to by calling camelCase() before export(), let me know if you use it and encounter any issues.
I've implemented experimental automatic API conversion (UpperCamelCase for types, lowerCamelCase for methods) that you can opt in to by calling `:camelCase()` before `:export()`, let me know if you use it and encounter any issues.
# License