왜 0.1f를 0으로 바꾸면 10배쯤 느려질까요?

조회수 3918회

비주얼 스튜디오 2010 SP1에서 실행했을 때 소스코드1이 소스코드2보다 10배쯤 빠르게 동작합니다.

실제로 바뀌는 부분은 딱 두줄이고 제가 보기엔 별 차이도 없는 것 같은데 왜 퍼포먼스는 이렇게 달라지나요?

소스코드1

const float x[16] = {  1.1,   1.2,   1.3,     1.4,   1.5,   1.6,   1.7,   1.8,
                       1.9,   2.0,   2.1,     2.2,   2.3,   2.4,   2.5,   2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
                     1.923, 2.034, 2.145,   2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
    y[i] = x[i];
}

for (int j = 0; j < 9000000; j++)
{
    for (int i = 0; i < 16; i++)
    {
        y[i] *= x[i];
        y[i] /= z[i];
        y[i] = y[i] + 0.1f; // <--
        y[i] = y[i] - 0.1f; // <--
    }
}

소스코드2

const float x[16] = {  1.1,   1.2,   1.3,     1.4,   1.5,   1.6,   1.7,   1.8,
                       1.9,   2.0,   2.1,     2.2,   2.3,   2.4,   2.5,   2.6};
const float z[16] = {1.123, 1.234, 1.345, 156.467, 1.578, 1.689, 1.790, 1.812,
                     1.923, 2.034, 2.145,   2.256, 2.367, 2.478, 2.589, 2.690};
float y[16];
for (int i = 0; i < 16; i++)
{
    y[i] = x[i];
}

for (int j = 0; j < 9000000; j++)
{
    for (int i = 0; i < 16; i++)
    {
        y[i] *= x[i];
        y[i] /= z[i];
        y[i] = y[i] + 0; // <--
        y[i] = y[i] - 0; // <--
    }
}

1 답변

  • 좋아요

    0

    싫어요
    채택 취소하기

    denormalized floating-point와 관련있는 문제네요.

    alt text

    그림에서 빨간색이 normalized number, 파란색이 denormalized number입니다. denormalized number0floating-point사이의 갭을 메우고 있습니다. 즉, 가장 작은 normalized number보다 더 작은, 하지만 0은 아닌 숫자 전체를 denormalized/subnormal number라고 하지요.

    denormalized floating-point에 연산을 하는 건 normalized floating-point에 연산을 하는 것 보다 수 백배 느릴 수도 있습니다. 대부분의 프로세서가 denormalized fp를 직접 처리할 수 없어 trap이 발생하고 microcode를 이용해 이를 하드웨어적으로 해결하기 때문입니다.

    다음 코드를 x64환경에서 코드를 실행해보면

    int main() {
    
        double start = omp_get_wtime();
    
        const float x[16]={1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0,2.1,2.2,2.3,2.4,2.5,2.6};
        const float z[16]={1.123,1.234,1.345,156.467,1.578,1.689,1.790,1.812,1.923,2.034,2.145,2.256,2.367,2.478,2.589,2.690};
        float y[16];
        for(int i=0;i<16;i++)
        {
            y[i]=x[i];
        }
        for(int j=0;j<9000000;j++)
        {
            for(int i=0;i<16;i++)
            {
                y[i]*=x[i];
                y[i]/=z[i];
    #ifdef FLOATING
                y[i]=y[i]+0.1f;
                y[i]=y[i]-0.1f;
    #else
                y[i]=y[i]+0;
                y[i]=y[i]-0;
    #endif
    
                if (j > 10000)
                    cout << y[i] << "  ";
            }
            if (j > 10000)
                cout << endl;
        }
    
        double end = omp_get_wtime();
        cout << end - start << endl;
    
        system("pause");
        return 0;
    }
    

    결과 :

    #define FLOATING
    1.78814e-007  1.3411e-007  1.04308e-007  0  7.45058e-008  6.70552e-008  6.70552e-008  5.58794e-007  3.05474e-007  2.16067e-007  1.71363e-007  1.49012e-007  1.2666e-007  1.11759e-007  1.04308e-007  1.04308e-007
    1.78814e-007  1.3411e-007  1.04308e-007  0  7.45058e-008  6.70552e-008  6.70552e-008  5.58794e-007  3.05474e-007  2.16067e-007  1.71363e-007  1.49012e-007  1.2666e-007  1.11759e-007  1.04308e-007  1.04308e-007
    
    //#define FLOATING
    6.30584e-044  3.92364e-044  3.08286e-044  0  1.82169e-044  1.54143e-044  2.10195e-044  2.46842e-029  7.56701e-044  4.06377e-044  3.92364e-044  3.22299e-044  3.08286e-044  2.66247e-044  2.66247e-044  2.24208e-044
    6.30584e-044  3.92364e-044  3.08286e-044  0  1.82169e-044  1.54143e-044  2.10195e-044  2.45208e-029  7.56701e-044  4.06377e-044  3.92364e-044  3.22299e-044  3.08286e-044  2.66247e-044  2.66247e-044  2.24208e-044
    

    2번째 run에서는 숫자들이 0에 매우 가까운 것을 확인할 수 있지요. Denormalized number는 그 수가 엄청 적기 때문에 대부분의 프로세서가 효율적으로 처리할 수가 없어 이런 차이가 생깁니다.

    denormalized number0으로 처리하게 만들려면 다음 코드를 추가하세요 그럼 더 이상 코드가 10배 느려지는 일이 없어질 겁니다.

    _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); *단, SSE가 활성화된 상태에서 compile 해야 합니다

    Core i7 920 @ 3.5 GHz에서 실험:

    //  `denormal`을 0으로 처리하지 않는 경우
    0.1f: 0.564067
    0   : 26.7669
    
    //  0으로 처리한 경우
    0.1f: 0.587117
    0   : 0.341406
    

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)