Desde que comecei a usar o Darktable, por volta de 2012, sempre me surpreendi com a pouca quantidade de RAM que ele usava. As pessoas acham que é uma coisa boa um aplicativo usar a memória com parcimônia, e isso certamente é verdade quando falamos do seu ambiente de trabalho. Mas, tratando-se de um software de produção que faz renderização pesada de pixels em imagens de 12 a 54 Mpixels, isso significa que os mesmos cálculos pesados são feitos repetidamente em vez de serem salvos para reutilização posterior. É para isso que serve um cache: evitar cálculos custosos. E ele deveria usar toda a RAM disponível para isso, porque computar é desperdiçar energia, e isso tem um impacto concreto se você está trabalhando na bateria. Além disso, você pagou por essa RAM e usá-la não esvazia sua bateria. A CPU/GPU, por outro lado…

Sim, foto-repórteres e muitos nômades digitais retocam na bateria de laptops, em campo. Já é hora de o mundo do código aberto perceber que nem todos os fotógrafos estão sentados em suas mesas nas noites e nos fins de semana, depois de seu “verdadeiro” trabalho diurno. Então, computar e recomputar as mesmas coisas repetidamente é simplesmente desperdiçar energia, esteja você ligado à tomada ou funcionando na bateria.

Enquanto isso, o Darktable sempre teve aquela estranha configuraçãozinha de RAM que permitia definir quanto você queria que ele usasse. Só que ele não tinha maneira nenhuma de realmente rastrear quanta RAM usava, então era mais um guia do que uma regra. Isso depois foi substituído por uma preferência qualitativa de “recursos” completamente idiota, que ao mesmo tempo não significa nada e, na verdade, não diz quanta RAM você aloca para o software.

Então, o cache de RAM do Darktable nunca funcionou de verdade, era subutilizado e havia necessidade de consertá-lo. Porque, como resultado, tudo era recomputado o tempo todo sem motivo.

Mas… Havia um motivo para o cache ser subutilizado e não funcionar de verdade: aquele software tinha visibilidade zero sobre o ciclo de vida dos dados, o que é meio que o pré-requisito se você quer armazenar dados para reutilizá-los. Isso vinha de um pipeline de pixels que era realmente confuso (fico realmente imaginando se alguém é capaz de desenhar o fluxograma do que fazemos com os pixels, do início ao fim, entre os “desenvolvedores” do Darktable), mas também de metadados de imagem que eram computados em vários lugares, copiados e armazenados (e depois parcialmente atualizados) em vários lugares…

O cache do pipeline tinha um único propósito: alocar os buffers de entrada e saída dos módulos e, possivelmente, reutilizá-los se já estivessem disponíveis. Mas seu tamanho era definido em número de entradas, o que era realmente limitado, e não em quantidade de memória alocada. Isso o tornava moderadamente útil e nos forçava a usá-lo de forma conservadora demais, porque seu tamanho real de memória era totalmente imprevisível.

Nem preciso dizer que “consertar o cache” implicava “consertar o pipeline”, o que por sua vez implicava “tornar o ciclo de vida dos dados visível, rastreável e gerenciado globalmente”, o que implicava redesenhar a arquitetura de alto nível do software. Como veremos, isso teve benefícios inesperados no desempenho, que superam largamente as otimizações internas por módulo que o Darktable fez no mesmo período.

O que mudou desde 2022

Este artigo é a sequência direta de Corrigindo o cache do pipeline e bugs de 10 anos de idade. Aquele capítulo anterior tratava de encontrar a podridão e estancar as falhas mais constrangedoras. Este trata do que aconteceu em seguida, quando ficou óbvio que os bugs do cache não eram bugs isolados de forma alguma, mas sintomas de um renderizador cujas responsabilidades haviam sido misturadas por tempo demais.

Onde isto se encaixa historicamente

O problema original não era meramente “o cache não faz cache o suficiente”. O problema real era que toda a pilha do pipeline havia crescido em torno de comportamento acidental. Redesenhos da interface podiam acabar iniciando o processamento de imagem, de maneira não regulada. A pré-visualização de máscara vazava estado da interface para dentro do renderizador. A lógica do histograma e do seletor dependia de efeitos colaterais especiais do pipeline. Exportação, miniaturas, pré-visualização e sala escura tinham, todos, suas próprias pequenas variações de “certamente podemos simplesmente copiar aquele buffer mais uma vez”. E sempre que a consistência ficava difícil de provar (durante a exibição de máscara ou mudanças de recorte), a estratégia de fallback era muitas vezes descartar linhas de cache e recomputar tudo, porque aparentemente “tocar fogo e começar do zero” contava como arquitetura por um tempo.

Alguns dos comentários no código já diziam justamente isso. Havia avisos sobre recomputação disparada por redesenho. Havia até uma nota antiga dizendo que o cache deveria eventualmente se tornar global. Então os últimos anos não foram sobre inventar uma nova teoria do zero. Foram, na maior parte, sobre finalmente fazer a limpeza que o código vinha implorando desde os anos 2010.

A mudança histórica fundamental é que o pipeline deixou de ser tratado como um único blob recursivo do qual se esperava que descobrisse suas próprias necessidades enquanto executava. Ele foi progressivamente dividido em caminhos de execução mais claros para renderização interativa, renderização headless, processamento na GPU, processamento na CPU e consumidores do lado da interface. Ao mesmo tempo, o comportamento da interface foi empurrado de volta para a interface. Desenhar voltou a ser desenhar. Processar voltou a ser processar. Isso parece banal, o que geralmente é sinal de que o design anterior havia se tornado absurdo.

Checksums, ou como a validade deixou de ser um jogo de adivinhação

Uma vez que o renderizador não estava mais emaranhado com cada widget e cada canal lateral, tornou-se possível definir o estado da imagem explicitamente. Cada item de histórico agora carrega um checksum de módulo construído a partir dos parâmetros do módulo, dos parâmetros de mesclagem e de quaisquer formas de máscara relevantes. Isso dá a cada estado de módulo uma impressão digital canônica assim que ele entra no histórico, em vez de deixar a validade para ser inferida depois a partir do que quer que tenha rodado.

