Заставить OpenMP не кэшировать большой объект в каждом потоке - PullRequest
2 голосов
/ 08 января 2020

Я пишу программу на C ++ с al oop, которую пытаюсь распараллелить, используя OpenMP. L oop, который я пишу, имеет следующую структуру:

#pragma omp parallel for
for (int i = 0; i < N; i++)
    result[i] = work_func(left[i], right[i], largeObject);

Аргумент largeObject помечен как постоянная ссылка. Моя проблема заключается в том, что при переходе от одного потока к нескольким потокам (~ 40) использование памяти резко увеличивается. Аргументы left и right невелики, что означает, что даже полное копирование их во все потоки не приведет к увеличению объема памяти.

Я бы хотел сказать OpenMP, чтобы он не копировал largeObject во весь локальный кэш потоков, вместо этого заставляя его использовать одну глобальную копию. Есть ли способ сделать это? Похоже, что это go против оптимизаций без ложного обмена, которые чаще встречаются с проблемами производительности OpenMP. Меня меньше беспокоит замедление времени выполнения, чем большие накладные расходы этой программы.

Спасибо!

1 Ответ

1 голос
/ 08 января 2020

int const largeObject - в директиве об объявлении должна указываться фаза компиляции во избежание любого совместного использования дополнительных механизмов и / или тактика синхронизации для принципиально не изменяемого объекта (так как не существует условий гонки, которые могут появиться ни при каких других попытках записи, для которых требуется доступ к объявленному неизменяемому const largeObject. Используя директиву volatile, как упомянутый @Gilles, использует другие механизмы стратегии доступа к значениям, внедренные компилятором, которые не имеют прямого отношения к OpenMP, но соблюдаются соответствующим omp -секцией (ами).

#include <iostream>                                                                
#include <omp.h>                                                                   

#define anIndeedLargeSIZE 2
int main()                                                                         
{   
    int               largeObject[anIndeedLargeSIZE] = {0};
    #pragma omp const largeObject

    std::cout << "largeObject address " << largeObject << std::endl;

    #pragma omp parallel for num_threads(2)
    for (int i = 0; i < 2; i++)
    {
        int tid = omp_get_thread_num();                                         

        std::cout << "tid: " << tid << " :: " << largeObject << std::endl;

        if (i == tid)
        {   
         // largeObject[i] = tid; // const .... un-mutable mode
            std::cout << "tid: " << tid << " :: now reading and using a const largeObject[" << (int)i << "] == " << largeObject[i] << std::endl;
            }

        }

    std::cout << "largeObject processing FINISHED." << std::endl;

    return 0;                                                                   
    }   

Пожалуйста, протестируйте побочные эффекты выделения памяти для действительно больших размеров, которые было несправедливо тестировать с помощью прототипа IDE на IDE-сайте Godbolt (полный MCVE-код для дальнейших экспериментов и профилирование расширений присутствует вместе с параметрами компилятора, используемыми там ) , поскольку документация OpenMP API предупреждает, что фактическое поведение равно " спецификация реализации c ".

enter image description here

(base) Wed Jan 08 00:00:00 @64FX:~/$ g++ -o largeObject_const_OMP -O3 -fopenmp largeObject_const_OMP.c
largeObject_const_OMP.c: In function ‘int main()’:
largeObject_const_OMP.c:65:30: error: expected ‘#pragma omp’ clause before ‘const’
     #pragma omp parallel for const (largeObject) num_threads(2)

<--------------------code-revised-as-desired-by-parsing-error:65:30:expected ‘#pragma omp’ clause ADDED before ‘const’-->
(base) Wed Jan 08 00:00:00 @64FX:~/$ g++ -o largeObject_const_OMP -O3 -fopenmp largeObject_const_OMP.c
<--------------------no-error-message|warning-from-parse|compile|link-phases-HERE->
(base) Wed Jan 08 00:00:00 @64FX:~/$ ./largeObject_const_OMP
largeObject address 0x7fff81b97d58
tid: tid: 0 :: 10x7fff81b97d58 :: 
tid: 0 :: now reading and using a const largeObject[0] == 0
0x7fff81b97d58
tid: 1 :: now reading and using a const largeObject[1] == 0
largeObject processing FINISHED.

Доступ int const v / s int volatile largeObject:

...