是否可以让 Fortran 源代码检测编译器标志?

Posted

技术标签:

【中文标题】是否可以让 Fortran 源代码检测编译器标志?【英文标题】:Is that possible to let Fortran source code detect compiler flags? 【发布时间】:2022-01-19 05:30:52 【问题描述】:

这个问题的灵感来自OpenMP with BLAS

动机是,我希望 Fortran 源代码对与串行/并行 BLAS 相关的编译器选项具有灵活性。我可以在Makefile 中为mkl 指定-mkl=parallel 或为lopenblas 指定USE_OPENMP=1。 我可以使用make ifortmake gfortranmake blah blah 来切换Makefile 中的库。 但是,

a) 如果我在Makefile中使用-mkl=parallel,我需要在源代码中设置call mkl_set_num_threads(numthreads)

b) 如果我使用OpenBLASUSE_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 和/或-mkl=sequential,我必须手动配置dgemm 线程(作为一种块分解),不管OMP_NUM_THREADS。没关系,但我需要使用if 来控制源代码以这种方式运行,如果源代码有 a) 和 b) 行

c) 中的手动编程dgemm 线程在某种程度上是通用的。当我想利用库中的并行 blas 时,事情可能会很复杂,以至于我不知道如何切换有关编译器选项的源代码。

添加环境文件中的OMP_NUM_THREADS .bashrc 是不可取的。 (对不起,我应该在前面提到这一点)源代码读取指定正在使用的核心数量的输入文件,并使用omp_set_num_thread 设置目标核心数量,而不是从环境文件中。

Addition2,根据我对MKL 的测试,OMP_NUM_THREADS 不能超过call mkl_set_num_threads。也就是说,我必须指定 call mkl_set_num_threads 才能使用 -mkl=parallel 标志。

【问题讨论】:

有什么原因不能只设置环境变量OMP_NUM_THREADS?如果没有,您可能需要某种形式的预处理。 this question 有一些关于将变量从 makefile 传递到 Fortran 预处理器的信息。 同意@IanBush:大多数现代 BLAS 库都遵循 OpenMP 环境变量。一般不需要设置源中的线程数。 关于我不得不处理的OMP_NUM_THREADS 方法的唯一陷阱是当变量设置为 not 时大多数实现使用所有内核的愚蠢默认设置.在这种情况下,您可以使用get_environment_variable 来检查OMP_NUM_THREADS,如果不存在,请使用omp_set_num_threads 将默认线程数设置为合理的值,即1 - 所有这些都是可饮用的。 我真的不明白你的意思。如果 MKL 或 OPENBLAS 不可用,您是否拥有自己的 openmp 线程 BLAS?如果是这种情况,OMP_NUM_THREADS 将受到尊重 - 使用 that 作为设置您使用的线程数的主要方式,如果您对OMP_NUM_THREADS 的情况感到偏执,请仅使用omp_set_num_threads没有设置,即大多数代码从不关心它。总之,如果您使用环境变量,几乎总是可以编写出不需要需要预处理的代码,而与 BLAS 实现无关。 【参考方案1】:

至少有两种方法。

预处理器变量

如在例如this question 和 this question 等,您可以将变量从 Makefile 直接传递到适当的预处理器。

例如,在您设置-mkl=parallel 的Makefile 分支中,您也可以设置-DMKL_PARALLEL。然后,在您的源代码中,您可以有一个类似于

的块
#ifdef MKL_PARALLEL
  call mkl_set_num_threads(numthreads)
#endif

如果您使用适当的预处理器编译您的代码,这允许您将任意信息从您的 Makefile 传递到您的源代码。

单独的文件

您可以不使用预处理器,而是拥有同一个文件的多个副本,每个副本都有一组不同的选项,并且只为项目编译正确的文件。

一个更好的方法是有一个模块文件,无论选项如何,它总是相同的,以及多个submodules,每个都包含一组选项。这减少了由多个文件引起的错误空间,并在您需要更改选项时减少了编译时间。

【讨论】:

以上是关于是否可以让 Fortran 源代码检测编译器标志?的主要内容,如果未能解决你的问题,请参考以下文章

用于 Ivy Bridge 架构的 GNU Fortran 编译器优化标志

cmake可以自动添加fortran预处理器-cpp标志吗?

Linux 上 fortran 代码的 Intel Vtune 奇怪行为

CMake Fortran 编译器相关标志

fortran调试断言失败怎么解决?

通过额外的优化标志减少 fortran 运行时间