Só isso não era suficiente, porque um pipeline não é apenas um monte de configurações de módulo. Ele também depende de ordem, região de interesse, contratos de buffer e estado relacionado à exibição. Então o estágio de planejamento acumula essas impressões digitais no nível de módulo ao longo de toda a cadeia e incorpora o restante do contrato de tempo de execução antes que qualquer pixel se mova. O resultado é uma identidade estável por estágio e uma identidade final do pipeline.

É aqui que a visibilidade finalmente aparece. O pipeline pode saber se ainda é válido comparando o hash de seu histórico. O backbuffer exibido pode saber se ainda corresponde ao estado atual do pipe e do histórico. Uma linha de cache pode saber se realmente pertence exatamente ao estágio, à ROI e aos parâmetros atualmente requisitados. Isso soa quase ofensivamente razoável, mas exigiu muita limpeza antes: a sincronização do histórico com o pipeline teve de ser tornada explícita, o desvio do cache teve de ser declarado com antecedência (para pré-visualização de máscara e edições de recorte), a exibição de máscara não podia mais mutar as regras no meio da execução, e os antigos efeitos colaterais disparados por redesenho tiveram de ir embora. Você não obtém hashes confiáveis em cima de um fluxo de controle não confiável.

O benefício prático é que a consistência não é mais mantida por superstição. Não precisamos mais perguntar “será que a interface provavelmente invalidou a coisa certa no momento certo?” A resposta está nos checksums. Ou o estado corresponde, ou não corresponde. E podemos pegar a saída de qualquer módulo a partir da camada da interface, sem executar um pipeline, porque o checksum do módulo é previsível e pode ser computado antes da renderização, ou em paralelo.

A arquitetura cache-first

Hashes confiáveis mudam a arquitetura quase à força. Uma vez que todo estado significativo do pipeline tem uma identidade estável conhecida de antemão, o cache deixa de ser uma otimização de melhor esforço e se torna o centro do fluxo de dados.

É por isso que o pipeline agora tem uma verdadeira fase de planejamento antes da execução. O histórico é sincronizado primeiro. As regiões de interesse são propagadas por toda a cadeia. Cada estágio recebe um contrato explícito de entrada e saída. A política de cache do lado do host é selada antes do tempo de execução. Os hashes globais são computados antes da execução. Em outras palavras, o motor sabe o que está prestes a fazer antes de começar a fazê-lo, o que é uma pausa revigorante em relação ao antigo método de descobrir no meio do voo e compensar com gambiarras.

A partir daí, as consultas ao cache se tornam determinísticas. Um estágio pode reabrir exatamente o buffer que corresponde ao seu estado, de modo que um módulo pode ignorar os cálculos inteiramente apenas olhando no cache se uma linha de cache já corresponder ao seu estado interno como uma consulta de checksum. Consumidores a jusante podem reabrir resultados publicados por hash em vez de pedir ao renderizador para executar mais uma dança especial só para eles. O cache deixa de ser um amontoado de memória vagamente reutilizável e se torna o registro autoritativo de resultados intermediários e finais válidos.

Isso também explica por que tanto código pôde ser removido ou simplificado. Uma vez que a validade é centralizada, você precisa de menos heurísticas, menos ramificações especiais, menos cláusulas do tipo “exceto quando a interface está neste modo” e menos descartes de emergência. O código fica mais curto não porque o problema encolheu, mas porque deixou de ser resolvido em seis lugares contraditórios ao mesmo tempo.

As linhas de cache também vinculam memória de GPU e CPU, o que nos permite usar memória fixada (pinned) do OpenCL. Existe uma preferência de usuário do OpenCL que permite habilitar ou não a memória fixada desde sempre, mas descobri que essa opção era usada apenas para processamento em ladrilhos, quando os módulos não conseguiam encaixar todas as suas necessidades de memória na GPU. A memória fixada agora foi estendida também para operações normais, pois permite que RAM e VRAM sejam mapeadas sem cópia. Usar memória fixada em um pipeline de GPU totalmente em cache reduz o tempo gasto movendo buffers de memória em até um fator de 7.

Mas forçar o cache das saídas de módulos OpenCL, mesmo com buffers fixados de cópia zero, ainda tem algum custo, e é mais custoso do que simplesmente pular o cache por completo. Para alguns módulos pesados (redução de ruído perfilada, difundir ou aguçar, equalizador de contraste), a sobrecarga do cache definitivamente vale a pena, mas para os rápidos (balanço de branco, exposição, perfil de cor de entrada), o custo de fazer cache dos buffers OpenCL fazia os módulos inteiros rodarem, na verdade, mais lentamente na GPU do que na CPU.

Então agora temos heurísticas por módulo que decidem se um módulo OpenCL publicará seu buffer de saída no cache de RAM. Módulos pesados e todos os módulos que capturam seletor de cor ou histogramas são publicados por padrão. Para os demais, os usuários podem decidir por si mesmos:

image

Isso também permitirá que os usuários desabilitem o OpenCL seletivamente em alguns módulos quando tiverem problemas recorrentes com eles. Por exemplo, redução de ruído perfilada e remoção de neblina consomem muita memória de GPU e podem falhar durante a execução por falta de memória disponível, mesmo que o planejamento inicial de memória tenha determinado que deveria ser suficiente. Quando isso acontece, o módulo já havia começado a computar por algum tempo e recorrerá à CPU. Se isso acontece com frequência, é melhor ignorar a GPU nesse módulo o tempo todo do que arcar com o dobro da penalidade.

Mas não para por aí. Os buffers de GPU também são mantidos vivos na GPU. Isso significa que reiniciar um pipeline parcial a partir de um módulo OpenCL obtém a entrada diretamente da GPU quando possível, sem nenhuma cópia da RAM. Também significa que os módulos leves conseguem reutilizar seu buffer de GPU anterior se ele couber, em vez de alocar um novo. Só isso abre a possibilidade de ter um pipeline em tempo real, necessário para o novo módulo Desenho, com cerca de 60-80 ms de latência entre as pinceladas e as atualizações da imagem. Eu nunca teria imaginado que isso seria possível de forma alguma.

