我有以下代碼,並期望使用exp()
函數的內在版本。不幸的是,它不是在x64的構建,使得它比類似的Win32(即32位版本)慢:如何在x64代碼中獲得exp()函數的內部函數?
#include "stdafx.h"
#include <cmath>
#include <intrin.h>
#include <iostream>
int main()
{
const int NUM_ITERATIONS=10000000;
double expNum=0.00001;
double result=0.0;
for (double i=0;i<NUM_ITERATIONS;++i)
{
result+=exp(expNum); // <-- The code of interest is here
expNum+=0.00001;
}
// To prevent the above from getting optimized out...
std::cout << result << '\n';
}
我使用我的生成以下開關:
/Zi /nologo /W3 /WX-
/Ox /Ob2 /Oi /Ot /Oy /GL /D "WIN32" /D "NDEBUG"
/D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm-
/EHsc /GS /Gy /arch:SSE2 /fp:fast /Zc:wchar_t /Zc:forScope
/Yu"StdAfx.h" /Fp"x64\Release\exp.pch" /FAcs /Fa"x64\Release\"
/Fo"x64\Release\" /Fd"x64\Release\vc100.pdb" /Gd /errorReport:queue
如您所見,根據MSDN article on intrinsics的要求,我確實有/Oi
,/O2
和/fp:fast
。然而,儘管我努力致電標準庫,但在x64構建中,exp()
的執行速度較慢。
這裏是生成的彙編:
for (double i=0;i<NUM_ITERATIONS;++i)
000000013F911030 movsd xmm10,mmword ptr [[email protected] (13F912248h)]
000000013F911039 movapd xmm8,xmm6
000000013F91103E movapd xmm7,xmm9
000000013F911043 movaps xmmword ptr [rsp+20h],xmm11
000000013F911049 movsd xmm11,mmword ptr [[email protected] (13F912240h)]
{
result+=exp(expNum);
000000013F911052 movapd xmm0,xmm7
000000013F911056 call exp (13F911A98h) // ***** exp lib call is here *****
000000013F91105B addsd xmm8,xmm10
expNum+=0.00001;
000000013F911060 addsd xmm7,xmm9
000000013F911065 comisd xmm8,xmm11
000000013F91106A addsd xmm6,xmm0
000000013F91106E jb main+52h (13F911052h)
}
正如你可以在組件上方看,有一個叫出來的exp()
功能。現在,讓我們來看看該for
環與32位編譯生成的代碼:
for (double i=0;i<NUM_ITERATIONS;++i)
00101031 xorps xmm1,xmm1
00101034 rdtsc
00101036 push ebx
00101037 push esi
00101038 movsd mmword ptr [esp+1Ch],xmm0
0010103E movsd xmm0,mmword ptr [[email protected] (102188h)]
00101046 push edi
00101047 mov ebx,eax
00101049 mov dword ptr [esp+3Ch],edx
0010104D movsd mmword ptr [esp+28h],xmm0
00101053 movsd mmword ptr [esp+30h],xmm1
00101059 lea esp,[esp]
{
result+=exp(expNum);
00101060 call __libm_sse2_exp (101EC0h) // <--- Quite different from 64-bit
00101065 addsd xmm0,mmword ptr [esp+20h]
0010106B movsd xmm1,mmword ptr [esp+30h]
00101071 addsd xmm1,mmword ptr [[email protected] (102180h)]
00101079 movsd xmm2,mmword ptr [[email protected] (102178h)]
00101081 comisd xmm2,xmm1
00101085 movsd mmword ptr [esp+20h],xmm0
expNum+=0.00001;
0010108B movsd xmm0,mmword ptr [esp+28h]
00101091 addsd xmm0,mmword ptr [[email protected] (102188h)]
00101099 movsd mmword ptr [esp+28h],xmm0
0010109F movsd mmword ptr [esp+30h],xmm1
001010A5 ja wmain+40h (101060h)
}
太多的代碼存在,但它的速度更快。我一個3.3千兆赫的Nehalem-EP主機上做了一個定時試驗產生如下結果:
32位:
For loop body average exec time: 34.849229 cycles/10.560373 ns
64位:
For loop body average exec time: 45.845323 cycles/13.892522 ns
非常古怪的行爲,確實如此。爲什麼會發生?
更新:
我創建了一個Microsoft Connect bug report。歡迎自己動手,以獲得微軟本身對使用浮點內部函數的權威答案,特別是在x64代碼中。
[本文](http://blogs.msdn.com/b/ricom/archive/2009/06/10/visual-studio-why-is-there-no-64-bit-version.aspx) (解釋爲什麼VS沒有64位版本)指出64位版本可能比32位版本慢。不過,我不知道這個解釋是否適用於你的具體情況。 – Attila 2012-04-10 20:01:02
該文章是關於Visual Studio本身的64位版本,它與提出的問題無關。有很多因素可以使64位應用程序比32位應用程序慢。除非我錯過了一些東西,但是這些因素都與我關於浮點運算的問題沒有任何關係。 – 2012-04-10 20:04:10
@MichaelGoldshteyn - 我的錯誤 – Attila 2012-04-10 20:08:28