Librsvg, Rust y arquitecturas que no son comunes

Translations: en - Tags: librsvg, rust

Hace casi cinco años que librsvg empezó a meter Rust en su código fuente. Más o menos por las mismas fechas, las distribuciones de Linux comenzaron a empaquetar las primeras versiones de Firefox que también requerían de Rust. Yo, sin pena alguna, quería montarme en esa misma ola: las distros tenían que integrar un lenguaje nuevo en su infraestructura de compilación, o se quedarían sin Firefox. Yo esperaba que al ya tener las herramientas de Rust funcionando en las distros, se les haría más fácil meter el librsvg rustificado.

Dos años después, alguien de Debian se quejó sobre cómo esto hacía difícil o imposible compilar librsvg (y todo el software que depende de la biblioteca, que es Bastante) en todas las arquitecturas en las que se compila Debian — en concreto, en cosas como HP PA-RISC o Alpha, que incluso Debian pone como "descontinuadas" hoy en día.

Hace unos días hubo un problema similar, esta vez desde Gentoo, en concreto sobre cómo el paquete de criptografía para Python ahora requiere Rust. Entonces, no compila en las plataformas que Rust/LLVM no soportan, como hppa, alpha e Itanium. Tampoco compila en plataformas para las que Gentoo todavía no tiene paquetes de Rust (mips, s390x, riscv entre ellas).

Recordando arquitecturas descontinuadas

Permítanme recordar algunas cuantas arquitecturas descontinuadas. Si mi lectura de la Wikipedia es correcta, los CPUs DEC Alpha dejaron de desarrollarse en 2001, y HP, quien compró a Compaq, quien compró a DEC, dejó de vender sistemas Alpha en 2007. Hay que hacer notar que Compaq descartó el Alpha y lo sustituyó con el Itanium, que a su vez dejó de fabricarse en 2017.

Yo usaba una máquina Alpha en 1997-1998, en la Universidad. Muy amablemente, Miguel me dejó programar y aprender de él en el Instituto donde trabajaba. El laboratorio de cómputo del Instituto consiguió una máquina Alpha para que los científicos pudieran correr sus modelos matemáticos en una máquina con aritmética de punto flotante realmente rápida. Esa era una época en la que la gente comúnmente hacía ssh a otras máquinas para correr aplicaciones de X11 de forma remota — en su caso, creo que usaban Matlab y Mathematica. Buenos tiempos, aquellos.

La Alpha tenía punto flotante muy rápido, mucho más rápido que el de los CPUs x86 de Intel, y a mí me encantaba correr mis programas de gráficos ahí. Es la primera máquina de 64 bits que usé, y me permitió aprender cómo arreglar código que sólo asumía 32 bits. Tenía una unidad de punto flotante realmente quisquillosa. Mientras que las PCs con x86 te mandaban un NaN si usabas memoria no inicializada como valores de punto flotante, la Alpha te tiraba una excepción de punto flotante y tiraba tu programa. ¡Pude arreglar muchos bugs gracias a eso!

También tengo recuerdos muy gratos de las SPARCs de 32 bits de la Universidad y sus pantallas planas CRT de frecuencia fija, pero imagínate, ni siquiera he visto una de esas desde 1998. Como yo hacía cosas de gráficos, usaba la única SPARC del laboratorio del Instituto que tenía gráficos de 24 bits, con un monitor CRT descomunal de 21". Las PCs de ese tiempo todavía tenían tarjetas gráficas de 8 bits y monitores pequeños y horribles.

Más o menos al mismo tiempo que el Instituto consiguió su Alpha, también consiguió una de las primeras UltraSPARCs de 64 bits de Sun — una máquina muy cara que definitivamente no era para tu hobby en casa. ¡Creo que tenía 2 CPUs! ¡El multi-core todavía no existía!

Creo que en mi vida sólo vi una máquina Itanium, tal vez alrededor de 2002-2005. En la oficina de Ximian/Novell nos pusieron una, para tareas de control de calidad — una máquina increíblemente ruidosa e inestable. Creo que nunca hicimos desarrollo en esa máquina; era para "¿puedes reproducir este bug ahí?" nada más. Creo que Ximian/Novell tenían un contrato con HP para probar la distribución ahí, no me acuerdo.