A mesma realocação de memória é feita na RAM, já que o Ansel agora hospeda todo o cache em sua própria arena de memória . Esse esquema não só nos permite pré-reservar um bloco de memória contíguo do sistema operacional ao iniciar o aplicativo, levando a alocações mais rápidas, como também garante que não ultrapassemos o volume de memória definido pelo usuário. Então, quando você decide alocar 8 GB de RAM para o Ansel, agora conseguimos garantir que isso realmente aconteça: vamos preencher todo esse volume até que esteja cheio, após o que começamos a reciclar os buffers mais antigos. Todos os buffers de pixels, entrada e saída de módulos, mas também os rascunhos internos temporários, são alocados em nossa arena de memória.

E, por último, mas não menos importante, há apenas um cache de pipeline para todo o aplicativo, o que significa que todos os tipos de pipeline (pré-visualização da sala escura, imagem principal da sala escura, exportação de miniatura e exportação de arquivo) compartilham o mesmo cache. Embora isso tenha precisado ser gerenciado para acesso concorrente multithread, significa que, se um pipeline precisa da saída de um módulo que já foi computada no mesmo tamanho por outro pipeline, ele pode pegar diretamente a linha de cache e ignorar sua própria recomputação.

Para tirar proveito disso, a “pré-visualização” da sala escura, antes de tamanho fixo (ou seja, a versão reduzida da imagem completa, usada no widget de navegação, para amostrar histogramas e seletores de cor, e como preenchimento transitório “borrado” enquanto a imagem principal está sendo recomputada), foi alterada para ser dimensionada dinamicamente ao nível de zoom de “ajuste” da imagem principal (aquela exibida no centro da sala escura). O resultado é que apenas uma imagem precisa ser computada quando você entra na sala escura, e voltar ao zoom de “ajuste” é instantâneo.

Mas, como essa pré-visualização de tamanho fixo vinha sendo usada preguiçosamente em muitos lugares da interface para remapear as coordenadas do cursor no espaço do widget para as coordenadas da imagem RAW em resolução plena, por meio de copiar e colar o mesmo bloco feio de código por toda parte (copiando até o comentário que dizia “não entendo o que isto faz”), todo o sistema de coordenadas teve de ser refeito para acomodar essa mudança. E, de novo, essas coordenadas eram computadas apenas dentro de um pipeline, então a interface tinha de esperar o pipeline recomputar os novos tamanhos para saber onde posicionar os objetos, o que disparava falhas visuais na interface, especialmente ao mudar o recorte. Mas agora tudo isso é computado com antecedência a partir de uma API unificada, então acabou o bobo copiar e colar multiplicado pelo número de módulos.

O que isso mudou fora do núcleo

A primeira consequência externa é que as cópias deixaram de se disfarçar de recursos. A sala escura não precisa mais de um backbuffer de interface dedicado para exibir o que o renderizador já produziu. Ela pode pegar a imagem publicada diretamente do cache, vincular uma superfície Cairo a ela e exibi-la em poucos milissegundos. Anteriormente, o caminho era mais lento e ocupado com cópias sem nenhuma boa razão além da confusão de design herdada. A sala escura também pode verificar diretamente se um dado backbuffer de pipeline está atualizado em relação ao histórico de edição atual, por meio de checksums. Anteriormente, isso dependia de um flag “sujo” que podia ser sobrescrito por várias threads e impedia qualquer redesenho de “melhor esforço” da sala escura (ou seja: estampar o último backbuffer válido conhecido enquanto se aguarda a recomputação do atualizado). Isso era importante quando o usuário mudava os parâmetros do módulo mais rápido do que o pipeline conseguia recomputar: ainda precisamos de algo para preencher a vista e evitar cintilação.

A mesma lógica agora se estende à exportação e às miniaturas, que podem reabrir o resultado final publicado em vez de reconstruir sua própria realidade privada. O código de histograma e seletor também deixou de pegar carona na execução do pipeline. Os scopes seguem sinais explícitos de conclusão do caminho de pré-visualização, fazem cache de sua própria superfície Cairo em relação ao estado de origem e amostram diretamente de backbuffers respaldados pelo cache. O histograma raw (amostrado após o módulo interpolação cromática) foi adicionado à saída antiga do pipeline: alternar entre os dois não requer uma recomputação do pipeline, nem a seleção de cor em qualquer um deles. Esse é um design bem mais entediante, o que é exatamente o motivo pelo qual é melhor.

Outra consequência importante é que os sabores de pipeline não vivem mais em silos de cache isolados. Consumidores de pré-visualização, sala escura, exportação, miniaturas e histograma agora podem compartilhar o estado do cache. Essa era a intenção já insinuada há muito tempo no código do cache; só foi preciso uma limpeza completa do rastreamento de validade para torná-la real. Uma vez que todos esses consumidores concordam com os mesmos hashes, eles finalmente podem concordar também com os mesmos buffers. O benefício é que um pipeline pode reutilizar a linha de cache já computada de outro pipe se ela couber (mesmo parâmetro, mesmo tamanho de entrada e saída). Então o início dos pipelines da sala escura foi mudado para resolução plena: a interpolação cromática e a redução de ruído serão mais lentas ao entrar na sala escura, mas depois o zoom e o pan se tornam instantâneos. E exportar uma imagem também pegará esses estágios iniciais direto do cache. Aliás, exportar a mesma imagem duas vezes em duas resoluções diferentes só recomputa a partir do módulo de escala, no fim do pipeline.

O gerenciamento de memória seguiu a mesma lógica. As linhas de cache passaram a ser objetos com contagem de referências, bloqueáveis e reutilizáveis, em vez de blobs descartáveis passados adiante por armazenamento lateral improvisado. Os caminhos de CPU e GPU agora compartilham muito mais o mesmo modelo de posse. No lado do OpenCL, os buffers de host e de dispositivo são gerenciados com regras explícitas de tempo de vida, a memória fixada é reutilizada em vez de descartada e recriada, e a RAM e a VRAM permanecem sincronizadas por meio de transferências fixadas e de cópia zero onde possível, em vez de serem espelhadas por cópias intermediárias inúteis. Isso não torna a GPU magicamente mais rápida em matemática. Basicamente, impede que o encanamento ao redor desperdice os ganhos.

