구글 퍼포먼스툴의 사용법
- 김민수(CTO본부 기반기술팀), 2008년 2월
서론 #
구글에서 개발하여 자사의 여러 인프라 소프트웨어에 적용한 기술중에 공개되고 있는 CPU 프로파일링 해석과 고속의 쓰레드 지원하는 캐쉬 malloc을 구현하는 오픈소스프로젝트의 툴입니다.
인스톨 #
google-perftools 는 이쪽에서부터 다운로드할 수 있습니다.
배포판별로 바이너리 패키지도 있지만 여기서는 소스를 다운로드해 컴파일 합니다. 현재는 최신버전이 0.93 이지만 과거 glibc 버전과의 호환성 문제가 발생할수 있기 때문에 안전하게 0.8을 써보겠습니다. 컴파일은 다른 패키지와 똑같이 ./configure 하여 make 하면 끝입니다. make install 하여 인스톨 할 때만 su하여 root로 해주세요.
$ tar xvfz google-perftools-0.8.tar.gz $ cd google-perftools-0.8 $ ./configure $ make $ su $ make install
이것으로 인스톨은 완료입니다.
Cpu profiler의 사용 #
사용하는 라이브러리는 libprofiler.so 를 링크하고 인클루드 파일은 google/profiler.h 입니다.
아래는 컴파일하려는 샘플 코드입니다. 정확한 프로파일링을 위하여 컴파일 되는동안 최적화 되거나 변경되지 않도록 asm volatile("sync") 를 사용하였습니다. 물론 다른 코드도 비교하여 계산하는데 적당한 코드라면 관계없습니다.
#include <iostream>
#include <google/profiler.h>
using namespace std;
void func1 ()
{
for (int i = 0; i < 10000; i++)
for (int j = 0; j < 1000; j++)
asm volatile ("sync");
}
void func2 ()
{
for (int i = 0; i < 10000; i++)
for (int j = 0; j < 2000; j++)
asm volatile ("sync");
}
void func3 ()
{
for (int i = 0; i < 10000; i++)
for (int j = 0; j < 3000; j++)
asm volatile ("sync");
func1 ();
func2 ();
}
int main (int argc, void** argv)
{
//ProfilerStart ("prof.out");
func3 ();
//ProfilerStop ();
return 0;
}
프로그램 전체의 프로파일을 취하고 싶을 때 #
공유 라이브러리로서 libprofiler.so 를 링크해 컴파일 합니다. 소스에 대한 수정은 이것 뿐입니다. -g 옵션을 붙여 디버그 정보를 부가할 필요도 없습니다. 실행시에 라이브러리에의 패스가 필요해서 환경 변수의 LD_LIBRARY_PATH 를 지정합니다.
csh 의 경우 $ setenv LD_LIBRARY_PATH /usr/local/lib
bash 의 경우 $ export LD_LIBRARY_PATH=/usr/local/lib
추가로 프로파일을 취하는 트리거로서 환경 변수 CPUPROFILE 을 설정합니다. 뒤에는 측정 결과를 쓰는 파일명입니다.
csh 의 경우 $ setenv CPUPROFILE prof.out
bash 의 경우 $ export CPUPROFILE=prof.out
이로써 준비는 끝입니다. 프로그램을 실행하면 프로파일 결과가 지정한 파일에 써집니다.
$ ./a.out PROFILE: interrupts/evictions/bytes = 439/0/508
프로그램의 특정 부분만의 프로파일을 취하고 싶을 때 #
공유 라이브러리로서 libprofiler.so 를 똑같이 링크하고, 측정하고 싶은 곳을 ProfilerStart ("file name") 와 ProfilerStop () 으로 둘러싸면 됩니다.
ProfilerStart ("prof.out");
// 여기가 측정 대상
ProfilerStop ();
prof.out 은 프로파일 결과를 써내는 파일명입니다. 실행시에 라이브러리에의 패스가 없기 때문에 환경 변수로 역시 LD_LIBRARY_PATH 를 지정합니다.
csh 의 경우 $ setenv LD_LIBRARY_PATH /usr/local/lib
bash 의 경우 $ export LD_LIBRARY_PATH=/usr/local/lib
이것으로 준비는 끝입니다. 프로그램을 실행하면 프로파일 결과가 지정한 파일에 써내집니다.
$ ./a.out PROFILE: interrupts/evictions/bytes = 454/0/536
프로파일 결과의 해석 #
측정 결과는 prof.out 로 합니다. 해석 프로그램은 pprof 라는 이름입니다. 실행한 프로그램과 프로파일 결과를 인자로 하여 실행해 주세요.
$ ./pprof a.out prof.out (pprof)
prompt가 표시되어 멈춥니다. 사용방법은 help 커멘드를 실행하면 나옵니다. 종료할 때는 당연하듯 quit 입니다. 해석 결과를 표시하기 위해서 top 커멘드를 사용합니다.
(pprof) top
Total: 441 samples
220 49.9% 49.9% 220 49.9% func3
147 33.3% 83.2% 147 33.3% func2
74 16.8% 100.0% 74 16.8% func1
0 0.0% 100.0% 441 100.0% generic_start_main
0 0.0% 100.0% 221 50.1% _init
0 0.0% 100.0% 441 100.0% __libc_start_main
0 0.0% 100.0% 441 100.0% main
이와 같이 수행시간이 오래 걸린 함수로부터 차례로 표시됩니다.
이 결과는 그래프로서 예쁜 그림으로 표시할 수도 있습니다. 추가로 doxygen 에서도 사용하는 graphviz 라고 하는 어플리케이션이 필요합니다. (커멘드명은 dot ). 일단 quit 하여 pprof 의 prompt를 종료합니다
(pprof) quit
커멘드 라인으로부터 pprof 를 기동해 닷 형식의 파일을 출력합니다.
$ pprof --dot a.out prof.out > prof.dot Dropping nodes with <= 2 samples; edges with <= 0 abs(samples)
가끔 에러 메세지가 나옵니다만 신경쓰지 않아도 됩니다. 그럼 graphviz (dot) 를 사용해 그래프를 만들어 그래픽 파일(png)을 출력합니다.
$ dot -T png prof.dot > prof.png
그래픽 파일을 보려면 적당한 프로그램을 사용하면 되며 여기서는 kview 를 사용했습니다.
$ kview prof.png
결과는 이러한 그래프를 얻을 수 있습니다. 그 함수가 전체의 몇%의 시간을 사용하고 있을지가 한눈에 그림으로 보입니다. 노드의 크기가 처리 시간에 비례하고 있기 때문에 쉽게 어디서 병목현상이 생기는지도 알수 있습니다.
TCMALLOC #
Google Perftools 은 위에서의 사용처럼 퍼포먼스 측정용의 프로파일러로 유명합니다만, 그 중에는 TCMalloc(Thread Caching Malloc)이라고 하는 고속의 쓰레드를 지원하여 캐쉬하는 malloc 라이브러리도 포함되어 있습니다.
TCMalloc의 페이지를 보면 벤치마크의 결과로 특히 multi-thread 어플리케이션에서 효과를 발휘해서 속도와 메모리를 절약하고 있습니다. 그러나, malloc 은 유저랜드의 근간을 이루는 중요한 라이브러리의 하나이므로 교체하면 치명적인 문제가 발생할수 있습니다만, 그런만큼 반대로 효과도 있는 것이기에 해볼만합니다.
사용법 #
사용법은 단지 위의 TCMalloc 의 페이지에서는 PRELOAD 로 tcmalloc 라이브러리만 지정하라고 적혀있습니다. 하지만 Ubuntu 7.04 에서는 ptherad_key_create 문제가 발생하고 있기 때문에 다음과 같이 하여야 합니다.
LD_PRELOAD="/usr/lib/libgthread-2.0.so.0:/usr/lib/libtcmalloc.so" firefox
아니면
export LD_PRELOAD="/usr/lib/libgthread-2.0.so.0:/usr/lib/libtcmalloc.so"
그 외의 리눅스 배포판에서는 /usr/lib/libtcmalloc.so 만 쓰면 됩니다. 더 확실하게 사용하려면 /etc/ld.so.preload 에 추가해 놓으면 항상 사용 할 수 있습니다.
사용결과 #
TCMalloc 이 효과가 있을 것 같은 multi-thread 화 되고 있는 어플리케이션을 ps axm등으로 해서 찾아 보면 mysql, firefox, thunderbird, eclipse (java) 과 같이 비교적 대규모의 쓰레드를 사용하는 어플리케이션이 많은 듯 합니다. 우선 shell 의 rc 설정하여 평상시에 리눅스 데스크탑으로 사용해 본 결과로는 적어도 브라우저와 eclipse, firefox 정도는 가벼워진 것 같은 생각이 듭니다. 특히 여러개의 어플리케이션을 시작할때는 무겁다는 느낌이 나름대로 없어진거 같은 느낌입니다.
그리고는 현재 시험해보지는 않습니다만 web 서버로 apache를 워커쓰레드 버전으로 하면 mysq과 같이 효과가 나올지도 않을까 생각이 듭니다.
결론 #
- 퍼포먼스 결과에 대한 수치를 정확하게 측정하여 어디에서 문제가 생기는지 찾을수 있고 대규모의 메모리 사용문제에 대해 보다 효율적인 캐쉬 방식을 도입할수 있습니다.
![[http]](/wiki/imgs/http.png)