Desde que empecé a usar Darktable, allá por 2012, siempre me sorprendió lo poca RAM que usaba. La gente cree que es bueno que una aplicación use la memoria con moderación, y eso es cierto sin duda si hablamos de tu entorno de escritorio. Pero hablando de un software de producción que hace un renderizado intensivo de píxeles sobre imágenes de 12 a 54 Mpíxeles, esto significa que los mismos cálculos pesados se hacen una y otra vez en lugar de guardarse para reutilizarse más tarde. Para eso sirve una caché: para evitar cálculos costosos. Y para eso debería usar toda la RAM disponible, porque calcular es malgastar energía, y eso tiene un impacto concreto si trabajas con batería. Además, pagaste por esa RAM y usarla no vacía tu batería. La CPU/GPU, por otro lado…

Sí, los foto-reporteros y muchos nómadas digitales retocan con portátiles a batería, sobre el terreno. Ya es hora de que el mundo del código abierto se dé cuenta de que no todos los fotógrafos están sentados en su escritorio por las tardes y los fines de semana, después de su trabajo diurno “de verdad”. Así que calcular y recalcular las mismas cosas una y otra vez es simplemente malgastar energía, tanto si estás enchufado a la pared como si funcionas con batería.

Mientras tanto, Darktable siempre tuvo ese pequeño ajuste raro de RAM que te permitía definir cuánta querías que usara. Solo que no tenía forma alguna de rastrear realmente cuánta RAM usaba, así que era más una guía que una regla. Eso se sustituyó más tarde por una preferencia cualitativa de “recursos” completamente idiota que no significa nada y que además no te dice cuánta RAM asignas al software.

Así que la caché de RAM de Darktable nunca funcionó realmente, estaba infrautilizada y había que arreglarla. Porque, como resultado, todo se recalculaba todo el tiempo sin razón alguna.

Pero… Había una razón por la que la caché estaba infrautilizada y no funcionaba realmente: ese software tenía cero visibilidad sobre el ciclo de vida de los datos, que es una especie de requisito previo si quieres almacenar datos para reutilizarlos. Eso venía de un pipeline de píxeles que era realmente enrevesado (me pregunto de verdad si alguien es capaz de dibujar el diagrama de flujo de lo que hacemos con los píxeles, de principio a fin, entre los “desarrolladores” de Darktable), pero también de metadatos de imagen que se calculaban en varios lugares, se copiaban y se almacenaban (y luego se actualizaban parcialmente) en varios lugares…

La caché del pipeline tenía un único propósito: asignar los búferes de entrada y salida de los módulos, y posiblemente reutilizarlos si ya estaban disponibles. Pero su tamaño se definía en número de entradas, lo cual era realmente limitado, y no en cantidad de memoria asignada. Eso la hacía moderadamente útil y nos obligaba a usarla de forma demasiado conservadora, porque su tamaño real de memoria era totalmente impredecible.

Huelga decir que “arreglar la caché” implicaba “arreglar el pipeline”, lo que a su vez implicaba “hacer que el ciclo de vida de los datos fuera visible, rastreable y gestionado globalmente”, lo que implicaba rediseñar la arquitectura de alto nivel del software. Como veremos, esto tuvo beneficios inesperados en el rendimiento, que superan con creces las optimizaciones internas por módulo que Darktable hizo durante el mismo periodo.

Qué cambió desde 2022

Este artículo es la secuela directa de Arreglando la caché del pipeline y bugs de hace 10 años. Aquel capítulo anterior trataba de encontrar la podredumbre y detener los fallos más embarazosos. Este trata de lo que pasó después, cuando se hizo evidente que los bugs de la caché no eran en absoluto bugs aislados, sino síntomas de un renderizador cuyas responsabilidades habían estado mezcladas durante demasiado tiempo.

Dónde encaja esto históricamente

El problema original no era simplemente “la caché no cachea lo suficiente”. El problema real era que toda la pila del pipeline había crecido en torno a comportamientos accidentales. Los redibujados de la GUI podían acabar iniciando el procesamiento de imágenes, de forma no regulada. La previsualización de máscaras filtraba estado de la GUI dentro del renderizador. La lógica del histograma y del selector dependía de efectos secundarios especiales del pipeline. La exportación, las miniaturas, la previsualización y el cuarto oscuro tenían todos sus pequeñas variaciones de “seguro que podemos copiar ese búfer una vez más”. Y siempre que la consistencia se volvía difícil de demostrar (durante la visualización de máscaras o los cambios de recorte), la estrategia de reserva a menudo era vaciar líneas de caché y recalcularlo todo, porque al parecer “préndele fuego y empieza de cero” contaba como arquitectura durante un tiempo.

Algunos de los comentarios del código ya lo decían. Había advertencias sobre el recálculo provocado por los redibujados. Había incluso una nota antigua que decía que la caché debería acabar siendo global. Así que los últimos años no fueron sobre inventar una nueva teoría desde cero. Fueron principalmente sobre hacer por fin la limpieza que el código llevaba pidiendo a gritos desde la década de 2010.

El cambio histórico clave es que el pipeline dejó de tratarse como un único bloque recursivo del que se esperaba que descubriera sus propias necesidades mientras se ejecutaba. Se fue dividiendo progresivamente en rutas de ejecución más claras para el renderizado interactivo, el renderizado sin interfaz, el procesamiento por GPU, el procesamiento por CPU y los consumidores del lado de la GUI. Al mismo tiempo, el comportamiento de la GUI se devolvió a la GUI. Dibujar volvió a ser dibujar. Procesar volvió a ser procesar. Eso suena banal, lo cual suele ser señal de que el diseño anterior se había vuelto absurdo.

Sumas de verificación, o cómo la validez dejó de ser un juego de adivinanzas

Una vez que el renderizador dejó de estar enredado con cada widget y cada canal secundario, se hizo posible definir el estado de la imagen de forma explícita. Cada elemento del historial ahora lleva una suma de verificación de módulo construida a partir de los parámetros del módulo, los parámetros de fusión y cualquier forma de máscara relevante. Eso le da a cada estado de módulo una huella canónica en cuanto entra en el historial, en lugar de dejar que la validez se infiera más tarde a partir de lo que casualmente se ejecutara.

Eso por sí solo no bastaba, porque un pipeline no es solo un montón de ajustes de módulos. También depende del orden, la región de interés, los contratos de búfer y el estado relacionado con la pantalla. Así que la fase de planificación acumula esas huellas a nivel de módulo a lo largo de toda la cadena e integra el resto del contrato de ejecución antes de que se mueva ningún píxel. El resultado es una identidad estable por etapa y una identidad final del pipeline.

Aquí es donde por fin aparece la visibilidad. El pipeline puede saber si sigue siendo válido comparando su hash del historial. El backbuffer mostrado puede saber si todavía coincide con el estado actual del pipe y del historial. Una línea de caché puede saber si realmente pertenece a la etapa, ROI y parámetros exactos solicitados en ese momento. Eso suena casi ofensivamente razonable, pero requirió mucha limpieza primero: la sincronización del historial con el pipeline tuvo que hacerse explícita, el bypass de la caché tuvo que declararse con antelación (para la previsualización de máscaras y las ediciones de recorte), la visualización de máscaras ya no podía mutar las reglas a mitad de ejecución, y los viejos efectos secundarios provocados por los redibujados tuvieron que desaparecer. No se obtienen hashes fiables sobre un flujo de control poco fiable.

El beneficio práctico es que la consistencia ya no se mantiene por superstición. Ya no necesitamos preguntar “¿la GUI probablemente invalidó lo correcto en el momento correcto?”. La respuesta está en las sumas de verificación. O el estado coincide, o no. Y podemos tomar cualquier salida de módulo desde la capa de la GUI, sin ejecutar un pipeline, porque la suma de verificación del módulo es predecible y puede calcularse antes del renderizado, o en paralelo.

La arquitectura centrada en la caché

Los hashes fiables cambian la arquitectura casi a la fuerza. Una vez que cada estado significativo del pipeline tiene una identidad estable conocida de antemano, la caché deja de ser una optimización de mejor esfuerzo y se convierte en el centro del flujo de datos.

Por eso el pipeline ahora tiene una verdadera fase de planificación antes de la ejecución. Primero se sincroniza el historial. Las regiones de interés se propagan por toda la cadena. Cada etapa recibe un contrato explícito de entrada y salida. La política de caché del lado del host se sella antes de la ejecución. Los hashes globales se calculan antes de la ejecución. En otras palabras, el motor sabe lo que está a punto de hacer antes de empezar a hacerlo, lo cual es un cambio refrescante respecto al método más antiguo de averiguarlo sobre la marcha y compensarlo con parches.

A partir de ahí, las búsquedas en caché se vuelven deterministas. Una etapa puede reabrir exactamente el búfer que coincide con su estado, de modo que un módulo puede omitir cálculos por completo con solo consultar la caché si una línea de caché ya coincide con su estado interno como una búsqueda de suma de verificación. Los consumidores posteriores pueden reabrir resultados publicados por hash en lugar de pedirle al renderizador que ejecute una danza especial más solo para ellos. La caché deja de ser un montón de memoria vagamente reutilizable y se convierte en el registro autoritativo de resultados intermedios y finales válidos.

Esto también explica por qué se pudo eliminar o simplificar tanto código. Una vez que la validez está centralizada, necesitas menos heurísticas, menos ramas especiales, menos cláusulas de “excepto cuando la GUI está en este modo” y menos vaciados de emergencia. El código se acorta no porque el problema se haya hecho más pequeño, sino porque dejó de resolverse en seis lugares contradictorios a la vez.

Las líneas de caché también vinculan la memoria de la GPU y de la CPU, lo que nos permite usar memoria fija (pinned) de OpenCL. Ha habido desde siempre una preferencia de usuario de OpenCL que permitía habilitar o no la memoria fija, pero descubrí que esa opción solo se usaba para el procesamiento por teselas, cuando los módulos no podían encajar todas sus necesidades de memoria en la GPU. La memoria fija ahora se ha extendido también a las operaciones normales, ya que permite mapear la RAM y la VRAM sin copiar. Usar memoria fija en un pipeline de GPU totalmente cacheado reduce el tiempo dedicado a mover búferes de memoria hasta en un factor de 7.

Pero forzar el cacheado de las salidas de los módulos OpenCL, incluso con búferes fijos de copia cero, tiene aún cierto coste, y es más costoso que simplemente omitir la caché por completo. Para algunos módulos pesados (denoise profiled, diffuse or sharpen, contrast equalizer) la sobrecarga del cacheado merece definitivamente la pena, pero para los rápidos (white balance, exposure, input color profile) el coste de cachear los búferes de OpenCL hacía que los módulos enteros se ejecutaran en realidad más lento en la GPU que en la CPU.

Así que ahora tenemos heurísticas por módulo que deciden si un módulo OpenCL publicará su búfer de salida en la caché de RAM. Los módulos pesados y todos los módulos que capturan el selector de color o histogramas se publican por defecto. Para los demás, los usuarios pueden decidir por sí mismos:

image

Esto permitirá a los usuarios también deshabilitar OpenCL de forma selectiva en algunos módulos cuando tengan problemas recurrentes con ellos. Por ejemplo, denoise profiled y dehaze consumen mucha memoria de GPU y pueden fallar durante la ejecución por falta de memoria disponible, aunque la planificación inicial de memoria hubiera determinado que debería ser suficiente. Cuando eso ocurre, el módulo ya había estado calculando durante un tiempo y recurrirá a la CPU. Si eso ocurre con frecuencia, mejor omitir la GPU en ese módulo todo el tiempo que asumir la penalización doble.

Pero no acaba ahí. Los búferes de GPU también se mantienen vivos en la GPU. Significa que reiniciar un pipeline parcial desde un módulo OpenCL obtiene la entrada directamente de la GPU cuando es posible, sin ninguna copia desde la RAM. También significa que los módulos ligeros pueden reutilizar su búfer de GPU anterior si encaja, en lugar de asignar uno nuevo. Esto por sí solo abre la posibilidad de tener un pipeline en tiempo real, necesario para el nuevo módulo Drawing, con alrededor de 60-80 ms de latencia entre las pinceladas y las actualizaciones de la imagen. Nunca habría pensado que esto sería posible en absoluto.

La misma reasignación de memoria se hace en RAM, ya que Ansel ahora aloja toda la caché en su propia arena de memoria . Este esquema no solo nos permite pre-reservar un bloque de memoria contiguo del sistema operativo al iniciar la aplicación, lo que lleva a asignaciones más rápidas, sino que también garantiza que no desbordemos el volumen de memoria definido por el usuario. Así, cuando decides asignar 8 GB de RAM a Ansel, ahora somos capaces de asegurar que eso realmente ocurra: llenaremos todo ese volumen hasta que esté lleno, tras lo cual empezamos a reciclar los búferes más antiguos. Todos los búferes de píxeles, la entrada y salida de los módulos, pero también los blocs de notas temporales internos, se asignan en nuestra arena de memoria.

Y, por último pero no menos importante, hay una sola caché de pipeline para toda la aplicación, lo que significa que todos los tipos de pipeline (previsualización del cuarto oscuro, imagen principal del cuarto oscuro, exportación de miniaturas y exportación de archivos) comparten la misma caché. Aunque esto requirió gestionarse para el acceso concurrente multihilo, significa que si un pipeline necesita una salida de módulo que ya fue calculada al mismo tamaño por otro pipeline, puede tomar directamente la línea de caché y omitir su propio recálculo.

Para aprovechar esto, la “previsualización” del cuarto oscuro, antes de tamaño fijo (es decir, la versión reducida de la imagen completa, usada en el widget de navegación, para muestrear histogramas y selectores de color, y como relleno “borroso” transitorio mientras la imagen principal se está recalculando) se ha cambiado para tener un tamaño dinámico según el nivel de zoom de “ajuste” de la imagen principal (la que se muestra en el centro del cuarto oscuro). El resultado es que solo hay que calcular una imagen cuando entras en el cuarto oscuro, y volver al zoom de “ajuste” es instantáneo.

Pero, dado que esa previsualización de tamaño fijo se había usado perezosamente en muchos lugares de la GUI para remapear las coordenadas del cursor en el espacio del widget a coordenadas de la imagen RAW a resolución completa, mediante copiar y pegar el mismo feo bloque de código por todas partes (copiando incluso el comentario que decía “no entiendo qué hace esto”), hubo que rehacer todo el sistema de coordenadas para acomodar este cambio. Y, de nuevo, esas coordenadas se calculaban solo dentro de un pipeline, así que la GUI tenía que esperar a que el pipeline recalculara los nuevos tamaños para saber dónde posicionar los objetos, lo que provocaba fallos gráficos en la GUI especialmente al cambiar el recorte. Pero ahora todo eso se calcula por adelantado desde una API unificada, así que se acabó el tonto copiar y pegar multiplicado por el número de módulos.

Qué cambió eso fuera del núcleo

La primera consecuencia externa es que las copias dejaron de disfrazarse de funciones. El cuarto oscuro ya no necesita un backbuffer de GUI dedicado para mostrar lo que el renderizador ya produjo. Puede tomar la imagen publicada directamente de la caché, enlazar una superficie de Cairo sobre ella y mostrarla en unos pocos milisegundos. Anteriormente, la ruta era más lenta y estaba ocupada copiando sin buena razón más allá de la confusión de diseño heredada. El cuarto oscuro también puede comprobar directamente si un backbuffer de pipeline dado está actualizado respecto al historial de revelado actual, mediante sumas de verificación. Anteriormente, eso dependía de un indicador “dirty” que podía ser sobrescrito por varios hilos e impedía cualquier redibujado del cuarto oscuro de “mejor esfuerzo” (es decir: plantar el último backbuffer válido conocido a la espera del recálculo del actualizado). Esto era importante cuando el usuario cambiaba los parámetros de los módulos más rápido de lo que el pipeline podía recalcular: aún necesitamos algo con lo que rellenar la vista para evitar parpadeos.

