加速收集

Speeding up gather

我有一个计算生成系数向量和 returns 该向量与从大型数组中获取的数据向量的点积。为了加快速度,我使用 AVX2 SIMD 内在函数一次对八个向量执行此操作。问题是大部分时间最终都被收集操作消耗掉了,获取点积的数据。

我尝试了不同的方式来实现收集,内在的似乎效果最好。我将不胜感激一些关于加快速度的建议。

这是一个草图:

__m256 Compute(__m256 input)
{
    __m256 coefficients[56] = ComputeCoefficients(input);

    __m256i indices = ComputeIndices(input);

    __m256 sum = _mm256_setzero_ps();
    for (size_t i = 0; i != 56; ++i)
    {
        __m256 data = _mm256_i32gather_ps(bigArray + i, indices, sizeof(float)); // 
        sum = _m256_fmadd_ps(coefficients[i], data, sum);
    }
    return sum;
}

我首先要确保您使用的是最新的 Intel 处理器。英特尔在改进收集指令方面投入了大量工程。

话虽这么说,但这并不神奇。如果存在缓存未命中,您将为此付出代价。

我会尝试在没有 SIMD 指令的情况下编写相同的代码。速度差不多吗?如果是,那么您很可能会受到内存访问的限制。矢量化很好地解决了 计算 限制,并以 vector-size 为单位写入和存储数据,但即使在原则上,也不能指望它对解决随机访问限制的问题有多大帮助和缓存问题。

您的代码重复调用 VPGATHERDPS。根据 Agner Fog 的说法,这条指令有 12 个周期的延迟和每 4 个周期一条指令的吞吐量。当然,延迟是 best-case 场景,缓存未命中会增加延迟。

您应该对代码进行基准测试并确保每次循环迭代接近 4 个周期。主循环应该在大约 300 个周期内完成,这已经相当快了。

你没有告诉我们很多关于你的问题,但我们可以猜测它比 300 个周期慢得多。如果是这样,那么您可能遇到了缓存问题。如果您的 table 很大并且您是随机访问它,那么这是一个难题。如果您需要更好的性能,您可能需要重新设计问题。