Seit ich um 2012 herum begann, Darktable zu benutzen, war ich immer überrascht, wie wenig RAM es verwendete. Die Leute halten es für eine gute Sache, wenn eine Anwendung sparsam mit dem Speicher umgeht, und das trifft sicherlich zu, wenn wir von Ihrer Desktop-Umgebung sprechen. Aber wenn wir von einer Produktionssoftware sprechen, die aufwendiges Pixel-Rendering an Bildern von 12 bis 54 Mpixel durchführt, dann bedeutet das, dass dieselben aufwendigen Berechnungen immer wieder durchgeführt werden, anstatt gespeichert zu werden, um später wiederverwendet zu werden. Genau dafür ist ein Cache da: um teure Berechnungen zu vermeiden. Und er sollte dafür den gesamten verfügbaren RAM nutzen, denn Rechnen bedeutet Energieverschwendung, und das hat konkrete Auswirkungen, wenn Sie im Akkubetrieb arbeiten. Außerdem haben Sie für diesen RAM bezahlt, und ihn zu nutzen leert Ihren Akku nicht. Die CPU/GPU hingegen…
Ja, Fotoreporter und viele digitale Nomaden retuschieren vor Ort auf akkubetriebenen Laptops. Es wird Zeit, dass die Open-Source-Welt begreift, dass nicht alle Fotografen abends und am Wochenende nach ihrem „richtigen" Tagesjob an ihrem Schreibtisch sitzen. Dieselben Dinge also immer und immer wieder zu berechnen und neu zu berechnen, ist schlicht Energieverschwendung, egal ob Sie an der Steckdose hängen oder im Akkubetrieb arbeiten.
In der Zwischenzeit hatte Darktable schon immer diese seltsame kleine RAM-Einstellung, mit der Sie festlegen konnten, wie viel es verwenden sollte. Nur hatte es keinerlei Möglichkeit, tatsächlich zu verfolgen, wie viel RAM es verwendete, sodass es eher ein Richtwert als eine Regel war. Das wurde später durch eine völlig idiotische qualitative „Ressourcen"-Einstellung ersetzt, die sowohl nichts bedeutet als auch tatsächlich nicht angibt, wie viel RAM Sie der Software zuweisen.
Der RAM-Cache von Darktable hat also nie wirklich funktioniert, wurde zu wenig genutzt und musste dringend repariert werden. Denn infolgedessen wurde alles ständig ohne jeden Grund neu berechnet.
Aber… Es gab einen Grund, warum der Cache zu wenig genutzt wurde und nicht wirklich funktionierte: Diese Software hatte keinerlei Einblick in den Lebenszyklus der Daten, was gewissermaßen die Voraussetzung ist, wenn man Daten zur Wiederverwendung speichern möchte. Das lag an einer Pixel-Pipeline, die wirklich verworren war (ich frage mich ernsthaft, ob irgendjemand unter den Darktable-„Entwicklern" in der Lage ist, das Flussdiagramm dessen zu zeichnen, was wir mit den Pixeln von Anfang bis Ende anstellen), aber auch an Bild-Metadaten, die an mehreren Stellen berechnet, kopiert und (dann teilweise aktualisiert) an mehreren Stellen gespeichert wurden…
Der Pipeline-Cache hatte einen einzigen Zweck: das Zuweisen von Ein- und Ausgabepuffern der Module und möglicherweise deren Wiederverwendung, falls sie bereits verfügbar waren. Doch seine Größe wurde in Anzahl der Einträge definiert, was wirklich begrenzt war, und nicht in der Menge des zugewiesenen Speichers. Das machte ihn mäßig nützlich und zwang uns, ihn viel zu zurückhaltend einzusetzen, weil seine tatsächliche Speichergröße völlig unvorhersehbar war.
Unnötig zu erwähnen, dass „den Cache reparieren" bedeutete „die Pipeline reparieren", was wiederum bedeutete „den Datenlebenszyklus sichtbar, nachverfolgbar und global verwaltet machen", was bedeutete, die High-Level-Architektur der Software neu zu gestalten. Wie wir sehen werden, hatte das unerwartete Vorteile für die Performance, die die modulweisen internen Optimierungen, die Darktable in derselben Zeit vornahm, bei weitem übertreffen.
Was sich seit 2022 geändert hat
Dieser Artikel ist die direkte Fortsetzung von Den Pipeline-Cache und 10 Jahre alte Bugs reparieren. In jenem vorherigen Kapitel ging es darum, die Fäulnis zu finden und die peinlichsten Fehler zu stoppen. In diesem hier geht es darum, was danach geschah, als offensichtlich wurde, dass die Cache-Bugs überhaupt keine isolierten Bugs waren, sondern Symptome eines Renderers, dessen Verantwortlichkeiten viel zu lange vermischt worden waren.
Wo sich das historisch einordnet
Das ursprüngliche Problem war nicht bloß „der Cache cached nicht genug". Das eigentliche Problem war, dass der gesamte Pipeline-Stack um zufälliges Verhalten herum gewachsen war. GUI-Neuzeichnungen konnten auf ungeregelte Weise die Bildverarbeitung anstoßen. Die Maskenvorschau ließ GUI-Zustand in den Renderer durchsickern. Histogramm- und Picker-Logik hingen von speziellen Nebeneffekten der Pipeline ab. Export, Vorschaubilder, Vorschau und Dunkelkammer hatten alle ihre eigenen kleinen Varianten von „sicher können wir diesen Puffer einfach noch ein weiteres Mal kopieren". Und immer wenn Konsistenz schwer zu beweisen wurde (während der Maskenanzeige oder bei Zuschnittsänderungen), bestand die Rückfallstrategie oft darin, Cache-Zeilen zu leeren und alles neu zu berechnen, denn offenbar galt „alles in Brand stecken und von vorn anfangen" eine Zeit lang als Architektur.
Einige der Code-Kommentare sagten das bereits genauso aus. Es gab Warnungen vor durch Neuzeichnung ausgelöster Neuberechnung. Es gab sogar eine alte Notiz, die besagte, der Cache solle letztlich global werden. Die letzten paar Jahre ging es also nicht darum, eine neue Theorie von Grund auf zu erfinden. Es ging größtenteils darum, endlich die Aufräumarbeit zu erledigen, um die der Code seit den 2010er Jahren gebettelt hatte.
Der entscheidende historische Wandel besteht darin, dass die Pipeline nicht mehr als ein einziger rekursiver Klumpen behandelt wird, von dem erwartet wird, seine eigenen Bedürfnisse während der Ausführung selbst herauszufinden. Sie wurde schrittweise in klarere Ausführungspfade aufgeteilt: für interaktives Rendering, Headless-Rendering, GPU-Verarbeitung, CPU-Verarbeitung und GUI-seitige Konsumenten. Zugleich wurde GUI-Verhalten zurück in die GUI verschoben. Zeichnen wurde wieder zu Zeichnen. Verarbeitung wurde wieder zu Verarbeitung. Das klingt banal, was gewöhnlich ein Zeichen dafür ist, dass das vorherige Design absurd geworden war.
Prüfsummen, oder wie Gültigkeit aufhörte, ein Ratespiel zu sein
Sobald der Renderer nicht mehr mit jedem Widget und jedem Seitenkanal verstrickt war, wurde es möglich, den Bildzustand explizit zu definieren. Jeder Verlaufseintrag trägt nun eine Modul-Prüfsumme, die aus Modulparametern, Überblendungsparametern und allen relevanten Maskenformen aufgebaut wird. Das verleiht jedem Modulzustand einen kanonischen Fingerabdruck, sobald er in den Verlauf eintritt, statt die Gültigkeit später aus dem abzuleiten, was zufällig ausgeführt wurde.
Das allein reichte nicht aus, denn eine Pipeline ist nicht nur ein Haufen von Moduleinstellungen. Sie hängt auch von der Reihenfolge, der Region of Interest, den Puffer-Verträgen und dem anzeigebezogenen Zustand ab. Die Planungsphase akkumuliert also diese Fingerabdrücke auf Modulebene über die gesamte Kette hinweg und bezieht den Rest des Laufzeit-Vertrags mit ein, bevor irgendein Pixel bewegt wird. Das Ergebnis ist eine stabile Identität pro Stufe und eine finale Pipeline-Identität.
Hier taucht endlich Sichtbarkeit auf. Die Pipeline kann wissen, ob sie noch gültig ist, indem sie ihren Verlaufs-Hash vergleicht. Der angezeigte Backbuffer kann wissen, ob er noch mit dem aktuellen Pipe- und Verlaufszustand übereinstimmt. Eine Cache-Zeile kann wissen, ob sie wirklich zu genau der aktuell angeforderten Stufe, ROI und den Parametern gehört. Das klingt fast beleidigend vernünftig, aber es erforderte zunächst eine Menge Aufräumarbeit: Die Synchronisierung des Verlaufs mit der Pipeline musste explizit gemacht werden, der Cache-Bypass musste im Voraus deklariert werden (für die Maskenvorschau und Zuschnittsbearbeitungen), die Maskenanzeige durfte die Regeln nicht mehr mitten in der Ausführung verändern, und die alten durch Neuzeichnung ausgelösten Nebeneffekte mussten verschwinden. Zuverlässige Hashes bekommt man nicht auf der Grundlage eines unzuverlässigen Kontrollflusses.
Der praktische Vorteil ist, dass Konsistenz nicht länger durch Aberglaube aufrechterhalten wird. Wir müssen nicht mehr fragen: „Hat die GUI wahrscheinlich das Richtige zur richtigen Zeit für ungültig erklärt?" Die Antwort steckt in den Prüfsummen. Entweder der Zustand stimmt überein, oder er tut es nicht. Und wir können jede beliebige Modulausgabe aus der GUI-Schicht abgreifen, ohne eine Pipeline auszuführen, weil die Modul-Prüfsumme vorhersehbar ist und im Voraus vor dem Rendering oder parallel dazu berechnet werden kann.
Die Cache-First-Architektur
Zuverlässige Hashes verändern die Architektur nahezu zwangsläufig. Sobald jeder bedeutsame Pipeline-Zustand eine stabile, im Voraus bekannte Identität besitzt, hört der Cache auf, eine Best-Effort-Optimierung zu sein, und wird zum Zentrum des Datenflusses.
Deshalb hat die Pipeline nun eine echte Planungsphase vor der Ausführung. Zuerst wird der Verlauf synchronisiert. Die Regions of Interest werden durch die gesamte Kette propagiert. Jede Stufe erhält einen expliziten Eingabe- und Ausgabevertrag. Die Host-seitige Cache-Richtlinie wird vor der Laufzeit versiegelt. Globale Hashes werden vor der Ausführung berechnet. Mit anderen Worten: Die Engine weiß, was sie zu tun im Begriff ist, bevor sie damit beginnt, was eine erfrischende Abwechslung zur älteren Methode ist, es mitten im Flug herauszufinden und mit Hacks auszugleichen.
Von da an werden Cache-Abfragen deterministisch. Eine Stufe kann genau den Puffer wieder öffnen, der ihrem Zustand entspricht, sodass ein Modul Berechnungen vollständig umgehen kann, indem es lediglich im Cache nachsieht, ob eine Cacheline bereits als Prüfsummen-Abfrage seinem internen Zustand entspricht. Nachgelagerte Konsumenten können veröffentlichte Ergebnisse per Hash wieder öffnen, statt den Renderer zu bitten, nur für sie einen weiteren speziellen Tanz aufzuführen. Der Cache hört auf, ein Haufen vage wiederverwendbaren Speichers zu sein, und wird zum maßgeblichen Register gültiger Zwischen- und Endergebnisse.
Das erklärt auch, warum so viel Code entfernt oder vereinfacht werden konnte. Sobald die Gültigkeit zentralisiert ist, braucht man weniger Heuristiken, weniger Sonderzweige, weniger „außer wenn die GUI in diesem Modus ist"-Klauseln und weniger Notfall-Leerungen. Der Code wird kürzer, nicht weil das Problem kleiner wurde, sondern weil es nicht mehr an sechs widersprüchlichen Stellen gleichzeitig gelöst wird.
Cachelines binden auch GPU- und CPU-Speicher, was uns ermöglicht, OpenCL-Pinned-Memory zu nutzen. Es gab seit jeher eine OpenCL-Benutzereinstellung, mit der sich Pinned-Memory aktivieren oder deaktivieren ließ, aber ich entdeckte, dass diese Option nur für die gekachelte Verarbeitung verwendet wurde, wenn Module ihren gesamten Speicherbedarf nicht auf der GPU unterbringen konnten. Pinned-Memory wurde nun auch auf normale Operationen ausgeweitet, da es ermöglicht, RAM und VRAM ohne Kopieren zu mappen. Der Einsatz von Pinned-Memory bei einer vollständig gecachten GPU-Pipeline reduziert die für das Verschieben von Speicherpuffern aufgewendete Zeit um bis zu einen Faktor von 7.
Doch das erzwungene Cachen von OpenCL-Modulausgaben hat, selbst mit Zero-Copy-Pinned-Puffern, immer noch gewisse Kosten und ist teurer, als den Cache einfach ganz zu überspringen. Für einige aufwendige Module (Profiliertes Entrauschen, Diffusion oder Schärfung, Kontrastequalizer) lohnt sich der Cache-Overhead durchaus, aber für schnelle Module (Weißabgleich, Belichtung, Eingabe-Farbprofil) ließen die Kosten des Cachens der OpenCL-Puffer die ganzen Module auf der GPU tatsächlich langsamer laufen als auf der CPU.
Wir haben nun also modulweise Heuristiken, die entscheiden, ob ein OpenCL-Modul seinen Ausgabepuffer im RAM-Cache veröffentlicht. Aufwendige Module und alle Module, die Color-Picker oder Histogramme erfassen, werden standardmäßig veröffentlicht. Für die übrigen können die Benutzer selbst entscheiden:

Dies wird es Benutzern auch ermöglichen, OpenCL selektiv bei einigen Modulen zu deaktivieren, wenn sie wiederkehrende Probleme mit ihnen haben. Zum Beispiel verbrauchen Profiliertes Entrauschen und Dunstentfernung viel GPU-Speicher und können zur Laufzeit aus Mangel an verfügbarem Speicher fehlschlagen, obwohl die anfängliche Speicherplanung ergab, dass er ausreichen sollte. Wenn das geschieht, hat das Modul bereits einige Zeit mit der Berechnung begonnen und weicht auf die CPU aus. Wenn das häufig passiert, umgehen Sie die GPU bei diesem Modul lieber die ganze Zeit, als die doppelte Strafe in Kauf zu nehmen.
Aber damit hört es nicht auf. GPU-Puffer werden auch auf der GPU am Leben gehalten. Das bedeutet, dass der Neustart einer partiellen Pipeline ab einem OpenCL-Modul die Eingabe wenn möglich direkt von der GPU bezieht, ohne jegliches Kopieren aus dem RAM. Es bedeutet auch, dass die leichtgewichtigen Module ihren vorherigen GPU-Puffer wiederverwenden können, wenn er passt, statt einen neuen zuzuweisen. Dies allein eröffnet die Möglichkeit einer Echtzeit-Pipeline, die für das neue Modul Zeichnen benötigt wird, mit etwa 60–80 ms Latenz zwischen Pinselstrichen und Bildaktualisierungen. Ich hätte nie gedacht, dass das überhaupt möglich wäre.
Dieselbe Speicher-Neuzuweisung wird im RAM durchgeführt, da Ansel den gesamten Cache nun in seiner eigenen Speicher-Arena beherbergt. Dieses Schema erlaubt uns nicht nur, beim Start der Anwendung einen zusammenhängenden Speicherblock vom Betriebssystem vorzureservieren, was zu schnelleren Zuweisungen führt, es stellt auch sicher, dass wir das benutzerdefinierte Speichervolumen nicht überschreiten. Wenn Sie also entscheiden, Ansel 8 GB RAM zuzuweisen, sind wir nun in der Lage sicherzustellen, dass dies tatsächlich geschieht: Wir werden dieses gesamte Volumen füllen, bis es voll ist, woraufhin wir beginnen, die ältesten Puffer zu recyceln. Alle Pixelpuffer, Modul-Eingaben, -Ausgaben, aber auch temporäre interne Scratchpads werden in unserer Speicher-Arena zugewiesen.
Und, nicht zuletzt, gibt es nur einen einzigen Pipeline-Cache für die gesamte Anwendung, was bedeutet, dass alle Pipeline-Typen (Dunkelkammer-Vorschau, Dunkelkammer-Hauptbild, Vorschaubild-Export und Datei-Export) sich denselben Cache teilen. Dies musste zwar für den nebenläufigen Multithread-Zugriff verwaltet werden, aber es bedeutet, dass eine Pipeline, wenn sie eine Modulausgabe benötigt, die bereits von einer anderen Pipeline in derselben Größe berechnet wurde, direkt die Cacheline abgreifen und ihre eigene Neuberechnung umgehen kann.
Um das auszunutzen, wurde die zuvor fest dimensionierte Dunkelkammer-„Vorschau" (also die herunterskalierte Version des vollständigen Bildes, die im Navigations-Widget, zum Abtasten von Histogrammen und Color-Pickern und als vorübergehende „verschwommene" Zwischenfüllung, während das Hauptbild neu berechnet wird, verwendet wird) so geändert, dass sie dynamisch auf die „Einpassen"-Zoomstufe des Hauptbilds (jenes, das in der Mitte der Dunkelkammer angezeigt wird) dimensioniert wird. Das Ergebnis ist, dass nur ein Bild berechnet werden muss, wenn Sie die Dunkelkammer betreten, und das Zurückzoomen auf den „Einpassen"-Zoom ist augenblicklich.
Da aber diese fest dimensionierte Vorschau an vielen Stellen in der GUI bequemerweise dazu benutzt worden war, Cursorkoordinaten im Widget-Raum auf die RAW-Bildkoordinaten in voller Auflösung umzurechnen, indem derselbe hässliche Codeblock überall hineinkopiert wurde (wobei sogar der Kommentar „Ich verstehe nicht, was das tut" mitkopiert wurde), musste das gesamte Koordinatensystem neu gemacht werden, um dieser Änderung Rechnung zu tragen. Und, wiederum, wurden diese Koordinaten nur innerhalb einer Pipeline berechnet, sodass die GUI darauf warten musste, dass die Pipeline die neuen Größen neu berechnete, um zu wissen, wo Objekte zu positionieren sind, was GUI-Störungen auslöste, insbesondere beim Ändern des Zuschnitts. Aber nun wird all das im Voraus über eine einheitliche API berechnet, sodass Schluss ist mit dem albernen Herumkopieren, multipliziert mit der Anzahl der Module.
Was sich dadurch außerhalb des Kerns geändert hat
Die erste externe Folge ist, dass Kopien aufhörten, sich als Funktionen zu tarnen. Die Dunkelkammer benötigt keinen dedizierten GUI-Backbuffer mehr, um das anzuzeigen, was der Renderer bereits produziert hat. Sie kann das veröffentlichte Bild direkt aus dem Cache abgreifen, eine Cairo-Surface daran binden und es in wenigen Millisekunden anzeigen. Zuvor war der Pfad langsamer und mit Kopiervorgängen belastet, ohne guten Grund außer ererbter Design-Verwirrung. Die Dunkelkammer kann über Prüfsummen auch direkt prüfen, ob ein gegebener Pipeline-Backbuffer mit dem aktuellen Entwicklungsverlauf auf dem neuesten Stand ist. Zuvor beruhte das auf einem „Dirty"-Flag, das von mehreren Threads überschrieben werden konnte und jedes „Best Effort"-Neuzeichnen der Dunkelkammer verhinderte (etwa: den letzten bekannten gültigen Backbuffer hinklatschen, während der aktuelle neu berechnet wird). Das war wichtig, wenn ein Benutzer Modulparameter schneller änderte, als die Pipeline neu berechnen konnte: Wir brauchen immer noch etwas, um die Ansicht zu füllen und Flackern zu vermeiden.
Dieselbe Logik erstreckt sich nun auf Export und Vorschaubilder, die das finale veröffentlichte Ergebnis wieder öffnen können, statt ihre eigene private Realität neu aufzubauen. Auch der Histogramm- und Picker-Code hat sich davon entfernt, sich an die Pipeline-Ausführung anzuhängen. Die Scopes folgen expliziten Abschlusssignalen vom Vorschaupfad, cachen ihre eigene Cairo-Surface gegen den Quellzustand und tasten direkt von cache-gestützten Backbuffern ab. Ein RAW-Histogramm (nach dem Modul Demosaic abgetastet) wurde der alten Pipeline-Ausgabe hinzugefügt: Das Umschalten zwischen beiden erfordert keine Pipeline-Neuberechnung, ebenso wenig das Color-Picking in beiden. Das ist ein viel langweiligeres Design, was genau der Grund ist, warum es besser ist.
Eine weitere wesentliche Folge ist, dass Pipeline-Varianten nicht mehr in isolierten Cache-Silos leben. Vorschau, Dunkelkammer, Export, Vorschaubilder und Histogramm-Konsumenten können nun Cache-Zustand teilen. Das war bereits die Absicht, die vor langer Zeit im Cache-Code angedeutet wurde; es bedurfte lediglich einer vollständigen Bereinigung der Gültigkeitsverfolgung, um sie Wirklichkeit werden zu lassen. Sobald sich all diese Konsumenten auf dieselben Hashes einigen, können sie sich endlich auch auf dieselben Puffer einigen. Der Vorteil ist, dass eine Pipeline die bereits berechnete Cacheline einer anderen Pipe wiederverwenden kann, wenn sie passt (gleicher Parameter, gleiche Ein- und Ausgabegröße). Der Beginn der Dunkelkammer-Pipelines wurde daher auf volle Auflösung umgestellt: Entrasterung und Entrauschen werden beim Betreten der Dunkelkammer langsamer sein, aber danach werden Zoomen und Verschieben augenblicklich. Und beim Exportieren eines Bildes werden diese frühen Stufen ebenfalls direkt aus dem Cache abgegriffen. Übrigens berechnet das zweimalige Exportieren desselben Bildes in zwei verschiedenen Auflösungen nur ab dem Skalierungsmodul am Ende der Pipeline neu.
Die Speicherverwaltung folgte derselben Logik. Cache-Zeilen wurden zu refcounted, sperrbaren, wiederverwendbaren Objekten statt zu wegwerfbaren Klumpen, die durch ad-hoc-Nebenspeicher herumgereicht wurden. CPU- und GPU-Pfade teilen sich nun weit mehr desselben Besitzmodells. Auf der OpenCL-Seite werden Host- und Device-Puffer mit expliziten Lebensdauerregeln verwaltet, Pinned-Memory wird wiederverwendet statt umgewälzt, und RAM und VRAM bleiben nach Möglichkeit über Pinned- und Zero-Copy-Transfers synchronisiert, statt über sinnlose Zwischenkopien gespiegelt zu werden. Das macht die GPU nicht auf magische Weise schneller im Rechnen. Es hindert vor allem die umgebende Sanitärverrohrung daran, die Gewinne zu verschwenden.
Der Vorteil ist nicht bloß Benchmark-Geschwindigkeit. Es sind auch Latenz, Robustheit und Energieverbrauch. Der Dunkelkammer-Start wird kürzer, weil es weniger Kopien und weniger duplizierte Durchläufe gibt. Zoomen, Verschieben, Maskenvorschau und Verlaufsnavigation hören auf, das halbe Universum für ungültig zu erklären, nur weil es früher zu schwer war, Korrektheit zu beweisen. OpenCL wird weniger zufällig, weil Fallback, Kachelung und Speicherbesitz expliziter angegeben sind. Die Software verbringt weniger Zeit damit, Pixel hin und her zu schieben, nur um sich zu vergewissern, dass sie noch irgendwo existieren.
Als Nebeneffekt wurde die Fehlerbehandlung in der Pipeline verbessert. Module, deren Speicherzuweisung fehlschlug, werfen nun sofort einen Fehler und brechen die Pipeline ab. Zuvor wurden Zuweisungsfehler nicht überall geprüft, und eine ganze Pipeline konnte einen NULL-Puffer bis zum Ende mitschleppen… oder ganz einfach an segmentation fault-Fehlern abstürzen. Dies wird nun vorgelagert auf einheitliche Weise in der gesamten Software verhindert.
Color-Picker-Abtastung und Histogramme können Daten abtasten, ohne eine Pipeline-Neuberechnung auszulösen, indem sie direkt den Cache abrufen, falls die angeforderte Cacheline existiert. Die globale Scopes-Werkzeugkiste erlaubt Ihnen die Wahl zwischen RAW RGB (nach dem Entrasterung abgetastet) oder finalem Pipeline-RGB (entweder nach dem Ausgabe-Farbprofil in 32-Bit-Gleitkomma oder im Backbuffer in 8-Bit-Ganzzahl abgetastet): Der Wechsel von einem zum anderen startet keine Pipeline neu, sondern lädt einfach eine andere Cacheline, und das Color-Picking geschieht transparent auf dieser Cacheline.
Was tatsächlich behoben wurde, indem man es richtig gemacht hat
Viele sichtbare Ärgernisse lassen sich eher auf diese Neugestaltung zurückführen als auf irgendeine einzelne Mikrooptimierung. Die High-DPI-ROI-Handhabung verbesserte sich, weil der Besitz der Geometrie klarer wurde und die Koordinatenzuordnung zwischen GUI und RAW-Bild nun in einer zentralen API gehandhabt wird. Die Resynchronisierung von Verlauf zu Pipeline wurde weniger fragil, weil der Verlauf aufhörte, ein beiläufiger Nebeneffekt des GUI-Flusses zu sein, und zu einer erstklassigen Eingabe für die Planung wurde. Die Echtzeit-Maskenvorschau muss nicht mehr gegen ein Cache-Modell ankämpfen, das für eine andere Ära entworfen wurde. Die Histogramm-Aktualisierung wurde vorhersehbar, weil sie nun veröffentlichte Daten konsumiert, statt zu hoffen, dass der richtige Zwischenpuffer zufällig irgendwo am Leben ist. Endlosschleifen, veraltete Cache-Zeilen, ungültige Backbuffer und das klassische „die Vorschau hat die volle Pipe ohne offensichtlichen Grund ab Modul 0 neu berechnet" werden allesamt leichter zu diagnostizieren, sobald der Lebenszyklus explizit ist.
Das Interessante hier ist also nicht, dass ein großes Refactoring in Isolation stattfand. Es ist, dass sich eine lange Reihe von Aufräumarbeiten endlich um eine Idee ausrichtete: Gültigkeit sollte im Voraus berechnet, benannt und geteilt werden. Sobald das geschah, folgte der Rest nahezu mechanisch. Der Cache wurde zentral, weil die Hashes vertrauenswürdig waren. Externe Konsumenten konnten aufhören zu kopieren, weil cache-veröffentlichte Puffer maßgeblich wurden. CPU- und GPU-Pfade konnten mehr Zustand teilen, weil der Besitz explizit wurde. Und der Renderer hörte auf, sich wie ein Spukhaus zu verhalten, in dem das Verstellen eines einzigen Reglers drei nicht verwandte Subsysteme und einen Neuzeichnungs-Callback aus 2013 aufwecken konnte.
Benchmarks
Die Benchmarks werden an beiden Anwendungen durchgeführt, lokal mit Release-Build und GCC14 unter Verwendung ihres jeweiligen build.sh --build-type Release-Skripts kompiliert.
- Konfig 1
- Die Hardware ist ein Thinkpad P51 mit 8 × Intel Xeon CPU E3-1505M v6 @ 3.00GHz und GPU Nvidia Quadro M2200, betrieben unter Fedora 41 Plasma mit Wayland. Die Nvidia-Treiberversion ist 580.105.08. Der Intel Xeon ist eine High-End-CPU, die 2015 veröffentlicht wurde. Die Quadro M2200 ist eine professionelle Mittelklasse-CPU, die 2017 veröffentlicht wurde.
- Konfig 2
- Die Hardware ist ein Desktop-PC mit 4 × Intel Core i3-4130 und GPU AMD Radeon RX 580 Polaris 10, betrieben unter Ubuntu 24.04 LTS mit Wayland. Die AMD-Treiberversion ist RustiCL 25.2.8. Der Core i3 ist eine Mittelklasse-CPU, die 2013 veröffentlicht wurde. Die AMD Polaris 10 ist eine GPU der oberen Mittelklasse, die 2017 veröffentlicht wurde.
Wir zeigen hier die Ausgabe von ansel -d perf und darktable -d perf. Sowohl die Ansel- als auch die Darktable-Konfigurationsdateien werden mit diesem Skript eingerichtet, um dieselbe Konfigurations-Baseline zu gewährleisten. Das 45-Mpx-Testbild stammt von hier und das Bearbeitungs-XMP kann hier heruntergeladen werden.
Anfängliches Laden in der Dunkelkammer
Warnung: In Ansel ist es wichtig, diesen Test durchzuführen, ohne dass ein Modul in der GUI fokussiert (das heißt, aufgeklappt) ist. In dieser Situation cached Ansel immer die Ausgabe des vorherigen Moduls, sodass wir sicherstellen, dass wir, wenn Änderungen in jenem fokussierten Modul vorgenommen werden, die Berechnungen immer von der unmittelbaren Eingabe aus neu starten. Aber das erzwungene Cachen auf diese Weise löst einen Speicher-Overhead aus, der bei leichtgewichtigen Modulen sichtbar sein kann.
Konfig 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'Konfig 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'Bericht
Zunächst einmal: Beim Betreten der Dunkelkammer berechnet Darktable 2 Pipelines für dasselbe Ergebnis wie Ansel, das nur eine berechnet. Also, unabhängig von den tatsächlichen Laufzeiten, ist bereits die Hälfte der Berechnungen nutzlos.
Dann berechnet Ansel das Bild in voller Auflösung bis zum Modul Anfängliches Resampling, während Darktable dies nur bis vor Demosaic tut. Das ist für den Vergleich wichtig.
Konfig 1 (Intel Xeon, Nvidia Quadro)
| Software | GPU | CPU |
|---|---|---|
| Ansel | 4.493 s | 10.692 s |
| Darktable 5.4.1 | 6.822 s | 13.66 s |
Konfig 2 (Intel i3, AMD Radeon)
| Software | GPU | CPU |
|---|---|---|
| Ansel | 3.784 s | 17.538 s |
| Darktable 5.4.1 | 3.927 s | 44.481 s |
Bei Konfig 1 schafft Darktable es, auf der GPU langsamer als Ansel zu sein, selbst wenn man nur das Rendering der einzelnen Haupt-Pipeline betrachtet und selbst wenn das Bild früher in der Pipeline auf die Anzeigeauflösung herunterskaliert wird. Aber wir sehen tatsächlich denselben Effekt auf der CPU, trotz all der angeblichen „Optimierungen", die um 2023–2024 an den reinen CPU-Modulen in Darktable vorgenommen wurden. Insgesamt wird Darktable Ihren Computer 2,3 bis 3,0 s länger einfrieren.
Bei Konfig 2 zeigt der CPU-Pfad eine Strafe von 0,8 s für Ansel, allein bei der Haupt-Pipeline. Die AMD-GPU zeigt einen schlechten Einbruch beim Modul Objektivkorrektur, das bei Ansel in voller Auflösung verarbeitet, während es bei Darktable in Bildschirmauflösung verarbeitet. Berücksichtigt man die zweite Pipeline, die Darktable ausführt, ist Ansel auf der GPU um 0,14 s schneller. Auf der CPU jedoch friert Darktable die Maschine nun 27,07 s länger ein, wegen dieser duplizierten Pipeline-Arbeit. Wie auch immer, die langsamen Module befinden sich am Anfang der Pipeline und werden nicht für die gesamte Sitzung neu berechnet.
Das ergibt uns die folgenden Modul-für-Modul-Vergleiche nebeneinander. Wir vergleichen nur Module, die in derselben Auflösung laufen, und nur für die Haupt-Bild-Pipeline. Im Durchschnitts-Tab werden Faktoren mit einem geometrischen Mittel und relative Differenzen mit einem harmonischen Mittel gemittelt:
| Modul / Chip | Ansel Master | Darktable 5.4.1 | Ansel-Beschleunigung |
|---|---|---|---|
| Raw settings* / CPU | 35 ms | 40 ms | ×1.14 / +13 % |
| Raw settings* / GPU | 18 ms | 17 ms | ×0.96 / -5.9 % |
| White balance* / CPU | 31 ms | 29 ms | ×0.94 / -6.9 % |
| White balance* / GPU | 16 ms | 13 ms | ×0.81 / -23 % |
| Highlights reconstruction* / CPU | 6.12 s | 6.33 s | ×1.03 / +3.4 % |
| Highlights reconstruction* / GPU | 2.49 s | 3.70 s | ×1.49 / +33 % |
| Demosaic* / CPU | 348 ms | 717 ms | ×2.06 / +52 % |
| Demosaic* / GPU | 254 ms | 490 ms | ×1.93 / +48 % |
| Exposure / CPU | 5 ms | 12 ms | ×2.4 / +58 % |
| Exposure / GPU | 6 ms | 10 ms | ×1.67 / +40 % |
| Input color profile / CPU | 3 ms | 15 ms | ×3 / +67 % |
| Input color profile / GPU | 2 ms | 32 ms | ×16 / +94 % |
| Color calibration / CPU | 70 ms | 84 ms | ×1.20 / +25 % |
| Color calibration / GPU | 1 ms | 39 ms | ×39 / +97 % |
| Diffuse or sharpen / CPU | 3.15 s | 4.21 s | ×1.34 / +25.2 % |
| Diffuse or sharpen / GPU | 1.09 s | 1.69 s | ×1.55 / +35 % |
| Color balance RGB / CPU | 262 ms | 261 ms | ×1.00 / -0.4 % |
| Color balance RGB / GPU | 9 ms | 12 ms | ×1.33 / +25 % |
| Filmic RGB / CPU | 137 ms | 140 ms | ×1.02 / +2.1 % |
| Filmic RGB / GPU | 6 ms | 11 ms | ×1.83 / +45 % |
| Output color profile / CPU | 13 ms | 21 ms | ×1.62 / +38 % |
| Output color profile / GPU | 23 ms | 52 ms | ×2.26 / +56 % |
| Dithering (CPU only) / CPU pipeline | 24 ms | 59 ms | ×2.46 / +59 % |
| Dithering (CPU only) / GPU pipeline | 43 ms | 88 ms | ×2.05 / +51 % |
| Gamma / display encoding (CPU only) / GPU pipeline | 12 ms | 9 ms | ×0.75 / -33 % |
| Gamma / display encoding (CPU only) / CPU pipeline | 12 ms | 9 ms | ×0.75 / -33 % |
*: Module, die auf beiden Anwendungen in voller Auflösung laufen.
| Modul / Chip | Ansel Master | Darktable 5.4.1 | Ansel-Beschleunigung |
|---|---|---|---|
| Raw settings* / CPU | 63 ms | 49 ms | ×0.78 / -29 % |
| Raw settings* / GPU | 37 ms | 59 ms | ×1.59 / +37 % |
| White balance* / CPU | 69 ms | 35 ms | ×0.5 / -97 % |
| White balance* / GPU | 7 ms | 7 ms | ×1 / 0 % |
| Highlights reconstruction* / CPU | 13.10 s | 12.91 s | ×0.99 / -1.5 % |
| Highlights reconstruction* / GPU | 1.42 s | 1.87 s | ×1.32 / +24 % |
| Demosaic* / CPU | 0.99 s | 1.80 s | ×1.82 / +45 % |
| Demosaic* / GPU | 149 ms | 123 ms | ×0.83 / -21 % |
| Exposure / CPU | 13 ms | 3 ms | ×0.23 / -333 % |
| Exposure / GPU | 33 ms | 2 ms | ×0.06 / -1550 % |
| Input color profile / CPU | 2 ms | 33 ms | ×16.5 / +94 % |
| Input color profile / GPU | 11 ms | 4 ms | ×0.36 / -175 % |
| Color calibration / CPU | 47 ms | 50 ms | ×1.06 / 6 % |
| Color calibration / GPU | 2 ms | 4 ms | ×2 / +50 % |
| Diffuse or sharpen / CPU | 1.71 s | 3.37 s | ×1.97 / +49.4 % |
| Diffuse or sharpen / GPU | 158 ms | 518 ms | ×3.28 / +70 % |
| Color balance RGB / CPU | 152 ms | 179 ms | ×1.18 / +15 % |
| Color balance RGB / GPU | 10 ms | 4 ms | ×0.40 / -150 % |
| Filmic RGB / CPU | 93 ms | 114 ms | ×1.23 / +18 % |
| Filmic RGB / GPU | 4 ms | 41 ms | ×10.26 / +90 % |
| Output color profile / CPU | 15 ms | 41 ms | ×2.73 / +63 % |
| Output color profile / GPU | 22 ms | 32 ms | ×1.45 / +31 % |
| Dithering (CPU only) / CPU pipeline | 9 ms | 28 ms | ×3.62 / +72 % |
| Dithering (CPU only) / GPU pipeline | 13 ms | 47 ms | ×2.76 / +64 % |
| Gamma / display encoding (CPU only) / CPU pipeline | 9 ms | 9 ms | ×1.0 / 0 % |
| Gamma / display encoding (CPU only) / GPU pipeline | 8 ms | 15 ms | ×1.88 / +47 % |
*: Module, die auf beiden Anwendungen in voller Auflösung laufen.
Durchschnitt über Konfig 1 und 2. Faktoren werden mit einem geometrischen Mittel und relative Differenzen mit einem harmonischen Mittel gemittelt.
| Modul / Chip | Ansel-Beschleunigung | Ansel-Code |
|---|---|---|
| Raw settings* / CPU | ×0.94 | Eigenentwicklung (manuell vektorisiert) |
| Raw settings* / GPU | ×1.23 | Gleich wie DT 5.4.1 |
| White balance* / CPU | ×0.69 | Eigenentwicklung (manuell vektorisiert) |
| White balance* / GPU | ×0.97 | Gleich wie DT 5.4.1 |
| Highlights reconstruction* / CPU | ×1.1 | Eigenentwicklung (manuell vektorisiert) |
| Highlights reconstruction* / GPU | ×1.4 | Eigenentwicklung |
| Demosaic* / CPU | ×1.94 | Gleich wie DT 4.0 |
| Demosaic* / GPU | ×1.26 | Eigenentwicklung |
| Exposure / CPU | ×0.74 | Eigenentwicklung (manuell vektorisiert) |
| Exposure / GPU | ×0.32 | Gleich wie DT 4.0 |
| Input color profile / CPU | ×7.04 | Eigenentwicklung (manuell vektorisiert) |
| Input color profile / GPU | ×2.41 | Eigenentwicklung |
| Color calibration / CPU | ×1.13 | Eigenentwicklung (manuell vektorisiert) |
| Color calibration / GPU | ×8.83 | Gleich wie DT 4.0 |
| Diffuse or sharpen / CPU | ×1.08 | Eigenentwicklung |
| Diffuse or sharpen / GPU | ×2.26 | Eigenentwicklung |
| Color balance RGB / CPU | ×1.08 | Eigenentwicklung (manuell vektorisiert) |
| Color balance RGB / GPU | ×0.73 | Eigenentwicklung |
| Filmic RGB / CPU | ×1.13 | Eigenentwicklung (manuell vektorisiert) |
| Filmic RGB / GPU | ×4.33 | Eigenentwicklung |
| Output color profile / CPU | ×2.10 | Eigenentwicklung (manuell vektorisiert) |
| Output color profile / GPU | ×1.81 | Eigenentwicklung |
| Dithering (CPU only) / CPU pipeline | ×2.71 | Gleich wie DT 4.0 |
| Dithering (CPU only) / GPU pipeline | ×2.72 | Gleich wie DT 4.0 |
| Gamma / display encoding (CPU only) / CPU pipeline | ×0.87 | Gleich wie DT 5.4.1 |
| Gamma / display encoding (CPU only) / GPU pipeline | ×1.63 | Gleich wie DT 5.4.1 |
*: Module, die auf beiden Anwendungen in voller Auflösung laufen.
Ansel zeigt GPU-Performance-Verbesserungen sogar bei Kerneln, die sich seit Darktable 4.0 nicht geändert haben. Die Beschleunigungen, die wir sehen, sind eindeutig der Vorteil der High-Level-Speicherverwaltung, die dort, wo es relevant ist, OpenCL-Pinned-Memory oder reine Device-only-Speicherpuffer verwendet.
Über alle Module hinweg ist Ansel auf der GPU 1,6-mal schneller als Darktable (geometrisches Mittel).
Auf der CPU sind die Dinge nuancierter.
Darktable 5.x soll CPU-Optimierungen für Dithering und Entrasterung (RCD) erhalten haben, dennoch schneiden beide Module auf beiden Konfigurationen schlechter ab als die von Ansel.
Ansel besitzt manuell vektorisierten CPU-Pixel-Code für Farbbalance RGB, Farbkalibrierung, Eingabe-/Ausgabe-Farbprofil, Raw settings, Weißabgleich, Belichtung und Filmic, während Darktable Compiler-Hinweise nutzt, um Vektorisierung zu erreichen. Sie alle schneiden auf dem Intel Xeon besser ab als die von Darktable. Auf dem Intel i3 schneidet Ansel bei grundlegender Farbmatrix-Arbeit (viel) besser ab, aber es schadet leicht grundlegenden Modulen wie Raw settings, Belichtung oder Weißabgleich.
Diffusion oder Schärfung sollte auf Ansel und auf Darktable 5.4 noch denselben Darktable-4.0-Code verwenden, aber Ansel ist auf beiden Konfigurationen schneller, was den Vorteil der Verwendung unseres eigenen vorab zugewiesenen Speicherarrays für den Cache und der Zuweisung von Speicherpuffern außerhalb der Betriebssystem-Verrohrung zeigt. Dies zeigt, dass das Optimieren auf Modulebene der falsche Fokus ist und dass die globale Pipeline zuerst eine Überarbeitung benötigte.
Aber es ist natürlich leichter, modulweise Optimierungen anzugehen, weil Module… modular sind, das heißt in sich geschlossen und eigenständig. Es besteht wenig Gefahr, die Software als Ganzes zu vermasseln, wenn man an Modulen arbeitet, weil sie vom Rest isoliert sind. Anwendungsglobale Architekturänderungen hingegen sind gefährlich, kompliziert und anspruchsvoll. Und sie erzwingen, die Entwicklung jeglicher neuer Module vollständig zu stoppen, während die Architektur stabilisiert wird. Wozu Darktable niemals die Disziplin haben wird, denn das Projekt ist ungemanagt und zufällige Pull Requests tauchen zu zufälligen Zeiten von zufälligen Mitwirkenden auf Github auf.
Über alle Module hinweg ist Ansel auf der CPU 1,8-mal schneller als Darktable (geometrisches Mittel).
Kombiniert man GPU- und CPU-Pfade über beide Konfigurationen, ist das Öffnen der Dunkelkammer 1,5-mal schneller auf Ansel (geometrisches Mittel).
Zoomen auf 100 %
In der Dunkelkammer aus der Größe „Zoom auf Einpassen" mit einem Klick über die mittlere Maustaste auf 100 % zoomen
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'Da Ansel die frühen Stufen der Pipeline in voller Auflösung verarbeitet, werden sie auch in voller Auflösung gecached, was bedeutet, dass Verschieben und Zoomen den Cache vorgelagert zum Modul Anfängliches Resampling abgreifen und nur nachgelagert neu berechnen. Es dauert also 2,9 s zum Rendern. Darktable hingegen hat einen nicht funktionierenden Cache, sodass es alles von Anfang an neu berechnet und 5,9 s braucht, um dasselbe zu rendern. Es ist eine ×2-Performance-Strafe für Darktable.
Verschieben bei 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'Das Verschieben (Panning) führt zur selben Situation wie das Zoomen: Ansel hat das Bild in voller Auflösung im Cache, sodass wir ab dem initialen Resampling neu berechnen, was 3 s dauert. Darktable kann keinen Cache ordentlich verwalten, sodass Ihnen eine vollständige Neuberechnung und 5,9 s eingefrorener Rechner bevorstehen.
Hin und her wechseln zum Leuchttisch
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'Der Pipeline-Cache von Ansel überlebt die Pipelines selbst, was bedeutet, dass das Verlassen der Dunkelkammer und das erneute Betreten nahezu augenblicklich erfolgt: Es dauert nur 60 ms, um alle Pipelines mit dem Entwicklungsverlauf neu zu synchronisieren und anhand ihrer Prüfsumme festzustellen, dass wir die Pipeline-Ausgabe bereits im Cache haben. Beachten Sie, dass es hier keinerlei Sonderbehandlung gibt, es handelt sich um generisches Cache-Verhalten.
Bei Darktable funktioniert es für das Hauptbild fast, aber nicht für die Vorschau, sodass Ihnen 1 s nutzloser Neuberechnung bevorsteht. Angesichts der Tatsache, dass dies bei der einen Pipe funktioniert, aber nicht bei der anderen, wette ich, dass es über Sonderfälle behandelt wird. Verglichen mit Ansel ist das eine Leistungseinbuße um den Faktor ×1,75.
Ein Modul mitten in der Pipeline deaktivieren
Ich habe diffuse or sharpen in der Zoomstufe „fill" (hineingezoomt) deaktiviert.
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'Auch hier funktioniert der Ansel-Cache einfach: Das Deaktivieren von diffuse or sharpen führt dazu, dass nur die nachgelagerten Module neu berechnet werden, was 172 ms dauert. Auch hier funktioniert der Darktable-Cache nicht, was dazu führt, dass die gesamten 2 Pipelines (Vorschau und Hauptbild) neu berechnet werden, mit Gesamtkosten von 6,9 s. Das ist eine Leistungseinbuße um den Faktor ×40, Leute! Damit werden all die +15 % vorgeblichen Beschleunigungen von Ralf Brown völlig belanglos! Aber hey! Suchen Sie Ihre verlorenen Schlüssel weiter dort, wo Sie Ihre Füße sehen, statt dort, wo Sie sie verloren haben! .
Farbpipette in einem Modul
Wir stellen den Weißabgleich in der Farbkalibrierung mit der Farbpipette ein, bei der Zoomstufe „zoom to fit" (an Fenster anpassen).
1colorpicker stats reading took 0.020 secs (0.088 CPU)
2colorpicker stats reading took 0.018 secs (0.087 CPU)
312.128030 [dev_pixelpipe] pipeline resync with history took 0.024 secs (0.037 CPU) for pipe virtual-preview
412.137829 [dev_pixelpipe] pipeline resync with history took 0.024 secs (0.056 CPU) for pipe preview
512.157665 [dev_pixelpipe] took 0.020 secs (0.048 CPU) processed `color calibration' on GPU, blended on GPU [preview]
613.327326 [dev_pixelpipe] took 1.170 secs (1.231 CPU) processed `diffuse or sharpen' on GPU, blended on GPU [preview]
713.336618 [dev_pixelpipe] took 0.009 secs (0.008 CPU) processed `color balance rgb' on GPU, recycled cacheline, blended on GPU [preview]
813.345393 [dev_pixelpipe] took 0.009 secs (0.007 CPU) processed `filmic rgb' on GPU, recycled cacheline, blended on GPU [preview]
913.368053 [dev_pixelpipe] took 0.023 secs (0.030 CPU) processed `output color profile' on GPU, blended on [preview]
1013.418643 [dev_pixelpipe] took 0.050 secs (0.061 CPU) processed `dithering' on CPU, blended on [preview]
1113.435846 [dev_pixelpipe] took 0.017 secs (0.024 CPU) processed `display encoding' on GPU, blended on [preview]
1213.435919 [pixelpipe] preview internal pixel pipeline processing took 1.298 secs (1.408 CPU)
1313.435949 [dev_process_preview] pipeline processing thread took 1.298 secs (1.408 CPU)
1413.526316 [dev_pixelpipe] pipeline resync with history took 0.080 secs (0.376 CPU) for pipe full
1513.526443 [dev_process_full] pipeline processing thread took 0.000 secs (0.000 CPU)
16colorpicker stats reading took 0.185 secs (0.741 CPU)
17image colorspace transform RGB-->RGB took 0.000 secs (0.000 CPU) [[histogram] sample swatch]
18image colorspace transform RGB-->RGB took 0.000 secs (0.000 CPU) [[histogram] sample swatch]
19image colorspace transform RGB-->RGB took 0.000 secs (0.000 CPU) [[histogram] sample swatch] 116,1190 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
216,1364 dt_color_picker_helper stats reading 4 channels (filters 2492765332) cst 2 -> 2 size 1118880 denoised 0 took 0,001 secs (0,005 CPU)
316,1396 [dev_pixelpipe] took 0,020 secs (0,025 CPU) [preview] processed `channelmixerrgb' on GPU, blended on GPU
416,2071 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
516,6064 [dev_pixelpipe] took 0,467 secs (0,567 CPU) [preview] processed `diffuse' on GPU, blended on GPU
616,6106 [dev_pixelpipe] took 0,004 secs (0,004 CPU) [preview] processed `colorbalancergb' on GPU, blended on GPU
716,6160 [dev_pixelpipe] took 0,005 secs (0,001 CPU) [preview] processed `filmicrgb' on GPU, blended on GPU
816,6192 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,003 secs (0,002 GPU) [colorout]
916,6364 [dev_pixelpipe] took 0,020 secs (0,010 CPU) [preview] processed `colorout' on GPU, blended on GPU
1016,6513 [dev_pixelpipe] took 0,015 secs (0,005 CPU) [preview] processed `dither' on CPU, blended on CPU
1116,6572 [dev_pixelpipe] took 0,006 secs (0,023 CPU) [preview] processed `gamma' on CPU, blended on CPU
1216,6584 dt_color_picker_helper stats reading 4 channels (filters 2492765332) cst 2 -> 2 size 1118880 denoised 0 took 0,001 secs (0,005 CPU)
1316,6586 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0,000 secs (0,000 CPU) [gamma]
1416,6587 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,000 secs (0,000 CPU) [primary picker]
1516,6754 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,017 secs (0,063 CPU) [final histogram]
1616,6843 [histogram] took 0,026 secs (0,093 CPU) final waveform
1716,6847 [dev_process_image] pixel pipeline took 0,566 secs (0,733 CPU) processing `2022-06-17__DSC00078.arw'
18
1916,6854 [dt_dev_process_image_job] loading image. took 0,000 secs (0,000 CPU)
2020,3395 [dev_pixelpipe] took 3,606 secs (3,778 CPU) [full] processed `highlights' on GPU with tiling, blended on CPU
2120,7350 [resample_cl] plan 0,001 secs (0,000 CPU) resample 0,010 secs (0,001 CPU)
2220,8263 [dev_pixelpipe] took 0,487 secs (0,285 CPU) [full] processed `demosaic' on GPU, blended on GPU
2320,8389 [dev_pixelpipe] took 0,012 secs (0,002 CPU) [full] processed `lens' on GPU, blended on GPU
2420,8505 [dev_pixelpipe] took 0,012 secs (0,002 CPU) [full] processed `exposure' on GPU, blended on GPU
2520,8812 [dev_pixelpipe] took 0,031 secs (0,008 CPU) [full] processed `colorin' on GPU, blended on GPU
2620,8972 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_LAB-->IOP_CS_RGB took 0,016 secs (0,004 GPU) [channelmixerrgb]
2720,9551 [dev_pixelpipe] took 0,074 secs (0,023 CPU) [full] processed `channelmixerrgb' on GPU, blended on GPU
2821,8137 [dev_pixelpipe] took 0,000 secs (0,000 CPU) initing base buffer [preview]
2921,8160 [dev_pixelpipe] took 0,001 secs (0,005 CPU) [preview] processed `rawprepare' on CPU, blended on CPU
3021,8173 [dev_pixelpipe] took 0,001 secs (0,001 CPU) [preview] processed `temperature' on CPU, blended on CPU
3121,9879 [dev_pixelpipe] took 0,171 secs (0,758 CPU) [preview] processed `highlights' on CPU, blended on CPU
3222,0020 [dev_pixelpipe] took 0,014 secs (0,080 CPU) [preview] processed `demosaic' on CPU, blended on CPU
3322,0103 [dev_pixelpipe] took 0,008 secs (0,016 CPU) [preview] processed `lens' on CPU, blended on CPU
3422,0127 [dev_pixelpipe] took 0,002 secs (0,014 CPU) [preview] processed `exposure' on CPU, blended on CPU
3522,0155 [dev_pixelpipe] took 0,003 secs (0,015 CPU) [preview] processed `colorin' on CPU, blended on CPU
3622,0172 [dt_ioppr_transform_image_colorspace] IOP_CS_LAB-->IOP_CS_RGB took 0,002 secs (0,009 CPU) [channelmixerrgb]
3722,0457 dt_color_picker_helper stats reading 4 channels (filters 2492765332) cst 2 -> 2 size 1118880 denoised 0 took 0,002 secs (0,013 CPU)
3822,0458 [dev_pixelpipe] took 0,030 secs (0,180 CPU) [preview] processed `channelmixerrgb' on CPU, blended on CPU
3922,6461 [dev_pixelpipe] took 1,691 secs (5,549 CPU) [full] processed `diffuse' on GPU, blended on GPU
4022,6595 [dev_pixelpipe] took 0,013 secs (0,079 CPU) [full] processed `colorbalancergb' on GPU, blended on GPU
4122,6725 [dev_pixelpipe] took 0,013 secs (0,073 CPU) [full] processed `filmicrgb' on GPU, blended on GPU
4222,6824 [dt_ioppr_transform_image_colorspace_cl] IOP_CS_RGB-->IOP_CS_LAB took 0,007 secs (0,041 GPU) [colorout]
4322,7443 [dev_pixelpipe] took 0,072 secs (0,398 CPU) [full] processed `colorout' on GPU, blended on GPU
4422,8624 [dev_pixelpipe] took 0,118 secs (0,664 CPU) [full] processed `dither' on CPU, blended on CPU
4522,8878 [dev_pixelpipe] took 0,025 secs (0,172 CPU) [full] processed `gamma' on CPU, blended on CPU
4622,8894 [dev_process_image] pixel pipeline took 6,637 secs (11,596 CPU) processing `2022-06-17__DSC00078.arw'
4723,4204 [dev_pixelpipe] took 1,374 secs (8,556 CPU) [preview] processed `diffuse' on CPU, blended on CPU
4823,5271 [dev_pixelpipe] took 0,106 secs (0,617 CPU) [preview] processed `colorbalancergb' on CPU, blended on CPU
4923,5788 [dev_pixelpipe] took 0,051 secs (0,291 CPU) [preview] processed `filmicrgb' on CPU, blended on CPU
5023,5817 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0,003 secs (0,011 CPU) [colorout]
5123,5870 [dev_pixelpipe] took 0,008 secs (0,037 CPU) [preview] processed `colorout' on CPU, blended on CPU
5223,5913 [dev_pixelpipe] took 0,004 secs (0,004 CPU) [preview] processed `dither' on CPU, blended on CPU
5323,5964 [dev_pixelpipe] took 0,005 secs (0,021 CPU) [preview] processed `gamma' on CPU, blended on CPU
5423,5973 dt_color_picker_helper stats reading 4 channels (filters 2492765332) cst 2 -> 2 size 1118880 denoised 0 took 0,001 secs (0,006 CPU)
5523,5976 [dt_ioppr_transform_image_colorspace] IOP_CS_RGB-->IOP_CS_LAB took 0,000 secs (0,000 CPU) [gamma]
5623,5977 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,000 secs (0,000 CPU) [primary picker]
5723,6099 [dt_ioppr_transform_image_colorspace_rgb] `Système' -> `sRVB' took 0,012 secs (0,067 CPU) [final histogram]
5823,6215 [histogram] took 0,024 secs (0,097 CPU) final waveform
5923,6219 [dev_process_image] pixel pipeline took 6,889 secs (15,651 CPU) processing `2022-06-17__DSC00078.arw'Ansel muss kein neues Pipeline-Rendering starten, um die Farbpipette abzutasten, da Eingang und Ausgang des Moduls noch im Cache sind, sodass das Abtasten insgesamt 40 ms dauert. Anschließend werden die neuen Parameter dem Modul übergeben, wodurch sich der Verlauf ändert und eine Neuberechnung des Moduls color calibration sowie aller nachgelagerten Module ausgelöst wird. Insgesamt aufgewendete Zeit: 1,4 s.
Darktable muss ein neues Pipeline-Rendering starten, um die Farbpipette abzutasten, weil warum auch nicht? Das dauert 0,6 s. Es wird Sie freuen zu erfahren, dass Darktable die Farbe auf der GPU abtastet, was nur 1 ms dauert (inmitten dieser 0,6 s Pipeline-Laufzeit), während Ansel auf der CPU in 20 ms abtastet. Anschließend werden die Farbpipetten-Parameter dem Verlauf übergeben, was eine vollständige Neuberechnung der 2 Pipelines neu startet. Insgesamt aufgewendete Zeit: 7,5 s.
Das ist eine Einbuße um den Faktor ×5,4 für Darktable, und das alles, weil sie nicht ihre Pipelines verbessern, sondern jeder erdenklichen sinnlosen Verfolgungsjagd nachgehen.
Export in voller Auflösung
Wir exportieren, nachdem wir das Bild in der Dunkelkammer geöffnet haben. Das ist wichtig. In Darktable wird das Abtasten in „hoher Qualität" verwendet, in Ansel ist es der einzige Modus.
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'Da wir in Ansel das Bild zuvor in der Dunkelkammer geöffnet haben, befinden sich die frühen Stufen der Pipeline noch im Cache, sodass der Export ab dem Modul exposure beginnt und 39,5 s dauert. In Darktable, nun ja … wie üblich: Es ist eine vollständige Neuberechnung der Pipeline, die 50 s dauert.
Erneuter Export in halber Auflösung
Wir exportieren in halber Auflösung direkt nach dem Export in voller Auflösung.
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'Da Ansel bis zum Modul Final resampling immer in voller Auflösung exportiert (der in Darktable „hohe Qualität" genannte Modus), bleibt die Pipeline größtenteils gleich, unabhängig von der endgültigen Größe. Da der Cache von Ansel funktioniert, befindet sich das zuvor exportierte Bild in voller Auflösung noch im Cache, sodass wir nur die letzten Stufen neu berechnen: output color profile, downsampling, dithering. Das dauert 0,5 s.
Darktable verwaltet wie üblich nicht das, was es zuvor berechnet hat, sodass Ihnen ein weiterer vollständiger Export von ~50 s bevorsteht. Also eine Leistungseinbuße um den Faktor ×100.
Beachten Sie, dass der Pipeline-Cache von Ansel über eine Garbage Collection verfügt, die alle unbenutzten Cache-Zeilen leert, die älter als 5 Minuten sind, sodass dies nicht funktionieren würde, wenn Sie zu lange warten.
Schlussfolgerung
Es ist zum Brüllen, in Tech-Bro-Foren wie discuss.pixls.us zu lesen, dass die Leute Darktable mehr vertrauen als Ansel, weil Ersteres viel mehr Affen hat, die mit den Armen in der Luft herumwedeln und so tun, als würden sie arbeiten, was offenbar genügt, um ein völlig falsches Gefühl von Zuverlässigkeit und Vertrauen zu vermitteln. Es ist schlicht der ultimative Beweis dafür, dass die Leute keine Ahnung haben, was im Code vor sich geht. Aber es ist eine kapitalistische Krankheit, Betriebsamkeit mit Arbeit zu verwechseln, und Arbeit, die keinen Wert schafft, lässt sich mit dem richtigen Marketing dennoch als Fortschritt verkaufen.
Ich mache keine Meinungen, ich mache Benchmarks. Die Zahlen, die ich hier veröffentlicht habe, lassen sich vollständig reproduzieren:
- einzelne Module sind auf der CPU im Schnitt 1,4-mal schneller auf Ansel als auf Darktable CPU,
- einzelne Module sind auf der GPU im Schnitt 1,6-mal schneller auf Ansel als auf Darktable GPU,
- vollständige Pipelines sind 1,5-mal bis 100-mal schneller auf Ansel als auf Darktable GPU, weil Ansel einen funktionierenden Cache hat,
- Ansel ist nicht nur schneller, sondern auch energieeffizienter, weil weniger Dinge (neu) berechnet werden.
All dies wurde erreicht, indem GUI-Code aus dem Pipeline-Rendering-Code entfernt wurde, indem der Datenlebenszyklus klarer, einfacher und robuster gemacht wurde, nicht indem mehr Sonderfallbehandlung und Workarounds hinzugefügt wurden. Ansel kann viel mehr RAM nutzen als Darktable und führt gleichzeitig die notwendige Buchführung, um zu wissen, wie viel es tatsächlich nutzt und ob es mit dem Recycling von Speicher beginnen sollte.
All dies ist der Beweis dafür, dass das Darktable-„Team" die Software nicht besser macht, dass sein (fehlendes) Management der Software aktiv schadet. Seit 2022 wurden in den Versionshinweisen viele „Optimierungen" angekündigt. Und dennoch ist ihre Software immer noch ein quälend langsames Ungetüm der Ineffizienz.
Beachten Sie, dass die modulweisen Optimierungen, die in Darktable vorgenommen wurden, nach Ansel zurückportiert werden können, auch wenn nicht alle davon nach dem, was hier gezeigt wird, wie tatsächliche Beschleunigungen aussehen. Einige wurden es bereits. Aber Darktable kann Ansels Pipeline-Architektur nicht zurückportieren, und von dort stammen die meisten unserer Beschleunigungen.
Während dieser Arbeit habe ich auch den Glauben an Vkdt verloren. Vkdt ist ein erneuter Versuch des Darktable-Gründers Johannes Hannika, eine RAW-Fotosoftware von Grund auf neu zu starten, die vollständig auf der GPU über Vulkan läuft. Aber aus 4 Jahren des Aufräumens der Scheiße anderer Leute habe ich ein paar Dinge gelernt:
- Die Verlangsamungen von Darktable sind nicht dem GTK-Stack oder dem OpenCL-Stack anzulasten. Zugegeben, die sind nicht großartig, aber das lässt sich handhaben. Es sind Programmierfehler und schlechtes Design, das nicht neu bewertet wurde, als sich die Bedürfnisse und Anforderungen der Software änderten.
- Ein Cache-zuerst-Design erlaubt es, viele Latenzen zu verbergen, indem Neuberechnungen vermieden werden, und ein reiner GPU-Workflow wird bald an die Speichergrenzen von GPUs stoßen.
- GPUs werden nach dem Ansturm der Kryptowährungen und nun dem Ansturm der KI zunehmend teurer.
- Was Darktable getötet hat, war ein Mangel an Management und ein Mangel an Vision, eine Kultur des „Laissez-faire" und der fröhlichen Beliebigkeit, die nur mit einer Handvoll Entwickler funktioniert, die sich alle kennen. Vkdt steuert in dieselbe Richtung. Wenn Code und Funktionen ohne Prioritäten und API-Straffung wachsen dürfen, ist es ein Zugunglück in Zeitlupe. „neuer = besser" ist nur ein vorübergehender Zustand. Die eigentliche Herausforderung besteht darin, das Wachstum zu managen.
Aus Entwicklersicht hat Darktable 3 Hauptkrankheiten:
- Seinen Entwicklern fehlen (und das seit langem) völlig die Abstraktionsfähigkeiten, um kognitiv zu trennen, was zur GUI-Schicht gehört und was zur Backend-Schicht. Daher finden Sie GUI/GTK-Zustände tief in Backend-Schichten eingekrustet, was umso ärgerlicher ist, als
darktable-cliheadless läuft und erzwingt, dass beide Modi verwaltet werden. Aber Sie finden auch wiederholt GUI-Probleme in der Backend-Schicht gelöst und umgekehrt. Diese lösen echte Zuverlässigkeitsprobleme aus, obendrein machen sie das Ganze kompliziert, unleserlich und verwoben. - Seine Entwickler verstehen das Konzept privater APIs und Kapselung nicht: Alle Datenstrukturen sind öffentlich, alle Header-Dateien werden in der gesamten Software importiert, sodass die gesamte Software von der gesamten Software weiß und Datenstrukturen von überall im Code an Ort und Stelle verändern darf.
- Komplexität wird durch mehr Komplexität „gelöst", und niemand scheint das als Problem namens technische Schuld zu erkennen.
Vernünftige Codebasen schützen Daten, indem sie sie privat machen und Interaktionen durch Getter-/Setter-Funktionen erzwingen, die als öffentliche APIs definiert sind. Dies ermöglicht eine einfache Verwaltung der Thread-Sicherheit, wenn es so weit ist, erlaubt uns aber auch, von einer zentralen Stelle aus nachzuverfolgen, was wo und wann schreibt. Und dann bindet man den minimalen Satz an APIs in jede Datei ein, um Code so weit wie möglich zu isolieren.
Stattdessen schreibt der Darktable-Quellcode von überall nach überall, ohne ordentliche Schnittstellen. Daher löst jede Art von Änderung in der Darktable-Codebasis systematisch Randeffekte aus und zerbricht etwas Unerwartetes am anderen Ende der Software, in deprimierenden Sitzungen des Whack-a-Mole, geboren aus Faulheit und Dummheit.
Also wurde in Ansel viel mühsame Arbeit geleistet, um APIs zu straffen, so viele Datenstrukturen wie möglich zu privatisieren und Bibliotheken voneinander zu isolieren, um den Abhängigkeitsgraphen etwas zu entwirren.
Anhang: die Pläne
Gesamtarchitektur
Hier ist das übergeordnete Flussdiagramm der gesamten Architektur, von der Datenbank bis zu den Backbuffern. Nun können wir endlich ein Flussdiagramm dieses Chaos zeichnen.
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
RAM-/vRAM-Speicherverwaltung
Verwaltung der Cache-Puffer:
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
Wenn die Modulausgabe zum Caching vorgesehen ist (wegen einer Benutzereinstellung, weil dieser Puffer für Histogramm/Farbpipette benötigt wird, oder weil das nächste Modul das in der GUI aktive ist), verwendet OpenCL einen gepinnten Speicherpuffer (gepinnt auf dem RAM-Cache). Wir pinnen auch Eingabe-Speicherpuffer, wenn die GPU ihre Eingabe aus dem RAM-Cache bezieht. Das ist etwas teurer als die Verwendung eines reinen Device-only-Puffers, aber weniger teuer als das Kopieren dieses Device-only-Puffers auf den Host. Wenn die OpenCL-Ausgabe nicht zum Caching vorgesehen ist, verwenden wir einen Device-only-Puffer, der später recycelt werden kann, aber niemals in den RAM kopiert wird.
Im Falle eines OpenCL-Fehlers bei einem bestimmten Modul (der offensichtlichste: Speichermangel) wird der GPU-Eingabepuffer transparent zurück in den RAM-Cache kopiert, bevor auf den reinen CPU-Pfad zurückgegriffen wird.
All diese Puffer werden von Cache-Einträgen nachverfolgt, die einen RAM-Puffer mit einem vRAM-Puffer verbinden (wenn wir in einer gepinnten Situation beide verwenden) oder einfach nachverfolgen, was allokiert ist. Wenn eine GPU-Speicherallokation fehlschlägt, durchsuchen wir zuerst den Cache, um alle zuvor allokierten Puffer freizugeben. Wenn die GPU-Speicherallokation danach erneut fehlschlägt, greifen wir auf die CPU zurück.
Cache-Einträge
Der Cache ist eine Hashtabelle aus Cache-Einträgen. Ihr Schlüssel ist ein Hash/eine Prüfsumme. Wir haben 2 Arten von Cache-Einträgen:
- interne, verwendet als wiederverwendbare Puffer für Modul-Eingaben/-Ausgaben,
- externe, verwendet als verwerfbare Puffer für Zwischenberechnungen der Module.
Interne Cache-Einträge werden über den global_hash ihres übergeordneten Moduls verschlüsselt und können später wiedergefunden werden (sogar von der GUI aus), weil dieser Hash über Läufe und Pipelines hinweg stabil ist. Sie können neu verschlüsselt werden, wenn wir ihren Speicherpuffer wiederverwenden, sodass der neue Schlüssel dem neuen Zustand ihres übergeordneten Moduls entspricht. Diese Cache-Einträge können im Lese- oder Schreibmodus gesperrt werden, um einen sicheren nebenläufigen Zugriff zwischen parallelen Threads zu gewährleisten. Eine Schreibsperre kann nur von einem einzigen Thread erlangt werden, wenn kein anderer Thread liest; eine Lesesperre kann von mehreren Threads erlangt werden, wenn kein anderer Thread schreibt. Da die Schreibsperre von dem Modul, das seine Ausgabe schreibt, früher freigegeben wird, als die Lesesperre von dem Modul erlangt wird, das denselben Cache-Eintrag als seine Eingabe verwendet, und dazwischen die Gefahr einer Löschung besteht, verfügen sie außerdem über einen refcount-Mechanismus: Der Produzent des Cache-Eintrags erhöht ihn, der Konsument verringert ihn. Derselbe Mechanismus wird von der Dunkelkammer verwendet, um den Backbuffer ohne Kopie abzurufen.
Externe Cache-Einträge werden über die Speicheradresse ihres Datenpuffers verschlüsselt. Sie sind für eine kurze Lebensdauer vorgesehen.
Das Hinzufügen/Entfernen von Cache-Einträgen erhöht/verringert automatisch die globale Cache-Größe. Wir fügen so lange neue Einträge hinzu, wie die globale Cache-Größe unter dem erlaubten Schwellenwert liegt; danach beginnen wir, die ältesten Einträge zu zerstören, wenn ihr refcount 0 ist und sie nicht gesperrt sind.
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
Ein Cache-Eintrag kennt die Art der Daten nicht, die er enthält. Er kennt nur die Adressen der Puffer, ihre Größe, ihren refcount und ihren Sperrzustand. Er ist also eine generische Abstraktion von Zeug, das im Speicher enthalten ist.
Translated from English by : ChatGPT, Claude. In case of conflict, inconsistency or error, the English version shall prevail.