【发布时间】:2016-02-10 05:17:05
【问题描述】:
我有以下循环,它取数组中每个条目的平方根:
#include <mmintrin.h>
float array[SIZE];
for (int i = 0; i < SIZE; i += 4)
{
__m128 fourFloats, fourRoots;
fourFloats = _mm_load_ps(&array[i]);
fourRoots = _mm_sqrt_ps(fourFloats);
float results[4];
_mm_store_ps(results, fourRoots);
// This is bottleneck
array[i] = results[0] > 63.0F ? 63.0F : floor(results[0]);
array[i+1] = results[1] > 63.0F ? 63.0F : floor(results[1]);
array[i+2] = results[2] > 63.0F ? 63.0F : floor(results[2]);
array[i+3] = results[3] > 63.0F ? 63.0F : floor(results[3]);
// This is slower
// array[i] = (int) std::min(floor(results[0]), 63.0F);
}
根据我的分析器 (Zoom),平方根不会花费大量时间,但结果的四个剪辑中的每一个都需要大约 20% 的时间,即使启用了 -O2 优化也是如此。有没有更有效的方法来实现循环?请注意,_mm_store_ps() 会被 gcc 优化掉。
我尝试了平方根的优化表查找,因为 97% 的输入 array 值低于 512,但这并没有帮助。请注意,对于我的完整应用程序(一个持续运行的图像识别应用程序)而言,此例程占用的总处理器时间不到四分之一。
【问题讨论】:
-
您是否尝试在
fourRoots上使用_mm_floor_ps,然后再将其存储到results中,然后再制作您拥有的这些条件内容? -
顺便说一句,有 SSE 命令一次处理 8 个浮点数
-
@ixSci 我没有意识到有这样的功能!我现在查了一下,SSE4 是 2007 年左右的,因为我们的目标是 i7 左右的设备,所以我对使用这个指令没有任何疑虑。
-
在下面更正了我的答案
-
您应该使用
gcc -O3来启用自动矢量化。转换为int并且返回很慢,尤其是,我并不感到惊讶。如果您使用的是标量,而不是使用_mm_cvttps_epi32(额外的t表示截断。)如果您希望结果最终为float,那么使用floor_ps并夹到63.0f 与min_ps。这需要 SSE4.1,因此您需要第二代 core2。 (或 AVX 用于 256b 向量,但这需要 Intel Sandybridge / AMD Bulldozer。第一代 i7(Nehalem/Westmere)已经过时但并未消失,甚至还没有完全过时。)