2012-09-28 2 views
2

C99의 성능에 대한 엄격한 앨리어싱의 영향을 이해하려고합니다. 내 목표는 내 프로그램에서 많은 시간을 차지하는 벡터 점 제품을 최적화하는 것입니다 (프로파일 링했습니다!). 나는 앨리어싱이 문제가 될 수 있다고 생각했지만 다음 코드는 표준 접근법과 엄격한 앨리어싱 버전 사이에 큰 차이를 보이지 않는다. 유사한 결과를 사용하여 앨리어싱을 피하기 위해 로컬 변수를 사용하려고했습니다.GCC C99에서 포인터의 엄격한 앨리어싱 예 성능 차이 없음

무슨 일입니까?

OSX 10.7.4에서 gcc-4.7을 사용하고 있습니다. 결과는 마이크로 초입니다.

$ /usr/local/bin/gcc-4.7 -fstrict-aliasing -Wall -std=c99 -O3 -o restrict restrict.c 
$ ./restrict 
sum: 100000000 69542 
sum2: 100000000 70432 
sum3: 100000000 70372 
sum4: 100000000 69891 
$ /usr/local/bin/gcc-4.7 -Wall -std=c99 -O0 -fno-strict-aliasing -o restrict restrict.c 
$ ./restrict 
sum: 100000000 258487 
sum2: 100000000 261349 
sum3: 100000000 258829 
sum4: 100000000 258129 

restrict.c (이 코드는 여러 백메가바이트 RAM이 필요합니다주의) : 커프 오프

#include <stdlib.h> 
#include <stdio.h> 
#include <time.h> 
#include <sys/time.h> 
#include <unistd.h> 

/* original */ 
long sum(int *x, int *y, int n) 
{ 
    long i, s = 0; 

    for(i = 0 ; i < n ; i++) 
     s += x[i] * y[i]; 

    return s; 
} 

/* restrict */ 
long sum2(int *restrict x, int *restrict y, int n) 
{ 
    long i, s = 0; 

    for(i = 0 ; i < n ; i++) 
     s += x[i] * y[i]; 

    return s; 
} 

/* local restrict */ 
long sum3(int *x, int *y, int n) 
{ 
    int *restrict xr = x; 
    int *restrict yr = y; 
    long i, s = 0; 

    for(i = 0 ; i < n ; i++) 
     s += xr[i] * yr[i]; 

    return s; 
} 

/* use local variables */ 
long sum4(int *x, int *y, int n) 
{ 
    int xr, yr; 
    long i, s = 0; 

    for(i = 0 ; i < n ; i++) 
    { 
     xr = x[i]; 
     yr = y[i]; 
     s += xr * yr; 
    } 

    return s; 
} 

int main(void) 
{ 
    struct timeval tp1, tp2; 
    struct timezone tzp; 

    long i, n = 1e8L, s; 
    int *x = malloc(sizeof(int) * n); 
    int *y = malloc(sizeof(int) * n); 
    long elapsed1; 

    for(i = 0 ; i < n ; i++) 
     x[i] = y[i] = 1; 

    gettimeofday(&tp1, &tzp); 
    s = sum(x, y, n); 
    gettimeofday(&tp2, &tzp); 
    elapsed1 = (tp2.tv_sec - tp1.tv_sec) * 1e6 
     + (tp2.tv_usec - tp1.tv_usec); 
    printf("sum:\t%ld\t%ld\n", s, elapsed1); 

    gettimeofday(&tp1, &tzp); 
    s = sum2(x, y, n); 
    gettimeofday(&tp2, &tzp); 
    elapsed1 = (tp2.tv_sec - tp1.tv_sec) * 1e6 
     + (tp2.tv_usec - tp1.tv_usec); 
    printf("sum2:\t%ld\t%ld\n", s, elapsed1); 

    gettimeofday(&tp1, &tzp); 
    s = sum3(x, y, n); 
    gettimeofday(&tp2, &tzp); 
    elapsed1 = (tp2.tv_sec - tp1.tv_sec) * 1e6 
     + (tp2.tv_usec - tp1.tv_usec); 
    printf("sum3:\t%ld\t%ld\n", s, elapsed1); 

    gettimeofday(&tp1, &tzp); 
    s = sum3(x, y, n); 
    gettimeofday(&tp2, &tzp); 
    elapsed1 = (tp2.tv_sec - tp1.tv_sec) * 1e6 
     + (tp2.tv_usec - tp1.tv_usec); 
    printf("sum4:\t%ld\t%ld\n", s, elapsed1); 

    return EXIT_SUCCESS; 
} 

답변

1

: 엄격한 앨리어싱 규칙

  • , 컴파일러 을 아마도은 의도 한 것과 약간 다른 작업을 수행하는 최적화 된 코드를 생성하기 만하면됩니다.

  • 엄격한 앨리어싱 규칙을 사용하지 않도록 설정하면 코드가 빨라지는 것은 아닙니다.

  • 만약 그렇다면, 그것은 의도 아닌 최적화 된 코드가 실제로 다른 결과를 보여 주어진. 이것은 실제 데이터 액세스 패턴에 의존하고 종종 프로세서/캐시 아키텍처에도 영향을 미칩니다. 귀하의 예제 코드에 대해서는

, 그 앨리어싱은 말할 것 관련이없는 (방출 코드, 적어도)에 sumXXX 내부 배열 요소에 대한 쓰기 권한이 결코 없기 때문에 기능.

동일한 벡터를 두 번 통과하면 성능이 약간 향상 될 수 있습니다. 핫 캐시와 더 작은 캐시 풋 프린트로 인해 많은 이익이 발생할 수 있습니다. 프리 페치 예측기를 오프로드하는 중복로드로 인해 패널티가 발생할 수 있습니다. . 언제나처럼 추적 : 는 프로파일)

+1

sehe 더 쓰기 권한이 없기 때문에이 경우에는 무관하다 앨리어싱 앱솔루트 권리를 사용합니다. 혹시 별칭 문제가 있는지 알고 싶다면 esp라는 어셈블러 출력을 살펴 봐야합니다. 로드 및 저장합니다. – flolo