당신의 벤치마크는 당신에게 거짓말을 하고 있습니다 (그리고 이 148-Star Crate가 그 이유를 알고 있습니다)
Source: Dev.to
번역을 진행하려면 번역하고자 하는 전체 텍스트를 제공해 주세요. 텍스트를 보내주시면 그대로 한국어로 번역해 드리겠습니다.
Overview
마이크로벤치마크는 – 악의적으로가 아니라 구조적으로 거짓말을 합니다. 빡빡한 루프를 작성하고, 천 번 측정하고, 두 구현을 비교해서 승자를 선언하죠. 그런데 두 번째 실행 중에 CPU가 열에 의해 스로틀링되었거나, 운영체제가 중간에 백그라운드 프로세스를 스케줄했거나, 점심을 먹고 돌아와서 메모리 할당자가 실행마다 다르게 단편화되었을 수도 있습니다.
대부분의 벤치마크 프레임워크는 더 많은 샘플을 수집하고 통계가 구원해 주길 바라며 이 문제를 해결합니다: 천 번 대신 만 번 실행하고, 이상치를 버리고, 신뢰 구간을 계산합니다. 어느 정도 도움이 되지만 근본적인 문제를 단순히 보완하는 것에 불과합니다. 즉, 기준선과 후보를 서로 다른 시점, 서로 다른 시스템 상황에서 측정한 것이기 때문입니다.
만약 그렇지 않아도 된다면?
Tango는 Denis Bazhenov가 만든 Rust 마이크로‑벤치마크 프레임워크로, 간단한 아이디어에 기반합니다: 기준선 과 후보를 순차적으로가 아니라 동시에 실행합니다.
기준선 → 후보 → 기준선 → 후보 … 같은 프로세스 내에서 매 반복마다 교대로 실행합니다.
- 열에 의한 드리프트가 두 경우에 동일하게 적용됩니다.
- 스케줄링 지터가 두 경우에 동일하게 적용됩니다.
결과를 비교할 때, 같은 시스템 상황을 같은 순간에 경험한 두 가지를 비교하게 됩니다. 프로젝트에서는 이를 **“paired testing”**이라고 부릅니다. 전통적인 순차 벤치마킹보다 더 타이트한 신뢰 구간과 적은 false‑positive를 제공합니다.
Stars: ~148 (작성 시점)
License: MIT (암시)
프로젝트 요약
| Item | Details |
|---|---|
| Name | tango |
| Stars | ~148 |
| Maintainer | 솔로 개발자, 활발히 커밋 중 |
| Code health | 작고, 밀집돼 있으며, 잘 정리됨 |
| Docs | 방법론 설명이 포함된 탄탄한 README; API 문서는 다소 얇음 |
| Contributor UX | 명확한 아키텍처, 반응 빠른 유지보수자, 기여에 개방적 |
| Worth using? | 벤치마크를 수행하고 결과 안정성을 중시한다면 사용 가치 있음 |
전체 워크스페이스는 약 3,900 줄의 Rust이며, 핵심 tango-bench 크레이트는 ~3,350 줄에 불과합니다 – 제공하는 기능에 비해 작습니다. 아키텍처가 그 줄 수를 정당화합니다.
기술 하이라이트
페어 테스트 구현
- 동적 라이브러리 로딩을
libloading크레이트를 통해 수행합니다. - 벤치마크는 dylib으로 컴파일되며, Tango는 같은 프로세스에 두 개의 복사본을 로드합니다.
- Linux에서는 GOT/PLT 패치(
goblin을 사용한 ELF 파싱)를 통해 함수 호출을 가로챕니다. - Windows에서는 Import Address Table을 패치합니다.
이는 std::time::Instant를 얇게 감싼 것이 아니라 실제 시스템 프로그래밍입니다.
벤치마킹 API
benchmark_fn("my_algorithm", |b| {
b.iter(|| my_function(1000))
});
Metric 선택은 제네릭이며, 터보피시 문법으로 선택됩니다. Metric 트레이트는 단일 메서드를 가집니다:
pub trait Metric {
fn measure_fn(f: impl FnMut()) -> u64;
}
클로저가 래핑되고 측정된 뒤 결과가 반환됩니다. 트레이트는 모노모픽화되어, 핫 경로에서 v‑table 디스패치가 없습니다.
- WallClock은 기본적으로
std::time::Instant를 사용하며(hw-timer기능 플래그를 사용하면rdtscp를 직접 사용할 수 있습니다). - 사용자는 벤치마크마다 메트릭을 교체할 수 있습니다:
b.metric::().iter(|| …);
의존성
| Crate | Purpose |
|---|---|
clap | CLI 파싱 |
rand | 섞인 반복 순서 |
libc / windows | 플랫폼 별 호출 |
goblin / scroll | ELF 파싱 및 패치 (Linux) |
alloca | 스택 할당 샘플링 버퍼(측정 시 할당 노이즈를 제거) |
불필요한 부피가 없습니다.
거친 부분들
- README 외의 API 문서는 부족합니다.
cli.rs에 남아 있는 Clippy 경고(인수가 너무 많은 함수)가 있습니다.- 핵심 통계 및 측정 코드에 대한 테스트 커버리지는 탄탄하지만, CLI와 dylib 로딩 경로에 대한 커버리지는 얇습니다 – 집중된 개인 프로젝트에서 흔히 볼 수 있는 상황입니다.
Source: …
최근 개발: Metric 트레이트
Tango가 PR #60에서 Metric 트레이트를 추가했을 때, 기본 구현은 WallClock 하나뿐이었습니다. 이전 PR (#57)에서는 기본 타이머를 clock_gettime(CLOCK_THREAD_CPUTIME_ID) 로 바꿔 스레드당 CPU 시간을 측정하자는 제안이 있었지만, 유지보수자는 올바르게 반박했습니다: CPU 시간 ≠ 벽 시간 (sleep(100 ms) 은 100 ms의 벽 시간을 기록하지만 CPU 시간은 거의 0에 가깝습니다).
플러그 가능한 Metric 트레이트가 도입되면서, 두 구현을 동시에 사용할 수 있게 되었습니다.
나의 기여: CpuTime 메트릭
- Unix –
clock_gettime(CLOCK_THREAD_CPUTIME_ID)사용 (나노초 정밀도). - Windows –
GetThreadTimes(GetCurrentThread())를 호출하고 사용자 시간 + 커널 시간을 합산.
새로운 크레이트는 필요 없었으며, 구현은 cfg 속성 뒤에 두어 WallClock 과 동일한 구조를 따릅니다. 이번 변경은 두 파일, 총 약 115 줄(테스트 포함)에 영향을 미칩니다.
통합 테스트 (PR #72)
#[test]
fn cpu_time_vs_sleep() {
// Sleep 50 ms → low CPU time
// Busy loop → high CPU time
// Assert busy loop reports ≥10× more CPU time than sleep
}
이 테스트는 메트릭의 목적을 보여줍니다: thread::sleep 은 벽 시간은 소비하지만 CPU 시간은 거의 소모하지 않습니다.
Source: …
전망
Tango는 벤치마크를 수행하고 일관되지 않은 결과에 지친 Rust 개발자를 대상으로 합니다. 노트북 팬이 작동하면서 5 % 회귀가 발생한 적이 있다면, 쌍방향 테스트 방식이 바로 그 문제를 해결해 줍니다.
프로젝트의 진행 방향은 명확합니다:
Metric트레이트가 최근에 도입되었습니다.- 비동기 벤치마크 지원이 진행 중입니다.
- 유지 관리자는 PR과 이슈에 신중하게 대응하고 있습니다.
이는 멈춰선 부수 프로젝트가 아니라—활발히 발전하고 있으며, 깔끔한 아키텍처가 추가 성장을 지원할 것입니다.
무엇이 더 발전을 이끌 수 있을까요?
- 공개 크레이트에 대한 Rustdoc 등 보다 풍부한 API 문서화.
- Windows 전용 로딩/패치 경로에 대한 테스트 커버리지 확대.
InstructionsRetired,CacheMisses와 같은 추가 내장 메트릭.- 커뮤니티 주도 플러그인을 통한 맞춤형 통계 분석.
Rust 코드를 벤치마크하고 결과 안정성을 중요하게 생각한다면, Tango를 한 번 사용해 보세요.
리뷰 폭탄 #4
더 많은 메트릭(예: perf_event_open을 통한 명령어 카운트 등), 개선된 API 문서, 그리고 더 넓은 인지도.
쌍 테스트(paired‑testing) 방법론은 한 번 이해하면 순차 벤치마킹이 명백히 잘못된 것처럼 느껴지는 아이디어입니다. 더 많은 사람들이 이 방법을 알아야 합니다.
Rust 코드를 벤치마크한다면 tango를 확인해 보세요:
- README의 Methodology 섹션을 읽어보세요.
- 예제 중 하나를 실행해 보세요.
- 현재는 Criterion을 사용하더라도, 쌍 테스트 접근법을 이해하는 것이 가치 있습니다.
참여 방법
- ⭐️ 저장소에 별표를 달아 주세요.
- 실제 벤치마크에 적용해 보세요.
- 열린 이슈 중 하나를 선택해 작업해 보세요.
작은 기여가 어떤 모습인지 보고 싶다면 제가 추가한 CpuTime PR을 확인해 보세요:
[PR #: Add CpuTime metric](https://github.com///pull/)