Изменить: мой первый пример кода был неправильным. Исправлено с более простым.
Я реализую библиотеку C ++ для алгебраических операций между большими векторами и матрицами.
На процессорах x86-x64 я обнаружил, что параллельное добавление векторов OpenMP, точечные продукты и т. Д. Работают не так быстро, как однопоточные.
Параллельные операции выполняются на -1-6% быстрее, чем однопоточные.
Это происходит из-за ограничения пропускной способности памяти (я думаю).
Итак, вопрос в том, есть ли реальный выигрыш в производительности для такого кода:
void DenseMatrix::identity()
{
assert(height == width);
size_t i = 0;
#pragma omp parallel for if (height > OPENMP_BREAK2)
for(unsigned int y = 0; y < height; y++)
for(unsigned int x = 0; x < width; x++, i++)
elements[i] = x == y ? 1 : 0;
}
В этом примере нет серьезных недостатков использования OpenMP.
Но если я работаю над OpenMP с разреженными векторами и разреженными матрицами, я не могу использовать, например, * .push_back (), и в этом случае вопрос становится серьезным. (Элементы разреженных векторов не являются непрерывными, как плотные векторы, поэтому параллельное программирование имеет недостаток, потому что результирующие элементы могут поступать в любое время — не для индекса от нижнего к верхнему)
Я не думаю, что это проблема пропускной способности памяти. Я ясно вижу проблему на r
: r
доступ из нескольких потоков, что вызывает как гонки данных а также ложный обмен. Ложный обмен может сильно повредить вашей производительности.
Мне интересно, можете ли вы получить даже правильный ответ, потому что на данных гонках r
, Вы получили правильный ответ?
Однако решение будет очень простым. Операция проведена на r
является сокращение, что может быть легко достигнуто reduction
пункт OpenMP.
Попробуй просто добавить reduction(+ : r)
после #pragma omp parallel
,
(Примечание: дополнения на double
не являются коммутативными и ассоциативными. Вы можете увидеть некоторые ошибки точности или некоторые различия с результатом последовательного кода.)
Других решений пока нет …