Использование унифицированного бэкенда в ArrayFire

Я пытаюсь выбрать свой бэкэнд arrayfire на основе доступных бэкэндов и их возможностей (если бэкенд поддерживает удвоение, используйте его, иначе нет). Поэтому я создал CMakeLists.txt-файл:

cmake_minimum_required(VERSION 3.10)

project(arrayfire_test)

if(USE_EXTERNAL_PATHS)
    set(CMAKE_C_COMPILER ${C_COMPILER})# CACHE PATH "" FORCE)
    set(CMAKE_CXX_COMPILER ${CXX_COMPILER})#CACHE PATH "" FORCE)
else()
    set(CMAKE_C_COMPILER mpicc)
    set(CMAKE_CXX_COMPILER mpic++)
endif()

if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    set(CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -fopenmp-simd")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
    set(CXX_FLAGS "${CMAKE_CXX_FLAGS} -xHost")
endif()

set(C_FLAGS "${CMAKE_C_FLAGS} ${CXX_FLAGS} -fPIC -flto -march=native -fopenmp -O2 -funroll-loops -funroll-all-loops -fstrict-aliasing  -std=gnu++14")
set(CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS} -fPIC -flto -march=native -fopenmp -O2 -funroll-loops -funroll-all-loops -fstrict-aliasing  -std=gnu++14")

string(REPLACE " " ";" REPLACED_CXX_FLAGS ${CXX_FLAGS})

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/lib)

set(ArrayFire_DIR "/opt/arrayfire/share/ArrayFire/cmake")
FIND_PACKAGE(ArrayFire)

find_package(Armadillo REQUIRED PATHS "/opt/armadillo")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp -std=c++11 -O0 -g3 -flto -march=native")
set(FORGE_LIBRARIES  "/opt/arrayfire/lib/libforge.so")

INCLUDE_DIRECTORIES(${ArrayFire_INCLUDE_DIRS} 
    ${ARMADILLO_INCLUDE_DIRS})

add_executable(${PROJECT_NAME} "source/main.cpp")

target_compile_options(${PROJECT_NAME} PRIVATE ${REPLACED_CXX_FLAGS})

TARGET_LINK_LIBRARIES(${PROJECT_NAME} 
    ${ArrayFire_Unified_LIBRARIES}
    ${ARMADILLO_LIBRARIES})# ${FORGE_LIBRARIES})

и основной файл:

int main(void){
    int backends = af::getAvailableBackends ();
    std::cout << backends << "\n";
    std::vector<af_backend> possible_backends;
    if(backends & AF_BACKEND_CUDA)
        possible_backends.push_back(AF_BACKEND_CUDA);
    if(backends & AF_BACKEND_OPENCL)
        possible_backends.push_back(AF_BACKEND_OPENCL);
    if(backends & AF_BACKEND_CPU)
        possible_backends.push_back(AF_BACKEND_CPU);
    if(possible_backends.size() == 0){
        std::cerr << "No backends available\n";
        return -1;
    }
    for(size_t i = 0; i < possible_backends.size(); ++i){
        af::setBackend (possible_backends[i]);
        af::setDevice (0);
        if(af::isDoubleAvailable (0)){
            std::cout << "Backend " << af::getActiveBackend () << " supports double\n";
            break;
        }
    }
    std::cout << "Backend " << af::getActiveBackend () << " is in use\n";
    return 0;
}

Согласно http://arrayfire.org/docs/unifiedbackend.htm, я должен использовать ${ArrayFire_Unified_LIBRARIES} при использовании этого бэкенда. Но при запуске кода я получаю

0
No backends available

хотя у меня есть и ЦП, и OpenCL в качестве бэкэнда. При замене ${ArrayFire_Unified_LIBRARIES} на ${ArrayFire_CPU_LIBRARIES} ${ArrayFire_OpenCL_LIBRARIES} я получаю вывод

1
Backend 1 supports double
Backend 1 is in use

При переключении порядка библиотек получаю

4
Backend 4 is in use

и тем самым указать, что виден только один бэкенд, хотя у меня два возможных бэкенда. Таким образом, есть ли ошибка в моем коде или мой подход неверен?


person arc_lupus    schedule 24.02.2020    source источник


Ответы (1)


Во-первых, мы рекомендуем использовать цели импорта вместо необработанных переменных cmake при интеграции ArrayFire в ваш проект на основе cmake. Поскольку ваша минимальная версия cmake — 3.10, у вас не должно возникнуть проблем с использованием целей импорта.

find_package(ArrayFire)
add_executable(<my_executable> [list your source files here])

# To use Unified backend, do the following.
# Unified backend lets you choose the backend at runtime
target_link_libraries(<my_executable> ArrayFire::af)
# for directly using cpu/cuda/opencl backend
# use `ArrayFire::[afcpu | afcuda | afopencl]` respectively

Вам не нужно связываться с Forge, он будет загружен во время выполнения ArrayFire, а графические функции будут включены автоматически.

Для правильной работы любой библиотеки времени выполнения (forge, freeimage), загружаемой ArrayFire и унифицированным бэкендом, путь к местоположению, в котором находятся эти библиотеки (обычно /opt/arrayfire/lib), должен быть виден для загрузки во время выполнения. Ознакомьтесь с учебником по установке, чтобы убедиться, что вы выполнили все необходимые шаги.

person pradeep    schedule 26.02.2020