2016-06-01 4 views
1

내 코드에서 일부 최적화를 수행하고 있습니다. 우선 OpenMP로 병렬 프로그래밍을 진행했습니다. 그런 다음 GNU GCC 컴파일러가 제공하는 최적화 플래그를 사용했습니다. 또한 역 제곱근을 계산하는 SSE 명령도 포함되었습니다. 하지만 마지막으로 문제는 각 스레드가 결과를 축소 변수에 쓸 때 마지막 작업이 ~ 80 %의 시간이 걸린다는 것입니다. 여기서 병렬 루프 :OpenMP에서 감소가 매우 느림

rsqrtSSE()을 기반으로 __mm_rsqrt_ps 함수 (__ M128의 X) xmmintrin.h의 소정 함수가
time(&t5); 
# pragma omp parallel for shared(NTOT) private(dx,dy,d,H,V,E,F,G,K) reduction(+:dU) 
for(j = 1; j <= NTOT; j++){ 
    if(!(j-i)) continue; 
    dx = (X[2*j-2]-X[2*i-2])*a; 
    dy = (X[2*j-1]-X[2*i-1])*a; 
    d = rsqrtSSE(dx*dx+dy*dy); 
    H = D*d*d*d; 
    V = dS[0]*spin[2*j-2]+dS[1]*spin[2*j-1]; 
    E = dS[0]*dx+dS[1]*dy; 
    F = spin[2*j-2]*dx+spin[2*j-1]*dy; 
    G = -3*d*d*E*F; 
    K = H*(V+G); 
    dU += K; 
} 
time(&t6); 
t_loop = difftime(t6, t5); 

. 이 문제를 해결할 수있는 해결책이 있다면? 또는 이것은 대역폭 제한 때문입니까?

은 내가 GCC -o 음식물을 prog.c -lm -fopenmp -03 컴파일 - ffast - 수학 -march = 네이티브 여기

내 컴퓨터에 대한 몇 가지 정보를 정기적으로 : 아키텍처 : (x86_64의 CPU 연산 모드의) : 32 비트, 64 비트 바이트 순서 : 리틀 엔디안 CPU : 4 온라인 CPU 목록 : 0-3 코어 당 스레드 : 2 코어 당 소켓 : 2 소켓 : 1 NUMA 노드 : 1 공급 업체 ID : GenuineIntel CPU 제품군 : 6 모델 : 69 01 23,516,모델명 : 인텔 (R) 코어 (TM) i5-4200U CPU에서 @의 1.60GHz 스테핑 1 CPU 메가 헤르츠 : 849.382 CPU 최대 메가 헤르츠 : 800.0000 밉스 : 4589.17 가상화 : VT-X MHz의 분 2600.0000 CPU L1D 캐쉬 : 32K L1i 캐시 : 32K L2 캐시 : 256K L3 캐시 : 3072K NUMA의 node0의 CPU (들) : CPU Avg_MHz %의 바쁜 Bzy_MHz의 TSC_MHz - 2,294 99.97 :

및 turboboost와 0-3 2300 2295 0 2295 100.00 2300 2295 1 2295 100.00 2300 2295 2 2292 99.87 2300 2295 3 2295 100.00 2300 2295

+0

기타 좋은 질문이 몇 가지 빠져 있습니다. 마지막 라인이 80 %의 시간을 소비한다고 어떻게 결정 했습니까? 실제로 여러 스레드를 고려할 때는 시간이 무엇을 의미합니까? 하나의 스레드 VS의 성능은 무엇입니까? 듀얼 코어 시스템에 두 개의 스레드가 있습니까? 'NTOT '는 얼마나 큰가요? 일반적으로 [mcve]는 귀하의 질문에 실질적으로 답변 할 수 있도록 많은 도움을줍니다. – Zulan

+0

나는 time_t 유형 (시간차를 쓰는 것)을 사용하는 것이 NTOT = 6400이고 크기가 6400X1000 인 다른 루프가 있다는 것을 알았습니다. 이 루프에서 경과 된 시간은 dU + = K 인 경우 160 초이고이 시간이없는 경우는 30 초입니다. 전체 코드를 작성할 수 없습니다. 그것은 372 라인입니다. 코어 당 2 개의 스레드이기 때문에 4 개의 스레드를 사용할 수 있습니다. 물론 2는 1과 4보다 2보다 좋습니다. –

+0

편집 : dU + = K 없이는 10 초 미만입니다 –

답변

1

측정에 결함이 있습니다.

첫 번째 방법은 선을 모두 제거하기 때문에 결과가 사용되지 않기 때문에 컴파일러가 대부분의 계산을 최적화 할 수 있습니다.

두 번째 방법은 올바르게 이해하면 루프 내부에 타이밍 instructins을 삽입하는 것입니다. 전/후 dU += K. 불행히도 이것은 또한 시시한 결과를 낳을 희망이 없습니다. 라이브러리 타이밍 호출은이 작업보다 magintune의 순서가 느립니다. 그래서 당신은 기본적으로 시간을받는 데 걸리는 시간을 측정합니다. 여러 타이밍 호출을 반복하고 차이를 비교하여이를 시도 할 수 있습니다.

what I have seen에서 OpenMP 구현은 루프가 완료된 후에 만 ​​dU을 스레드 개인 변수로 유지하고 루프가 완료된 후에 만 ​​원자/잠금 작동을 줄일 수있을 것으로 생각됩니다.

개별 라인의 성능을 결정하는 더 좋은 방법은 샘플링을 사용하는 것입니다. 리눅스 용 perf 도구를 살펴보면 매우 유용 할 수 있습니다. 편견이있을 수 있기 때문에 결과가 항상 완벽하게 신뢰할 수있는 것은 아닙니다. 컴파일러 최적화 (예 : 언 롤링) 및 하드웨어 최적화 (예 : 파이프 라이닝)로 인해 여러 줄의 코드가 동시에 실행 상태에있을 수 있습니다.한 줄의 코드가 얼마나 많은 시간을 소비하는지 말하는 것은 매우 어려운 질문이됩니다.

문제가 있는지 알아 보는 한 가지 방법은 이론적 인 하드웨어 성능을 파악하는 것입니다. __mm_rsqrt_ps에 대해서는 어려워 보입니다. 하드웨어 성능 카운터를 살펴보고 많은 캐시 미스가 있는지 확인할 수도 있습니다. perf도 도움이됩니다.

+0

답변 주셔서 감사합니다. 이미 설치된 리눅스 도구가 있지만 perf 사용하는 방법을 모르겠습니다. 거기에 설명 할 튜토리얼이 있습니까? –

+0

apic_timer_interupt 22 %. 이게 너에게 의미가 있니? –

+0

두 가지를 검색하는 것보다 나은 것은 아무것도 없습니다. – Zulan