1 pontos por GN⁺ 2025-10-04 | 1 comentários | Compartilhar no WhatsApp
  • Refatoração do kernel de Attention para um formato persistent, melhorando o desempenho em comprimentos de contexto baixos
  • Em fp16, em contextos grandes, há queda de desempenho devido a um problema de escalonamento de instruções do ptxas na partição de softmax
  • Em fp8, foi observado um ganho de cerca de 100 TFLOPS de desempenho quando o nome do kernel inclui "cutlass"
  • Essa otimização foi analisada como um truque de otimização hardcoded por meio da nomeação do kernel
  • O impacto no desempenho e a causa do comportamento são um fenômeno peculiar causado pela implementação interna do ptxas da NVIDIA

Resumo: Refatoração do kernel Persistent Attention e o efeito da nomenclatura "cutlass"

Visão geral

  • Este Pull Request refatora o kernel de attention do Triton para o modelo de persistent attention
  • O principal objetivo é obter otimização de desempenho em faixas de comprimento de contexto baixas
  • Porém, no caso do tipo fp16, conforme o contexto aumenta, surge uma queda de desempenho devido a um problema de escalonamento de instruções do ptxas na parte de softmax

Efeito de adotar o nome "cutlass" em fp8

  • Ao usar modelos fp8, foi medido um ganho de desempenho de até cerca de 100 TFLOPS quando "cutlass" é incluído no nome do kernel
  • Isso acontece porque o ptxas (montador PTX) da NVIDIA aplica internamente uma otimização especial quando o nome do kernel contém "cutlass"
  • No código real, quando o dtype é float8e5, o nome do kernel é atribuído como algo como "cutlass_gluon_attention"
  • A análise do disassembly do ptxas mostrou que, de fato, existe uma condição strstr(kernel_name, "cutlass") no código interno

Benchmark de desempenho

  • Nos dados de benchmark antes e depois da refatoração, foi observada uma queda relativa de desempenho em D=64 em comparação com antes da aplicação de persistent attention
    • Isso é atribuído ao problema de escalonamento de instruções na parte de softmax
  • Porém, ao combinar fp8 com a nomenclatura "cutlass", em certos contextos e tamanhos foi registrado um throughput significativamente mais alto
  • Resumo de resultados representativos:
    • Attention Z=4, H=32, D=64, causal=False:
      • antes de aplicar persistent: triton-fp16 cerca de 383, triton-fp8 cerca de 413, cudnn-fp16 cerca de 565
      • depois de aplicar persistent: triton-fp16 cerca de 360, triton-fp8 cerca de 370
    • Attention Z=4, H=32, D=128, causal=True:
      • antes de aplicar persistent: triton-fp16 cerca de 312, triton-fp8 cerca de 345, cudnn-fp16 cerca de 553
      • depois de aplicar persistent: triton-fp16 cerca de 356, triton-fp8 cerca de 351

Descoberta e análise do truque de nomenclatura

  • Análises da comunidade confirmaram que, quando a string "cutlass" está incluída no nome do kernel, uma rotina experimental de otimização é ativada no NVIDIA ptxas
  • O ptxas contém lógica hardcoded para casar nomes (strstr(kernel_name, "cutlass"))
  • Esse truque é uma otimização agressiva e experimental, e se há mudança na exatidão do kernel pode variar conforme o hardware e a situação

Discussão na comunidade

  • Vários revisores levantaram perguntas e análises sobre comparação de desempenho, exatidão e método de otimização
  • Também foram discutidos pontos como o conteúdo do relatório técnico da Deepseek e diferenças em arquiteturas específicas, como GPUs Hopper
  • Também surgiram questões sobre o quão amplamente essa otimização via mudança de nome se aplica e sobre possíveis problemas de estabilidade

Conclusão e implicações

  • É um fenômeno bastante incomum que apenas o nome do kernel possa causar mudanças reais de desempenho no nível de hardware
  • O fato de existir um gatilho de otimização oculto na stack de software da NVIDIA (pxtas) sugere que, no desenvolvimento de frameworks de IA, as convenções de nomenclatura também podem afetar o desempenho
  • Na prática, ao usar esse truque, é essencial testar reprodutibilidade e estabilidade, além de acompanhar de perto as políticas de otimização do fornecedor de hardware

