1 puntos por GN⁺ 2025-10-04 | 1 comentarios | Compartir por WhatsApp
  • Se refactorizó el kernel de attention a una forma persistent para mejorar el rendimiento en longitudes de contexto bajas
  • En fp16, con contextos grandes, aparece una caída de rendimiento por un problema de planificación de instrucciones de ptxas en la partición de softmax
  • En fp8, se confirmó una mejora de rendimiento de aproximadamente 100 TFLOPS cuando el nombre del kernel incluye "cutlass"
  • Se analiza esta optimización como un truco de optimización hardcodeado mediante el nombrado del kernel
  • El impacto en el rendimiento y la causa del comportamiento son un fenómeno peculiar debido a la implementación interna de NVIDIA ptxas

Resumen: Refactorización del kernel Persistent Attention y efecto del nombre "cutlass"

Visión general

  • Este Pull Request trata sobre la refactorización del kernel de attention de Triton al enfoque de persistent attention
  • El objetivo principal es obtener optimización de rendimiento en el rango de longitudes de contexto bajas
  • Sin embargo, en el caso de fp16, a medida que aumenta el tamaño del contexto, aparece una degradación de rendimiento debido a un problema de planificación de instrucciones de ptxas en la parte de softmax

Efecto de adoptar el nombre "cutlass" en fp8

  • Al usar modelos fp8, se midió una mejora de rendimiento de hasta aproximadamente 100 TFLOPS si el nombre del kernel incluye "cutlass"
  • Esto ocurre porque ptxas (el ensamblador PTX) de NVIDIA aplica internamente una optimización especial cuando el nombre del kernel contiene "cutlass"
  • En el código real, cuando el dtype es float8e5, se asigna al kernel un nombre como "cutlass_gluon_attention"
  • El análisis del desensamblado de ptxas mostró que, efectivamente, existe una condición strstr(kernel_name, "cutlass") dentro del código interno

Benchmark de rendimiento

  • En los datos de benchmark antes y después de la refactorización, se observó una caída relativa de rendimiento en D=64 frente a antes de aplicar persistent attention
    • Esto se atribuye al problema de planificación de instrucciones en la parte de softmax
  • Sin embargo, al combinar el tipo fp8 con el nombre "cutlass", se registró un throughput notablemente más alto en ciertos contextos y tamaños
  • Resumen de resultados representativos:
    • Attention Z=4, H=32, D=64, causal=False:
      • antes de aplicar persistent: triton-fp16 aprox. 383, triton-fp8 aprox. 413, cudnn-fp16 aprox. 565
      • después de aplicar persistent: triton-fp16 aprox. 360, triton-fp8 aprox. 370
    • Attention Z=4, H=32, D=128, causal=True:
      • antes de aplicar persistent: triton-fp16 aprox. 312, triton-fp8 aprox. 345, cudnn-fp16 aprox. 553
      • después de aplicar persistent: triton-fp16 aprox. 356, triton-fp8 aprox. 351

Descubrimiento y análisis del truco de nombrado

  • El análisis de la comunidad confirmó que, si la cadena "cutlass" está incluida en el nombre del kernel, se activa una rutina de optimización experimental en NVIDIA ptxas
  • En ptxas existe una lógica hardcodeada para hacer match por nombre (strstr(kernel_name, "cutlass"))
  • Este truco es una optimización agresiva y experimental, y si afecta o no la exactitud del kernel puede variar según el hardware y la situación

Discusión en la comunidad

  • Varios reviewers hicieron preguntas y análisis sobre comparación de rendimiento, exactitud y método de optimización
  • También se discutieron contenidos del informe técnico de Deepseek y diferencias en arquitecturas específicas como las GPU Hopper
  • Se planteó qué tan ampliamente se aplica la optimización por cambio de nombre y si existen problemas de estabilidad

Conclusión e implicaciones

  • Es un fenómeno muy peculiar que solo con el nombre del kernel pueda producirse una variación real de rendimiento a nivel de hardware
  • Sugiere que existen triggers de optimización ocultos en el stack de software de NVIDIA (ptxas), y que las reglas de nombrado también pueden afectar el rendimiento al desarrollar frameworks de IA
  • En la práctica, al usar este truco, es indispensable probar reproducibilidad y estabilidad, y conviene seguir de cerca las políticas de optimización del proveedor de hardware

