LAPACK routines are thread-safe... depending on how you build them
I spent last week testing my R package 'sme' for race conditions using the helgrind tool.
I was already aware that the LAPACK routines built-in to R, based on the now fairly old version 3.1 released in 2006, were not thread-safe but I wasn't fully aware how
pervasive the problem was. DLAMCH is the offending routine, which is called pretty much all over the place, regardless of whether you want to carry out a singular-value decomposition, find a least-squares solution or
invert a matrix.
The solution was to bundle up-to-date versions of the routines my code calls (DLMACH has been fixed since LAPACK version 3.3.0) but the story does not end there. Depending on how you compile these routines, they may still not be thread-safe. I had problems using gfortran to compile DORMQR which declares a local two-dimensional double-precision array T of size LDT by NBMAX where NBMAX = 64 and LDT = NBMAX + 1. The problem is that if doubles on your platform are 8-bytes in size, the array occupies 65 * 64 * 8 = 33,280 bytes. Referring to the gfortran man page:
-fmax-stack-var-size=n
This option specifies the size in bytes of the largest array that will be put on the stack; if the size is exceeded static memory is used (except in procedures marked as RECURSIVE ). Use the option -frecursive to allow for recursive procedures which do not have a RECURSIVE attribute or for parallel programs. Use -fno-automatic to never use the stack.
This option currently only affects local arrays declared with constant bounds, and may not apply to all character variables. Future versions of GNU Fortran may improve this behavior.
The default value for n is 32768.
T is slightly too big to fit on the stack; it therefore ends up as a static variable and race conditions ensue. The solution? Use the -frecursive flag or in the case of OpenMP programs, -fopenmp. In the context of building OpenMP enabled R packages such as 'sme', simply don't forget to set PKG_FFLAGS=$(SHLIB_OPENMP_FFLAGS) in your Makevars file...
The solution was to bundle up-to-date versions of the routines my code calls (DLMACH has been fixed since LAPACK version 3.3.0) but the story does not end there. Depending on how you compile these routines, they may still not be thread-safe. I had problems using gfortran to compile DORMQR which declares a local two-dimensional double-precision array T of size LDT by NBMAX where NBMAX = 64 and LDT = NBMAX + 1. The problem is that if doubles on your platform are 8-bytes in size, the array occupies 65 * 64 * 8 = 33,280 bytes. Referring to the gfortran man page:
-fmax-stack-var-size=n
This option specifies the size in bytes of the largest array that will be put on the stack; if the size is exceeded static memory is used (except in procedures marked as RECURSIVE ). Use the option -frecursive to allow for recursive procedures which do not have a RECURSIVE attribute or for parallel programs. Use -fno-automatic to never use the stack.
This option currently only affects local arrays declared with constant bounds, and may not apply to all character variables. Future versions of GNU Fortran may improve this behavior.
The default value for n is 32768.
T is slightly too big to fit on the stack; it therefore ends up as a static variable and race conditions ensue. The solution? Use the -frecursive flag or in the case of OpenMP programs, -fopenmp. In the context of building OpenMP enabled R packages such as 'sme', simply don't forget to set PKG_FFLAGS=$(SHLIB_OPENMP_FFLAGS) in your Makevars file...