SSE 中的高效 min() 函数
Efficient min() function in SSE
我有以下循环,它取数组中每个条目的平方根:
#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),平方根不需要花费大量时间,但是即使启用了-O2
优化,结果的四个裁剪中的每一个都花费了大约20%的时间。有没有更有效的方法来实现循环?请注意,_mm_store_ps()
会通过 gcc
进行优化。
我尝试了平方根的优化表查找,因为 97% 的输入array
值低于 512,但这没有帮助。请注意,对于我的完整应用程序(一个持续运行的图像识别应用程序),此例程占用的总处理器时间不到四分之一。
有 MAXPS 和 MINPS:
__m128d _mm_max_ps(__m128d a, __m128d b);
对第一个源操作数和第二个源操作数中的打包单精度浮点值执行 SIMD 比较,并将每对值的最大值返回给目标操作数。
和
__m128d _mm_min_ps(__m128d a、__m128d b);
对第一个源操作数和第二个源操作数中打包的单精度浮点值执行 SIMD 比较,并将每对值的最小值返回给目标操作数。
使用具有四个 63.0f 值的 XMM 寄存器作为第二个操作数。
鉴于您可以使用非常现代的CPU,我将从以下开始:
float array[SIZE];
for(int i = 0; i < SIZE; i += 8)
{
__m256 eightFloats, eightRoots;
eightFloats = _mm256_load_ps(&array[i]);
eightRoots = _mm256_sqrt_ps(eightFloats);
float results[8];
eightRoots = _mm256_floor_ps(eightRoots);
_mm256_store_ps(results, eightRoots);
...
}
如果允许使用最先进的 SIMD 指令,甚至可以使用 512 版本。
总结这两个答案,这是我最终决定为我的全部要求而选择的代码,array[i] = std::min(floor(sqrt(array[i])), (float) 0x3f);
float array[SIZE];
const float clipValue = (float) 0x3f;
const float clipArray[8] = {clipValue, clipValue, clipValue, clipValue,
clipValue, clipValue, clipValue, clipValue};
__m256 eightClips = _mm256_load_ps(clipArray);
for(int i = 0; i < SIZE; i += 8)
{
__m256 eightFloats = _mm256_load_ps(&array[i]);
__m256 eightRoots = _mm256_sqrt_ps(eightFloats);
__m256 eightFloors = _mm256_floor_ps(eightRoots);
__m256 eightMins = _mm256_min_ps(eightFloors, eightClips);
_mm256_store_ps(&array[i], eightMins);
}
我的目标是垂直应用程序中的特定硬件,因此给定了与 AVX 兼容的处理器。
相关文章:
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 为什么 -mmacosx-version-min=10.10 不阻止使用标记为从 10.11 开始的函数?
- 第 5 行:字符 54:错误:调用"min(int,std::__cxx11::basic_string<char>::size_type)"没有匹配函数
- 如何使用函数std::min()来计算最小值
- 在函数 'int main(int, char**) 中,没有声明 'MIN'
- 函数读取最大和min int值,并用文本字符串返回
- 在调试中,如何知道对函数的重复调用中参数的统计数据(max-min,average,distribution..)
- 为什么 std::numeric_limits<float>::min() 在流式传输到具有不同函数的输出时行为不同?
- min()函数的副作用
- 实现min函数
- 使用 std::initializer_list 使函数指向 std::min
- SSE 中的高效 min() 函数
- 为什么<T>编译器将 numeric_limits::min 解释为函数指针?
- 这个min()函数是如何工作的
- 调用'min(uint8_t&, int)'没有匹配函数
- 错误:没有匹配函数调用"min(长期无符号 int&,无符号 int&)"