La misma lógica se extiende ahora a la exportación y las miniaturas, que pueden reabrir el resultado final publicado en lugar de reconstruir su propia realidad privada. El código del histograma y del selector también se alejó de aprovecharse de la ejecución del pipeline. Los osciloscopios siguen señales de finalización explícitas de la ruta de previsualización, cachean su propia superficie de Cairo contra el estado de origen, y muestrean directamente de backbuffers respaldados por caché. Se ha añadido el histograma raw (muestreado después del módulo demosaic) a la antigua salida del pipeline: cambiar entre ambos no requiere un recálculo del pipeline, ni tampoco el selector de color en ninguno de los dos. Ese es un diseño mucho más aburrido, que es exactamente por lo que es mejor.

Otra consecuencia importante es que las variantes de pipeline ya no viven en silos de caché aislados. Los consumidores de previsualización, cuarto oscuro, exportación, miniaturas e histograma ahora pueden compartir estado de caché. Esa era la intención que ya se insinuaba hace tiempo en el código de la caché; solo hizo falta una limpieza completa del seguimiento de validez para hacerla realidad. Una vez que todos esos consumidores coinciden en los mismos hashes, por fin pueden coincidir también en los mismos búferes. El beneficio es que un pipeline puede reutilizar la línea de caché ya calculada de otro pipe si encaja (mismo parámetro, mismo tamaño de entrada y salida). Así que el inicio de los pipelines del cuarto oscuro se ha cambiado a resolución completa: el interpolación cromática y la reducción de ruido serán más lentos al entrar en el cuarto oscuro, pero luego el zoom y el desplazamiento se vuelven instantáneos. Y exportar una imagen también tomará estas primeras etapas directamente de la caché. Por cierto, exportar la misma imagen dos veces a dos resoluciones diferentes solo recalcula a partir del módulo de escalado, al final del pipeline.

El manejo de la memoria siguió la misma lógica. Las líneas de caché pasaron a ser objetos con recuento de referencias, bloqueables y reutilizables en lugar de blobs desechables pasados de un lado a otro a través de almacenamiento secundario improvisado. Las rutas de CPU y GPU ahora comparten mucho más del mismo modelo de propiedad. En el lado de OpenCL, los búferes del host y del dispositivo se gestionan con reglas explícitas de tiempo de vida, la memoria fija se reutiliza en lugar de rotarse, y la RAM y la VRAM permanecen sincronizadas mediante transferencias fijas y de copia cero donde es posible, en lugar de reflejarse a través de copias intermedias inútiles. Esto no hace que la GPU sea mágicamente más rápida en matemáticas. Sobre todo evita que la fontanería circundante desperdicie las ganancias.

El beneficio no es solo la velocidad en los benchmarks. Es también la latencia, la robustez y el consumo de energía. El arranque del cuarto oscuro se acorta porque hay menos copias y menos pasadas duplicadas. El zoom, el desplazamiento, la previsualización de máscaras y la navegación por el historial dejan de invalidar medio universo solo porque demostrar la corrección solía ser demasiado difícil. OpenCL se vuelve menos aleatorio porque la reserva, el teselado y la propiedad de la memoria se declaran de forma más explícita. El software pasa menos tiempo moviendo píxeles de un lado a otro solo para tranquilizarse de que todavía existen en algún sitio.

Como efecto secundario, se ha mejorado el manejo de errores en el pipeline. Los módulos que fallaban al asignar memoria ahora lanzan inmediatamente un error y abortan el pipeline. Anteriormente, los fallos de asignación no se comprobaban en todas partes, y todo un pipeline podía arrastrar un búfer NULL hasta el final… o simplemente fallar sin más con errores de segmentation fault. Esto ahora se previene aguas arriba de forma uniforme en todo el software.

El muestreo del selector de color y los histogramas pueden muestrear datos sin desencadenar un recálculo del pipeline obteniéndolos directamente de la caché, si la línea de caché solicitada existe. La caja de herramientas global de osciloscopios te permite elegir entre RGB RAW (muestreado después del interpolación cromática) o RGB final del pipeline (muestreado bien después del output color profile en coma flotante de 32 bits o en el backbuffer en enteros de 8 bits): cambiar de uno a otro no reinicia un pipeline sino que simplemente carga una línea de caché diferente, y el selector de color actúa sobre esa línea de caché de forma transparente.

Qué se arregló realmente al hacerlo bien

Muchas molestias visibles se remontan a este rediseño más que a cualquier microoptimización concreta. El manejo del ROI en alta DPI mejoró porque la propiedad de la geometría se volvió más clara y el mapeo de coordenadas entre la GUI y la imagen RAW ahora se maneja en una API central. La resincronización del historial con el pipeline se volvió menos frágil porque el historial dejó de ser un efecto secundario incidental del flujo de la GUI y se convirtió en una entrada de primera clase para la planificación. La previsualización de máscaras en tiempo real ya no tiene que pelear con un modelo de caché diseñado para otra época. El refresco del histograma se volvió predecible porque ahora consume datos publicados en lugar de esperar que el búfer intermedio correcto resulte estar vivo en algún sitio. Los bucles infinitos, las líneas de caché obsoletas, los backbuffers inválidos y el clásico “la previsualización recalculó el pipe completo desde el módulo 0 sin razón aparente” se vuelven todos más fáciles de diagnosticar una vez que el ciclo de vida es explícito.

Así que la parte interesante aquí no es que ocurriera una gran refactorización de forma aislada. Es que una larga serie de limpiezas por fin se alineó en torno a una idea: la validez debería calcularse, nombrarse y compartirse por adelantado. Una vez que eso ocurrió, el resto siguió casi mecánicamente. La caché se volvió central porque los hashes eran fiables. Los consumidores externos pudieron dejar de copiar porque los búferes publicados en caché se volvieron autoritativos. Las rutas de CPU y GPU pudieron compartir más estado porque la propiedad se volvió explícita. Y el renderizador dejó de comportarse como una casa encantada donde mover un solo control deslizante podía despertar tres subsistemas no relacionados y un callback de redibujado de 2013.

Pruebas de rendimiento

Los benchmarks se hacen en ambas aplicaciones compiladas localmente con la compilación Release y GCC14 usando su respectivo script build.sh --build-type Release.

Config 1
El hardware es un Thinkpad P51, con CPU 8 × Intel Xeon E3-1505M v6 @ 3.00GHz y GPU Nvidia Quadro M2200, funcionando sobre Fedora 41 Plasma con Wayland. La versión del controlador de Nvidia es 580.105.08. El Intel Xeon es una CPU de gama alta lanzada en 2015. La Quadro M2200 es una CPU profesional de gama media lanzada en 2017.
Config 2
El hardware es un PC de sobremesa con 4 × Intel Core i3-4130 y GPU AMD Radeon RX 580 Polaris 10, funcionando sobre Ubuntu 24.04 LTS con Wayland. La versión del controlador de AMD es RustiCL 25.2.8. El Core i3 es una CPU de gama media lanzada en 2013. La AMD Polaris 10 es una GPU de gama media-alta lanzada en 2017.

Mostramos aquí la salida de ansel -d perf y darktable -d perf. Los archivos de configuración tanto de Ansel como de Darktable se ajustan con este script  para asegurar la misma línea base de configuración. La imagen de prueba de 45 Mpx está tomada de aquí  y el XMP de edición puede descargarse aquí.

Carga inicial en el cuarto oscuro

Advertencia: en Ansel, es importante ejecutar esta prueba sin ningún módulo enfocado en la GUI (es decir, desplegado). En esta situación, Ansel siempre cachea la salida del módulo anterior para que aseguremos que, cuando se hagan modificaciones en ese módulo enfocado, siempre reiniciemos los cálculos desde la entrada inmediata. Pero forzar la caché de este modo desencadena una sobrecarga de memoria que puede ser visible para los módulos ligeros.

Config 1

 13.690316 [dev_pixelpipe] took 0.000 secs (0.000 CPU) to load the image.
 24.201079 [dev_pixelpipe] pipeline resync with history took 0.029 secs (0.026 CPU) for pipe virtual-preview
 34.260916 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 44.260963 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 54.327523 [dev_pixelpipe] pipeline resync with history took 0.019 secs (0.025 CPU) for pipe preview
 64.384013 [dev_pixelpipe] took 0.056 secs (0.072 CPU) initing base buffer [preview]
 74.402520 [dev_pixelpipe] took 0.018 secs (0.031 CPU) processed `Raw settings' on GPU, blended on  [preview]
 84.421489 [dev_pixelpipe] took 0.016 secs (0.012 CPU) processed `white balance' on GPU, blended on  [preview]
 96.912680 [dev_pixelpipe] took 2.491 secs (2.470 CPU) processed `highlight reconstruction' on GPU, blended on GPU [preview]
107.167233 [dev_pixelpipe] took 0.254 secs (0.144 CPU) processed `demosaic' on GPU, blended on  [preview]
117.470521 [dev_pixelpipe] took 0.303 secs (0.173 CPU) processed `lens correction' on GPU, blended on  [preview]
127.629764 [dev_pixelpipe] took 0.159 secs (0.172 CPU) processed `Initial resampling' on GPU, blended on  [preview]
137.635593 [dev_pixelpipe] took 0.006 secs (0.006 CPU) processed `exposure' on GPU, blended on GPU [preview]
147.638110 [dev_pixelpipe] took 0.002 secs (0.001 CPU) processed `input color profile' on GPU, blended on  [preview]
157.639667 [dev_pixelpipe] took 0.002 secs (0.002 CPU) processed `color calibration' on GPU, blended on GPU [preview]
168.726634 [dev_pixelpipe] took 1.087 secs (1.090 CPU) processed `diffuse or sharpen' on GPU, blended on GPU [preview]
178.735900 [dev_pixelpipe] took 0.009 secs (0.009 CPU) processed `color balance rgb' on GPU, blended on GPU [preview]
188.742309 [dev_pixelpipe] took 0.006 secs (0.007 CPU) processed `filmic rgb' on GPU, blended on GPU [preview]
198.765175 [dev_pixelpipe] took 0.023 secs (0.029 CPU) processed `output color profile' on GPU, blended on  [preview]
208.808546 [dev_pixelpipe] took 0.043 secs (0.049 CPU) processed `dithering' on CPU, blended on  [preview]
218.820376 [dev_pixelpipe] took 0.012 secs (0.061 CPU) processed `display encoding' on CPU, blended on  [preview]
228.820439 [pixelpipe] preview internal pixel pipeline processing took 4.493 secs (4.332 CPU)
238.820483 [dev_process_preview] pipeline processing thread took 4.493 secs (4.333 CPU)
248.858716 [dev_pixelpipe] pipeline resync with history took 0.026 secs (0.032 CPU) for pipe full
258.858805 [dev_process_full] pipeline processing thread took 0.000 secs (0.000 CPU)
 110,5815 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
 210,6799 [dev_pixelpipe] took 0,018 secs (0,029 CPU) initing base buffer [full]
 310,6968 [dev_pixelpipe] took 0,017 secs (0,020 CPU) [full] processed `rawprepare' on GPU, blended on GPU
 410,7094 [dev_pixelpipe] took 0,013 secs (0,011 CPU) [full] processed `temperature' on GPU, blended on GPU
 514,4091 [dev_pixelpipe] took 3,700 secs (3,719 CPU) [full] processed `highlights' on GPU with tiling, blended on CPU
 614,8078 [resample_cl] plan 0,000 secs (0,000 CPU) resample 0,010 secs (0,002 CPU)
 714,8988 [dev_pixelpipe] took 0,490 secs (0,349 CPU) [full] processed `demosaic' on GPU, blended on GPU
 814,9094 [dev_pixelpipe] took 0,010 secs (0,001 CPU) [full] processed `lens' on GPU, blended on GPU
 914,9200 [dev_pixelpipe] took 0,010 secs (0,002 CPU) [full] processed `exposure' on GPU, blended on GPU
1014,9516 [dev_pixelpipe] took 0,032 secs (0,010 CPU) [full] processed `colorin' on GPU, blended on GPU
1114,9654 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,013 secs (0,000 GPU) [channelmixerrgb]
1214,9902 [dev_pixelpipe] took 0,039 secs (0,006 CPU) [full] processed `channelmixerrgb' on GPU, blended on GPU
1316,6800 [dev_pixelpipe] took 1,690 secs (1,745 CPU) [full] processed `diffuse' on GPU, blended on GPU
1416,6923 [dev_pixelpipe] took 0,012 secs (0,007 CPU) [full] processed `colorbalancergb' on GPU, blended on GPU
1516,7037 [dev_pixelpipe] took 0,011 secs (0,005 CPU) [full] processed `filmicrgb' on GPU, blended on GPU
1616,7100 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,006 secs (0,000 GPU) [colorout]
1716,7555 [dev_pixelpipe] took 0,052 secs (0,020 CPU) [full] processed `colorout' on GPU, blended on GPU
1816,8435 [dev_pixelpipe] took 0,088 secs (0,052 CPU) [full] processed `dither' on CPU, blended on CPU
1916,8525 [dev_pixelpipe] took 0,009 secs (0,066 CPU) [full] processed `gamma' on CPU, blended on CPU
2016,8594 [dev_process_image] pixel pipeline took 6,197 secs (6,048 CPU) processing `2022-06-17__DSC00078.arw'
21
2216,8918 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
2316,9470 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
2416,9968 [dev_pixelpipe] took 0,000 secs (0,000 CPU) initing base buffer [preview]
2516,9986 [dev_pixelpipe] took 0,002 secs (0,002 CPU) [preview] processed `rawprepare' on GPU, blended on GPU
2616,9995 [dev_pixelpipe] took 0,001 secs (0,001 CPU) [preview] processed `temperature' on GPU, blended on GPU
2717,0698 [dev_pixelpipe] took 0,070 secs (0,081 CPU) [preview] processed `highlights' on GPU, blended on GPU
2817,0811 [dev_pixelpipe] took 0,011 secs (0,005 CPU) [preview] processed `demosaic' on GPU, blended on GPU
2917,0829 [dev_pixelpipe] took 0,002 secs (0,000 CPU) [preview] processed `lens' on GPU, blended on GPU
3017,0853 [dev_pixelpipe] took 0,002 secs (0,001 CPU) [preview] processed `exposure' on GPU, blended on GPU
3117,0886 [dev_pixelpipe] took 0,003 secs (0,001 CPU) [preview] processed `colorin' on GPU, blended on GPU
3217,0915 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,003 secs (0,000 GPU) [channelmixerrgb]
3317,0952 [dev_pixelpipe] took 0,007 secs (0,002 CPU) [preview] processed `channelmixerrgb' on GPU, blended on GPU
3417,4667 [dev_pixelpipe] took 0,371 secs (0,354 CPU) [preview] processed `diffuse' on GPU, blended on GPU
3517,4702 [dev_pixelpipe] took 0,003 secs (0,001 CPU) [preview] processed `colorbalancergb' on GPU, blended on GPU
3617,4748 [dev_pixelpipe] took 0,004 secs (0,001 CPU) [preview] processed `filmicrgb' on GPU, blended on GPU
3717,4776 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,002 secs (0,000 GPU) [colorout]
3817,4939 [dev_pixelpipe] took 0,019 secs (0,009 CPU) [preview] processed `colorout' on GPU, blended on GPU
3917,5141 [dev_pixelpipe] took 0,020 secs (0,007 CPU) [preview] processed `dither' on CPU, blended on CPU
4017,5195 [dev_pixelpipe] took 0,005 secs (0,021 CPU) [preview] processed `gamma' on CPU, blended on CPU
4117,5355 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,016 secs (0,067 CPU) [final histogram]
4217,6218 [dev_process_image] pixel pipeline took 0,625 secs (0,657 CPU) processing `2022-06-17__DSC00078.arw'
 14.146713 [dev_pixelpipe] took 0.000 secs (0.000 CPU) to load the image.
 24.642451 [dev_pixelpipe] pipeline resync with history took 0.029 secs (0.026 CPU) for pipe virtual-preview
 34.703889 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 44.703915 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 54.782635 [dev_pixelpipe] pipeline resync with history took 0.033 secs (0.041 CPU) for pipe preview
 64.796521 [dev_pixelpipe] took 0.014 secs (0.018 CPU) initing base buffer [preview]
 74.831601 [dev_pixelpipe] took 0.035 secs (0.061 CPU) processed `Raw settings' on CPU, blended on  [preview]
 84.862626 [dev_pixelpipe] took 0.031 secs (0.077 CPU) processed `white balance' on CPU, blended on  [preview]
 910.978874 [dev_pixelpipe] took 6.116 secs (43.505 CPU) processed `highlight reconstruction' on CPU, blended on CPU [preview]
