본문으로 건너뛰기
Embedded Performance Engineering · 11/57

Branch Prediction 분석 — Static·2-bit·BTB·BHT·Mispredict 비용

· Hawk · 5분 읽기

#한 줄 요약

“Branch prediction = pipeline 살리는 트릭” 입니다. mispredict 시 전체 flush가 일어납니다.

#Mispredict 비용

Pipeline depth: 8
Branch resolved at: stage 5
Misprediction → 5 cycle flush → 5 cycle 손실
CPUPipelineMispredict Penalty
Cortex-M021 cycle
Cortex-M3/M432 cycle
Cortex-M764~5 cycle
Cortex-A5388 cycle
Cortex-A721515 cycle
Intel Skylake14~1915+ cycle

깊은 pipeline일수록 예측 실패 비용이 커집니다. Modern CPU에서 mispredict는 cache miss와 비슷한 비용을 갖습니다.

#Static Prediction — BTFNT

Backward Taken, Forward Not-Taken.

for (int i = 0; i < N; i++) { // backward branch — predict taken
// loop body
}
if (rare_error) { // forward — predict not-taken
handle_error();
}

Loop은 대부분 taken이고 error path는 대부분 not-taken이라, 통계적 hit rate가 약 70%입니다.

ARM Cortex-M0/M3는 pure static 방식입니다. Branch instruction 자체가 backward·forward를 판별할 수 있습니다.

#Dynamic — 1-bit Predictor

last_branch_taken → 1
last_branch_not_taken → 0
predict = last result
for (int i = 0; i < 10; i++) { ... } // 9 taken + 1 not-taken

루프 끝에서 두 번 mispredict가 발생합니다 (taken→not-taken 전환과 다음 루프 시작 not-taken→taken). 정확도는 70-80%입니다.

#2-bit Saturating Counter — 표준

[Strongly Not Taken] ←→ [Weakly Not Taken] ←→ [Weakly Taken] ←→ [Strongly Taken]
00 01 10 11
Predict:
00, 01 → Not Taken
10, 11 → Taken
Update on actual outcome:
Taken → counter++ (saturate at 11)
Not Taken → counter-- (saturate at 00)

루프 끝에서 한 번만 mispredict가 발생합니다. 한 번의 예외로 바로 flip되지 않기 때문입니다. 정확도는 85-95%입니다.

#BHT (Branch History Table)

각 branch PC를 index로 2-bit counter를 저장합니다.

PC (12-bit hash) → Index → 2-bit counter

크기는 보통 1k~16k entry입니다. ARM Cortex-A53은 256 entry × 4-way set associative 구조를 갖습니다.

#BTB (Branch Target Buffer)

분기 주소뿐 아니라 대상 주소도 캐시합니다.

PC → BTB entry:

  • { target_addr, predict_bits }

분기 명령 fetch 시점에 BTB hit이면 바로 target fetch가 이루어집니다. 1 cycle도 잃지 않습니다.

#Global History — Two-Level Adaptive (gshare)

last 8 branches taken? → 8-bit history register
index = (PC ^ history) mod table_size

상관관계 학습입니다. if (a) {} if (b) {} if (a && b) {} 패턴에서 c의 결과를 a·b 결과로 예측합니다.

Cortex-A72는 Tournament predictor를 씁니다 (local + global을 모두 두고 동적으로 선택).

#Indirect Branch — Function Pointer·vtable

void (*handler)(int) = handlers[type];
handler(arg); // indirect branch — target 가변

BTB 한 entry는 최근 target만 기억합니다. 가변이면 mispredict가 빈번해집니다.

해결책은 Indirect Branch Predictor입니다 (Cortex-A72의 별도 hardware).

#Return Address Stack

function_a(); // call → push return addr to stack
/* ... */
return; // pop stack → predict return target

별도의 return stack을 둡니다 (8~16 entry). Function call/return은 거의 완벽하게 예측됩니다.

깊은 recursion이 stack을 초과하면 mispredict가 발생합니다.

#Cortex-M3/M4 — Limited Prediction

; Cortex-M3 prediction
beq label ; static prediction만 (BTFNT 기본)
bx lr ; return*prediction 없음*, 항상 flush

Cortex-M3는 branch 자체에 prefetch buffer를 둡니다. mispredict는 2 cycle이고 그 외 hit은 0 cycle입니다.

#Cortex-A53 — Branch Predictor Spec

항목사양
BTB256 entry, 4-way set assoc
BHT6144 entry
Return Stack8-entry
Predict per cycle1
Mispredict penalty8 cycle

