【发布时间】:2019-05-15 07:28:35
【问题描述】:
我正在尝试优化以下sum{vec4[indexarray[i]] * scalar[i]},其中vec4 是float[4],scalar 是浮点数。对于 128 位寄存器,这归结为
sum = _mm_fmadd_ps(
_mm_loadu_ps(vec4[indexarray[i]]),
_mm_set_ps1(scalar[i]),
sum);
如果我想在 256 位寄存器上执行 FMA,我必须这样做
__m256 coef = _mm256_set_m128(
_mm_set_ps1(scalar[2 * i + 0]),
_mm_set_ps1(scalar[2 * i + 1]));
__m256 vec = _mm256_set_m128(
_mm_loadu_ps(vec4[indexarray[2 * i + 0]]),
_mm_loadu_ps(vec4[indexarray[2 * i + 1]]));
sum = _mm256_fmadd_ps(vec, coef, sum);
随着随机播放并在末尾添加以求上车道和下车道的总和。
理论上,我从单个 FMA 中获得了 5 的延迟(假设 Haswell 架构),但从 _mm256_set_m128 中减少了 2x3 的延迟。
有没有办法使用 ymm 寄存器使这更快,或者单个 FMA 的所有收益都会因组合 xmm 寄存器而抵消?
【问题讨论】:
-
英特尔的 MKL 库有一个函数可以用于该操作:cblas?_ddoti,参见software.intel.com/en-us/mkl-developer-reference-c-cblas-doti。我怀疑这个功能是由英特尔高度优化的。因此,您可以直接使用它,也可以查看它的(汇编)源代码——前提是您拥有英特尔编译器许可证。
-
难道
sdoti不需要x和y数组具有相同数量的元素吗?在我的例子中,x中的元素数量是y的四分之一。 -
不,我指的函数是sparse版本。您可以在页面的“描述”部分看到这一点。一个向量是密集的,而另一个向量是稀疏的。我认为该函数完全执行您的操作。
-
vec4有多大,或者indexarray的范围是多少?首先将scalar[i]汇总到一个临时数组(temp[indexarray[i]]处的每个值)并在最后计算一个简单的矩阵向量积可能更有效——除非indexarray中的条目非常稀疏。 -
@chtz
vec4数以千计(少于 10k)。indexarray是稀疏的(我没有确切的数字给你,但我的直觉大约是 5-10%),但索引往往会聚集在一起。
标签: c++ simd intrinsics avx2