2016-01-30 3 views
2

Я использую функцию ступенчатого разностного разностного разрыва 8-го порядка (для двумерного акустического волнового уравнения), показанного ниже.Местоположение процессора Intel __assume влияет на производительность

Я наблюдаю существенное (до 25%) увеличение производительности от размещения инструкции Intel __assume во внутреннем цикле, по сравнению с размещением ее в начале тела функции. (Это происходит независимо от количества потоков OpenMP).

Код компилируется компилятором Intel 2016-update1, Linux, с опцией оптимизации -O3 и для архитектуры с поддержкой AVX (Xeon E5-2695 v2).

Это проблема с компилятором?

/* Finite difference, 8-th order scheme for acoustic 2D equation. 
    p  - current pressure 
    q  - previous and next pressure 
    c  - velocity 
    n0 x n1 - problem size 
    p1  - stride 
*/ 

void fdtd_2d(float const* const __restrict__ p, 
       float  * const __restrict__ q, 
       float const* const __restrict__ c, 
       int   const    n0, 
       int   const    n1, 
       int   const    p1) 
{ 
    // Stencil coefficients. 
    static const float C[5] = { -5.6944444e+0f, 1.6000000e+0f, -2.0000000e-1f, 2.5396825e-2f, -1.7857143e-3f }; 

    // INTEL OPTIMIZER PROBLEM? 
    //  PLACING THE FOLLOWING LINE INSIDE THE LOOP BELOW 
    //  INSTEAD OF HERE SPEEDS UP THE CODE! 
    // __assume(p1 % 16 == 0); 

    #pragma omp parallel for default(none) 
    for (int i1 = 0; i1 < n1; ++i1) 
    { 
     float const* const __restrict__ ps = p + i1 * p1; 
     float  * const __restrict__ qs = q + i1 * p1; 
     float const* const __restrict__ cs = c + i1 * p1; 

     #pragma omp simd aligned(ps, qs, cs : 64) 
     for (int i0 = 0; i0 < n0; ++i0) 
     { 
      // INTEL OPTIMIZER PROBLEM? 
      //  PLACING THE FOLLOWING LINE HERE 
      //  INSTEAD OF THE ABOVE SPEEDS UP THE CODE! 
      __assume(p1 % 16 == 0); 

      // Laplacian cross stencil: 
      // center and 4 points up, down, left and right from the center 
      auto lap = C[0] * ps[i0]; 
      for (int r = 1; r <= 4; ++r) 
       lap += C[r] * (ps[i0 + r] + ps[i0 - r] + ps[i0 + r * p1] + ps[i0 - r * p1]); 

      qs[i0] = 2.0f * ps[i0] - qs[i0] + cs[i0] * lap; 
     } 
    } 
} 
+0

Является ли первый комментарий строго точным? Если вы раскомментировали '__assume' вне цикла, он бы замедлялся, даже если вы оставили' __assume' внутри цикла активным? И с тем, что в цикле прокомментировал, будет ли ранний '__assume' делать ваш код медленнее, чем без' __assume' вообще? Из текста это звучит не так, поэтому я думаю, что ваши комментарии «все-шапки», возможно, говорят «не помогают здесь», а «только помогает здесь, а не за пределами цикла», или что-то в этом роде. –

+0

@PeterCordes Да, я попытался разместить '__assume' либо сверху, либо внутри цикла, но не в обоих местах одновременно. – user2052436

+1

Работает ли этот код, и этот вопрос все еще случается с ICC13? Если это так, вы можете поместить свой код [на godbolt] (http://goo.gl/3nrETr). Я пробовал, но он не компилируется; может быть, есть компиляция, которую мне не хватает? В противном случае просто отредактируйте разборку для обеих версий в вопросе, чтобы мы могли видеть, какая разница в автообвещении. Конечно, это не скажет нам * почему * он не может оптимизировать, когда '__assume' выходит за рамки OpenMP-прагм, просто * как *. Более медленный случай, вероятно, просто испускает больше кода для обработки несоосности для 'r * p1'. –

ответ

1

Я указал на следующее на веб-сайте Intel:

Морозы, такие как __assume_aligned и __assume сказать компилятору, что свойство имеет место в определенный момент в программе, где появляется пункт. Таким образом, утверждение __assume_aligned (a, 64); означает, что указатель a выровнен на 64 байта, когда выполнение программы достигает этой точки. Компилятор может распространять это свойство на другие точки программы (например, на более поздний цикл), но это поведение не гарантируется (возможно, что компилятор должен сделать консервативные предположения и не может безопасно применять это свойство для более позднего цикла в той же функции).

Так что, когда я помещаю __assume в начале тела функции, предположение не распространяется на внутреннюю петлю, что приводит к менее оптимальный код.

Хотя, мое ожидание было разумным: поскольку p1 объявлен как const, компилятор мог распространить предположение.

Смежные вопросы