I/O는 더 이상 병목이 아닌가?

1 month ago 8

  • 최근 논의된 I/O 성능과 CPU 처리 속도의 불균형을 실험으로 검증하며, 실제로는 여전히 CPU가 주요 제약임을 보여줌
  • 순차 읽기 속도는 냉 캐시에서 1.6GB/s, 온 캐시에서 12.8GB/s에 달하지만, 단일 스레드의 단어 빈도 계산은 278MB/s 수준에 머무름
  • 코드의 분기(branch) 구조가 벡터화(vectorization)를 방해하며, 단순한 소문자 변환 최적화로도 330MB/s 정도만 향상됨
  • wc -w 명령어조차 245MB/s에 불과해, 디스크보다 CPU 연산 및 분기 처리가 병목임을 확인
  • AVX2 기반 수동 벡터화로 1.45GB/s까지 끌어올렸지만, 여전히 순차 읽기 속도의 약 11% 수준으로, I/O가 아닌 CPU가 병목임을 입증

I/O 속도와 CPU 성능 비교

  • Ben Hoyt의 주장에 따라, 최근의 순차 읽기 속도 향상이 CPU 속도 정체를 앞질렀는지 실험
    • 동일한 방식으로 측정 시 냉 캐시 1.6GB/s, 온 캐시 12.8GB/s 기록
  • 그러나 단일 스레드에서 단어 빈도 계산을 수행하면 278MB/s에 불과
    • 이는 캐시가 따뜻한 상태에서도 디스크 읽기 속도의 약 1/5 수준

C 기반 단어 빈도 계산 실험

  • GCC 12로 optimized.c를 -O3 -march=native 옵션으로 컴파일 후 425MB 입력 파일에서 실행
    • 결과: 1.525초 소요, 278MB/s 처리 속도
  • 코드 내 다중 분기와 조기 종료가 컴파일러의 벡터화 최적화를 방해
    • 소문자 변환 로직을 루프 외부로 이동한 후 330MB/s로 향상
    • Clang 사용 시 벡터화가 더 잘 수행됨

단순 단어 세기(wc -w) 비교

  • 빈도 계산 대신 단순 단어 수만 세는 wc -w 명령어 실행
    • 결과: 245.2MB/s, 예상보다 느림
  • wc는 ' ', '\n', '\t' 등 다양한 공백 문자와 로케일 문자를 처리
    • 단순 공백만 구분하는 코드보다 연산량이 많음

AVX2 기반 벡터화 시도

  • 최신 CPU 기능을 활용해 AVX2 명령어 집합으로 벡터화 구현
    • 256비트 레지스터 사용, 데이터 32비트 정렬
    • 공백 문자 비교를 위해 VPCMPEQB 명령어 사용
  • 비트 마스크(PMOVMSKB)Find First Set(ffs) 명령어로 단어 경계 탐지
    • Cosmopolitan libc의 strlen 구현에서 착안

성능 결과 및 결론

  • 수동 벡터화 코드(wc-avx2)는 1.45GB/s 처리 속도 달성
    • wc -w와 동일한 결과(82,113,300 단어) 검증
  • 냉 캐시 상태에서도 여전히 user 모드 연산 시간이 지배적
    • 디스크 I/O보다 CPU 연산이 병목임을 확인
  • 전체적으로 디스크 속도는 충분히 빠르지만, 분기 처리와 해시 계산 등 CPU 연산이 한계 요인으로 남음
  • 코드와 실험 결과는 GitHub(haampie/wc-avx2)에 공개됨

Read Entire Article