1 puntos por GN⁺ 2025-05-11 | 1 comentarios | Compartir por WhatsApp
  • La versión más reciente, Sep 0.10.0, logra una impresionante velocidad de parsing de CSV de 21 GB/s en AMD 9950X
  • El rendimiento mejoró notablemente gracias al soporte de AVX-512 y a la superación de problemas con registros de máscara
  • El nuevo parser AVX-512-to-256 supera a AVX2 y al parser AVX-512 anterior
  • En un entorno multihilo, procesa 1 millón de filas en 72 ms y registra un ancho de banda de 8 GB/s
  • Con optimización continua de software y hardware, se logró una mejora de rendimiento de casi 3x en 2 años

Lanzamiento de Sep 0.10.0 y panorama de mejora de rendimiento

  • En su lanzamiento reciente 0.10.0, Sep realizó optimizaciones para CPUs con soporte de AVX-512 (por ejemplo, AMD 9950X, Zen 5) y actualizó los resultados de benchmark
  • En la versión más reciente registró un resultado sobresaliente de 21 GB/s en el parsing de CSV de bajo nivel
  • Es una mejora importante frente a los 18 GB/s de la versión anterior
  • Los detalles de las mejoras pueden verse en las releases de GitHub y el README de Sep
  • El texto explica el proceso de mejora de rendimiento mediante código C# basado en SIMD y ensamblador SIMD x64 para superar la ineficiencia del código máquina AVX-512 en .NET 9.0

Evolución del rendimiento de Sep

  • Se muestra visualmente la evolución de Sep desde la versión inicial 0.1.0 hasta la 0.10.0, de .NET 7.0 a 9.0, y de AMD 5950X (Zen 3) a 9950X (Zen 5)
  • Los benchmarks están basados en un solo hilo y puede haber ligeras variaciones entre releases
  • El mensaje clave es que tanto un gran refactor (reescritura de la estructura interna en 0.2.0) como pequeñas optimizaciones acumuladas impulsaron mejoras constantes de rendimiento
  • Con el avance conjunto de hardware y software, se alcanzó una velocidad de parsing de 21 GB/s, alrededor de 3 veces superior en promedio en 2 años
  • Solo el cambio generacional de hardware (5950X→9950X, 4.9→5.7GHz) ya explica una mejora de más de 1.2x

Generación de código AVX-512 y problema de los registros de máscara

  • Sep ha soportado AVX-512 desde la versión 0.2.3, pero existían limitaciones en el uso de los registros de máscara (k1-k8) de AVX-512
  • En .NET 8 no había soporte directo para registros de máscara, así que las copias y conversiones repetidas entre registros normales provocaban pérdida de rendimiento
  • En la etapa inicial, al no contar con una CPU aparte con soporte AVX-512, se probó de forma limitada en un Xeon Silver 4316 y se confirmó que era lo más rápido

Upgrade a 9950X y comparación entre AVX-512 y AVX2

  • Tras actualizar recientemente la CPU de Zen 3 (5950X) a Zen 5 (9950X), al ejecutar los benchmarks de Sep se alcanzaron 18 GB/s
  • En una comparación directa entre los parsers AVX-512 y AVX2, de forma algo inesperada AVX2 mostró alrededor de 20 GB/s, cerca de un 10% más rápido que AVX-512
  • Esto sugiere que la ineficiencia del manejo de registros de máscara en el JIT de .NET seguía siendo un problema

Código del parser, análisis de ensamblador y nuevo parser AVX-512-to-256

  • Todos los parsers de Sep procesan bloques de char span de 16K y usan operaciones de comparación basadas en registros SIMD (como Vector256)
  • Con SIMD identifican rápidamente caracteres especiales (saltos de línea, comillas, separadores, etc.) y los convierten en bitmasks para optimizar operaciones de conjunto
  • El parser basado en AVX-512 tenía muchas operaciones redundantes por los movimientos repetidos entre registros de máscara (k1, etc.) y registros generales (zmm, etc.)
  • En la versión 0.10.0 se adelantó la llamada a MoveMask para minimizar conversiones de máscara innecesarias, reduciendo así la cantidad de instrucciones en ensamblador
  • El parser AVX2, al no tener registros de máscara, tenía una estructura mucho más simple y en la práctica era más rápido que AVX-512
  • El nuevo parser AVX-512-to-256 lee datos con AVX-512 y evita de raíz el problema del manejo de máscaras usando instrucciones de conversión a 256 bits; la implementación se simplificó y logró un rendimiento de más de 21 GB/s

Resumen de benchmarks de varios parsers

  • Al comparar mediante variable de entorno los benchmarks de todos los tipos de parser, el parser AVX-512-to-256 fue el más rápido con 21.5 GB/s
  • Los parsers basados en AVX2 y Vector256 también mostraron un rendimiento cercano, con una diferencia de apenas 5%
  • Los parsers basados en Vector128 y Vector512 fueron entre 5% y 10% más lentos que AVX2; en particular, el parser Vector512 fue incluso más lento que Vector128
  • El parser IndexOfAny fue marcadamente más lento que los otros parsers SIMD. Vector64 no está acelerado en 9950X, por lo que mostró un rendimiento muy pobre
  • Los parsers SIMD basados en AVX-512 y AVX2 demostraron un rendimiento abrumador frente a otros parsers CSV del mismo tipo

