lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 11 January 2017 at 13:02, Xianfu Pan <pxfgod@gmail.com> wrote:
> We use Lua 5.3 in our game project.
>
> There is a function frequently called. and the function will generate
> several temporary tables.
> The function looks like this:
> `
> function cfg_read_from_database(...)
> local tmp = {}
> -- some writes on table 'tmp'
> return tmp
> end
> `
> `tmp` is a non-nested table of some fields. it's sorely aimed to pass
> configs.
> Do not look down upon the only sentence `local tmp = {}` inside function,
> the side-effect of tmp is upon the frequency it is called!!!
>
> The more frequently it be called, the more offen memory be alloced for
> `tmp`, thus next gc loop comes sooner and sooner.
> Our monitor of gc curve gose steeply because of the frequece of temporary
> table, which leads to terrible gc latency.
>
> So we optimize our function; it looks like this
>
> `
> local tmp = {}
> function cfg_read_from_database()
> for k, v in pairs(tmp) do tmp[k] = v end
> ...
> return tmp
> end
> `
> Just a strategy to waste time and to save space.
> This code will avoid temporary table memory alloc, but at cost of extra
> operations to clear table.
>
> And since memory increases slowlier, gc loop behaves less aggressive, which
> finally saves time.
>
> So we dicide to optimize `for k, v in pairs(tmp) do tmp[k] = v end` with
> `table.reset(tmp)`.
> They are of same sementics.
>
> Here is the implementation of `table.reset`
> `
> static int treset(lua_State *L) {
> if (lua_istable(L, 1)) {
> lua_resettable(L, 1);
> }
> else {
> luaL_error(L, "bad argument to table.reset table expect got %s",
> lua_typename(L, lua_type(L, 1)));
> }
> return 0;
> }
> `
> we add a LUA_API to "lua.h"
> `
> LUA_API void lua_resettable(lua_State *L, int idx){
> StkId o;
> lua_lock(L);
> api_checknelems(L, 2);
> o = index2addr(L, idx);
> api_check(L, ttistable(o), "table expected");
> luaC_resettable(L, hvalue(o));
> lua_unlock(L);
> }
> `
>
> and `luaC_resettable` is implemented as follows in "lgc.c"
> `
> void luaC_resettable(lua_State *L, Table *h) {
> /*need not to barrierback, because new value is NIL*/
> Node *n, *limit = gnodelast(h);
> unsigned int i;
> for (i = 0; i < h->sizearray; i++){
> TValue *cell = &h->array[i];
> setnilvalue(cell);
> }
> for (n = gnode(h, 0); n < limit; n++) {  /* traverse hash part */
> TValue *cell = gval(n);
> if (!ttisnil(cell))
> setnilvalue(cell);
> }
> }
> `
>
> Are there any issues/pitfalls of my implementation. Or any advices for me?
> Many thanks.

Perhaps your issue is actually that you are growing the table too often.
When creating your table, do you get better performance if you
preallocate some fields?
i.e. `local tmp = {a=nil, b=nil, c=nil, d=nil}`
Add as many fields as your `tmp` table has in the non-rare cases.

In C you have lua_createtable for this.