Less slow.cpp
lastmod 2025-04-21created 2025-04-213 edits
Learn to write less slow C/C++ code
Playing around "Less Slow" coding practices in C++ 20, C, CUDA, PTX, & Assembly, from numerics & SIMD to coroutines, ranges, exception handling, networking and user-space IO
About
- Open-source project for learning high-performance C/C++ and assembly coding techniques through practical examples
- Includes examples of using optimized libraries instead of the STL and various hardware optimization techniques
- Explains various performance tricks, such as input generation cost, approximating math functions, CPU branch prediction, and multi-core parallelization
- Broadly covers platform-specific optimization techniques for CUDA, PTX, ASM, FPGA, JSON processing, etc., as well as how to measure benchmarks
- Provides automation for running benchmarks and processing statistics, based on Google Benchmark
Writing performance-oriented C/C++ and assembly code
- This project is a collection of benchmark code that helps build the intuition and mindset needed to design high-performance software
- Covers practical coding examples for avoiding common bugs, security issues, performance bottlenecks, etc. in modern code
- Systematically introduces practical performance-oriented techniques that are hard to come across in university courses or bootcamps
- Most code runs on Linux with GCC and Clang, but Windows and macOS are partially supported
- Also introduces parallel algorithms, coroutines, polymorphism, etc. for implementing high-performance code
Key topics
- Random inputs 100x cheaper?! Input generation can be slower than the algorithm itself
- 1/40 the cost at 1% error: approximating STL trigonometric functions like std::sin in just 3 lines of code
- Lazy logic 4x faster? Implementing extreme laziness with custom std::ranges and iterators
- Compiler optimizations beyond -O3: hidden flags and tricks can double performance again
- Matrix multiplication is the problem? A 3x3x3 GEMM can be 70% slower than 4x4x4 despite 60% fewer operations
- The truth about AI scaling? Measuring the gap between theoretical ALU throughput and actual BLAS performance
- How many conditionals is too many? Testing the limits of the CPU branch predictor in just 10 lines of code
- Is recursion better? Measure the stack depth yourself to see where the SEGFAULT happens
- Why avoid exceptions? Want to try alternatives like std::error_code or std::variant?
- Scaling to multiple cores? How to use OpenMP, Intel oneTBB, or your own thread pool
- How to process JSON without memory allocation? Is C++20 better, or are old-school C99 tools simpler?
- How to use custom keys and transparent comparators to use STL associative containers properly?
- Is there a way faster than a hand-written parser? Going head-to-head with a consteval-based regular expression engine
- Are pointers really 64 bits? Let's use pointer tagging
- How many packets does UDP drop? Let's go as far as handling web requests in user space with io_uring
- Implementing 50% faster vectorized non-contiguous memory operations with Scatter-Gather
- Intel oneAPI vs Nvidia CCCL? What's special about <thrust> and <cub>?
- How do CUDA C++, PTX, and SASS differ from CPU code?
- Performance-sensitive code? Comparing which to choose: intrinsics, inline asm, or .S files
- Tensor Cores and memory architecture — how do the CPU and Volta, Ampere, Hopper, and Blackwell GPUs differ?
- How does FPGA coding differ from GPUs? What's the difference between high-level synthesis (HLS), Verilog, and VHDL? 🔜 #36
- What is an Encrypted Enclave? Comparing the latency of Intel SGX, AMD SEV, and ARM Realm 🔜 #31
External libraries used
- Google Benchmark: performance measurement
- Intel oneTBB: parallel STL backend
- Meta libunifex: asynchronous execution model
- range-v3: replacement for std::ranges
- fmt: replacement for std::format
- StringZilla: replacement for std::string
- CTRE: replacement for std::regex
- nlohmann/json, yyjson: JSON parsers
- Abseil: high-performance containers
- cppcoro: coroutine implementation
- liburing: Linux kernel-bypass I/O
- ASIO: asynchronous networking
- Nvidia CCCL, CUTLASS: GPU algorithms and matrix operations
Google Benchmark usage tips summary
- Register benchmarks with BENCHMARK(), pass parameters with ->Args({x,y})
- Control compiler optimizations with DoNotOptimize() and ClobberMemory()
- Control iteration count and benchmark time with ->Iterations(n) and ->MinTime(n)
- Specify time complexity with ->Complexity(...) and ->SetComplexityN(n)
- Control timing sections directly with state.PauseTiming() and ResumeTiming()
- Custom counters can be registered with state.counters[...]