39 pontos por GN⁺ 2025-04-21 | 1 comentários | Compartilhar no WhatsApp
  • Projeto open source para aprender técnicas de código C/C++ e assembly de alto desempenho com exemplos práticos
  • Inclui exemplos de uso de bibliotecas otimizadas no lugar da STL e várias técnicas de otimização de hardware
  • Explica diversos truques de performance, como custo de geração de entrada, aproximação de funções matemáticas, predição de desvios da CPU e paralelização multicore
  • Cobre amplamente técnicas de otimização por plataforma e até métodos de medição de benchmark, incluindo CUDA, PTX, ASM, FPGA e processamento de JSON
  • Oferece recursos de automação da execução de benchmarks e do processamento estatístico com base no Google Benchmark

Como escrever código C/C++ e assembly orientado a desempenho

  • Este projeto é uma coleção de códigos de benchmark para ajudar a desenvolver a intuição e a forma de pensar necessárias ao design de software de alto desempenho
  • Traz exemplos práticos de código para evitar bugs, problemas de segurança e gargalos de desempenho comuns no código moderno
  • Apresenta de forma sistemática técnicas práticas orientadas a performance que são difíceis de encontrar em aulas universitárias ou bootcamps
  • A maior parte do código roda em ambientes Linux baseados em GCC e Clang, com suporte parcial a Windows e macOS
  • Também apresenta algoritmos paralelos, corrotinas e polimorfismo para implementação de código de alto desempenho

Principais tópicos

  • Entradas aleatórias 100x mais baratas?! O fato de que gerar a entrada pode ser mais lento do que o próprio algoritmo
  • Erro de 1% por 1/40 do custo: aproximando funções trigonométricas da STL como std::sin em apenas 3 linhas de código
  • Lógica preguiçosa 4x mais rápida? Implementando preguiça extrema com std::ranges customizado e iteradores
  • Otimizações de compilador além de -O3: flags escondidas e truques podem extrair o dobro de performance
  • O problema é multiplicação de matrizes? Mesmo com 60% menos operações, um GEMM 3x3x3 pode ser 70% mais lento que 4x4x4
  • A verdade sobre o escalonamento de IA? Medindo a diferença entre o throughput teórico da ALU e a performance real de BLAS
  • Quantos ifs são demais? Testando os limites do preditor de desvios da CPU com apenas 10 linhas de código
  • Recursão é melhor? Vamos medir diretamente a profundidade da pilha para ver onde ocorre SEGFAULT
  • Por que evitar exceções? Que tal usar alternativas como std::error_code ou std::variant?
  • Quer escalar em multicore? Como usar OpenMP, Intel oneTBB ou um thread pool feito à mão
  • Como processar JSON sem alocação de memória? C++20 é melhor ou ferramentas antigas em C99 são mais simples?
  • Para usar bem os contêineres associativos da STL, como aproveitar chaves customizadas e comparadores transparentes?
  • E se houver algo mais rápido que um parser artesanal? Um duelo direto com um motor de regex baseado em consteval
  • O tamanho de um ponteiro é mesmo 64 bits? Vamos usar pointer tagging
  • Quanto o UDP realmente perde em pacotes? Indo até o processamento de requisições web em espaço de usuário com io_uring
  • Implementação de operações vetorizadas em memória não contígua 50% mais rápidas com Scatter-Gather
  • Intel oneAPI vs Nvidia CCCL? O que há de especial em <thrust> e <cub>?
  • CUDA C++, PTX, SASS: em que diferem do código de CPU?
  • Para código sensível a desempenho, comparação entre intrinsics, asm inline e arquivos .S para escolher a melhor opção
  • Tensor Core e estrutura de memória — como diferem CPU e GPUs Volta, Ampere, Hopper e Blackwell?
  • Como a programação para FPGA difere de GPU? Quais são as diferenças entre síntese de alto nível (HLS), Verilog e VHDL? 🔜 #36
  • O que é um Encrypted Enclave? Comparação de latência entre Intel SGX, AMD SEV e ARM Realm 🔜 #31

Como executar e configurar o ambiente

  • Recomendado: Linux + GCC; também é possível usar WSL ou Clang no Mac (distribuição não padrão)
  • É preciso instalar CMake, liburing, OpenBLAS, g++ e build-essential
  • Depois de compilar o executável less_slow, a execução dispara automaticamente os benchmarks
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  
  • É possível escolher se vai usar CUDA e Intel TBB (com flags como -D USE_INTEL_TBB=OFF)
  • Na execução, dá para selecionar apenas benchmarks específicos, salvar em JSON ou definir o formato de saída
build_release/less_slow --benchmark_filter=std_sort  
build_release/less_slow --benchmark_out=results.json --benchmark_format=json  

Dicas para melhorar a medição de desempenho

  • Desabilite SMT e use random interleaving para minimizar ruído
  • A opção --benchmark_perf_counters do Google Benchmark permite medir contadores de desempenho de hardware
