덜 느린 C/C++ 코드 작성하는 법 배우기
(github.com/ashvardanian)- 고성능 C/C++ 및 어셈블리 코딩 기법을 실전 예제로 학습할 수 있는 오픈소스 프로젝트
- STL 대신 최적화된 라이브러리와 다양한 하드웨어 최적화 기법 사용 예시 포함
- 입력 생성 비용, 수학 함수 근사화, CPU 분기 예측, 멀티코어 병렬화 등 다양한 퍼포먼스 트릭 설명
- CUDA, PTX, ASM, FPGA, JSON 처리 등 플랫폼별 최적화 기법과 벤치마크 측정 방법까지 폭넓게 다룸
- Google Benchmark 기반으로 벤치마크 실행 및 통계 처리 자동화 기능 제공
성능 지향 C/C++ 및 어셈블리 코드 작성법
- 이 프로젝트는 고성능 소프트웨어 설계에 필요한 직관과 사고방식 형성을 돕는 벤치마크 코드 모음임
- 현대 코드에서 흔한 버그, 보안 문제, 성능 병목 등을 피하기 위한 실전 코딩 예제를 다룸
- 대학 강의나 부트캠프에서 접하기 어려운 실무 성능 지향 기법을 체계적으로 소개함
- 대부분의 코드는 GCC, Clang 기반의 Linux 환경에서 동작하지만, Windows와 macOS도 일부 지원함
- 고성능 코드 구현을 위한 병렬 알고리듬, 코루틴, 다형성 등도 함께 소개함
주요 항목들
- 무려 100배 저렴한 무작위 입력?! 알고리듬보다 입력 생성이 더 느릴 수도 있다는 사실
-
1% 오차로 비용은 1/40:
std::sin
같은 STL 삼각함수를 단 3줄 코드로 근사화해보기 -
지연 로직이 4배 더 빠르다고? 커스텀
std::ranges
와 반복자로 극한의 게으름 구현 -
-O3
를 넘는 컴파일러 최적화: 숨겨진 플래그와 트릭으로 성능을 2배 더 끌어올릴 수 있음 - 행렬 곱셈이 문제라고? 연산 수는 60% 적지만 3x3x3 GEMM이 4x4x4보다 70% 느릴 수 있음
- AI 스케일링의 진실? 이론적 ALU 처리량과 실제 BLAS 성능 간의 간극 측정해보기
- 조건문 몇 개가 많다고 할 수 있을까? 단 10줄 코드로 CPU 분기 예측기의 한계 실험
-
재귀가 더 좋아? 어디서
SEGFAULT
나는지 스택 깊이 직접 측정해보자 -
예외를 피해야 하는 이유?
std::error_code
나std::variant
같은 대안 써볼래? - 멀티코어 확장하려면? OpenMP, Intel oneTBB, 혹은 직접 만든 스레드 풀을 이용하는 법
- 메모리 할당 없이 JSON 처리하는 법? C++20이 더 나을까, 아니면 구식 C99 도구가 더 간단할까?
- STL의 연관 컨테이너 제대로 쓰려면 커스텀 키와 투명 비교자를 어떻게 활용할까?
-
수제 파서보다 빠른 방법이 있다면?
consteval
기반 정규표현식 엔진으로 정면 승부 - 포인터 크기는 진짜 64비트일까? 포인터 태깅을 활용해보자
-
UDP가 얼마나 많은 패킷을 드롭할까? 사용자 공간에서
io_uring
으로 웹 요청 처리까지 해보자 - Scatter-Gather로 50% 더 빠른 벡터화된 비연속 메모리 연산 구현
-
Intel oneAPI vs Nvidia CCCL?
<thrust>
와<cub>
은 뭐가 특별할까? - CUDA C++, PTX, SASS는 CPU 코드와 뭐가 다른가?
-
성능 민감한 코드라면? 인트린식, 인라인
asm
, 또는.S
파일 중 어떤 걸 선택할지 비교 - Tensor Core와 메모리 구조 — CPU와 Volta, Ampere, Hopper, Blackwell GPU는 어떻게 다를까?
- FPGA 코딩은 GPU랑 어떻게 다를까? 고수준 합성(HLS), Verilog, VHDL의 차이점은? 🔜 #36
- Encrypted Enclave란 무엇인가? Intel SGX, AMD SEV, ARM Realm의 지연시간 비교 🔜 #31
실행 방법 및 환경 설정
- Linux + GCC 환경 추천, WSL 또는 Mac의 Clang(비기본 배포판)도 사용 가능
-
CMake
,liburing
,OpenBLAS
,g++
,build-essential
설치 필요 -
less_slow
실행 파일을 빌드 후 실행하면 벤치마크 자동 수행됨
git clone https://github.com/ashvardanian/less_slow.cpp.git
cd less_slow.cpp
pip install cmake --upgrade
sudo apt install -y build-essential g++ liburing-dev libopenblas-base
cmake -B build_release -D CMAKE_BUILD_TYPE=Release
cmake --build build_release --config Release
build_release/less_slow
- CUDA 및 Intel TBB 사용 여부 선택 가능 (
-D USE_INTEL_TBB=OFF
등 플래그 사용) - 실행시 특정 벤치마크만 선택 실행하거나 JSON 저장, 출력 포맷 지정 가능
build_release/less_slow --benchmark_filter=std_sort
build_release/less_slow --benchmark_out=results.json --benchmark_format=json
성능 측정 향상 팁
- SMT 비활성화, random interleaving 사용으로 노이즈 최소화
- Google Benchmark의
--benchmark_perf_counters
옵션으로 하드웨어 성능카운터 측정 가능
sudo build_release/less_slow --benchmark_perf_counters="CYCLES,INSTRUCTIONS"
- 또는 Linux
perf
툴을 이용한 벤치마크 측정 가능
sudo perf stat taskset 0xEFFFEFFFEFFFEFFFEFFFEFFFEFFFEFFF build_release/less_slow --benchmark_filter=super_sort
프로젝트 파일 구조
- 메인 소스:
less_slow.cpp
(CPU 벤치마크 코드 중심) - 플랫폼별 최적화 파일 포함: x86/ARM용 ASM, CUDA
.cu
, PTX.ptx
코드 포함
├── less_slow.cpp # 주 벤치마크 코드
├── less_slow_amd64.S # x86 어셈블리
├── less_slow_aarch64.S # ARM 어셈블리
├── less_slow.cu # CUDA C++
├── less_slow_sm70.ptx # PTX IR (Volta)
├── less_slow_sm90a.ptx # PTX IR (Hopper)
외부 라이브러리 사용
- Google Benchmark: 성능 측정
- Intel oneTBB: 병렬 STL 백엔드
- Meta libunifex: 비동기 실행 모델
- range-v3:
std::ranges
대체 - fmt:
std::format
대체 - StringZilla:
std::string
대체 - CTRE:
std::regex
대체 - nlohmann/json, yyjson: JSON 파서
- Abseil: 고성능 컨테이너
- cppcoro: 코루틴 구현
- liburing: 리눅스 커널 우회 I/O
- ASIO: 비동기 네트워킹
- Nvidia CCCL, CUTLASS: GPU 알고리듬 및 행렬 연산
Google Benchmark 사용 팁 요약
-
BENCHMARK()
로 벤치마크 등록,->Args({x,y})
로 파라미터 전달 -
DoNotOptimize()
,ClobberMemory()
로 컴파일러 최적화 제어 -
->Iterations(n)
,->MinTime(n)
으로 반복 수 및 벤치 시간 제어 -
->Complexity(...)
,->SetComplexityN(n)
으로 시간 복잡도 지정 -
state.PauseTiming()
,ResumeTiming()
으로 타이밍 구간 직접 제어 -
state.counters[...]
로 커스텀 카운터 등록 가능
밈과 유머 요소
- 교육 자료에 기술 밈 이미지 삽입으로 흥미 유발
- 성능과 추상화의 대립, IEEE 754 부동소수점 등 유머러스하게 표현
Hacker News 의견
-
40배 빠른 삼각법: std::sin 같은 표준 라이브러리 함수를 3줄의 코드로 가속화할 수 있음
- 확장을 몇 개의 항으로 제한하여
sin(x)
를 근사할 수 있음 - 계산 비용은 줄어들지만 정확도도 감소함
- 정확도 감소는 과소평가임. [-2, 2] 범위를 벗어난 입력에 대해 매우 부정확함
- 단일 사인파 구간도 처리할 수 없으며 반복적인 특성도 다루지 못함. 쓸모없는 "최적화"임
- 확장을 몇 개의 항으로 제한하여
-
마이크로컨트롤러에서의 경험 공유
- 임베디드 시스템에서 작업 중이며, 힙은 약 256 KiB, 가장 큰 스택은 4 KiB임
- 현대적인 C++를 주로 사용하지만 모든 트릭이 모든 상황에 적합하지 않음
- CTRE는 스택 오버플로우를 피하는 한 괜찮음. HTTP 프록시 구성의 문자열을 검증하려고 시도했으나 스택 오버플로우로 인해 시스템이 충돌함
- JSON을 내부적으로 거의 사용하지 않고 자체 BSON 라이브러리를 작성함. 메모리 할당이나 단편화를 걱정할 필요가 없음
- newlib 대신 picolibc를 사용하고 C/C++ 표준 라이브러리 로케일 코드를 제거함. 프로그램 크기를 줄임
-
Abseil의 선택에 대한 의견
- 처음 등장했을 때 큰 이슈였지만, 이제는 약점을 개선한 여러 대안이 존재함
- 최근 몇 년 동안 Abseil에 대한 불만이 증가함. Google에서 핵심 라이브러리 유지 관리자의 이탈이 있었음
-
C++에서 성능을 위한 왜곡에 대한 비판
- CTRE가 좋은 결과를 준다는 것에 놀람. 더 깊이 파고들 필요가 있음
- OpenMP 및 TBB 스레드풀 벤치마크를 조사하고 Boost::ASIO 스레드풀을 추가할 수 있는지 확인하고 싶음
-
FPGA와 GPU 코딩의 차이점 및 고급 합성, Verilog, VHDL에 대한 요청
- 이 주제에 대한 우선 요청을 받고 싶음
-
비정규화된 부동소수점에 대한 새로운 정보
- GPU에서 행렬을 곱할 때 가끔 궁금해함
-
Google Benchmark 게시물에 대한 긍정적인 피드백
- 성능 벤치마킹에 대한 집중이 좋음. 저장소가 잘 구성되어 있음
-
"덜 느린 C, C++, 어셈블리 코드"에 대한 기대
- C 코드도 포함될 줄 알았으나 .cpp와 .S만 있음
- less_slow.cpp가 많은 C++ 특성을 사용함. "C"를 목록에서 제거하거나 수정이 필요함