2007년 9월 6일 목요일

공유객체 속도

UNIX 공유객체(shared object) 만들기

테스트 환경을 만들기 전에 파일명을 소개하겠다.
  • Makefile - 빌드를 위한 스크립트
  • plgn.cpp - plgn.so를 위한 소스. func2 함수가 포함되어 있다.
  • sotest.cpp - 시간 측정을 위한 소스. func1 함수가 포함되어 있다.
일단 Makefile
TARGET=sotest plgn.so
CXXFLAGS=-g -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_REENTRANT
LDFLAGS=-ldl

all:$(TARGET)

clean:
    $(RM) $(TARGET) *.o

sotest:sotest.cpp

plgn.so:plgn.o
    $(CXX) $(CXXFLAGS) -shared -lc -o $@ $<

plgn.o:plgn.cpp
    $(CXX) $(CXXFLAGS) -c -fPIC $<
뭐, 대충 흉내만 내놓고... 다음은 plgn.cpp
extern "C" void func2(volatile int*);

void
func2(volatile int* v)
{
    ++(*v);
}
역시나 흉내내기. extern "C"를 붙여 맹글링 회피 능력을 +3 했다. (뻘소리)
다음은 sotest.cpp
#include <iostream>
#include <dlfcn.h>
#include <sys/time.h>
using namespace std;

static const size_t testcount(1000000UL);

long long
getTimestamp(void)
{
    static struct timeval tv;
    gettimeofday(&tv, NULL);
    return 1000000LL*tv.tv_sec+tv.tv_usec;
}

extern "C" void func1(volatile int*);

typedef void (*func_t) (volatile int*);

void
func1
(volatile int* i)
{
    ++(*i);
}

void
testFunc(func_t f, const char* msg)
{
    static const long long t1(getTimestamp());
    volatile int v(0);
    for ( size_t i(0); i<testcount; i++ )
    {
        f(&v);
    }
    cout << msg << ": " << (getTimestamp()-t1)/1000.0 << " msec" << endl;
}

void
testSFunc(int flag, const char* msg)
{
    static void* handle(NULL);
    handle = dlopen("./plgn.so", flag);
    if ( !handle )
    {
        cout << dlerror() << endl;
        return;
    }

    int tip;
    func_t f((func_t)dlsym(handle,"func2"));
    f(&tip);
    testFunc(f, msg);
    dlclose(handle);
    handle = NULL;
}

int
main(int,char**)
{
    testFunc(func1,"Local");
    testSFunc(RTLD_LAZY|RTLD_LOCAL, "Shared(LAZY|LOCAL)");
    testSFunc(RTLD_NOW|RTLD_LOCAL, "Shared(NOW|LOCAL)");
    testSFunc(RTLD_LAZY|RTLD_GLOBAL, "Shared(LAZY|GLOBAL)");
    testSFunc(RTLD_NOW|RTLD_GLOBAL, "Shared(NOW|GLOBAL)");

    return 0;
}
자, 빌드해보자.
$make
g++ -g -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_REENTRANT -ldl sotest.cpp -o sotest
g++ -g -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_REENTRANT -c -fPIC plgn.cpp
g++ -g -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_REENTRANT -shared -lc -o plgn.so plgn.o
실행 결과는?
$ ./sotest
Local: 3.496 msec
Shared(LAZY|LOCAL): 7.221 msec
Shared(NOW|LOCAL): 10.786 msec
Shared(LAZY|GLOBAL): 14.349 msec
Shared(NOW|GLOBAL): 17.908 msec
느리구나... -_- 두 배나...