본문으로 건너뛰기

put_many 4N→2N 락 최적화 벤치마크

변경 개요

5a27732f ([Perf][RawBlock] Reduce put_many lock count from 4N to 2N) 가 _write_one 내부에서 잡던 _inflight_io_count ±1 락 2개를 put_many 의 allocate-lock / commit-lock 으로 흡수. 명목상 키당 4회 → 2회 락 절약.

벤치마크 설계

  • 파일: benchmarks/storage_backend_io/bench_put_many_lock_patterns.py
  • 2N 패턴: 현재 코드 그대로
  • 4N 시뮬레이션: _write_one monkeypatch — 원본 호출 전후에 with self._lock: dummy ±1 2회 추가
  • 조건: N=[10, 100, 1000] × latency=[0, 10, 50] µs (pwrite sleep), warmup=3, iters=10
  • 환경: /home/ny/LMCache (fake in-memory device, Python 3.12)

결과

N latency 2N median 4N median diff lock%
────────────────────────────────────────────────────────────
10 0 µs 0.077 ms 0.080 ms +3.9% 3.8%
10 10 µs 1.296 ms 1.364 ms +5.3% 5.0% (sleep 노이즈)
10 50 µs 2.581 ms 2.623 ms +1.6% 1.6%
100 0 µs 1.237 ms 0.735 ms -40.6% -- (GC/JIT 이상치)
100 10 µs 17.977 ms 18.650 ms +3.7% 3.6% (sleep 노이즈)
100 50 µs 26.025 ms 25.720 ms -1.2% -- (noise)
1000 0 µs 7.271 ms 7.463 ms +2.6% 2.6%
1000 10 µs 183.928 ms 187.898 ms +2.2% 2.1%
1000 50 µs 262.893 ms 263.900 ms +0.4% 0.4%

diff = (4N − 2N) / 2N × 100
N=100 lat=0 결과는 2N 측정 중 GC 인터럽트로 인한 이상치.
lat=10µs 계열은 OS sleep 최소 단위(~100µs)보다 작아 노이즈 큼.
신뢰할 수 있는 값: N=1000 lat=0 (순수 CPU) / N=1000 lat=50µs (NVMe급).

해석

구간이득판단
lat=0µs (순수 CPU)24%실재하지만 작음
lat=50µs (빠른 NVMe)<1%측정 노이즈와 구별 불가
lat≥100µs (일반 NVMe/SATA)≪1%사실상 0

락 자체의 소유 시간이 매우 짧아(_inflight_io_count ±1 정수 연산 수십 ns), 실제 I/O 지연이 조금만 있어도 절약 효과가 묻힘.

부작용 (코드 리뷰에서 확인된 것)

#내용심각도
F1_last_io_ts 가 prep 실패 시에도 갱신 → checkpoint idle gate 회귀high
F3+F11inflight_io_count() ON window 가 docstring 보다 넓어짐medium
F5_CountingLock.__enter__ 반환값 버그 (latent)low

F1/F5 는 브랜치에서 수정 완료, 하지만 이 수정들이 필요했다는 것 자체가 최적화의 순이익이 작음을 보여줌.

결정

PR drop. 실측 이득 <1%(NVMe 현실 구간) 대비 semantic 변화(inflight window 확장)와 코드 복잡도 증가 비용이 크다. raw-block-perf-findings.md §2-1, §2-2 의 lock 항목은 여전히 open (이 PR 이 해결한 것으로 보지 않음).