[英]Switching Between High Performance Libraries in c++
我正在编写一些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的工作。
我很确定除了大量预处理程序垃圾之外唯一的其他选择是为不同的平台提供不同的文件,构建过程将选择您针对特定库定位的体系结构的文件。 这样做的缺点是,如果有更复杂的函数,维护相同函数的不同实现,以便它们的行为相同,会变得有点棘手。 在某些情况下,您可能希望使用公共文件或宏来实现跨架构共同的功能方面。 例如:
当然,进行大量单元测试对于所有跨平台抽象都是非常关键的。
另一件需要考虑的事情是CPU调度。 例如,如果您在ARM上运行,则可能需要检测运行时是否存在NEON。 IPP为英特尔变体做了很多工作,但随着ARM的成熟和NEON功能的改变与SSE相同,您可能需要实施自己的调度机制,除非您使用的是为您处理此问题的3P产品。
而不是在每个函数中放置定义,而是为每个库创建一个包含其所有函数的定义。 这是一个例子。 假设您需要一个跨平台的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的Vector类库中的文件“vectormath.h”:C数学库,Intel SVML和AMD LIBM。 您可以使用Eigen for NEON(MKL比x86上的Eigen快得多)然后您不必编写任何添加模块。 只是这个头文件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.