쓰레드별 변수 __thread 사용

Posted at 2009/04/09 13:53 // in Programming // by Daniel

OS가 지원해야 하며 일단 제가 알기로는 Linux(2.6부터) gcc와 MSVC에서 지원되는데요,

TLS - Thread Local Storage 라고 불립니다. 시스템콜로 구현되는 것 같더군요.

일단 구현된 내용은 차치하고 사용법은 다음과 같습니다.

 

gcc의 경우만 설명

__thread int my_thread_var;
static __thread int my_static_thread_var;

 

__thread 키워드로 구분되며 이렇게 선언한 변수는 쓰레드마다 가지게 됩니다.

 

관련 내용 링크

Linux 2.6 속으로!

... 또 다른 변화는 TLS (Thread Local Storage) 시스템 호출의 도입이다. 쓰레드 레지스터로 사용될 수 있는 GDT (Global Descriptor Table) 엔트리를 한 개 이상 할당 할 수 있다. GDT는 CPU 기반이고 엔트리는 쓰레드 기반이다.

TLS - Thread Local Storage http://purewell.egloos.com/3398289

* GCC 메뉴얼 보면 TLS가 아니라 TSD(Thread Storage Duration)이라고 표현하였는데 대충 같은 말이다.
이것을 위해 POSIX는 pthread_key_create, pthread_get/setspecific 등 함수를 마련해놨지만 눈만 팽글팽글 돌고, 소스만 지저분해져 보일 것 같다. 귀찮으면 C99, C++98 표준 __thread 키워드를 사용하자.

http://kldp.org/node/78262

~$ /lib/libc.so.6
...
Thread-local storage support included. << 이부분이 보인다면 현재 glibc가 TLS를 지원하는버젼입니다.

크리에이티브 커먼즈 라이센스
Creative Commons License

함수의 리턴 주소 알아내기

Posted at 2009/03/23 11:16 // in Programming // by Daniel

프로파일링이나 함수 래핑으로 lock등의 작업을 가로채서 로깅할 때 호출한 쪽의 PC값을 알고 싶을 경우가 있습니다.

현재실행되는 함수 입장에서 보면 리턴 주소이죠

이 때 쓸 수 있는 함수가 gcc의 builtin함수로 __builtin_return_address() 입니다.

__builtin_return_address(level)

여기서 level은 call stack 에서 몇번째를 리턴할 것인지에 대한 값입니다.

__builtin_return_address(0) 하면 현재함수의 리턴주소가 나옵니다.

__builtin_return_address(1) 하면 나를 호출한 함수의 리턴주소가 나옵니다...

예제 코드를 짜봤습니다.

#include <stdio.h>
#include <stdlib.h>

int my_func1()
{
    void *addr;
    addr = __builtin_return_address(0);
    printf("1's caller %p\n",addr);
    printf("hello 1\n");
}
int my_func0()
{
    void *addr;
    printf("hello 0\n");
    addr = __builtin_return_address(0);
    printf("0's caller %p\n",addr);
    my_func1();
}

int main(void)
{
    printf("backtrace test\n");
    printf("main: %p\n", (void *)main);
    printf("my_func0: %p\n", (void *)my_func0);
    printf("my_func1: %p\n", (void *)my_func1);
    my_func0();
    return 0;
}


이 소스코드를 컴파일해서 objdump해보면

080483d1 <my_func0>:
...
80483fc:   e8 a3 ff ff ff          call   80483a4 <my_func1>
8048401:   c9                      leave
8048402:   c3                      ret

08048403 <main>:
...

804845c:   e8 70 ff ff ff          call   80483d1 <my_func0>
8048461:   b8 00 00 00 00          mov    $0x0,%eax
...

이와 같이 호출하게 되어있고

실행해보면

backtrace test
main: 0x8048403
my_func0: 0x80483d1
my_func1: 0x80483a4
hello 0
0's caller 0x8048461
1's caller 0x8048401
hello 1

이렇게 나옵니다. call 바로 다음 주소--리턴 주소가 나오지요.

이외에도 몇가지 builtin함수들이 있습니다.

예를 들어 __builtin_frame_address(level)은 프레임 포인터를 반환합니다.


관련 포스트 :

gcc 컴파일 옵션으로 커스텀 프로파일 해서 실행 트레이스 뽑기

크리에이티브 커먼즈 라이센스
Creative Commons License

컴파일러에서 제공하는 기본 설정 매크로 한 번에 보기

Posted at 2008/11/18 11:48 // in Tips // by Daniel

gcc -v -E -dM - < /dev/null

이 명령치면 기본 설정된 매크로 가 한 번에 보입니다

http://kldp.org/node/99917

