Вложенный параллелизм OpenMP OpenBLAS

мы пытаемся запустить два экземпляра cblas_dgemm параллельно. Если общее количество потоков равно 16, мы хотели бы, чтобы каждый экземпляр выполнялся с использованием 8 потоков. В настоящее время мы используем такую ​​структуру:

#pragma omp parallel num_threads(2)
{
   if (omp_get_thread_num() == 0){
     cblas_dgemm(...);
   }else {
     cblas_dgemm(...);
   }
}

Вот проблема:

На верхнем уровне есть два потока OpenMP, каждый из которых активен внутри одного из блоков if/else. Теперь мы ожидаем, что эти потоки будут вызывать функции cblas_dgemm параллельно, и внутри этих функций cblas_dgemm мы ожидаем, что будут порождены новые потоки.

Чтобы установить количество потоков, внутренних для каждого cblas_dgemm, мы устанавливаем соответствующую переменную среды: setenv OPENBLAS_NUM_THREADS 8 Однако, похоже, это не работает. Если мы измеряем время выполнения для каждого из параллельных вызовов, значения времени выполнения равны, но они равны времени выполнения одного вызова cblas_dgemm, когда вложенный параллелизм не используется и переменная среды OPENBLAS_NUM_THREADS установлена ​​в 1.

Что происходит не так? и как мы можем иметь желаемое поведение? Можно ли как-то узнать количество потоков внутри функции cblas_dgemm?

Большое спасибо за ваше время и помощь


person sanaz    schedule 09.03.2019    source источник


Ответы (1)


Механизм, который вы пытаетесь использовать, называется «вложением», то есть создание новой параллельной области внутри существующей внешней параллельной области уже активно. Хотя большинство реализаций поддерживают вложение, по умолчанию оно отключено. Попробуйте установить OMP_NESTED=true в командной строке или вызвать omp_set_nested(true) перед первой директивой OpenMP в вашем коде.

Я бы также изменил приведенный выше код, чтобы он читался так:

#pragma omp parallel num_threads(2)
{
#pragma omp sections
#pragma omp section
    {
        cblas_dgemm(...);
    }
#pragma omp section
    {
        cblas_dgemm(...);
    }
}

Таким образом, код также будет правильно вычислять только один поток, сериализуя два вызова dgemm. В вашем примере только с одним потоком код будет работать, но пропустит второй вызов dgemm.

person Michael Klemm    schedule 11.03.2019
comment
Большое спасибо, Майкл. Мы используем omp_set_nested(true). Я поместил операторы печати для печати идентификаторов потоков openMP внутри каждого раздела. Я также замерил время каждого раздела и сравнил его с общим временем. Наша текущая конструкция openMP, похоже, работает так, как предполагалось. Мы просто не уверены в потоках внутри функций openBLAS. - person sanaz; 12.03.2019