O benefício não é apenas velocidade de benchmark. É também latência, robustez e uso de energia. A inicialização da sala escura fica mais curta porque há menos cópias e menos passagens duplicadas. Zoom, pan, pré-visualização de máscara e navegação no histórico deixam de invalidar metade do universo só porque provar a correção costumava ser difícil demais. O OpenCL se torna menos aleatório porque o fallback, o ladrilhamento e a posse de memória são declarados de forma mais explícita. O software gasta menos tempo movendo pixels de um lado para o outro só para se tranquilizar de que eles ainda existem em algum lugar.

Como efeito colateral, o tratamento de erros no pipeline foi melhorado. Módulos que falham em alocar memória agora lançam imediatamente um erro e abortam o pipeline. Anteriormente, as falhas de alocação não eram verificadas em todos os lugares, e um pipeline inteiro podia carregar um buffer NULL até o fim… ou travar de forma exemplar com erros de segmentation fault. Isso agora é prevenido a montante de maneira uniforme em todo o software.

A amostragem do seletor de cor e os histogramas podem amostrar dados sem disparar uma recomputação do pipeline, buscando diretamente no cache, se a linha de cache requisitada existir. A caixa de ferramentas global scopes permite escolher entre RGB RAW (amostrado após a interpolação cromática) ou RGB final do pipeline (amostrado após o perfil de cor de saída em ponto flutuante de 32 bits, ou no backbuffer em inteiros de 8 bits): mudar de um para o outro não reinicia um pipeline, mas simplesmente carrega uma linha de cache diferente, e a seleção de cor acontece nessa linha de cache de forma transparente.

O que de fato foi consertado ao fazer certo

Muitos incômodos visíveis remontam a este redesenho mais do que a qualquer micro-otimização isolada. O tratamento de ROI em High-DPI melhorou porque a posse da geometria ficou mais clara e o mapeamento de coordenadas entre a interface e a imagem RAW agora é tratado em uma API central. A ressincronização entre histórico e pipeline ficou menos frágil porque o histórico deixou de ser um efeito colateral incidental do fluxo da interface e se tornou uma entrada de primeira classe para o planejamento. A pré-visualização de máscara em tempo real não precisa mais lutar contra um modelo de cache projetado para outra era. A atualização do histograma ficou previsível porque agora consome dados publicados em vez de torcer para que o buffer intermediário certo por acaso esteja vivo em algum lugar. Loops infinitos, linhas de cache obsoletas, backbuffers inválidos e o clássico “a pré-visualização recomputou o pipe inteiro a partir do módulo 0 sem motivo óbvio”, tudo se torna mais fácil de diagnosticar quando o ciclo de vida é explícito.

Então a parte interessante aqui não é que uma grande refatoração aconteceu isoladamente. É que uma longa série de limpezas finalmente se alinhou em torno de uma ideia: a validade deve ser computada, nomeada e compartilhada com antecedência. Uma vez que isso aconteceu, o resto veio quase mecanicamente. O cache se tornou central porque os hashes eram confiáveis. Consumidores externos puderam parar de copiar porque os buffers publicados no cache se tornaram autoritativos. Os caminhos de CPU e GPU puderam compartilhar mais estado porque a posse ficou explícita. E o renderizador parou de se comportar como uma casa mal-assombrada onde mexer em um controle deslizante podia acordar três subsistemas não relacionados e um callback de redesenho de 2013.

Benchmarks

Os benchmarks são feitos em ambos os aplicativos compilados localmente com build Release e GCC14 usando seus respectivos scripts build.sh --build-type Release.

Config 1
O hardware é um Thinkpad P51, com 8 × CPU Intel Xeon E3-1505M v6 @ 3.00GHz e GPU Nvidia Quadro M2200, rodando no Fedora 41 Plasma com Wayland. A versão do driver Nvidia é 580.105.08. O Intel Xeon é uma CPU de ponta lançada em 2015. A Quadro M2200 é uma CPU profissional de gama média lançada em 2017.
Config 2
O hardware é um PC desktop com 4 × Intel Core i3-4130 e GPU AMD Radeon RX 580 Polaris 10, rodando no Ubuntu 24.04 LTS com Wayland. A versão do driver AMD é RustiCL 25.2.8. O Core i3 é uma CPU de gama média lançada em 2013. A AMD Polaris 10 é uma GPU de gama média-alta lançada em 2017.

Mostramos aqui a saída de ansel -d perf e darktable -d perf. Os arquivos de configuração do Ansel e do Darktable são definidos com este script  para garantir a mesma linha de base de configuração. A imagem de teste de 45 Mpx foi tirada daqui  e o XMP de edição pode ser baixado aqui.

Carregamento inicial na sala escura

Aviso: no Ansel, é importante executar este teste sem nenhum módulo em foco na interface (isto é, não recolhido). Nessa situação, o Ansel sempre faz cache da saída do módulo anterior, para garantir que, quando forem feitas modificações naquele módulo em foco, sempre reiniciemos os cálculos a partir da entrada imediata. Mas forçar o cache dessa forma dispara uma sobrecarga de memória que pode ser visível para módulos leves.

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'

Relatório

Antes de mais nada, ao entrar na sala escura, o Darktable computa 2 pipelines para o mesmo resultado que o Ansel obtém computando apenas um. Então, independentemente dos tempos de execução reais, já são metade de cálculos inúteis.

Depois, o Ansel computa a imagem em resolução plena até o módulo de reamostragem inicial, enquanto o Darktable o faz apenas até antes da interpolação cromática. Isso é importante para a comparação.

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

Na config 1, o Darktable consegue ser mais lento que o Ansel na GPU mesmo olhando apenas para a renderização do único pipeline principal e mesmo reduzindo a imagem para a resolução de exibição mais cedo no pipeline. Mas vemos, na verdade, o mesmo efeito na CPU, apesar de todas as alegadas “otimizações” feitas nos módulos exclusivos de CPU por volta de 2023-2024 no Darktable. No geral, o Darktable vai congelar seu computador por 2.3 a 3.0 s a mais.

