Split View: 컴퓨터 아키텍처의 현대 — CPU 파이프라인·Out-of-Order·캐시·브랜치 예측·Meltdown·Apple Silicon·ARM·RISC-V·SIMD·GPU 심층 가이드 (2025)
컴퓨터 아키텍처의 현대 — CPU 파이프라인·Out-of-Order·캐시·브랜치 예측·Meltdown·Apple Silicon·ARM·RISC-V·SIMD·GPU 심층 가이드 (2025)
왜 2025년의 백엔드 엔지니어가 CPU 내부를 알아야 하는가
Rust를 썼는데 왜 C보다 느릴 때가 있는가. HashMap을 쓰는데 왜 Vec<(K,V)> 선형 탐색이 더 빠른 순간이 있는가. if 하나가 왜 10배 느려지는가. 왜 M1이 같은 세대 Intel을 이겼는가. 정답은 모두 CPU 내부에서 일어나는 일을 이해하면 자명하다. 소프트웨어는 결국 하드웨어 위에서 돈다. CPU는 우리가 a + b라고 쓴 코드를 그 순서대로 실행하지 않는다. 파이프라인, 캐시, 브랜치 예측자, 메모리 컨트롤러가 보이지 않게 개입한다. 이 글은 그 내부를 연다.
2018년 Meltdown/Spectre 이후 "CPU는 더 이상 블랙박스가 아니다"가 업계 상식이 됐다. Apple Silicon M1(2020)은 "RISC ARM이 x86을 정확히 이길 수 있음"을 증명했고, AWS Graviton4·NVIDIA Grace·Ampere Altra는 클라우드 비용 30% 절감을 현실로 만들었다. RISC-V는 Western Digital·SiFive·Tenstorrent·Meta가 실리콘을 굽는 단계다. GPU는 H100/H200을 넘어 B100/B200 Blackwell(2024)·GB300(2025)이 LLM 경제를 지배한다. 모든 소프트웨어 엔지니어가 이 흐름을 피할 방법이 이제는 없다.
이 글은 앞서 쓴 Rust 심층 가이드와 연결된다. Rust가 zero-cost abstraction을 선언할 수 있는 이유는 결국 CPU 친화적 코드로 컴파일되기 때문이고, 그 "CPU 친화"의 정체를 이 글에서 해부한다.
1부. 트랜지스터에서 명령어까지 — 당신의 if 문이 진짜로 하는 일
1.1 폰 노이만에서 현대 CPU까지의 30초
1945년 폰 노이만이 제안한 구조는 지금도 논리적으로 바뀌지 않았다. 메모리에 코드와 데이터가 같이 있고, CPU가 순차적으로 읽어 실행한다. 하지만 물리적으로는 상전벽해가 일어났다.
- 1971 Intel 4004 — 4-bit, 2,300 트랜지스터, 740kHz
- 1985 Intel 386 — 32-bit, 275K 트랜지스터, 16MHz
- 1993 Pentium — 슈퍼스칼라(한 사이클에 2개 명령), 파이프라인 5단계
- 1995 Pentium Pro — Out-of-Order, 투기 실행, 레지스터 리네이밍
- 2006 Core 2 — Intel이 power wall에 부딪혀 "클럭 대신 병렬로"
- 2011 Sandy Bridge — 통합 메모리 컨트롤러·AVX
- 2020 Apple M1 — 5nm, 16B 트랜지스터, 통합 메모리(UMA), 뛰어난 IPC
- 2024 Intel Lunar Lake / AMD Zen 5 / Apple M4 — Performance-core + Efficiency-core 혼합
한 칩 안에 200억 개 넘는 트랜지스터가 들어가지만, 우리가 짜는 코드는 여전히 a + b다. 그 간극을 메우는 게 현대 CPU의 설계다.
1.2 명령어가 실행되는 5단계(사실은 20단계)
교과서가 말하는 RISC 파이프라인 5단계.
- Fetch — 메모리에서 명령어 읽기
- Decode — 무엇을 하라는 건지 해석
- Execute — 실제 연산
- Memory Access — 필요하면 메모리 read/write
- Write Back — 결과를 레지스터에 저장
현대 x86 (Golden Cove, Zen 4)은 이것이 14~20 단계로 더 잘게 쪼개져 있다. 그래야 각 단계가 더 빨리 끝나고 클럭을 더 높일 수 있다. 단, 파이프라인이 길어질수록 브랜치 예측 실패 비용이 커진다.
1.3 슈퍼스칼라 — 한 사이클에 4~8개 명령
단일 명령 파이프라인은 1990년대에 끝났다. 지금은 한 클럭 사이클에 여러 명령을 동시에 issue한다.
- Apple M3/M4 P-core: 10-wide decode, 9-wide issue
- Intel Golden Cove: 6-wide decode, 5-wide issue
- AMD Zen 5: 8-wide decode, 6-wide issue
이게 왜 중요한가? 당신이 짠 C/Rust 코드의 IPC(Instructions Per Cycle)가 3~4에 달하면, CPU가 병렬로 여러 연산을 굴리고 있다는 뜻이다. 반대로 IPC가 0.5라면, 뭔가 파이프라인을 죽이고 있다(브랜치 미스, 캐시 미스, 의존성 체인).
2부. Out-of-Order 실행 — CPU는 당신 코드를 재정렬한다
2.1 왜 재정렬하는가
int a = load_from_memory(&x); // 100 사이클 걸리는 미스
int b = 2 + 2; // 1 사이클
In-order CPU는 첫째 줄이 끝날 때까지 b를 시작 못한다. Out-of-Order CPU는 b를 먼저 실행하고 a가 도착하면 그제서야 합친다. 명령어 사이에 의존성이 없으면 순서 상관없이 실행한다.
2.2 ROB, RS, Register Renaming
- ROB (Re-Order Buffer) — 실행은 out-of-order, commit은 in-order로 보장
- RS (Reservation Station) — 피연산자가 준비되면 바로 실행 유닛으로 발사
- Register Renaming — 아키텍처 레지스터(16개) → 물리 레지스터(수백 개) 매핑
"코드상의 RAX가 실제로는 192개 물리 레지스터 중 하나"로 매핑되기 때문에, false dependency가 제거된다. Apple M3의 ROB는 약 700 entries, Zen 5는 약 480. 이 숫자가 클수록 더 멀리 보고 재정렬할 수 있다.
2.3 Speculative Execution — 미래를 먼저 살아본다
분기 예측 → 둘 중 하나를 가정하고 실행 → 맞으면 이익, 틀리면 롤백. 이걸 잘못 설계한 결과가 2018년 Spectre/Meltdown이다(4부에서 다룸).
3부. 캐시 계층 — 왜 배열이 linked list를 이기는가
3.1 메모리 계층의 현실
2025년 기준 대략적 수치(x86 P-core, 빠를수록 위).
| 계층 | 용량 | 레이턴시 | 처리량 |
|---|---|---|---|
| 레지스터 | ~400 | 0 사이클 | per-op |
| L1d | 48~80KB | 4~5 사이클 | 3~4 load/cycle |
| L2 | 2~3MB | 12~15 사이클 | 1 load/cycle |
| L3 | 32~96MB | 40~50 사이클 | shared |
| DRAM | 32~512GB | 200~300 사이클 | 50~100 GB/s |
| NVMe | TB급 | 10~100μs | 7~14 GB/s |
| 네트워크 | ∞ | 100μs~ | 10~100 Gb/s |
레지스터와 DRAM 사이에 약 100배 차이가 있다. 캐시는 이 간극을 메우는 장치다.
3.2 Cache Line — 캐시의 최소 단위는 64바이트
CPU는 1바이트만 읽어도 64바이트(Apple Silicon은 128바이트)를 통째로 가져온다. 이것이 "배열이 linked list를 이기는 가장 큰 이유".
- 배열
int[1000]을 순회 → 첫 접근에서 16 int 한꺼번에 로드, 이후 15개는 캐시 히트 - linked list → 각 노드가 메모리 여기저기 흩어져서 매번 캐시 미스
한 요소 100 사이클 vs 5 사이클, 즉 20배 차이.
3.3 Prefetch — CPU가 미래를 준비한다
하드웨어 프리페처는 접근 패턴을 감지해서 미리 L1/L2로 당겨놓는다. 선형 스트라이드(a[0], a[1], a[2]...)는 완벽히 감지되고, 복잡한 포인터 체이싱은 실패한다. 소프트웨어적으로는 __builtin_prefetch(ptr) (GCC/Clang)로 힌트를 줄 수 있다.
3.4 False Sharing — 64바이트 안의 지옥
두 스레드가 같은 캐시 라인의 서로 다른 변수를 쓰면, 하드웨어 코히런시 프로토콜(MESI)이 라인 전체를 핑퐁한다. 성능이 10배 추락하는 가장 흔한 사인이다.
#[repr(align(64))]
struct PaddedCounter(AtomicU64);
이렇게 64바이트 정렬로 분리하면 사라진다.
3.5 Data-Oriented Design — 게임 엔진이 발견한 진실
OOP가 만든 Entity { name, pos, vel, hp, ... }는 캐시 입장에서 악몽이다. 실제로 update_positions를 돌릴 때 필요한 건 pos와 vel뿐인데, name과 hp가 캐시 라인을 오염시킨다. ECS(Entity-Component-System)와 SoA(Struct-of-Arrays)는 이 문제를 구조적으로 해결한다.
// AoS: Entity entities[N] → 캐시 낭비
// SoA: float xs[N], ys[N], vxs[N], vys[N] → 순수 적재
Unity DOTS, Unreal Mass Entity, Bevy ECS가 이 설계를 밀고 있다.
4부. 브랜치 예측 — 분기가 10배 느려지는 순간
4.1 왜 예측이 필요한가
파이프라인 15단계라면, if 분기를 만난 순간 "어느 쪽으로 갈지 모름"이다. CPU는 멈추는 대신 한쪽을 찍고 계속 간다. 맞으면 손해 없음, 틀리면 15 사이클 낭비.
4.2 2-bit 포화 카운터에서 TAGE까지
- 1-bit: 마지막 결과만 기억 → 정확도 60%
- 2-bit 포화: 맞을수록 확신 누적 → 90%
- Perceptron (AMD 2008~): 신경망 기반 → 95%+
- TAGE (Intel/Apple 2010s~): 다양한 히스토리 길이로 태깅 → 97~99%
Stack Overflow의 유명한 질문 "왜 정렬된 배열이 정렬 안 된 배열보다 빠른가"의 답이 이것이다. 정렬된 배열은 if 분기 패턴이 예측 가능해서 예측 정확도가 100%에 가깝고, 랜덤 배열은 50%다.
4.3 Branchless 프로그래밍
핫 루프에서 분기를 제거하면 예측 실패 비용이 0이 된다.
// branch
int max = a > b ? a : b;
// branchless (CMOV)
int max = b ^ ((a ^ b) & -(a > b));
Rust/LLVM은 단순한 삼항 연산자라면 cmov로 자동 컴파일한다. 복잡해지면 SIMD로 전체 분기 자체를 벡터화한다.
5부. 2018년 이후 — Meltdown, Spectre, MDS, Zenbleed
5.1 Meltdown (Intel)
유저 모드에서 커널 메모리를 투기적으로 읽고 → 캐시 상태 차이로 값을 유추. Intel CPU가 권한 체크보다 먼저 데이터를 로드하는 버그. KPTI(Kernel Page Table Isolation) 패치로 5~30% 성능 하락.
5.2 Spectre v1/v2
브랜치 예측을 공격자가 조작 → 희생자 프로세스의 메모리를 캐시 사이드 채널로 추출. 하드웨어 설계 자체의 결함이라 "완전 해결 불가", mitigation만 누적되는 중(IBRS, STIBP, retpoline).
5.3 MDS, L1TF, ZombieLoad, Zenbleed
2019~2023년에 드러난 variant들. 하이퍼스레딩(SMT)을 끄는 클라우드 프로바이더가 생겼을 정도. AWS Nitro, Google Titan, Azure Pluton은 이 위협 모델에 맞춰 설계된 전용 보안 칩.
5.4 Post-Quantum 시대 보안 칩
Apple Secure Enclave, Intel SGX/TDX, AMD SEV-SNP, ARM CCA는 CPU 내부에 격리된 실행 환경을 만들어 커널조차 못 보게 한다. Confidential Computing(4부 포스트 시리즈 대형 테마)의 하드웨어 기반.
6부. Apple Silicon — M1은 왜 Intel을 이겼나
6.1 설계 비결 5가지
- wide decode (10-wide vs Intel 6-wide) — x86은 가변 길이 명령어 때문에 디코더 병렬화가 어렵지만 ARM은 고정 32-bit라 쉽다
- Unified Memory Architecture (UMA) — CPU·GPU·NPU가 같은 LPDDR에 접근, 복사 비용 0
- 거대한 ROB + 많은 물리 레지스터 — out-of-order 윈도우가 Intel 대비 2배
- SoC 수준 통합 — 메모리 컨트롤러·Thunderbolt·NVMe·Display가 한 다이, 레이턴시 붕괴
- TSMC 5nm/3nm 선공정 — 동일 전력에서 20~30% 앞서 시작
6.2 P-core / E-core 하이브리드
M-시리즈는 고성능 코어와 고효율 코어를 섞어 둔다. 백그라운드 작업(Spotlight 인덱싱, 메일 체크)은 E-core에 내려 배터리를 지키고, 포그라운드 연산만 P-core에 올린다. 윈도우/리눅스에서 이 스케줄링이 복잡한 이유는 OS가 워크로드 성격을 추론해야 하기 때문(Intel의 Thread Director가 도움).
6.3 Graviton/Ampere — 클라우드가 ARM으로 이동 중
AWS Graviton3/4는 동일 성능에서 30~40% 저렴하다. Netflix·Snap·Airbnb가 대규모 전환. Cloudflare Workers가 ARM 우선. 이유는 단순하다 — 와트 당 성능(performance per watt)이 절대적으로 앞선다.
7부. x86 vs ARM vs RISC-V — 2025년의 지형
7.1 x86이 남은 이유
- 레거시 호환성 (Windows/Linux/Steam 게임 전체)
- AVX-512, VNNI 같은 성숙한 SIMD
- 서버 데이터센터의 관성
하지만 전성비 싸움에서 ARM에게 밀리는 중. Intel은 Lunar Lake(2024)부터 메모리를 온패키지로 올리는 등 Apple 방식을 모방.
7.2 ARM이 이기는 전선
- 모바일 (이건 이미 100% ARM)
- 클라우드 (Graviton/Ampere가 30% 이상)
- Mac (100% ARM)
- Windows on ARM (Qualcomm Snapdragon X, 2024)
7.3 RISC-V — 오픈 ISA의 반란
- 장점: 로열티 프리, 모듈러 확장 (RV32I, RV64I, +M/A/F/D/V)
- 2024~2025 실리콘: SiFive P870, Tenstorrent Ascalon, Meta MTIA, 중국 XuanTie
- 단점: 생태계/소프트웨어 성숙도 아직 부족, 벡터 확장 파편화
관건은 RVA23 프로파일 표준화. Linux 커널은 이미 완벽히 지원.
8부. SIMD — 벡터 명령으로 8배 빠르게
8.1 왜 SIMD가 필요한가
스칼라 CPU는 한 번에 한 값. SIMD는 한 명령어로 여러 값을 동시에 처리(Single Instruction, Multiple Data).
- SSE (1999~): 128-bit, float 4개 동시
- AVX/AVX2 (2011~): 256-bit, float 8개 동시
- AVX-512 (2017~): 512-bit, float 16개 동시 (Intel 서버·일부 데스크탑, AMD Zen 4+)
- ARM NEON (2004~): 128-bit 표준
- SVE/SVE2 (2016~): 가변 길이 벡터 (128~2048-bit), Apple M4·Graviton3에 채택
- RISC-V V (2021~): SVE 유사, 가변 길이
8.2 자동 벡터화와 수동
LLVM/GCC는 단순 루프를 자동 벡터화한다. 하지만 의존성이 있거나 분기가 섞이면 실패. 성능이 절실하면 intrinsics 또는 std::simd(Rust portable SIMD, 2024 nightly), std::experimental::simd(C++)를 쓴다.
use std::simd::f32x8;
let a = f32x8::from_array([1.0; 8]);
let b = f32x8::from_array([2.0; 8]);
let c = a + b; // 한 명령어로 8개 덧셈
8.3 실전 사례
- simdjson: JSON 파싱 1
3 GB/s (스칼라 대비 410배) - ClickHouse: 집계 쿼리 SIMD 극한 튜닝
- WebP/AVIF 디코딩
- LLM inference의 Q4/Q8 양자화 연산
- Ripgrep의 문자열 검색(memchr 크레이트)
9부. GPU 아키텍처 — CUDA 코어, SM, Warp
9.1 CPU와 GPU의 철학 차이
- CPU: 깊은 파이프라인, 복잡한 예측, 소수 스레드, 레이턴시 최소화
- GPU: 얕은 파이프라인, 수만 스레드, 스루풋 최대화
GPU는 캐시 미스가 나면 다른 스레드로 스위칭한다. 즉 레이턴시를 숨긴다. CPU는 캐시 미스가 나면 기다릴 뿐이다.
9.2 H100/B200/GB300 내부 구조
- SM (Streaming Multiprocessor): GPU의 "코어 묶음", H100은 132개, B200은 208개
- CUDA Core: SM 안의 스칼라 ALU, SM 당 128개
- Tensor Core: 4x4 matrix multiply per cycle, LLM의 핵심 엔진
- Warp: 32 스레드 묶음이 SIMT(Single Instruction, Multiple Threads)로 함께 실행
- Shared Memory: SM 당 ~228KB, 수동 관리 캐시
- HBM3e (B200): 192GB, 8TB/s 대역폭
9.3 Warp Divergence — GPU의 브랜치 비용
같은 warp의 32 스레드가 서로 다른 분기를 타면 양쪽을 모두 실행한 뒤 마스크로 버린다. 즉 분기 비용이 극악. LLM 커널들이 branchless로 짜여진 이유.
9.4 LLM inference의 병목
- Prefill: compute-bound, 텐서 코어 100% 활용
- Decode: memory-bound, KV 캐시 읽기가 병목 → 플래시어텐션, 페이지드어텐션, continuous batching
- Blackwell B200의 FP4 (2024): 메모리 대역폭 2배 효과
9.5 ROCm·Apple MLX·Metal — NVIDIA 외 생태계
- AMD ROCm은 HIP로 CUDA 코드 포팅 가능, MI300X(HBM3 192GB)가 H100 대안
- Apple Metal + MLX: M-시리즈에서 LLM 로컬 실행, UMA 덕분에 모델 로딩 즉시
- Intel Arc/Gaudi: OneAPI/SYCL, Gaudi3는 추론 가성비 목표
10부. 메모리의 법칙 — DRAM, HBM, CXL, NVLink
10.1 DDR5 · LPDDR5X · HBM3e
- DDR5 (데스크탑/서버): 최대 8400 MT/s, 2채널 ~90 GB/s
- LPDDR5X (모바일·Apple·Qualcomm): 8533 MT/s, 저전력
- HBM3e (GPU): 3D 적층, 8TB/s per GPU, B200에서 필수
10.2 NUMA의 함정
소켓이 2개 있는 서버에서 다른 소켓 메모리 접근은 2~3배 느리다. Linux numactl, mbind 등으로 조정. 쿠버네티스 Topology Manager가 이걸 인지.
10.3 CXL (Compute Express Link)
2024년부터 현실화된 표준.
- CXL.cache: CPU가 원격 메모리를 캐시 가능
- CXL.mem: 메모리 풀링·디스아그리게이션
- CXL.io: PCIe 호환
의미: "서버 안의 RAM이 공유 자원"이 된다. 메모리 과프로비저닝을 전체 랙 단위로 해결.
10.4 NVLink / NVSwitch
GPU 간 직결. H100 NVLink 900 GB/s, B200 1.8 TB/s. 대규모 LLM 학습에서 병렬 전략(TP/PP/EP)이 가능한 하드웨어 기반.
11부. 전력·열·양자 — 왜 클럭이 더 이상 안 오르는가
11.1 Power Wall과 Dennard Scaling의 종말
2006년쯤 Dennard Scaling(트랜지스터 작아질수록 전력도 비례해 감소)이 멈췄다. 그 뒤로 클럭은 3~5GHz에서 고착. 해결책은 병렬화(코어 늘리기)와 특화(NPU, Tensor Core).
11.2 다크 실리콘
200억 트랜지스터가 있어도 전력 예산상 동시에 켜는 건 일부뿐. 그래서 용도별 전용 블록(AMX, NPU, 미디어 엔진)을 박아 꺼 놨다가 필요할 때만 킨다.
11.3 3D 패키징
TSMC CoWoS, Intel Foveros — 로직과 메모리를 수직 적층해 레이턴시/대역폭 폭발. B200, MI300X 모두 3D 어셈블리.
11.4 양자 컴퓨팅 — 2025년 현실
IBM Osprey(433 qubit), Google Willow(2024, 105 qubit + 오류 보정 돌파), Atom Computing 1000 qubit neutral atom. "암호 깨기까지 아직 멀었지만 최적화/화학 문제에서 유용성 보임" 단계. 소프트웨어 엔지니어에게 당장의 영향은 post-quantum crypto(Kyber, Dilithium) 준비.
12부. 이 모든 걸 성능에 어떻게 꿰는가 — 측정·프로파일·튜닝
12.1 Linux perf
perf stat -d ./myapp
# instructions, cycles, IPC, cache-misses, branch-misses
perf record -g ./myapp && perf report
- IPC < 1 → 미스 많음
- branch-miss > 2% → 예측 실패
- LLC-load-miss > 10% → 캐시 설계 실패
12.2 Intel VTune, AMD uProf, Apple Instruments
Top-Down 분석법: Retiring / Bad Speculation / Frontend Bound / Backend Bound. 네 버킷 중 어디에 병목이 있는지 1분에 판단.
12.3 마이크로벤치의 함정
std::chrono로 100만 번 돌려 평균? 컴파일러가 loop-invariant로 판단해 코드 자체를 날려버린다. black_box (Rust), benchmark::DoNotOptimize (Google Benchmark)로 방지.
12.4 성능 작업 체크리스트
- 먼저 측정 → 추측 금지
- 알고리즘 → O(n²) → O(n log n)가 마이크로튜닝보다 항상 선행
- 데이터 레이아웃(SoA/AoS) 확인
- 할당 횟수 — Rust
alloc훅, jemalloc stats - Lock contention —
perf lock,perf trace - SIMD 기회 — 자동 벡터화 로그(
-Rpass=loop-vectorize)
13부. 실전 — 왜 같은 언어에서 같은 알고리즘인데 10배 차이나는가
13.1 사례 1: 해시맵 선형 프로빙 vs chaining
std::unordered_map 같은 chaining은 캐시 미스의 온상. **오픈 어드레싱(linear probing)**이 현대 CPU에서 2~5배 빠르다. Rust의 hashbrown(std HashMap 기반, Google SwissTable 포팅)이 대표 사례.
13.2 사례 2: JSON 파서가 1 GB/s가 가능한 이유
simdjson은 AVX-512/ARM NEON으로 한 번에 64바이트를 스캔해 구조를 파악하고, 두 번째 패스에서 파싱. 전통적 파서 대비 10배 이상.
13.3 사례 3: Redis vs KeyDB vs Dragonfly
Redis는 싱글 스레드. KeyDB/Dragonfly는 io_uring + shared-nothing으로 코어 당 선형 확장. 10~25배 스루풋 차이를 같은 하드웨어에서 낸다.
13.4 사례 4: LLM 추론 — TensorRT-LLM vs vLLM vs SGLang
- 같은 모델, 같은 GPU에서 처리량 3~8배 차이
- 이유: KV 캐시 관리, continuous batching, paged attention, CUDA graph, FP8/FP4 양자화
- "모델을 바꾼 효과"와 "런타임을 바꾼 효과"가 비슷
14부. 하드웨어 변화가 소프트웨어 설계에 미치는 영향
14.1 NVMe + io_uring = 파일 I/O의 부활
디스크가 빨라지면서 블로킹 I/O 오버헤드가 병목. 비동기 I/O가 필수(앞선 OS 글 참고).
14.2 100 Gb/s NIC + RDMA + DPDK
네트워크가 PCIe보다 빨라지는 시대. 커널 바이패스(DPDK), RDMA(RoCEv2) 없이는 성능을 못 낸다. Cloudflare, Meta, Stripe의 엣지가 이 기술로 돌아감.
14.3 DPU/IPU
NVIDIA BlueField, Intel IPU, AWS Nitro — 네트워크/스토리지/보안을 CPU에서 분리한 전용 프로세서. 2025년 데이터센터 표준 디자인.
14.4 AI 가속기 춘추전국
NVIDIA B200/GB300, AMD MI350X, Google TPU v5p/v6, AWS Trainium2/Inferentia3, Cerebras WSE-3, Groq LPU, Tenstorrent. 각자 "한 분야에서 NVIDIA를 이긴다"가 목표.
15부. 체크리스트 12 · 안티패턴 10
✅ 체크리스트 12
- 핫 경로의 데이터 구조가 캐시 친화적인가? (배열 > linked list)
- Struct 레이아웃이 64바이트 정렬·패딩을 고려했는가?
- 멀티스레드 공유 데이터에 false sharing은 없는가?
- 핫 루프의 분기 예측률을 perf로 확인했는가?
- IPC가 1 미만이면 왜인지(캐시? 분기? 의존성?) 조사했는가?
- SIMD 기회가 있는 루프에 자동 벡터화가 성공했는가?
- NUMA 시스템이라면 numactl/topology manager로 로컬 메모리 고정했는가?
- 가상화/클라우드 vCPU의 SMT 노이즈 이웃 영향을 측정했는가?
- GPU 워크로드의 Warp divergence를 측정했는가?
- 메모리 할당을 arena/slab으로 묶어 fragmentation을 줄였는가?
- post-quantum crypto 전환 로드맵이 있는가? (2030 타임라인)
- ARM64 빌드(CI/CD)와 벤치가 준비됐는가?
⚠️ 안티패턴 10
- 벤치 없이 "Rust는 빠르다"라는 믿음으로 결정
- OOP AoS만 쓰고 SoA 고려 안 함
- 핫 루프에
HashMap남발 - 아토믹 카운터 하나에 모든 스레드 경합
- 가상 스레드·async가 CPU-bound 문제를 해결한다고 생각
- x86에서 튜닝하고 ARM을 테스트 안 함
- GPU 코드에서 if-else로 warp divergence 유발
memcpy최적화에 시간 쓰고 알고리즘을 방치- KVM/VM 내부 벤치를 베어메탈처럼 신뢰
- Meltdown/Spectre mitigation을 성능 때문에 전면 해제
다음 글 예고 — "관측가능성의 현대" — OpenTelemetry·eBPF continuous profiling·Grafana LGTM·Pyroscope·Sentry Performance·Datadog·Honeycomb·SLO·SRE·온콜
CPU를 배웠으니 "그 CPU 위에서 뭐가 일어나는지 실시간으로 보는 법"이 필요하다. 다음 글은 2025년의 관측가능성을 파낸다.
- 메트릭 × 로그 × 트레이스 × 프로파일 — Four Pillars로 승격
- OpenTelemetry가 사실상 표준이 되는 과정
- eBPF continuous profiling — Parca, Pyroscope, Grafana Pyroscope, Polar Signals
- 분산 트레이싱 — sampling 전략, tail-based, head-based
- LGTM 스택 — Loki/Grafana/Tempo/Mimir
- Sentry Performance, Datadog APM, Honeycomb 비교
- SLO/SLI/Error Budget — SRE 책 이후 10년의 진화
- AI 기반 이상 탐지 — Datadog Watchdog, Grafana Oncall AI
- 온콜 운영 — 로테이션, 포스트모템, 블레임리스 컬처
하드웨어에서 소프트웨어로, 소프트웨어에서 운영으로 — 스택의 다음 층으로 올라간다.
Modern Computer Architecture — CPU Pipelines, Out-of-Order, Caches, Branch Prediction, Meltdown, Apple Silicon, ARM, RISC-V, SIMD, GPU Deep Dive (2025)
Why a 2026 Backend Engineer Must Know CPU Internals
You wrote Rust but it was sometimes slower than C. You reached for HashMap but a linear scan over Vec<(K,V)> was faster. A single if made your code 10x slower. M1 outran same-generation Intel. All those answers become obvious once you understand what happens inside the CPU. Software runs on hardware. The CPU does not execute a + b in the order you wrote it — pipelines, caches, branch predictors, and memory controllers silently intervene. This post opens that box.
Since Meltdown/Spectre (2018), "the CPU is no longer a black box" is industry consensus. Apple Silicon M1 (2020) proved ARM could decisively beat x86. AWS Graviton4, NVIDIA Grace, Ampere Altra made 30% cloud savings real. RISC-V is silicon-shipping stage at Western Digital, SiFive, Tenstorrent, Meta. GPUs moved past H100/H200 to B100/B200 Blackwell (2024) and GB300 (2025), dominating the LLM economy. No software engineer can sidestep this anymore.
This post extends the earlier Rust Deep Dive. The reason Rust can claim zero-cost abstraction is that it compiles to CPU-friendly code — and that "CPU-friendly" is what we dissect here.
Part 1. From Transistors to Instructions — What Your if Actually Does
1.1 Von Neumann to Modern CPU in 30 Seconds
The 1945 Von Neumann architecture is logically unchanged: code and data share memory, CPU reads and executes sequentially. But the physical implementation has been revolutionized.
- 1971 Intel 4004 — 4-bit, 2,300 transistors, 740kHz
- 1985 Intel 386 — 32-bit, 275K transistors, 16MHz
- 1993 Pentium — superscalar (2 instructions per cycle), 5-stage pipeline
- 1995 Pentium Pro — Out-of-Order, speculative execution, register renaming
- 2006 Core 2 — Intel hit the power wall, switched to parallelism
- 2011 Sandy Bridge — integrated memory controller, AVX
- 2020 Apple M1 — 5nm, 16B transistors, Unified Memory Architecture (UMA), class-leading IPC
- 2024 Intel Lunar Lake / AMD Zen 5 / Apple M4 — hybrid Performance-core + Efficiency-core
A chip now holds 200 billion+ transistors, yet we still write a + b. Modern CPU design is the bridge.
1.2 5 Stages of Execution (Actually 20)
The textbook RISC pipeline:
- Fetch — read instruction from memory
- Decode — interpret the opcode
- Execute — actual computation
- Memory Access — read/write if needed
- Write Back — store result to register
Modern x86 (Golden Cove, Zen 4) splits this into 14 to 20 stages so each stage completes faster and clock can go higher. Longer pipelines amplify the cost of branch misprediction.
1.3 Superscalar — 4 to 8 Instructions per Cycle
Single-instruction pipelines ended in the 1990s. Today multiple instructions issue per clock.
- Apple M3/M4 P-core: 10-wide decode, 9-wide issue
- Intel Golden Cove: 6-wide decode, 5-wide issue
- AMD Zen 5: 8-wide decode, 6-wide issue
Why it matters: if your IPC (Instructions Per Cycle) hits 3 to 4, the CPU is running many ops in parallel. If IPC is 0.5, something is killing the pipeline — branch miss, cache miss, or dependency chain.
Part 2. Out-of-Order Execution — The CPU Reorders Your Code
2.1 Why Reorder
int a = load_from_memory(&x); // 100-cycle miss
int b = 2 + 2; // 1 cycle
In-order CPU blocks on line 1 before starting line 2. Out-of-Order CPU runs b first, then merges when a arrives. If instructions have no dependency, they execute in any order.
2.2 ROB, RS, Register Renaming
- ROB (Re-Order Buffer) — out-of-order execution, in-order commit
- RS (Reservation Station) — dispatch to execution unit as soon as operands are ready
- Register Renaming — architectural registers (16) map to physical registers (hundreds)
The RAX in your code is actually one of 192 physical registers, so false dependencies vanish. Apple M3 ROB has ~700 entries, Zen 5 ~480. Larger ROB means further-out reordering.
2.3 Speculative Execution — Living the Future First
Branch predict then assume one side and execute. Right: win. Wrong: roll back. Poor design here produced Spectre/Meltdown in 2018 (Part 4).
Part 3. Cache Hierarchy — Why Arrays Beat Linked Lists
3.1 Memory Hierarchy Reality
Approximate 2025 x86 P-core numbers:
| Tier | Capacity | Latency | Throughput |
|---|---|---|---|
| Registers | ~400 | 0 cycles | per-op |
| L1d | 48 to 80KB | 4 to 5 cycles | 3 to 4 loads/cycle |
| L2 | 2 to 3MB | 12 to 15 cycles | 1 load/cycle |
| L3 | 32 to 96MB | 40 to 50 cycles | shared |
| DRAM | 32 to 512GB | 200 to 300 cycles | 50 to 100 GB/s |
| NVMe | TB-scale | 10 to 100 us | 7 to 14 GB/s |
| Network | infinity | 100 us+ | 10 to 100 Gb/s |
Register and DRAM differ by ~100x. Cache bridges the gap.
3.2 Cache Line — 64 Bytes Is the Unit
Read 1 byte, get 64 (Apple Silicon: 128). This is the top reason arrays beat linked lists.
int[1000]traversal: first touch loads 16 ints; next 15 hit cache- linked list: nodes scattered in memory, cache miss per hop
5 cycles vs 100 cycles — 20x.
3.3 Prefetch — The CPU Prepares the Future
Hardware prefetchers detect access patterns and pull lines into L1/L2 early. Linear stride (a[0], a[1], a[2]...) is perfectly detected; pointer chasing fails. Software-side: __builtin_prefetch(ptr) (GCC/Clang).
3.4 False Sharing — 64-Byte Hell
Two threads writing different variables on the same cache line cause the MESI coherence protocol to ping-pong the whole line. 10x performance drop is common.
#[repr(align(64))]
struct PaddedCounter(AtomicU64);
Align to 64 bytes and the problem disappears.
3.5 Data-Oriented Design — What Game Engines Learned
OOP's Entity { name, pos, vel, hp, ... } is a cache nightmare. update_positions only needs pos and vel, but name and hp pollute lines. ECS (Entity-Component-System) and SoA (Struct-of-Arrays) fix this structurally.
// AoS: Entity entities[N] -> cache waste
// SoA: float xs[N], ys[N], vxs[N], vys[N] -> pure loads
Unity DOTS, Unreal Mass Entity, Bevy ECS all adopt this.
Part 4. Branch Prediction — When a Branch Is 10x Slower
4.1 Why Predict
With a 15-stage pipeline, an if means "don't know which way yet." Instead of stalling, the CPU guesses and continues. Right: no cost. Wrong: 15 cycles wasted.
4.2 From 2-bit Saturating Counter to TAGE
- 1-bit: remembers last outcome only, ~60% accuracy
- 2-bit saturating: confidence accumulates, ~90%
- Perceptron (AMD 2008+): neural network, 95%+
- TAGE (Intel/Apple 2010s+): tagged histories of varied lengths, 97 to 99%
This is why the famous Stack Overflow question "why is a sorted array faster" answers itself — sorted patterns are trivially predictable (near 100%), random ones are ~50%.
4.3 Branchless Programming
Strip branches from hot loops and misprediction cost disappears.
// branch
int max = a > b ? a : b;
// branchless (CMOV)
int max = b ^ ((a ^ b) & -(a > b));
Rust/LLVM auto-compiles simple ternaries to cmov. For complex code, SIMD vectorizes the whole branch.
Part 5. Post-2018 — Meltdown, Spectre, MDS, Zenbleed
5.1 Meltdown (Intel)
Speculatively reads kernel memory from user mode, then infers the value via cache side-channel. Intel loaded data before permission check. KPTI patches cost 5 to 30%.
5.2 Spectre v1/v2
Attacker trains the branch predictor, extracts victim memory via cache side channel. A design-level flaw: "no full fix," only layered mitigations (IBRS, STIBP, retpoline).
5.3 MDS, L1TF, ZombieLoad, Zenbleed
Variants surfaced 2019 to 2023. Some cloud providers disable SMT. AWS Nitro, Google Titan, Azure Pluton are dedicated security chips shaped by this threat model.
5.4 Post-Quantum Era Security Chips
Apple Secure Enclave, Intel SGX/TDX, AMD SEV-SNP, ARM CCA provide isolated execution inside the CPU even the kernel cannot see — the hardware basis of Confidential Computing.
Part 6. Apple Silicon — Why M1 Beat Intel
6.1 Five Design Wins
- Wide decode (10-wide vs Intel's 6) — x86 variable-length instructions resist parallel decode; ARM's fixed 32-bit makes it easy
- Unified Memory Architecture (UMA) — CPU/GPU/NPU share LPDDR, zero copy cost
- Huge ROB + many physical registers — 2x Intel's OoO window
- SoC-level integration — memory controller, Thunderbolt, NVMe, display on one die, latency collapses
- TSMC 5nm/3nm leading process — 20 to 30% head start at same power
6.2 P-core / E-core Hybrid
M-series mixes performance and efficiency cores. Background work (Spotlight indexing, mail) runs on E-cores to save battery; foreground compute on P-cores. Windows/Linux scheduling is tricky because the OS must infer workload character (Intel's Thread Director helps).
6.3 Graviton/Ampere — Cloud Is Moving to ARM
AWS Graviton3/4 is 30 to 40% cheaper at equal performance. Netflix, Snap, Airbnb migrated at scale. Cloudflare Workers is ARM-first. Reason: absolute lead in performance per watt.
Part 7. x86 vs ARM vs RISC-V — 2025 Landscape
7.1 Why x86 Remains
- Legacy compatibility (Windows/Linux/Steam catalog)
- Mature SIMD (AVX-512, VNNI)
- Server datacenter inertia
But losing perf/watt war. Intel's Lunar Lake (2024) imitates Apple: on-package memory.
7.2 ARM's Winning Fronts
- Mobile (already 100% ARM)
- Cloud (Graviton/Ampere 30%+)
- Mac (100% ARM)
- Windows on ARM (Qualcomm Snapdragon X, 2024)
7.3 RISC-V — The Open-ISA Revolt
- Strengths: royalty-free, modular (RV32I, RV64I, +M/A/F/D/V)
- 2024 to 2025 silicon: SiFive P870, Tenstorrent Ascalon, Meta MTIA, China XuanTie
- Weaknesses: ecosystem maturity, vector fragmentation
Key is RVA23 profile standardization. Linux kernel already fully supports it.
Part 8. SIMD — 8x Faster with Vector Instructions
8.1 Why SIMD
Scalar: one value per op. SIMD: many values per op (Single Instruction, Multiple Data).
- SSE (1999+): 128-bit, 4 floats
- AVX/AVX2 (2011+): 256-bit, 8 floats
- AVX-512 (2017+): 512-bit, 16 floats (Intel server, AMD Zen 4+)
- ARM NEON (2004+): 128-bit standard
- SVE/SVE2 (2016+): variable-length (128 to 2048-bit), Apple M4, Graviton3
- RISC-V V (2021+): SVE-like, variable length
8.2 Auto-Vectorization and Manual
LLVM/GCC auto-vectorize simple loops. Dependencies or branches defeat them. For tight performance, use intrinsics or std::simd (Rust portable SIMD, 2024 nightly), std::experimental::simd (C++).
use std::simd::f32x8;
let a = f32x8::from_array([1.0; 8]);
let b = f32x8::from_array([2.0; 8]);
let c = a + b; // 8 adds in one instruction
8.3 Real Examples
- simdjson: JSON parse 1 to 3 GB/s (4 to 10x over scalar)
- ClickHouse: SIMD-tuned aggregations
- WebP/AVIF decode
- LLM inference Q4/Q8 quantization
- Ripgrep string search (memchr crate)
Part 9. GPU Architecture — CUDA Cores, SM, Warp
9.1 CPU vs GPU Philosophy
- CPU: deep pipeline, complex prediction, few threads, minimize latency
- GPU: shallow pipeline, tens of thousands of threads, maximize throughput
GPU hides latency by context-switching threads on cache miss. CPU just waits.
9.2 H100/B200/GB300 Internals
- SM (Streaming Multiprocessor): GPU's "core cluster", H100 has 132, B200 has 208
- CUDA Core: scalar ALU in an SM, 128 per SM
- Tensor Core: 4x4 matrix multiply per cycle, LLM's engine
- Warp: 32 threads co-execute in SIMT
- Shared Memory: ~228KB per SM, manual-managed cache
- HBM3e (B200): 192GB, 8TB/s
9.3 Warp Divergence — GPU's Branch Cost
If 32 threads in a warp take different branches, both paths execute with masks. Branch cost is brutal — hence LLM kernels are branchless.
9.4 LLM Inference Bottlenecks
- Prefill: compute-bound, tensor cores 100% busy
- Decode: memory-bound, KV-cache reads dominate → FlashAttention, PagedAttention, continuous batching
- Blackwell B200 FP4 (2024): 2x effective memory bandwidth
9.5 ROCm, Apple MLX, Metal — Outside NVIDIA
- AMD ROCm ports CUDA via HIP, MI300X (HBM3 192GB) is H100 alternative
- Apple Metal + MLX: local LLM on M-series, UMA gives instant model load
- Intel Arc/Gaudi: OneAPI/SYCL, Gaudi3 targets inference value
Part 10. Laws of Memory — DRAM, HBM, CXL, NVLink
10.1 DDR5, LPDDR5X, HBM3e
- DDR5 (desktop/server): up to 8400 MT/s, ~90 GB/s 2-ch
- LPDDR5X (mobile, Apple, Qualcomm): 8533 MT/s, low power
- HBM3e (GPU): 3D-stacked, 8TB/s per GPU, mandatory on B200
10.2 NUMA Pitfalls
Remote-socket memory is 2 to 3x slower on 2-socket servers. Tune with Linux numactl, mbind. Kubernetes Topology Manager recognizes this.
10.3 CXL (Compute Express Link)
Real standard since 2024.
- CXL.cache: CPU caches remote memory
- CXL.mem: memory pooling, disaggregation
- CXL.io: PCIe-compatible
Meaning: "RAM in a server becomes a shared resource." Rack-level memory over-provisioning solved.
10.4 NVLink / NVSwitch
Direct GPU interconnect. H100 NVLink 900 GB/s, B200 1.8 TB/s. Hardware foundation for large-LLM parallelism (TP/PP/EP).
Part 11. Power, Heat, Quantum — Why Clocks Stopped Rising
11.1 End of Power Wall and Dennard Scaling
Dennard Scaling (transistors shrink, power drops proportionally) stopped ~2006. Clocks stuck at 3 to 5GHz since. Solutions: parallelism (more cores) and specialization (NPU, Tensor Core).
11.2 Dark Silicon
With 200B transistors, the power budget only allows a fraction on simultaneously. Hence purpose-built blocks (AMX, NPU, media engine) that turn on only when used.
11.3 3D Packaging
TSMC CoWoS, Intel Foveros — stack logic and memory vertically, latency/bandwidth explodes. B200, MI300X are 3D assemblies.
11.4 Quantum Computing — 2025 Reality
IBM Osprey (433 qubit), Google Willow (2024, 105 qubit + error-correction breakthrough), Atom Computing 1000-qubit neutral atom. "Far from breaking crypto but useful for optimization/chemistry." Immediate impact for engineers: post-quantum crypto prep (Kyber, Dilithium).
Part 12. Wiring Performance End-to-End — Measure, Profile, Tune
12.1 Linux perf
perf stat -d ./myapp
# instructions, cycles, IPC, cache-misses, branch-misses
perf record -g ./myapp && perf report
- IPC less than 1 → many misses
- branch-miss greater than 2% → prediction failure
- LLC-load-miss greater than 10% → cache design failure
12.2 Intel VTune, AMD uProf, Apple Instruments
Top-Down analysis: Retiring / Bad Speculation / Frontend Bound / Backend Bound. Judge the bottleneck in a minute.
12.3 Microbench Traps
Run a million times with std::chrono and average? Compiler treats it as loop-invariant and deletes the code. Use black_box (Rust), benchmark::DoNotOptimize (Google Benchmark).
12.4 Performance Checklist
- Measure first, never guess
- Algorithm: O(n squared) → O(n log n) before any microtuning
- Check data layout (SoA/AoS)
- Allocation count — Rust
allochooks, jemalloc stats - Lock contention —
perf lock,perf trace - SIMD opportunity — auto-vectorization logs (
-Rpass=loop-vectorize)
Part 13. Practice — Why 10x Differences Appear in the Same Language
13.1 Case 1: Linear Probing vs Chaining HashMap
std::unordered_map-style chaining is a cache-miss generator. Open addressing (linear probing) is 2 to 5x faster on modern CPUs. Rust hashbrown (std HashMap backbone, Google SwissTable port) exemplifies.
13.2 Case 2: Why a JSON Parser Can Do 1 GB/s
simdjson scans 64 bytes at once via AVX-512/ARM NEON to identify structure, then parses in a second pass. 10x-plus over traditional parsers.
13.3 Case 3: Redis vs KeyDB vs Dragonfly
Redis is single-threaded. KeyDB/Dragonfly use io_uring + shared-nothing for linear per-core scaling. 10 to 25x throughput gap on the same hardware.
13.4 Case 4: LLM Inference — TensorRT-LLM vs vLLM vs SGLang
- Same model, same GPU, 3 to 8x throughput spread
- Reasons: KV-cache management, continuous batching, paged attention, CUDA graph, FP8/FP4 quantization
- "Runtime swap" rivals "model swap" in effect
Part 14. How Hardware Shifts Shape Software Design
14.1 NVMe + io_uring = File I/O Reborn
As disks accelerated, blocking I/O overhead became the bottleneck. Async I/O is mandatory.
14.2 100 Gb/s NIC + RDMA + DPDK
Network faster than PCIe. Without kernel bypass (DPDK) and RDMA (RoCEv2) you leave performance on the table. Cloudflare, Meta, Stripe edges run on these.
14.3 DPU/IPU
NVIDIA BlueField, Intel IPU, AWS Nitro offload network, storage, security off CPU. 2025 datacenter standard.
14.4 AI Accelerator Warring States
NVIDIA B200/GB300, AMD MI350X, Google TPU v5p/v6, AWS Trainium2/Inferentia3, Cerebras WSE-3, Groq LPU, Tenstorrent. Each aims to beat NVIDIA in one domain.
Part 15. Checklist 12, Anti-patterns 10
Checklist 12
- Hot-path data structures are cache-friendly? (array beats linked list)
- Struct layout considers 64-byte alignment/padding?
- Multi-thread shared data has no false sharing?
- Hot loop branch prediction rate checked with perf?
- If IPC below 1, investigated cause (cache, branch, dependency)?
- Loops with SIMD opportunity got auto-vectorized?
- On NUMA systems, pinned local memory with numactl or topology manager?
- Measured SMT noisy-neighbor impact on vCPU?
- GPU workload Warp divergence measured?
- Memory allocation batched via arena or slab to reduce fragmentation?
- Have a post-quantum crypto migration roadmap (2030 timeline)?
- ARM64 builds (CI/CD) and benches ready?
Anti-patterns 10
- Deciding "Rust is fast" without benchmarks
- Using OOP AoS exclusively, ignoring SoA
- Spraying
HashMapin hot loops - All threads contending on one atomic counter
- Thinking virtual threads/async fix CPU-bound problems
- Tuning on x86, not testing ARM
- GPU code with if-else causing warp divergence
- Micro-tuning
memcpywhile leaving algorithm alone - Trusting KVM/VM-internal benches as bare-metal
- Disabling Meltdown/Spectre mitigation for performance
Next — "Observability in the Modern Era" — OpenTelemetry, eBPF continuous profiling, Grafana LGTM, Pyroscope, Sentry Performance, Datadog, Honeycomb, SLO, SRE, on-call
You learned the CPU — now you need to see what happens on it in real time. Next post drills into 2025 observability.
- Metrics x Logs x Traces x Profiles — Four Pillars
- OpenTelemetry becoming the de facto standard
- eBPF continuous profiling — Parca, Pyroscope, Polar Signals
- Distributed tracing — sampling strategies, tail/head-based
- LGTM stack — Loki/Grafana/Tempo/Mimir
- Sentry Performance, Datadog APM, Honeycomb compared
- SLO/SLI/Error Budget — decade since the SRE book
- AI anomaly detection — Datadog Watchdog, Grafana Oncall AI
- On-call operations — rotation, postmortem, blameless culture
From hardware to software to operations — up the next stack layer.