Teu progresso
0 / 83 módulos0%
Estágio 01 · 01-14
Bloqueado01-01 cobriu modelo de computação de alto nível. Mas decisões reais de performance, por que esse loop é 10x mais lento, por que o profiler aponta cache misses, por que threads parecem rápidas em um core e lentas em outro, exigem entender CPU por dentro. Pipelining, branch prediction, out-of-order execution, store buffers, MESI, NUMA não são tópicos acadêmicos: governam latência de toda linha de código que você escreve.
Engenheiro Pleno geralmente trata CPU como caixa-preta. Senior+ que trabalha com performance, sistemas, baixo nível, ou ML inference precisa entender. Sem isso, profiler é caixa de caracteres incompreensível, e otimizações ficam superstição. Com isso, você lê flamegraph e sabe por quê sua hot loop não vetoriza.
Este módulo é mecânico-simpático: arquitetura Intel/ARM moderna, hierarquia de cache (L1/L2/L3, TLB), branch prediction, speculative execution, prefetching, SIMD, NUMA, store buffers, memory ordering em x86 vs ARM (conexão 01-11), memory consistency. Plus PMU (performance monitoring units) e como usar perf pra ler counters reais.
CPU clássica fetch → decode → execute → memory → writeback (5-stage RISC pipeline). Modernas têm 14-20+ stages.
Pipelining permite múltiplas instruções "em voo" simultaneamente. Throughput melhora; latência por instrução individual permanece similar.
Hazards:
Compilador e CPU coordenam pra reduzir hazards (instruction scheduling, register renaming).
CPUs modernas fazem out-of-order execution: reordenam instruções dinamicamente pra preencher pipeline. Reorder Buffer (ROB) commit em ordem original.
Superscalar: múltiplas instruções por ciclo via múltiplas execution units (ALUs, FPUs, load/store ports). x86 modern (Intel Golden Cove) faz 6+ instruções/ciclo em hot path.
Implicação: ILP (Instruction-Level Parallelism) é grátis se compilador e código permitem.
Branches custam ciclos se misspeculados (pipeline flush). CPU prediz direção via:
Misprediction = 10-20 ciclos perdidos em pipelines profundos. Reduce com:
std::min, ternary, bitops).Spectre (2018): exploit de branch predictor pra ler memória além de bounds. CPU specula past bounds check; embora rollback, traces ficam em cache. Mitigation patches custaram 5-30% performance.
Latency aproximada (Intel x86):
Cache organizada em lines (64 bytes x86). Set-associative (8-16 ways em L1).
Implicação: leitura de byte custa 64 bytes. Loop em array sequencial (stride 1) = quase free. Random access = penalty.
Profile reveal misses via perf stat -e cache-misses.
Virtual → physical address translation cached em TLB. Miss = page table walk (custo significativo).
Page sizes: 4KB default, 2MB / 1GB huge pages disponíveis. Huge pages reduzem TLB pressure pra workloads com large memory.
madvise(MADV_HUGEPAGE) em Linux. JVM, ClickHouse, Redis suportam huge pages.
Hardware prefetcher detecta padrões (stride) e busca cache lines antes de uso. Funciona pra acessos lineares.
Software prefetch: _mm_prefetch (intrinsic), __builtin_prefetch (GCC). Útil em estruturas com indireção (linked list, hash table).
Registers wide (128/256/512 bit) processam múltiplos valores. Sets x86: SSE, AVX, AVX2, AVX-512. ARM: NEON, SVE.
Auto-vectorization: compiladores tentam. Hand-written via intrinsics (_mm256_add_ps).
Speedup 4-16x em loops vetorizáveis (numeric, hashing, image, audio, ML inference). Wide use em libs (BLAS, SIMD-JSON, ClickHouse vectorized engine).
Condições pra auto-vectorization acontecer:
x[i] = x[i-1] + 1 não vetoriza).restrict / noalias informando compilador que ponteiros não overlap.Verifique com gcc -O3 -fopt-info-vec / clang -Rpass=loop-vectorize antes de assumir.
Data layout: AoS vs SoA
Mesmos dados, layouts diferentes mudam tudo:
// Array of Structures (AoS): natural pra OO, mata SIMD.
struct Particle { float x, y, z, m; } a[N];
// Structure of Arrays (SoA): SIMD-friendly.
struct {
float x[N];
float y[N];
float z[N];
float m[N];
} s;
Loop somando x[i] em AoS lê 16B mas usa só 4B útil por iteração (waste de banda + cache). Em SoA, AVX2 carrega 8 floats x contíguos em um único registro, vetoriza limpo. ECS (game engines, Bevy/Unity DOTS) é SoA por princípio. ClickHouse, Apache Arrow, Pandas (interno) são SoA. Cruza com 01-04 §2.2 (cache locality) e 01-04 §2.4 (Robin Hood hash table SoA quando perf é crítica).
Custo invisível: SIMD width crescendo (AVX-512 em 512b) traz frequency throttling em x86 — códigos AVX-512 derrubam clock do core, às vezes anulando o ganho. Mensure ciclo a ciclo (PMU) antes de acreditar em "AVX-512 é 8x mais rápido".
Two logical threads compartilham um core físico. Compartilham execution units; cada um seu register file e arquivo de estado.
Ganhos: ~20-30% em workloads heterogêneos (memory-bound thread libera ALUs pro outro). Não 2x.
Em workloads CPU-bound puros, SMT pode degradar. Em containerized, garbage collection threads se beneficiam.
x86 TSO (Total Store Order): stores não reordenam entre si; loads não reordenam entre si; mas store-then-load podem (StoreLoad).
ARM/POWER: relaxed; quase tudo pode reordenar. Programador insere barriers (DMB, DSB).
Implicação prática: código C++ que "funciona" em x86 frequentemente quebra em ARM se sync primitives mal usadas. Migrações cloud x86 → Graviton ARM expuseram bugs latentes.
Stores não vão direto a cache. Store buffer (10-50 entries) coalesce e escreve em batch.
Implicação: thread A store, thread B load same address, A pode estar no store buffer, B vê stale do cache. (Origem do exemplo §2.2 01-11.)
Servers multi-socket: cada socket com memory controller dedicado. Acesso a memory de outro socket via interconnect (UPI / Infinity Fabric) = penalty.
NUMA-aware:
Apps single-socket ignoram. DBs grandes (Postgres, ClickHouse, Cassandra) têm tuning NUMA.
perfCada core tem counters de hardware:
perf stat -d ./program: básico. perf record -F 99 -g; perf report: profiling.
perf top: live view.
Linux perf é canônico. Outros: VTune (Intel), AMD μProf, eBPF (Brendan Gregg's work).
Plot performance (FLOPS) vs arithmetic intensity (FLOPS/byte memory):
Use pra entender se workload está saturando memory ou compute. ML inference frequentemente memory-bound (large weights); ML training compute-bound (FLOPs heavy).
GPU é 1000s de cores SIMT (Single Instruction, Multiple Threads), high latency tolerated via massive parallelism.
CPU optimized for low-latency single thread + small parallelism.
Workloads diferem. ML training = GPU. Database OLTP = CPU. Mix = consciência arquitetural.
Modern CPUs throttle clocks sob calor. Boost clock breve > sustained clock. Server-room workloads sustained.
Energy: dynamic + static. Race-to-idle (rapid burst then sleep) frequently mais eficiente que sustained low.
ARM em mobile/cloud: melhor perf/watt. Datacenter shifts pra ARM (AWS Graviton, Azure Cobalt, GCP Axion) por economics.
Práticas concretas:
__builtin_expect, [[likely]]/[[unlikely]] C++20).Código que respeita arquitetura pode ser 10-100x mais rápido sem mudar algoritmo.
Sample command:
perf stat -e cycles,instructions,cache-misses,branch-misses,L1-dcache-load-misses ./mybench
Output útil:
PMU é fonte de verdade sobre o que CPU está fazendo. Profiling sem PMU é guess.
Cruza com: 01-13 §2.17 (V8 Maglev/TurboShaft pipeline — JIT moderno aproveita μarch features), 01-07 §2.12 (V8 internals 2026).
Você precisa, sem consultar:
perf stat mentalmente: que counters indicam o quê.Microbenchmarks instrumentados com PMU revelando cache, branch, NUMA effects.
Linguagem: Rust ou C (acesso direto a intrinsics).
if a[i] > threshold then x else y.f32. Versão escalar vs auto-vectorized vs intrinsics AVX2.analysis.md:
perf stat outputs.perf (Linux) ou Instruments (macOS) ou similar.-O2/-O3 -march=native).perf docs, eBPF docs.Threshold de Maestria
Acerte todas as 5 pra marcar o módulo como concluído. Sem pressa, sem timer. Tudo fica salvo no teu navegador.
Q1Por que iterar um array ordenado é tipicamente muito mais rápido que iterar o mesmo array embaralhado num loop com `if a[i] > threshold`?
Q2Qual a estimativa de latência relativa entre L1 cache, L3 cache e DRAM em CPU x86 moderna?
Q3Por que false sharing degrada performance mesmo sem locks ou data races verdadeiras?
Q4Que condição IMPEDE a auto-vetorização de um loop por compiladores como gcc/clang?
Q5Por que SoA (Structure of Arrays) costuma vencer AoS (Array of Structures) em hot loops numéricos?
Destrava
01-14 é prereq dos seguintes módulos: