성능 최적화를 위해 꼭 알아야 할 숫자들

모바일 게임은 핸드폰에서 돌릴 수 있는 가장 무거운 소프트웨어 중 하나이기 때문에 출시 전 성능 최적화가 반드시 필요합니다. Peter Norvig이 쓴 Teach Yourself Programming in Ten Years을 보면 성능 최적화를 위해 개발자가 반드시 숙지하고 있어야 할 숫자들이 나옵니다.

  • execute typical instruction: 1/1,000,000,000 sec = 1 nanosec
  • fetch from L1 cache memory: 0.5 nanosec
  • branch misprediction: 5 nanosec
  • fetch from L2 cache memory: 7 nanosec
  • Mutex lock/unlock: 25 nanosec
  • fetch from main memory: 100 nanosec
  • send 2K bytes over 1Gbps network: 20,000 nanosec
  • read 1MB sequentially from memory: 250,000 nanosec
  • fetch from new disk location (seek): 8,000,000 nanosec
  • read 1MB sequentially from disk: 20,000,000 nanosec
  • send packet US to Europe and back: 150 milliseconds = 150,000,000 nanosec

최적화에서 위 숫자가 중요한 이유는 각 최적화마다 기대되는 효과가 천차만별이기 때문입니다. 예를 들어, 실제로는 네트워크 병목이 문제인 게임에서 뮤텍스 락을 최적화해서 기대되는 효과는 무척 낮을 수밖에 없습니다. 위 표를 보면 미국에서 유럽으로 패킷을 보내고 받을 때 걸리는 지연 시간(latency)는 뮤텍스 락을 잡고 푸는데 걸리는 시간보다 무려 6,000,000배나 깁니다.

하드웨어 성능은 매년 발전하기 때문에 위 표의 숫자를 기계적으로 다 외울 필요는 없습니다. 다만, 각 연산에 걸리는 시간의 차이를 상대적으로는 기억할 필요가 있습니다. L1 캐시(cache)에서 데이터를 가져오는 데 걸리는 시간은 0.5 nanosec이고, 캐시 미스(cache miss)가 나서 메인 메모리에서 데이터를 가져오게 되면 100 nonosec이 걸립니다. 캐시 미스가 나면 페널티로 200배 가까운 시간이 더 걸리는 셈입니다.

그런데 저 표를 외우기가 쉽지 않습니다. 보통 사람은 nanosec이라는 시간에 대해 전혀 감이 없습니다. 1초도 눈 깜짝할 사이기 때문에 1초의 1/1,000이나 1/1,000,000이나 1/1,000,000,000이나 다 그냥 짧은 시간처럼 느껴지기 때문입니다. 최적화에서는 어차피 상대적인 시간이 중요하기 때문에 위 표를 외우는 좀 더 쉬운 방법은 1 nanosec을 1 sec로 생각하고 우리가 일상적으로 쓰는 단위로 환산해 보는 것입니다.

  • execute typical instruction: 1/1,000,000,000 sec = 1 초
  • fetch from L1 cache memory: 0.5 초
  • branch misprediction: 5 초
  • fetch from L2 cache memory: 7 초
  • Mutex lock/unlock: 0.5 분
  • fetch from main memory: 1.5 분
  • send 2K bytes over 1Gbps network: 5.5 시간
  • read 1MB sequentially from memory: 3 일
  • fetch from new disk location (seek): 13 주
  • read 1MB sequentially from disk: 6.5 달
  • send packet US to Europe and back: 5 년

이렇게 놓고 보면 nanosec으로 보는 것에 비해 시간의 상대적이 길이가 한 눈에 들어옵니다. 뮤텍스 락을 잡고 푸는데 걸리는 시간은 0.5분이고, 미국에서 유럽으로 패킷을 보내고 받는데 걸리는 시간은 무려 5년입니다. 비유를 하자면, 네트워크가 병목인 소프트웨어에서 뮤텍스 락 잡는 시간을 줄이는 최적화를 하는 것은, 유럽 미국 왕복 여행을 하는데 비행기 시간 줄일 생각은 안 하고 아침에 세수하는 시간 줄이는 수준의 일을 하는 것입니다.

최적화 작업을 수행하기 전에는 최적화의 오래된 격언을 항상 상기하시기 바랍니다.

Premature optimization is the root of all evil (섣부른 최적화는 모든 악의 근원이다.)

Advertisements