1011.369357 [dev_pixelpipe] took 0.390 secs (2.623 CPU) processed `demosaic' on CPU, blended on  [preview]
1111.449953 [dev_pixelpipe] took 0.081 secs (0.474 CPU) processed `lens correction' on CPU, blended on  [preview]
1211.797645 [dev_pixelpipe] took 0.348 secs (2.088 CPU) processed `Initial resampling' on CPU, blended on  [preview]
1311.802788 [dev_pixelpipe] took 0.005 secs (0.025 CPU) processed `exposure' on CPU, blended on CPU [preview]
1411.807751 [dev_pixelpipe] took 0.005 secs (0.024 CPU) processed `input color profile' on CPU, blended on  [preview]
1511.877682 [dev_pixelpipe] took 0.070 secs (0.361 CPU) processed `color calibration' on CPU, blended on CPU [preview]
1615.025427 [dev_pixelpipe] took 3.148 secs (23.610 CPU) processed `diffuse or sharpen' on CPU, blended on CPU [preview]
1715.290600 [dev_pixelpipe] took 0.262 secs (1.469 CPU) processed `color balance rgb' on CPU, blended on CPU [preview]
1815.425400 [dev_pixelpipe] took 0.135 secs (0.761 CPU) processed `filmic rgb' on CPU, blended on CPU [preview]
1915.438259 [dev_pixelpipe] took 0.013 secs (0.072 CPU) processed `output color profile' on CPU, blended on  [preview]
2015.463031 [dev_pixelpipe] took 0.025 secs (0.039 CPU) processed `dithering' on CPU, blended on  [preview]
2115.474803 [dev_pixelpipe] took 0.012 secs (0.058 CPU) processed `display encoding' on CPU, blended on  [preview]
2215.474885 [pixelpipe] preview internal pixel pipeline processing took 10.692 secs (75.269 CPU)
2315.474906 [dev_process_preview] pipeline processing thread took 10.692 secs (75.269 CPU)
2415.522324 [dev_pixelpipe] pipeline resync with history took 0.037 secs (0.047 CPU) for pipe full
2515.522431 [dev_process_full] pipeline processing thread took 0.000 secs (0.000 CPU)
 14,5577 [dt_dev_load_raw] loading the image. took 0,131 secs (0,040 CPU)
 25,4913 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
 35,6087 [dev_pixelpipe] took 0,017 secs (0,029 CPU) initing base buffer [full]
 45,6491 [dev_pixelpipe] took 0,040 secs (0,120 CPU) [full] processed `rawprepare' on CPU, blended on CPU
 55,6782 [dev_pixelpipe] took 0,029 secs (0,061 CPU) [full] processed `temperature' on CPU, blended on CPU
 612,0060 [dev_pixelpipe] took 6,328 secs (45,005 CPU) [full] processed `highlights' on CPU, blended on CPU
 712,6762 [resample_plain] plan 0,001 secs (0,001 CPU) resample 0,249 secs (1,829 CPU)
 812,7230 [dev_pixelpipe] took 0,717 secs (4,499 CPU) [full] processed `demosaic' on CPU, blended on CPU
 912,7370 [dev_pixelpipe] took 0,013 secs (0,029 CPU) [full] processed `lens' on CPU, blended on CPU
1012,7487 [dev_pixelpipe] took 0,012 secs (0,029 CPU) [full] processed `exposure' on CPU, blended on CPU
1112,7637 [dev_pixelpipe] took 0,015 secs (0,045 CPU) [full] processed `colorin' on CPU, blended on CPU
1212,7693 [dt_ioppr_transform_image_colorspace] IOP_CS_LAB-->IOP_CS_RGB took 0,006 secs (0,028 CPU) [channelmixerrgb]
1312,8473 [dev_pixelpipe] took 0,084 secs (0,438 CPU) [full] processed `channelmixerrgb' on CPU, blended on CPU
1417,0570 [dev_pixelpipe] took 4,210 secs (32,406 CPU) [full] processed `diffuse' on CPU, blended on CPU
1517,3181 [dev_pixelpipe] took 0,261 secs (1,872 CPU) [full] processed `colorbalancergb' on CPU, blended on CPU
1617,4583 [dev_pixelpipe] took 0,140 secs (0,898 CPU) [full] processed `filmicrgb' on CPU, blended on CPU
1717,4634 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0,005 secs (0,033 CPU) [colorout]
1817,4792 [dev_pixelpipe] took 0,021 secs (0,116 CPU) [full] processed `colorout' on CPU, blended on CPU
1917,5381 [dev_pixelpipe] took 0,059 secs (0,037 CPU) [full] processed `dither' on CPU, blended on CPU
2017,5472 [dev_pixelpipe] took 0,009 secs (0,061 CPU) [full] processed `gamma' on CPU, blended on CPU
2117,5543 [dev_process_image] pixel pipeline took 11,962 secs (85,649 CPU) processing `2022-06-17__DSC00078.arw'
22
2317,5861 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
2417,6428 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
2517,6993 [dev_pixelpipe] took 0,000 secs (0,000 CPU) initing base buffer [preview]
2617,7004 [dev_pixelpipe] took 0,001 secs (0,002 CPU) [preview] processed `rawprepare' on CPU, blended on CPU
2717,7015 [dev_pixelpipe] took 0,001 secs (0,004 CPU) [preview] processed `temperature' on CPU, blended on CPU
2817,8101 [dev_pixelpipe] took 0,109 secs (0,570 CPU) [preview] processed `highlights' on CPU, blended on CPU
2917,8261 [dev_pixelpipe] took 0,016 secs (0,071 CPU) [preview] processed `demosaic' on CPU, blended on CPU
3017,8308 [dev_pixelpipe] took 0,005 secs (0,006 CPU) [preview] processed `lens' on CPU, blended on CPU
3117,8345 [dev_pixelpipe] took 0,004 secs (0,006 CPU) [preview] processed `exposure' on CPU, blended on CPU
3217,8393 [dev_pixelpipe] took 0,005 secs (0,016 CPU) [preview] processed `colorin' on CPU, blended on CPU
3317,8411 [dt_ioppr_transform_image_colorspace] IOP_CS_LAB-->IOP_CS_RGB took 0,002 secs (0,008 CPU) [channelmixerrgb]
3417,8670 [dev_pixelpipe] took 0,028 secs (0,144 CPU) [preview] processed `channelmixerrgb' on CPU, blended on CPU
3519,0763 [dev_pixelpipe] took 1,209 secs (8,091 CPU) [preview] processed `diffuse' on CPU, blended on CPU
3619,1926 [dev_pixelpipe] took 0,116 secs (0,708 CPU) [preview] processed `colorbalancergb' on CPU, blended on CPU
3719,2628 [dev_pixelpipe] took 0,070 secs (0,342 CPU) [preview] processed `filmicrgb' on CPU, blended on CPU
3819,2667 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0,003 secs (0,012 CPU) [colorout]
3919,2758 [dev_pixelpipe] took 0,012 secs (0,045 CPU) [preview] processed `colorout' on CPU, blended on CPU
4019,2860 [dev_pixelpipe] took 0,010 secs (0,003 CPU) [preview] processed `dither' on CPU, blended on CPU
4119,2907 [dev_pixelpipe] took 0,005 secs (0,020 CPU) [preview] processed `gamma' on CPU, blended on CPU
4219,3052 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,014 secs (0,071 CPU) [final histogram]
4319,3928 [dev_process_image] pixel pipeline took 1,694 secs (10,211 CPU) processing `2022-06-17__DSC00078.arw'

Config 2

 136.764111 [dev_pixelpipe] took 0.313 secs (0.056 CPU) to load the image.
 237.528673 [dev_pixelpipe] pipeline resync with history took 0.044 secs (0.040 CPU) for pipe virtual-preview
 337.691646 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 437.691699 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 537.745145 [dev_pixelpipe] pipeline resync with history took 0.036 secs (0.043 CPU) for pipe preview
 637.916228 [dev_pixelpipe] took 0.171 secs (0.115 CPU) initing base buffer [preview]
 737.953157 [dev_pixelpipe] took 0.037 secs (0.024 CPU) processed `Raw settings' on GPU, blended on  [preview]
 837.959823 [dev_pixelpipe] took 0.007 secs (0.002 CPU) processed `white balance' on GPU, blended on  [preview]
 939.377680 [dev_pixelpipe] took 1.418 secs (0.196 CPU) processed `highlight reconstruction' on GPU, blended on GPU [preview]
1039.526422 [dev_pixelpipe] took 0.149 secs (0.039 CPU) processed `demosaic' on GPU, blended on  [preview]
1141.012847 [dev_pixelpipe] took 1.486 secs (0.271 CPU) processed `lens correction' on GPU, blended on  [preview]
1241.266624 [dev_pixelpipe] took 0.254 secs (0.110 CPU) processed `Initial resampling' on GPU, blended on  [preview]
1341.299983 [dev_pixelpipe] took 0.033 secs (0.025 CPU) processed `exposure' on GPU, blended on GPU [preview]
1441.311230 [dev_pixelpipe] took 0.011 secs (0.009 CPU) processed `input color profile' on GPU, blended on  [preview]
1541.313526 [dev_pixelpipe] took 0.002 secs (0.002 CPU) processed `color calibration' on GPU, blended on GPU [preview]
1641.471857 [dev_pixelpipe] took 0.158 secs (0.049 CPU) processed `diffuse or sharpen' on GPU, blended on GPU [preview]
1741.482377 [dev_pixelpipe] took 0.010 secs (0.008 CPU) processed `color balance rgb' on GPU, blended on GPU [preview]
1841.486457 [dev_pixelpipe] took 0.004 secs (0.007 CPU) processed `filmic rgb' on GPU, blended on GPU [preview]
1941.508325 [dev_pixelpipe] took 0.022 secs (0.018 CPU) processed `output color profile' on GPU, blended on  [preview]
2041.521171 [dev_pixelpipe] took 0.013 secs (0.016 CPU) processed `dithering' on CPU, blended on  [preview]
2141.529057 [dev_pixelpipe] took 0.008 secs (0.014 CPU) processed `display encoding' on CPU, blended on  [preview]
2241.529178 [pixelpipe] preview internal pixel pipeline processing took 3.784 secs (0.906 CPU)
2341.529291 [dev_process_preview] pipeline processing thread took 3.784 secs (0.906 CPU)
2441.576629 [dev_pixelpipe] pipeline resync with history took 0.036 secs (0.049 CPU) for pipe full
2541.579279 [dev_process_full] pipeline processing thread took 0.000 secs (0.000 CPU)
 123.6180 [dt_dev_load_raw] loading the image. took 0.290 secs (0.055 CPU)
 224.6549 [dt_dev_process_image_job] loading image. took 0.000 secs (0.000 CPU)
 324.7621 [dev_pixelpipe] took 0.023 secs (0.034 CPU) initing base buffer [full]
 424.8212 [dev_pixelpipe] took 0.059 secs (0.022 CPU) [full] processed `rawprepare' on GPU, blended on GPU
 524.8286 [dev_pixelpipe] took 0.007 secs (0.000 CPU) [full] processed `temperature' on GPU, blended on GPU
 626.6983 [dev_pixelpipe] took 1.870 secs (0.433 CPU) [full] processed `highlights' on GPU, blended on GPU
 726.7416 [resample_cl] plan 0.002 secs (0.001 CPU) resample 0.032 secs (0.000 CPU)
 826.8215 [dev_pixelpipe] took 0.123 secs (0.009 CPU) [full] processed `demosaic' on GPU, blended on GPU
 926.8260 [dev_pixelpipe] took 0.004 secs (0.001 CPU) [full] processed `lens' on GPU, blended on GPU