Arquitecturas que LLVM no soporta

Las plataformas como Alpha o Itanium que Rust/LLVM no soportan — vaya, están muertas. El compilador no puede generar código para ellas, pues Rust genera código a través de LLVM, y LLVM no las soporta.

No sé por qué las distribuciones que mantienen voluntarios se atribuyen la responsabilidad de mantener su software corriendo en plataformas que ya no han sido fabricadas por años, y que ni siquiera fueron máquinas para hobby personal.

El otro día estaba leyendo, y ahora me arrepiento de no haber guardado el enlace, algo así: no creas que tu cómputo por hobby te da derecho al trabajo no remunerado por parte de quien escribe los compiladores y de quien mantiene el software y las distros. (Si alguien me ayuda a encontrar la fuente, con gusto pongo un enlace y la cito de forma correcta).

Plataformas no de primer nivel y "$distro no compila Rust ahí todavía"

Me parece que la gente está descubriendo esto una vez más:

  • Escribir y darle soporte a un compilador para cierta arquitectura implica Trabajo Real.

  • Soportar una distro para cierta arquitectura implica Trabajo Real.

  • Arreglar el software para que funcione en cierta arquitectura implica Trabajo Real.

Rust divide el soporte para diversas plataformas en diferentes niveles o "tiers", que van desde el "tier 1" para las que tienen mejor soporte, hasta "tier 3" para las menos soportadas. O, debería decir, a las que menos se les presta atención, que es una combinación de la gente que sí tiene el hardware en cuestión, y de si la infraestructura de pruebas y compilación está preparada para lidiar con esas plataformas de forma tan efectiva como las plataformas de "tier 1".

En otras palabras: hay más gente con la capacidad de prestarle atención, y probar cosas, en PCs con x86_64, que las que hay para sparc-unknown-linux-gnu.

Algunas anécdotas de Suse

En Suse le damos soporte a las mainframes s390x de IBM; esas bestias corren Suse Linux Enterprise Server. Tienes que pagar mucho dinero para comprar una máquina así y su soporte. Es una máquina que ocupa una habitación completa y requiere de cuidados profesionales.

Cuando librsvg y Firefox empezaron a rustificarse, por supuesto que había dudas sobre hacer funcionar Rust correctamente en la s390x. Trabajé esporádicamente con la gente que hizo que la distro funcionara ahí, y tuvimos que lidiar con compilar Rust y Firefox en esa plataforma (librsvg no fue mayor problema después de hacer funcionar Rust y Firefox).

Creo que todo el trabajo necesario para que LLVM funcionara en la s390x se hizo en IBM. Hubo unos cuantos bugs de compilaciones incorrectas que afectaban a Firefox; se arreglaron y ya.

Uno esperaría que los bugs en el software para mainframes de IBM los arreglara IBM o sus contratistas, no una bola de voluntarios que mantienen una distro en su tiempo libre.

Darle tiempo de cómputo de mainframes a voluntarios en las distros podría parecer como una acción samaritana, o como una trampa para extraer trabajo no remunerado de gente inocente.

Bugs de endianness

Más que nada, los problemas de Firefox en la s390x eran acerca de código que no funcionaba en big-endian. Verás: todas las arquitecturas comunes de hoy en día (x86_64 y arm64) son little-endian. Sin embargo, la s390x es big-endian, lo cual quiere decir que todos los números de más de un byte se guardan al revés en la memoria de como la mayoría del software lo esperaría.

No es ningún problema escribir software que asume little-endian o big-endian todo el tiempo, pero sí requiere un poco de cuidado escribir software que funcione en cualquiera de los dos esquemas.

Casi todo el software escrito por voluntarios y por gente a quien se le paga es para CPUs que son little-endian, porque es casi seguro que es ahí donde va a correr su software. Es un dolor de cabeza encontrar código que no funciona en big-endian — doloroso porque saber dónde buscar evidencia de esos bugs es difícil, y arreglar código existente para que funcione con cualquier endianness puede ser o muy sencillo, o toda una aventura de refactorización y pruebas.

Dos casos al respecto:

