TL;DR

  • 반복 측정이 필요한 벤치마크에서 코어 고정, 성능 주파수 조정, SMT 비활성화, 터보 비활성화를 순차 적용해 변동계수(CV)를 2.72%에서 0.26%로 낮추고 실행 속도를 1.8배 높임.
  • 벤치마킹용 튜닝은 최고 성능보다 반복 가능한 측정을 우선하며, 프로덕션 서버의 성능 튜닝과 목적이 다름.
  • 짧은 작업과 유휴 간격으로 실제 서비스의 동작을 흉내 낸 배열 합산 벤치마크를 10회 반복해 평균, 표준편차, CV를 비교함.
  • 하드웨어 토폴로지를 확인하면 코어별 성능 차이, 캐시 공유 관계, 입출력 장치와 NUMA 노드 연결을 파악할 수 있음.
  • 주소 공간 배치 난수화(ASLR), NMI 감시 장치, 투명 대형 페이지(THP) 비활성화도 추가로 시험할 수 있으며, 설정은 재부팅 후 유지되지 않음.

측정 잡음이 있는 기준선

  • 코드 최적화는 측정에서 시작되며, 측정 결과가 반복 가능해야 2% 개선을 5% 잡음과 구분할 수 있음.
  • 튜닝하지 않은 기계에서는 같은 바이너리도 실행마다 수 퍼센트 빠르거나 느릴 수 있음. 이 글은 작은 벤치마크를 이용해 변경을 하나씩 적용하고 매번 다시 측정하며 결과의 결정성을 높이는 과정임.
  • 벤치마킹 튜닝은 최고 속도를 일부 포기하더라도 기계의 반복성을 확보하는 방식이며, 프로덕션 서버 튜닝은 최대한의 속도를 추구하는 방식임.
  • 예제는 double 배열의 합을 짧은 구간마다 계산하는 작업임. 실제 서비스처럼 2밀리초 유휴 간격 뒤에 합산 256회를 실행하고, 유휴 간격은 측정 시간에서 제외함.
  • 측정 일시 정지와 재개는 대기 시간을 측정에서 빼며, 결과 최적화 방지는 컴파일러가 계산 루프를 제거하지 못하게 함.
  • 릴리스 빌드에 -O3, -march=native, -mtune=native, -flto, -ffast-math 최적화를 적용하고 10회 반복한 기준선은 평균 99,575나노초, 표준편차 2,704나노초, CV 2.72%임.
  • CV는 표준편차를 평균으로 나눈 변동계수임. 기준선에서는 3%에 가까운 실행 간 잡음 때문에 그보다 작은 최적화 효과를 확인하기 어려움.

하드웨어 구성 파악

  • 설정을 바꾸기 전에 튜닝 대상의 하드웨어 구성을 확인해야 함. lstopo는 캐시, 코어, SMT 쌍, PCIe 장치를 한 화면에 표시함.
  • Intel Core Ultra 5 135U 노트북은 두 개의 P 코어(각각 하드웨어 스레드 2개), 네 개씩 묶여 L2 캐시를 공유하는 E 코어 8개, L3 캐시와 완전히 분리된 저전력 E 코어 2개로 구성됨.
  • 하이브리드 프로세서에서는 코어 선택이 측정 결과에 영향을 줌. CPU 4에서는 낮은 클럭의 E 코어에 배치되고, CPU 12에서는 L3 캐시까지 사용할 수 없음.
  • AMD Ryzen 7 PRO 8700GE 홈랩 서버는 캐시 구성이 동일한 동종 코어 8개로 구성됨. NVMe 드라이브와 네트워크 인터페이스 카드(NIC)는 오른쪽 PCIe에 연결됨.
  • 모든 코어가 동등한 동종 시스템은 벤치마킹에 더 적합함. 입출력을 다루는 벤치마크에서는 PCIe 구성을 통해 어떤 NVMe나 NIC를 사용하는지, 다중 소켓 시스템에서는 장치가 어느 비균일 메모리 접근(NUMA) 노드에 연결됐는지 확인할 수 있음.

