【发布时间】:2015-07-22 23:40:03
【问题描述】:
基于this question 的答案/cmets,我用 gcc 4.9.2 (MinGW64) 编写了一个性能测试,以估计哪种方式的多个整数除法更快,如下所示:
#include <emmintrin.h> // SSE2
static unsigned short x[8] = {0, 55, 2, 62003, 786, 5555, 123, 32111}; // Dividend
__attribute__((noinline)) static void test_div_x86(unsigned i){
for(; i; --i)
x[0] /= i,
x[1] /= i,
x[2] /= i,
x[3] /= i,
x[4] /= i,
x[5] /= i,
x[6] /= i,
x[7] /= i;
}
__attribute__((noinline)) static void test_div_sse(unsigned i){
for(; i; --i){
__m128i xmm0 = _mm_loadu_si128((const __m128i*)x);
__m128 xmm1 = _mm_set1_ps(i);
_mm_storeu_si128(
(__m128i*)x,
_mm_packs_epi32(
_mm_cvtps_epi32(
_mm_div_ps(
_mm_cvtepi32_ps(_mm_unpacklo_epi16(xmm0, _mm_setzero_si128())),
xmm1
)
),
_mm_cvtps_epi32(
_mm_div_ps(
_mm_cvtepi32_ps(_mm_unpackhi_epi16(xmm0, _mm_setzero_si128())),
xmm1
)
)
)
);
}
}
int main(){
const unsigned runs = 40000000; // Choose a big number, so the compiler doesn't dare to unroll loops and optimize with constants
test_div_x86(runs),
test_div_sse(runs);
return 0;
}
GNU Gprof 和工具参数的结果。
/*
gcc -O? -msse2 -pg -o test.o -c test.c
g++ -o test test.o -pg
test
gprof test.exe gmon.out
-----------------------------------
test_div_sse(unsigned int) test_div_x86(unsigned int)
-O0 2.26s 1.10s
-O1 1.41s 1.07s
-O2 0.95s 1.09s
-O3 0.77s 1.07s
*/
现在我很困惑,为什么 x86 测试几乎没有得到优化,而 SSE 测试却变得更快,尽管昂贵的浮点转换成本。此外,我想知道有多少结果取决于编译器和架构。
总结一下:到底哪个更快:一分一分还是浮点绕道?
【问题讨论】:
-
似乎
unsigned short x[8]在第一次测试中被修改了。所以第二个测试从不同的值开始。 (而且所有x的值似乎都很快转到0。) -
操作持续时间不应受参数影响,编译器不应检测
x何时为0。当我设置本地红利时没有区别,所以x没关系。 -
你可以做得更好:你可以乘以被除数的模逆,而不是除法。这是编译器将通过编译时常量进行除法的操作,您也可以在运行时执行此操作,但需要做一些工作。
-
@Youka "操作持续时间不应该受参数影响" 我会说他们会这样做,至少在一般情况下是这样。例如。英特尔的一位指南说:““DIV/IDIV r64”的吞吐量随输入 RDX:RAX 中有效数字的数量而变化”。不过,我并不是说这对你来说很重要。
标签: c performance integer sse division