Firefox. Cuando Suse empezó a lidiar con Rust y Firefox en la s390x, había bugs de endianness en el código de gráficos en Firefox que se ocupa de los formatos de pixeles. El que los pixeles se guarden en memoria como ARGB/ABGR/RGBA/etgc. es algo específico de cada plataforma, y es una combinación del hardware de gráficos y la arquitectura del CPU. En esa época, parecía ser que el código de Firefox en C++ que se ocupa de los formatos de pixeles había sido refactorizado o reescrito, y había perdido la funcionalidad que alguna vez tuvo para big-endian. No sé del estado actual (no tengo ningún CPU big-endian cerca), pero ya no he visto bugs al respecto en el bugzilla de Suse. ¿Tal vez ya está todo arreglado?

Librsvg tenía dos causas principales de bugs en big-endian. Una estaba en el código viejo para los efectos de filtros de SVG, que estaba escrito en C; nunca tuvo soporte para big-endian. La primera conversión a Rust heredó el mismo bug (puedes pensar en un port línea por línea, aunque no fue exactamente así), pero se arregló cuando mi alumno del Verano de Código, Ivan Molodetskikh, refactorizó el código para tener una abstracción Pixel que funcionara para little-endian y big-endian, y que considerara las idiosincrasias de Cairo.

El otro bug de big-endian en librsvg estaba en el código para calcular máscaras. Una vez más, un poco de refactorización con ese tipo Pixel lo resolvió todo.

Yo sabía que el código original en C para los efectos de filtros de SVG no funcionaba en big-endian. Incluso así, en Suse nunca nos llegó un reporte de un bug sobre resultados incorrectos al renderizar SVGs que usaran filtros en la s390x... tal vez la gente no usa sus mainframes para correr rsvg-convert. Yo deseaba que la conversión a Rust hiciera más fácil arreglar ese bug, y más o menos ocurrió así gracias al trabajo cuidadoso de Ivan.

¿Y el código para calcular máscaras? Se reportaron dos bugs con la misma causa: uno desde Debian sobre una falla en la suite de pruebas de librsvg (¡victoria; atraparon el bug!), y uno desde alguien que corría una Apple PowerBook G4 con un escritorio MATE y que pintaba iconos SVG incorrectamente.

¿Y saben qué? Me fascina ver cómo la gente mantiene corriendo esas maravillas de máquinas. Una laptop que no se calienta lo suficiente para quemarte los muslos, vaya concepto. Una laptop de 32 bits que funciona perfectamente bien, con un máximo de 1 GB de RAM y disco duro de 40 GB (ni siquiera tiene HDMI)... pero bueno, es el mismo deleite que siento al escuchar a la gente que sigue haciendo fotografía con cámaras mecánicas como la Rollei 35. Mucha nostalgia por el hardware de tiempos pasados, y muchos sentimientos encontrados sobre no tirar a la basura cosas que todavía funcionan.

Como programador de gráficos siento la responsabilidad de escribir código que funcione en little-endian y en big-endian, pero bueno, eso ya no es una cuestión de todos los días. La última máquina big-endian que usé a diario fue una de las SPARCs en la universidad, hace más de 20 años.

¿A quién le pagan por arreglar esto?

Esa es la cuestión. A Suse le pagan por darle soporte a Firefox en la s390x; me imagino que a IBM le interesa arreglar LLVM ahí; ambas compañías tienen gente y hardware y dinero para hacerlo posible.

Dentro de Suse, por default soy el responsable de mantener librsvg funcionando para la s390x — se compila como parte de la distro, después de todo. Nunca me ha llegado un bug de endianness por parte de Suse.

Lo cual me hace sospechar que, tal vez de forma similar con Debian y Gentoo, compilamos mucho software porque está ahí en la cadena de compilación, pero nunca lo ejecutamos a toda su capacidad. ¿Es que la gente corre escritorios GNOME en sus máquinas virtuales de una s390x? ¿Tal vez? ¿Y si no se dieron cuenta de los bugs de endianness porque no ocurren en el código que tiende a ejecutarse para los iconos de GNOME? ¡Quién sabe!

Agradezco que Simon haya traido a librsvg el bug que tuvo Debian con la suite de pruebas con las máscaras de SVG, y también a Mingcong por mostrar un lindo pantallazo de MATE corriendo en una PowerBook PPC. Eso fue útil de su parte.

Además — se portaron muy amables al respecto. Fue un placer interactuar con ellos.