1 comentarios

 
GN⁺ 2025-10-04
Opinión de Hacker News
  • Al desensamblar ptxas, se confirmó que hay lógica hardcodeada para detectar nombres de kernel que contienen "cutlass"
    Parece que NVIDIA aplicó aquí una optimización inestable, experimental y agresiva; si la activaran siempre e incondicionalmente, podría introducir bugs sutiles

    • En la práctica, aparecen más variaciones sutiles de rendimiento que bugs sutiles
      Los compiladores de GPU son extremadamente difíciles, y cuando intentas ir más allá de las optimizaciones básicas, casi siempre obtienes resultados mixtos junto con problemas
      Algunos kernels se vuelven más rápidos y otros más lentos, y lograr que el rendimiento global suba es muy difícil
      Casi nunca pasa que una sola optimización aumente siempre la velocidad en toda una batería de pruebas
      Mi experiencia es con sistemas GPU que no son de Nvidia, pero esta situación me resulta muy familiar
      Parece que Nvidia también encontró una optimización que da resultados increíbles en cierto conjunto de kernels y resultados pésimos en otro, y no logró hallar un criterio confiable para aplicarla automáticamente
  • Gracias por dar ese contexto
    No soy de esta área (y además es la primera vez que oigo hablar de este proyecto), así que por más que lo miraba no entendía ni el título ni el contenido del PR

  • Esto me recordó a cuando, hace 25 años, ATI (AMD) fue descubierta haciendo trampa porque el rendimiento cambiaba en el benchmark de Quake III si se renombraba el ejecutable a 'quack'
    También dejo enlaces relacionados: reseña de techreport.com, reseña de hardocp.com, artículo de 3dcenter.de

    • Lo aclaro por si alguien lo entendió mal como yo
      ATI detectaba el nombre del ejecutable "quake" y cambiaba la calidad de texturas y otras cosas para subir la puntuación del benchmark
      La gente descubrió esto porque al cambiar el nombre del ejecutable a "quack", la calidad de imagen subía y la puntuación bajaba; es decir, el driver de ATI estaba reduciendo deliberadamente la calidad para ganar velocidad
      O sea, ATI no cambió el nombre del archivo; lo hicieron los usuarios

    • O también estuvo el caso del Intel C++ Compiler que revisaba la cadena "GenuineIntel" en la salida
      El enlace a la wiki está aquí

    • Hasta hoy, todos los vendors hacen este tipo de cosas
      Los drivers interceptan el rendering loop de juegos populares para corregir bugs, sustituir shaders por versiones más optimizadas, abrir code paths más rápidos y otras intervenciones similares
      Estos cambios deberían afectar lo mínimo posible al resultado, pero en algunos casos la intervención es tan agresiva que la calidad se degrada muchísimo
      Así hacen que el juego corra más rápido en su hardware

    • Hay un hilo donde este tema se discute con más profundidad; recomiendo verlo aquí
      Curiosamente, es otra publicación anterior sobre la misma optimización de cutlass

    • Este tipo de casos es muy común
      Los fabricantes de chipsets para teléfonos hicieron trampas para benchmarks (VW con emisiones, Nvidia con el benchmark 3DMark, Intel con benchmarks SPEC para Xeon, etc.)
      En gráficos por computadora, ya es casi costumbre que los drivers metan tweaks, settings y workarounds específicos para cada juego
      (Por desgracia, hoy en día los enlaces a fuentes confiables desaparecen demasiado seguido, así que toca usar archive.org. Creo que vale la pena preservar estos recuerdos.)
      Enlaces de referencia: trampa de benchmarks de Mediatek, escándalo de emisiones de Volkswagen, controversia de Nvidia con 3DMark, impacto del compilador de Intel en benchmarks SPEC

  • Desde la perspectiva de quien trabaja con compiladores, este tipo de optimizaciones a veces depende del nombre (schema, substring, etc.)
    Aunque no guste, en la práctica así funcionan algunas cosas
    No necesariamente es algo malicioso; diseñar la optimización para que solo se aplique a su propia librería también puede ser una opción más segura que arriesgarse a romper todo
    O a veces pasa porque el frontend no puede proporcionar información más confiable, como información estructural

    • Probablemente no sea malicioso, pero esta forma de optimizar termina creando una barrera nueva
    • Puedo entender depender del tipo de función o del schema, pero aplicarlo solo por el nombre se siente un poco raro
    • Incluso si es “para evitar que se rompa”, si alguien usa ese mismo nombre por casualidad puede provocar problemas inesperados
      No me parece una forma útil de hacerlo
  • No me parece nada nuevo

    • A inicios de 2024, SPEC invalidó 2,600 resultados de benchmarks de CPU Intel Xeon porque el compilador de Intel había usado optimizaciones injustas para inflar las puntuaciones (artículo de Tom's Hardware)
    • Microsoft también ha hecho cosas parecidas con métricas de benchmarks de compiladores Java/C
    • Y todo el mundo está obsesionado con hacer trampa en benchmarks de IA (escándalo de benchmarks de IA)
  • Esto me recordó a cuando, hace unos 10 años, en cierta versión de Webpack se rompía el build si usabas un archivo llamado add.svg
    Al final se resolvía cambiándole el nombre a plus.svg

    • numpy también es así
      Hay gente que sin querer rompió numpy por tener un archivo llamado “secret.py”
  • Me impresiona lo honesto del mensaje del commit

    • Hubo críticas a la manera en que estaba armado el diff del commit
      Alguien escribe “hice algo aproximadamente 100 tflops más rápido” y aun así la reacción es “el mensaje del commit está mal”… entonces seguro tampoco les gustaría el estilo de commits de John Carmack

    • Personalmente, me gustan este tipo de mensajes honestos
      Se sienten mucho mejor que ver una avalancha de mensajes de commit generados por IA (cosas repetidas como "refactored X")

    • Creo que hubiera sido mejor hacer squash y dejar el historial de commits agrupado
      No entiendo muy bien por qué no hicieron squash al subirlo a GitHub

  • Esto me recordó cuando aprendí a usar NVIDIA Jetson
    Descubrí que ejecutar un solo comando hacía que todo fuera más rápido (enlace relacionado)

    • Me pregunto si hablas del modo de energía
      Según el artículo, hay dos opciones, 5W y 10W, y 10W es la predeterminada, así que incluso podría interpretarse que eso de “más rápido” solo aplica cuando cambias desde la configuración por defecto a 5W; quizá estoy entendiendo algo mal
  • A veces usas código extremadamente ajustado en un lenguaje de alto nivel (C++, etc.) y también esperas resultados concretos hasta en el ensamblador de GPU, pero el compilador no genera lo que quieres
    Si consultas con el equipo de cómputo, seguramente te ofrecerán varias soluciones, pero en código open source muchas de ellas son difíciles de aplicar (por ejemplo, #pragma propietarios, intrinsics, etc.)
    Si estás construyendo una librería de alto rendimiento, si no obtienes el rendimiento esperado simplemente no puedes sacar el producto
    En esos casos no te queda más que usar trucos como inducir ciertas transformaciones del código por medio del nombre de la función y cosas así
    Este tipo de optimizaciones se usa mucho en el mundo real, y no creo que sea comparable con hacer trampa en benchmarks bajando la calidad de imagen

    • En estos casos también salió la pregunta de por qué no usar ensamblador inline
  • Todo esto ya se había discutido cuando se publicó este PR por primera vez
    No siento que haya nada nuevo
    Discusión anterior

    • Me sonaba familiar, como si ya lo hubiera visto antes
  • Ojalá existiera una estructura económica que facilitara compartir código
    En vez de drivers binary blob, baseband y otras estructuras complejas, sería bueno que cualquiera pudiera acceder fácilmente a la información y así reducir el tiempo y esfuerzo desperdiciados
    Muchísimos ingenieros e investigadores brillantes pasan meses o años haciendo reverse engineering y descifrando documentación, esquemas de circuitos y binarios que alguien más ya tiene
    CUDA y empresas como NVIDIA resultan frustrantes

    • El problema de fondo son los costos fijos iniciales de desarrollar una codebase de software, luego el costo laboral de mantenimiento y después un costo pequeño de distribución (por ejemplo, servidores de descarga)
      En apps de escritorio, el costo adicional por cada usuario extra tiende casi a cero
      Por eso el software necesita una estructura de ingresos periódicos, pero esos ingresos no deberían crecer indefinidamente en proporción al número de usuarios
      Quienes invirtieron en desarrollar código nuevo deben recuperar su inversión cuando el producto se vuelve popular, pero el crowdfunding tradicional no satisface esa estructura
      A medida que crece el número de usuarios, la contribución por persona cae muchísimo; incluso si todos aportaran el 100%, o el 10%, o hasta el 1%, el total de la inversión podría volverse astronómico
      Al final creo que hace falta una especie de sistema de compromisos tipo subasta
      Ese esquema también tiene problemas, y la transición entre modos exclusivos y no exclusivos es especialmente complicada
      Si unas pocas grandes empresas cubren todo el costo de desarrollo y luego el resultado se libera como open source, todas las demás personas y empresas terminan siendo, en la práctica, free riders