- Proyecto open source para aprender técnicas de programación de alto rendimiento en C/C++ y ensamblador con ejemplos prácticos
- Incluye ejemplos de uso de bibliotecas optimizadas y varias técnicas de optimización de hardware en lugar de STL
- Explica varios trucos de rendimiento como costo de generación de entrada, aproximación de funciones matemáticas, predicción de saltos del CPU y paralelización multinúcleo
- Cubre ampliamente técnicas de optimización por plataforma y métodos para medir benchmarks, incluyendo CUDA, PTX, ASM, FPGA y procesamiento de JSON
- Ofrece funciones para automatizar la ejecución de benchmarks y el procesamiento estadístico basadas en Google Benchmark
Cómo escribir código C/C++ y ensamblador orientado al rendimiento
- Este proyecto es una colección de código de benchmark para ayudar a formar la intuición y la forma de pensar necesarias para diseñar software de alto rendimiento
- Presenta ejemplos prácticos para evitar bugs, problemas de seguridad y cuellos de botella de rendimiento comunes en el código moderno
- Introduce de forma sistemática técnicas reales orientadas al rendimiento que es difícil ver en clases universitarias o bootcamps
- La mayor parte del código funciona en entornos Linux basados en GCC y Clang, aunque también hay soporte parcial para Windows y macOS
- También presenta algoritmos paralelos, corrutinas y polimorfismo para implementar código de alto rendimiento
Temas principales
- ¿Entrada aleatoria nada menos que 100 veces más barata? La generación de entrada puede ser más lenta que el algoritmo
- 1% de error por 1/40 del costo: probar a aproximar funciones trigonométricas de STL como
std::sin en solo 3 líneas de código
- ¿La lógica perezosa es 4 veces más rápida? Llevar la evaluación diferida al extremo con
std::ranges personalizado e iteradores
- Optimización del compilador más allá de
-O3: con flags ocultos y trucos se puede exprimir hasta 2 veces más rendimiento
- ¿El problema es la multiplicación de matrices? Aunque hay 60% menos operaciones, un GEMM 3x3x3 puede ser 70% más lento que uno 4x4x4
- ¿La verdad sobre el escalado de la IA? Medir la brecha entre el rendimiento teórico de ALU y el rendimiento real de BLAS
- ¿Cuántos
if ya son demasiados? Probar los límites del predictor de saltos del CPU con solo 10 líneas de código
- ¿La recursión es mejor? Midamos directamente la profundidad de pila donde aparece un
SEGFAULT
- ¿Por qué conviene evitar excepciones? ¿Qué tal usar alternativas como
std::error_code o std::variant?
- ¿Quieres escalar a multinúcleo? Cómo usar OpenMP, Intel oneTBB o un thread pool hecho a mano
- ¿Cómo procesar JSON sin asignación de memoria? ¿Será mejor C++20 o una herramienta antigua de C99 más simple?
- Para usar bien los contenedores asociativos de STL, cómo aprovechar claves personalizadas y comparadores transparentes
- ¿Y si hubiera una forma más rápida que un parser casero? Ir de frente con un motor de expresiones regulares basado en
consteval
- ¿El tamaño de los punteros realmente es de 64 bits? Pongamos a trabajar el pointer tagging
- ¿Cuántos paquetes puede perder UDP? Hasta procesar solicitudes web desde espacio de usuario con
io_uring
- Implementación de operaciones vectorizadas sobre memoria no contigua 50% más rápidas con Scatter-Gather
- ¿Intel oneAPI vs Nvidia CCCL? ¿Qué tienen de especial
<thrust> y <cub>?
- CUDA C++, PTX, SASS: ¿en qué se diferencian del código para CPU?
- ¿Código sensible al rendimiento? Comparación de cuándo elegir intrinsics,
asm inline o archivos .S
- Tensor Core y estructura de memoria — ¿en qué se diferencian CPU y las GPU Volta, Ampere, Hopper y Blackwell?
- ¿En qué se diferencia programar FPGA de GPU? ¿Cuáles son las diferencias entre síntesis de alto nivel (HLS), Verilog y VHDL? 🔜 #36
- ¿Qué es un Encrypted Enclave? Comparación de latencia entre Intel SGX, AMD SEV y ARM Realm 🔜 #31
Cómo ejecutarlo y configurar el entorno
- Se recomienda Linux + GCC; también se puede usar WSL o Clang en Mac (distribución no predeterminada)
- Es necesario instalar
CMake, liburing, OpenBLAS, g++ y build-essential
- Si compilas y ejecutas el binario
less_slow, los benchmarks se correrán automáticamente
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
- Se puede elegir si usar CUDA e Intel TBB (con flags como
-D USE_INTEL_TBB=OFF)
- Al ejecutar, puedes seleccionar solo ciertos benchmarks, guardar en JSON o definir el formato de salida
build_release/less_slow --benchmark_filter=std_sort
build_release/less_slow --benchmark_out=results.json --benchmark_format=json
Consejos para mejorar la medición de rendimiento
- Desactivar SMT y usar random interleaving para minimizar el ruido
- Con la opción
--benchmark_perf_counters de Google Benchmark se pueden medir contadores de rendimiento de hardware
sudo build_release/less_slow --benchmark_perf_counters="CYCLES,INSTRUCTIONS"
- O también se puede medir el benchmark usando la herramienta
perf de Linux
sudo perf stat taskset 0xEFFFEFFFEFFFEFFFEFFFEFFFEFFFEFFF build_release/less_slow --benchmark_filter=super_sort
Estructura de archivos del proyecto
- Fuente principal:
less_slow.cpp (centrado en código de benchmark para CPU)
- Incluye archivos de optimización por plataforma: ensamblador para x86/ARM, código CUDA
.cu y PTX .ptx
├── less_slow.cpp # Código principal de benchmark
├── less_slow_amd64.S # Ensamblador x86
├── less_slow_aarch64.S # Ensamblador ARM
├── less_slow.cu # CUDA C++
├── less_slow_sm70.ptx # PTX IR (Volta)
├── less_slow_sm90a.ptx # PTX IR (Hopper)
Uso de bibliotecas externas
- Google Benchmark: medición de rendimiento
- Intel oneTBB: backend paralelo para STL
- Meta libunifex: modelo de ejecución asíncrona
- range-v3: reemplazo de
std::ranges
- fmt: reemplazo de
std::format
- StringZilla: reemplazo de
std::string
- CTRE: reemplazo de
std::regex
- nlohmann/json, yyjson: parsers de JSON
- Abseil: contenedores de alto rendimiento
- cppcoro: implementación de corrutinas
- liburing: I/O de bypass del kernel de Linux
- ASIO: networking asíncrono
- Nvidia CCCL, CUTLASS: algoritmos de GPU y operaciones matriciales
Resumen de consejos para usar Google Benchmark
- Registrar benchmarks con
BENCHMARK() y pasar parámetros con ->Args({x,y})
- Controlar la optimización del compilador con
DoNotOptimize() y ClobberMemory()
- Controlar número de iteraciones y tiempo del benchmark con
->Iterations(n) y ->MinTime(n)
- Especificar complejidad temporal con
->Complexity(...) y ->SetComplexityN(n)
- Controlar manualmente la sección cronometrada con
state.PauseTiming() y ResumeTiming()
- Se pueden registrar contadores personalizados con
state.counters[...]
Memes y humor
- Inserta imágenes de memes técnicos en el material educativo para hacerlo más atractivo
- Expresa de forma humorística la oposición entre rendimiento y abstracción, así como el punto flotante IEEE 754
1 comentarios
Opiniones en Hacker News
Trigonometría 40 veces más rápida: se pueden acelerar funciones de biblioteca estándar como
std::sincon 3 líneas de códigosin(x)limitando la expansión a unos pocos términosExperiencia compartida en microcontroladores
Opinión sobre la elección de Abseil
Crítica a las distorsiones en C++ por rendimiento
Diferencias entre programar para FPGA y GPU, y solicitud de contenido sobre síntesis avanzada, Verilog y VHDL
Información nueva sobre números de punto flotante desnormalizados
Retroalimentación positiva sobre la publicación de Google Benchmark
Expectativas sobre "código menos lento en C, C++ y ensamblador"
.cppy.Sless_slow.cppusa muchas características de C++. Habría que quitar la "C" de la lista o corregirlo