1 comentários

 
GN⁺ 2025-10-04
Comentários no Hacker News
  • Ao desmontar o ptxas, confirmaram que existe lógica hardcoded para detectar nomes de kernel contendo "cutlass"
    Parece que a NVIDIA aplicou aqui uma otimização instável, experimental e agressiva; se essa otimização fosse sempre ativada incondicionalmente, poderia causar bugs sutis

    • Na prática, aparecem mais variações sutis de desempenho do que bugs sutis
      Compiladores de GPU são extremamente difíceis, e sempre que se tenta ir além das otimizações básicas, os resultados costumam vir misturados com problemas
      Alguns kernels ficam mais rápidos e outros mais lentos, e é muito difícil conseguir um ganho geral de desempenho
      Quase nunca uma única otimização aumenta consistentemente a velocidade em toda a bateria de testes
      Minha experiência é com sistemas de GPU que não são da Nvidia, mas a situação parece bem familiar
      A Nvidia provavelmente também encontrou uma otimização que produz resultados incríveis para alguns conjuntos de kernels e resultados péssimos para outros, e aparentemente não conseguiu achar um critério confiável para aplicá-la automaticamente
  • Obrigado pelo contexto
    Não sou dessa área (e é a primeira vez que ouço falar desse projeto), então eu realmente não estava entendendo o título nem o conteúdo do PR

  • Isso me lembrou de quando a ATI (AMD), há 25 anos, foi pega manipulando benchmark no Quake III porque o desempenho mudava ao renomear o executável para quack
    Também deixaram links relacionados: review da techreport.com, review da hardocp.com, artigo da 3dcenter.de

    • Só para esclarecer, caso alguém tenha entendido errado como eu
      A ATI detectava o nome de executável quake e alterava a qualidade das texturas etc. para inflar a pontuação do benchmark
      As pessoas perceberam isso ao renomear o executável para quack: a qualidade da imagem aumentava e a pontuação caía, mostrando que o driver da ATI estava reduzindo deliberadamente a qualidade para ganhar velocidade
      Ou seja, não foi a ATI que mudou o nome do arquivo; foram os usuários

    • Ou então aquela questão em que o Intel C++ Compiler verificava a string GenuineIntel na saída
      O link da wiki está aqui

    • Até hoje todos os vendors fazem esse tipo de coisa
      O driver intercepta o loop de renderização de jogos populares para corrigir bugs, substituir shaders por versões mais otimizadas ou liberar caminhos rápidos de execução, entre várias outras intervenções
      Essas mudanças deveriam ter impacto mínimo no resultado visual, mas em alguns casos a intervenção é agressiva demais e a qualidade cai bastante
      Tudo isso para fazer o jogo rodar mais rápido no hardware deles

    • Há uma thread com discussão mais profunda sobre esse tema; recomendo esta aqui
      Curiosamente, é um post anterior sobre a mesma otimização relacionada ao cutlass

    • Esse tipo de caso é muito comum
      Fabricantes de chipsets para celulares trapacearam em benchmarks (VW nas emissões, Nvidia no benchmark 3DMark, Intel nos benchmarks SPEC para Xeon etc.)
      Em computação gráfica, já virou quase costume os drivers incluírem tweaks, configurações e workarounds específicos para cada jogo
      (Infelizmente, hoje em dia links de fontes confiáveis somem com tanta frequência que é preciso usar o archive.org. Acho importante preservar esse tipo de memória.)
      Links de referência: manipulação de benchmark pela Mediatek, escândalo das emissões da Volkswagen, polêmica do Nvidia 3DMark, impacto do compilador da Intel em benchmarks SPEC

  • Do ponto de vista de quem trabalha com compiladores, às vezes esse tipo de otimização acaba dependendo de nomes (schema, substring etc.)
    Mesmo que isso não agrade, na prática é assim que funciona
    Nem sempre é algo malicioso; projetar a otimização para atingir só a própria biblioteca pode ser uma escolha mais segura do que arriscar quebrar tudo
    Ou então isso acontece porque o frontend não consegue fornecer informações mais confiáveis, como informações estruturais

    • Provavelmente não é algo malicioso, mas esse tipo de otimização acaba criando uma nova barreira
    • Até dá para entender depender de tipo de função ou schema, mas aplicar com base apenas no nome parece meio estranho
    • Mesmo que seja "para evitar quebrar as coisas", se alguém usar acidentalmente o mesmo nome, problemas inesperados podem surgir
      Não acho que esse tipo de abordagem ajude
  • Não acho que haja muita novidade nisso

    • No começo de 2024, a SPEC invalidou 2.600 resultados de benchmark de CPUs Intel Xeon porque o compilador da Intel usou otimizações injustas para inflar as pontuações (artigo da Tom's Hardware)
    • A Microsoft também já fez algo parecido em métricas de benchmark de compiladores Java/C
    • E todo mundo está obcecado em trapacear benchmarks de IA (escândalo de benchmarks de IA)
  • Isso me lembrou de quando, cerca de 10 anos atrás, em uma certa versão do Webpack, usar o nome de arquivo add.svg quebrava o build
    No fim, o problema foi resolvido trocando o nome do arquivo para plus.svg

    • O numpy também é parecido
      Tem gente que já acabou quebrando o numpy sem querer ao usar um arquivo chamado secret.py
  • Acho impressionante como a mensagem do commit é honesta

    • Houve crítica sobre a forma como o diff do commit foi organizado
      Alguém escreve “tornou alguma coisa cerca de 100 tflops mais rápida”, e mesmo assim a reação é dizer que “a mensagem do commit é ruim”… nesse caso, imagino que essa pessoa também não gostaria do estilo de commits do John Carmack

    • Pessoalmente, eu gosto desse tipo de mensagem sincera
      Acho muito melhor do que uma sequência interminável de mensagens de commit geradas por IA, do tipo "refactored X"

    • Acho que seria melhor fazer squash e consolidar o histórico de commits
      Não entendo muito bem por que não fizeram squash ao subir no GitHub

  • Isso me lembrou de quando aprendi a usar o NVIDIA Jetson
    Descobri que bastava executar um único comando para tudo ficar mais rápido (link relacionado)

    • Você está falando do modo de energia?
      Pelo artigo, existem dois modos, 5W e 10W, e como 10W é o padrão, isso até pode ser interpretado como “fica mais rápido” só quando você muda de 5W de volta para o padrão. Talvez eu tenha entendido algo errado
  • Às vezes se usa código altamente ajustado em linguagem de alto nível (C++ etc.) e ainda assim se espera um resultado específico no assembly de GPU, mas o compilador não gera o que se queria
    Se você falar com a equipe do fornecedor, talvez ofereçam várias soluções, mas em código open source muitas delas são difíceis de aplicar (por exemplo, #pragma proprietário, intrinsic etc.)
    Para quem constrói bibliotecas de alto desempenho, não atingir a performance esperada pode significar que o produto simplesmente não pode ser lançado
    Nesses casos, acaba sendo necessário recorrer a truques como induzir certas transformações de código por meio do nome da função
    Esse tipo de otimização é comum no mundo real e, na minha opinião, não está no mesmo nível de reduzir a qualidade da imagem para trapacear benchmark

    • Também apareceu a pergunta: por que não usar assembly inline nesses casos?
  • Esse assunto já tinha sido discutido quando esse PR foi aberto pela primeira vez
    Não parece haver nada de novo
    Discussão anterior

    • Parecia familiar, então tive a sensação de que já tinha visto isso antes
  • Eu gostaria que existisse uma estrutura econômica em que compartilhar código fosse fácil
    Em vez de drivers com binary blobs, baseband e outras estruturas complexas, seria bom se todos pudessem acessar facilmente a informação e reduzir o desperdício de tempo e esforço
    Inúmeros engenheiros e pesquisadores brilhantes passam meses ou anos fazendo engenharia reversa e decifrando documentação, esquemas e código binário que alguém já possui
    Empresas como CUDA e NVIDIA são frustrantes nesse sentido

    • O cerne do problema é o custo fixo inicial para desenvolver uma base de código de software, o custo contínuo de manutenção em mão de obra e o pequeno custo de distribuição (por exemplo, servidores de download)
      No caso de aplicativos desktop, o custo adicional por usuário tende praticamente a zero
      Por isso, software precisa de uma estrutura de receita recorrente, mas essa receita não pode continuar crescendo proporcionalmente ao número de usuários
      Quem investiu no desenvolvimento de código novo precisa recuperar esse investimento quando o produto se tornar popular, mas o crowdfunding tradicional não atende bem a essa estrutura
      À medida que o número de usuários cresce, a contribuição por pessoa cai drasticamente; mesmo que todos contribuam com 100%, 10% ou até 1%, o montante arrecadado ainda pode ser astronômico
      No fim, acho que seria necessário um sistema de promessas no estilo leilão (pledge)
      Esse modelo também tem problemas, especialmente na transição entre modos exclusivos e não exclusivos
      Quando algumas grandes empresas bancam todo o custo de desenvolvimento e depois o resultado é aberto como open source, todas as outras pessoas e empresas acabam, na prática, como free riders