OpenMP 및 SIMD를 사용하여 배열 축소를 수행하려고합니다. 나는 다음과 링크에서이 아이디어를 가지고SSE/AVX가있는 OpenMP에서의 감소
inline float sum_scalar_openmp2(const float a[], const size_t N) {
float sum = 0.0f;
#pragma omp parallel
{
float sum_private = 0.0f;
#pragma omp parallel for nowait
for(int i=0; i<N; i++) {
sum_private += a[i];
}
#pragma omp atomic
sum += sum_private;
}
return sum;
}
: http://bisqwit.iki.fi/story/howto/openmp/#ReductionClause 을하지만 원자는 복잡한 연산자를 지원하지 않습니다 난에 OpenMP의 감소가 동등 읽어 보시기 바랍니다. 내가 한 일은 중요와 원자 대체했고이 같은 OpenMP를하고 SSE와 감소를 구현 :
#define ROUND_DOWN(x, s) ((x) & ~((s)-1))
inline float sum_vector4_openmp(const float a[], const size_t N) {
__m128 sum4 = _mm_set1_ps(0.0f);
#pragma omp parallel
{
__m128 sum4_private = _mm_set1_ps(0.0f);
#pragma omp for nowait
for(int i=0; i < ROUND_DOWN(N, 4); i+=4) {
__m128 a4 = _mm_load_ps(a + i);
sum4_private = _mm_add_ps(a4, sum4_private);
}
#pragma omp critical
sum4 = _mm_add_ps(sum4_private, sum4);
}
__m128 t1 = _mm_hadd_ps(sum4,sum4);
__m128 t2 = _mm_hadd_ps(t1,t1);
float sum = _mm_cvtss_f32(t2);
for(int i = ROUND_DOWN(N, 4); i < N; i++) {
sum += a[i];
}
return sum;
}
그러나,이 기능뿐만 아니라 내가 희망대로 작동하지 않습니다. Visual Studio 2012 Express를 사용하고 있습니다. SSE로드를 풀어서 성능을 조금 향상시킬 수 있다는 것을 알고 있습니다.하지만 몇 번 추가해도 여전히 예상보다 적습니다.
내가 스레드의 수와 동일한 배열의 슬라이스에 걸쳐 실행하여 더 나은 성능을 얻을 : 더 복잡와 감축을하는 더 나은 방법이 있는지
inline float sum_slice(const float a[], const size_t N) {
int nthreads = 4;
const int offset = ROUND_DOWN(N/nthreads, nthreads);
float suma[8] = {0};
#pragma omp parallel for num_threads(nthreads)
for(int i=0; i<nthreads; i++) {
suma[i] = sum_vector4(&a[i*offset], offset);
}
float sum = 0.0f;
for(int i=0; i<nthreads; i++) {
sum += suma[i];
}
for(int i=nthreads*offset; i < N; i++) {
sum += a[i];
}
return sum;
}
inline float sum_vector4(const float a[], const size_t N) {
__m128 sum4 = _mm_set1_ps(0.0f);
int i = 0;
for(; i < ROUND_DOWN(N, 4); i+=4) {
__m128 a4 = _mm_load_ps(a + i);
sum4 = _mm_add_ps(sum4, a4);
}
__m128 t1 = _mm_hadd_ps(sum4,sum4);
__m128 t2 = _mm_hadd_ps(t1,t1);
float sum = _mm_cvtss_f32(t2);
for(; i < N; i++) {
sum += a[i];
}
return sum;
}
사람은 알고 있나요 OpenMP의 연산자?
테스트를 수행하는 데 사용하는 N의 크기는 무엇입니까? – veda
N (L1) = 32k, N (L2) = 256K, N (L3/4) = 2M 및 N >> N (L3)의 캐시 크기에 대한 테스트를 수행합니다. –