我正在尝试优化以下代码:
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寄存器的组合所抵消?
sdoti
不需要x
和y
数组具有相同数量的元素吗?实际上,x
中的元素数量是y
中的四分之一。 - Avi Ginsburgvec4
的大小是多少,或者indexarray
的范围是什么?首先将scalar[i]
累加到一个临时数组中(每个值在temp[indexarray[i]]
处),然后在最后计算一个简单的矩阵向量积可能更有效,除非indexarray
中的条目非常稀疏。 - chtzvec4
数量在几千个左右(少于1万)。indexarray
是稀疏的(我没有一个确切的数字可以给你,但我的直觉是大约5-10%是满的),但索引倾向于聚集在一起。 - Avi Ginsburg4 x n
矩阵乘以稀疏向量的结果。对于Avi的后续问题:indexarray
中是否有重复项?条目是否已排序?如果值聚集在一起,将它们存储在2、4或8个块中是否可行?(例如,将一个起始索引i
与值s[i]
到s[i+7]
组合在一起)这将允许在内部循环中手动调整固定大小的矩阵-向量乘积。 - chtz