Na config 2, o caminho da CPU mostra uma penalidade de 0.8 s para o Ansel apenas no pipeline principal. A GPU AMD sofre um golpe ruim no módulo de correção de lente, que processa em resolução plena no Ansel enquanto processa na resolução da tela no Darktable. Levando em conta o segundo pipeline que o Darktable executa, o Ansel é mais rápido em 0.14 s na GPU. Na CPU, porém, o Darktable agora congela a máquina por 27.07 s a mais por causa desse trabalho de pipeline duplicado. De qualquer forma, os módulos lentos estão no início do pipeline e não serão recomputados durante toda a sessão.

Isso nos dá as seguintes comparações lado a lado entre módulos. Comparamos apenas módulos rodando na mesma resolução, para o pipeline da imagem principal apenas. Na aba de médias, os fatores são calculados com uma média geométrica e as diferenças relativas com uma média harmônica:

Módulo / chipAnsel MasterDarktable 5.4.1Ganho do Ansel
Configurações raw* / CPU35 ms40 ms×1.14 / +13 %
Configurações raw* / GPU18 ms17 ms×0.96 / -5.9 %
Balanço de branco* / CPU31 ms29 ms×0.94 / -6.9 %
Balanço de branco* / GPU16 ms13 ms×0.81 / -23 %
Reconstrução de realces* / CPU6.12 s6.33 s×1.03 / +3.4 %
Reconstrução de realces* / GPU2.49 s3.70 s×1.49 / +33 %
Interpolação cromática* / CPU348 ms717 ms×2.06 / +52 %
Interpolação cromática* / GPU254 ms490 ms×1.93 / +48 %
Exposição / CPU5 ms12 ms×2.4 / +58 %
Exposição / GPU6 ms10 ms×1.67 / +40 %
Perfil de cor de entrada / CPU3 ms15 ms×3 / +67 %
Perfil de cor de entrada / GPU2 ms32 ms×16 / +94 %
Calibração de cor / CPU70 ms84 ms×1.20 / +25 %
Calibração de cor / GPU1 ms39 ms×39 / +97 %
Difundir ou aguçar / CPU3.15 s4.21 s×1.34 / +25.2 %
Difundir ou aguçar / GPU1.09 s1.69 s×1.55 / +35 %
Balanço de cor RGB / CPU262 ms261 ms×1.00 / -0.4 %
Balanço de cor RGB / GPU9 ms12 ms×1.33 / +25 %
Filmic RGB / CPU137 ms140 ms×1.02 / +2.1 %
Filmic RGB / GPU6 ms11 ms×1.83 / +45 %
Perfil de cor de saída / CPU13 ms21 ms×1.62 / +38 %
Perfil de cor de saída / GPU23 ms52 ms×2.26 / +56 %
Dithering (apenas CPU) / pipeline CPU24 ms59 ms×2.46 / +59 %
Dithering (apenas CPU) / pipeline GPU43 ms88 ms×2.05 / +51 %
Gamma / codificação de tela (apenas CPU) / pipeline GPU12 ms9 ms×0.75 / -33 %
Gamma / codificação de tela (apenas CPU) / pipeline CPU12 ms9 ms×0.75 / -33 %

*: módulos executados em resolução plena em ambos os aplicativos.

Módulo / chipAnsel MasterDarktable 5.4.1Ganho do Ansel
Configurações raw* / CPU63 ms49 ms×0.78 / -29 %
Configurações raw* / GPU37 ms59 ms×1.59 / +37 %
Balanço de branco* / CPU69 ms35 ms×0.5 / -97 %
Balanço de branco* / GPU7 ms7 ms×1 / 0 %
Reconstrução de realces* / CPU13.10 s12.91 s×0.99 / -1.5 %
Reconstrução de realces* / GPU1.42 s1.87 s×1.32 / +24 %
Interpolação cromática* / CPU0.99 s1.80 s×1.82 / +45 %
Interpolação cromática* / GPU149 ms123 ms×0.83 / -21 %
Exposição / CPU13 ms3 ms×0.23 / -333 %
Exposição / GPU33 ms2 ms×0.06 / -1550 %
Perfil de cor de entrada / CPU2 ms33 ms×16.5 / +94 %
Perfil de cor de entrada / GPU11 ms4 ms×0.36 / -175 %
Calibração de cor / CPU47 ms50 ms×1.06 / 6 %
Calibração de cor / GPU2 ms4 ms×2 / +50 %
Difundir ou aguçar / CPU1.71 s3.37 s×1.97 / +49.4 %
Difundir ou aguçar / GPU158 ms518 ms×3.28 / +70 %
Balanço de cor RGB / CPU152 ms179 ms×1.18 / +15 %
Balanço de cor RGB / GPU10 ms4 ms×0.40 / -150 %
Filmic RGB / CPU93 ms114 ms×1.23 / +18 %
Filmic RGB / GPU4 ms41 ms×10.26 / +90 %
Perfil de cor de saída / CPU15 ms41 ms×2.73 / +63 %
Perfil de cor de saída / GPU22 ms32 ms×1.45 / +31 %
Dithering (apenas CPU) / pipeline CPU9 ms28 ms×3.62 / +72 %
Dithering (apenas CPU) / pipeline GPU13 ms47 ms×2.76 / +64 %
Gamma / codificação de tela (apenas CPU) / pipeline CPU9 ms9 ms×1.0 / 0 %
Gamma / codificação de tela (apenas CPU) / pipeline GPU8 ms15 ms×1.88 / +47 %

*: módulos executados em resolução plena em ambos os aplicativos.

Média entre config 1 e 2. Os fatores são calculados com uma média geométrica, e as diferenças relativas com uma média harmônica.