sudo build_release/less_slow --benchmark_perf_counters="CYCLES,INSTRUCTIONS"  
  • Ou use a ferramenta perf do Linux para medir os benchmarks
sudo perf stat taskset 0xEFFFEFFFEFFFEFFFEFFFEFFFEFFFEFFF build_release/less_slow --benchmark_filter=super_sort  

Estrutura de arquivos do projeto

  • Fonte principal: less_slow.cpp (foco no código de benchmark para CPU)
  • Inclui arquivos de otimização por plataforma: assembly para x86/ARM, código CUDA .cu e PTX .ptx
├── less_slow.cpp           # código principal de benchmark  
├── less_slow_amd64.S       # assembly x86  
├── less_slow_aarch64.S     # assembly 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: medição de desempenho
  • Intel oneTBB: backend paralelo para STL
  • Meta libunifex: modelo de execução assíncrona
  • range-v3: substituto para std::ranges
  • fmt: substituto para std::format
  • StringZilla: substituto para std::string
  • CTRE: substituto para std::regex
  • nlohmann/json, yyjson: parsers JSON
  • Abseil: contêineres de alto desempenho
  • cppcoro: implementação de corrotinas
  • liburing: I/O em Linux sem passar pela camada tradicional do kernel
  • ASIO: rede assíncrona
  • Nvidia CCCL, CUTLASS: algoritmos de GPU e operações com matrizes

Resumo de dicas de uso do Google Benchmark

  • Registre benchmarks com BENCHMARK() e passe parâmetros com ->Args({x,y})
  • Controle otimizações do compilador com DoNotOptimize() e ClobberMemory()
  • Controle número de repetições e tempo de benchmark com ->Iterations(n) e ->MinTime(n)
  • Defina complexidade temporal com ->Complexity(...) e ->SetComplexityN(n)
  • Controle manualmente o trecho cronometrado com state.PauseTiming() e ResumeTiming()
  • É possível registrar contadores customizados com state.counters[...]

Memes e humor

  • Inserção de imagens de memes técnicos no material educacional para despertar interesse
  • Oposição entre performance e abstração, IEEE 754 de ponto flutuante etc. expressos com humor

1 comentários

 
GN⁺ 2025-04-21
Comentários no Hacker News
  • Trigonometria 40x mais rápida: dá para acelerar funções da biblioteca padrão como std::sin com 3 linhas de código

    • É possível aproximar sin(x) limitando a expansão a alguns termos
    • O custo computacional diminui, mas a precisão também cai
    • A perda de precisão está sendo subestimada. Para entradas fora do intervalo [-2, 2], fica extremamente impreciso
    • Nem sequer consegue lidar com um único intervalo da onda senoidal e também não trata sua natureza periódica. É uma "otimização" inútil
  • Compartilhando experiência com microcontroladores

    • Trabalha com sistemas embarcados, onde o heap é de cerca de 256 KiB e a maior stack é de 4 KiB
    • Usa principalmente C++ moderno, mas nem todos os truques servem para todas as situações
    • CTRE é aceitável desde que se evite stack overflow. Ao tentar validar strings de configuração de proxy HTTP, o sistema travou por causa de stack overflow
    • Quase não usa JSON internamente e escreveu sua própria biblioteca BSON. Assim, não precisa se preocupar com alocação de memória nem fragmentação
    • Usa picolibc em vez de newlib e removeu o código de locale da biblioteca padrão de C/C++. Isso reduziu o tamanho do programa
  • Opinião sobre as escolhas do Abseil

    • Quando apareceu pela primeira vez, foi um grande assunto, mas agora existem várias alternativas que melhoraram seus pontos fracos
    • Nos últimos anos, as reclamações sobre o Abseil aumentaram. Houve saída de mantenedores centrais da biblioteca no Google
  • Crítica às distorções em nome do desempenho em C++

    • Surpreso com o fato de CTRE dar bons resultados. Vale investigar mais a fundo
    • Quer analisar benchmarks de thread pools do OpenMP e do TBB e ver se é possível adicionar o thread pool do Boost::ASIO
  • Diferenças entre programação para FPGA e GPU, e pedido por conteúdo sobre síntese de alto nível, Verilog e VHDL

    • Gostaria de ver isso tratado com prioridade
  • Nova informação sobre números de ponto flutuante desnormalizados

    • Às vezes se pergunta sobre isso ao multiplicar matrizes na GPU
  • Feedback positivo sobre o post do Google Benchmark

    • O foco em benchmark de desempenho é bom. O repositório está bem organizado
  • Expectativa sobre "código C, C++ e assembly menos lento"

    • Esperava que código C também estivesse incluído, mas só há .cpp e .S
    • less_slow.cpp usa muitos recursos de C++. Seria melhor remover o "C" da lista ou ajustar isso