Что может быть лучше, если компилировать OpenMP и однопоточные версии алгоритма? - PullRequest
2 голосов
/ 09 декабря 2011

Я использую уродливый обходной путь для компиляции одного и того же исходного кода один раз для OpenMP и один раз для однопоточного кода. Он включает макросы компилятора и двойной #include C-файла. Я ищу лучшее решение.

Потоки OpenMP и Mac не смешиваются. Это, очевидно, хорошо известно. Цитата из http://www.imagemagick.org/script/architecture.php#threads.

Комитет OpenMP не определил поведение микширования OpenMP с другими моделями потоков, такими как нити Posix. Однако, используя современные выпуски Linux, OpenMP и Posix темы появляются в взаимодействовать без жалоб. Если вы хотите использовать темы Posix ... от Mac OS X или более старой версии Linux, вам может потребоваться отключить Поддержка OpenMP в ImageMagick.

У меня есть библиотека Python с расширением C, которая очень хорошо масштабируется с OpenMP, и она действительно включает только разброс операторов #pragma и правильные флаги компилятора.

Я также работаю на Mac. Когда я использую свою библиотеку в чем-то отличном от основного потока, у меня возникает ошибка. Например, если я использую поддержку OpenMP, я не могу использовать свою библиотеку в Django.

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

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

Единственное решение, которое я придумал, это ужасный хак, когда я # включаю один и тот же код C дважды:

#ifdef _OPENMP

#define MYFUNC static int _myfunc_openmp
#include "algorithm.c"
#undef MYFUNC
#define MYFUNC static int _myfunc_single
#include "algorithm.c"

int myfunc(int arg) {
  if (omp_get_num_threads() <= 1) {
      return _myfunc_single(arg);
  } else {
      return _myfunc_openmp(arg);
  }
}

#else

#define MYFUNC int myfunc
#include "algorithm.c"

#endif

и где "gorithm.c "выглядит как

MYFUNC(int arg) {
#ifdef _OPENMP
  #pragma omp for ...
#endif
   ... algorithm here ...
}

Это работает, но мне кажется, что я выбрал неправильный подход.

Я пытался использовать предложение OpenMP "if ()", как в

  int in_parallel = (omp_get_num_threads() > 1);
  #pragma omp for ... if(in_parallel)

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

Знаете ли вы лучший способ использования одного и того же алгоритма для путей кода OpenMP и не-OpenMP?

1 Ответ

2 голосов
/ 10 декабря 2011

Если у вас есть C99 (gcc и clang do для этого случая), вы можете использовать оператор _Pragma. Это полезно особенно внутри макросов:

#ifdef WITH_OPENMP
# define PARALLEL_FOR _Pragma("omp for")
#else
# define PARALLEL_FOR
#endif

Теперь вы можете просто добавить к этому макросу соответствующие циклы for и, таким образом, избежать всего остального #if/#else в остальной части кода, что затрудняет его поддержку.

Двойное включение файла само по себе не выглядит неправильно для меня. Наличие особого случая, который статически компилируется без OpenMp, позволяет избежать любого решения во время выполнения, которое OpenMp может попытаться принять.

Чего я не хотел бы делать, так это передавать спецификацию хранилища, возвращаемый тип и имя в одном макросе. В любом случае, наличие двух функций, видимых компоновщиком, ничего не стоит, поэтому static является излишним. Единственное, что вы должны посмотреть, это то, что символы компоновщика, начинающиеся с подчеркивания, зарезервированы, лучше переименуйте их в нечто приличное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...