2013-12-13 3 views
1

나는 여러 번 실행 루프를 가지고 있고, 많은 시간을 비용 :루프 사용 SSE에서이 문제를 최적화 할 수있는 사람이 있습니까?

이 코드를 최적화 한
for (int z=0; z<temp; z++) 
{ 
    float findex= a + b * A[z]; 
    int iindex = findex ; 
    outArray[z] += inArray[iindex] + (findex - iindex) * (inArray[iindex+1] - inArray[iindex]); 
    a++; 
} 

하지만, 더 성능 향상이 없습니다! 어쩌면 내 SSE 코드가 좋지 않을 수도 있습니다.

+0

무엇이 수행되는지 알려주십시오. A가 무엇입니까? 어셈블리 출력에서 ​​확인 했습니까? – Marco

+1

'z ++'을'++ z'로 바꾸는 것은 좋은 생각입니다. – user2485710

+2

@ user2485710 : 왜 다른 점이 있습니까? –

답변

3

restrict 키워드를 inArray 및 outArray에서 사용해보십시오. 그렇지 않으면 컴파일러는 inArray이 == outArray 일 수 있다고 가정해야합니다. 이 경우 병렬화가 불가능합니다.

+0

안녕하세요, 회신 해 주셔서 감사합니다. for 루프 외부에서 멀티 쓰레드를 사용하고 있으므로 병렬화를 사용할 필요가 없다고 생각합니다. 원래 프로그램은 조금 복잡하므로 for 루프를 단순화했습니다. simd를 사용하여 루프를 최적화하고 싶습니다. sse와 함께 성능 imorove가있을 수 있습니다! – myej

+2

"restrict"키워드를 사용하면 컴파일러가 inArray 및 outArray의 모호성을 제거하여 루프를 자동 또는 반자동으로 벡터화 할 수 있습니다. (그리고 저는 Kay가 명령 수준 병렬화 (즉, 벡터화)를 의미한다고 생각합니다. 그러나 1.disambiguation은 루프를 효율적으로 벡터화하는 데 충분하지 않습니다. 아래에 언급 된 다른 것들처럼, 당신은 또한 교차 반복 종속성을 해결하고 3. 유닛 스트라이드 (연속적인) 메모리 액세스를 생각해야합니다. 일단 컴파일이 끝나면 컴파일러가 자동 벡터화 할 수 있어야합니다 (인텔 컴파일러의 경우 #pragma simd 또는 # pragma ivdep를 시도 할 수도 있음) – zam

3

루프는 outArray[z]에 쓸 때 루프 종속성이 있습니다. CPU가 한 번에 두 개 이상의 부동 소수점 합을 처리 할 수 ​​있지만 현재 루프에서는 outArray[z]의 합계 만 허용됩니다. 이 문제를 해결하려면 루프를 해제해야합니다. SIMD의 측면에서

for (int z=0; z<temp; z+=2) { 
    float findex_v1 = a + b * A[z]; 
    int iindex_v1 = findex_v1; 
    outArray[z] += inArray[iindex_v1] + (findex_v1 - iindex_v1) * (inArray[iindex_v1+1] - inArray[iindex_v1]); 

    float findex_v2 = (a+1) + b * A[z+1]; 
    int iindex_v2 = findex_v2; 
    outArray[z+1] += inArray[iindex_v2] + (findex_v2 - iindex_v2) * (inArray[iindex_v2+1] - inArray[iindex_v2]); 
    a+=2; 
} 

문제는 당신이 inArray[iindex_v1]에 액세스 할 때 비 연속 데이터를 수집해야한다는 것입니다. AVX2에는 수집 지침이 있지만 사용하지 않았습니다. 그렇지 않으면 SIMD없이 모임을하는 것이 가장 좋습니다. z에 액세스하는 모든 작업은 인접한 메모리에 액세스하므로 쉽게 작업 할 수 있습니다. 푸시 코드 (언 롤링하지 않음)는 다음과 같이 표시됩니다.

int indexa[4]; 
float inArraya[4]; 
float dinArraya[4]; 
int4 a4 = a + float4(0,1,2,3); 
for (int z=0; z<temp; z+=4) { 
    //use SSE for contiguous memory 
    float4 findex4 = a4 + b * float4.load(&A[z]); 
    int4 iindex4 = truncate_to_int(findex4); 

    //don't use SSE for non-contiguous memory 
    iindex4.store(indexa);  
    for(int i=0; i<4; i++) { 
     inArraya[i] = inArray[indexa[i]]; 
     dinArraya[i] = inArray[indexa[i+1]] - inArray[indexa[i]]; 
    } 
    //loading from and array right after writing to it causes a CPU stall 
    float4 inArraya4 = float4.load(inArraya); 
    float4 dinArraya4 = float4.load(dinArraya); 

    //back to SSE 
    float4 outArray4 = float4.load(&outarray[z]); 
    outArray4 += inArray4 + (findex4 - iindex4)*dinArray4; 
    outArray4.store(&outArray[z]); 
    a4+=4;  
}