1026.8282 [dev_pixelpipe] took 0.002 secs (0.001 CPU) [full] processed `ashift' on GPU, blended on GPU
1126.8306 [dev_pixelpipe] took 0.002 secs (0.001 CPU) [full] processed `exposure' on GPU, blended on GPU
1226.8347 [dev_pixelpipe] took 0.004 secs (0.001 CPU) [full] processed `colorin' on GPU, blended on GPU
1326.8370 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0.002 secs (0.001 GPU) [channelmixerrgb]
1426.8384 [dev_pixelpipe] took 0.004 secs (0.001 CPU) [full] processed `channelmixerrgb' on GPU, blended on GPU
1527.3567 [dev_pixelpipe] took 0.518 secs (0.022 CPU) [full] processed `diffuse' on GPU, blended on GPU
1627.3613 [dev_pixelpipe] took 0.004 secs (0.001 CPU) [full] processed `colorbalancergb' on GPU, blended on GPU
1727.4019 [dev_pixelpipe] took 0.041 secs (0.011 CPU) [full] processed `filmicrgb' on GPU, blended on GPU
1827.4053 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0.003 secs (0.001 GPU) [colorout]
1927.4345 [dev_pixelpipe] took 0.032 secs (0.009 CPU) [full] processed `colorout' on GPU, blended on GPU
2027.4814 [dev_pixelpipe] took 0.047 secs (0.025 CPU) [full] processed `dither' on CPU, blended on CPU
2127.4962 [dev_pixelpipe] took 0.015 secs (0.045 CPU) [full] processed `gamma' on CPU, blended on CPU
2227.4990 [dev_process_image] pixel pipeline took 2.760 secs (0.618 CPU) processing `2022-06-17__DSC00078.arw'
23
2427.5249 [dt_dev_process_image_job] loading image. took 0.005 secs (0.013 CPU)
2527.5866 [dt_dev_process_image_job] loading image. took 0.000 secs (0.000 CPU)
2627.6513 [dev_pixelpipe] took 0.000 secs (0.000 CPU) initing base buffer [preview]
2727.6561 [dev_pixelpipe] took 0.005 secs (0.006 CPU) [preview] processed `rawprepare' on GPU, blended on GPU
2827.6580 [dev_pixelpipe] took 0.002 secs (0.001 CPU) [preview] processed `temperature' on GPU, blended on GPU
2927.7797 [dev_pixelpipe] took 0.122 secs (0.062 CPU) [preview] processed `highlights' on GPU, blended on GPU
3027.7845 [dev_pixelpipe] took 0.005 secs (0.002 CPU) [preview] processed `demosaic' on GPU, blended on GPU
3127.7854 [dev_pixelpipe] took 0.001 secs (0.000 CPU) [preview] processed `lens' on GPU, blended on GPU
3227.8023 [dev_pixelpipe] took 0.017 secs (0.002 CPU) [preview] processed `ashift' on GPU, blended on GPU
3327.8034 [dev_pixelpipe] took 0.001 secs (0.000 CPU) [preview] processed `exposure' on GPU, blended on GPU
3427.8058 [dev_pixelpipe] took 0.002 secs (0.000 CPU) [preview] processed `colorin' on GPU, blended on GPU
3527.8077 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0.001 secs (0.000 GPU) [channelmixerrgb]
3627.8089 [dev_pixelpipe] took 0.003 secs (0.000 CPU) [preview] processed `channelmixerrgb' on GPU, blended on GPU
3728.5157 [dev_pixelpipe] took 0.707 secs (0.076 CPU) [preview] processed `diffuse' on GPU, blended on GPU
3828.5240 [dev_pixelpipe] took 0.008 secs (0.004 CPU) [preview] processed `colorbalancergb' on GPU, blended on GPU
3928.6037 [dev_pixelpipe] took 0.079 secs (0.031 CPU) [preview] processed `filmicrgb' on GPU, blended on GPU
4028.6092 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0.005 secs (0.000 GPU) [colorout]
4128.6323 [dev_pixelpipe] took 0.028 secs (0.007 CPU) [preview] processed `colorout' on GPU, blended on GPU
4228.6675 [dev_pixelpipe] took 0.035 secs (0.010 CPU) [preview] processed `dither' on CPU, blended on CPU
4328.6881 [dev_pixelpipe] took 0.021 secs (0.066 CPU) [preview] processed `gamma' on CPU, blended on CPU
4428.8183 [dev_process_image] pixel pipeline took 1.167 secs (0.442 CPU) processing `2022-06-17__DSC00078.arw'
 113.969925 [dev_pixelpipe] took 0.271 secs (0.044 CPU) to load the image.
 214.519352 [dev_pixelpipe] pipeline resync with history took 0.039 secs (0.037 CPU) for pipe virtual-preview
 314.609258 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 414.609291 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 514.685917 [dev_pixelpipe] pipeline resync with history took 0.036 secs (0.048 CPU) for pipe preview
 614.724434 [dev_pixelpipe] took 0.038 secs (0.024 CPU) initing base buffer [preview]
 714.787570 [dev_pixelpipe] took 0.063 secs (0.064 CPU) processed `Raw settings' on CPU, blended on  [preview]
 814.857062 [dev_pixelpipe] took 0.069 secs (0.080 CPU) processed `white balance' on CPU, blended on  [preview]
 927.961302 [dev_pixelpipe] took 13.104 secs (32.983 CPU) processed `highlight reconstruction' on CPU, blended on CPU [preview]
1028.949286 [dev_pixelpipe] took 0.988 secs (3.057 CPU) processed `demosaic' on CPU, blended on  [preview]
1129.075925 [dev_pixelpipe] took 0.127 secs (0.326 CPU) processed `lens correction' on CPU, blended on  [preview]
1230.176998 [dev_pixelpipe] took 1.101 secs (3.061 CPU) processed `Initial resampling' on CPU, blended on  [preview]
1330.190589 [dev_pixelpipe] took 0.013 secs (0.024 CPU) processed `exposure' on CPU, blended on CPU [preview]
1430.192681 [dev_pixelpipe] took 0.002 secs (0.005 CPU) processed `input color profile' on CPU, blended on  [preview]
1530.239877 [dev_pixelpipe] took 0.047 secs (0.103 CPU) processed `color calibration' on CPU, blended on CPU [preview]
1631.944712 [dev_pixelpipe] took 1.705 secs (4.286 CPU) processed `diffuse or sharpen' on CPU, blended on CPU [preview]
1732.096771 [dev_pixelpipe] took 0.152 secs (0.407 CPU) processed `color balance rgb' on CPU, blended on CPU [preview]
1832.190015 [dev_pixelpipe] took 0.093 secs (0.228 CPU) processed `filmic rgb' on CPU, blended on CPU [preview]
1932.205505 [dev_pixelpipe] took 0.015 secs (0.028 CPU) processed `output color profile' on CPU, blended on  [preview]
2032.214424 [dev_pixelpipe] took 0.009 secs (0.011 CPU) processed `dithering' on CPU, blended on  [preview]
2132.223982 [dev_pixelpipe] took 0.009 secs (0.021 CPU) processed `display encoding' on CPU, blended on  [preview]
2232.224049 [pixelpipe] preview internal pixel pipeline processing took 17.538 secs (44.709 CPU)
2332.224090 [dev_process_preview] pipeline processing thread took 17.538 secs (44.710 CPU)
2432.276027 [dev_pixelpipe] pipeline resync with history took 0.042 secs (0.054 CPU) for pipe full
2532.276152 [dev_process_full] pipeline processing thread took 0.000 secs (0.000 CPU)
 112.5778 [dt_dev_process_image_job] loading image. took 0.000 secs (0.000 CPU)
 212.6692 [dt_dev_process_image_job] loading image. took 0.000 secs (0.000 CPU)
 312.7607 [dev_pixelpipe] took 0.018 secs (0.022 CPU) initing base buffer [full]
 412.8098 [dev_pixelpipe] took 0.049 secs (0.105 CPU) [full] processed `rawprepare' on CPU
 512.8448 [dev_pixelpipe] took 0.035 secs (0.042 CPU) [full] processed `temperature' on CPU
 625.7535 [dev_pixelpipe] took 12.909 secs (44.992 CPU) [full] processed `highlights' on CPU
 727.5129 [resample_plain] plan 0.001 secs (0.001 CPU) resample 0.732 secs (2.749 CPU)
 827.5515 [dev_pixelpipe] took 1.798 secs (6.012 CPU) [full] processed `demosaic' on CPU
 927.5571 [dev_pixelpipe] took 0.006 secs (0.005 CPU) [full] processed `lens' on CPU
1027.5603 [dev_pixelpipe] took 0.003 secs (0.003 CPU) [full] processed `ashift' on CPU
1127.5634 [dev_pixelpipe] took 0.003 secs (0.005 CPU) [full] processed `exposure' on CPU
1227.5963 [dev_pixelpipe] took 0.033 secs (0.100 CPU) [full] processed `colorin' on CPU
1327.6038 [dt_ioppr_transform_image_colorspace] IOP_CS_LAB-->IOP_CS_RGB took 0.007 secs (0.018 CPU) [channelmixerrgb]
1427.6464 [dev_pixelpipe] took 0.050 secs (0.163 CPU) [full] processed `channelmixerrgb' on CPU
1531.0132 [dev_pixelpipe] took 3.367 secs (12.611 CPU) [full] processed `diffuse' on CPU
1631.1921 [dev_pixelpipe] took 0.179 secs (0.647 CPU) [full] processed `colorbalancergb' on CPU
1731.3065 [dev_pixelpipe] took 0.114 secs (0.406 CPU) [full] processed `filmicrgb' on CPU
1831.3321 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0.025 secs (0.091 CPU) [colorout]
1931.3475 [dev_pixelpipe] took 0.041 secs (0.124 CPU) [full] processed `colorout' on CPU
2031.3754 [dev_pixelpipe] took 0.028 secs (0.020 CPU) [full] processed `dither' on CPU
2131.3849 [dev_pixelpipe] took 0.009 secs (0.034 CPU) [full] processed `gamma' on CPU
2231.3870 [dev_process_image] pixel pipeline took 18.644 secs (65.292 CPU) processing `2022-06-17__DSC00078.arw'
23
2431.4040 [dt_dev_process_image_job] loading image. took 0.000 secs (0.000 CPU)
2531.5018 [dt_dev_process_image_job] loading image. took 0.000 secs (0.000 CPU)
2631.5722 [dev_pixelpipe] took 0.000 secs (0.000 CPU) initing base buffer [preview]
2731.5824 [dev_pixelpipe] took 0.010 secs (0.014 CPU) [preview] processed `rawprepare' on CPU
2831.5861 [dev_pixelpipe] took 0.004 secs (0.008 CPU) [preview] processed `temperature' on CPU
2932.7796 [dev_pixelpipe] took 1.193 secs (4.129 CPU) [preview] processed `highlights' on CPU
3032.8917 [dev_pixelpipe] took 0.112 secs (0.387 CPU) [preview] processed `demosaic' on CPU
3132.9099 [dev_pixelpipe] took 0.018 secs (0.031 CPU) [preview] processed `lens' on CPU
3232.9433 [dev_pixelpipe] took 0.033 secs (0.050 CPU) [preview] processed `ashift' on CPU
3332.9610 [dev_pixelpipe] took 0.018 secs (0.023 CPU) [preview] processed `exposure' on CPU
3433.1087 [dev_pixelpipe] took 0.148 secs (0.532 CPU) [preview] processed `colorin' on CPU
3533.1362 [dt_ioppr_transform_image_colorspace] IOP_CS_LAB-->IOP_CS_RGB took 0.027 secs (0.096 CPU) [channelmixerrgb]
3633.3353 [dev_pixelpipe] took 0.227 secs (0.825 CPU) [preview] processed `channelmixerrgb' on CPU
3755.6386 [dev_pixelpipe] took 22.303 secs (82.427 CPU) [preview] processed `diffuse' on CPU
3856.4763 [dev_pixelpipe] took 0.837 secs (3.180 CPU) [preview] processed `colorbalancergb' on CPU
3957.0002 [dev_pixelpipe] took 0.523 secs (1.966 CPU) [preview] processed `filmicrgb' on CPU
4057.1225 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0.122 secs (0.437 CPU) [colorout]
4157.1852 [dev_pixelpipe] took 0.184 secs (0.637 CPU) [preview] processed `colorout' on CPU
4257.2043 [dev_pixelpipe] took 0.019 secs (0.018 CPU) [preview] processed `dither' on CPU
4357.2471 [dev_pixelpipe] took 0.043 secs (0.155 CPU) [preview] processed `gamma' on CPU
4457.4090 [dev_process_image] pixel pipeline took 25.837 secs (94.647 CPU) processing `2022-06-17__DSC00078.arw'

Informe

En primer lugar, al entrar en el cuarto oscuro, Darktable calcula 2 pipelines para el mismo resultado que Ansel, que calcula solo uno. Así que, independientemente de los tiempos de ejecución reales, ya de entrada es la mitad de cálculos inútiles.

Luego, Ansel calcula la imagen a resolución completa hasta el módulo initial resampling, mientras que Darktable lo hace solo hasta antes de demosaic. Esto es importante para la comparación.

Config 1 (Intel Xeon, Nvidia Quadro)

SoftwareGPUCPU
Ansel4.493 s10.692 s
Darktable 5.4.16.822 s13.66 s

Config 2 (Intel i3, AMD Radeon)

SoftwareGPUCPU
Ansel3.784 s17.538 s
Darktable 5.4.13.927 s44.481 s

En la config 1, Darktable consigue ser más lento que Ansel en GPU incluso mirando solo el renderizado del único pipeline principal e incluso reduciendo la imagen a la resolución de pantalla antes en el pipeline. Pero en realidad vemos el mismo efecto en CPU, a pesar de todas las supuestas “optimizaciones” hechas en los módulos exclusivos de CPU allá por 2023-2024 en Darktable. En conjunto, Darktable congelará tu ordenador de 2,3 a 3,0 s más.

En la config 2, la ruta de CPU muestra una penalización de 0,8 s para Ansel solo en el pipeline principal. La GPU de AMD muestra un golpe fuerte en el módulo lens correction, que procesa a resolución completa en Ansel mientras que procesa a resolución de pantalla en Darktable. Teniendo en cuenta el segundo pipeline que Darktable ejecuta, Ansel es más rápido por 0,14 s en GPU. En CPU, sin embargo, Darktable ahora congela la máquina 27,07 s más debido a ese trabajo de pipeline duplicado. En cualquier caso, los módulos lentos están al principio del pipeline y no se recalcularán durante el resto de la sesión.

Eso nos da las siguientes comparaciones de módulos lado a lado. Comparamos solo los módulos que se ejecutan a la misma resolución, solo para el pipeline de la imagen principal. En la pestaña de promedios, los factores se promedian con una media geométrica y las diferencias relativas con una media armónica:

Módulo / chipAnsel MasterDarktable 5.4.1Aceleración de Ansel
Raw settings* / CPU35 ms40 ms×1.14 / +13 %
Raw settings* / GPU18 ms17 ms×0.96 / -5.9 %
White balance* / CPU31 ms29 ms×0.94 / -6.9 %
White balance* / GPU16 ms13 ms×0.81 / -23 %
Highlights reconstruction* / CPU6.12 s6.33 s×1.03 / +3.4 %
Highlights reconstruction* / GPU2.49 s3.70 s×1.49 / +33 %
Demosaic* / CPU348 ms717 ms×2.06 / +52 %
Demosaic* / GPU254 ms490 ms×1.93 / +48 %
Exposure / CPU5 ms12 ms×2.4 / +58 %
Exposure / GPU6 ms10 ms×1.67 / +40 %
Input color profile / CPU3 ms15 ms×3 / +67 %
Input color profile / GPU2 ms32 ms×16 / +94 %
Color calibration / CPU70 ms84 ms×1.20 / +25 %
Color calibration / GPU1 ms39 ms×39 / +97 %
Diffuse or sharpen / CPU3.15 s4.21 s×1.34 / +25.2 %
Diffuse or sharpen / GPU1.09 s1.69 s×1.55 / +35 %
Color balance RGB / CPU262 ms261 ms×1.00 / -0.4 %
Color balance RGB / GPU9 ms12 ms×1.33 / +25 %
Filmic RGB / CPU137 ms140 ms×1.02 / +2.1 %
Filmic RGB / GPU6 ms11 ms×1.83 / +45 %
Output color profile / CPU13 ms21 ms×1.62 / +38 %
Output color profile / GPU23 ms52 ms×2.26 / +56 %
Dithering (CPU only) / CPU pipeline24 ms59 ms×2.46 / +59 %
Dithering (CPU only) / GPU pipeline43 ms88 ms×2.05 / +51 %
Gamma / display encoding (CPU only) / GPU pipeline12 ms9 ms×0.75 / -33 %
Gamma / display encoding (CPU only) / CPU pipeline12 ms9 ms×0.75 / -33 %

*: módulos que se ejecutan a resolución completa en ambas aplicaciones.

