2014-11-20 5 views
3

Я не понимаю, почему такой код не векторизаций с GCC 4.4.6НКУ авто-векторизация (необработанные данные ссылок)

int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex) 
{ 
    for (int i = 0; i < iSize; i++) 
    pfResult[i] = pfResult[i] + pfTab[iIndex]; 
} 

note: not vectorized: unhandled data-ref 

Однако, если я пишу следующий код

int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex) 
{ 
    float fTab = pfTab[iIndex]; 
    for (int i = 0; i < iSize; i++) 
    pfResult[i] = pfResult[i] + fTab; 
} 

НКУ преуспевает автоматического Vectorize этот цикл

если добавить директиву OMP

int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex) 
{ 
    float fTab = pfTab[iIndex]; 
    #pragma omp parallel for 
    for (int i = 0; i < iSize; i++) 
    pfResult[i] = pfResult[i] + fTab; 
} 

У меня есть следующая погрешность: нет необработанных данных-ref

Не могли бы вы помочь мне, почему первый код и третий код не авто-векторизованы?

Второго вопрос: математика операнд, кажется, не векторизации (ехр, журнал, и т.д. ...), этот код, например

for (int i = 0; i < iSize; i++) 
     pfResult[i] = exp(pfResult[i]); 

не векторизации. Это из-за моей версии gcc?

Edit: с новой версией GCC 4.8.1 и OpenMP 2011 (эхо | касты -fopenmp -dM | Grep -i открыть) я имею следующую ошибку для всех видов петли даже в основном

for (iGID = 0; iGID < iSize; iGID++) 
     { 
      pfResult[iGID] = fValue; 
     } 


note: not consecutive access *_144 = 5.0e-1; 
note: Failed to SLP the basic block. 
note: not vectorized: failed to find SLP opportunities in basic block. 

Edit2:

#include<stdio.h> 
#include<sys/time.h> 
#include <string.h> 
#include <math.h> 
#include <stdlib.h> 
#include <omp.h> 

int main() 
{ 
     int szGlobalWorkSize = 131072; 
     int iGID = 0; 
     int j = 0; 
     omp_set_dynamic(0); 
     // warmup 
     #if WARMUP 
     #pragma omp parallel 
     { 
     #pragma omp master 
     { 
     printf("%d threads\n", omp_get_num_threads()); 
     } 
     } 
     #endif 
     printf("Pagesize=%d\n", getpagesize()); 
     float *pfResult = (float *)malloc(szGlobalWorkSize * 100* sizeof(float)); 
     float fValue = 0.5f; 
     struct timeval tim; 
     gettimeofday(&tim, NULL); 
     double tLaunch1=tim.tv_sec+(tim.tv_usec/1000000.0); 
     double time = omp_get_wtime(); 
     int iChunk = getpagesize(); 
     int iSize = ((int)szGlobalWorkSize * 100)/iChunk; 
     //#pragma omp parallel for 
     for (iGID = 0; iGID < iSize; iGID++) 
     { 
      pfResult[iGID] = fValue; 
     } 
     time = omp_get_wtime() - time; 
     gettimeofday(&tim, NULL); 
     double tLaunch2=tim.tv_sec+(tim.tv_usec/1000000.0); 
     printf("%.6lf Time1\n", tLaunch2-tLaunch1); 
     printf("%.6lf Time2\n", time); 
} 

результат с

#define _OPENMP 201107 
gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-15) 

gcc -march=native -fopenmp -O3 -ftree-vectorizer-verbose=2 test.c -lm 

много

note: Failed to SLP the basic block. 
note: not vectorized: failed to find SLP opportunities in basic block. 
and note: not consecutive access *_144 = 5.0e-1; 

Благодарности

+0

Первым делом стоит попробовать более новую версию gcc. Тогда поймите, что без «ограничения» векторизация может быть неправильной. И добавьте -ffast-math, потому что компилятор в противном случае испугался. Для exp и log я уверен, что видел связанные вопросы о SO. В принципе, вам понадобится библиотека, которая предоставляет векторные версии exp и log, так что gcc может генерировать вызовы к ним. –

+0

