OpenMP: огромные различия в производительности между Visual C ++ 2008 и 2010 - PullRequest
25 голосов
/ 19 января 2011

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

При переходе на VC2010 я вижу очень странный скачок производительности: под VC2010 мое приложение использует почти 100% ЦП, а по сравнению с VC2008 - только 10%.

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

Я сократил код, необходимый для воспроизведения проблемы, до простого цикла, который выполняет следующие действия:

  for (int i=0; i<1000; ++i)
  {
    GetImage(buffer);//wait for image
    Copy2Array(buffer, my_array);

    long long sum = 0;//do some simple OpenMP parallel loop
    #pragma omp parallel for reduction(+:sum)
    for (int j=0; j<size; ++j)
      sum += my_array[j];
  }

Этот цикл потребляет 5% ЦП в 2008 году и 70% в 2010 году.

Я провел некоторое профилирование, которое показывает, что в 2010 году большую часть времени проводит в OpenMP vcomp100.dll!_vcomp::PartialBarrierN::Block

Я также выполнил некоторое профилирование параллелизма:

В 2008 году обработка обрабатывается по 3 рабочим потокам, которые очень слабо активны, поскольку время обработки значительно уступает времени ожидания изображения

Те же потоки появляются в 2010 году, но все они на 100% заняты функцией PartialBarrierN::Block. Поскольку у меня четыре ядра, они потребляют 75% работы, что примерно соответствует тому, что я вижу при загрузке процессора.

Похоже, что существует конфликт между OpenMP и библиотекой сбора Matrox (проприетарной). Но это ошибка VS2010 или Matrox? Что я могу сделать? Использование VC ++ 2010 является для меня обязательным, поэтому я не могу просто придерживаться 2008 года.

Большое спасибо

ОБНОВЛЕНИЕ СОСТОЯНИЯ

Использование новой среды параллелизма, как предложено DeadMG, приводит к 40% CPU. Профилирование показывает, что время тратится на обработку, поэтому оно не показывает ошибку, которую я вижу с OpenMP, но производительность в моем случае намного ниже, чем у OpenMP.

ОБНОВЛЕНИЕ СОСТОЯНИЯ 2

Я установил ознакомительную версию последней версии Intel C ++. Это показывает те же проблемы с производительностью!

Я сделал кросс-пост на MSDN forum

ОБНОВЛЕНИЕ СОСТОЯНИЯ 3

Протестировано на 64-битной Windows 7 и 32-битной XP, с точно такими же результатами (на том же компьютере)

Ответы [ 4 ]

18 голосов
/ 07 февраля 2011

В 2010 году OpenMP каждый рабочий поток выполняет спин-ожидание около 200 мс после завершения задачи. В моем случае ожидания ввода-вывода и повторяющейся задачи OpenMP это массовая загрузка процессора.

Решение состоит в том, чтобы изменить это поведение; В Intel C ++ есть подпрограмма расширения для этого kmp_set_blocktime(). Однако Visual 2010 не имеет такой возможности.

В этой заметке Autodesk говорится о проблеме для Intel C ++. Этот компилятор сначала ввел поведение, но позволяет изменить его (см. Выше). Visual 2010 перешел на него, но ... без обходного пути, как Intel.

Таким образом, чтобы подвести итог, переключение на Intel C ++ и использование kmp_set_blocktime(0) решило это.

Спасибо Джону Лилли из DataLever Corporation в другом потоке MSDN

Проблема была отправлена ​​на MS Connect и получена обратная связь "не будет исправлено".

5 голосов
/ 14 марта 2015

В OpenMP 3.0 спинвейт может быть деактивирован с помощью OMP_WAIT_POLICY:

_putenv_s( "OMP_WAIT_POLICY", "PASSIVE" );

Эффект в основном такой же, как с kmp_set_blocktime(0), но поскольку мы устанавливаем переменную среды OMP_WAIT_POLICY во время выполнения,это повлияет только на текущий процесс и дочерние процессы.

Конечно, OMP_WAIT_POLICY также может быть установлено приложением запуска, например, Blender обрабатывает его таким образом.

Исправление для VC2010 доступно здесь , более поздние версии, такие как VC2013, поддерживают его напрямую.

4 голосов
/ 19 января 2011

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

То есть

for (int i=0; i<1000; ++i)
  {
    GetImage(buffer);//wait for image
    Copy2Array(buffer, my_array);

    long long sum = 0;//do some simple OpenMP parallel loop
    #pragma omp parallel for reduction(+:sum)
    for (int j=0; j<size; ++j)
      sum += my_array[j];
  }

станет

for (int i=0; i<1000; ++i)
  {
    GetImage(buffer);//wait for image
    Copy2Array(buffer, my_array);

    Concurrency::combinable<int> combint;
    Concurrency::parallel_for(0, size / 1000, [&](int j) {
      for(int i = 0; i < 1000; i++)
          combint.local() += my_array[(j * 1000) + i];
    });
    combint.combine([](int a, int b) { return a + b; });
  }
1 голос
/ 01 февраля 2011

Я протестировал другую плату сбора данных, и проблема идентична, поэтому виновником является VC ++ 2010. Microsoft внесла изменения в реализацию OpenMP, которые испортили программы, подобные моей, как показано в потоке на форумах MSDN .

...