lua-users home
lua-l archive

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


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.