Search code examples
copenmp

OpenMP methods in C


I was playing around with OpenMP and came across the following 2 methods: omp_get_num_threads() and omp_get_num_procs(). I tried them using just plain C, without the OpenMP directives and even without #include <omp.h>:

int main ()
{
    int t, p;

    t = omp_get_num_threads();
    p = omp_get_num_procs();

    printf("Number of threads = %d\n", t);
    printf("Number of processors = %d\n", p);
}

Nevertheless I got the expected result:

Number of threads = 1
Number of processors = 4

As those methods both start with opm I assume these are OpenMP methods and are unknown in C. How come they deliver the right result even outside of OpenMP?


Solution

  • First of all, there is no such thing as "outside" OpenMP. The OpenMP pragmas just translate to normal code, for example using pthread functions if compiled with gcc. So any function of OpenMP would work even if you don't have a #pragma omp.

    Indead, omp_get_num_procs returns the number of processors, regardless of what you are running or if at all you use OpenMP, and omp_get_num_threads returns the number of collaborating threads which would of course be 1 if not using OpenMP:

    Returns the number of threads in the current team. In a sequential section of the program omp_get_num_threads returns 1.


    Now the actual question becomes the following: How can C know that it should call those OpenMP functions without you including the header?

    It actually doesn't. If you enable warnings on your compiler (for example gcc -Wall, you would receive warnings saying:

    implicit declaration of function ‘omp_get_num_threads’

    implicit declaration of function ‘omp_get_num_procs’

    But this is not forbidden by the standard. So what happens is that C assumes these implicitly defined functions don't take any parameters (which by chance matches the declaration of omp_get_num_procs/threads).

    Next, there is the link stage, which is done after the compilation and you are beyond the realm of C. The linker however, doesn't bother with function signatures. All it needs is to know function names. Since those functions are implicitly declared, they are still declared! So they exist in the object file and are ready to be linked. If the linker is instructed to link against the OpenMP library, it would correctly link those implicitly declared functions.

    Only mystery remaining is why your compiler is trying to link with OpenMP even if you haven't told it? First guess is that you have told it to link against OpenMP. If not, there could be a couple of reasons. Off the top of my head, if you are using software made for grandmothers (e.g. Microsoft products), it may have been configured to link every program against many unnecessary libraries so the programmer won't have to bother with that configuration.


    With gcc 4.8.1, this is the output (note that you should write int main(void) and also return something from it, not to mention you haven't included stdio.h):

    $ gcc -c a.c -Wall
    a.c: In function ‘main’:
    a.c:5:5: warning: implicit declaration of function ‘omp_get_num_threads’ [-Wimplicit-function-declaration]
         t = omp_get_num_threads();
         ^
    a.c:6:5: warning: implicit declaration of function ‘omp_get_num_procs’ [-Wimplicit-function-declaration]
         p = omp_get_num_procs();
         ^
    a.c:8:5: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
         printf("Number of threads = %d\n", t);
         ^
    a.c:8:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
    a.c:10:1: warning: control reaches end of non-void function [-Wreturn-type]
     }
     ^
    

    Note that what is stated in the comment above:

    I think you enabled OpenMP in the compiler, which automatically defined the functions for you.

    is not true at least for gcc, as the output of gcc -c a.c -Wall -fopenmp is exactly the same.

    And during link, if you don't specify -fopenmp, the linker won't find the symbols:

    $ gcc a.o
    a.o: In function `main':
    a.c:(.text+0xe): undefined reference to `omp_get_num_threads'
    a.c:(.text+0x1b): undefined reference to `omp_get_num_procs'
    collect2: error: ld returned 1 exit statusw