메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

한빛랩스 - 지식에 가능성을 머지하다 / 강의 콘텐츠 무료로 수강하시고 피드백을 남겨주세요. ▶︎

IT/모바일

컴파일 시간을 줄이자 - 성능 분석을 통한 케이스 스터디

한빛미디어

|

2002-05-15

|

by HANBIT

10,043

저자: 『System Performance Tuning, 2nd Edition』의 공동 저자 Gian-Paolo D. Musumeci, 역 이호재

고성능을 요구하는 B2C 애플리케이션을 개발하는 회사인 e-Gizmo의 소프트웨어 엔지니어는 가끔씩 골머리를 앓을 때가 있습니다. 바로 중요한 라이브러리를 컴파일 하는데 너무 많은 시간이 걸리기 때문입니다.

개발 서버인 polaris는 듀얼 250MHz UltraSPARC II 프로세서와 512MB의 메모리, 18GB로 구성된 Sun Enterprise 2 서버입니다. 이 하드디스크 중 하나는 1GB의 스왑 용량과 17GB의 루트 파일 시스템으로 나누어져 있으며, 나머지 하드디스크는 모든 컴파일이 이루어 지는 /export/src로 구성되어 있습니다. 이 시스템의 운영체제는 솔라리스 7이며 모두 패치 되어 있습니다. 개발자들은 컴파일러로 Forte Developer 6 update 2 compiler suite를 사용합니다. 물론 이런 장비는 아무런 튜닝 작업을 하지 않았습니다.

System Performance Tuning, 2nd Edition
소프트웨어 개발자들의 불만은 제품 컴파일에 걸리는 시간이 너무 길다는 점이었습니다. 예를 들어 100,000라인의 C 코드를 컴파일 하는 데만 약 18분이 걸립니다. 컴파일 결과물에 영향을 주지 않고서 컴파일 시간이 35% 단축된 12분 정도가 되면 정말 좋겠지만, 이 프로젝트를 위해 자금이 지원되지 않았기 때문에 개발자들은 현재 자신들이 가지고 있는 하드웨어만을 사용해야만 했습니다.

이 소프트웨어는 전체 애플리케이션의 성능에 아주 중대한 영향을 미치기 때문에 매우 높은 수준의 최적화 옵션으로 컴파일을 했습니다. 그 옵션은 -fast -xarch=v8plusa 입니다.

시스템의 부하를 살펴보기 전에, 무엇이 병목 현상(bottleneck)을 일으키는지를 예상해보고 튜닝 전략을 세워보도록 하겠습니다. 컴파일이 시스템에 주는 stress를 기준으로 하여 메모리 소비와 CPU 사용, 디스크 입출력(disk I/O)를 검사하기로 했습니다. NFS는 사용하지 않았기 때문에 네트워크가 이 문제의 원인은 아니었습니다. 그래서 우리는 세가지 질문을 만들었습니다.
  • 메모리가 부족합니까? 메모리 부족의 가장 확실한 증거는 vmstat 결과의 sr 항목에 있습니다. 이러한 사항은 『System Performance Tuning, 2nd Edition』 4장에 자세히 설명되어 있습니다.
  • 디스크 입출력에 문제가 있습니까? 컴파일은 종종 디스크를 많이 이용합니다. 우리는 이를 iostat 명령어를 통해 알 수 있습니다. 디스크 입출력은 『System Performance Tuning, 2nd Edition』 5장에 자세히 설명되어 있습니다.
  • CPU사용이 포화상태입니까? 우리는 라이브러리를 가능한 한 빨리 컴파일하기 위해 최선을 다해야 합니다. 그래서 우리는 두개의 CPU 가동률이 100%가 되길 원합니다. 프로세서 성능에 관한 자세한 사항은 『System Performance Tuning, 2nd Edition』 3장을 참고하기 바랍니다.
