Tôi đã sử dụng nội tại SSE của Intel trong một thời gian khá lâu với hiệu suất hoạt động tốt. Do đó, tôi mong đợi bản chất của AVX để tăng tốc hơn nữa các chương trình của tôi. Điều này, thật không may, không phải là trường hợp cho đến bây giờ. Có lẽ tôi đang làm một sai lầm ngu ngốc, vì vậy tôi sẽ rất biết ơn nếu ai đó có thể giúp tôi ra ngoài.Sử dụng nội tại AVX thay vì SSE không cải thiện tốc độ - tại sao?
Tôi sử dụng Ubuntu 11.10 với g ++ 4.6.1. Tôi đã biên soạn chương trình của mình (xem bên dưới) với
g++ simpleExample.cpp -O3 -march=native -o simpleExample
Hệ thống thử nghiệm có CPU Intel i7-2600.
Đây là mã minh họa cho vấn đề của tôi. Trên hệ thống của tôi, tôi nhận được đầu ra
98.715 ms, b[42] = 0.900038 // Naive
24.457 ms, b[42] = 0.900038 // SSE
24.646 ms, b[42] = 0.900038 // AVX
Lưu ý rằng tính toán sqrt (sqrt (sqrt (x))) chỉ được chọn để đảm bảo băng thông bộ nhớ không giới hạn tốc độ thực thi; nó chỉ là một ví dụ.
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;
}
Any help is appreciated!
Tôi đã không biết rằng AVX đã từng mô phỏng - bạn có một tài liệu tham khảo cho việc này? CPU nào sẽ là trường hợp này? –
Trên Sandy Bridge, theo [bảng hướng dẫn] (http://www.agner.org/optimize/instruction_tables.pdf), trang 87--88, có vẻ như 'VDIVPS/PD' thực hiện 2 vi lệnh trên cổng 0 , so với 1 microop cho 'DIVPS/PS'. Các lệnh 'SQRT' sẽ giống nhau. Kể từ khi đơn vị phân chia không được pipelined, thực hiện mất 2x dài hơn. Điều này chỉ ra rằng Sandy Bridge thực sự chỉ có 128-bit thực hiện của đơn vị phân chia. –
@Norbert: cảm ơn vì đã làm rõ - Tôi không biết rằng –