Interesting. Even more interesting would have been seeing if/how C# SIMD intrinsics would have improved performance.
[dead]
Very interesting readup! I have some C# projects I've had in mind to try to compile to AOT. Quite different for complex programs of course, but the perf being very close to C is a great motivator.
Why would you want them in AOT, though? It's great for startup time and native interoperability, but it might be slower in general due to machine specific optimizations.
Because of Docker. You want the images to be as small as possible.
I would object, I want my containers to be as fast as possible and the JIT compiles for each CPU arch you run it on (supposedly optimally). Docker image size, who cares?
I would have expected the filters to run as a shader on the GPU which would make them much more efficient. I remember implementing two-pass gaussian blur in GLSL almost 20 years ago.
Yep if you want it done quickly, the GPU is the way to go. Especially once you get to 4K resolution and beyond.
See here:
https://aras-p.info/blog/2026/10/01/Fast-blur-with-animated-...
Most industries consider 8% a mountain. More than their entire profit margin.
And 8% milk would taste bad and ruin most recipes.
I don't know why we're comparing completely different categories of number though. In a business context getting a project done a few percent faster, or more accurately one step done a few percent faster, barely affects revenue at all. And saving CPU time matters even less.
There are much faster algorithms available for Gaussian blur though, running in O(n) rather than O(nσ) for an n pixel image and radius σ. See https://www.ipol.im/pub/art/2013/87/article.pdf for a survey.
If we look at the example of the FFT blur filter, sure O(n) looks easier and independent of the blur size, but you have an overhead in needing FFT and iFFT. It can be faster for some sigmas, but not for all. So you need different variants depending on sigma and a smooth transition between them.
Then you can start approximating - for large sigmas just using every 10th pixel would work. Looks like MS Teams background blur is doing this, you get a blurry background with aliasing - yay!
Once you add SIMD variants and look at CPU caching behaviour, you build versions for different CPUs. Instead of filtering the whole image for one dimension you might finish blocks locally.
You've now got a dozen variants that need testing and maintenance on different architectures.
I'm reminded of my colleague preaching requirements engineering - what was the goal gain?
FFT is O(n log n), not O(n). The better O(n) algorithms are the likes of Deriche, Vliet–Young–Verbeek, or Alvarez–Mazorra.
The C# version uses unsafe raw pointers which is practically the same as writing it in C. No surprise then that the outcomes are similar.
Yeah, the point being that you can write a much safer application, and in a very small section reach out to unsafe code, instead of having 100% unsafe code application, or having to do Python style, "Python libraries" that are actually C libraries.
You can also do Memory<T> and Span<T> over unmanaged memory to make things.. Safer.
Nice article!
What surprises me is that the original VLC filter does not use SIMD. Sometimes I wonder why I spent my money on a "modern" CPU with a lot of new features that stay completely ignored by most software I run every day.
[flagged]
It surprises me that it runs on the CPU at all, honestly.
Probably a reflection of the age of that code along with the usefulness of the feature. If no one actually needs the video blurry, then it doesn't matter how efficient the filter is.
It's also a basic implementation, doing a divide per sample to renormalize and not taking advantage of the symmetry of the kernel.
Even on a GPU, you wouldn't use an algorithm this simple in production. For small radii, leveraging bilinear filtering halves the number of samples. For larger radii, hierarchical pyramid approximations are popular.
> Two small edits close most of it: compute the loop bounds into locals before the loop,
I always assumed any decent runtime/compiler takes care of such optimisations, and usually leave such things to JDK in my Java code. Is that really not the case?
In C++ we have such troubles either. If something looking as constant cannot be 100% proved to be a constant, it cannot be optimized.
> Incrementing vectors (26.08.2019)
Decent ones do. .NET's JIT has historically (before ryujit especially and tbh I haven't looked at .NET much in the past decade) not been decent, general statements about decent compilers never applied to it. It has been playing catch-up lately but apparently it still has a ways to go.
They have been improving, this is one area however where those C# vs Java flamewars kind of miss out.
While C# the language has much more goodies than Java the language, Java the platform has had much better options than the CLR, because it has been mostly Microsoft and Mono (nowadays almost gone after the acquisition), whereas the Java ecosystem has a plethora of implementations, each one wiht their JIT and GC implementations, even AOT caches since almost three decades now.
Thankfully the outcome of Project Midori, and the whole Secure Future Initiative , has had the side effect of Microsoft becoming more serious about .NET performance, instead of always outsourcing performance workloads to C++ and COM.
It never was a priority I believe. As opposed to C, the main target audience of C#/.NET has always been LOB CRUD app shops.
Kind of, us users of .NET would have liked a Delphi, VB 6 kind of attention to performance, however for many years, Microsoft management had exactly that attitude, expecting that anyone that cared about performance would be writting COM in C++, or DLLs, and consuming those artifacts from .NET.
Finally they changed their approach to .NET, besides Midori, SFI that I mention on a sibling comment, certainly also due to Go and Rust competition.
Note how Azure nowadays does most of their open source contributions in Go and Rust, the rewrites that completly ignored .NET, while the team mentions lack of adoption on .NET related podcasts.