Módulo / chipGanho do AnselCódigo do Ansel
Configurações raw* / CPU×0.94Personalizado (vetorizado manualmente)
Configurações raw* / GPU×1.23Igual ao DT 5.4.1
Balanço de branco* / CPU×0.69Personalizado (vetorizado manualmente)
Balanço de branco* / GPU×0.97Igual ao DT 5.4.1
Reconstrução de realces* / CPU×1.1Personalizado (vetorizado manualmente)
Reconstrução de realces* / GPU×1.4Personalizado
Interpolação cromática* / CPU×1.94Igual ao DT 4.0
Interpolação cromática* / GPU×1.26Personalizado
Exposição / CPU×0.74Personalizado (vetorizado manualmente)
Exposição / GPU×0.32Igual ao DT 4.0
Perfil de cor de entrada / CPU×7.04Personalizado (vetorizado manualmente)
Perfil de cor de entrada / GPU×2.41Personalizado
Calibração de cor / CPU×1.13Personalizado (vetorizado manualmente)
Calibração de cor / GPU×8.83Igual ao DT 4.0
Difundir ou aguçar / CPU×1.08Personalizado
Difundir ou aguçar / GPU×2.26Personalizado
Balanço de cor RGB / CPU×1.08Personalizado (vetorizado manualmente)
Balanço de cor RGB / GPU×0.73Personalizado
Filmic RGB / CPU×1.13Personalizado (vetorizado manualmente)
Filmic RGB / GPU×4.33Personalizado
Perfil de cor de saída / CPU×2.10Personalizado (vetorizado manualmente)
Perfil de cor de saída / GPU×1.81Personalizado
Dithering (apenas CPU) / pipeline CPU×2.71Igual ao DT 4.0
Dithering (apenas CPU) / pipeline GPU×2.72Igual ao DT 4.0
Gamma / codificação de tela (apenas CPU) / pipeline CPU×0.87Igual ao DT 5.4.1
Gamma / codificação de tela (apenas CPU) / pipeline GPU×1.63Igual ao DT 5.4.1

*: módulos executados em resolução plena em ambos os aplicativos.

Velocidade relativa por módulo (GPU). Maior é melhor.

O Ansel mostra melhorias de desempenho na GPU mesmo em kernels que não mudaram desde o Darktable 4.0. Os ganhos de velocidade que vemos são claramente o benefício do gerenciamento de memória de alto nível, usando memória fixada do OpenCL ou buffers de memória exclusivos do dispositivo onde pertinente.

Em todos os módulos, o Ansel é 1.6 vezes mais rápido que o Darktable na GPU (média geométrica).

Velocidade relativa por módulo (CPU). Maior é melhor.

Na CPU, as coisas são mais nuançadas.

O Darktable 5.x supostamente recebeu otimizações de CPU para dithering e interpolação cromática (RCD), mas ambos esses módulos têm desempenho pior que os do Ansel em ambas as configs.

O Ansel tem código de pixel de CPU vetorizado manualmente para balanço de cor RGB, calibração de cor, perfil de cor de entrada/saída, configurações raw, balanço de branco, exposição e filmic, enquanto o do Darktable usa dicas de compilador para alcançar a vetorização. Todos eles têm desempenho melhor que os do Darktable no Intel Xeon. No Intel i3, para o trabalho básico de matriz de cor, o Ansel tem desempenho (bem) melhor, mas está prejudicando ligeiramente módulos básicos como configurações raw, exposição ou balanço de branco.

Difundir ou aguçar deveria ainda usar o mesmo código do Darktable 4.0 no Ansel e no Darktable 5.4, mas o Ansel é mais rápido em ambas as configs, o que mostra o benefício de usar nosso próprio array de memória pré-alocado para o cache, e de alocar buffers de memória fora do circuito do sistema operacional. Isso mostra que otimizar no nível do módulo é o escopo errado, e que o pipeline global precisava primeiro de uma revisão completa.

Mas é claro que é mais fácil abordar otimizações por módulo porque os módulos são… modulares, ou seja, autocontidos e autossuficientes. Há pouca chance de estragar o software como um todo ao trabalhar em módulos, porque eles estão isolados do resto. Mudanças de arquitetura globais do aplicativo, por outro lado, são perigosas, complicadas e exigentes. E elas impõem parar completamente o desenvolvimento de qualquer novo módulo enquanto a arquitetura está sendo estabilizada. O que o Darktable nunca terá a disciplina de fazer, porque o projeto não é gerenciado e pull requests aleatórios aparecem no Github em momentos aleatórios, vindos de colaboradores aleatórios.

Em todos os módulos, o Ansel é 1.8 vezes mais rápido que o Darktable na CPU (média geométrica).

Combinando os caminhos de GPU e CPU nas duas configs, abrir a sala escura é 1.5 vezes mais rápido no Ansel (média geométrica).

Zoom em 100%

Na sala escura, a partir do tamanho “zoom para ajustar”, aplique zoom em 100% com um clique usando o botão do meio do mouse

 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 o Ansel processa os estágios iniciais do pipeline em resolução plena, eles também são armazenados em cache em resolução plena, o que significa que o pan e o zoom buscam o cache a montante do módulo de reamostragem inicial, e recomputam apenas a jusante. Então leva 2.9 s para renderizar. O Darktable, por outro lado, tem um cache que não funciona, então recomputa tudo desde o início, levando 5.9 s para renderizar a mesma coisa. É uma penalidade de desempenho de ×2 para o Darktable.

Pan em 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'

O deslocamento (panning) leva à mesma situação que o zoom: o Ansel tem a imagem em resolução completa em cache, então recalculamos a partir da reamostragem inicial, o que leva 3 s. O Darktable não consegue gerenciar um cache adequadamente, então você fica sujeito a um recálculo completo e a 5,9 s de computador travado.

Indo e voltando para a 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'

O cache do pipeline do Ansel sobrevive aos próprios pipelines, o que significa que sair da sala escura e entrar nela novamente é quase instantâneo: leva apenas 60 ms para ressincronizar todos os pipelines com o histórico de revelação e descobrir que já temos a saída do pipeline em cache através de seu checksum. Note que não há nenhum tratamento especial de qualquer tipo aqui, é o comportamento genérico do cache.

No caso do Darktable, quase funciona para a imagem principal, mas não para a de pré-visualização, então você fica sujeito a 1 s de recálculo inútil. Dado que isso funciona em um pipe mas não no outro, vou apostar que é tratado por meio de casos especiais. Comparado ao Ansel, é uma penalidade de desempenho de ×1,75.

Desativando um módulo no meio do pipeline

Eu desativei o diffuse or sharpen com zoom no tamanho “fill”.

 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'

Novamente, o cache do Ansel simplesmente funciona: desativar o diffuse or sharpen leva a recalcular apenas os módulos a jusante, o que leva 172 ms. Novamente, o cache do Darktable não funciona, o que leva a recalcular os 2 pipelines inteiros (pré-visualização e principal), a um custo total de 6,9 s. Isso é uma penalidade de desempenho de ×40, pessoal! Isso torna todos os aumentos espúrios de velocidade de +15 % de Ralf Brown completamente irrelevantes! Mas ei! Continue procurando suas chaves perdidas onde você consegue ver os pés em vez de onde você as perdeu! .

