6 Punkte von GN⁺ 2025-07-21 | 3 Kommentare | Auf WhatsApp teilen
  • Das FFmpeg-Entwicklerteam meldet dank handgeschriebenem Assemblercode Leistungssteigerungen von bis zu 100x
  • Dieser Patch beschleunigt nicht das gesamte Programm, sondern nur bestimmte Funktionen
  • Mit AVX512-Unterstützung auf aktuellen CPUs wurden bis zu 100x, mit AVX2 64 % mehr Leistung gemessen
  • Die verbesserte Funktionalität betrifft vor allem weniger bekannte Filter
  • Die automatische Optimierung durch Compiler zeigt weiterhin einen deutlichen Leistungsabstand zu handgeschriebenem Assemblercode

Leistungssteigerung bei FFmpeg: Was 100-fach schneller tatsächlich bedeutet

Neuester Patch und wichtigste Verbesserungen

  • Die Entwickler des FFmpeg-Projekts betonen, dass durch den Einsatz von eigens geschriebenem Assemblercode bei dem Open-Source- und plattformübergreifenden Medien-Transcoding-Tool eine "100-fache Beschleunigung" erreicht wurde
  • Gleichzeitig stellen sie klar, dass sich diese Aussage nicht auf ganz FFmpeg, sondern nur auf eine einzelne Funktion bezieht
  • Die außergewöhnliche Optimierung wurde in der Funktion rangedetect8_avx512 umgesetzt; auf aktuellen Prozessoren mit AVX512-Unterstützung sind bis zu 100x möglich, auf dem AVX2-Pfad wurde eine Leistungssteigerung von rund 64 % erreicht
  • Die Änderung betrifft einen wenig bekannten Filter, der bislang keine hohe Entwicklungspriorität hatte; nun wurde dort mittels SIMD (Single Instruction, Multiple Data) eine Optimierung der Parallelverarbeitung umgesetzt

Erläuterungen des Entwicklerteams und technischer Hintergrund

  • Das FFmpeg-Entwicklerteam stellte über Twitter klar: "Diese eine Funktion ist 100-mal schneller geworden, nicht FFmpeg insgesamt"
  • In zusätzlichen Erläuterungen hieß es, dass je nach System auch Leistungssteigerungen von bis zu 100 % möglich seien
  • Grundlage der Verbesserung ist SIMD-Technologie, die die Effizienz paralleler Verarbeitung auf modernen Chips deutlich erhöht

Die Bedeutung von handgeschriebenem Assembler

Frühere und heutige Ansätze zur Optimierung

  • In den 1980er- und 1990er-Jahren war handgeschriebener Assemblercode unter den damaligen Hardware-Beschränkungen ein zentrales Mittel, um Spiele und andere Software zu beschleunigen
  • Heute wandeln die meisten modernen Compiler Code aus höheren Programmiersprachen in Assembler um, doch Grenzen bei Compiler-Optimierungen wie der Registerzuweisung führen weiterhin dazu, dass handgeschriebener Assemblercode in manchen Fällen mehr Leistung bietet
  • FFmpeg gehört zu den wenigen Projekten, die an dieser Optimierungsphilosophie festhalten, und bietet sogar eigene Assembler-Tutorials an

FFmpegs Einfluss im Ökosystem

  • Die Bibliotheken und Tools von FFmpeg laufen in unterschiedlichsten Umgebungen, darunter Linux, Mac OS X, Microsoft Windows, BSD und Solaris
  • Auch populäre Videoplayer wie VLC nutzen FFmpegs Bibliotheken libavcodec und libavformat
  • Das unterstreicht die große technische Bedeutung von FFmpeg im breiten Open-Source-Ökosystem für Medien-Encoding und -Decoding

Fazit

  • Die aktuelle Leistungssteigerung ist nicht auf die gesamte Kernfunktionalität beschränkt, sondern auf einzelne Funktionen, zeigt aber anschaulich, wie sich Leistungsgrenzen weiter verschieben lassen
  • Auf moderne Hardware zugeschnittene Optimierungen und der Open-Source-Gedanke machen FFmpeg weiterhin zu einem technischen Vorbild im Bereich Medienverarbeitung

3 Kommentare

 
bobcat 2025-07-24

