是否可以让 Fortran 源代码检测编译器标志?
Is that possible to let Fortran source code detect compiler flags?
问题的灵感来自
动机是,我希望 Fortran 源代码能够灵活地适应与 serial/parallel BLAS 相关的编译器选项。我可以在 Makefile
中为 mkl
指定 -mkl=parallel
或为 lopenblas
指定 USE_OPENMP=1
。
我可能会 make ifort
或 make gfortran
或 make blah blah
来切换 Makefile
中的库。
但是,
a) 如果我在Makefile
中使用-mkl=parallel
,我需要在源代码中设置call mkl_set_num_threads(numthreads)
,
b) 如果我使用 OpenBLAS
和 USE_OPENMP=1
,我可能需要在源代码中使用 openblas_set_num_threads(num_threads)
https://rdrr.io/github/wrathematics/openblasctl/man/openblas_set_num_threads.html#:~:text=threads%20to%20use.-,Details,t%20simply%20call%20R%27s%20Sys.
c) 目前如果只有 lblas
and/or 和 -mkl=sequential
,我必须手动配置 dgemm
线程(作为一种块分解) ,无论 OMP_NUM_THREADS
。没关系,但我需要使用 if
来控制源代码以这种方式运行,如果源代码包含 a) 和 b)
c) 中的手动编程 dgemm
线程在某种程度上是通用的。当我想从库中利用并行 blas 时,事情似乎很复杂,以至于我不知道如何切换有关编译器选项的源代码。
来自环境文件 .bashrc
的添加 OMP_NUM_THREADS
不是可取的。 (抱歉,我应该早点提到这一点)源代码读取了一个指定正在使用的内核数量的输入文件,并使用 omp_set_num_thread
设置目标内核数量,而不是从环境文件中读取。
Addition2,从我在MKL
上的测试来看,OMP_NUM_THREADS
无法压制call mkl_set_num_threads
。也就是说,我必须指定 call mkl_set_num_threads
才能使用 -mkl=parallel
标志。
至少有两种方法。
预处理器变量
如中所述 and ,除其他外,您可以将变量从 Makefile 直接传递到适当的预处理器。
例如,在您设置 -mkl=parallel
的 Makefile 分支中,您也可以设置 -DMKL_PARALLEL
。然后,在您的源代码中,您可以有一个看起来像
的块
#ifdef MKL_PARALLEL
call mkl_set_num_threads(numthreads)
#endif
只要您使用适当的预处理器编译代码,就可以将任意信息从 Makefile 传递到源代码。
单独的文件
您可以拥有同一个文件的多个副本,每个副本都有一组不同的选项,并且只为项目编译正确的文件,而不是使用预处理器。
一个稍微好一点的方法是有一个模块文件,无论选项如何,它总是相同的,还有多个 submodules,每个文件包含一组选项。这减少了由多个文件引起的错误空间,并在您需要更改选项时减少编译时间。
问题的灵感来自
动机是,我希望 Fortran 源代码能够灵活地适应与 serial/parallel BLAS 相关的编译器选项。我可以在 Makefile
中为 mkl
指定 -mkl=parallel
或为 lopenblas
指定 USE_OPENMP=1
。
我可能会 make ifort
或 make gfortran
或 make blah blah
来切换 Makefile
中的库。
但是,
a) 如果我在Makefile
中使用-mkl=parallel
,我需要在源代码中设置call mkl_set_num_threads(numthreads)
,
b) 如果我使用 OpenBLAS
和 USE_OPENMP=1
,我可能需要在源代码中使用 openblas_set_num_threads(num_threads)
https://rdrr.io/github/wrathematics/openblasctl/man/openblas_set_num_threads.html#:~:text=threads%20to%20use.-,Details,t%20simply%20call%20R%27s%20Sys.
c) 目前如果只有 lblas
and/or 和 -mkl=sequential
,我必须手动配置 dgemm
线程(作为一种块分解) ,无论 OMP_NUM_THREADS
。没关系,但我需要使用 if
来控制源代码以这种方式运行,如果源代码包含 a) 和 b)
c) 中的手动编程 dgemm
线程在某种程度上是通用的。当我想从库中利用并行 blas 时,事情似乎很复杂,以至于我不知道如何切换有关编译器选项的源代码。
来自环境文件 .bashrc
的添加 OMP_NUM_THREADS
不是可取的。 (抱歉,我应该早点提到这一点)源代码读取了一个指定正在使用的内核数量的输入文件,并使用 omp_set_num_thread
设置目标内核数量,而不是从环境文件中读取。
Addition2,从我在MKL
上的测试来看,OMP_NUM_THREADS
无法压制call mkl_set_num_threads
。也就是说,我必须指定 call mkl_set_num_threads
才能使用 -mkl=parallel
标志。
至少有两种方法。
预处理器变量
如中所述
例如,在您设置 -mkl=parallel
的 Makefile 分支中,您也可以设置 -DMKL_PARALLEL
。然后,在您的源代码中,您可以有一个看起来像
#ifdef MKL_PARALLEL
call mkl_set_num_threads(numthreads)
#endif
只要您使用适当的预处理器编译代码,就可以将任意信息从 Makefile 传递到源代码。
单独的文件
您可以拥有同一个文件的多个副本,每个副本都有一组不同的选项,并且只为项目编译正确的文件,而不是使用预处理器。
一个稍微好一点的方法是有一个模块文件,无论选项如何,它总是相同的,还有多个 submodules,每个文件包含一组选项。这减少了由多个文件引起的错误空间,并在您需要更改选项时减少编译时间。