Selecionando cor em um módulo

Definimos o balanço de branco no color calibration usando o seletor de cor, no nível de zoom “zoom to fit”.

 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'

O Ansel não precisa iniciar uma nova renderização de pipeline para amostrar o seletor de cor porque a entrada e a saída do módulo ainda estão em cache, então leva um total de 40 ms para amostrar. Em seguida, os novos parâmetros são confirmados no módulo, o que altera o histórico e dispara um recálculo do módulo color calibration e de todos os módulos a jusante. Tempo total gasto: 1,4 s.

O Darktable precisa reiniciar uma nova renderização de pipeline para amostrar o seletor de cor porque por que não? Isso leva 0,6 s. Você ficará satisfeito em saber que o Darktable amostra a cor na GPU, o que leva apenas 1 ms (no meio desses 0,6 s de execução do pipeline), enquanto o Ansel amostra na CPU em 20 ms. Em seguida, os parâmetros do seletor de cor são confirmados no histórico, o que reinicia um recálculo completo dos 2 pipelines. Tempo total gasto: 7,5 s.

Isso é uma penalidade de ×5,4 para o Darktable, tudo isso porque eles não estão melhorando seus pipelines, mas embarcando em toda caça aos gambozinos que existe.

Exportando em resolução completa

Exportamos após ter aberto a imagem na sala escura. Isso é importante. A amostragem de “alta qualidade” é usada no Darktable; no Ansel é o ú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'

No Ansel, como abrimos a imagem anteriormente na sala escura, os estágios iniciais do pipeline ainda estão em cache, então a exportação começa a partir do módulo exposure e leva 39,5 s. No Darktable, bem… tudo como sempre: é um recálculo completo do pipeline que leva 50 s.

Exportando novamente em meia resolução

Exportamos em meia resolução logo após ter exportado em resolução 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 o Ansel sempre exporta em resolução completa até o módulo Final resampling (o modo chamado “alta qualidade” no Darktable), o pipeline permanece o mesmo em sua maior parte, independentemente do tamanho final. Como o cache do Ansel funciona, a imagem em resolução completa exportada anteriormente ainda está em cache, então recalculamos apenas os últimos estágios: output color profile, downsampling, dithering. Isso leva 0,5 s.

O Darktable, como de costume, não gerencia o que calculou anteriormente, então você fica sujeito a mais uma exportação completa de ~50 s. Ou seja, uma penalidade de desempenho de ×100.

Note que o cache do pipeline do Ansel tem uma coleta de lixo que esvazia todas as linhas de cache não utilizadas com mais de 5 minutos, então isso não funcionaria se você esperasse tempo demais.

Conclusão

É hilário ler, em fóruns de tech-bros como o discuss.pixls.us , que as pessoas confiam mais no Darktable do que no Ansel porque o primeiro tem muito mais macacos agitando as mãos no ar e fingindo trabalhar, o que aparentemente é suficiente para dar uma sensação completamente equivocada de confiabilidade e confiança. É apenas a prova definitiva de que as pessoas não fazem ideia do que está acontecendo no código. Mas é uma doença capitalista confundir agitação com trabalho, e trabalho que não cria valor ainda pode ser vendido como progresso com o marketing adequado.

Eu não faço opiniões, faço benchmarks. Os números que publiquei aqui podem ser inteiramente reproduzidos:

Darktable performance penalty per benchmark case
  • módulos individuais são em média 1,4 vez mais rápidos no Ansel CPU em comparação com o Darktable CPU,
  • módulos individuais são em média 1,6 vez mais rápidos no Ansel GPU em comparação com o Darktable GPU,
  • pipelines completos são entre 1,5 vez e 100 vezes mais rápidos no Ansel em comparação com o Darktable GPU, porque o Ansel tem um cache funcional,
  • o Ansel não é apenas mais rápido, ele também é mais eficiente em termos de energia, porque menos coisas são (re)calculadas.

Tudo isso foi alcançado removendo código de GUI do código de renderização do pipeline, tornando o ciclo de vida dos dados mais claro, mais simples e mais robusto, não adicionando mais tratamento de casos especiais e gambiarras. O Ansel é capaz de usar muito mais RAM do que o Darktable, ao mesmo tempo que faz a contabilidade necessária para saber quanto ele realmente usa e se deveria começar a reciclar memória.

Tudo isso é a prova de que a “equipe” do Darktable não está tornando o software melhor, que sua (falta de) gestão está prejudicando ativamente o software. Houve muitas “otimizações” anunciadas nas notas de versão desde 2022. E, ainda assim, o software deles continua sendo uma besta de ineficiência dolorosamente lenta.

Note que as otimizações feitas por módulo no Darktable podem ser retroportadas para o Ansel, embora nem todas pareçam ganhos de velocidade reais pelo que é mostrado aqui. Algumas já foram. Mas o Darktable não pode retroportar a arquitetura de pipeline do Ansel, que é de onde vem a maioria dos nossos ganhos de velocidade.

Durante este trabalho, também perdi a fé no Vkdt . O Vkdt é uma nova tentativa, do fundador do Darktable, Johannes Hannika, de reconstruir do zero um software de fotografia RAW rodando inteiramente na GPU através do Vulkan. Mas de 4 anos limpando a merda dos outros, há algumas coisas que eu aprendi:

  1. As lentidões do Darktable não devem ser culpa da stack do GTK ou da stack do OpenCL. Certo, essas não são ótimas, mas isso pode ser gerenciado. São erros de programação e mau design que não foi reavaliado à medida que as necessidades e os requisitos do software mudaram.
  2. Um design que prioriza o cache permite ocultar muitas latências ao evitar recálculos, e um fluxo de trabalho totalmente em GPU logo enfrentará as limitações de memória das GPUs.
  3. As GPUs estão ficando cada vez mais caras, depois da corrida das criptomoedas e agora da corrida da IA.
  4. O que matou o Darktable foi a falta de gestão e a falta de visão, uma cultura de “laissez faire” e aleatoriedade feliz, que só funciona com um punhado de desenvolvedores que se conhecem todos. O Vkdt está indo na mesma direção. Se código e recursos têm permissão para crescer sem prioridades e sem aperto da API, é um trem descarrilando em câmera lenta. “mais novo = melhor” é apenas um estado transitório. O verdadeiro desafio é gerenciar o crescimento.