Módulo / chipAnsel MasterDarktable 5.4.1Aceleración de Ansel
Raw settings* / CPU63 ms49 ms×0.78 / -29 %
Raw settings* / GPU37 ms59 ms×1.59 / +37 %
White balance* / CPU69 ms35 ms×0.5 / -97 %
White balance* / GPU7 ms7 ms×1 / 0 %
Highlights reconstruction* / CPU13.10 s12.91 s×0.99 / -1.5 %
Highlights reconstruction* / GPU1.42 s1.87 s×1.32 / +24 %
Demosaic* / CPU0.99 s1.80 s×1.82 / +45 %
Demosaic* / GPU149 ms123 ms×0.83 / -21 %
Exposure / CPU13 ms3 ms×0.23 / -333 %
Exposure / GPU33 ms2 ms×0.06 / -1550 %
Input color profile / CPU2 ms33 ms×16.5 / +94 %
Input color profile / GPU11 ms4 ms×0.36 / -175 %
Color calibration / CPU47 ms50 ms×1.06 / 6 %
Color calibration / GPU2 ms4 ms×2 / +50 %
Diffuse or sharpen / CPU1.71 s3.37 s×1.97 / +49.4 %
Diffuse or sharpen / GPU158 ms518 ms×3.28 / +70 %
Color balance RGB / CPU152 ms179 ms×1.18 / +15 %
Color balance RGB / GPU10 ms4 ms×0.40 / -150 %
Filmic RGB / CPU93 ms114 ms×1.23 / +18 %
Filmic RGB / GPU4 ms41 ms×10.26 / +90 %
Output color profile / CPU15 ms41 ms×2.73 / +63 %
Output color profile / GPU22 ms32 ms×1.45 / +31 %
Dithering (CPU only) / CPU pipeline9 ms28 ms×3.62 / +72 %
Dithering (CPU only) / GPU pipeline13 ms47 ms×2.76 / +64 %
Gamma / display encoding (CPU only) / CPU pipeline9 ms9 ms×1.0 / 0 %
Gamma / display encoding (CPU only) / GPU pipeline8 ms15 ms×1.88 / +47 %

*: módulos que se ejecutan a resolución completa en ambas aplicaciones.

Promedio sobre las config 1 y 2. Los factores se promedian con una media geométrica, y las diferencias relativas con una media armónica.

Módulo / chipAceleración de AnselCódigo de Ansel
Raw settings* / CPU×0.94Personalizado (vectorizado manualmente)
Raw settings* / GPU×1.23Igual que DT 5.4.1
White balance* / CPU×0.69Personalizado (vectorizado manualmente)
White balance* / GPU×0.97Igual que DT 5.4.1
Highlights reconstruction* / CPU×1.1Personalizado (vectorizado manualmente)
Highlights reconstruction* / GPU×1.4Personalizado
Demosaic* / CPU×1.94Igual que DT 4.0
Demosaic* / GPU×1.26Personalizado
Exposure / CPU×0.74Personalizado (vectorizado manualmente)
Exposure / GPU×0.32Igual que DT 4.0
Input color profile / CPU×7.04Personalizado (vectorizado manualmente)
Input color profile / GPU×2.41Personalizado
Color calibration / CPU×1.13Personalizado (vectorizado manualmente)
Color calibration / GPU×8.83Igual que DT 4.0
Diffuse or sharpen / CPU×1.08Personalizado
Diffuse or sharpen / GPU×2.26Personalizado
Color balance RGB / CPU×1.08Personalizado (vectorizado manualmente)
Color balance RGB / GPU×0.73Personalizado
Filmic RGB / CPU×1.13Personalizado (vectorizado manualmente)
Filmic RGB / GPU×4.33Personalizado
Output color profile / CPU×2.10Personalizado (vectorizado manualmente)
Output color profile / GPU×1.81Personalizado
Dithering (CPU only) / CPU pipeline×2.71Igual que DT 4.0
Dithering (CPU only) / GPU pipeline×2.72Igual que DT 4.0
Gamma / display encoding (CPU only) / CPU pipeline×0.87Igual que DT 5.4.1
Gamma / display encoding (CPU only) / GPU pipeline×1.63Igual que DT 5.4.1

*: módulos que se ejecutan a resolución completa en ambas aplicaciones.

Velocidad relativa por módulo (GPU). Más alto es mejor.

Ansel muestra mejoras de rendimiento en GPU incluso en kernels que no han cambiado desde Darktable 4.0. Las aceleraciones que vemos son claramente el beneficio de la gestión de memoria de alto nivel, usando memoria fija de OpenCL o búferes de memoria exclusivos del dispositivo donde procede.

A través de todos los módulos, Ansel es 1,6 veces más rápido que Darktable en GPU (media geométrica).

Velocidad relativa por módulo (CPU). Más alto es mejor.

En CPU, las cosas son más matizadas.

Se supone que Darktable 5.x ha recibido optimizaciones de CPU para dithering y demosaicing (RCD), y sin embargo ambos módulos rinden peor que los de Ansel en ambas configuraciones.

Ansel tiene código de píxeles de CPU vectorizado manualmente para color balance RGB, color calibration, input/output color profile, raw settings, white balance, exposure y filmic, mientras que el de Darktable usa pistas del compilador para lograr la vectorización. Todos ellos rinden mejor que los de Darktable en el Intel Xeon. En el Intel i3, para el trabajo básico de matrices de color, Ansel rinde (mucho) mejor, pero perjudica ligeramente a módulos básicos como raw settings, exposure o white balance.

Diffuse or sharpen debería seguir usando el mismo código de Darktable 4.0 en Ansel y en Darktable 5.4, pero Ansel es más rápido en ambas configuraciones, lo que muestra el beneficio de usar nuestro propio array de memoria pre-asignado para la caché, y asignar los búferes de memoria fuera de la circuitería del sistema operativo. Esto demuestra que optimizar a nivel de módulo es el alcance equivocado, y que el pipeline global necesitaba una revisión primero.

Pero por supuesto es más fácil abordar optimizaciones por módulo porque los módulos son… modulares, es decir, autocontenidos y autosuficientes. Hay pocas probabilidades de estropear el software en su conjunto al trabajar en los módulos, porque están aislados del resto. Los cambios de arquitectura global de la aplicación, por otro lado, son peligrosos, complicados y exigentes. Y obligan a detener por completo el desarrollo de cualquier módulo nuevo mientras la arquitectura se estabiliza. Cosa que Darktable nunca tendrá la disciplina de hacer, porque el proyecto no está gestionado y en Github aparecen pull requests aleatorios en momentos aleatorios de colaboradores aleatorios.

A través de todos los módulos, Ansel es 1,8 veces más rápido que Darktable en CPU (media geométrica).

Combinando las rutas de GPU y CPU sobre ambas configuraciones, abrir el cuarto oscuro es 1,5 veces más rápido en Ansel (media geométrica).

Zoom al 100 %

En el cuarto oscuro, desde el tamaño “zoom para ajustar”, haz zoom al 100 % con un clic usando el botón central del ratón

 112.083270 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
 212.111607 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe full
 312.177976 [dev_pixelpipe] took 0.066 secs (0.095 CPU) processed `Initial resampling' on GPU, blended on  [full]
 412.179976 [dev_pixelpipe] took 0.002 secs (0.002 CPU) processed `exposure' on GPU, blended on GPU [full]
 512.183194 [dev_pixelpipe] took 0.003 secs (0.005 CPU) processed `input color profile' on GPU, blended on  [full]
 612.185327 [dev_pixelpipe] took 0.002 secs (0.002 CPU) processed `color calibration' on GPU, blended on GPU [full]
 714.887725 [dev_pixelpipe] took 2.702 secs (2.705 CPU) processed `diffuse or sharpen' on GPU, blended on GPU [full]
 814.899213 [dev_pixelpipe] took 0.011 secs (0.013 CPU) processed `color balance rgb' on GPU, blended on GPU [full]
 914.907159 [dev_pixelpipe] took 0.008 secs (0.008 CPU) processed `filmic rgb' on GPU, blended on GPU [full]
1014.940617 [dev_pixelpipe] took 0.033 secs (0.039 CPU) processed `output color profile' on GPU, blended on  [full]
1115.005967 [dev_pixelpipe] took 0.065 secs (0.057 CPU) processed `dithering' on CPU, blended on  [full]
1215.030966 [dev_pixelpipe] took 0.025 secs (0.036 CPU) processed `display encoding' on GPU, blended on  [full]
1315.031021 [pixelpipe] full internal pixel pipeline processing took 2.919 secs (2.963 CPU)
1415.031080 [dev_process_full] pipeline processing thread took 2.919 secs (2.963 CPU)
 189,3415 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
 289,3440 [dev_pixelpipe] took 0,002 secs (0,001 CPU) initing base buffer [full]
 389,3544 [dev_pixelpipe] took 0,010 secs (0,008 CPU) [full] processed `rawprepare' on GPU, blended on GPU
 489,3573 [dev_pixelpipe] took 0,003 secs (0,001 CPU) [full] processed `temperature' on GPU, blended on GPU
 589,8611 [dev_pixelpipe] took 0,504 secs (0,511 CPU) [full] processed `highlights' on GPU, blended on GPU
 689,9200 [dev_pixelpipe] took 0,059 secs (0,023 CPU) [full] processed `demosaic' on GPU, blended on GPU
 789,9251 [dev_pixelpipe] took 0,005 secs (0,003 CPU) [full] processed `lens' on GPU, blended on GPU
 889,9346 [dev_pixelpipe] took 0,009 secs (0,003 CPU) [full] processed `exposure' on GPU, blended on GPU
 989,9480 [dev_pixelpipe] took 0,013 secs (0,003 CPU) [full] processed `colorin' on GPU, blended on GPU
1089,9576 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,009 secs (0,002 GPU) [channelmixerrgb]
1189,9736 [dev_pixelpipe] took 0,026 secs (0,008 CPU) [full] processed `channelmixerrgb' on GPU, blended on GPU
1294,9286 [dev_pixelpipe] took 4,955 secs (5,096 CPU) [full] processed `diffuse' on GPU, blended on GPU
1394,9528 [dev_pixelpipe] took 0,024 secs (0,007 CPU) [full] processed `colorbalancergb' on GPU, blended on GPU
1494,9836 [dev_pixelpipe] took 0,031 secs (0,009 CPU) [full] processed `filmicrgb' on GPU, blended on GPU
1594,9925 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,009 secs (0,000 GPU) [colorout]
1695,0700 [dev_pixelpipe] took 0,086 secs (0,028 CPU) [full] processed `colorout' on GPU, blended on GPU
1795,2184 [dev_pixelpipe] took 0,148 secs (0,093 CPU) [full] processed `dither' on CPU, blended on CPU
1895,2404 [dev_pixelpipe] took 0,022 secs (0,104 CPU) [full] processed `gamma' on CPU, blended on CPU
1995,2537 [dev_process_image] pixel pipeline took 5,912 secs (5,904 CPU) processing `2022-06-17__DSC00078.arw'
2095,2634 [dev_process_image] pixel pipeline took 0,010 secs (0,004 CPU) processing `2022-06-17__DSC00078.arw'

Como Ansel procesa las primeras etapas del pipeline a resolución completa, también se cachean a resolución completa, lo que significa que el desplazamiento y el zoom obtienen la caché aguas arriba del módulo initial resampling, y solo recalculan aguas abajo. Así que tarda 2,9 s en renderizar. Darktable, por otro lado, tiene una caché que no funciona, así que lo recalcula todo desde el principio, tardando 5,9 s en renderizar lo mismo. Es una penalización de rendimiento de ×2 para Darktable.

Desplazamiento al 100 %

 155.456510 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe full
 255.536149 [dev_pixelpipe] took 0.080 secs (0.121 CPU) processed `Initial resampling' on GPU, blended on  [full]
 355.541720 [dev_pixelpipe] took 0.005 secs (0.003 CPU) processed `exposure' on GPU, recycled cacheline, blended on GPU [full]
 455.551346 [dev_pixelpipe] took 0.009 secs (0.006 CPU) processed `input color profile' on GPU, recycled cacheline, blended on  [full]
 555.559669 [dev_pixelpipe] took 0.008 secs (0.005 CPU) processed `color calibration' on GPU, recycled cacheline, blended on GPU [full]
 658.290943 [dev_pixelpipe] took 2.731 secs (2.819 CPU) processed `diffuse or sharpen' on GPU, blended on GPU [full]
 758.310400 [dev_pixelpipe] took 0.016 secs (0.017 CPU) processed `color balance rgb' on GPU, recycled cacheline, blended on GPU [full]
 858.322514 [dev_pixelpipe] took 0.012 secs (0.014 CPU) processed `filmic rgb' on GPU, recycled cacheline, blended on GPU [full]
 958.364803 [dev_pixelpipe] took 0.042 secs (0.054 CPU) processed `output color profile' on GPU, blended on  [full]
1058.411730 [dev_pixelpipe] took 0.045 secs (0.052 CPU) processed `dithering' on CPU, recycled cacheline, blended on  [full]
1158.440432 [dev_pixelpipe] took 0.029 secs (0.042 CPU) processed `display encoding' on GPU, blended on  [full]
1258.440478 [pixelpipe] full internal pixel pipeline processing took 2.984 secs (3.133 CPU)
1358.440516 [dev_process_full] pipeline processing thread took 2.984 secs (3.133 CPU)
 1253,1082 [dev_pixelpipe] took 0,003 secs (0,004 CPU) initing base buffer [full]
 2253,1132 [dev_pixelpipe] took 0,005 secs (0,004 CPU) [full] processed `rawprepare' on GPU, blended on GPU
 3253,1152 [dev_pixelpipe] took 0,002 secs (0,001 CPU) [full] processed `temperature' on GPU, blended on GPU
 4253,5743 [dev_pixelpipe] took 0,459 secs (0,441 CPU) [full] processed `highlights' on GPU, blended on GPU
 5253,6257 [dev_pixelpipe] took 0,051 secs (0,022 CPU) [full] processed `demosaic' on GPU, blended on GPU
 6253,6307 [dev_pixelpipe] took 0,005 secs (0,002 CPU) [full] processed `lens' on GPU, blended on GPU
 7253,6394 [dev_pixelpipe] took 0,009 secs (0,003 CPU) [full] processed `exposure' on GPU, blended on GPU
 8253,6521 [dev_pixelpipe] took 0,013 secs (0,003 CPU) [full] processed `colorin' on GPU, blended on GPU
 9253,6610 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,008 secs (0,001 GPU) [channelmixerrgb]
10253,6760 [dev_pixelpipe] took 0,024 secs (0,005 CPU) [full] processed `channelmixerrgb' on GPU, blended on GPU
11258,6306 [dev_pixelpipe] took 4,954 secs (4,882 CPU) [full] processed `diffuse' on GPU, blended on GPU
12258,6548 [dev_pixelpipe] took 0,024 secs (0,005 CPU) [full] processed `colorbalancergb' on GPU, blended on GPU
13258,6857 [dev_pixelpipe] took 0,031 secs (0,009 CPU) [full] processed `filmicrgb' on GPU, blended on GPU
14258,6945 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,009 secs (0,000 GPU) [colorout]
15258,7725 [dev_pixelpipe] took 0,087 secs (0,034 CPU) [full] processed `colorout' on GPU, blended on GPU
16258,9198 [dev_pixelpipe] took 0,147 secs (0,086 CPU) [full] processed `dither' on CPU, blended on CPU
17258,9373 [dev_pixelpipe] took 0,017 secs (0,110 CPU) [full] processed `gamma' on CPU, blended on CPU
18258,9407 [dev_process_image] pixel pipeline took 5,859 secs (5,614 CPU) processing `2022-06-17__DSC00078.arw'
19258,9735 [dev_process_image] pixel pipeline took 0,033 secs (0,014 CPU) processing `2022-06-17__DSC00078.arw'

El desplazamiento (panning) lleva a la misma situación que el zoom: Ansel tiene la imagen a resolución completa en caché, así que recalculamos desde el remuestreo inicial, lo que tarda 3 s. Darktable no sabe gestionar una caché correctamente, así que te toca un recálculo completo y 5,9 s de ordenador congelado.

