Optimize SIMD pipelines and math across compression/decompression paths - #665
Optimize SIMD pipelines and math across compression/decompression paths#665GermanAizek wants to merge 1 commit into
Conversation
|
Awesome, thanks - will take a look. |
It’s very strange, but locally my CTest runs successfully, while it doesn’t through GitHub Actions — how is that possible? |
|
Looks like it needs updated reference CSV files. |
|
What compiler and build settings are you using? I get a significant performance regression (15-20%) compared to the main branch when compiling for AVX2 with Clang++-20 (only tested on an older CoffeeLake Core-i5 so far). I also get a small IQ drop on some images. |
|
|
||
| vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero; | ||
| sum_xp += select(zero, texel_datum, tdm0); | ||
| if (dr > 0.0f) |
There was a problem hiding this comment.
I would expect all the changes to use branches to be a significant regression unless the compiler turns it back into a select - these branches are inherrently unpredictable, and the cost of the mispredict far outweighs the cost of the additional instructions when vectorized.
There was a problem hiding this comment.
Biggest issue currently is that I can't reproduce the improvements - on my test hardware I get a large regression. I don't have a Xeon to hand at the moment - can test more in the office next week. Tested the AVX2 build on:
- Intel Core i5-9600K (desktop part)
- Intel Core Ultra 7 165U (mobile part)
If I revert all of the changes in astcenc_averages_and_directions.cpp I avoid the regression, but still don't see any improvement over the current main branch.
| if (!constant_wes) | ||
| { | ||
| weight_error_scale = gatherf_byte_inds<vfloat>(ei.weight_error_scale, texel); | ||
| vfloat wes = gatherf_byte_inds<vfloat>(ei.weight_error_scale, texel); |
There was a problem hiding this comment.
This change is invalid I think. It's only safe if weight_error_scale is guaranteed to be 1.0f in the cases where it's flagged as constant, but it's not guaranteed to be (I don't think). You need to keep the multiply outside of the if.
Ditto later change too.
Sorry for the long answer. Yes, indeed, I didn’t mention the Linux kernel version and the compiler. |
I did the wrong thing; it would have been better to test performance changes directly on GCC and Clang and display the data about them together. Perhaps -O optimization flags work differently in Clang. |
I've not checked for a few years but when I last checked Clang was about 10-15% faster than GCC, and about 30% faster than MSVC. Using MSVC with clang-cl was somewhere between native Clang and GCC. |
|
@solidpixel I suggest temporarily abandoning these changes. I need to take into account working with two compilers at once and the maximum -O3 compiler flags. Later, I will send you more guaranteed changes for the PR if there is an improvement with both compilers. |
I am continuing the development of the TCC compiler (https://en.wikipedia.org/wiki/Tiny_C_Compiler - Fabrice Bellard) (https://github.com/GermanAizek/tinycpp) and I can say that Clang is not always more efficient than GCC. I have automated benchmarks that compare examples using GCC, Clang, and TCC. |
|
@solidpixel check my results Example: c_binary_trees https://github.com/GermanAizek/tinycpp/blob/mob/tests/benchmarks/c/c_binary_trees.c
|
For sure, I was only talking in the context of astcenc, and I last checked properly with GCC 11 or so, it's been a while. I know GCC historically had some efficiency problems with intrinsics, and it has been getting better in recent years. I really should do another sweep with latest compilers. |
|
@solidpixel If you’re interested, I can send you a report with benchmark GCC vs Clang vs TCC data, but on average, Clang is 5–10 % faster than GCC, yet it consumes significantly more use RAM and size in compiled binary file due to unrolling and an excess of inline functions. |
- Split partition averages, error squaring, and endpoint evaluation loops into unmasked SIMD fast paths and tails - Simplify ideal weight decimation by eliminating redundant error scale multiplies when constant - Hoist dot products and simplify weight difference calculations in weight realignment and ideal color finding - Hoist quantization table lookups in color quantization - Enable BMI/BMI2/LZCNT instructions for AVX2 builds
|
@solidpixel I force push new commit e40f9c1 At the moment, I have an increase in MT/s across two compilers GCC and Clang. If there is indeed an increase with your microarchitecture, I’ll create graphs for the PR (I have 2xE5-2699v3, 22 cores and 72 threads on Haswell). |

@solidpixel
Thank you so much for your support and for developing ASTC encoder. I would like to help and contribute; I already contributed to this project about 5 years ago. According to the tests, we managed to optimize absolutely all bench indicators, even though
fastestpreset dropped slightlyThe tests were conducted using your benchmarks. The testing was performed on a Xeon 2xE5-2699v3 (18+18 - 36+36 threads) cpu with max AVX2 support
description commit changes:
lerp_color_intformula to halve vector multiplications.compute_symbolic_block_difference_1plane_1partition.unit_weightsincompute_error_squared_rgb_single_partition(eliminates 12 vector muls/iter).constant_wesfast paths incompute_error_of_weight_set_1plane/2planesto bypass redundant vector loads and muls.weight_down/weight_uparithmetic inrealign_weights_decimated.compute_lowest_and_highest_weightfor cut errors.