Как я могу узнать, сколько работ было выполнено в OpenMP & quot; для директивы & quot ;?

Я хотел бы знать прогресс цикла for с использованием OpenMP.
Я знаю, что директива сокращения не работает, но я написал так:

#pragma omp for reduction (+:sum)
for (int i=0; i < size; i++){
// do something that takes about 10seconds
sum++;
#pragma omp critical
cout << sum << " / " << size << endl;
}

это вернет что-то вроде этого:

1 / 100
1 / 100
2 / 100
1 / 100
...

но я хочу этого:

1 / 100
2 / 100
3 / 100

. ..

Есть ли способ получить правильный sum значение во время reduction Директива?
или я должен использовать другой метод?

4

Решение

reduction пункт имеет очень четко определенное значение, подробно объясненное в разделе 2.9.3.6 новейший стандарт OpenMP. Я сомневаюсь, что вы сможете использовать его для целей, описанных выше.

В любом случае, возможно реализовать это поведение с небольшими изменениями в вашем источнике:

sum = 0
#pragma omp for shared(sum) schedule(guided)
for (int i=0; i < size; i++){
// do something that takes about 10seconds
#pragma omp critical(PRINT)
{
sum++;
cout << sum << " / " << size << endl;
}
}

Таким образом, вы можете быть уверены, что только один поток пытается увеличить сумму и вывести ее на экран. Учитывая длительность каждой итерации, такая синхронизация не должна вызывать проблем с производительностью.

0

Другие решения

Вы должны использовать другой метод. Редукция создает приватную переменную потока (в вашем случае sum), которое уменьшается только в конце, когда все потоки объединяются. Сокращение сильно зависит от реализации. Он может ожидать завершения всех потоков, может уменьшаться по завершении потоков, может создавать дерево сокращений и т. Д.

Вместо этого, чтобы отслеживать прогресс, вы могли бы иметь другую переменную numDone, который каждый поток атомарно увеличивается.

РЕДАКТИРОВАТЬ

Википедия объясняет это довольно хорошо:

сокращение (оператор | встроенный: список): переменная имеет локальную копию
в каждом потоке, но значения локальных копий будут суммироваться
(уменьшено) в глобальную переменную общего доступа.

0

Чтобы избежать необходимости обмена данными (от обновления общего счетчика), вы можете просто распечатать номер потока вместе с количеством элементов, которые он обработал до настоящего времени, т.е.

#pragma omp parallel
{
int count = 0;
#pragma omp for schedule(dynamic)           // or whatever schedule you want
for(int i=0; i<size; ++i) {
// ...
printf("@ %d: done %d loops\n",
omp_get_thread_num(),++count);   // should not need a critical section
}
}

В вашем конкретном случае, поскольку работа занимает около 10 секунд, любые коммуникации не являются критическими, но может быть целесообразно использовать динамическое расписание, в частности, если работа может варьироваться между различными i,

0
По вопросам рекламы [email protected]