c++ - 加速收集

标签 c++ optimization simd avx2

我有一个计算生成一个系数 vector ,并返回该 vector 与从一个大数组中获取的数据 vector 的点积。为了加快速度,我使用 AVX2 SIMD 内在函数一次对八个 vector 执行此操作。问题在于,大部分时间最终都花在了获取点积数据的收集操作上。

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

这是一个草图:

__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 大小为单位写入和存储数据,但即使在原则上,也不能指望它对解决随机访问和缓存问题所带来的问题有多大帮助。

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

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

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

关于c++ - 加速收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41499625/

相关文章:

c++ - 使用基指针调用派生对象函数

c# - x86 CPU 执行哪些类型的重新排序优化?

php - 在性能(php/mysql)方面对脚本进行故障排除的好方法是什么?

mysql - 优化mysql慢查询

c++ - 为什么要把 std::lock 放在 std::lock_guard 之前

c++ - 获取用于 for 循环的数组大小

c++ - SANITYCHECK和maxUsedValInHistogramData

SSE2 : How to reduce a _m128 to a word

c++ - 计算两个 _m128i SIMD vector 之间的匹配字节数

c++ - 如何使用内在函数将两个 char 数组按元素相乘并将乘法相加为 int?