37

I have a C++ program using OpenMP, which will run on several machines that may have or not have OpenMP installed.

How could I make my program know if a machine has no OpenMP and ignore those #include <omp.h>, OpenMP directives (like #pragma omp parallel ...) and/or library functions (like tid = omp_get_thread_num();) ?

kaya3
  • 47,440
  • 4
  • 68
  • 97
Tim
  • 1
  • 141
  • 372
  • 590
  • 2
    Please see Andrew's answer. The best I can tell, he's the only one who actually answered the question (and did it correctly). Also see [What preprocessor define does -fopenmp provide?](http://stackoverflow.com/q/30803126) – jww Jun 12 '15 at 13:12

5 Answers5

70

OpenMP compilation adds the preprocessor definition "_OPENMP", so you can do:

#if defined(_OPENMP)
   #pragma omp ...
#endif

For some examples, see http://bisqwit.iki.fi/story/howto/openmp/#Discussion and the code which follows.

Andrew Dalke
  • 14,889
  • 4
  • 39
  • 54
  • 10
    It's unnecessary to protect #pragma omp, since such pragma is not intrusive (safely skipped when openmd is not activated). – YvesgereY Nov 13 '12 at 14:12
  • 10
    While true, if one likes to compile without warnings even under -Wall then a compiler message like "warning: unknown pragma ignored" will be annoying. – Andrew Dalke Nov 16 '12 at 18:48
  • 2
    About compilation warning, I use to compile with `-Wno-unknown-pragmas` for this very reason. Problem: may affect other pragmas in the project and remove useful warnings. – johan d Dec 16 '13 at 12:44
  • 3
    This if-block is useful to hide function call like omp_set_num_threads() or omp_get_thread_num() . `#if defined(_OPENMP) tid = omp_get_thread_num(); #else tid = 0; #endif` – KRoy Dec 03 '15 at 21:29
  • This is also useful if using OpenMP locks (for example) depending on whether running in parallel or not. Those are *not* no-ops if OpenMP is not being used (say, with `-fno-openmp`). – emprice Nov 12 '17 at 23:47
  • @YvesgereY - Re: guarding use of pragmas... GCC is OpenMP compliant but issues unknown pragma warnings if OpenMP is not enabled. It breaks a clean compile that many use as a security gate. Also see [Issue 66943, GCC warns of Unknown Pragma for OpenMP, even though it support it](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66943). – jww Jan 22 '19 at 08:15
  • Does the `_OPENMP` macro defined on all major x86 compilers (MSVC, Clang, GCC)? – Royi Aug 19 '19 at 17:15
25

Compilers are supposed to ignore #pragma directives they don't understand; that's the whole point of the syntax. And the functions defined in openmp.h have simple well-defined meanings on a non-parallel system -- in particular, the header file will check for whether the compiler defines ENABLE_OPENMP and, if it's not enabled, provide the right fallbacks.

So, all you need is a copy of openmp.h to link to. Here's one: http://cms.mcc.uiuc.edu/qmcdev/docs/html/OpenMP_8h-source.html .

The relevant portion of the code, though, is just this:

#if defined(ENABLE_OPENMP)
#include <omp.h>
#else
typedef int omp_int_t;
inline omp_int_t omp_get_thread_num() { return 0;}
inline omp_int_t omp_get_max_threads() { return 1;}
#endif

At worst, you can just take those three lines and put them in a dummy openmp.h file, and use that. The rest will just work.

Brooks Moses
  • 9,267
  • 2
  • 33
  • 57
  • 12
    +1 for `#pragma` semantic. -1 for `ENABLE_OPENMP`, which is not standard compliant. Use `_OPENMP` instead. – YvesgereY Nov 13 '12 at 14:23
  • *"... the header file will check for whether the compiler defines ENABLE_OPENMP"* - I don't think this is true. Could you provide a reference for `ENABLE_OPENMP`? I could not find it in the preprocessor defines. See [What preprocessor define does -fopenmp provide?](http://stackoverflow.com/q/30803126) – jww Jun 12 '15 at 13:11
  • I am compiling with clang 3.6.2 and `clang++ -fopenmp` tells me _OPENMP is not defined. – Arne Sep 27 '15 at 21:22
  • 1
    [LLVM's page](http://openmp.llvm.org/) on the subject seems to suggest, OpenMP was only properly introduced into the compiler-suit with version 3.8. The earlier versions (trying 3.6 and 3.7 on FreeBSD here) seem to accept the `-fopenmp` flag, but ignore it... With clang-3.8 the `_OPENMP` is defined and the parallelization actually works. – Mikhail T. Dec 31 '16 at 06:43
0

OpenMP is a compiler runtime thing and not a platform thing.

ie. If you compile your app using Visual Studio 2005 or higher, then you always have OpenMP available as the runtime supports it. (and if the end-user doesn't have the Visual Studio C runtime installed, then your app won't work at all).

So, you don't need to worry, if you can use it, it will always be there just like functions such as strcmp. To make sure they have the CRT, then you can install the visual studio redistributable.

edit:

ok, but GCC 4.1 will not be able to compile your openMP app, so the issue is not the target machine, but the target compiler. As all compilers have pre-defined macros giving their version, wrap your OpenMP calls with #ifdef blocks. for example, GCC uses 3 macros to identify the compiler version, __GNUC__, __GNUC_MINOR__ and __GNUC_PATCHLEVEL__

gbjbaanb
  • 51,617
  • 12
  • 104
  • 148
  • My problem is that I want to run the program without multi-threading on those machines that don't have it. GCC below version 4.2.x doesn't support OpenMP. So I want to make my Makefile be able to tell this and ask g++ to ignore the OpenMP part in my program instead of failing the compilation. Any idea? – Tim Aug 20 '09 at 12:10
  • 3
    -1: Compiler version is completely inadequate. Both compiler and runtime have to support openmp _and_ it has to be _enabled_ too. The same compiler version may support openmp on one computer and not support it on another. – Jan Hudec Feb 19 '14 at 10:29
0

How could I make my program know if a machine has no OpenMP and ignore those #include <omp.h>, OpenMP directives (like #pragma omp parallel ...) and/or library functions (like tid = omp_get_thread_num();) ?

Here's a late answer, but we just got a bug report due to use of #pragma omp simd on Microsoft compilers.

According to OpenMP Specification, section 2.2:

Conditional Compilation

In implementations that support a preprocessor, the _OPENMP macro name is defined to have the decimal value yyyymm where yyyy and mm are the year and onth designations of the version of the OpenMP API that the implementation supports.

It appears modern Microsoft compilers only support OpenMP from sometime between 2000 and 2005. I can only say "sometime between" because OpenMP 2.0 was released in 2000, and OpenMP 2.5 was released in 2005. But Microsoft advertises a version from 2002.

Here are some _OPENMP numbers...

  • Visual Studio 2012 - OpenMP 200203
  • Visual Studio 2017 - OpenMP 200203
  • IBM XLC 13.01 - OpenMP 201107
  • Clang 7.0 - OpenMP 201107
  • GCC 4.8 - OpenMP 201107
  • GCC 8.2 - OpenMP 201511

So if you want to use, say #pragma omp simd to guard a loop, and #pragma omp simd is available in OpenMP 4.0, then:

#if _OPENMP >= 201307
    #pragma omp simd
    for (size_t i = 0; i < 16; ++i)
        data[i] += x[i];
#else
    for (size_t i = 0; i < 16; ++i)
        data[i] += x[i];
#endif

which will run on several machines that may have or not have OpenMP installed.

And to be clear, you probably need to build your program on each of those machines. The x86_64 ABI does not guarantee OpenMP is available on x86, x32 or x86_64 machines. And I have not read you can build on one machine, and then run on another machine.

jww
  • 97,681
  • 90
  • 411
  • 885
  • As the target execution platform will need to have installed library support for the compiler used to build the application, it shouldn't be necessary to build on each machine. In the example just above, pragma omp simd by itself isn't likely to depend on library support. It should be enough to write – tim18 Jan 23 '19 at 12:15
  • 1
    #pragma omp simd if(_OPENMP >= 201307) without multiple copies of identical source code. – tim18 Jan 23 '19 at 12:16
  • @tim18 - *"... pragma omp simd by itself isn't likely to depend on library support"* - The use case I was thinking about was a distro model. Building on an i686 machine, and then running on another i686 machine without SSE2 and friends. SSE2 and friends is part of the core instruction set on x86_64, but it is optional on 32-bit processors. This can work in theory using runtime dispatching but I don't see where the prerequisites/requirements are in place so that is does work in practice. – jww Jan 28 '19 at 02:59
  • @tim18 - Have you confirmed `#pragma omp simd if(_OPENMP >= 201307)` works on Visual Studio with its ancient 2002 OpenMP implementation? When I attempt to use it with Visual Studio 2015 I receive *`test.cpp(8): error C3001: 'simd': expected an OpenMP directive name`* – jww Jan 28 '19 at 03:00
-2

There is another approach that I like, borrowed from Bisqwit:

#if defined(_OPENMP)
#include <omp.h>
extern const bool parallelism_enabled = true;
#else
extern const bool parallelism_enabled = false;
#endif

Then, start your OpenMP parallel for loops like this:

#pragma omp parallel for if(parallelism_enabled)

Note: there are valid reasons for not using pragma, which is non-standard, hence why Google and others do not support it.

Adam Erickson
  • 6,027
  • 2
  • 46
  • 33
  • If `_OPENMP` is not defined, then the `#pragma omp` won't be understood anyway so the `if` will have no effect in this case. You also say there are valid reasons not to use `#pragma`, but your linked article is about `#pragma once` (not `#pragma omp` which is totally different) and your solution uses `#pragma omp` anwyay. It is not possible to use OpenMP functionality without `#pragma omp`. – Jake Lishman Oct 01 '20 at 14:55