[英]Using AVX intrinsics instead of SSE does not improve speed — why?
我已經使用英特爾的SSE內在函數已經有一段時間了,性能有了很好的提升。 因此,我期望AVX內在函數能夠進一步加速我的程序。 不幸的是,直到現在情況並非如此。 可能我犯了一個愚蠢的錯誤,所以如果有人能幫助我,我將非常感激。
我使用Ubuntu 11.10和g ++ 4.6.1。 我編寫了我的程序(見下文)
g++ simpleExample.cpp -O3 -march=native -o simpleExample
測試系統配有Intel i7-2600 CPU。
這是代表我的問題的代碼。 在我的系統上,我得到輸出
98.715 ms, b[42] = 0.900038 // Naive
24.457 ms, b[42] = 0.900038 // SSE
24.646 ms, b[42] = 0.900038 // AVX
注意,僅選擇計算sqrt(sqrt(sqrt(x)))以確保內存帶寬不限制執行速度; 這只是一個例子。
simpleExample.cpp:
#include <immintrin.h>
#include <iostream>
#include <math.h>
#include <sys/time.h>
using namespace std;
// -----------------------------------------------------------------------------
// This function returns the current time, expressed as seconds since the Epoch
// -----------------------------------------------------------------------------
double getCurrentTime(){
struct timeval curr;
struct timezone tz;
gettimeofday(&curr, &tz);
double tmp = static_cast<double>(curr.tv_sec) * static_cast<double>(1000000)
+ static_cast<double>(curr.tv_usec);
return tmp*1e-6;
}
// -----------------------------------------------------------------------------
// Main routine
// -----------------------------------------------------------------------------
int main() {
srand48(0); // seed PRNG
double e,s; // timestamp variables
float *a, *b; // data pointers
float *pA,*pB; // work pointer
__m128 rA,rB; // variables for SSE
__m256 rA_AVX, rB_AVX; // variables for AVX
// define vector size
const int vector_size = 10000000;
// allocate memory
a = (float*) _mm_malloc (vector_size*sizeof(float),32);
b = (float*) _mm_malloc (vector_size*sizeof(float),32);
// initialize vectors //
for(int i=0;i<vector_size;i++) {
a[i]=fabs(drand48());
b[i]=0.0f;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Naive implementation
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
s = getCurrentTime();
for (int i=0; i<vector_size; i++){
b[i] = sqrtf(sqrtf(sqrtf(a[i])));
}
e = getCurrentTime();
cout << (e-s)*1000 << " ms" << ", b[42] = " << b[42] << endl;
// -----------------------------------------------------------------------------
for(int i=0;i<vector_size;i++) {
b[i]=0.0f;
}
// -----------------------------------------------------------------------------
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// SSE2 implementation
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pA = a; pB = b;
s = getCurrentTime();
for (int i=0; i<vector_size; i+=4){
rA = _mm_load_ps(pA);
rB = _mm_sqrt_ps(_mm_sqrt_ps(_mm_sqrt_ps(rA)));
_mm_store_ps(pB,rB);
pA += 4;
pB += 4;
}
e = getCurrentTime();
cout << (e-s)*1000 << " ms" << ", b[42] = " << b[42] << endl;
// -----------------------------------------------------------------------------
for(int i=0;i<vector_size;i++) {
b[i]=0.0f;
}
// -----------------------------------------------------------------------------
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// AVX implementation
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pA = a; pB = b;
s = getCurrentTime();
for (int i=0; i<vector_size; i+=8){
rA_AVX = _mm256_load_ps(pA);
rB_AVX = _mm256_sqrt_ps(_mm256_sqrt_ps(_mm256_sqrt_ps(rA_AVX)));
_mm256_store_ps(pB,rB_AVX);
pA += 8;
pB += 8;
}
e = getCurrentTime();
cout << (e-s)*1000 << " ms" << ", b[42] = " << b[42] << endl;
_mm_free(a);
_mm_free(b);
return 0;
}
任何幫助表示贊賞!
這是因為VSQRTPS
(AVX指令)在Sandy Bridge處理器上的周期是SQRTPS
(SSE指令)的兩倍。 請參閱Agner Fog的優化指南: 說明表 ,第88頁。
像平方根和除法這樣的指令不會受益於AVX。 另一方面,增加,乘法等。
如果您對增加平方根性能感興趣,可以使用VRSQRTPS和Newton-Raphson公式代替VSQRTPS:
x0 = vrsqrtps(a)
x1 = 0.5 * x0 * (3 - (a * x0) * x0)
VRSQRTPS本身並沒有受益於AVX,但其他計算也是如此。
如果23位精度足夠你使用它。
只是為了完整。 如果您的代碼中的操作數量有限,那么Newton-Raphson(NR)對分區或平方根等操作的實現將非常有用。 這是因為如果您使用這些替代方法,您將在其他端口(例如乘法和加法端口)上產生更大的壓力。 這基本上是x86架構具有處理這些操作的特殊硬件單元而不是替代軟件解決方案(如NR)的原因。 我引用了英特爾64和IA-32架構優化參考手冊 p.556:
“在某些情況下,當除法或平方根運算是隱藏這些運算的一些延遲的較大算法的一部分時,使用Newton-Raphson的近似可能會減慢執行速度。”
因此在大型算法中使用NR時要小心。 實際上,我有關於這一點的碩士論文,我將在這里留下一個鏈接,以供將來參考,一旦發布。
同樣對於人們如何總是想知道某些指令的吞吐量和延遲,請查看IACA 。 它是英特爾提供的一種非常有用的工具,用於靜態分析代碼的內核執行性能。
在此編輯的是論文的鏈接那些有興趣誰論文
根據您的處理器硬件,AVX指令可以作為SSE指令在硬件中進行仿真。 您需要查找處理器的部件號以獲得准確的規格,但這是低端和高端英特爾處理器之間的主要區別之一,專用執行單元的數量與硬件仿真的比較。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.