Many functions in Intel® Math Kernel Library (MKL) have multiple entry points. This article describes the entry points that exist and why they are there. We take a sample MKL function, a service routine, and describe all the entry points that exist for that function. We then expand this to consider how this applies to other domains.
Consider the MKL routine: mkl_set_num_threads( number )
This function allows a user to suggest the number of OpenMP threads for MKL independently from their application. If their application uses eight threads, then as long as number is no greater than eight, this tells MKL to use this number of threads when possible (some routines may choose a different value unless the user sets MKL_DYNAMIC to FALSE). For more details, look at the manual.
The manual describes both the FORTRAN and C interfaces at the same time:
call mkl_set_num_threads ( number )
void mkl_set_num_threads ( number );
The FORTRAN 77 interface is declared in mkl_service.fi and the C interface in mkl_service.h. The manual also notes that the user must add #include "mkl.h" for C usage. We now explain why that last include is necessary for the C users.
Here are the actual entry points, in C syntax, that are resolved in MKL, starting with the two obvious ones for FORTRAN and C respectively:
void mkl_set_num_threads_ ( int *number );
void MKL_Set_Num_Threads (int number );
The C interface used internally in MKL differs from the documented C interface. This is resolved for C users in "mkl_service.h" which is one of the includes in "mkl.h":
#define mkl_set_num_threads MKL_Set_Num_Threads
Our motivation to do #define in C was to provide the same language name for both Fortran and C users. Normally the same language name in Fortran and C results in different library symbols, because Fortran decorates the name (such as adding underscore or uppercasing the name). But Fortran compilers are not consistent in decorating language names into library symbols - almost every Fortran compiler has a flag to cancel name decoration and some MKL customers use these flags. So the decision was made to provide Fortran symbols in many decorations, sometimes conflicting with C names, and use #define for C symbols to avoid symbol conflicts between Fortran and C.
This use of #define in the header file explains why C users must include "mkl.h" in order to get things to work correctly, but until we describe the other entry points, it may not be obvious why we do this. Here are the unobvious and undocumented entry points, in C syntax, that are resolved in MKL:
void mkl_set_num_threads ( int *number );
void MKL_SET_NUM_THREADS ( int *number );
void MKL_SET_NUM_THREADS_ (int *number );
void mkl_set_num_threads__ ( int *number );
Both "mkl_set_num_threads" and "mkl_set_num_threads_" assume the FORTRAN default of passing by reference. So, if a C user forgets to add the #include "mkl.h" then MKL will assume that it is being passed a pointer, and not a value, and the function will not behave as expected.
•· Windows Intel64 libraries do not include the MKL_SET_NUM_THREADS_() entry point.
•· If a function doesn't already have an underscore in the name, we do not include the double underscore variant.
The inclusion of some of these extra, undocumented entry points is necessary for supporting various usage models. For instance, some versions of the GNU compiler will add a second underscore to any function that has an underscore in it. So, if a user compiles a FORTRAN routine with "call mkl_set_num_threads ( number )" the compiler will require a link reference with two trailing underscores. Also, some compilers will automatically convert FORTRAN references to upper case, which requires MKL to be able to resolve this as well.
Extending this to other MKL Domains:
Different MKL domains have different APIs. In the previous example, we considered the most general case of a function that we've invented with no given API. Consider instead a BLAS routine like dgemm_( parameters by reference). In this case:
void dgemm_( parameters by reference );
void dgemm( parameters by reference );
void DGEMM ( parameters by reference );
void DGEMM_ (parameters by reference ) ;
However, note in this case that we also have a separate, completely different C interface to the BLAS, because there is a pre-defined BLAST standard here.