C# 提高 SIMD Sum 的性能

C# Improve performance of SIMD Sum

我正在编写一个 SIMD 库并试图榨取每一点性能。
我已经将 array 就地转换为 Span<Vector<int>>,而不是创建新对象。
目标数组很大(超过 1000 个元素)。
有没有更有效的数组求和方法?
欢迎提出想法。

    public static int Sum(int[] array)
    {
        Vector<int> vSum = Vector<T>.Zero;
        int sum;
        int i;

        Span<Vector<int>> vsArray = MemoryMarshal.Cast<int, Vector<int>>(array);

        for (i = 0; i < vsArray.Length; i++)
        {
            vSum += vsArray[i];
        }

        sum = Vector.Dot(vSum, Vector<int>.One);

        i *= Vector<int>.Count;

        for (; i < array.Length; i++)
        {
            sum += array[i];
        }

        return sum;
    }

你的代码很好。只能提高 4%,方法如下:

// Test result: only 4% win on my PC.
[MethodImpl( MethodImplOptions.AggressiveInlining )]
static int sumUnsafeAvx2( int[] array )
{
    unsafe
    {
        fixed( int* sourcePointer = array )
        {
            int* pointerEnd = sourcePointer + array.Length;
            int* pointerEndAligned = sourcePointer + ( array.Length - array.Length % 16 );
            Vector256<int> sumLow = Vector256<int>.Zero;
            Vector256<int> sumHigh = sumLow;
            int* pointer;
            for( pointer = sourcePointer; pointer < pointerEndAligned; pointer += 16 )
            {
                var a = Avx.LoadVector256( pointer );
                var b = Avx.LoadVector256( pointer + 8 );
                sumLow = Avx2.Add( sumLow, a );
                sumHigh = Avx2.Add( sumHigh, b );
            }
            sumLow = Avx2.Add( sumLow, sumHigh );
            Vector128<int> res4 = Sse2.Add( sumLow.GetLower(), sumLow.GetUpper() );
            res4 = Sse2.Add( res4, Sse2.Shuffle( res4, 0x4E ) );
            res4 = Sse2.Add( res4, Sse2.Shuffle( res4, 1 ) );
            int scalar = res4.ToScalar();
            for( ; pointer < pointerEnd; pointer++ )
                scalar += *pointer;
            return scalar;
        }
    }
}

Here's a complete test.

明确地说,我不建议做我上面写的。不是为了 4% 的改进。不安全的代码是不安全的。你的版本在没有 AVX2 的情况下也可以工作,并且如果可用的话可以从 AVX512 中获益,我的优化版本在没有 AVX2 的情况下会崩溃,并且即使硬件支持它也不会使用 AVX512。