이제부터는 컴파일을 처음으로 실행했을 때 얻은 실제 데이터를 살펴보도록 하겠습니다. 위에서 언급한 세 가지 질문에 대한 해답을 얻기 위해 vmstat 5, iostat -xnP 30, mpstat 5의 결과 중 주목해야 할 부분을 요약했습니다.

메모리 부족 현상이 있습니까? vmstat 결과를 살펴보도록 합시다.
polaris% vmstat 5
 procs     memory            page            disk          faults      cpu
 r b w   swap  free  re  mf pi po fr de sr s1 s1 s2 --   in   sy   cs us sy id
 0 0 0 1425960 396952 0 727  4  1  1  0  0  0  3  0  0  141 2220  121 38 12 50
 0 0 0 1426912 397856 0 1207 8  0  0  0  0  0  4  0  0  148 3513  153 29 20 51
 0 0 0 1426072 396896 0 628  6  0  0  0  0  0  2  0  0  330 7017  930 40 14 46
메모리 부족의 가장 중요한 척도는 sr 열입니다. 여기서는 0값을 계속해서 유지하고 있습니다. 메모리가 부족할 경우, 우리가 해야 할 첫번째 방법은 priority paging을 사용하는 것입니다. 여기서 약간 의심스러운 점은 id 열에서 볼 수 있는 것처럼 약간의 idle 시간이 있다는 사실입니다. 이에 대해서 살펴봐야 할 것입니다.

디스크 입출력에 문제입니까? iostat -xnP 5의 결과는 디스크 입출력의 문제가 아니라는 것을 보여줍니다.
polaris% iostat -xnP 5
...
                             extended device statistics
 r/s  w/s   kr/s   kw/s wait actv wsvc_t asvc_t  %w  %b device
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t0d0s0
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t0d0s1
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t0d0s2
 0.2  2.6    0.6    8.6  0.0  0.0    0.0   14.0   0   2 c0t1d0s0
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t1d0s2
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 polaris:vold(pid208)
...
많은 디스크 활동은 없습니다. 입출력은 오직 /export/src(c0tld0s0) 에서만 일어납니다. c0t0d0s0는 swap 영역이고 c0t0d0s1/ 입니다.

마지막으로 mpstat의 결과를 살펴보고 CPU에 어떤 일이 일어나고 있는지 살펴보도록 하겠습니다.
polaris% mpstat 5
CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
 0  294   0  115   214   13   92    9    6    0    0   599    9   5   1  85
 1  489   0   67    28   14   39   13    8    1    0  1875   63  22   1  14
CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
 0  147   0  155   216   12   96   12    5    1    0   871    5   9   0  85
 1 1098   1   71    32   17   60   14   10    1    0  2890   51  32   3  14
아주 유용한 일을 하는데 있어 오직 하나의 프로세서만을 이용하는 것처럼 보입니다. e-Gizmo가 소프트웨어 개발에 사용하는 이러한 멀티프로세서 시스템에서는 dmake 라는 것을 사용할 수 있습니다. 이는 컴파일 과정을 병렬화합니다. 우리가 이 소프트웨어를 사용하여 CPU 사용률을 높힐 수 있는지 살펴보도록 하겠습니다(† 역자 주: 리눅스의 make는 이미 -j 옵션을 가지고 있습니다. 두 개 이상의 CPU를 갖고 있는 시스템이 있다면 make 명령을 사용할 때 -j [thread_number] 옵션을 추가하면 됩니다.).

이를 테스트하려면 예전의 모든 object 파일들을 제거하기 위해 make clean을 실행해야 합니다. 그리고 난 후 파일 시스템 캐쉬를 제거하기 위해 /export/src를 언마운트(unmount)하고 다시 마운트합니다. 이러한 방법으로 똑같은 테스트를 병렬 make를 이용해서 다시 한 번 더 수행합니다. 두 개의 프로세서를 가지고 있기 때문에 컴파일할 때 두 개의 스레드를 갖도록 했습니다.
 
