[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: ways to avoid (or speed up) luaL_checkudata() in LuaJIT2?
- From: Luiz Henrique de Figueiredo <lhf@...>
- Date: Mon, 8 Nov 2010 23:40:04 -0200
> > the problem is that [luaL_checkudata] this function actually needs to
> > create a new string in order to do the user data name check at all.
>
> If that is a problem for your application, just write your own
> luaL_checkudata and luaL_newmetatable. You can for instance use void*
> instead of strings and use a static address in your library.
To test the performance of this approach, I've added the code below to
my lcomplex library and ran a simple Mandelbrot test. This tests creates
lots of temporary complex numbers that need to be checked at each step.
Here are the timings: the new scheme takes 70% of the original tinme.
Original scheme -- using strings as keys
0.780u 0.024s 0:00.80 100.0% 0+0k 0+104io 0pf+0w
New scheme -- using light udata as keys
0.540u 0.020s 0:00.55 101.8% 0+0k 0+104io 0pf+0w
Unsafe scheme -- no checking of udata
0.436u 0.012s 0:00.44 100.0% 0+0k 0+0io 0pf+0w
The unsafe scheme uses just this:
#define luaL_checkudata(L,i,s) lua_touserdata(L,i)
Here is the code, which was based directly on the code in lauxlib.c.
For production, the my_* functions should probably receive the pointer
&mykey, instead of using it directly.
/* udata.c. Include it after lauxlib.h. */
static int mykey=0;
static int my_newmetatable (lua_State *L) {
lua_pushlightuserdata(L,&mykey);
lua_rawget(L, LUA_REGISTRYINDEX);
if (!lua_isnil(L, -1)) /* name already in use? */
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1);
lua_newtable(L); /* create metatable */
lua_pushlightuserdata(L,&mykey);
lua_pushvalue(L, -2);
lua_rawset(L, LUA_REGISTRYINDEX);
return 1;
}
static void my_getmetatable (lua_State *L) {
lua_pushlightuserdata(L,&mykey);
lua_rawget(L, LUA_REGISTRYINDEX);
}
static void *my_checkudata (lua_State *L, int ud, const char *tname) {
void *p = lua_touserdata(L, ud);
if (p != NULL) { /* value is a userdata? */
if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
lua_pushlightuserdata(L,&mykey);
lua_rawget(L, LUA_REGISTRYINDEX); /* get correct metatable */
if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */
lua_pop(L, 2); /* remove both metatables */
return p;
}
}
}
luaL_typerror(L, ud, tname); /* else error */
return NULL; /* to avoid warnings */
}
#undef luaL_getmetatable
#define luaL_getmetatable(L,s) my_getmetatable(L)
#define luaL_newmetatable(L,s) my_newmetatable(L)
#define luaL_checkudata(L,i,s) my_checkudata(L,i,s)