- Exploración de la implementación de los pipes de Unix en Linux y de cómo optimizar programas de prueba que escriben y leen datos a través de un pipe
- El programa inicial tenía un rendimiento de aproximadamente 3.5 GiB/s, y mediante varias optimizaciones se mejoró 20 veces
- Estas optimizaciones se lograron perfilando el programa con la herramienta
perf de Linux
- El texto está inspirado en un programa optimizado de FizzBuzz que empuja salida a un pipe a una velocidad de ~35 GiB/s
- Profundiza en cómo funcionan internamente los pipes, por qué escribir y leer desde ellos es lento, y cómo las llamadas al sistema
vmsplice y splice pueden mejorar el rendimiento
- Se analiza cómo el paginado de Linux y el uso de huge pages pueden llevar a versiones más rápidas del programa
- La optimización final incluye reemplazar el polling por un busy loop
- Las pruebas se realizaron en una CPU Intel Skylake i7-8550U y Linux 5.17
- El texto explica en detalle cómo la memoria está compuesta por páginas, que son bloques de tamaño fijo, y cómo la CPU usa tablas de páginas para traducir direcciones virtuales a direcciones físicas
- El texto concluye con la observación de que cambiar a huge pages en el programa mejora el rendimiento en alrededor de 50%
- También analiza el uso de huge pages en la CPU y cómo reducir los fallos del Translation Lookaside Buffer (TLB), lo que puede mejorar el rendimiento
- El código del kernel asume que
struct page apunta a una página de tamaño estándar para la arquitectura actual. En el caso de huge pages, el struct page "head" contiene la información de la página física real, mientras que las páginas "tail" consecutivas solo contienen un puntero a la página head
- Los kernels recientes (desde 5.17) incluyen
struct folio, un nuevo tipo que identifica explícitamente la página head. Esto mejora el rendimiento al reducir la necesidad de comprobar en tiempo de ejecución si un struct page es una página head o tail
- El texto analiza el concepto de busy loop para evitar el costo de sincronización. Esto consiste en pedir que
vmsplice retorne cuando no se puede escribir en el pipe y entrar en un busy loop hasta que esté listo. Esto puede aportar una mejora de rendimiento de 25%, pero a costa de ocupar completamente un núcleo de CPU hasta que vmsplice esté listo
- El autor resume los temas principales tratados en el texto: operaciones de zero-copy, ring buffers, paginación y memoria virtual, sobrecarga de sincronización
- El autor también reconoce que existen muchas otras opciones y detalles que no se trataron en el texto, ya sea porque no eran relevantes o por falta de interés
- El texto fue bien recibido por los lectores, quienes lo encontraron útil e interesante
1 comentarios
Comentarios de Hacker News
vmsplice, que funciona como un mini mecanismo de memoria compartida entre dos procesosvmsplicerequiere un manejo cuidadoso de los búferes al leer y escribir, y aunque es complejo, puede ser eficientesplice()yvmsplice(), que según se informa son difíciles de usar y poco aprovechadas en la mayoría de los programasstdoutde un programa alstdinde otro, haciendo que la operación seazerocopyo, en escenarios menos optimizados, unonecopyrápidoperf, destacando su importancia para el rendimientocat,sed,awk,cut,grep,uniqyjq