Estos últimos días he realizado algunos cambios importantes en ColorSharp, aunque no han repercutido demasiado en su funcionalidad. He cambiado ligeramente la arquitectura subyacente, he añadido algo de documentación, TODOs, CHANGELOGs… Sin embargo lo que me motivó para realizar los cambios que me llevaron al cambio de arquitectura fue la búsqueda de un mayor rendimiento.
La realidad es que las mejoras que obtuve fueron marginales. No he tomado medidas (os prometo que la próxima vez seré más serio), pero puedo asegurar que la conversión de unas 40.000 muestras de color CIE XYZ a sRGB (que en mi máquina tomaba un segundo y medio aproximadamente) presentaba cambios difícilmente perceptibles por un ser humano.
Cambios planteados
SIMD
El primer cambio que me planteé fue introducir paralelismo a nivel de instrucción (SIMD) en los algoritmos. Había leído hace tiempo que Mono facilitaba el uso de SIMD sin necesidad de usar código inseguro, y eso fue lo que me incentivó a buscar. Desgraciadamente tuve que abandonar este enfoque, pues el diablo está en los detalles.
La versión «original» de .NET no permite usar SIMD, o no lo permitía hasta hace muy poco. Recientemente han creado «RyuJIT», que facilita el uso de SIMD… pero que presenta dos problemas: Es semiexperimental y su API para trabajar con SIMD es diferente a la que presentaba Mono. Por otro lado, parece que las versiones recientes de Mono para entornos de escritorio han eliminado el soporte de SIMD.
Algoritmo de Strassen
Una parte sustancial del cómputo realizado para convertir espacios de colores son productos de matrices. El algoritmo clásico de multiplicación de matrices toma un tiempo del orden O(n³) siendo n·n las dimensiones de la matriz. El algoritmo de Strassen se basa en un inteligente truco (basado en una observación de Gauss) que permite reducir ligeramente la complejidad asintótica del algoritmo. Aun no he aplicado esta optimización, sin embargo no espero una gran mejora, pues trabajo con n pequeña (generalmente 3).
Cambio de arquitectura
Este es el único cambio de la lista que ya he realizado a día de hoy. Consistió básicamente en reducir el uso de «Generics» y métodos «introspection/reflection», así como hardcodear los mejores caminos de conversión entre espacios de color en vez de calcularlos en tiempo de ejecución.
Aunque este cambio no presentó cambios notables, es el que permite un mejor aprovechamiento de las futuras mejoras que incorporen las VMs/JITs de .NET y Mono.
Aprovechar la GPU con OpenCL
Cuando pensé en usar SIMD también pensé en aprovechar la GPU, sin embargo mi desconocimiento en este campo frenó mi avance en esta dirección. Casualmente esta mañana he encontrado información muy útil que seguramente llevará a que en breve ColorSharp sea mucho más eficiente 🙂 .
Mi plan es usar OpenCL.NET (que funciona en Windows, Linux y Mac, tanto en .NET como en Mono). En cuanto a como aprenderé a usarlo en condiciones, he encontrado este tutorial, parece que promete bastante.
Futuros artículos
Puede que parezca raro tener en cuenta los artículos divulgativos en la lista de tareas pendientes, pero considero que es una parte esencial del proyecto.
Siguen pendientes los artículos sobre .NET, Mono, NuGet, PowerShell, PASH, Chocolatey… (también hablaré de Wine!). Como avance, tratarán sobre el ecosistema de software libre alrededor de Mono, especialmente sobre sus puntos débiles.
Además, hay otros dos puntos muy importantes que deben ser tratados: Qué motiva el desarrollo de ColorSharp y qué lo diferencia del resto de bibliotecas; y cómo preparar un desarrollo Mono para poder usar un entorno de CI (Continuous Integration).