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

> Clean Markdown view of GeekNews topic #25647. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=25647](https://news.hada.io/topic?id=25647)
- GeekNews Markdown: [https://news.hada.io/topic/25647.md](https://news.hada.io/topic/25647.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-01-08T07:32:51+09:00
- Updated: 2026-01-08T07:32:51+09:00
- Original source: [stoppels.ch](https://stoppels.ch/2022/11/27/io-is-no-longer-the-bottleneck.html)
- Points: 2
- Comments: 1

## Topic Body

- 최근 논의된 **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`)에 공개됨

## Comments



### Comment 48845

- Author: neo
- Created: 2026-01-08T07:32:51+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=46506994) 
- 현대 CPU의 **성능 한계**는 단일 코어가 처리할 수 있는 데이터 양, 즉 `memcpy()` 속도에 의해 결정된다고 생각함  
  대부분의 x86 코어는 약 6GB/s, Apple M 시리즈는 약 20GB/s 수준임  
  광고에서 말하는 ‘200GB/s’ 같은 수치는 전체 코어 합산 대역폭일 뿐, 단일 코어는 여전히 6GB/s 근처에 머무름  
  따라서 완벽한 파서를 작성해도 이 한계를 넘을 수 없음  
  하지만 **zero-copy 포맷**을 사용하면 CPU가 불필요한 데이터를 건너뛸 수 있어 이론적으로 6GB/s를 ‘초과’할 수 있음  
  내가 개발 중인 [Lite³ 포맷](https://github.com/fastserial/lite3)은 이 원리를 활용해 simdjson보다 최대 120배 빠른 성능을 보임
  - 제시한 단일 코어 수치는 너무 낮다고 생각함  
    예를 들어 Zen 1은 단일 코어에서 25GB/s를 보여줌([참고 링크](https://stackoverflow.com/a/44948720))  
    내가 작성한 **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](https://stoppels.ch/2022/11/30/io-is-no-longer-the-bottlenec...)
  - 예전에 **단어 빈도수 계산 대회**에 참가한 적이 있음  
    참가자들이 사용한 다양한 최적화 기법을 다룬 [분석 글](https://easyperf.net/blog/2022/05/28/Performance-analysis-and-tuning-contest-6#upd-july-20th-2022-results)이 흥미로움  
    문제의 복잡도나 공백 문자 분류 수에 따라 접근 방식이 달라졌음
  - 만약 이 테스트가 단일 코어에서 수행된 것이라면, 위에서 주장한 “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 성능은 하드디스크의 탐색 시간으로 측정했음  
    순차 읽기 속도는 코드로 개선할 수 없으니, **비순차 접근 최적화**가 핵심이었음
