Live data from Hacker News

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

tomshardware.com

111–120 of 138 posts

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

#111

Earlier quoted context omitted.

> 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.

Examples of optimization passes in llvm that reason across arbitrary numbers of blocks:

- SROA

- GVN

- regalloc

And those are just the heaviest hitters. In fact most optimization passes are capable of performing changes that impact many blocks at once.

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

#112
post #68
post #58

Earlier quoted context omitted.

Personally I’ve never been able to beat gcc or icx autovectorization by using intrinsics; often I’m slower by a factor of 1.5-2x. Do you have any wisdom you can share about techniques or references you can point to?

I recently finished a 4 part series about vectorizing perlin noise.. from the very basics up to beating the state-of-the-art by 1.8x https://scallywag.software/vim/blog/simd-perlin-noise-i

Very cool, thank you for sharing!

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

#114
post #94

Earlier quoted context omitted.

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

A good example is a vector addition kernel, which is simple, embarrassingly parallel, and well-suited for SIMD: void vector_add(float *a, float *b, float *c, int n) { for (int i = 0; i

Indeed, automatic vectorizers do such simple things pretty reliably these days.

However, if you build your software from kernels like that, you leave a lot of performance on the table. For example, each core of my Zen 4 CPU at base frequency can add FP32 numbers with AVX1 or AVX-512 at 268 GB/sec, which results in 806 GB/sec total bandwidth for your kernel with two inputs and 1 output.

However, dual-channel DDR5 memory in my computer can only deliver 83 GB/sec bandwidth shared across all CPU cores. That’s an order of magnitude difference for a single threaded program, and almost 2 orders of magnitude difference when computing something on the complete CPU.

Even worse, the difference between compute and memory widens over time. The next generation Zen 5 CPUs can add numbers twice as fast per cycle if using AVX-512.

For this reason, ideally you want your kernels to do much more work with the numbers loaded from memory. That’s why efficient compute kernels are often way more complicated than the for loop in your example. Sadly, seems modern compilers can only reliably autovectorize very simple loops.

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

#115
post #79

Earlier quoted context omitted.

Looking at the linked patches, you’ll note that the baseline (ff_detect_range_c) [1] is bog-standard scalar C code while the speedup is achieved in the AVX-512 version (ff_detect_rangeb_avx512) [2] of the same computation. FFmpeg devs prefer to write straight assembly using a library of vector-width-agnostic macros they maintain, but at a glance the equivalent code looks to be straightforwardly expressible in C with…

> the equivalent code looks to be straightforwardly expressible in C with Intel intrinsics if that’s more your jam. (Granted, that’s essentially assembly except with a register allocator, so the practical difference is limited.) The vectorization is most of the speedup, not the assembly. At my day job I have a small pile of code I'm responsible for which is a giant pile of intrinsics. We compile to GCC and MSVC. We h…

I’m not sure it’s register allocation. VC++ is indeed less than ideal, but 2x performance difference is IMO too much to explain by register allocation alone.

First check that you’re passing correct flags to VC++ compiler and linker: optimized release configuration, correct /arch switch, and ideally LTCG. BTW if you’re using cmake build system it’s rather hard to do, cmake support of VC++ compiler is not great.

Another thing, VC++ doesn’t like emitting giant functions. A possible reason for 2x difference VC++ failed to inline stuff, and your function has calls to other functions instead of a single large one. Note the compiler supports __forceinline keyword to work around that.

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

#116
post #14

Earlier quoted context omitted.

> you can already use a SAT solver Could you elaborate please? How would you approach this problem, using a SAT solver? All I know is that a SAT solver tells you whether a certain formula of ANDs and ORs is true. I don't know how it could be useful in this case.

Pretty much all instructions at the assembly level are sequences of AND/OR/XOR operations. SAT solvers can prove that some (shorter) sequences are equivalent to other (longer) sequences. But it takes a brute force search. IIRC, these super optimizing SAT solvers can see patterns and pick 'Multiply' instructions as part of their search. So it's more than traditional SAT. But it's still... At the end of the day.... A S…

I see a guy who has never seen assembly explain assembly to people who have written assembly and written compilers and optimisations…

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

#117

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.

If you want something optimised… "equivalent" isn't going to do it.

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

#118

Earlier quoted context omitted.

> 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.

ISPC is a lot different from C++ compiler auto vectorization and it works extremely well. Have you tried it or not? If so where does it actually fall down? It warns you when doing slow stuff like gathers and scatters.

Is it a lot different from autovec with #pragma omp simd? I played around with ISPC a bit and it didn't seem much different.

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

#119

Earlier quoted context omitted.

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.

What do you think implements assembly language?

Answer: Verilog or VHDL. And these all synthesize down to AND/OR/XOR gates and eventually converted into NAND gates only.

Every assembly language statement is either data movement, or logic, or some combination of the two.

-------

We are talking about SAT solvers and superoptimizers. Are you at all familiar with this domain? Or have you even done a basic search on what the subject matter is?

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

#120

Earlier quoted context omitted.

Looking at the linked patches, you’ll note that the baseline (ff_detect_range_c) [1] is bog-standard scalar C code while the speedup is achieved in the AVX-512 version (ff_detect_rangeb_avx512) [2] of the same computation. FFmpeg devs prefer to write straight assembly using a library of vector-width-agnostic macros they maintain, but at a glance the equivalent code looks to be straightforwardly expressible in C with…

Moreover the baseline _c function is compiled with -march=generic and -fno-tree-vectorize on GCC. Hence it's the best case comparison for handcrafted AVX512 code. And while it's is obviously faster and that's very cool, boasting the 100x may be misinterpreted by outsider readers. I was commenting there with some suggested change and you can find more performance comparison [0]. For example with small adjustment to C…

I think this comment should be on the top lol.

I mean, I love ffmpeg, I use it a lot and it's fantastic for my needs, but I've found their public persona often misleading and well, this just confirms my bias.

    > We made a 100x improvement over incredibly unoptimized C by writing heavily specific cpu instructions that the compiler cannot use because we don't allow it!
2x is still an improvement, but way less outstanding as they want it to publicize it because they used assembly.
Post reply on HN