#측정 — PMU Event

Event의미
0x10 BR_PRED분기 명령 수
0x11 BR_MIS_PRED잘못 예측한 분기 수
0x18 BR_RETURN_MIS_PRED잘못 예측한 return
Terminal window
# Linux perf
perf stat -e branches,branch-misses ./prog
# branch-miss-rate = branch-misses / branches
# 일반 코드: < 5%
# 잘 짜인 코드: < 1%
# branch-heavy worst case: 15~20%

#Branchless Code

// 회피
int max(int a, int b) {
if (a > b) return a;
else return b;
}
// Good — branchless
int max(int a, int b) {
int diff = a - b;
int mask = diff >> 31; // -1 if a<b, 0 if a>=b
return b + (diff & ~mask);
}

또는 ARM Thumb-2 IT block:

cmp r0, r1
it gt
movgt r0, r1 ; conditional move

Mispredict를 회피하는 기법입니다. 다만 modern OoO에서 predict가 잘 되면 branchless가 더 빠르지 않을 수 있어 측정이 우선입니다.

#__builtin_expect — 컴파일러 힌트

if (__builtin_expect(rare_error, 0)) {
handle();
}
// 매크로화
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
if (unlikely(rare_error)) {
handle();
}

컴파일러가 forward branch arrangement를 hint대로 배치합니다. 일부 ARM에서는 static prediction에도 영향을 줍니다.

#Spectre — Branch Prediction의 어두운 면

if (x < array_size) { // mispredict → speculative execution
y = array[secret_offset]; // 실행되지만 commit 안 됨
// 그러나 *cache state 변경* → side channel
}

CVE-2017-5754 Meltdown·Spectre 계열입니다. ARM에서도 Cortex-A75 이상에서 영향이 있습니다. 완화 기법으로는 csdb barrier와 KAISER 기법이 있습니다.

#자주 하는 실수

⚠️ volatile로 mispredict 회피 시도

volatile은 컴파일러 재정렬 차단입니다. branch prediction과는 무관합니다.

⚠️ 짧은 if-else로 무조건 branchless

if (rare_case) special_path(); // ← 1% taken

99% predict가 성공하면 mispredict 비용은 적습니다. Branchless가 항상 빠른 것은 아닙니다.

⚠️ Indirect call 남발

op_table[op_code](); // 함수 포인터 — indirect branch mispredict 빈번

switchjump table로 컴파일되지만 direct jump 형태라 일부 컴파일러는 BTB 친화적으로 처리합니다. Computed goto (&&label)도 옵션으로 쓸 수 있습니다.

⚠️ Inline assembly로 branch 자제

asm volatile ("b label"); // 직접 jump → mispredict 가능성 ↑ (BHT 학습 못 함)

컴파일러가 자동으로 생성한 branch보다 덜 효율적입니다. 명시적인 이유가 없으면 자제합니다.

#정리

  • Mispredict 비용은 pipeline 깊이만큼 cycle을 손실합니다.
  • Static BTFNT에서 2-bit saturating, BTB + BHT + return stack 순으로 발전합니다.
  • Cortex-A는 tournament + indirect predictor까지 지원합니다.
  • PMU BR_MIS_PRED로 측정하며, 목표는 5% 미만입니다.
  • __builtin_expect·branchless·jump table을 적극 활용합니다.

다음 편은 Speculative Execution입니다.

#관련 항목

