Насколько велика n?
Планирование по умолчанию для директивы OpenMP parallel for
зависит от конкретной реализации. Похоже, что в GOMP (реализация OpenMP, используемая gcc), по умолчанию (dynamic,1)
в соответствии с документацией здесь . Это означает, что каждый поток обращается (в i-1
и i+1
) к областям памяти, которые загружены соседними потоками, что может привести к плохому использованию кэша. На современных архитектурах ЦП подобные операции с трафаретом часто связаны с памятью и чувствительны к кешированию. Вы можете попробовать указать расписание с большими кусками, например, с помощью:
#pragma omp parallel for schedule(dynamic,1024)
Я просто использую 1024 здесь в качестве примера. На практике вы должны экспериментировать, чтобы найти оптимальный фактор разбиения на блоки (или систематический поиск с разверткой параметров, процесс, часто называемый «автонастройкой»). Или вы можете выбрать теоретически основанное на значении значение, например, исходя из размера кэша L1 или L2 вашего ЦП.
Или вместо этого вы можете попробовать статическое планирование, так как объем вычислений внутри цикла for одинаков для всех потоков, а накладные расходы динамического планировщика могут стать причиной узкого места. Если вы укажете
#pragma omp parallel for schedule(static)
без размера чанка, тогда каждому потоку будет присвоен один чанк примерно одинакового размера.
Наконец, вы также можете прикрепить потоки OpenMP к своим собственным ядрам ЦП. Вы можете сделать это, используя переменную окружения GOMP_CPU_AFFINITY .
Edit:
Я просто играл со следующей тестовой программой, скомпилированной с gcc 4.2.1, и я думаю, что документация, на которую я ссылался выше, неверна. Похоже, GOMP по умолчанию schedule(static)
.
#include <stdio.h>
#include <omp.h>
int main(int argc, char** argv)
{
int i;
#pragma omp parallel for
for (i=0; i<15; i++) {
int id = omp_get_thread_num();
printf("%d assigned to thread %d\n", i, id);
}
}
И вывод с двумя потоками:
$ ./test_sched | sort -n
0 assigned to thread 0
1 assigned to thread 0
2 assigned to thread 0
3 assigned to thread 0
4 assigned to thread 0
5 assigned to thread 0
6 assigned to thread 0
7 assigned to thread 0
8 assigned to thread 1
9 assigned to thread 1
10 assigned to thread 1
11 assigned to thread 1
12 assigned to thread 1
13 assigned to thread 1
14 assigned to thread 1