Live data from Hacker News

FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

tomshardware.com

81–90 of 138 posts

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#81

Earlier quoted context omitted.

Sorry for the derail, but it sounds like you have a ton of experience with SIMD. Have you used ISPC, and what are your thoughts on it? I feel it's a bit ridiculous that in this day and age you have to write SIMD code by hand, as regular compilers suck at auto-vectorizing, especially as this has never been the case with GPU kernels.

> Have you used ISPC No professional kernel writer uses Auto-vectorization. > I feel it's a bit ridiculous that in this day and age you have to write SIMD code by hand You feel it's ridiculous because you've been sold a myth/lie (abstraction). In reality the details have always mattered.

I'm hard pressed to think of a kernel function that would benefit from auto-vectorization.

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#82
post #64

Earlier quoted context omitted.

It's still unclear from your explanation how it's actually used in practice. I run thousands of ffmpeg conversions every day, so it would be useful to know how/if this is likely to help me. Are you saying that it's run once during a conversion as part of the process? Or that it's a specific flag that you give, it then runs this function, and returns output on the console? (Either of those would be a one-time affair,…

This is a new filter that hasn’t even been committed yet, it only runs if explicitly specified, and would only ever be specified by someone that already knows that they don’t know the characteristics of their video. So you wouldn’t ever run this.

Thank you, exactly what I was looking for.

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#83

When I spent a decade doing SIMD optimizations for HEVC (among other things), it was sort of a joke to compare the assembly versions to plain c. Because you’d get some ridiculous multipliers like 100x. It is pretty misleading, what it really means is it was extremely inefficient to begin with. The devil is in the details, microbenchmarks are typically calling the same function a million times in a loop and everything…

Sorry for the derail, but it sounds like you have a ton of experience with SIMD. Have you used ISPC, and what are your thoughts on it? I feel it's a bit ridiculous that in this day and age you have to write SIMD code by hand, as regular compilers suck at auto-vectorizing, especially as this has never been the case with GPU kernels.

ISPC suffers from poor scatter and gather support in hardware. The direct result is that it is hard to make programs that scale in complexity without resorting to shenanigans.

An ideal scatter-read or gather-store instruction should take time proportional to the number of cache lines that it touches. If all of the lane accesses are sequential and cache line aligned it should take the same amount of time as an aligned vector load or store. If the accesses have high cache locality such that only two cache lines are touched, it should cost exactly the same as loading those two cache lines and shuffling the results into place. That isn't what we have on x86-AVX512. They are microcoded with inefficient lane-at-a-time implementations. If you know that there is good locality of reference in the access, then it can be faster to hand-code your own cache line-at-a-time load/shuffle/masked-merge loop than to rely on the hardware. This makes me sad.

ISPC's varying variables have no way to declare that they are sequential among all lanes. Therefore, without extensive inlining to expose the caller's access pattern, it issues scatters and gathers at the drop of a hat. You might like to write your program with a naive x[y] (x a uniform pointer, y a varying index) in a subroutine, but ISPC's language cannot infer that y is sequential along lanes. So, you have to carefully re-code it to say that y is actually a uniform offset into the array, and write x[y + programIndex]. Error-prone, yet utterly essential for decent performance. I resorted to munging my naming conventions for such indexes, not unlike the Hungarian notation of yesteryear.

Rewriting critical data structures in SoA format instead of AoS format is non-trivial, and a prerequisite to get decent performance from ISPC. You cannot "just" replace some subroutines with ISPC routines, you need to make major refactorings that touch the rest of the program as well. This is neutral in an ISPC-versus-intrinsics (or even ISPC-versus-GPU) shootout, but it is worth mentioning only to point out that ISPC is also not a silver bullet in this regards, either.

Non-minor nit: The ISPC math library gives up far too much precision by default in the name of speed. Fortunately, Sleef is not terribly difficult to integrate and use for the 1-ulp max rounding error that I've come to expect from a competent libm.

Another: The ISPC calling convention adheres rather strictly to the C calling convention... which doesn't provide any callee-saved vector registers, not even for the execution mask. So if you like to decompose your program across multiple compilation units, you will also notice much more register save and restore traffic than you would like or expect.

I want to like it, I can get some work done in it, and I did get significant performance improvements over scalar code when using it. But the resulting source code and object code are not great. They are merely acceptable.

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#84
post #80

Earlier quoted context omitted.

The reason you have to optimize SIMD by hand is that compilers can't redesign your data structures and algorithms. This is the level of abstraction at which you often need to be working with SIMD. Compilers are limited to codegen things like auto-vectorizing simple loops, but that isn't where most of the interesting possibilities are with SIMD. If you look at heavily-optimized SIMD code side-by-side with the equivale…

Hope you one day can get around to writing some blog posts or maybe even publish some books/courses on this - it sounds interesting!

You'll find the video in this submission a fun watch if you want to learn a bit about optimization and AVX-512.

https://news.ycombinator.com/item?id=44176729

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#85

When I spent a decade doing SIMD optimizations for HEVC (among other things), it was sort of a joke to compare the assembly versions to plain c. Because you’d get some ridiculous multipliers like 100x. It is pretty misleading, what it really means is it was extremely inefficient to begin with. The devil is in the details, microbenchmarks are typically calling the same function a million times in a loop and everything…

Sadly, even beyond the hot cache issue,

> They would later go on to elaborate that the functionality, which might enjoy a 100% speed boost, depending upon your system, was “an obscure filter.”

However, to be fair, they communicate this stuff very clearly.

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#86
Interesting. The one time I ended up writing assembly was because of SIMD. I was speaking about it recently and had forgotten it was because SIMD instructions, so nice to be reminded. However, that one time, I also ended up finding the right syntactic sugar, to get the compiler to do it right. If I remember right it was all down to aliasing. I had to convince the compiler the data wasn't going to be accessed any other place. It wasn't working that out itself, so it didn't know it could use the SIMD instruction I was. Once I found this and the right non-standard extra key words, the compiler would do it right. So I ended removing the assembly I had written.

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#87
post #75

Article is unclear what will actually be affected. It mentions "rangedetect8_avx512" and calls it an obscure function. So, what situations is it actually used for, and what is the real-time improvement in performance for the entire conversion process?

Back in ye olden tymes, video was an analog signal. It was wibbly wobbly waves. You could look at them with an oscilloscope. One of the things that it used to do to make stuff work was to encode control stuff in band. This is sorta like putting editor notes in a text file. There might be something like . In particular, it used blacks which were blacker than black to signal when it was time to go to the next line, or…

Maybe you could get some savings from the codec by knowing if the range is full or limited, but probably the more useful thing is to just be able to flag the video correctly so it will play right, or to know that you need to convert it if you want, say, only limited-range output.

Also as an aside, "limited" is even more limited than 16-255, it's limited on the top end also: max white is 235, and the color components top out at 240.

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#88
post #8

Earlier quoted context omitted.

But we do! For llvm there's https://github.com/AliveToolkit/alive2 There are papers like https://people.cs.rutgers.edu/~sn349/papers/cgo19-casmverify... There's https://github.com/google/souper There's https://cr.yp.to/papers/symexemu-20250505.pdf And probably other things I'm not aware of. If you're limiting the scope to a few blocks at a time, symbolic execution will do fine.

> limiting the scope to a few blocks Yeah so like that doesn’t scale. The interesting optimizations involve reasoning across thousands of blocks And my point is there is no reliable general purpose solution here. „Only works for a few blocks at a time” is not reliable. It’s not general purpose

No optimisation currently done in production compilers (that I know of) work on more than a few blocks. I haven't seen anyone claim they're not general purpose or don't scale yet, or are not reliable.

Meanwhile the patch we're discussing is 2 functions, 3 blocks each. So in this context we're not talking about anything crazy.

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#89
post #37

Actually a bit surprised to hear that assembly is faster than optimized C. I figured that compilers are so good nowadays that any gains from hand-written assembly would be infinitesimal. Clearly I'm wrong on this; I should probably properly learn assembly at some point...

It's SIMD specifically. SIMD is crazy fast and compilers are still not good at generating it.

There are other things too like using the carry bit directly with ADC instead of using "tricks" to check for overflow before/after it happens for example.

Re: FFmpeg devs boast of another 100x leap thanks to handwritten assembly code

#90

Earlier quoted context omitted.

A short look at any compiled code on godbolt will very quickly inform you that pretty much all instructions at the assembly level are, in fact, NOT sequences of AND/OR/XOR operations.

All instructions are implemented with logic gates. In fact. All instructions today are likely NAND gates. Have you ever seen a WallaceTree multiplier? A good sequence that shows how XOR and AND gates can implement multiply. Now, if multiply + XOR gets the new function you want, it's likely better than whatever the original compiler output.

That was not the claim. The claim was that assembler was made up out of sequences of OR/AND/XOR, and that claim is demonstrably false.
Post reply on HN