#c #performance #parallel-processing #openmp #pragma
#c #Производительность #параллельная обработка #openmp #pragma
Вопрос:
добрый день. Я хочу реализовать внутренний продукт тремя способами: 1 — последовательный, 2 — полупараллельный, 3 — полностью параллельный
полупараллельное означает параллельное умножение и последовательное суммирование.
вот мой код:
int main(int argc, char *argv[]) {
int *x, *y, *z, *w, xy_p, xy_s, xy_ss, i, N=5000;
double s, e;
x = (int *) malloc(sizeof(int)*N);
y = (int *) malloc(sizeof(int)*N);
z = (int *) malloc(sizeof(int)*N);
w = (int *) malloc(sizeof(int)*N);
for(i=0; i < N; i ) {
x[i] = rand();
y[i] = rand();
z[i] = 0;
}
s = omp_get_wtime();
xy_ss = 0;
for(i=0; i < N; i )
{
xy_ss = x[i] * y[i];
}
e = omp_get_wtime() - s;
printf ( "[**] Sequential execution time is:n.10f and <A,B> is %dn", e, xy_ss );
s = omp_get_wtime();
xy_s = 0;
#pragma omp parallel for shared ( N, x, y, z ) private ( i )
for(i = 0; i < N; i )
{
z[i] = x[i] * y[i];
}
for(i=0; i < N; i )
{
xy_s = z[i];
}
e = omp_get_wtime() - s;
printf ( "[**] Half-Parallel execution time is:n.10f and <A,B> is %dn", e, xy_s );
s = omp_get_wtime();
xy_p = 0;
# pragma omp parallel shared (N, x, y) private(i)
# pragma omp for reduction ( : xy_p )
for(i = 0; i < N; i )
{
xy_p = x[i] * y[i];
}
e = omp_get_wtime() - s;
printf ( "[**] Full-Parallel execution time is:n.10f and <A,B> is %dn", e, xy_p );
}
итак, у меня есть некоторый вопрос:
сначала я хочу знать: корректен ли мой код?!!!!
второй: почему полупараллельный быстрее последовательного?!
в-третьих: является ли 5000 подходящим размером для параллелизма?
и, наконец, почему последовательный является самым быстрым? из-за 5000?!
пример вывода:
Время последовательного выполнения составляет: 0.0000196100, а точка равна -1081001655
Время полупараллельного выполнения составляет: 0.0090819710, а точка равна -1081001655
Время полностью параллельного выполнения составляет: 0.0080959420, а точка равна -1081001655
и для N = 5000000
Время последовательного выполнения составляет: 0,0150297650 и равно -1629514371
Время полупараллельного выполнения составляет: 0,0292110600 и равно -1629514371
Время полностью параллельного выполнения составляет: 0,0072323760 и равно -1629514371
в любом случае, почему полупараллельный является самым медленным?
Комментарии:
1. 5000 умножений не стоят параллельных вычислений. Стоимость создания потока (или взятия потока из пула) и присоединения к потоку намного выше, чем фактический расчет. Вы можете выполнить упражнение и проверить сами, каков минимальный размер точечного произведения, чтобы параллель была прибыльной.
2. Спасибо, но я тестировал на 5000000, и полностью параллельный — самый быстрый, а полупараллельный — самый медленный! Почему полупараллельный не лучше последовательного?!
3. Циклы For для seq и parallel отличаются от полупараллельных — они создают разный ассемблерный код. Полупараллельный генерирует вдвое больший объем кода, и вы все равно платите за порождение потоков. Увеличьте размер операции до чего-то более реалистичного, например, до 50 миллионов или около того, и проверьте еще раз.
4. Когда вы разделяете циклы, в вашем самом большом случае у вас будут потери кэша и удвоится количество промахов кэша в вашем «полупараллельном» случае. Платформа NUMA может усугубить проблему. В вашем меньшем случае векторизация с сокращением omp simd должна быть более эффективной, чем tthreading. В зависимости от вашего компилятора и настроек опций, возможно, вы уже добились этой оптимизации. В типичных реализациях omp_wtime не будет точным для таких коротких временных интервалов.