Benchmarks de nivel superior: comparación entre 5950X y 9950X

  • Tomando como referencia 1 millón de filas de activos de paquetes, Sep_MT registró 72 ms (8GB/s) en 9950X y 119 ms (4.9GB/s) en 5950X
  • Incluso con datos de carga real (como float), en 9950X se logró un ancho de banda de ~8GB/s en multihilo
  • El cambio generacional (5950X→9950X) produjo una mejora de aproximadamente 1.5 a 1.6 veces en parsing de aplicaciones reales
  • También se demostró un throughput muy superior y una asignación mínima de recursos frente a bibliotecas CSV competidoras (Sylvan, ReadLine, CsvHelper, etc.)

Conclusión y resumen

  • Sep 0.10.0 supera los límites del rendimiento de parsing de CSV combinando optimización de software y funciones de hardware más recientes (AVX-512, alta frecuencia)
  • El núcleo de la innovación está en el diseño de algoritmos SIMD modernos y en la mejora de la estructura del código JIT de .NET y del ensamblador
  • Es notable el efecto de las mejoras de rendimiento acumuladas y del cambio generacional de arquitectura en un periodo corto
  • Sep presenta en el área de parsing de CSV un nivel de alto rendimiento, multiplataforma y escalabilidad que en la práctica está entre los mejores de la industria

