Я думаю, что самое легкое, что вы можете сделать, это разрешить его разбиение на 4 потока и вычислить ошибки UYVY в каждом из них. Вместо того, чтобы их отдельные значения, сделать их массив:
double sqError[4] = {0};
const int numBytes = width * height * 2;
#pragma omp parallel for
for(int elem = 0; elem < 4; elem++) {
for(int i = elem; i < numBytes; i += 4) {
int val = refData[i] - calData[i];
sqError[elem] += (double)(val*val);
}
}
Таким образом, каждый поток работает исключительно на одном и нет никаких разногласий.
Возможно, это не самое продвинутое использование OMP, но вы должны увидеть ускорение.
После вашего комментария об ударе производительности я сделал несколько экспериментов и обнаружил, что производительность была еще хуже. Я подозреваю, что это может быть из-за промахов в кеше.
Вы сказали:
производительность удар на этот раз с OpenMP: Время: 0.040637 с последовательным Время: 0,018670
Так что я переработал его с помощью сокращения на каждой переменной и с помощью одного цикла :
#pragma omp parallel for reduction(+:e0) reduction(+:e1) reduction(+:e2) reduction(+:e3)
for(int i = 0; i < numBytes; i += 4) {
int val = refData[i] - calData[i];
e0 += (double)(val*val);
val = refData[i+1] - calData[i+1];
e1 += (double)(val*val);
val = refData[i+2] - calData[i+2];
e2 += (double)(val*val);
val = refData[i+3] - calData[i+3];
e3 += (double)(val*val);
}
с моим теста на 4-ядерный машине, я заметил, немного меньше, чем 4-кратное улучшение:
serial: 2025 ms
omp with 2 loops: 6850 ms
omp with reduction: 455 ms
[Редактировать] По вопросу о том, почему первая часть кода выполняется хуже, чем не-параллельной версии, Христо Илиев сказал:
Ваш первый кусок код - ужасный пример того, что ложное разделение делает в многопоточных кодах. Поскольку sqError имеет только 4 элемента по 8 байт каждый, он вписывается в одну строку кеша (даже в половине кэша на современных процессорах x86). С 4 потоками, постоянно записывающимися в соседние элементы , это создало бы огромное количество межядерных кешей недействительности из-за ложного обмена. Можно обойти это, используя вместо структуры, подобной этой структуре _error {double val; двойной накладка [7]; } sqError [4]; Теперь каждый sqError [i] .val будет в отдельной строке кеша , следовательно, не будет обмена ложью.
Спасибо, падди, я быстро внес эти изменения и протестировал, это устраняет зависимость данных и улучшает производительность. однако вычисленный параллельный выход openmp не такой же, как выход последовательной программы. –
Вы говорите, что если вы прокомментируете строку '# pragma', результаты будут разными? Или вы сравниваете это с другой программой? Поскольку это C, вы можете определить 'i' вне цикла. Если это так, попробуйте добавить предложение 'private (i)' в конец строки '# pragma'. То же самое с 'val'. – paddy
Для справки это изменения, которые я сделал: const int nBytes = (ширина * высота)/2; double sqError [4] = {0}; #pragma OMP параллельного { #pragma OMP для для (INT эля = 0; эль <4; эль ++) { для (INT I = эль; г <число-байты; г + = 4) { двойного вала = refData [i] - calData [i]; sqError [elem] + = (double) (val * val); } } } mse_y = ((double) (sqError [1] + sqError [3])/(ширина * высота)); mse_u = ((double) sqError [0]/(ширина * высота/2)); mse_v = ((double) sqError [2]/(ширина * высота/2)); –