This is a little finger exercise in SIMD-optimization. The example we try to optimize is an image processing operation known as "color twist". It is a matrix-multication of an RGB-triple and a given matrix. So, if we have the source pixel values r, g, b, then the destination pixels R, G, B are calculated as
where
is the color twist matrix.
There are SIMD-optimized versions leveraging AVX-instructions (for x86) and Neon-instructions (for ARM).
Here are some numbers (1MB = 1,000,000 bytes):
Intel Core i7-8700K @ 3.70GHz, msvc 19.27.29112, x64 : 2048x2048 RGB48 bitmap
| version | performance in MB/s |
|---|---|
| colorTwistRGB48_C | 1226.24 |
| colorTwistRGB48_IPP | 1720.98 |
| colorTwistRGB48_AVX | 3291.02 |
| colorTwistRGB48_AVX2 | 4297.74 |
| colorTwistRGB48_AVX3 | 5175.55 |
| colorTwistRGB24_C | 318.01 |
| colorTwistRGB24_IPP | 892.93 |
| colorTwistRGB24_AVX3 | 2966.55 |
Intel Core i7-8700K @ 3.70GHz, Intel icl 19.1.3.311, x64 : 2048x2048 RGB48 bitmap
| version | performance in MB/s |
|---|---|
| colorTwistRGB48_C | 1313.22 |
| colorTwistRGB48_IPP | 1809.26 |
| colorTwistRGB48_AVX | 3354.22 |
| colorTwistRGB48_AVX2 | 4452.38 |
| colorTwistRGB48_AVX3 | 5207.50 |
| colorTwistRGB24_C | 340.01 |
| colorTwistRGB24_IPP | 922.14 |
| colorTwistRGB24_AVX3 | 3180.88 |
Intel Core i7-8700K @ 3.70GHz, gcc 10.2.0, x64 : 2048x2048 RGB48 bitmap
| version | performance in MB/s |
|---|---|
| colorTwistRGB48_C | 1453.32 |
| colorTwistRGB48_AVX | 3334.76 |
| colorTwistRGB48_AVX2 | 4315.26 |
| colorTwistRGB48_AVX3 | 5011.39 |
| colorTwistRGB24_C | 328.43 |
| colorTwistRGB24_AVX3 | 2998.93 |
Raspberry Pi 4, gcc 8.3.0-6, 32bit : 2048x2048 RGB48 bitmap
| version | performance in MB/s |
|---|---|
| colorTwistRGB48_C | 366.99 |
| colorTwistRGB48_NEON | 410.42 |
| colorTwistRGB48_NEON2 | 1009.3 |
| colorTwistRGB24_C | 96.14 |
| colorTwistRGB24_NEON2 | 480.69 |
Raspberry Pi 3b, gcc 8.3.0-6, 32bit : 2048x2048 RGB48 bitmap
| version | performance in MB/s |
|---|---|
| colorTwistRGB48_C | 181.37 |
| colorTwistRGB48_NEON | 170.11 |
| colorTwistRGB48_NEON2 | 347.69 |
| colorTwistRGB24_C | 48.45 |
| colorTwistRGB24_NEON2 | 222.63 |
AMD Ryzen 7 4700U, msvc 19.27.29112, x64 : 2048x2048 RGB48 bitmap
| version | performance in MB/s |
|---|---|
| colorTwistRGB48_C | 1202.02 |
| colorTwistRGB48_IPP | 1836.64 |
| colorTwistRGB48_AVX | 3810.53 |
| colorTwistRGB48_AVX2 | 4970.00 |
| colorTwistRGB48_AVX3 | 5572.38 |
| colorTwistRGB24_C | 297.13 |
| colorTwistRGB24_IPP | 920.24 |
| colorTwistRGB24_AVX3 | 2548.42 |
AMD Ryzen 7 4700U, Intel icl 19.1.3.311, x64 : 2048x2048 RGB48 bitmap
| version | performance in MB/s |
|---|---|
| colorTwistRGB48_C | 1355.20 |
| colorTwistRGB48_IPP | 1862.04 |
| colorTwistRGB48_AVX | 3881.71 |
| colorTwistRGB48_AVX2 | 5150.99 |
| colorTwistRGB48_AVX3 | 5736.88 |
| colorTwistRGB24_C | 287.26 |
| colorTwistRGB24_IPP | 952.50 |
| colorTwistRGB24_AVX3 | 2508.71 |
Intel Core m3-6Y30 @ 0.9GHz, msvc 19.27.29112, x64 : 2048x2048 RGB48 bitmap
| version | performance in MB/s |
|---|---|
| colorTwistRGB48_C | 650.32 |
| colorTwistRGB48_IPP | 935.62 |
| colorTwistRGB48_AVX | 1769.30 |
| colorTwistRGB48_AVX2 | 2370.21 |
| colorTwistRGB48_AVX3 | 2943.29 |
| colorTwistRGB24_C | 157.44 |
| colorTwistRGB24_IPP | 466.74 |
| colorTwistRGB24_AVX3 | 1793.66 |