본문 바로가기

카테고리 없음

Lua의 성능향상을 위해...

오랜만에 포스팅 합니다... 주로, 제가 잊어버리지 않으려 하다 보니.. 신경을 많이 못쓰네요..

lua 과연 원하는 성능을 내고 있는가?

여러 이유로 성능에 만족 못하는 개발자들이 있을 것이다..
그러다 보니, 개발 과정중에 lua의 비중이 점점 줄어드는 상황 까지도 발생되어 나중에는 포기하는
상황까지도 발생하곤 한다.

여기에서는 많은 기법중 하나를 이야기 하고자 한다.

- lua에는 스크립터 코드를 로딩하는 방법이 있다. 일반적으로 lua_dofile()도 그중 하나인데..

lua의 성능에 영향을 미치는 가장큰 하나가 바로 lua_dofile()과 같은 스크립터 적재 과정에 있다.
프로그램 구동시 단 한번만 사용한다면 크게 문제가 되지 않겠지만, 그렇지 않은 상황이라면
lua의 성능에 가장 많은 영향을 끼치는 요소가 바로 이 과정이다.

- lua_dofile()이 처리하는 과정을 보면
  1) 스크립터 파일을 메모리로 적재
  2) 스크립터 코드를 해석
  3) 해성된 코드의 실행

여기에서 가장 많은 속도 저하의 요소가 바로 "스크립터 코드의 해석"에 있다. 이 과정을 일반적으로
compile 과정이라고 하는데, lua를 사용해 보면 알겠지만.. 이러한 문제를 해결하기 위해 luac라는 별도의
실행 파일이 존재하기 까지 한다.

그럼.. 여기서 내가 알려주려 하는 것은,
   1) luac 와 같은 과정을 프로그램 내에서 하도록 하는 방법과
   2) C/C++과의 인터페이스로 인해 생성된 함수로 인해 컴파일된 스크립터 실행시 오류를 해결하는 방법을
알려 주고자 한다.

먼저, 가장 간단한 luac 구현 방법이다.
 
static int ldump_writer(lua_State *L, const void *b, size_t size, void *B)
{
    (void) L;
    luaL_addlstring((luaL_Buffer *) B, (const char *) b, size);
    return 0;
}

static std::string luaScriptCompile( lua_State *L, std::string file)
{
    int top = lua_gettop( L);
    std::string r;
    if (luaL_loadfile( L, file.c_str()) != 0)
    {
        fprintf( stderr, "luaScriptCompile :: %d - %s: %s\n", __LINE__, file.c_str(), lua_tostring(L, -1) );
    }
    else {
        luaL_Buffer b;

        luaL_buffinit( L, &b);
        lua_dump( L, ldump_writer, &b);
        luaL_pushresult( &b);

        r = std::string( lua_tostring( L, -1), lua_strlen( L, -1));
        fprintf( stderr, " PRECOMPILE: '%s' -> %d bytes\n", file.c_str(), r.length());
        lua_settop( L, top);
    } return r;
}


참으로 간단하지 않은가? 이후에는 반환된 컴파일 스크립터 데이터를 lua_dofile()이나, lua_dobuffer()를 통해
필요할때 실행하면 된다. (그럴려면 빌드된 데이터를 메모리에 보관하던지, 아니면 패키징 파일에 넣어둬야 하겠죠^^)

여기에서 이렇게 빌드된 컴파일 데이터를 lua_dofile()로 실행할때 로딩할수 없다는 오류가 나는 경우가 있다.

특히, 나는 lua에 try...catch...finally 패치를 해서 사용하는데.. 이 부분을 해결하는데도 아주 도움이 많이 되었다.
두번째로 설명하고자 하는 것이 이 부분에 대한 패치인데..

diff -uNr lua-5.1.4.orig/src/ldebug.c lua-5.1.4/src/ldebug.c
--- lua-5.1.4.orig/src/ldebug.c 2009-01-07 00:04:25.000000000 +0900
+++ lua-5.1.4/src/ldebug.c      2009-01-07 00:04:48.000000000 +0900
@@ -303,7 +303,7 @@

 static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) {
   switch (mode) {
-    case OpArgN: check(r == 0); break;
+    case OpArgN: /* check(r == 0); */ break;
     case OpArgU: break;
     case OpArgR: checkreg(pt, r); break;
     case OpArgK:

이 패치는 만약에 오류가 발생되는 상황이 된다면 수정할수 있다.

실제로 이렇게 컴파일한 lua 스크립터를 통해 테스트를 해보면 스크립터의 실행속도가 상당히 많이 빨라졌다는 것을
체감할수 있을 정도로 느낄수도 있을것이다.

도움이 되길~