OpenMP плохая производительность с ложным разделением

Я знаю что существует эта тема
производительность openMP

но здесь мой пример очень прост

Код C:

int MaFunc(size_t szGlobalWorkSize)
{
int iGID = 0;
float *pfResult = (float *)calloc(szGlobalWorkSize * 100, sizeof(float));
float fValue = 0.5f;
struct timeval tim;
gettimeofday(&tim, NULL);
double tLaunch1=tim.tv_sec+(tim.tv_usec/1000000.0);

#pragma omp parallel for
for (iGID = 0; iGID < (int)szGlobalWorkSize * 100; iGID++)
{
pfResult[iGID] = fValue;
// printf("Element %d traité par le thread %d \n",iGID,omp_get_thread_num());
}
gettimeofday(&tim, NULL);
double tLaunch2=tim.tv_sec+(tim.tv_usec/1000000.0);
printf("%.6lf Time OMP\n", tLaunch2-tLaunch1);
}

Время этого примера увеличивается, когда я использую openMP
0,015 с без OpenMP против 0,045 с с OpenMP (szGlobalworkSize = 131072)

Я использую эту строку GCC:
gcc -march = native -fopenmp -O3 MyCode.c -lm

gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-15)

Edit1:

int MyFunc2()
{
int iGID = 0;
int j = 0;
//float *pfResult = (float *)calloc(szGlobalWorkSize * 100, sizeof(float));
float *pfResult = (float *)valloc(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
#pragma omp parallel for
for (iGID = 0; iGID < iSize; iGID++)
{
for (j = 0; j < iChunk; j++)
{

pfResult[iGID * iChunk + j] = fValue;
//pfResult[iGID] = fValue;
}
// printf("Element %d traité par le thread %d \n",iGID,omp_get_thread_num());
}
time = omp_get_wtime() - time;
gettimeofday(&tim, NULL);
double tLaunch2=tim.tv_sec+(tim.tv_usec/1000000.0);
printf("%.6lf Time OMP\n", tLaunch2-tLaunch1);
printf("Pagesize=%d\n", getpagesize());
printf("%.6lf Time OMP2\n", time);
}

также то же самое время с куском с Memalign

Редактировать 2 с синхронизацией по теме

#pragma omp parallel private(dLocalTime)
{
pdTime[omp_get_thread_num()] = omp_get_wtime();
printf("Thread Begin %d Time %f\n", omp_get_thread_num(), pdTime[omp_get_thread_num()] );
#pragma omp for
for (iGID = 0; iGID < iSize; iGID++)
{
//   for (j = 0; j < iChunk; j++)
{

//  pfResult[iGID * iChunk + j] = fValue;
pfResult[iGID] = fValue;
}

}
//dLocalTime = (omp_get_wtime() - dLocalTime);
pdTime[omp_get_thread_num()] = (omp_get_wtime() - pdTime[omp_get_thread_num()]);
printf("Thread End %d Time %f\n", omp_get_thread_num(), pdTime[omp_get_thread_num()]);

// printf("End Element %d traité par le thread %d \n",0,tid);
}

Каждый поток занимает 0,015, в общей сложности 0,045, поэтому в openmp есть исправленная часть 0,03.
Странно, что даже при огромных размерах мы видим, что эта исправленная часть openmp и thread, у которой меньше работы, занимает столько же времени, сколько весь размер (здесь 48 потоков)

Спасибо

0

Решение

Хорошо, так как вы настаиваете .. 🙂

С фиксированным прогревом нитей:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <omp.h>
#include <unistd.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 *)valloc(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++)
{
for (j = 0; j < iChunk; j++)
pfResult[iGID * iChunk + j] = 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);
}

У меня есть следующие цифры на моей машине:

$ g++ -O2 -fopenmp testomp.cpp && OMP_NUM_THREADS=1 ./a.out
Pagesize=4096
0.036493 Time1
0.036489 Time2
$ g++ -O2 -fopenmp testomp.cpp && ./a.out
Pagesize=4096
0.034721 Time1
0.034718 Time2
$ g++ -O2 -fopenmp testomp.cpp -DWARMUP && ./a.out
24 threads
Pagesize=4096
0.026966 Time1
0.026963 Time2

Как видите, время создания потоков вносит большой вклад в цифры.

Почему до сих пор не масштабируется? Ну, это чрезвычайно ограниченная память. Фактически, он заполняет страницы дважды: как только ОС очищает его при первом касании, затем программа заполняет его через значение.
Кажется, в системе просто недостаточно пропускной способности памяти. Я бы не ожидал, что ложное разделение сыграет здесь важную роль, поскольку parallel for по умолчанию используется статическое расписание, которое не чередует итерации между потоками, поэтому ложное совместное использование возможно только один раз на границах.

0

Другие решения


По вопросам рекламы [email protected]