Do ponto de vista de um desenvolvedor, o Darktable tem 3 doenças principais:

  1. Seus desenvolvedores carecem completamente (e há muito tempo) das habilidades de abstração para separar cognitivamente o que pertence à camada de GUI e o que pertence à camada de backend. Assim, você encontrará estados de GUI/GTK incrustados no fundo das camadas de backend, o que é ainda mais irritante dado que o darktable-cli roda sem interface (headless) e força ambos os modos a serem gerenciados. Mas você também encontra repetidamente problemas de GUI resolvidos na camada de backend, e vice-versa. Esses disparam problemas reais de confiabilidade, além de tornar a coisa toda complicada, ilegível e emaranhada.
  2. Seus desenvolvedores não entendem o conceito de APIs privadas e encapsulamento: todas as estruturas de dados são públicas, todos os arquivos de cabeçalho são importados por todo o software, de modo que o software inteiro conhece o software inteiro e tem permissão para modificar estruturas de dados no local a partir de qualquer ponto do código.
  3. Complexidade é “resolvida” com mais complexidade, e ninguém parece ver isso como um problema chamado dívida técnica.

Bases de código sãs protegem os dados tornando-os privados e forçando as interações através de funções getters/setters definidas como APIs públicas. Isso permite o gerenciamento fácil da segurança entre threads (thread safety) quando chega a hora, mas também nos permite rastrear o que está escrevendo onde e quando a partir de um lugar central. E então, você inclui o conjunto mínimo de APIs em cada arquivo, para isolar o código o máximo possível.

Em vez disso, o código-fonte do Darktable escreve em qualquer lugar a partir de qualquer lugar, sem interfaces adequadas. Assim, qualquer tipo de mudança na base de código do Darktable dispara sistematicamente efeitos colaterais e quebra algo inesperado na outra ponta do software, em deprimentes sessões de whack-a-mole nascidas da preguiça e da estupidez.

Portanto, muito trabalho tedioso no Ansel foi feito para apertar as APIs, privatizar o máximo possível de estruturas de dados e isolar as bibliotecas umas das outras para desemaranhar um pouco o grafo de dependências.

Anexo: os planos

Arquitetura completa

Aqui está o fluxograma de alto nível de toda a arquitetura, do banco de dados aos backbuffers. Agora podemos finalmente desenhar um fluxograma dessa bagunça.

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

Gerenciamento de memória RAM/vRAM

Gerenciamento de buffers de cache:

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

Se a saída do módulo está planejada para cache (por causa de preferência do usuário, necessidade desse buffer para histograma/seletor de cor, ou porque o próximo módulo é o que está ativo na GUI), o OpenCL usa um buffer de memória fixada (pinned, fixado no cache da RAM). Também fixamos os buffers de memória de entrada, quando a GPU recebe entrada do cache da RAM. Isso é ligeiramente mais caro do que usar um buffer exclusivo do dispositivo (device-only), mas menos caro do que copiar esse buffer device-only para o host. Se a saída do OpenCL não está planejada para cache, usamos um buffer device-only que pode ser reciclado posteriormente, mas que nunca será copiado para a RAM.

Em caso de um erro do OpenCL para um módulo específico (o mais óbvio: falta de memória), o buffer de entrada da GPU é copiado de volta de forma transparente para o cache da RAM antes de recorrer ao caminho exclusivo de CPU.

Todos esses buffers são rastreados por entradas de cache, que vinculam um buffer de RAM a um de vRAM (se usarmos ambos numa situação de fixação), ou simplesmente mantêm o controle do que está alocado. Se uma alocação de memória de GPU falha, primeiro percorremos o cache para liberar todos os buffers alocados anteriormente. Se a alocação de memória de GPU falhar novamente depois disso, recorremos à CPU.

Entradas de cache

O cache é uma tabela hash de entradas de cache. A chave delas é um hash/checksum. Temos 2 tipos de entradas de cache:

  • internas, usadas como buffers reutilizáveis para entradas/saídas de módulos,
  • externas, usadas como buffers descartáveis para computações intermediárias dos módulos.

As entradas de cache internas são indexadas pelo global_hash de seu módulo pai, e podem ser encontradas novamente mais tarde (mesmo a partir da GUI) porque esse hash é estável entre execuções e pipelines. Elas podem ser reindexadas se reutilizarmos seu buffer de memória, de modo que a nova chave corresponda ao novo estado de seu módulo pai. Essas entradas de cache podem ser travadas em modo de leitura ou escrita para acesso concorrente seguro entre threads paralelas. Uma trava de escrita pode ser capturada por apenas uma thread se nenhuma outra thread estiver lendo; uma trava de leitura pode ser capturada por várias threads se nenhuma outra thread estiver escrevendo. Como a trava de escrita é liberada pelo módulo que escreve sua saída antes de a trava de leitura ser adquirida pelo módulo que usa a mesma entrada de cache como sua entrada, e há um risco de exclusão nesse meio-tempo, elas também têm um mecanismo de refcount: o produtor da entrada de cache o incrementa, o consumidor o decrementa. O mesmo mecanismo é usado pela sala escura para buscar o backbuffer sem cópia.

As entradas de cache externas são indexadas pelo endereço de memória de seu buffer de dados. Elas devem ter vida curta.

Adicionar/remover entradas de cache incrementa/decrementa automaticamente o tamanho global do cache. Continuamos adicionando novas entradas enquanto o tamanho global do cache estiver abaixo do limite permitido, após o que começamos a destruir as entradas mais antigas se o refcount delas for 0 e elas não estiverem travadas.

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

Uma entrada de cache não sabe o tipo de dado que contém. Ela sabe apenas os endereços dos buffers, seu tamanho, seu refcount e seu estado de trava. Portanto, é uma abstração genérica das coisas contidas na memória.


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