Ir y volver a la mesa de luz

1184.536988 [dev_pixelpipe] took 0.000 secs (0.000 CPU) to load the image.
2184.574776 [dev_pixelpipe] pipeline resync with history took 0.019 secs (0.016 CPU) for pipe virtual-preview
3185.012395 [dev_pixelpipe] pipeline resync with history took 0.020 secs (0.017 CPU) for pipe virtual-preview
4185.046379 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
5185.046424 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe virtual-preview
6185.049883 [dev_pixelpipe] pipeline resync with history took 0.026 secs (0.049 CPU) for pipe preview
7185.049931 [dev_pixelpipe] pipeline resync with history took 0.000 secs (0.000 CPU) for pipe preview
8185.068516 [dev_pixelpipe] pipeline resync with history took 0.019 secs (0.020 CPU) for pipe full
9185.068568 [dev_process_full] pipeline processing thread took 0.000 secs (0.000 CPU)
 13324,5295 [histogram] took 0,006 secs (0,005 CPU) scope draw
 23324,5837 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
 33324,6371 [dev_process_image] pixel pipeline took 0,002 secs (0,001 CPU) processing `2022-06-17__DSC00078.arw'
 4
 53324,7352 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
 63324,8074 [dev_pixelpipe] took 0,000 secs (0,000 CPU) initing base buffer [preview]
 73324,8155 [dev_pixelpipe] took 0,008 secs (0,005 CPU) [preview] processed `rawprepare' on GPU, blended on GPU
 83324,8165 [dev_pixelpipe] took 0,001 secs (0,001 CPU) [preview] processed `temperature' on GPU, blended on GPU
 93324,8178 [dev_pixelpipe] took 0,001 secs (0,003 CPU) [preview] processed `highlights' on GPU, blended on GPU
103324,8337 [dev_pixelpipe] took 0,016 secs (0,021 CPU) [preview] processed `demosaic' on GPU, blended on GPU
113324,8351 [dev_pixelpipe] took 0,001 secs (0,002 CPU) [preview] processed `lens' on GPU, blended on GPU
123324,8387 [dev_pixelpipe] took 0,003 secs (0,013 CPU) [preview] processed `exposure' on GPU, blended on GPU
133324,8440 [dev_pixelpipe] took 0,005 secs (0,015 CPU) [preview] processed `colorin' on GPU, blended on GPU
143324,8491 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,005 secs (0,012 GPU) [channelmixerrgb]
153324,8545 [dev_pixelpipe] took 0,010 secs (0,019 CPU) [preview] processed `channelmixerrgb' on GPU, blended on GPU
163325,6440 [dev_pixelpipe] took 0,789 secs (0,921 CPU) [preview] processed `diffuse' on GPU, blended on GPU
173325,6482 [dev_pixelpipe] took 0,004 secs (0,003 CPU) [preview] processed `colorbalancergb' on GPU, blended on GPU
183325,6534 [dev_pixelpipe] took 0,005 secs (0,003 CPU) [preview] processed `filmicrgb' on GPU, blended on GPU
193325,6569 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,003 secs (0,002 GPU) [colorout]
203325,6747 [dev_pixelpipe] took 0,021 secs (0,008 CPU) [preview] processed `colorout' on GPU, blended on GPU
213325,6979 [dev_pixelpipe] took 0,023 secs (0,009 CPU) [preview] processed `dither' on CPU, blended on CPU
223325,7061 [dev_pixelpipe] took 0,008 secs (0,029 CPU) [preview] processed `gamma' on CPU, blended on CPU
233325,7263 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,020 secs (0,068 CPU) [final histogram]
243325,7357 [dev_process_image] pixel pipeline took 0,935 secs (1,152 CPU) processing `2022-06-17__DSC00078.arw'

La caché de pipeline de Ansel sobrevive a los propios pipelines, lo que significa que salir del cuarto oscuro y entrar de nuevo es casi instantáneo: solo tarda 60 ms en resincronizar todos los pipelines con el historial de revelado y darse cuenta de que ya tenemos la salida del pipeline en caché mediante su suma de comprobación. Ten en cuenta que aquí no hay ningún tratamiento especial de ningún tipo, es un comportamiento de caché genérico.

En el caso de Darktable, casi funciona para la imagen principal, pero no para la de vista previa, así que te toca 1 s de recálculo inútil. Dado que esto funciona en un pipe pero no en el otro, voy a apostar a que se gestiona mediante casos especiales. Comparado con Ansel, es una penalización de rendimiento de ×1,75.

Desactivar un módulo a mitad del pipeline

Desactivé difuminar o enfocar con el zoom ampliado al tamaño “llenar”.

 1124.206298 [dev_pixelpipe] pipeline resync with history took 0.011 secs (0.010 CPU) for pipe virtual-preview
 2124.237640 [dev_pixelpipe] pipeline resync with history took 0.011 secs (0.028 CPU) for pipe preview
 3124.290940 [dev_pixelpipe] took 0.023 secs (0.028 CPU) processed `color balance rgb' on GPU, recycled cacheline, blended on GPU [preview]
 4124.303176 [dev_pixelpipe] took 0.012 secs (0.012 CPU) processed `filmic rgb' on GPU, recycled cacheline, blended on GPU [preview]
 5124.331334 [dev_pixelpipe] took 0.028 secs (0.030 CPU) processed `output color profile' on GPU, blended on  [preview]
 6124.370193 [darkroom] took 0.007 secs (0.011 CPU) redraw
 7124.382425 [dev_pixelpipe] took 0.051 secs (0.055 CPU) processed `dithering' on CPU, blended on  [preview]
 8124.410053 [dev_pixelpipe] took 0.028 secs (0.028 CPU) processed `display encoding' on GPU, blended on  [preview]
 9124.410088 [pixelpipe] preview internal pixel pipeline processing took 0.172 secs (0.197 CPU)
10124.410115 [dev_process_preview] pipeline processing thread took 0.172 secs (0.197 CPU)
11124.433186 [dev_pixelpipe] pipeline resync with history took 0.013 secs (0.017 CPU) for pipe full
12124.433286 [dev_process_full] pipeline processing thread took 0.000 secs (0.000 CPU)
 1300,9771 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
 2301,0564 [dev_pixelpipe] took 0,016 secs (0,028 CPU) initing base buffer [full]
 3301,0936 [dev_pixelpipe] took 0,037 secs (0,037 CPU) [full] processed `rawprepare' on GPU, blended on GPU
 4301,1102 [dev_pixelpipe] took 0,017 secs (0,017 CPU) [full] processed `temperature' on GPU, blended on GPU
 5304,8700 [dev_pixelpipe] took 3,760 secs (3,786 CPU) [full] processed `highlights' on GPU with tiling, blended on CPU
 6305,2630 [resample_cl] plan 0,001 secs (0,000 CPU) resample 0,010 secs (0,001 CPU)
 7305,3543 [dev_pixelpipe] took 0,484 secs (0,284 CPU) [full] processed `demosaic' on GPU, blended on GPU
 8305,3648 [dev_pixelpipe] took 0,010 secs (0,002 CPU) [full] processed `lens' on GPU, blended on GPU
 9305,3764 [dev_pixelpipe] took 0,012 secs (0,001 CPU) [full] processed `exposure' on GPU, blended on GPU
10305,4083 [dev_pixelpipe] took 0,032 secs (0,007 CPU) [full] processed `colorin' on GPU, blended on GPU
11305,4220 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,013 secs (0,001 GPU) [channelmixerrgb]
12305,4460 [dev_pixelpipe] took 0,038 secs (0,008 CPU) [full] processed `channelmixerrgb' on GPU, blended on GPU
13307,1388 [dev_pixelpipe] took 1,693 secs (1,645 CPU) [full] processed `diffuse' on GPU, blended on GPU
14307,1500 [dev_pixelpipe] took 0,011 secs (0,003 CPU) [full] processed `colorbalancergb' on GPU, blended on GPU
15307,1612 [dev_pixelpipe] took 0,011 secs (0,003 CPU) [full] processed `filmicrgb' on GPU, blended on GPU
16307,1675 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,006 secs (0,001 GPU) [colorout]
17307,2185 [dev_pixelpipe] took 0,057 secs (0,020 CPU) [full] processed `colorout' on GPU, blended on GPU
18307,3095 [dev_pixelpipe] took 0,091 secs (0,056 CPU) [full] processed `dither' on CPU, blended on CPU
19307,3235 [dev_pixelpipe] took 0,014 secs (0,065 CPU) [full] processed `gamma' on CPU, blended on CPU
20307,3333 [dev_process_image] pixel pipeline took 6,293 secs (5,969 CPU) processing `2022-06-17__DSC00078.arw'
21307,3843 [dev_process_image] pixel pipeline took 0,051 secs (0,018 CPU) processing `2022-06-17__DSC00078.arw'
22
23307,4258 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
24307,4875 [dev_pixelpipe] took 0,000 secs (0,000 CPU) initing base buffer [preview]
25307,4895 [dev_pixelpipe] took 0,002 secs (0,002 CPU) [preview] processed `rawprepare' on GPU, blended on GPU
26307,4906 [dev_pixelpipe] took 0,001 secs (0,001 CPU) [preview] processed `temperature' on GPU, blended on GPU
27307,5609 [dev_pixelpipe] took 0,070 secs (0,072 CPU) [preview] processed `highlights' on GPU, blended on GPU
28307,5722 [dev_pixelpipe] took 0,011 secs (0,005 CPU) [preview] processed `demosaic' on GPU, blended on GPU
29307,5740 [dev_pixelpipe] took 0,002 secs (0,000 CPU) [preview] processed `lens' on GPU, blended on GPU
30307,5765 [dev_pixelpipe] took 0,002 secs (0,001 CPU) [preview] processed `exposure' on GPU, blended on GPU
31307,5798 [dev_pixelpipe] took 0,003 secs (0,002 CPU) [preview] processed `colorin' on GPU, blended on GPU
32307,5827 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,002 secs (0,002 GPU) [channelmixerrgb]
33307,5864 [dev_pixelpipe] took 0,007 secs (0,003 CPU) [preview] processed `channelmixerrgb' on GPU, blended on GPU
34307,9576 [dev_pixelpipe] took 0,371 secs (0,356 CPU) [preview] processed `diffuse' on GPU, blended on GPU
35307,9613 [dev_pixelpipe] took 0,003 secs (0,002 CPU) [preview] processed `colorbalancergb' on GPU, blended on GPU
36307,9659 [dev_pixelpipe] took 0,005 secs (0,000 CPU) [preview] processed `filmicrgb' on GPU, blended on GPU
37307,9686 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,002 secs (0,000 GPU) [colorout]
38307,9847 [dev_pixelpipe] took 0,019 secs (0,008 CPU) [preview] processed `colorout' on GPU, blended on GPU
39308,0043 [dev_pixelpipe] took 0,020 secs (0,011 CPU) [preview] processed `dither' on CPU, blended on CPU
40308,0103 [dev_pixelpipe] took 0,006 secs (0,023 CPU) [preview] processed `gamma' on CPU, blended on CPU
41308,0244 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,014 secs (0,081 CPU) [final histogram]
42308,0353 [dev_process_image] pixel pipeline took 0,553 secs (0,604 CPU) processing `2022-06-17__DSC00078.arw'

De nuevo, la caché de Ansel simplemente funciona: desactivar difuminar o enfocar lleva a recalcular únicamente los módulos posteriores, lo que tarda 172 ms. De nuevo, la caché de Darktable no funciona, lo que lleva a recalcular los 2 pipelines enteros (vista previa y principal), por un coste total de 6,9 s. ¡Eso es una penalización de rendimiento de ×40, amigos! ¡Eso hace que todas las aceleraciones espurias del +15 % de Ralf Brown sean completamente irrelevantes! Pero ¡oye! ¡Sigue buscando tus llaves perdidas donde puedes verte los pies en lugar de donde las perdiste! .

Seleccionar color en un módulo

Ajustamos el balance de blancos en la calibración de color usando el selector de color, con el nivel de zoom “ajustar a la ventana”.

 1colorpicker stats reading took 0.020 secs (0.088 CPU)
 2colorpicker stats reading took 0.018 secs (0.087 CPU)
 312.128030 [dev_pixelpipe] pipeline resync with history took 0.024 secs (0.037 CPU) for pipe virtual-preview
 412.137829 [dev_pixelpipe] pipeline resync with history took 0.024 secs (0.056 CPU) for pipe preview
 512.157665 [dev_pixelpipe] took 0.020 secs (0.048 CPU) processed `color calibration' on GPU, blended on GPU [preview]
 613.327326 [dev_pixelpipe] took 1.170 secs (1.231 CPU) processed `diffuse or sharpen' on GPU, blended on GPU [preview]
 713.336618 [dev_pixelpipe] took 0.009 secs (0.008 CPU) processed `color balance rgb' on GPU, recycled cacheline, blended on GPU [preview]
 813.345393 [dev_pixelpipe] took 0.009 secs (0.007 CPU) processed `filmic rgb' on GPU, recycled cacheline, blended on GPU [preview]
 913.368053 [dev_pixelpipe] took 0.023 secs (0.030 CPU) processed `output color profile' on GPU, blended on  [preview]
1013.418643 [dev_pixelpipe] took 0.050 secs (0.061 CPU) processed `dithering' on CPU, blended on  [preview]
1113.435846 [dev_pixelpipe] took 0.017 secs (0.024 CPU) processed `display encoding' on GPU, blended on  [preview]
1213.435919 [pixelpipe] preview internal pixel pipeline processing took 1.298 secs (1.408 CPU)
1313.435949 [dev_process_preview] pipeline processing thread took 1.298 secs (1.408 CPU)
1413.526316 [dev_pixelpipe] pipeline resync with history took 0.080 secs (0.376 CPU) for pipe full
1513.526443 [dev_process_full] pipeline processing thread took 0.000 secs (0.000 CPU)
16colorpicker stats reading took 0.185 secs (0.741 CPU)
17image colorspace transform RGB-->RGB took 0.000 secs (0.000 CPU) [[histogram] sample swatch]
18image colorspace transform RGB-->RGB took 0.000 secs (0.000 CPU) [[histogram] sample swatch]
19image colorspace transform RGB-->RGB took 0.000 secs (0.000 CPU) [[histogram] sample swatch]
 116,1190 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
 216,1364 dt_color_picker_helper stats reading 4 channels (filters 2492765332) cst 2 -> 2 size 1118880 denoised 0 took 0,001 secs (0,005 CPU)
 316,1396 [dev_pixelpipe] took 0,020 secs (0,025 CPU) [preview] processed `channelmixerrgb' on GPU, blended on GPU
 416,2071 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
 516,6064 [dev_pixelpipe] took 0,467 secs (0,567 CPU) [preview] processed `diffuse' on GPU, blended on GPU
 616,6106 [dev_pixelpipe] took 0,004 secs (0,004 CPU) [preview] processed `colorbalancergb' on GPU, blended on GPU
 716,6160 [dev_pixelpipe] took 0,005 secs (0,001 CPU) [preview] processed `filmicrgb' on GPU, blended on GPU
 816,6192 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,003 secs (0,002 GPU) [colorout]
 916,6364 [dev_pixelpipe] took 0,020 secs (0,010 CPU) [preview] processed `colorout' on GPU, blended on GPU
