Blog • Artigo
    CPUGPUNVIDIA

    A Escolha de Hardware é uma Decisão de Produto, Não de Infraestrutura

    Existe uma conversa que acontece em quase toda empresa que começa a operar modelos de linguagem em produção. Ela começa como uma discussão técnica sobre GPUs versus TPUs, custo de serving e throughput, mas invariavelmente termina no mesmo lugar: perceber que a escolha de hardware define o que o produto pode prometer para o usuário final.

    Alexsander
    AlexsanderEngenheiro de Software
    Mar 12, 2026
    18 min de leitura
    A Escolha de Hardware é uma Decisão de Produto, Não de Infraestrutura

    Latência de 8ms ou 80ms não é uma métrica de infraestrutura. É a diferença entre uma experiência que parece instantânea e uma que parece lenta. E essa diferença nasce de decisões tomadas muito antes do código de serving ser escrito: na arquitetura do chip, no compilador que mapeia o grafo computacional para o silício, e na estratégia de batching que determina como requisições concorrentes compartilham o hardware.

    Esse artigo é sobre essa camada. Não é um survey de hardware. É uma análise de trade-offs para quem precisa tomar decisões que afetam produto, custo e escala simultaneamente.


    A Operação Fundamental: Por que MatMul Define Tudo

    Para entender por que o hardware importa, preciso partir do núcleo computacional de qualquer rede neural: a multiplicação de matrizes (MatMul). Independente de estarmos falando de Transformers, CNNs ou arquiteturas de state space como Mamba, a operação que domina o custo computacional é sempre a mesma: o produto entre o tensor de entrada e a matriz de pesos de cada camada.

    Código
    Output = Input Tensor × Weight Matrix
    [ n × d ] × [ d × k ] → [ n × k ]
    

    Em um modelo de linguagem, essa operação ocorre em cada camada de atenção (Q, K, V projections e output projection) e em cada MLP block, para cada token no batch. Num modelo de 70B parâmetros com 80 camadas, um único forward pass envolve centenas de operações de MatMul sobre matrizes de dimensão 8192 x 8192 ou maior.

    O custo computacional de um forward pass pode ser estimado como:

    Código
    FLOPs ≈ 2 × N × T
    

    Onde N é o número de parâmetros do modelo e T é o número de tokens processados. Para um modelo de 70B gerando um token com prefill de 1024 tokens, estamos falando de aproximadamente 1.4 x 10^14 FLOPs por requisição. A latência aceitável em produção para o primeiro token (TTFT, Time to First Token) é tipicamente abaixo de 500ms, e para tokens subsequentes (TPOT, Time Per Output Token) abaixo de 50ms para experiências interativas fluidas.

    Isso não é uma meta de engenharia. É uma restrição de produto. E ela determina diretamente qual hardware é viável.

    "

    Fonte: Hoffmann et al., "Training Compute-Optimal Large Language Models" (Chinchilla, DeepMind, 2022) estabelece a relação entre FLOPs de treinamento e parâmetros. Para inferência, a estimativa 2xNxT é derivada diretamente do paper e amplamente usada na literatura de serving.


    CPUs: O Limite Arquitetural do Propósito Geral

    A CPU moderna é projetada para minimizar latência em tarefas sequenciais com fluxo de controle complexo. Sua arquitetura combina poucos núcleos de alta frequência (tipicamente 8 a 96 em servidores AMD EPYC ou Intel Xeon de última geração), cache hierárquico profundo (L1/L2/L3 somando dezenas de MB), branch prediction com acurácia acima de 95%, e execução out-of-order com janelas de instruções de centenas de operações.

    Para workloads com dependências de dados irregulares, lógica de controle complexa e acesso a estruturas de dados dinâmicas, essa arquitetura é imbatível. Mas para MatMul densa, ela esbarra em dois limites fundamentais que não são resolvíveis com mais clock ou mais cache.

    O primeiro é o arithmetic intensity insuficiente. MatMul tem arithmetic intensity de O(n) para matrizes nxn: a proporção entre operações de ponto flutuante e bytes movidos da memória cresce com o tamanho da matriz, mas numa CPU a largura de banda de memória (tipicamente 200-400 GB/s para DDR5 em servidores) cria um gargalo estrutural antes que os núcleos sejam saturados.

    O segundo é o paralelismo limitado. Mesmo com AVX-512 (512 bits de SIMD, 16 floats FP32 simultâneos por núcleo) e 96 núcleos físicos, o throughput teórico máximo de um Xeon de ponta fica em torno de 4-6 TFLOPS em FP32. Uma GPU de entrada de servidor supera isso por um fator de 50x.

    Código
    // O problema não é o algoritmo. É o hardware map.
    // BLAS otimizado (OpenBLAS, MKL) usa tiling e SIMD,
    // mas o teto de throughput permanece ordens de magnitude abaixo de GPU.
    
    // Intel MKL cblas_sgemm — melhor caso possível em CPU:
    cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                4096, 4096, 4096,
                1.0f, A, 4096, B, 4096, 0.0f, C, 4096);
    // Tempo em Xeon Platinum 8480+ (60 cores): ~6.8s
    // Mesmo resultado em H100 SXM5: ~0.7ms
    // Razão: ~9700x
    

    A CPU continua sendo indispensável no pipeline de serving: tokenization, roteamento de requisições, pré e pós-processamento, decoding de logits e orquestração geral rodam eficientemente em CPU. O erro é colocar o forward pass do modelo nela.


    GPUs: Por que o Ecossistema Importa Tanto quanto o Silício

    A GPU foi redesenhada para IA a partir de 2017, quando a NVIDIA lançou a arquitetura Volta com as Tensor Cores, unidades dedicadas para operações de MatMul em precisão mista. Mas o que tornou as GPUs dominantes para IA não foi apenas o hardware: foi o ecossistema de software construído ao redor dele.

    Uma H100 SXM5 possui 16.896 CUDA cores e 528 Tensor Cores de quarta geração, organizados em 132 Streaming Multiprocessors. A memória HBM3 de 80 GB oferece bandwidth de 3.35 TB/s, com throughput de pico de 3.958 TFLOPS em FP8 e 1.979 TFLOPS em FP16 via Tensor Cores. O NVLink 4.0 permite bandwidth de 900 GB/s entre GPUs no mesmo servidor, crítico para tensor parallelism em modelos que não cabem numa única GPU.

    Mas o que torna a GPU realmente poderosa em produção é a camada de software:

    FlashAttention-2 e 3 (Dao et al., 2022/2023) reescreve o attention mechanism para minimizar acesso à HBM, fundindo operações e trabalhando em SRAM. O resultado é uma redução de 2-4x no tempo de attention e 5-20x na memória necessária para sequências longas. Sem isso, modelos com contexto de 128k tokens seriam simplesmente inviáveis economicamente.

    cuBLAS e cuDNN fornecem implementações de MatMul e convoluções otimizadas para cada geração de GPU NVIDIA, com suporte a quantização INT8 e FP8 com correção de escala por tensor ou por canal.

    NCCL (NVIDIA Collective Communications Library) implementa AllReduce, AllGather e ReduceScatter otimizados para topologias NVLink/InfiniBand, base de todo framework de training distribuído.

    Código
    // FlashAttention-3: o attention block inteiro funde em um único kernel
    // Evita materializar a matriz NxN de atenção em HBM
    
    // Pseudocódigo do que acontece internamente:
    // 1. Carrega bloco de Q da HBM para SRAM
    // 2. Para cada bloco de K,V: computa QK^T em SRAM, aplica softmax online
    // 3. Acumula output em SRAM
    // 4. Escreve resultado final na HBM uma única vez
    
    // Resultado: O(N) de uso de memória vs O(N²) da attention naive
    // Speedup de 1.5-3x sobre FlashAttention-2 em H100 (Dao, 2023)
    

    A liberdade arquitetural da GPU é o que mantém o ecossistema de pesquisa inteiro rodando sobre ela. Mamba, RWKV, Mixture-of-Experts com roteamento dinâmico, attention com sparsidade aprendida, todos rodam em GPU sem modificação de hardware. Isso tem um custo: a GPU é um hardware de propósito semi-geral, e paga um overhead de scheduling e sincronização que um chip especializado não paga.


    TPUs: Quando a Especialização Vira Vantagem Competitiva

    O TPU foi a resposta do Google a uma constatação específica: em 2015, se cada usuário do Google usasse reconhecimento de fala por apenas 3 minutos por dia, a empresa precisaria dobrar sua capacidade de data centers inteira só para rodar as redes neurais necessárias. CPUs e GPUs disponíveis à época não resolveriam o problema dentro das restrições de energia e custo.

    A solução foi construir um chip do zero para executar especificamente uma operação: multiplicação de matrizes em inteiros de 8 bits (INT8), com os números representados em formato de ponto fixo. O resultado foi o TPU v1, descrito no paper original de Jouppi et al. (2017) no ISCA.

    O componente central é o systolic array: uma grade de 256x256 unidades de multiplicação-acumulação (MACs) que totaliza 65.536 MACs operando em paralelo. O nome vem da analogia com o sistema circulatório: os dados fluem de forma rítmica e coordenada através da grade, com cada MAC recebendo dados dos vizinhos, computando e passando o resultado adiante, sem nunca precisar ir buscar operandos na memória principal durante a computação.

    Código
    Systolic Array — fluxo de dados para MatMul A × B = C:
    
    Pesos de B são pré-carregados nas colunas do array (weight stationary)
    Ativações de A entram pela esquerda, fluem para a direita
    Resultados parciais acumulam de cima para baixo
    
    Ciclo 1:  A[0,0] entra → MAC[0,0] computa A[0,0]*B[0,0]
    Ciclo 2:  A[0,0] → MAC[0,1], A[1,0] → MAC[0,0]
    Ciclo 3:  A[0,0] → MAC[0,2], A[1,0] → MAC[0,1], A[2,0] → MAC[0,0]
    ...
    
    Resultado: 65.536 MACs operando simultaneamente sem acesso à memória
    durante a computação. Zero latência de memória no caminho crítico.
    

    Essa arquitetura tem uma consequência importante e pouco discutida: o compilador XLA (Accelerated Linear Algebra) precisa conhecer as formas exatas dos tensores em tempo de compilação para fazer o layout de memória e o mapeamento para o systolic array de forma otimizada. Isso significa que mudanças na forma de um tensor durante o forward pass (dynamic shapes) são problemáticas para TPUs do ponto de vista de performance, e às vezes impossíveis sem recompilação.

    Código
    # JAX + XLA: o compilador analisa o grafo inteiro antes de executar
    import jax
    import jax.numpy as jnp
    
    # jit compila a função para o hardware alvo (TPU, GPU ou CPU)
    # XLA faz: fusão de operações, layout de memória, tiling otimizado
    @jax.jit
    def transformer_layer(x, w_q, w_k, w_v, w_o):
        q = jnp.dot(x, w_q)  # XLA funde com operações subsequentes
        k = jnp.dot(x, w_k)  # quando possível, evitando roundtrips HBM
        v = jnp.dot(x, w_v)
        scores = jnp.dot(q, k.T) / jnp.sqrt(q.shape[-1])
        attn = jax.nn.softmax(scores)
        return jnp.dot(jnp.dot(attn, v), w_o)
    
    # XLA analisa esse grafo e pode:
    # 1. Reordenar operações para melhor uso do systolic array
    # 2. Fundir dot + softmax em um único kernel
    # 3. Escolher layout de memória (row-major vs col-major) por tensor
    # 4. Particionar automaticamente entre chips em multi-TPU
    
    # Limitação crítica: shapes devem ser estáticos em compile time
    # Padding de sequences para potências de 2 é prática padrão em TPU
    

    O TPU v4 oferece 275 TFLOPS por chip em BF16, com TDP de 170W versus 700W do H100 SXM5. A razão de performance-por-watt é o argumento central para TPUs em produção de larga escala: para um workload de serving estável com arquitetura de modelo fixada, o custo de energia pode ser 3-4x menor que em GPUs equivalentes. Num data center operando 24/7 com milhares de chips, essa diferença muda a estrutura de custo do produto.

    "

    Fonte: Jouppi et al., "In-Datacenter Performance Analysis of a Tensor Processing Unit" (Google, ISCA 2017). Norrie et al., "The Design Process for Google's Training Chips: TPUv2 and TPUv3" (IEEE Micro, 2021). Specs do TPU v4 via Google Cloud documentation.

    A limitação real dos TPUs fora do Google é o atrito de ecossistema. O toolchain JAX/XLA tem curva de aprendizado significativa para times acostumados com PyTorch. Modelos com dynamic shapes (como decodificação autoregressiva com batch sizes variáveis) requerem técnicas específicas como bucketing de sequence lengths ou XLA dynamic shapes experimental. E o suporte a novas arquiteturas que saem de pesquisa pode levar semanas ou meses para ser otimizado no compilador.


    Comparativo com Fontes: Os Números Reais

    MétricaCPU (Xeon 8480+)GPU (H100 SXM5)TPU v4
    Peak FP16/BF16 TFLOPS~4 (com AMX)1.979275
    Memory Bandwidth307 GB/s (DDR5)3.35 TB/s (HBM3)1.2 TB/s (HBM)
    TDP350W700W170W
    TFLOPS/Watt (BF16)0.0112.831.62
    MatMul 4096x4096 FP16~6.8s~0.7ms~0.3ms
    Custo por hora (cloud)~$0.10 (96 vCPU)~$3.50 (A3 GCP)~$3.22 (v4 GCP)
    "

    Fontes: NVIDIA H100 Datasheet (NVIDIA, 2023). Intel Xeon 8480+ spec sheet. Google TPU v4 documentation (cloud.google.com). Benchmarks de MatMul medidos com NVIDIA NSight e JAX benchmark suite, reportados em Chowdhery et al. "PaLM" (2022) e em benchmarks públicos do MLPerf Inference v3.1 (2023).

    A coluna de custo por hora é enganosa isolada: o que importa é o custo por token gerado, que depende do MFU (Model FLOP Utilization) atingido em produção. Um H100 com 30% de MFU custa mais por token do que um A100 com 55% de MFU. A especialização do TPU permite MFU mais consistentemente alto para workloads regulares justamente porque o compilador tem mais informação para otimizar.


    O Pipeline Real: Prefill, Decode e o Problema do KV Cache

    A versão simplificada do pipeline de LLM serving esconde o problema mais importante de engenharia nessa área. O forward pass de um LLM em inferência tem dois regimes computacionais fundamentalmente diferentes, e tratá-los da mesma forma é o erro mais comum que vejo em implementações de primeiro corte.

    Prefill processa todos os tokens do prompt em paralelo. É compute-bound: o hardware está saturado com MatMul, e a performance é dominada pelos TFLOPS disponíveis. Um prompt de 1024 tokens pode ser processado numa única operação de MatMul com matrizes grandes.

    Decode gera um token de cada vez, condicionado em todos os tokens anteriores. É memory-bandwidth-bound: a cada step, precisamos carregar todos os pesos do modelo da HBM para os núcleos de computação, para processar um único vetor de dimensão D. O arithmetic intensity cai para O(1) por byte carregado. Aqui, o que importa não é TFLOPS, é GB/s de bandwidth de memória.

    Código
    Pipeline completo de LLM serving:
    
    [Request] → Load Balancer → Prefill Workers → Decode Workers → [Response]
                                     |                  |
                               Compute-bound      Memory-bound
                               (GPU/TPU saturados  (bandwidth-limited,
                                em MatMul)          1 token/step)
    
    KV Cache: armazena chaves e valores de atenção de todos os tokens
              já processados, evitando recomputação a cada step.
              Crescimento: O(layers × heads × seq_len × d_head × 2 × dtype_bytes)
              Para LLaMA-70B com seq_len=4096 em FP16: ~35 GB por requisição
    

    O KV cache é o gargalo de memória que define a capacidade de concorrência do sistema. Em produção, o estado da arte é o PagedAttention (vLLM, Kwon et al. 2023), que gerencia o KV cache como páginas de memória virtual, permitindo compartilhamento entre requisições com prefixes comuns e eliminando a fragmentação que desperdiçava tipicamente 60-80% da memória em implementações ingênuas.

    Continuous batching (também chamado de iteration-level scheduling) é a outra otimização fundamental. Em vez de esperar todas as requisições de um batch terminarem antes de iniciar novas (static batching), novas requisições são inseridas no batch a cada step de decode, quando slots ficam disponíveis. O resultado é utilização de hardware 2-5x maior em workloads com distribuição realista de comprimentos de resposta.

    Código
    # Pseudocódigo de continuous batching (simplificado)
    # Implementado em vLLM, TensorRT-LLM, SGLang
    
    running_batch = []
    waiting_queue = []
    
    while True:
        # A cada step de decode:
        step_outputs = model.forward(running_batch)  # Um step para todas as seqs
    
        for i, seq in enumerate(running_batch):
            if step_outputs[i].is_eos or seq.reached_max_len:
                running_batch.remove(seq)
                output_queue.put(seq.generated_tokens)
    
        # Preenche slots vazios com novas requisições
        while len(running_batch) < max_batch_size and waiting_queue:
            new_seq = waiting_queue.pop(0)
            # Aloca páginas de KV cache para a nova sequência
            kv_cache_manager.allocate(new_seq)
            running_batch.append(new_seq)
    

    Speculative decoding (Leviathan et al., 2023) é a otimização mais elegante: usa um modelo draft pequeno e rápido para propor múltiplos tokens, e o modelo principal verifica todos em paralelo num único forward pass. Quando os tokens são aceitos (o que acontece a taxa alta para texto previsível), o sistema efetivamente gera vários tokens pelo custo de um. Em workloads com sequências longas e previsíveis, isso pode reduzir latência em 2-3x.

    A escolha de hardware afeta diretamente qual dessas otimizações é viável. Speculative decoding, por exemplo, é mais eficiente em GPUs onde a flexibilidade de batch size variável é nativa. PagedAttention foi desenvolvido originalmente para CUDA. Adaptar essas técnicas para TPU exige implementações específicas em XLA, com restrições adicionais de static shapes.


    MFU: A Métrica que Mais Importa e Quase Ninguém Mede Direito

    Model FLOP Utilization é a proporção entre os FLOPs efetivamente realizados na computação do modelo e o throughput de pico teórico do hardware. É a métrica mais honesta de eficiência de um sistema de serving.

    Código
    MFU = (FLOPs observados por segundo) / (Peak TFLOPS do hardware)
        = (tokens_por_segundo × FLOPs_por_token) / Peak_TFLOPS
    

    Valores típicos em produção: 30-45% em GPUs com implementação cuidadosa, 50-65% com FlashAttention e TensorRT-LLM otimizado para o modelo específico. TPUs em workloads regulares frequentemente atingem 55-70% de MFU porque o compilador XLA tem mais liberdade para otimizar o mapeamento para o systolic array.

    O ponto que quero fazer de forma explícita: um H100 com 25% de MFU tem throughput efetivo equivalente a um A100 com 50% de MFU, ao dobro do custo de hardware e energia. A maioria das implementações de primeiro corte que vejo em empresas opera com MFU na faixa de 15-30%, deixando a maior parte do hardware pago ocioso.

    As causas mais comuns de MFU baixo em produção: static batching com batch sizes pequenos, KV cache ineficiente causando OOM frequente e redução forçada de batch size, falta de fusão de kernels (cada operação do Transformer executando como kernel separado com overhead de launch), e tensor parallelism mal configurado com AllReduce dominando o tempo de comunicação.

    "

    Fonte: A métrica MFU e análise de valores típicos foi formalizada em Chowdhery et al., "PaLM: Scaling Language Modeling with Pathways" (Google, 2022). Análise de causas de MFU baixo baseada em Rajbhandari et al., "DeepSpeed-Inference" (Microsoft, SC21) e documentação do vLLM (2023).


    Próxima Geração: Co-design Como Norma

    A separação entre hardware, compilador e modelo está se dissolvendo. O Blackwell (B100/B200) da NVIDIA foi co-desenvolvido com os times de LLM: o FP4 Tensor Core, o NVLink Switch com 1.8 TB/s de bandwidth biseccional e o novo Transformer Engine são respostas diretas a profiles de workload coletados de clientes operando GPT-4 e similares em escala.

    O Google TPU v5p triplicou os TFLOPS do v4 mantendo o consumo energético similar, usando systolic arrays maiores e HBM3e. O TPU v5e reduziu o custo por chip para targets de serving de menor escala, reconhecendo que training e inferência têm profiles de hardware ideais distintos.

    O Groq LPU elimina o dynamic scheduling completamente em favor de execução determinística: o compilador MLIR planeja a execução de cada operação em cada ciclo de clock, eliminando o overhead de scheduling que consome parte do throughput de GPU. O resultado é jitter de latência próximo de zero, que para aplicações em tempo real é às vezes mais valioso do que throughput médio alto.

    O que muda para engenheiros: arquiteturas de modelo precisam ser co-desenvolvidas levando em conta o hardware alvo. Mamba e RWKV foram parcialmente motivadas pelo custo de atenção em sequências longas numa GPU. Ring Attention foi desenvolvida para escalar contexto em clusters de TPU onde o bandwidth inter-chip é alto e simétrico. A pergunta "qual hardware vamos usar" precisa ser feita junto com "qual arquitetura vamos treinar", não depois.


    Conclusão: Hardware é Estratégia

    A escolha entre CPU, GPU e TPU não é uma decisão de infraestrutura que pode ser delegada para o time de plataforma. É uma decisão que define o envelope de custo-latência do produto, determina quais otimizações de serving são viáveis, e influencia diretamente quais arquiteturas de modelo fazem sentido explorar.

    CPUs para orquestração, tokenization e tudo que envolve fluxo de controle complexo. GPUs para experimentação, modelos em evolução rápida e workloads que precisam de flexibilidade arquitetural. TPUs para serving em larga escala de modelos estáveis, onde a vantagem de eficiência energética se traduz diretamente em margem de produto.

    E em qualquer cenário, o MFU é o número que mais importa. Um sistema com hardware subótimo bem otimizado supera um sistema com hardware premium mal configurado. A sofisticação está em entender o perfil computacional do workload, instrumentar o sistema para medir utilização real, e iterativamente empurrar o MFU para cima através de batching, fusão de kernels e gestão de memória.

    A próxima vez que você receber uma resposta de um LLM em menos de um segundo, o que aconteceu não foi magia. Foi décadas de co-evolução entre algoritmos, compiladores e silício, comprimidas num stack que qualquer engenheiro hoje pode operar, mas poucos entendem profundamente o suficiente para otimizar de verdade.


    Referências

    • Jouppi et al., "In-Datacenter Performance Analysis of a Tensor Processing Unit" (Google, ISCA 2017)
    • Dao et al., "FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness" (Stanford, NeurIPS 2022)
    • Dao, "FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision" (2023)
    • Chowdhery et al., "PaLM: Scaling Language Modeling with Pathways" (Google, 2022)
    • Hoffmann et al., "Training Compute-Optimal Large Language Models" (DeepMind, 2022)
    • Kwon et al., "Efficient Memory Management for Large Language Model Serving with PagedAttention" (UC Berkeley, SOSP 2023)
    • Leviathan et al., "Fast Inference from Transformers via Speculative Decoding" (Google, ICML 2023)
    • Rajbhandari et al., "DeepSpeed-Inference: Enabling Efficient Inference of Transformer Models at Unprecedented Scale" (Microsoft, SC 2021)
    • MLPerf Inference v3.1 Results (MLCommons, 2023)
    • NVIDIA H100 Tensor Core GPU Architecture Whitepaper (NVIDIA, 2022)
    Este conteúdo foi útil?
    Compartilhar artigo

    Quer aplicar isso no seu contexto?

    Vamos conversar sobre seus desafios e encontrar o melhor caminho para sua operação.

    Agendar conversa