-v는 불필요합니다.

본문과 관련이 있을 것 같은 URL 올립니다.

* http://predef.sourceforge.net/
* http://msdn.microsoft.com/library/defau ··· r_18.asp

image

크리에이티브 커먼즈 라이센스
Creative Commons License

gcc 컴파일 옵션으로 커스텀 프로파일 해서 실행 트레이스 뽑기

Posted at 2008/09/04 10:36 // in Programming // by Daniel

실행 트레이스 뽑기

  • 이 링크 (원문 IBM) 에 보면 소스에 작은 글루 코드를 컴파일 시 붙여 콜 그래프를 뽑을 수 있다고 나옵니다.(gcc에서 지원하는 트레이스 뽑는 방법). –g 옵션과 -finstrument-functions 로 됨.

사용방법 :
1. Instrument.c
Instrument.c를 만들고 내용에
void main_constructor( void )
void main_deconstructor( void )
void __cyg_profile_func_enter( void *this, void *callsite )
void __cyg_profile_func_exit( void *this, void *callsite )

를 만들어 넣음. (trace.txt를 열고 닫고, 포인터 프린트하는 걸로 충분. 예제 코드 있음.)
#include <stdio.h>
#include <stdlib.h>
필요.
2. 컴파일
gcc –g -finstrument-functions test.c instrument.c –o test
로 컴파일

3. 실행
이러면 trace.txt가 나옴. 여기엔 들어가고 나온 함수의 주소가 나옴.

4. 심볼 이름 뽑고 정리하기
여기까지만 하고 addr2line으로 함수이름 뽑을 수 있고,
나머지 복잡한 것은 링크 참조. pvtrace라는 프로그램을 컴파일해서 콜 그래프 생성 예제가 있습니다.
Thread 정보 보고싶으면, self = pthread_self();으로 쓰레드 아이디 읽어와서 뿌리면 됨.

런타임에 함수 이름 뽑고 싶으면 몇가지 방법이 있을 듯 합니다.
libtrace_resolve (func, buf_func, CTRACE_BUF_LEN, NULL, 0); 등을 써서..

심볼 이름 찾는 또다른 방법은 여기 더 설명 나옴. backtrace, backtrace_symbols libbfd 등.
 이곳에서는 트레이스 함수를 좀더 많이 정보를 뿌리게 만들었음.


제가 실행해본 예입니다.

해당 방법으로 midori 브라우저(웹킷 기반의 가벼운 브라우저입니다) instrumentation

Makefile.in에서
 midori_OBJECTS = $(am_midori_OBJECTS) instrument.$(OBJEXT)
 이렇게 고치고
CFLAGS = @CFLAGS@ -finstrument-functions
이렇게 추가.
Makefile.am에서
midori_SOURCES = 에 instrument.c 추가 (이건 별 효과 없는 듯)
$ make clean
$ make
$ ./midori 
$ ~/misc/pvtrace/pvtrace midori 
$ dot -Tjpg graph.dot -o graph.jpg
그림 확인
$ eog graph.jpg

trace.txt를 얻어,

image

콜 그래프 생성했습니다.

크리에이티브 커먼즈 라이센스
Creative Commons License

gprof 간단사용

Posted at 2008/04/29 01:52 // in Tips/Utility programs // by Daniel
http://kldp.org/node/32606

gcc 옵션에 -pg를 붙여서 컴파일한다.

그리고 컴파일한 프로그램을 실행하면,

gmon.out 이란 파일이 생긴다.


그리고 gprof 실행

gprof 사용법은,
gprof [실행 binary] [실행으로 생성된 gmon.out]


$ gprof myprog gmon.out > profile.txt

크리에이티브 커먼즈 라이센스
Creative Commons License

gcc 매크로의 가변 인자 사용하기

Posted at 2008/04/06 14:57 // in Programming // by Daniel

춮처 : http://developer.apple.com/documentation/DeveloperTools/gcc-4.0.1/cpp/Variadic-Macros.html

#define DEBUG
#ifdef DEBUG
#define DBG(...)    fprintf(stderr, __VA_ARGS__)
#else
#define DBG(...)    do{}while(0)
#endif

이런식으로 사용합니다.

C99 표준이라고 돼 있고 gcc 4.0부터는 확실히 이렇게 쓰는 것 같습니다.

gcc가 이전부터 사용하는 것과 맞추려면(C99표준은 아닌 것 같습니다)

#define eprintf(format, args...) fprintf (stderr, format , ##args)

이런식으로 쓰라는군요

## args 전에는 콤마(,)와 빈칸이 꼭 있어야 한답니다.

크리에이티브 커먼즈 라이센스
Creative Commons License