1016,6513 [dev_pixelpipe] took 0,015 secs (0,005 CPU) [preview] processed `dither' on CPU, blended on CPU
1116,6572 [dev_pixelpipe] took 0,006 secs (0,023 CPU) [preview] processed `gamma' on CPU, blended on CPU
1216,6584 dt_color_picker_helper stats reading 4 channels (filters 2492765332) cst 2 -> 2 size 1118880 denoised 0 took 0,001 secs (0,005 CPU)
1316,6586 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0,000 secs (0,000 CPU) [gamma]
1416,6587 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,000 secs (0,000 CPU) [primary picker]
1516,6754 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,017 secs (0,063 CPU) [final histogram]
1616,6843 [histogram] took 0,026 secs (0,093 CPU) final waveform
1716,6847 [dev_process_image] pixel pipeline took 0,566 secs (0,733 CPU) processing `2022-06-17__DSC00078.arw'
18
1916,6854 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
2020,3395 [dev_pixelpipe] took 3,606 secs (3,778 CPU) [full] processed `highlights' on GPU with tiling, blended on CPU
2120,7350 [resample_cl] plan 0,001 secs (0,000 CPU) resample 0,010 secs (0,001 CPU)
2220,8263 [dev_pixelpipe] took 0,487 secs (0,285 CPU) [full] processed `demosaic' on GPU, blended on GPU
2320,8389 [dev_pixelpipe] took 0,012 secs (0,002 CPU) [full] processed `lens' on GPU, blended on GPU
2420,8505 [dev_pixelpipe] took 0,012 secs (0,002 CPU) [full] processed `exposure' on GPU, blended on GPU
2520,8812 [dev_pixelpipe] took 0,031 secs (0,008 CPU) [full] processed `colorin' on GPU, blended on GPU
2620,8972 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,016 secs (0,004 GPU) [channelmixerrgb]
2720,9551 [dev_pixelpipe] took 0,074 secs (0,023 CPU) [full] processed `channelmixerrgb' on GPU, blended on GPU
2821,8137 [dev_pixelpipe] took 0,000 secs (0,000 CPU) initing base buffer [preview]
2921,8160 [dev_pixelpipe] took 0,001 secs (0,005 CPU) [preview] processed `rawprepare' on CPU, blended on CPU
3021,8173 [dev_pixelpipe] took 0,001 secs (0,001 CPU) [preview] processed `temperature' on CPU, blended on CPU
3121,9879 [dev_pixelpipe] took 0,171 secs (0,758 CPU) [preview] processed `highlights' on CPU, blended on CPU
3222,0020 [dev_pixelpipe] took 0,014 secs (0,080 CPU) [preview] processed `demosaic' on CPU, blended on CPU
3322,0103 [dev_pixelpipe] took 0,008 secs (0,016 CPU) [preview] processed `lens' on CPU, blended on CPU
3422,0127 [dev_pixelpipe] took 0,002 secs (0,014 CPU) [preview] processed `exposure' on CPU, blended on CPU
3522,0155 [dev_pixelpipe] took 0,003 secs (0,015 CPU) [preview] processed `colorin' on CPU, blended on CPU
3622,0172 [dt_ioppr_transform_image_colorspace] IOP_CS_LAB-->IOP_CS_RGB took 0,002 secs (0,009 CPU) [channelmixerrgb]
3722,0457 dt_color_picker_helper stats reading 4 channels (filters 2492765332) cst 2 -> 2 size 1118880 denoised 0 took 0,002 secs (0,013 CPU)
3822,0458 [dev_pixelpipe] took 0,030 secs (0,180 CPU) [preview] processed `channelmixerrgb' on CPU, blended on CPU
3922,6461 [dev_pixelpipe] took 1,691 secs (5,549 CPU) [full] processed `diffuse' on GPU, blended on GPU
4022,6595 [dev_pixelpipe] took 0,013 secs (0,079 CPU) [full] processed `colorbalancergb' on GPU, blended on GPU
4122,6725 [dev_pixelpipe] took 0,013 secs (0,073 CPU) [full] processed `filmicrgb' on GPU, blended on GPU
4222,6824 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,007 secs (0,041 GPU) [colorout]
4322,7443 [dev_pixelpipe] took 0,072 secs (0,398 CPU) [full] processed `colorout' on GPU, blended on GPU
4422,8624 [dev_pixelpipe] took 0,118 secs (0,664 CPU) [full] processed `dither' on CPU, blended on CPU
4522,8878 [dev_pixelpipe] took 0,025 secs (0,172 CPU) [full] processed `gamma' on CPU, blended on CPU
4622,8894 [dev_process_image] pixel pipeline took 6,637 secs (11,596 CPU) processing `2022-06-17__DSC00078.arw'
4723,4204 [dev_pixelpipe] took 1,374 secs (8,556 CPU) [preview] processed `diffuse' on CPU, blended on CPU
4823,5271 [dev_pixelpipe] took 0,106 secs (0,617 CPU) [preview] processed `colorbalancergb' on CPU, blended on CPU
4923,5788 [dev_pixelpipe] took 0,051 secs (0,291 CPU) [preview] processed `filmicrgb' on CPU, blended on CPU
5023,5817 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0,003 secs (0,011 CPU) [colorout]
5123,5870 [dev_pixelpipe] took 0,008 secs (0,037 CPU) [preview] processed `colorout' on CPU, blended on CPU
5223,5913 [dev_pixelpipe] took 0,004 secs (0,004 CPU) [preview] processed `dither' on CPU, blended on CPU
5323,5964 [dev_pixelpipe] took 0,005 secs (0,021 CPU) [preview] processed `gamma' on CPU, blended on CPU
5423,5973 dt_color_picker_helper stats reading 4 channels (filters 2492765332) cst 2 -> 2 size 1118880 denoised 0 took 0,001 secs (0,006 CPU)
5523,5976 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0,000 secs (0,000 CPU) [gamma]
5623,5977 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,000 secs (0,000 CPU) [primary picker]
5723,6099 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,012 secs (0,067 CPU) [final histogram]
5823,6215 [histogram] took 0,024 secs (0,097 CPU) final waveform
5923,6219 [dev_process_image] pixel pipeline took 6,889 secs (15,651 CPU) processing `2022-06-17__DSC00078.arw'

Ansel no necesita iniciar un nuevo renderizado del pipeline para muestrear el selector de color, porque la entrada y la salida del módulo siguen en caché, así que tarda un total de 40 ms en muestrear. Luego los nuevos parámetros se aplican al módulo, lo que cambia el historial y desencadena un recálculo del módulo calibración de color y de todos los módulos posteriores. Tiempo total invertido: 1,4 s.

Darktable necesita reiniciar un nuevo renderizado del pipeline para muestrear el selector de color porque ¿por qué no? Eso tarda 0,6 s. Te complacerá saber que Darktable muestrea el color en la GPU, lo que tarda solo 1 ms (en medio de esos 0,6 s de ejecución del pipeline), mientras que Ansel muestrea en la CPU en 20 ms. Luego los parámetros del selector de color se aplican al historial, lo que reinicia un recálculo completo de los 2 pipelines. Tiempo total invertido: 7,5 s.

Eso es una penalización de ×5,4 para Darktable, todo ello porque no están mejorando sus pipelines, sino embarcándose en todas las persecuciones inútiles imaginables.

Exportar a resolución completa

Exportamos después de haber abierto la imagen en el cuarto oscuro. Esto es importante. En Darktable se usa el muestreo de “alta calidad”; en Ansel es el único modo.

 118.917740 [dev_pixelpipe] took 0.000 secs (0.000 CPU) to load the image.
 218.970877 [export] creating pixelpipe took 0.054 secs (0.074 CPU)
 319.215438 [dev_pixelpipe] took 0.244 secs (0.222 CPU) processed `exposure' on GPU, blended on GPU [export]
 419.241544 [dev_pixelpipe] took 0.026 secs (0.025 CPU) processed `input color profile' on GPU, blended on  [export]
 519.267887 [dev_pixelpipe] took 0.026 secs (0.026 CPU) processed `color calibration' on GPU, blended on GPU [export]
 656.171662 [dev_pixelpipe] took 36.904 secs (36.592 CPU) processed `diffuse or sharpen' on GPU with tiling, blended on CPU [export]
 756.364588 [dev_pixelpipe] took 0.193 secs (0.156 CPU) processed `color balance rgb' on GPU, blended on GPU [export]
 857.293819 [dev_pixelpipe] took 0.929 secs (0.468 CPU) processed `filmic rgb' on GPU with tiling, blended on CPU [export]
 957.516252 [dev_pixelpipe] took 0.222 secs (0.176 CPU) processed `output color profile' on GPU, blended on  [export]
1057.534628 [dev_pixelpipe] took 0.018 secs (0.017 CPU) processed `Final resampling' on GPU, blended on  [export]
1158.462789 [dev_pixelpipe] took 0.928 secs (0.544 CPU) processed `dithering' on CPU, blended on  [export]
1258.462829 [pixelpipe] export internal pixel pipeline processing took 39.492 secs (38.227 CPU)
1358.462898 [dev_process_export] pixel pipeline processing thread took 39.492 secs (38.227 CPU)
14[export_job] exported to `/home/aurelienpierre/Téléchargements/2022-06-17__DSC00078_08.jpg'
 1526,9861 [export] creating pixelpipe took 0,063 secs (0,091 CPU)
 2526,9862 [dev_pixelpipe] took 0,000 secs (0,000 CPU) initing base buffer [export]
 3527,0072 [dev_pixelpipe] took 0,021 secs (0,020 CPU) [export] processed `rawprepare' on GPU, blended on GPU
 4527,0237 [dev_pixelpipe] took 0,016 secs (0,007 CPU) [export] processed `temperature' on GPU, blended on GPU
 5530,7560 [dev_pixelpipe] took 3,732 secs (3,868 CPU) [export] processed `highlights' on GPU with tiling, blended on CPU
 6531,1444 [dev_pixelpipe] took 0,388 secs (0,201 CPU) [export] processed `demosaic' on GPU, blended on GPU
 7531,9899 [dev_pixelpipe] took 0,845 secs (0,493 CPU) [export] processed `lens' on GPU with tiling, blended on CPU
 8532,1378 [dev_pixelpipe] took 0,148 secs (0,139 CPU) [export] processed `exposure' on GPU, blended on GPU
 9532,1968 [dev_pixelpipe] took 0,059 secs (0,047 CPU) [export] processed `colorin' on GPU, blended on GPU
10532,2287 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,031 secs (0,019 GPU) [channelmixerrgb]
11532,3206 [dev_pixelpipe] took 0,124 secs (0,089 CPU) [export] processed `channelmixerrgb' on GPU, blended on GPU
12575,5645 [dev_pixelpipe] took 43,244 secs (43,220 CPU) [export] processed `diffuse' on GPU with tiling, blended on CPU
13575,7422 [dev_pixelpipe] took 0,178 secs (0,167 CPU) [export] processed `colorbalancergb' on GPU, blended on GPU
14576,2975 [dev_pixelpipe] took 0,555 secs (0,474 CPU) [export] processed `filmicrgb' on GPU with tiling, blended on CPU
15576,3897 [resample_cl] took 0,000 secs (0,000 CPU) 1:1 copy/crop of 7968x5320 pixels
16576,4081 [dev_pixelpipe] took 0,111 secs (0,101 CPU) [export] processed `finalscale' on GPU, blended on GPU
17576,4403 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,032 secs (0,020 GPU) [colorout]
18576,5618 [dev_pixelpipe] took 0,154 secs (0,120 CPU) [export] processed `colorout' on GPU, blended on GPU
19577,0202 [dev_pixelpipe] took 0,458 secs (0,456 CPU) [export] processed `dither' on CPU, blended on CPU
20577,0204 [dev_process_export] pixel pipeline processing took 50,034 secs (49,403 CPU)
21578,2407 [export_job] exported to `/home/aurelienpierre/Téléchargements/2022-06-17__DSC00078_06.jpg'

En Ansel, como abrimos la imagen previamente en el cuarto oscuro, las primeras etapas del pipeline siguen en caché, así que la exportación arranca desde el módulo exposición y tarda 39,5 s. En Darktable, bueno… lo de siempre: es un recálculo completo del pipeline que tarda 50 s.

Exportar de nuevo a media resolución

Exportamos a media resolución justo después de haber exportado a resolución completa.

