3

我正在编写一些针对各种平台的 C++ 代码。这包括 x86、x64 和 ARM。我目前在 x64 上使用 Intel IPP 和 MKL(用于 SSE),并希望为 ARM 添加一个 NEON 库。有没有一种标准的方法来围绕特定的库进行分支并且具有最小的依赖和大惊小怪?我目前正在使用 Visual Studio 2008 或 2012。

我最初的想法是围绕特定调用进行#ifdef 并测试 X86、X64、ARM 等。例如:

void addVectors(int * a, int * b, int n)
{

   #ifdef INTELIPP
      ippsAdd_32s_I(...);
   #elif ARMNEON
      neonAdd_32s_I(...);
   #else
      for(int k = 0; k < n; k++)
         a[k] += b[k];
   #endif

}

但这可能会变得非常混乱。我想知道标准方法是什么。例如,我希望 IPP 和 NEON 代码的单独项目更干净,并且只针对其中一个构建主项目?

除了支持之外,IDE 并不是非常重要——而且我怀疑我们将改用 Eclipse 之类的东西来进行 ARM 工作。

4

2 回答 2

3

我很确定,除了大量的预处理器垃圾之外,唯一的其他选择是为不同的平台提供不同的文件,并且构建过程将为您针对特定库的体系结构选择文件。这样做的缺点是,如果有更复杂的函数,维护同一函数的不同实现以使它们都表现相同会变得更加棘手。在某些情况下,您可能希望使用通用文件或宏来实现跨体系结构通用的功能的各个方面。例如:

  • MyFFT.h(公共 API)
  • MyFFT_Intel.c
  • MyFFT_Neon.c
  • MyFFT_CrossPlatform.c(纯 C 实现)
  • MyFFT_Common.c
  • MyFFT_Private.h(用于在 MyFFT_Common.c 中实现的常用辅助函数原型)

当然,拥有大量的单元测试对于像这样的所有跨平台抽象来说真的很关键。

要考虑的另一件事是 CPU 调度。例如,如果您在 ARM 上运行,您可能想要检测运行时是否存在 NEON。IPP 确实适用于 Intel 变体,但随着 ARM 的成熟和 NEON 功能的变化与 SSE 相同,您可能需要实现自己的调度机制,除非您使用的是 3P 产品来为您处理这个问题。

于 2014-05-14T21:29:51.433 回答
1

不要将定义放在每个函数中,而是为每个包含其所有函数的库进行定义。这是一个例子。假设您想要一个跨平台的 BLAS 库。为简单起见,我们只选择两个函数

dot(double *a , double *b, double *c, int n)
gemm(double *a , double *b, double *c, int n);


#if BLASLIB == 0
    #include <blas_default.h>
    static inline dot(double *a , double *b, double *c, int n) {
        dot_default(a,b,c,n);
    }
    static inline gemm(double *a , double *b, double *c, int n) {
        gemm_default(a,b,c,n)      
    }
#elif BLASLIB == 1
    #include <mkl.h>
    static inline dot_mkl(double *a , double *b, double *c, int n) {
        cblas_daxpy(a,b,c,n);  //fix parameters
    }
    static inline gemm(double *a , double *b, double *c, int n) {
        cblas_gemm(a,b,c,n); //fix parameters      
    }

#elif BLASLIB == 2
    #include <blas_neon.h>
    static inline dot_neon(double *a , double *b, double *c, int n) {
        dot_neon(a,b,c,n);
    }
    static inline gemm(double *a , double *b, double *c, int n) {
        gemm_neon(a,b,c,n)      
    }
#endif

然后制作三个不同的构建文件,包括适当的库,并添加例如-DBLASLIB 1命令行选项。有关处理三个库的示例,请参见 Agner Fog 的矢量类库中的文件“vectormath.h”:C 数学库、英特尔 SVML 和 AMD LIBM。您可以将 Eigen 用于 NEON(MKL 比 x86 上的 Eigen 快得多),然后您就不必编写任何附加模块。就是这个头文件。

于 2014-05-15T10:33:29.033 回答