코어 하나에 고정

  • 스케줄러는 벤치마크 프로세스를 코어 사이에서 이동시킬 수 있으며, 이동할 때마다 따뜻해진 캐시를 잃음. 하이브리드 CPU에서는 성능 코어와 효율 코어의 처리 속도가 달라 결과가 두 무리로 나뉠 수 있음.
  • 벤치마크를 단일 코어에 고정하며, 하이브리드 프로세서에서는 P 코어를 선택함. 예를 들어 taskset -c 2로 CPU 2에 고정함.
  • 코어 고정 후 평균은 55.3마이크로초, CV는 절반 이하인 1.06%로 감소함.
  • 개선 폭은 코어 이동 비용만으로 설명되지 않음. 각 작업 구간이 같은 코어에서 시작하므로 유휴 간격 동안 코어 클럭이 떨어질 시간이 줄어듦.
  • 코어 고정은 벤치마크를 해당 코어에 배치할 뿐, 다른 작업이 그 코어에서 실행되는 것을 막지는 않음. 부하가 높은 기계에서는 커널 명령행의 isolcpus=2 nohz_full=2 rcu_nocbs=2 설정이나 실행 중 cpuset 제어 그룹으로 코어를 벤치마크 전용으로 예약할 수 있음.

CPU 주파수 고정

  • 기본 설정에서 리눅스는 부하에 따라 CPU 주파수를 조절하므로 벤치마크가 낮고 차가운 클럭으로 시작해 높고 따뜻한 클럭으로 끝날 수 있음.
  • 주파수 조정기를 performance로 변경하면 클럭을 높은 수준으로 유지함. /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor에서 값이 performance인지 확인함.
  • 재측정 결과 평균은 54.9마이크로초, CV는 0.79%임. 코어 고정으로 이미 클럭이 유지돼 추가 개선 폭은 작음.
  • 주파수 조정기만 적용하면 코어 고정 전 기준선 평균 99.6마이크로초가 54.5마이크로초로 낮아짐. 어느 경우든 작업 구간이 차가운 클럭에서 시작하지 않음.

하이퍼스레딩 비활성화

  • CPU는 SMT 형제 스레드와 실행 유닛, L1/L2 캐시를 공유함. 스케줄러가 형제 스레드에 배치하는 다른 작업이 측정을 교란할 수 있음.
  • /sys/devices/system/cpu/smt/control에 off를 기록해 SMT를 비활성화함.
  • CV는 0.26%로 감소해 세 배 더 안정적인 측정이 됨. 해당 코어의 실행 유닛과 캐시를 벤치마크가 단독으로 사용함.

터보 부스트 비활성화

  • 성능 주파수 조정기를 사용해도 터보 주파수는 온도와 전력 예산에 따라 달라짐. 따뜻한 기계에서는 같은 실행도 차가운 기계보다 낮은 클럭으로 동작함.
  • /sys/devices/system/cpu/cpufreq/boost에 0을 기록해 터보를 비활성화함.
  • 이 기계에서는 짧은 작업 구간이 실리콘을 터보 상태로 전환할 만큼 길지 않아 결과 변화가 없음. 터보가 활성화되는 기계에서는 최고 성능을 포기하므로 평균 실행 시간이 늘어날 수 있음.
  • 최적화에서는 상대 수치가 중요하므로 실행 간 비교 가능성이 높아지는 교환이 허용됨. 저지연 프로덕션 튜닝에서는 반대로 터보를 유지하며, 지연 시간에 가장 민감한 일부 트레이딩 업체는 더 나은 냉각을 바탕으로 서버를 오버클럭하고 기본값보다 높은 고정 전체 코어 주파수로 운용함.

요약

  • 각 행은 앞선 변경을 모두 누적한 측정 결과임.
  • 튜닝 전후의 평균, 표준편차, CV는 다음과 같음.
  • 미튜닝: 평균 99.6마이크로초, 표준편차 2.70마이크로초, CV 2.72%.
  • 코어 하나에 고정: 평균 55.3마이크로초, 표준편차 0.59마이크로초, CV 1.06%.
  • 성능 주파수 조정기 적용: 평균 54.9마이크로초, 표준편차 0.43마이크로초, CV 0.79%.
  • 하이퍼스레딩 비활성화: 평균 55.3마이크로초, 표준편차 0.15마이크로초, CV 0.26%.
  • 터보 비활성화: 평균 55.5마이크로초, 표준편차 0.14마이크로초, CV 0.26%.
  • 전체 과정에서 잡음은 거의 3%에서 0.26%로 낮아지고, 실행은 1.8배 빨라짐. 이제 0.5% 차이도 실제 측정 신호로 구분할 수 있음.
  • 부하가 더 많은 기계에서는 주소 공간 배치 난수화(ASLR), NMI 감시 장치, 투명 대형 페이지(THP) 비활성화도 시험할 수 있음. bench-remote.sh 스크립트는 이 설정을 모두 적용함.
  • 설정은 재부팅 후 유지되지 않음. 튜닝과 측정을 마친 뒤 일반적인 기계 상태로 재부팅하는 방식임.