Das gilt sowohl früher als auch heute.
Ähnlich habe ich beim Portieren einer Codec-Bibliothek auf ARM damit begonnen, die in SSE geschriebenen Kernel Stück für Stück aufzudröseln, und als nach dem vollständigen Auflösen nur noch Skalar-Code übrig war und ich einen Real-World-Benchmark laufen ließ, war der Leistungsunterschied signifikant.

 
aer0700 2025-07-23

Ein Ingenieur, der stärker optimierten Code schreiben kann als GCC ... wirklich beeindruckend.

 
GN⁺ 2025-07-21
Hacker-News-Kommentare
  • Ich habe 10 Jahre lang SIMD-Optimierungen für HEVC und Ähnliches gemacht, und der Vergleich zwischen Assembly-Versionen und normalem C war fast schon ein Witz, weil dabei riesige Zahlen wie der Faktor 100 herauskamen. Tatsächlich bedeuten solche Ergebnisse, dass die Ausgangsversion anfangs extrem ineffizient war. In der Praxis wird eine Funktion nicht wie in einem Mikrobenchmark millionenfach mit bereits vollem Cache immer wieder in derselben Umgebung aufgerufen. Stattdessen kann sie in realen Szenarien auch nur einmal innerhalb vieler anderer Aufgaben aufgerufen werden. Um Cache-Effekte zu verringern, müsste man einen sehr großen Test-Speicherbereich anlegen und damit testen; ob das tatsächlich gemacht wird, ist fraglich.

    • Ich frage mich, ob Videokonvertierungssoftware wie FFmpeg zusätzlich auch „Makro-Benchmarks“ durchführt. Ich würde erwarten, dass über längere Zeit Leistung, Qualität und CPU-Auslastung für verschiedene Videos und Konvertierungskombinationen gemessen werden. Dafür bräuchte man wohl dedizierte, konsistente Hardware.

    • Das ist kurz eine etwas andere Frage, aber du scheinst viel Erfahrung mit SIMD zu haben, deshalb wollte ich fragen, ob du ISPC benutzt hast und wie du es einschätzt. Es wirkt heutzutage immer noch etwas absurd, dass man SIMD-Code oft noch von Hand schreiben muss und normale Compiler bei der Auto-Vektorisierung schwach sind. Das steht im Kontrast zu GPU-Kernels, bei denen es gefühlt schon immer automatische Vektorisierung gab.

    • Ich würde sagen, dass ffmpeg selbst sich gar nicht so sehr von einem Mikrobenchmark unterscheidet. Im Kern ist es im Wesentlichen eine Struktur wie while (read(buf)) write(transform(buf)).

    • Leider gab es neben Cache-Problemen auch Fälle, in denen Entwickler von 100 % Geschwindigkeitsgewinn sprachen, obwohl das in Wirklichkeit nur für einen sehr begrenzten Filter galt. Trotzdem wird die Information meist recht transparent vermittelt.

    • Zur Deutung „am Anfang ineffizient“: Für mich ist entscheidend, welche Zahlen tatsächlich herauskommen; das Ergebnis selbst ist wichtig.

  • Im Artikel steht teils etwas von 100x, an anderer Stelle aber von 100 % Geschwindigkeitssteigerung, was verwirrend ist. Zum Beispiel heißt es, die Leistung von rangedetect8_avx512 sei um 100,73 % gestiegen, während der Screenshot 100,73x zeigt. 100x wären 9900 % Zuwachs, 100 % Geschwindigkeitssteigerung wären doppelt so schnell. Ich frage mich, was davon nun stimmt.

    • Wie im Screenshot zu sehen, sind es eindeutig 100x (bzw. 100,73x); das entspricht 9973 % Geschwindigkeitssteigerung. Im Artikeltext wurde das Prozentzeichen offenbar falsch verwendet.

    • Bezogen auf die einzelne Funktion sind es 100x, bezogen auf den gesamten Filter 100 % (also 2x).

    • Die Behauptung aus dem ffmpeg-Umfeld lautet 100x. Die 100 % im Artikel wirken wie ein Tippfehler.

    • Der Funktionsname hat mit „8“ zu tun, und wenn auf 8-Bit-Werten gearbeitet wird, dann kann eine frühere skalare Implementierung mit AVX512 theoretisch 128 Elemente auf einmal verarbeiten, sodass ich 100x Geschwindigkeitssteigerung für möglich halte.

  • Ich lasse hier noch die offizielle ffmpeg-Anleitung zum Schreiben von Assembly als Referenz da: https://news.ycombinator.com/item?id=43140614

  • Im Artikel bleibt für mich unklar, in welchen Situationen rangedetect8_avx512 tatsächlich verwendet wird und wie groß die tatsächliche Echtzeit-Leistungssteigerung im gesamten Konvertierungsprozess ist. Ich frage mich, ob das wirklich eine spürbare praktische Bedeutung hat.

    • Früher, als Videosignale analog waren, wurden Steuersignale im Band codiert und so verarbeitet. Auch nach der DVD-Zeit wurden digitale Signale analog ausgegeben, weshalb Werte unterhalb von Farbe 16 (im Bereich 0–255) als „schwärzer als Schwarz“ verwendet wurden; bei BluRay und HDMI war das ähnlich. In letzter Zeit geht der Trend dahin, den gesamten Bereich 0–255 zu nutzen. Dennoch wird die Signalbereichsunterscheidung oft noch nicht korrekt behandelt, wodurch Videos zu dunkel und damit beschädigt wirken. Diese Funktion scheint dazu da zu sein festzustellen, ob Pixelwerte im Bereich 16–255 oder 0–255 liegen. Wenn sicher ist, dass es 16–255 sind, kann man beim Encodieren Informationen sparen. Das ist allerdings Spekulation. Ich arbeite beruflich ebenfalls mit Video, und es ist mir fast peinlich, dass ich die Behandlung des Schwarzpegels immer noch nicht zuverlässig hinbekomme.

    • Dieser Filter wird im Konvertierungsprozess nicht direkt verwendet, sondern dazu, Informationen für Metadaten zu bestimmen, etwa den Farbbereich oder ob Alpha premultiplied ist. Die betreffende Funktion gehört dabei zur Ermittlung des Farbbereichs.

  • Ich möchte eine interessante Erfahrung erwähnen. Der einzige Grund, warum ich selbst einmal Assembly geschrieben habe, war ebenfalls SIMD. Vor Kurzem habe ich wieder darüber gesprochen und dabei fast vergessen, dass ich damals überhaupt Assembly verwenden musste. Tatsächlich lag es an einem Aliasing-Problem im Compiler, weshalb nicht so optimiert wurde, wie ich es wollte. Nachdem ich klar gemacht hatte, dass auf die Daten nicht auf andere Weise zugegriffen wird, und ein nicht standardisiertes Keyword verwendet hatte, nutzte der Compiler automatisch SIMD-Instruktionen. Am Ende habe ich die handgeschriebene Assembly wieder entfernt.

  • Es ist schon etwas ironisch, dass diese Optimierung nur für x86/x86-64 (AVX2, AVX512) gilt. Eine Zeit lang nutzten alle x86, sodass SIMD-Optimierungen breit einsetzbar waren, aber die neueren Erweiterungsarchitekturen waren entweder wirklich nicht gut oder es fehlte an Kompatibilität. Und jetzt, wo x86-SIMD endlich besser geworden ist, ist x86 nicht mehr der Standard, sodass man sich nur schwer darauf verlassen kann.

    • AVX512 besteht aus mehreren Erweiterungssätzen, und sobald man nicht nur die Basis-Instruktionen verwendet, kann der unterstützte Umfang je nach CPU unterschiedlich sein. Moderne Encoder haben bei Multithreading zwar Fortschritte gemacht, stoßen aber auch an Grenzen. Ich hatte früher in einem Embedded-Projekt wegen Kompatibilitätsproblemen mit dem Video-Encoder eines SoC zu kämpfen, habe dann ffmpeg ausprobiert und mit mehreren CPU-Kernen bessere Ergebnisse erzielt.
  • Ehrlich gesagt hat es mich überrascht, dass Assembly schneller als optimiertes C sein kann. Moderne Compiler sind inzwischen so gut, dass ich dachte, handgeschriebene Assembly würde höchstens noch minimale Vorteile bringen. Offenbar lag ich damit klar falsch. Ich habe beschlossen, irgendwann doch ernsthaft Assembly zu lernen.

    • Wenn man sich die zugehörigen Patches ansieht, ist die bisherige Baseline (ff_detect_range_c) sehr allgemeiner skalarer C-Code, und der Geschwindigkeitsgewinn kommt aus der AVX-512-Version derselben Operation (ff_detect_rangeb_avx512). Die FFmpeg-Entwickler schreiben Assembly gern direkt mit Makros, die unabhängig von der Vektorbreite sind, aber mit Intel-Intrinsics ließe sich das fast identisch ausdrücken. Praktisch macht das kaum einen Unterschied, abgesehen etwa von der Registerallokation. Entscheidend für den Geschwindigkeitsunterschied ist, wie gut vektorisiert wird. Mit modernen Compilern ist die Vektorisierung nichttrivialer Schleifen fast unmöglich, und selbst dann wird es nur mit Optionen wie gcc -O3 überhaupt versucht. Deshalb ergeben sich bei so kleinen Einheiten wie 8 Bit mit direkter Vektorisierung per AVX/AVX2/AVX-512 leicht Unterschiede um mindestens einige Dutzend Faktoren. Auf modernen CPUs kann man in seltenen Fällen sogar extrem optimierten skalaren Code schreiben, der schneller ist als das, was der Compiler erzeugt, aber das ist sehr selten und erfordert viel Sorgfalt, etwa bei Abhängigkeitsketten und der Last auf Execution Ports. Ich selbst habe tatsächlich schon einmal 40 % Geschwindigkeitsgewinn erlebt. Relevante Links: baseline C, AVX512-Version

    • Wenn man näher an Low-Level-Optimierung herangeht, erlebt man innerhalb kürzester Zeit Fälle, in denen C-Compiler plötzlich merkwürdige Dinge tun. Wenn es sich um Code handelt, der extrem häufig aufgerufen wird, dann sind Optimierungsprobleme in der Praxis tatsächlich sehr wichtig. Beispiel: https://stackoverflow.com/questions/71343461/how-does-gcc-not-clang-make-this-optimization-deciding-that-a-store-to-one-str

    • Schon der Schritt hinunter zu SIMD-Intrinsics reicht, um deutlich leichter als mit dem Compiler Leistung herauszuholen. Ich habe dazu einmal eine mehrteilige Anleitung geschrieben: https://scallywag.software/vim/blog/simd-perlin-noise-i

    • In fast allen performancekritischen Bereichen von C/C++-Bibliotheken kommt handgeschriebene Assembly zum Einsatz, selbst bei einfachen Funktionen wie strlen. Compiler liefern meistens brauchbare Ergebnisse, aber nur wenige Programme sind so wichtig, dass sich dieser Aufwand lohnt.

    • Der eigentliche Performancegewinn kommt nicht durch Assembly, sondern durch AVX512. Dieser Kernel ist so simpel, dass bei einer Implementierung mit AVX512-Intrinsics der Unterschied zwischen C-Code und Assembly fast verschwindet. Der Grund für den 100x-Unterschied ist: a) min/max werden in SIMD jeweils mit einer einzelnen Instruktion erledigt, während sie im skalaren Fall in cmp + cmov zerfallen, b) wegen der 8-Bit-Präzision verarbeitet jede AVX512-Instruktion 64 Werte gleichzeitig. Dadurch kann man sogar die Bandbreite von L1- und L2-Cache sättigen (bei Zen 5: 128B bzw. 64B/Zyklus). Wenn jedoch ein ganzes Frame verarbeitet wird und wegen der Größe auf L3 zugegriffen werden muss, halbiert sich dieser Vorteil, und wenn es nicht einmal in L3 passt, fällt der Gewinn noch geringer aus.

  • Das erinnert mich an Sound Open Firmware (SOF), das ebenfalls entweder mit gcc oder dem kommerziellen Cadence-XCC-Compiler (mit Unterstützung für Xtensa-HiFi-SIMD-Intrinsics) gebaut werden kann: https://thesofproject.github.io/latest/introduction/index.html#toolchain-faq

  • Es sind 100x, nicht 100 % x.