Hacker News 의견들
  • 현대 CPU의 성능 한계는 단일 코어가 처리할 수 있는 데이터 양, 즉 memcpy() 속도에 의해 결정된다고 생각함
    대부분의 x86 코어는 약 6GB/s, Apple M 시리즈는 약 20GB/s 수준임
    광고에서 말하는 ‘200GB/s’ 같은 수치는 전체 코어 합산 대역폭일 뿐, 단일 코어는 여전히 6GB/s 근처에 머무름
    따라서 완벽한 파서를 작성해도 이 한계를 넘을 수 없음
    하지만 zero-copy 포맷을 사용하면 CPU가 불필요한 데이터를 건너뛸 수 있어 이론적으로 6GB/s를 ‘초과’할 수 있음
    내가 개발 중인 Lite³ 포맷은 이 원리를 활용해 simdjson보다 최대 120배 빠른 성능을 보임

    • 제시한 단일 코어 수치는 너무 낮다고 생각함
      예를 들어 Zen 1은 단일 코어에서 25GB/s를 보여줌(참고 링크)
      내가 작성한 microbenchmark 결과에 따르면 Zen 2는 AVX 비사용 시 17GB/s, non-temporal AVX 사용 시 35GB/s까지 나옴
      Apple M3 Max에서는 non-temporal NEON으로 125GB/s까지 측정됨
      따라서 x86 6GB/s, Apple 20GB/s라는 수치는 실제보다 훨씬 낮음
    • 이 한계가 어디서 오는지 궁금함 — 코어와 캐시, 혹은 메모리 컨트롤러 사이의 버스 구조 때문인지 질문함
    • 왜 Apple M 시리즈가 x86보다 코어당 3배 높은 대역폭을 가지는지 궁금함
    • 최신 칩에서는 CPU만으로는 메모리 대역폭을 포화시키기 어렵고, iGPU를 활용해야 가능함
      iGPU가 통합 메모리에 접근할 수 있기 때문임
      따라서 대용량 메모리 복사나 병렬 파싱, 압축/해제 같은 작업은 iGPU를 blitter로 활용하는 것이 기술적으로 유리함
      다만 zero-copy 포맷에서 말하는 ‘건너뛰기’는 캐시라인 단위로 이루어짐
    • 삼성 NVMe SSD가 14GB/s 읽기 속도를 광고하는데, CPU 단일 코어가 6GB/s라면 이 수치와의 관계가 흥미로움
  • 원글 작성자가 time 명령어의 출력을 잘못 해석한 것 같음
    system 시간은 커널이 프로세스를 대신해 사용한 CPU 시간임
    예시에서 real 0.395s, user 0.196s, sys 0.117s라면 CPU는 총 313ms 동안만 일했고, 나머지 82ms는 유휴 상태였음
    즉, 디스크 서브시스템보다 빠르게 동작하긴 했지만 차이는 크지 않음
    또한 I/O 경로가 CPU 바운드 상태임 — 디스크와 코드가 무한히 빠르더라도 커널 I/O 코드 실행에 117ms가 필요함

  • 글 작성자임. 후속편이 있음: I/O is no longer the bottleneck, part 2

    • 예전에 단어 빈도수 계산 대회에 참가한 적이 있음
      참가자들이 사용한 다양한 최적화 기법을 다룬 분석 글이 흥미로움
      문제의 복잡도나 공백 문자 분류 수에 따라 접근 방식이 달라졌음
    • 만약 이 테스트가 단일 코어에서 수행된 것이라면, 위에서 주장한 “6GB/s 한계”는 실험적으로 반박된 셈임
  • 성능 병목은 항상 “CPU냐 I/O냐” 같은 단일 요인이 아니라, 실제 워크로드에서 가장 먼저 포화되는 자원
    CPU, 메모리 대역폭, 캐시, 디스크, 네트워크, 락, 지연 등 중 어느 것이든 될 수 있음
    따라서 측정하고, 프로파일링으로 증명하고, 변경 후 다시 측정해야 함

  • 문제는 CPU나 I/O가 아니라 지연(latency)처리량(throughput) 의 균형임
    대부분의 소프트웨어는 지연을 무시해서 느림
    데이터를 메모리에 선형적으로 배치하거나, 배치 처리와 병렬화를 적용하면 훨씬 빨라짐

  • CPU ↔ 캐시 ↔ 비휘발성 스토리지 구조만으로 구성된 아키텍처를 상상해봄
    mmap()malloc()과 동일한 성능 특성을 가진다면, 프로그램 메모리를 파일 이름으로 지정해 OS에 영속성을 맡길 수도 있을 것임
    여전히 많은 소프트웨어 설계가 하드디스크 시대의 제약에 묶여 있음

    • 하지만 fsync()는 여전히 느림
      진짜 영속성을 위해서는 회전 디스크 여부와 관계없이 다른 접근이 필요함
    • 리눅스에서도 비슷한 걸 구현할 수 있음
      실제로 대부분의 메모리 요청은 mmap()을 통해 이루어짐
      다만 커널이 접근 패턴을 예측하기 어려워 read/write보다 느릴 수 있음
  • 클라우드 환경에서는 성능이 요금제 조정 수단이 되기도 함
    하드웨어 성능은 놀라울 정도로 발전했지만, 일부 소프트웨어(특히 Windows나 메신저 앱)는 오히려 더 느리게 느껴짐

    • 실제로 클라우드 인스턴스 성능은 M1 MacBook보다 5배 느리면서도 훨씬 비쌈
      개발자 원격 워크스테이션으로는 비효율적임
    • 대부분의 GUI 앱이 느린 이유는 여전히 I/O 대기 때문임
      Telegram이나 FB Messenger는 빠르지만 Teams나 Skype는 그렇지 않음
    • CRT 모니터는 데이터를 더 빨리 표시했음
      일부 LCD는 500ms 지연이 있음
  • NVMe SSD가 처음 나왔을 때 “이제 2TB RAM을 가진 셈”이라고 농담했음
    그런데 요즘 GPU 서버는 실제로 2TB RAM을 탑재함 — 놀라운 엔지니어링임

    • 예전에 중고 Epyc 서버에서 2TB DDR4 RAM 구성을 5천 달러에 본 적 있음
      그때 사둘 걸 아쉬워함
  • OLAP 데이터베이스를 고도 동시성 환경에서 최적화한 경험상, 병목은 대부분 메모리 속도였음

  • I/O 병목은 원래 순차 읽기가 아니라 탐색(seek) 시간과 관련된 개념이었음
    글의 요지는 이해하지만, 이 점은 짚고 싶음

    • CXL/PCIe 같은 최신 기술 덕분에 이제 RAM과 메모리 컨트롤러도 일종의 I/O 장치로 간주할 수 있음
    • 예전 데이터베이스 수업에서 I/O 성능은 하드디스크의 탐색 시간으로 측정했음
      순차 읽기 속도는 코드로 개선할 수 없으니, 비순차 접근 최적화가 핵심이었음