1 comentarios

 
GN⁺ 2025-05-11
Comentarios de Hacker News
  • Es realmente absurdo que Intel haya invertido durante años incluso área de chip para dar soporte a AVX-512 en productos de consumo y que, justo ahora que las bibliotecas empiezan a usarlo cada vez más, lo haya eliminado de los SKU de consumo; no es que AMD tenga un mejor soporte de AVX-512, sino que, como Intel renunció a lo que había invertido, de forma irónica AVX-512 terminó llegando a los CPU de consumo de AMD
    • Intel siempre repite el mismo patrón de crear un mercado tecnológico (Optane) y luego retirarse de golpe (Depth Cameras), confundiendo a los consumidores; apuesta todo de una vez a una tecnología nueva y, si no hay adopción, la abandona enseguida; canceló el soporte de Optane justo cuando en el kernel de Linux empezaba a madurar, y además tiene estrategias raras de recorte de costos; si uno mira hacia atrás, viene repitiendo errores similares desde el Intel iAPX 432
    • En este artículo, con un CPU AMD se observaron velocidades de original: 18GB/s, AVX2: 20GB/s, AVX512: 21GB/s; AVX-512 apenas ofrece ventaja frente a AVX2; los CPU de consumo de Intel también soportan AVX2 en los E-cores; el benchmark es monohilo; Intel quitó AVX-512 del chip para meter más núcleos, y como resultado su tope de gama tiene 24 núcleos, mientras AMD tiene 16; como la diferencia entre AVX2 y AVX512 es mínima, en multihilo podría ganar el que tenga más núcleos; en la mayoría de las cargas reales, aumentar la cantidad de núcleos aporta más que AVX-512; salvo algunos trabajos muy específicos, me parece que la decisión de Intel fue razonable
    • Pronto llegará AVX-10, y se espera que tenga casi las mismas funciones que AVX-512 (aunque yo tampoco sé bien cuál es la diferencia)
    • Lo más interesante de este artículo fue que, en el AMD 9950X, el parser AVX2 fue alrededor de un 10% más rápido que el parser basado en AVX-512 (20GB/s frente a 21GB/s); al final, AVX-512 no parece aportar mucho al consumidor real; con 20GB/s parseando CSV ya no tengo de qué quejarme; solo a los fanáticos del ensamblador les importa realmente si está soportado o no
    • Es increíble lo torpe que está actuando Intel
    • Si sirve de consuelo, Sep usa AVX-512 siempre que puede sin configuración adicional; funciona bien en un runtime JIT, así que, incluso si sin querer apuntas al mínimo común denominador de rendimiento, no sales perdiendo
    • Intel también anda flojo en soporte de software; la iGPU de mi laptop es bastante decente, pero me da pena que no tenga buen soporte en PyTorch y similares; con llama.cpp y la inferencia por Vulkan funciona bien, así que ojalá otro software también diera ese tipo de soporte
  • En vez de hacer cuatro comparaciones por carácter ('\n', '\r', ';', '“') y luego tres operaciones or, se puede aplicar un truco común para hacer 1 shuffle, 1 comparación y 0 operaciones or; publiqué ese truco en un blog, por si les sirve; dicho eso, en este artículo también redujeron operaciones or con vpternlogd y vpor
  • Da vergüenza ver a Intel decidir que los CPU de consumo deben llevar núcleos lentos y además quitar todo AVX-512 sin siquiera considerar el “multi-pumping”
    • La causa principal de esta elección fueron los problemas del proceso de 10nm; como el rendimiento de fabricación era bajo y el costo demasiado alto, intentaron sacar la mayor ganancia posible recortando chips y vendiendo núcleos de la familia Atom o marketing de bajo consumo; en los productos caros buscaron defender el mercado de servidores y nube aumentando el tamaño y reduciendo margen; al final la rentabilidad cayó y también perdieron cuota, pero al menos intentaron algo
  • La afirmación de que hubo una mejora de velocidad de casi 3x en los 2 años desde el lanzamiento de Sep (junio de 2023) es debatible si se tiene en cuenta el salto de hardware
    • En el mismo hardware, la mejora del software (0.9.0 frente a 0.10.0) es del 17%, y si sumas 17% a 13088 de la 0.9.0 te da 15375; comparado con 7335 de la 0.1.0, eso es alrededor de 2.1x de mejora
    • Se afirma que en el mismo hardware hubo una mejora de 3GB/s frente a una versión anterior de sep, y la velocidad real junto con la información del hardware están descritas con transparencia
    • Hoy ya no estamos en la época de la ley de Moore, así que es difícil esperar una mejora de 3x solo por hardware; incluso así, me parece un resultado suficientemente impresionante para los tiempos actuales
    • Está claro que afirmar una mejora de 3x sin considerar el salto de hardware deja espacio para discusión, pero aun así es interesante como una forma de ver el rendimiento real del software año a año
    • El gráfico de benchmark se salta cuatro generaciones de CPU y de repente hace que parezca una “gran mejora de rendimiento”, así que no resulta confiable
  • Espero que Arthur Whitney se motive con este resultado y lo supere con una línea de código, o que rompa el récord con una línea junto con una actualización del motor shakti o alguna noticia nueva; tengo expectativas de que siga habiendo avances
  • Solo de pensar quién necesita procesar diez millones de líneas de CSV a esa velocidad ya da vértigo
    • Yo también he pasado por eso; al principio eliges CSV porque se ajusta a volúmenes pequeños y porque a los no desarrolladores —sobre todo los que manejan bien Excel— les resulta fácil de leer, así que logs y procesos también se resuelven de forma ordenada con CSV; pero cuando los datos crecen 10x o 100x, optimizar la ingesta rápida de CSV con cientos de millones o miles de millones de filas se vuelve una necesidad real; este tipo de optimización, en cierto modo, compra tiempo para migrar gradualmente los procesos internos a formatos más adecuados
    • CSV es un formato más común de lo que parece incluso internamente, y además tiene la ventaja de que se comprime fácil (deflate); hace tiempo me tocó trabajar con código que volcaba datos Netflow en CSV a velocidad de tarjeta NIC; personalmente, si van a hacer un procesamiento tan complejo, preferiría usar protocol buffers; protobuf no es un formato tan difícil, pero por alguna razón no se adopta mucho
    • Más miedo me da lo que significa almacenar el resultado de procesar CSV a 21GB/s; por más útil que sea el agregado, a esa velocidad todo eso al final tiene que terminar acumulado en alguna parte, y eso me da curiosidad
    • A pesar de sus muchas desventajas, sigo pensando que CSV sigue siendo el formato de intercambio de datos más común
    • En el sector financiero, CSV se comparte fácilmente entre todos, y al ser texto se puede meter y procesar en casi cualquier lado
    • Un ejemplo son esos archivos de producto cartesiano que te manda contabilidad a fin de año
    • De hecho, estoy sufriendo precisamente porque tengo que lidiar con este tipo de CSV heredados
    • En casi todos los casos HDF5 es mejor que CSV; aun así, cuesta explicar su uso por otra cosa que no sea ignorancia, pereza o el clásico “porque funciona”
  • Entré esperando código en ensamblador, pero me sorprendió e impresionó que fuera C#; gran resultado
    • El .NET moderno es el “lenguaje de alto nivel” que más profundamente ha integrado SIMD e intrínsecos vectoriales; Tanner Gooding de Microsoft impulsó muchos de esos avances, y sus artículos de blog sobre el tema también son excelentes
  • Me confunde que en el texto no esté claramente definido qué hace exactamente el código de 21GB/s; por ejemplo, no queda claro cuál es el formato de parseo en concreto (como el manejo de comillas en CSV) ni cómo se usa el resultado después de parsear (si se mete en una estructura de datos, etc.)
    • Los ns/fila calculados en el artículo son aproximadamente 27ns/fila (unas 37,000 filas por segundo), pero si eso fuera realmente 21GB/s, entonces serían como 570KB por fila, así que parece un benchmark muy extraño
  • En mi experiencia, con código SIMD personalizado es difícil obtener una gran ventaja frente a la autovectorización de los compiladores modernos (sobre todo en código amigable con vectores), aunque en casos especiales como el parseo de JSON sí puede ser distinto
  • Hace poco trabajé con una extracción CSV de 300GB, y se fue demasiado tiempo en manipulación y verificación de integridad, así que realmente hace falta un parser CSV tan rápido como este
    • No entiendo por qué no usan un formato especializado para guardar datos de punto flotante; HDF5 es una alternativa mucho mejor