Embedded Performance Engineering · 12 of 57

  1. 1Embedded Performance Engineering — 임베디드 성능 엔지니어링 시리즈 소개
  2. 2임베디드 성능 분석 방법론 — Measure → Analyze → Optimize 사이클
  3. 3성능 지표 정의 — Latency·Throughput·Utilization 분석
  4. 4성능 측정의 기본 — Wall-Clock·CPU Cycle·Instruction Count
  5. 5성능 데이터 통계적 분석 — Percentile·Histogram·평균의 함정
  6. 6실시간 성능 분석 — WCET·Jitter·Deadline Miss 측정
  7. 7임베디드 벤치마킹 기초 — 재현성·Warmup·노이즈 제거
  8. 8성능 모델링 — Amdahl·Gustafson·Roofline Model 적용
  9. 9프로파일링 기법 개요 — Sampling vs Instrumentation·PGO·LTO
  10. 10CPU 파이프라인 분석 — 5-stage·Cortex-M·Cortex-A 비교
  11. 11Pipeline Stall 분석 — Data·Structural·Control Hazard·Forwarding
  12. 12Branch Prediction 분석 — Static·2-bit·BTB·BHT·Mispredict 비용
  13. 13Speculative Execution 분석 — OoO·Reorder Buffer·Register Renaming
  14. 14CPU Cache 기초 — L1·L2·L3·Set Associative·Replacement Policy
  15. 15Cache Miss 3C Model 분석 — Compulsory·Capacity·Conflict
  16. 16Cache Line 최적화 — Alignment·Prefetch·False Sharing 처리
  17. 17메모리 대역폭 분석 — STREAM·Roofline·Bus Saturation 측정
  18. 18SIMD·NEON 활용 — 128-bit Vector·Auto-Vectorization·SVE/SVE2
  19. 19PMU·HPM 하드웨어 카운터 분석 — 정밀 성능 진단
  20. 20임베디드 Bus Architecture — AHB·AXI·CHI 진화와 5-Channel
  21. 21Bus Contention 진단 — Arbitration·QoS·Starvation 측정
  22. 22DMA 성능 최적화 — Burst·Scatter-Gather·Chain·Cache 일관성
  23. 23DMA vs CPU Copy 성능 비교 — Break-even·Setup Overhead 실측
  24. 24Interrupt Latency 분석 — 진입·종료·Tail-Chaining·Late Arrival
  25. 25Interrupt Storm 처리 — NAPI·Rate-Limit·Polling 전환
  26. 26MMIO 접근 성능 — Cache Policy·Write-Combining·Volatile·Barrier
  27. 27Peripheral Clock 분석 — PLL·Divider·Gating·DVFS
  28. 28Power vs Performance 트레이드오프 — DVFS·Race-to-Idle·Big.LITTLE
  29. 29Thermal Throttling 분석 — Junction Temp·Trip Point·냉각
  30. 30CXL Interconnect 분석 — AI 시대 메모리 대역폭 확장
  31. 31Concurrency 기초 — Concurrency vs Parallelism·Race·Memory Model
  32. 32False Sharing 진단 — Cache Line Ping-Pong·Padding·측정
  33. 33Lock Contention 분석 — Wait·Hold·Convoy·측정 기법
  34. 34Spinlock 성능 분석 — Spin-Wait vs Context Switch·Ticket·MCS
  35. 35Mutex 성능 분석 — Futex·Adaptive·Priority Inheritance
  36. 36Reader-Writer Lock 성능 — Reader/Writer Priority·RCU·Seqlock
  37. 37Lock-Free 자료구조 성능 — CAS·ABA·Hazard Pointer·Epoch Reclamation
  38. 38Memory Ordering 분석 — Acquire·Release·Seq-Cst·ARM Relaxed Model
  39. 39Cache Coherency 프로토콜 — MESI·MOESI·Snoop·Directory
  40. 40SMP 성능 분석 — Per-Core·Affinity·Load Balance·Scalability
  41. 41Linux perf 기초 — stat·record·report 활용
  42. 42Linux perf 고급 — Raw Event·Tracepoint·perf script
  43. 43ftrace 활용 — function·function_graph·latency tracer
  44. 44eBPF·bpftrace 동적 트레이싱 — 커널 무수정 관측
  45. 45Flamegraph 분석 — On-CPU·Off-CPU·Differential
  46. 46ARM DS·Lauterbach 분석 — Hardware Trace 전문 도구
  47. 47Bare-metal 프로파일링 — GPIO·DWT·SysTick·ITM 활용
  48. 48NVIDIA Nsight Systems — GPU·NPU 포함 시스템 분석
  49. 49모던 프로파일러 비교 — Tracy·Hotspot·uftrace·Coz
  50. 50연속 프로파일링 — Parca·Pixie·Pyroscope·Tetragon
  51. 51실전 사례 — ISR Latency 100µs Deadline Miss 추적
  52. 52실전 사례 — Matrix Multiply가 예상의 10배 느린 이유
  53. 53실전 사례 — 8-core가 4-core를 넘으면 throughput이 떨어지는 이유
  54. 54실전 사례 — 카메라 1080p 60fps가 30fps로 떨어지는 이유
  55. 55CXL.mem 지연·대역폭 실측 — Direct·Switch·Pooled 토폴로지 비교
  56. 56CXL 성능 프로파일링 도구 — cxl-cli·DAMON·perf-mem 활용
  57. 57실전 사례 — CXL.mem 추가로 LLM inference KV cache 처리량 회복