165.601240 [dev_pixelpipe] took 0.000 secs (0.000 CPU) to load the image.
265.658874 [export] creating pixelpipe took 0.060 secs (0.079 CPU)
365.912677 [dev_pixelpipe] took 0.254 secs (0.233 CPU) processed `output color profile' on GPU, blended on  [export]
465.972780 [dev_pixelpipe] took 0.060 secs (0.073 CPU) processed `Final resampling' on GPU, blended on  [export]
566.160165 [dev_pixelpipe] took 0.187 secs (0.238 CPU) processed `dithering' on CPU, blended on  [export]
666.160184 [pixelpipe] export internal pixel pipeline processing took 0.501 secs (0.544 CPU)
766.160202 [dev_process_export] pixel pipeline processing thread took 0.501 secs (0.545 CPU)
8[export_job] exported to `/home/aurelienpierre/Téléchargements/2022-06-17__DSC00078_09.jpg'
 1607,7584 [export] creating pixelpipe took 0,064 secs (0,088 CPU)
 2607,7586 [dev_pixelpipe] took 0,000 secs (0,000 CPU) initing base buffer [export]
 3607,7918 [dev_pixelpipe] took 0,033 secs (0,028 CPU) [export] processed `rawprepare' on GPU, blended on GPU
 4607,8083 [dev_pixelpipe] took 0,016 secs (0,007 CPU) [export] processed `temperature' on GPU, blended on GPU
 5611,5555 [dev_pixelpipe] took 3,747 secs (3,865 CPU) [export] processed `highlights' on GPU with tiling, blended on CPU
 6611,9454 [dev_pixelpipe] took 0,390 secs (0,201 CPU) [export] processed `demosaic' on GPU, blended on GPU
 7612,7083 [dev_pixelpipe] took 0,763 secs (0,462 CPU) [export] processed `lens' on GPU with tiling, blended on CPU
 8612,8559 [dev_pixelpipe] took 0,148 secs (0,137 CPU) [export] processed `exposure' on GPU, blended on GPU
 9612,9149 [dev_pixelpipe] took 0,059 secs (0,045 CPU) [export] processed `colorin' on GPU, blended on GPU
10612,9468 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,032 secs (0,021 GPU) [channelmixerrgb]
11613,0390 [dev_pixelpipe] took 0,124 secs (0,090 CPU) [export] processed `channelmixerrgb' on GPU, blended on GPU
12656,1897 [dev_pixelpipe] took 43,151 secs (42,852 CPU) [export] processed `diffuse' on GPU with tiling, blended on CPU
13656,3673 [dev_pixelpipe] took 0,178 secs (0,167 CPU) [export] processed `colorbalancergb' on GPU, blended on GPU
14656,9163 [dev_pixelpipe] took 0,549 secs (0,467 CPU) [export] processed `filmicrgb' on GPU with tiling, blended on CPU
15657,0078 [resample_cl] plan 0,001 secs (0,000 CPU) resample 0,001 secs (0,000 CPU)
16657,1070 [dev_pixelpipe] took 0,191 secs (0,181 CPU) [export] processed `finalscale' on GPU, blended on GPU
17657,1233 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,016 secs (0,004 GPU) [colorout]
18657,1792 [dev_pixelpipe] took 0,072 secs (0,030 CPU) [export] processed `colorout' on GPU, blended on GPU
19657,3186 [dev_pixelpipe] took 0,139 secs (0,136 CPU) [export] processed `dither' on CPU, blended on CPU
20657,3187 [dev_process_export] pixel pipeline processing took 49,560 secs (48,669 CPU)
21657,8107 [export_job] exported to `/home/aurelienpierre/Téléchargements/2022-06-17__DSC00078_07.jpg'

Como Ansel siempre exporta a resolución completa hasta el módulo remuestreo final (el modo llamado “alta calidad” en Darktable), el pipeline se mantiene igual en su mayor parte sin importar el tamaño final. Dado que la caché de Ansel funciona, la imagen a resolución completa exportada anteriormente sigue en caché, así que solo recalculamos las últimas etapas: perfil de color de salida, submuestreo, tramado. Eso tarda 0,5 s.

Darktable, como de costumbre, no gestiona lo que ha calculado antes, así que te toca otra exportación completa de ~50 s. O sea, una penalización de rendimiento de ×100.

Ten en cuenta que la caché de pipeline de Ansel tiene una recolección de basura que vacía todas las líneas de caché sin usar más antiguas de 5 minutos, así que esto no funcionaría si esperas demasiado tiempo.

Conclusión

Es hilarante leer, en foros de tech-bros como discuss.pixls.us , que la gente confía más en Darktable que en Ansel porque el primero tiene muchos más monos agitando las manos en el aire y fingiendo trabajar, lo cual aparentemente basta para dar una sensación completamente errónea de fiabilidad y confianza. Es simplemente la prueba definitiva de que la gente no tiene ni idea de lo que ocurre en el código. Pero es una enfermedad capitalista confundir agitación con trabajo, y un trabajo que no crea valor todavía puede venderse como progreso con el marketing adecuado.

Yo no doy opiniones, hago benchmarks. Las cifras que he publicado aquí se pueden reproducir por completo:

Darktable performance penalty per benchmark case
  • los módulos individuales son en promedio 1,4 veces más rápidos en Ansel CPU comparado con Darktable CPU,
  • los módulos individuales son en promedio 1,6 veces más rápidos en Ansel GPU comparado con Darktable GPU,
  • los pipelines completos son entre 1,5 veces y 100 veces más rápidos en Ansel comparado con Darktable GPU, porque Ansel tiene una caché que funciona,
  • Ansel no es solo más rápido, también es más eficiente energéticamente, porque se (re)calculan menos cosas.

Todo esto se logró eliminando el código de la interfaz gráfica (GUI) del código de renderizado del pipeline, haciendo el ciclo de vida de los datos más claro, más simple y más robusto, no añadiendo más tratamiento de casos especiales y soluciones improvisadas. Ansel es capaz de usar mucha más RAM que Darktable, a la vez que lleva la contabilidad necesaria para saber cuánta usa en realidad y si debería empezar a reciclar memoria.

Todo esto es la prueba de que el “equipo” de Darktable no está mejorando el software, de que su (falta de) gestión está perjudicando activamente al software. Ha habido muchas “optimizaciones” anunciadas en las notas de versión desde 2022. Y aun así su software sigue siendo una bestia de ineficiencia dolorosamente lenta.

Ten en cuenta que las optimizaciones a nivel de módulo hechas en Darktable pueden portarse a Ansel, aunque no todas parecen aceleraciones reales por lo que se muestra aquí. Algunas ya se han portado. Pero Darktable no puede portar la arquitectura de pipeline de Ansel, que es de donde provienen la mayoría de nuestras aceleraciones.

Durante este trabajo, también perdí la fe en Vkdt . Vkdt es un intento renovado, por parte del fundador de Darktable, Johannes Hannika, de reiniciar desde cero un software de fotografía RAW que se ejecuta enteramente en la GPU a través de Vulkan. Pero tras 4 años limpiando la mierda de otros, hay un par de cosas que he aprendido:

  1. Las ralentizaciones de Darktable no son culpa de la pila GTK ni de la pila OpenCL. De acuerdo, no son estupendas, pero eso se puede gestionar. Son errores de programación y mal diseño que no se reevaluó a medida que las necesidades y los requisitos del software cambiaban.
  2. Un diseño que prioriza la caché permite ocultar muchas latencias evitando recálculos, y un flujo de trabajo enteramente en GPU pronto se enfrentará a las limitaciones de memoria de las GPU.
  3. Las GPU se están volviendo cada vez más caras, tras la fiebre de las criptomonedas y ahora la fiebre de la IA.
  4. Lo que mató a Darktable fue una falta de gestión y una falta de visión, una cultura de “laissez faire” y de feliz aleatoriedad, que solo funciona con un puñado de desarrolladores que se conocen todos entre sí. Vkdt va en la misma dirección. Si al código y a las funciones se les permite crecer sin prioridades ni un endurecimiento de la API, es un tren que descarrila a cámara lenta. “más nuevo = mejor” es solo un estado transitorio. El verdadero reto es gestionar el crecimiento.

Desde la perspectiva de un desarrollador, Darktable tiene 3 enfermedades principales:

  1. A sus desarrolladores les faltan por completo (y desde hace mucho tiempo) las habilidades de abstracción para separar cognitivamente lo que pertenece a la capa de la GUI y lo que pertenece a la capa del backend. Como consecuencia, encontrarás estados de GUI/GTK incrustados en lo más profundo de las capas del backend, lo cual resulta tanto más molesto cuanto que darktable-cli se ejecuta sin interfaz (headless) y obliga a gestionar ambos modos. Pero también encuentras una y otra vez problemas de GUI resueltos en la capa del backend, y viceversa. Estos provocan verdaderos problemas de fiabilidad, además de hacer que todo el conjunto sea complicado, ilegible y enmarañado.
  2. Sus desarrolladores no entienden el concepto de las API privadas y el encapsulamiento: todas las estructuras de datos son públicas, todos los archivos de cabecera se importan por todo el software, así que todo el software conoce todo el software y tiene permiso para modificar las estructuras de datos in situ desde cualquier parte del código.
  3. La complejidad se “resuelve” con más complejidad, y nadie parece ver eso como un problema llamado deuda técnica.

Las bases de código sensatas protegen los datos haciéndolos privados y forzando las interacciones a través de funciones getter/setter definidas como API públicas. Esto permite gestionar fácilmente la seguridad entre hilos cuando llegue el momento, pero también nos permite rastrear qué escribe dónde y cuándo desde un lugar central. Y luego incluyes el conjunto mínimo de API en cada archivo, para aislar el código tanto como sea posible.

En lugar de eso, el código fuente de Darktable escribe en cualquier parte desde cualquier parte, sin interfaces adecuadas. Así que cualquier tipo de cambio en la base de código de Darktable provoca sistemáticamente efectos colaterales y rompe algo inesperado en el otro extremo del software, en deprimentes sesiones de whack-a-mole (dar golpes a topos) nacidas de la pereza y la estupidez.

Así que se ha hecho mucho trabajo tedioso en Ansel para endurecer las API, privatizar tantas estructuras de datos como sea posible y aislar las bibliotecas entre sí para desenmarañar en cierta medida el grafo de dependencias.

Anexo: los planos

Arquitectura completa

Aquí está el diagrama de flujo de alto nivel de toda la arquitectura, desde la base de datos hasta los backbuffers. Ahora por fin podemos dibujar un diagrama de flujo de este desastre.

flowchart TD
  subgraph Module
    M["Module instance
dt_iop_module_t"] end subgraph Develop H["dev->history
history items"] D["dt_develop_t
history_end
history_hash"] end subgraph Persist["DB + image cache"] DB["SQLite history tables"] IC["image cache
dt_image_t"] end subgraph Pipeline F["Pipe dirty flags"] P["Pipe nodes / pieces"] G["global_hash"] B["Backbuf"] end subgraph Cache C["Pixelpipe cache"] end subgraph Consumers["Backbuffer consumers"] DR["darkroom.c"] NAV["navigation.c"] EXP["imageio.c"] end M -->|"write snapshot
dt_dev_add_history_item_real()"| H H -->|"update history_end / history_hash
dt_dev_add_history_item_real()"| D D -->|"write history
dt_dev_write_history_ext()"| DB D -->|"write image-side hash
dt_dev_write_history_ext()"| IC DB -.->|"read history
dt_dev_read_history_ext()"| H IC -.->|"read image metadata
dt_dev_read_history_ext()"| H H -->|"apply to modules
dt_dev_pop_history_items_ext()"| M D -->|"mark pipes dirty
dt_dev_add_history_item_real()"| F D -->|"check history mismatch
dt_dev_darkroom_pipeline()"| F H -->|"sync history into pipe
dt_dev_pixelpipe_change()"| P F -->|"consume dirty flags
dt_dev_pixelpipe_change()"| P P -->|"compute cache keys
dt_pixelpipe_get_global_hash()"| G G -->|"key cache entries
dt_dev_pixelpipe_process_rec()"| C C -.->|"read exact-hit / input
dt_dev_pixelpipe_process_rec()"| P P -->|"publish stage output
dt_dev_pixelpipe_process_rec()"| C C -->|"promote final output
dt_dev_pixelpipe_process()"| B B -->|"borrow main/preview backbuf
_darkroom_expose()"| DR B -->|"copy preview backbuf
_lib_navigation_draw_callback()"| NAV B -->|"borrow export backbuf
dt_imageio_export_with_flags()"| EXP EXP -->|"update mipmap hash
dt_imageio_export_with_flags()"| IC

Gestión de memoria RAM/vRAM

Gestión de los búferes de caché:

flowchart TD
  H["CPU RAM buffer"]
  P["Pinned vRAM buffer
CL_MEM_USE_HOST_PTR"] V["Device-only vRAM buffer"] G["pixelpipe_process_on_GPU()"] C["pixelpipe_process_on_CPU()"] H -->|"prepare GPU input
dt_dev_pixelpipe_cache_prepare_cl_input()"| P P -->|"sync host/device if needed
dt_dev_pixelpipe_cache_sync_cl_buffer()"| G V -->|"reuse existing vRAM input
dt_dev_pixelpipe_cache_prepare_cl_input()"| G G -->|"publish pinned output
dt_dev_pixelpipe_cache_release_cl_buffer()"| P G -->|"publish device-only output
dt_dev_pixelpipe_cache_release_cl_buffer()"| V V -->|"GPU to CPU fallback copy
dt_dev_pixelpipe_cache_restore_cl_buffer()"| H H -->|"resume CPU processing
pixelpipe_process_on_CPU()"| C

Si está previsto almacenar en caché la salida del módulo (por preferencia del usuario, por necesidad de este búfer para el histograma/selector de color, o porque el siguiente módulo es el activo en la GUI), OpenCL usa un búfer de memoria fijada (pinned, anclada en la caché de RAM). También fijamos los búferes de memoria de entrada cuando la GPU toma su entrada de la caché de RAM. Esto es ligeramente más costoso que usar un búfer exclusivo del dispositivo, pero menos costoso que copiar ese búfer exclusivo del dispositivo al host. Si no está previsto almacenar en caché la salida de OpenCL, usamos un búfer exclusivo del dispositivo que podrá reciclarse más adelante, pero que nunca se copiará a la RAM.

En caso de un error de OpenCL para un módulo en particular (el más obvio: falta de memoria), el búfer de entrada de la GPU se copia de forma transparente de vuelta a la caché de RAM antes de recurrir a la ruta puramente de CPU.

Todos esos búferes están rastreados por entradas de caché, que vinculan un búfer de RAM con uno de vRAM (si usamos ambos en una situación de fijado), o simplemente llevan la cuenta de lo que hay asignado. Si falla una asignación de memoria de la GPU, primero recorremos la caché para liberar todos los búferes asignados previamente. Si la asignación de memoria de la GPU vuelve a fallar después de eso, recurrimos a la CPU.

Entradas de caché

La caché es una tabla hash de entradas de caché. Su clave es un hash/suma de comprobación. Tenemos 2 tipos de entradas de caché:

  • las internas, usadas como búferes reutilizables para las entradas/salidas de los módulos,
  • las externas, usadas como búferes desechables para los cálculos intermedios de los módulos.

Las entradas de caché internas se indexan mediante el global_hash de su módulo padre, y se pueden volver a encontrar más adelante (incluso desde la GUI) porque ese hash es estable entre ejecuciones y pipelines. Se pueden reindexar si reutilizamos su búfer de memoria, de modo que la nueva clave coincida con el nuevo estado de su módulo padre. Esas entradas de caché se pueden bloquear en modo lectura o escritura para un acceso concurrente seguro entre hilos paralelos. Un bloqueo de escritura solo lo puede capturar un único hilo si ningún otro hilo está leyendo; un bloqueo de lectura lo pueden capturar varios hilos si ningún otro hilo está escribiendo. Dado que el bloqueo de escritura lo libera el módulo que escribe su salida antes de que el bloqueo de lectura lo adquiera el módulo que usa la misma entrada de caché como su entrada, y hay un riesgo de eliminación en el intervalo, también tienen un mecanismo de refcount: el productor de la entrada de caché lo incrementa, el consumidor lo decrementa. El mismo mecanismo lo usa el cuarto oscuro para obtener el backbuffer sin copia.

Las entradas de caché externas se indexan mediante la dirección de memoria de su búfer de datos. Se supone que son de vida corta.

Añadir/eliminar entradas de caché incrementa/decrementa automáticamente el tamaño global de la caché. Seguimos añadiendo nuevas entradas mientras el tamaño global de la caché esté por debajo del umbral permitido, tras lo cual empezamos a destruir las entradas más antiguas si su refcount es 0 y no están bloqueadas.

flowchart TD
  A["absent"]
  B["reserved for write
refcount + 1
write-locked"] C["published
exact-hit eligible"] D["borrowed by consumer
refcount > 0"] E["backbuf-held
one display ref kept"] F["auto-destroy flagged"] G["removed / freed"] A -->|"create new entry
dt_dev_pixelpipe_cache_get()
dt_dev_pixelpipe_cache_get_writable()"| B C -->|"rekey reusable entry
dt_dev_pixelpipe_cache_get_writable()
dt_dev_pixelpipe_cache_rekey()"| B B -->|"backend finishes and unlocks
dt_dev_pixelpipe_process_rec()"| C C -->|"exact-hit / reopen / GUI read-only
dt_dev_pixelpipe_cache_peek()
dt_dev_pixelpipe_cache_get_read_only()"| D D -->|"release consumer ref
dt_dev_pixelpipe_cache_unref_hash()
dt_dev_pixelpipe_cache_close_read_only()"| C C -->|"keep final output alive for display
_update_backbuf_cache_reference()"| E E -->|"backbuf changes or invalidates
_update_backbuf_cache_reference()"| C C -->|"mark transient output
dt_dev_pixelpipe_cache_flag_auto_destroy()"| F F -->|"reap when no ref and no lock remain
dt_dev_pixelpipe_cache_auto_destroy_apply()"| G C -->|"explicit remove / GC / LRU
dt_dev_pixelpipe_cache_remove()
dt_dev_pixelpipe_cache_flush_old()
dt_dev_pixel_pipe_cache_remove_lru()"| G C -->|"invalid payload detected
dt_dev_pixelpipe_cache_peek()"| G

Una entrada de caché no conoce el tipo de datos que contiene. Solo conoce las direcciones de los búferes, su tamaño, su refcount y su estado de bloqueo. Así que es una abstracción genérica de las cosas contenidas en la memoria.


Translated from English by : ChatGPT, Claude. In case of conflict, inconsistency or error, the English version shall prevail.