2010-10-01 4 views
0

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

Мой внутренний цикл:

#pragma omp parallel for 
    for(unsigned long j = 0; j < c_numberOfElements; ++j) 
    { 
     //int th_id = omp_get_thread_num(); 
     //printf("thread %d, j = %d\n", th_id, (int)j); 

     Point3D current; 
     #pragma omp critical 
     { 
      current = _points[j]; 
     } 

     Point3D next = getNext(current); 

     if (!hasConstraint(next)) 
     { 
      continue; 
     } 

     #pragma omp critical 
     { 
      _points[j] = next; 
     } 
    } 

_points является pointMap_t, определяется как:

typedef boost::unordered_map<unsigned long, Point3D> pointMap_t; 

Без OpenMP мой бег времени 44.904s. С включенным OpenMP, на компьютере с двумя ядрами это 64.224s. Что я делаю неправильно?

ответ

1

Почему вы завернули свои чтения и записи в _points[j] в критических разделах? Я не очень программист на C++, но он не выглядит так, как будто вам нужны эти разделы вообще. Поскольку вы написали это (uunamed критические разделы), каждый поток будет ждать, пока другой пройдет через каждый из разделов. Это может сделать программу медленнее.

+0

Это segfaults без него. Я не думаю, что могу изменить карту из двух разных потоков одновременно. –

0

Кажется возможным, что поиск и запись в _points в критических разделах перетаскивают производительность при использовании OpenMP. Однопоточный, это не приведет к каким-либо спорам.

Совместное использование данных семян кажется контрпродуктивным в контексте параллельного программирования. Можете ли вы реструктурировать, чтобы избежать этих точек соперничества?

+0

Есть еще один способ сделать это? Я не привык к параллельному программированию. –

+0

@Vitor - Я не понимаю, почему это было бы ошибкой, если вы просто удалите критические разделы. Что-то в коде, которое мы не можем видеть, может быть? '_points' не добавляется или не удаляется, пока цикл выполняется, правильно? У вызовов функции есть побочные эффекты за пределами текущей записи? Где исключение? –

+1

Даже если вы удалите критические разделы, это может привести к значительному замедлению. См. http://www.drdobbs.com/go-parallel/article/showArticle.jhtml;jsessionid=200XVQJZEWF3HQE1GHPCKH4ATMY32JVN?articleID=217500206&pgno=1. –

0

Вам нужно показать остальную часть кода. Из комментария к другому ответу кажется, что вы используете карту. Это действительно плохая идея, особенно если вы сопоставляете номера 0..n с значениями: почему вы не используете массив?

Если вам действительно нужно использовать контейнеры, рекомендуется использовать те из Intel's Thread Building Blocks library.

+0

Вы правы. Карта в основном осталась прежней, где идентификатор не всегда был последовательным. Я сделал это в массив. Это все еще медленно, но я думаю, что я, вероятно, столкнулся с проблемой ложного обмена или чем-то еще. –

+0

@Vitto Py: попробуйте создать небольшой компилируемый образец кода, который показывает проблему. Вы так упростили код, что убрали проблему. Одна вещь, которую нужно попробовать, - сделать «hasContraint» статичным встроенным, чтобы избежать уплаты штрафа за вызов функции. – florin

0

Я согласен, что было бы лучше, чтобы увидеть некоторые рабочий код.

Конечная проблема заключается в том, что в параллельной области есть критические моменты, а критические ситуации (а) чрезвычайно дороги сами по себе и (б) по определению убивают параллелизм. Присвоение текущему определенному не обязательно должно находиться внутри критического, поскольку оно является частным; Я бы не подумал, что назначение _points [j] будет, но я не знаю, что делает карта, и так вы идете.

Но у вас есть цикл, в котором у вас есть огромное количество накладных расходов, которые линейно растут в количестве потоков (двух критических областей), чтобы сделать небольшое количество фактической работы (пройдите по связанному списку, это выглядит как). Это никогда не будет хорошей сделкой ...

Смежные вопросы