Расточительный барьер OpenMP GCC GOMP

#gcc #openmp

#gcc #openmp

Вопрос:

У меня есть следующая программа. nv составляет около 100, dgemm — 20×100 или около того, так что предстоит проделать еще много работы:

 #pragma omp parallel for schedule(dynamic,1)
        for (int c = 0; c < int(nv);   c) {
            omp::thread thread;                                               
            matrix amp;t3_c = vv_.at(omp::num_threads() thread);
            if (terms.first) {
                blas::gemm(1, t2_, vvvo_, 1, t3_c);
                blas::gemm(1, vvvo_, t2_, 1, t3_c);
            }

            matrix amp;t3_b = vv_[thread];
            if (terms.second) {
                matrix amp;t2_ci = vo_[thread];
                blas::gemm(-1, t2_ci, Vjk_, 1, t3_c);
                blas::gemm(-1, t2_ci, Vkj_, 0, t3_b);
            }
        }
  

однако с GCC 4.4, GOMP v1, на gomp_barrier_wait_end приходится почти 50% времени выполнения. Изменение GOMP_SPINCOUNT снижает нагрузку, но тогда используется только 60% ядер. То же самое для OMP_WAIT_POLICY=passive . Система Linux, 8 ядер.

Как я могу добиться полного использования без перезаписи / ожидания переполнения

Комментарии:

1. Просто ради интереса попробуйте изменить расписание на использование «schedule (static)» и посмотрите, что произойдет.

2. @ejd тоже пробовал это, тот же эффект.

3. @Anycorn: вы решили проблему? У меня такая же проблема…

Ответ №1:

Барьер — это симптом, а не проблема. Причина, по которой в конце цикла возникает много ожиданий, заключается в том, что некоторые потоки выполняются намного раньше других, и все они довольно долго ждут в конце цикла for, пока все не будут выполнены.

Это классическая проблема с дисбалансом нагрузки, которая здесь странная, поскольку это всего лишь набор матричных умножений. Они разного размера? Как они размещены в памяти, с точки зрения материала NUMA — все ли они в настоящее время находятся в кэше одного ядра или есть другие проблемы с общим доступом? Или, проще говоря — существует ли только 9 матриц, так что оставшиеся 8 обречены застрять в ожидании того, кто получил последнюю?

Когда подобные вещи происходят в более крупном параллельном блоке кода, иногда можно перейти к следующему блоку кода, пока некоторые итерации цикла еще не выполнены; там вы можете добавить nowait директиву к for, которая переопределит поведение по умолчанию и избавит от подразумеваемого барьера. Здесь, однако, поскольку параллельный блок в точности соответствует размеру цикла for, это действительно не может помочь.

Комментарии:

1. имеется 100 матриц, дисбаланс нагрузки крайне маловероятен. ложный обмен также маловероятен. nowait значительно ухудшает ситуацию с точки зрения скорости.

2. Маловероятно или нет, если бы не было проблем с дисбалансом нагрузки, все ваши задачи не ожидали бы завершения omp для. nowait также должен иметь ровно нулевую разницу здесь, если код такой, как указано выше; он должен просто сдвинуть подразумеваемый барьер с конца for на конец параллельного блока…

3. и, как предположил комментарий @ejd, я подозреваю, что причина, по которой расписание в настоящее время (динамическое, 1), заключается в том, что с расписанием по умолчанию все было хуже и даже динамично с большим размером фрагмента, да? Опять же, это признак проблемы с дисбалансом нагрузки. Один из способов увидеть, что происходит, если ваши инструменты профилирования не делают этого за вас, — рассчитать время каждой итерации цикла и распечатать время с соответствующим индексом потока и номером итерации и посмотреть, сможете ли вы выяснить, откуда возникает дисбаланс.

Ответ №2:

Может ли быть так, что ваша реализация BLAS также вызывает OpenMP внутри? Если только вы не видите только один вызов gomp_barrier_wait_end .

Комментарии:

1. Это определенно идея, которую стоит проверить. Даже если он использует pthreads, там может быть некоторое взаимодействие.

2. В любом случае, вы не должны так сильно беспокоиться о барьере (если только ваша цель не состоит в том, чтобы уменьшить накладные расходы на барьер), но для вашего времени работы в настенном режиме: какое ускорение вы получаете?