polaris% /bin/time -p dmake -j 2
...
real 614.14
user 867.14
sys 219.82
퍼포먼스 향상을 위해 관심을 가져야 할 부분은 wall-clock 컴파일 시간으로/bin/time은 이를 "real"로 나타냅니다. 여기서 우리는 훌륭하게도 거의 2분에 가까운 시간을 줄였습니다. mpstat의 결과를 보면 대부분의 idle 시간을 줄였다는 것을 알 수 있습니다.
polaris% mpstat 5
...
CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
 0  448   0   80   221   12   83   33    9    1    0  1372   76  15   1   8
 1  440   0  105    39   14   48   24    8    1    0  1218   84  13   1   2
...
우리는 프로세서 수보다 많은 병렬 실행 스레드를 지정할 수도 있습니다. 그래서 몇 가지 테스트를 해봤고 그 결과는 다음과 같습니다.
 
-j      real time (m:s)  user time (m:s)  sys time (m:s)
 1      18:03.03         14:14.34         3:27.34
 2      10:14.14         14:27.14         3:39.82
 3       9:41.86         14:28.37         3:39.45
 4       9:34.66         14:33.45         3:39:22
여기서 우리는 스레드가 많아질수록 대체적으로 시간이 줄어든다는 것을 알 수 있습니다. 더 많은 j 값에 대한 실험을 해보면 컴파일 시간을 몇 초 정도 줄일 수도 있겠지만 e-Gizmo사의 테스트 요청 시간이 많지 않았기 때문에 여기까지만 테스트를 하였습니다.

여기에서는 -j 4가 최고의 선택이라고 생각했습니다. 그리고 마지막으로 튜닝하기 쉬운 타겟이 시스템의 다른 곳에 없다는 것을 확실히 확인하기 위해 iostatvmstat의 결과를 살펴볼 것입니다.
 
polaris% vmstat 5
procs     memory            page            disk          faults      cpu
r b w   swap  free  re  mf pi po fr de sr s1 s1 s2 --   in   sy   cs us sy id
1 0 0 1412432 368488 0 1583 11 0  0  0  0  0  5  0  0  512 5491 1135 71 28  0
2 0 0 1409768 365920 0 1552 11 0  0  0  0  0 10  0  0  530 5417  812 73 27  0
2 0 0 1412144 367768 0 1460 1  0  0  0  0  0  4  0  0  561 4954  518 73 27  0

polaris% iostat -xnP 5
                             extended device statistics
 r/s  w/s   kr/s   kw/s wait actv wsvc_t asvc_t  %w  %b device
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t0d0s0
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t0d0s1
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t0d0s2
 1.2  5.0    8.6  229.0  0.0  0.2    0.0   32.3   0   3 c0t1d0s0
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t1d0s2
 0.0  0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 islington:vold(pid208)
이상 우리가 수행 했던 것보다 더 쉬운 성능 향상은 더 이상 없습니다. 게다가 클라이언트 시스템에 매달릴 시간이 더 이상 없었기 때문에 우리는 여기까지만 하고 작업을 마무리 지었습니다. 그리고 e-Gizmo의 엔지니어들은 성능 향상을 이룰 수 있었기 때문에 이제 더 이상 골머리를 앓을 필요도 없어졌습니다.

지금 까지 살펴본 것은 직접적인 문제에 대한 직접적인 해결책이었습니다. 하지만 해결방법이 항상 이렇게 쉬운 것은 아닙니다. 이번 케이스 스터디에서 얻을 수 있었던 교훈은 dmake를 통해 얼마나 속도를 향상시킬 수 있었느냐도 아니고, -j 값으로 가장 적당한 값이 어떤 것이었는가도 아닙니다. 핵심은 바로 우리가 문제에 접근하는 방법에 관한 것이었습니다. 성능 향상을 위한 요구사항, 튜닝을 하기 위한 가설, 시스템이 작동하고 있는 동안 얻은 데이터와 여기에 대응하는 방법들이 바로 이 기사에서 다룬 가장 중요한 사항이라는 사실을 잊지 마시기 바랍니다.
TAG :
댓글 입력
자료실

최근 본 상품0