C++ intel TBB оптимизация внутреннего цикла

Я пытаюсь использовать Intel TBB для распараллеливания внутреннего цикла (2-й из 3-х), однако, я получаю достойную отдачу только тогда, когда внутренние 2-х циклы значительны по размеру.

TBB порождает новые потоки для каждой итерации основного цикла? Есть ли способ уменьшить накладные расходы?

tbb::task_scheduler_init tbb_init(4); //I have 4 cores
tbb::blocked_range<size_t> blk_rng(0, crs_.y_sz, crs_.y_sz/4);
boost::chrono::system_clock::time_point start   =boost::chrono::system_clock::now();
for(unsigned i=0; i!=5000; ++i)
{   
    tbb::parallel_for(blk_rng, 
    [&](const tbb::blocked_range<size_t>& br)->void
    {   
    :::

Может быть интересно отметить, что у openMP (который я пытаюсь удалить!!!) нет этой проблемы.

Я собираю с:

Intel ICC 12.1 в -03 -xHost -mavx

На intel 2500k (4 ядра)

РЕДАКТИРОВАТЬ: я действительно могу изменить порядок циклов, потому что тест выходных циклов необходимо заменить на предикат, основанный на результате цикла.

1 ответ

Нет, TBB не создает новые потоки для каждого вызова parallel_for, На самом деле, в отличие от параллельных областей OpenMP, каждый из которых может создавать новую группу потоков, TBB работает с одной и той же группой потоков, пока все task_scheduler_init объекты уничтожены; и в случае неявной инициализации (с task_scheduler_init опущено), одни и те же рабочие потоки используются до конца программы.

Так что проблема с производительностью вызвана чем-то другим. Исходя из моего опыта, наиболее вероятные причины:

  • отсутствие оптимизации компилятора, в первую очередь автоматическая векторизация (это можно проверить, сравнив однопоточную производительность OpenMP и TBB; если TBB намного медленнее, то это наиболее вероятная причина).
  • отсутствует кеш; если вы 5000 раз пробегаете одни и те же данные, локальность кэша имеет огромное значение, и OpenMP по умолчанию schedule(static) работает очень хорошо, детерминистически повторяя одно и то же разбиение каждый раз, в то время как планировщик краж работы TBB имеет значительную случайность. Установка размера зерна block_range равным problem_size/num_threads обеспечивает один кусок работы на поток, но не гарантирует одинаковое распределение частей; а также affinity_partitioner должен помочь с этим.
Другие вопросы по тегам