visual studio — переключение между высокопроизводительными библиотеками при переполнении стека

Я пишу код на C ++ для разных платформ. Это включает в себя x86, x64 и ARM. В настоящее время я использую Intel IPP и MKL (для SSE) на x64 и ожидаю добавить библиотеку NEON для ARM. Существует ли стандартный способ обхода определенных библиотек с минимальными зависимостями и суетой? В настоящее время я использую 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.

3

Решение

Я почти уверен, что кроме множества ненужных препроцессоров есть еще один вариант — иметь разные файлы для разных платформ, и процесс сборки выберет файл для архитектуры, на которую вы ориентируетесь для конкретной библиотеки. Недостатком этого является то, что если есть более сложные функции, поддержание различных реализаций одной и той же функции, чтобы они все вели себя одинаково, становилось немного сложнее. В некоторых случаях вы можете захотеть использовать общий файл или макросы для реализации аспектов функций, общих для разных архитектур. Например:

  • MyFFT.h (публичный API)
  • MyFFT_Intel.c
  • MyFFT_Neon.c
  • MyFFT_CrossPlatform.c (простая реализация C)
  • MyFFT_Common.c
  • MyFFT_Private.h (для общих прототипов вспомогательных функций, реализованных в MyFFT_Common.c)

Конечно, наличие множества модульных тестов действительно является ключевым для всех кроссплатформенных абстракций, подобных этой.

Еще одна вещь, которую следует учитывать, — диспетчеризация процессора. Например, если вы работаете в ARM, вы можете определить, присутствует ли NEON во время выполнения. IPP работает под капотом для вариантов Intel, но, поскольку ARM становится более зрелым, а возможности NEON изменяются так же, как SSE, вам может потребоваться реализовать собственный механизм диспетчеризации, если вы не используете продукт 3P, который обрабатывает это для вас.

3

Другие решения

Вместо того, чтобы помещать определения в каждую функцию, создайте определение для каждой библиотеки, которая включает все ее функции. Вот пример. Предположим, вам нужна кроссплатформенная библиотека 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 к параметрам командной строки. Смотрите файл «vectormath.h» в Agner Fog’s Библиотека векторных классов для примера, который обрабатывает три библиотеки: математическая библиотека C, Intel SVML и AMD LIBM. Вы могли бы использовать Eigen для NEON (MKL намного быстрее, чем Eigen на x86), тогда вам не пришлось бы писать какие-либо дополнительные модули. Просто этот заголовочный файл.

1

По вопросам рекламы [email protected]