Scratch мой предыдущий комментарий, почему вы не используете 'i' в своих циклах ??? –

+0

спасибо большое Я уже пробовал с '__restrict__' и const, и результат тот же Я попробую с более новой версией gcc извините за цикл typo – parisjohn

ответ

7

GCC не vectorise первой версии цикла, поскольку он не может доказать, что pfTab[iIndex] не содержится где-то в памяти, натянутой на pfResult[0] ... pfResult[iSize-1] (указатель псевдонимов). Действительно, если pfTab[iIndex] находится где-то внутри этой памяти, тогда его значение должно быть перезаписано назначением в теле цикла, а новое значение должно использоваться в последующих итерациях. Вы должны использовать restrict ключевое слово, чтобы намекнуть на компилятор, что это никогда не случится, и тогда он должен счастливо vectorise код:

$ cat foo.c 
int MyFunc(const float *restrict pfTab, float *restrict pfResult, 
      int iSize, int iIndex) 
{ 
    for (int i = 0; i < iSize; i++) 
    pfResult[i] = pfResult[i] + pfTab[iIndex]; 
} 
$ gcc -v 
... 
gcc version 4.6.1 (GCC) 
$ gcc -std=c99 -O3 -march=native -ftree-vectorizer-verbose=2 -c foo.c 
foo.c:3: note: LOOP VECTORIZED. 
foo.c:1: note: vectorized 1 loops in function. 

Второй вариант vectorises, так как значение передается переменной с автоматической продолжительности хранения. Общее предположение здесь состоит в том, что pfResult не распространяется на память стека, где хранится fTab (беглое чтение спецификации языка C99 не дает понять, слабо ли это предположение или что-то в стандарте допускает).

Версия OpenMP не указывает на то, что OpenMP реализован в GCC. Он использует код, обозначающий параллельные области.

int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex) 
{ 
    float fTab = pfTab[iIndex]; 
    #pragma omp parallel for 
    for (int i = 0; i < iSize; i++) 
    pfResult[i] = pfResult[i] + fTab; 
} 

фактически становится:

struct omp_data_s 
{ 
    float *pfResult; 
    int iSize; 
    float *fTab; 
}; 

int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex) 
{ 
    float fTab = pfTab[iIndex]; 
    struct omp_data_s omp_data_o; 

    omp_data_o.pfResult = pfResult; 
    omp_data_o.iSize = iSize; 
    omp_data_o.fTab = fTab; 

    GOMP_parallel_start (MyFunc_omp_fn0, &omp_data_o, 0); 
    MyFunc._omp_fn.0 (&omp_data_o); 
    GOMP_parallel_end(); 
    pfResult = omp_data_o.pfResult; 
    iSize = omp_data_o.iSize; 
    fTab = omp_data_o.fTab; 
} 

void MyFunc_omp_fn0 (struct omp_data_s *omp_data_i) 
{ 
    int start = ...; // compute starting iteration for current thread 
    int end = ...; // compute ending iteration for current thread 

    for (int i = start; i < end; i++) 
    omp_data_i->pfResult[i] = omp_data_i->pfResult[i] + omp_data_i->fTab; 
} 

MyFunc_omp_fn0 содержит структурированную код функции. Компилятор не может доказать, что omp_data_i->pfResult не указывает на память, что псевдонимы omp_data_i и, в частности, его член fTab.

Для того, чтобы обозначить этот цикл, вы должны сделать fTabfirstprivate. Это превратит его в автоматическую переменную в выделенном коде, и это будет эквивалентно вашему второму случаю:

$ cat foo.c 
int MyFunc(const float *pfTab, float *pfResult, int iSize, int iIndex) 
{ 
    float fTab = pfTab[iIndex]; 
    #pragma omp parallel for firstprivate(fTab) 
    for (int i = 0; i < iSize; i++) 
    pfResult[i] = pfResult[i] + fTab; 
} 
$ gcc -std=c99 -fopenmp -O3 -march=native -ftree-vectorizer-verbose=2 -c foo.c 
foo.c:6: note: LOOP VECTORIZED. 
foo.c:4: note: vectorized 1 loops in function. 
+0

спасибо много !!! – parisjohn