SSE векторизация математической функции 'pow' gcc - PullRequest
10 голосов
/ 03 августа 2011

Я пытался векторизовать цикл, содержащий использование функции 'pow' в математической библиотеке. Я знаю, что компилятор Intel поддерживает использование 'pow' для инструкций sse - но я не могу заставить его работать с gcc (я думаю). Это тот случай, с которым я работаю:

int main(){
        int i=0;
        float a[256],
        b[256];

        float x= 2.3;


        for  (i =0 ; i<256; i++){
                a[i]=1.5;
        }

        for (i=0; i<256; i++){
                b[i]=pow(a[i],x);
        }

        for (i=0; i<256; i++){
                b[i]=a[i]*a[i];
        }
    return 0;

}

Я собираю следующее:

gcc -O3 -Wall -ftree-vectorize -msse2 -ftree-vectorizer-verbose=5 code.c -o runthis

Это на OS X 10.5.8 с использованием gcc версии 4.2 (я также использовал 4.5 и не мог сказать, что-нибудь векторизовал - так как он вообще ничего не выводил). Похоже, что ни один из циклов не векторизован - есть проблема с выравниванием или какая-то другая проблема, которую мне не нужно использовать restrict? Если я напишу один из циклов как функцию, я получу более подробный вывод (код):

void pow2(float *a, float * b, int n) {
        int i;
        for (i=0; i<n; i++){
                b[i]=a[i]*a[i];
        }
}
Вывод

(с использованием подробного вывода уровня 7):

note: not vectorized: can't determine dependence between *D.2878_13 and *D.2877_8
bad data dependence.

Я посмотрел на страницу auto-vectorization *1013* gcc, но это не очень помогло. Если невозможно использовать pow в gcc-версии, что я могу найти в ресурсе для выполнения функции, эквивалентной pow (я в основном имею дело с целочисленными степенями).

Редактировать так что я просто копался в другом источнике - как он это векторизовал?!:

void array_op(double * d,int len,double value,void (*f)(double*,double*) ) { 
    for ( int i = 0; i < len; i++ ){
        f(&d[i],&value);
    }
};

Соответствующий вывод gcc:

note: Profitability threshold is 3 loop iterations.

note: LOOP VECTORIZED.

Ну, теперь я в растерянности - 'd' и 'value' модифицируются функцией, о которой gcc не знает - странно? Может быть, мне нужно проверить эту часть более тщательно, чтобы убедиться, что результаты верны для векторизованной части. Все еще ищете векторизованную математическую библиотеку - почему нет открытых библиотек?

Ответы [ 2 ]

5 голосов
/ 03 августа 2011

Это не совсем ответ на ваш вопрос;а скорее предложение о том, как можно было бы полностью избежать этой проблемы.

Вы упоминаете, что используете OS X;на этой платформе уже есть API-интерфейсы, которые обеспечивают операции, которые вы просматриваете, без необходимости автоматической векторизации.Есть ли какая-то причина, по которой вы их не используете?Автоматическая векторизация - это действительно круто, но она требует некоторой работы, и в целом она не дает результатов, которые так же хороши, как использование API, уже векторизованных для вас.

#include <string.h>
#include <Accelerate/Accelerate.h>

int main() {

    int n = 256;
    float a[256],
    b[256];

    // You can initialize the elements of a vector to a set value using memset_pattern:
    float threehalves = 1.5f;
    memset_pattern4(a, &threehalves, 4*n);

    // Since you have a fixed exponent for all of the base values, we will use
    // the vImage gamma functions.  If you wanted to have different exponents
    // for each input (i.e. from an array of exponents), you would use the vForce
    // vvpowf( ) function instead (also part of Accelerate).
    //
    // If you don't need full accuracy, replace kvImageGamma_UseGammaValue with
    // kvImageGamma_UseGammaValue_half_precision to get better performance.
    GammaFunction func = vImageCreateGammaFunction(2.3f, kvImageGamma_UseGammaValue, 0);
    vImage_Buffer src = { .data = a, .height = 1, .width = n, .rowBytes = 4*n };
    vImage_Buffer dst = { .data = b, .height = 1, .width = n, .rowBytes = 4*n };
    vImageGamma_PlanarF(&src, &dst, func, 0);
    vImageDestroyGammaFunction(func);

    // To simply square a instead, use the vDSP_vsq function.
    vDSP_vsq(a, 1, b, 1, n);

    return 0;
}

В целом, если только выАлгоритм довольно прост, автоматическая векторизация вряд ли даст отличные результаты.По моему опыту, спектр методов векторизации обычно выглядит примерно так:

better performance                                            worse performance
more effort                                                         less effort
+------+------+----------------------+----------------------------+-----------+
|      |      |                      |                            |           |
|      |  use vectorized APIs        |                   auto vectorization   |
|  skilled vector C                  |                              scalar code
hand written assembly       unskilled vector C
5 голосов
/ 03 августа 2011

Использование __restrict или использование входных данных (присвоение локальных переменных) перед записью выходных данных должно помочь.

Как и сейчас, компилятор не может векторизовать, потому что a может иметь псевдоним b, что делает 4параллельное умножение и обратная запись значений 4 может быть неправильным.

(Обратите внимание, что __restrict не гарантирует, что компилятор векторизуется, но так много можно сказать, что прямо сейчас он уверен, что не может).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...