Clang,OpenMP和自定义矢量/矩阵缩减

时间:2018-09-11 23:19:25

标签: c++ clang openmp eigen armadillo

到目前为止,我必须使用自制的gcc在Mac上编译OMP增强的代码。

好消息是,Apple Clang现在可以找到OMP标头(至少在其Apple LLVM version 9.1.0 (clang-902.0.39.2)版本中)。

坏消息是,过去用于工作的自定义归约子句不再有效。我已在下面附上了演示我的问题的代码段。进入带有段错误或以下错误的并行块时,它立即崩溃:

DebugOMP(46436,0x7fff8fc12380) malloc: *** error for object 0x7fff8fc02000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

有没有办法解决这个问题?像#pragma omp parallel for这样的简单OMP子句可以正常工作。我正在使用Armadillo 9.100.5。本征也会发生同样的问题。

main.cpp:

#include <armadillo>

#pragma omp declare reduction( + : arma::vec : omp_out += omp_in ) \
initializer( omp_priv = omp_orig )


int main() {

    int N = 10000;
    int M = 100;
    double a = 0;

    // Built-in reduction, works
    #pragma omp parallel for reduction(+:a)
    for (int k = 0; k < M; ++k){
        a += k;
    }

    std::cout << a << std::endl;

    arma::vec v = arma::zeros<arma::vec>(M);

    // Parallel access, works
    #pragma omp parallel for
    for (int k = 0; k < M; ++k){
        v(k) = k;
    }

    std::cout << v << std::endl;

    // Custom, reduction, segfaults
    #pragma omp parallel for reduction(+:v)
    for (int i = 0; i < N; ++i){
        v += arma::ones<arma::vec>(v.n_rows);
    }

    std::cout << v << std::endl;

    return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.0.0)

# Building procedure
get_filename_component(dirName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
set(EXE_NAME ${dirName} CACHE STRING "Name of executable to be created.")

project(${EXE_NAME})

# Find Armadillo 
find_package(Armadillo REQUIRED )
include_directories(${ARMADILLO_INCLUDE_DIRS})

# Find OpenMP
find_package(OpenMP)
if(OPENMP_FOUND)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()

# Add source files in root directory
add_executable(${EXE_NAME}
main.cpp)


# Linking
set(library_dependencies ${ARMADILLO_LIBRARIES} )


target_link_libraries(${EXE_NAME} ${library_dependencies} OpenMP::OpenMP_CXX)

2 个答案:

答案 0 :(得分:2)

您可以像这样手动进行缩小

#pragma omp parallel
{
  arma::vec t = arma::zeros<arma::vec>(M);
  #pragma omp for nowait
  for (int i = 0; i < N; ++i) t += arma::ones<arma::vec>(v.n_rows);
  #pragma omp critical
  v += t;
}

适用于Clang。这可以帮助您弄清楚如何定义initializer-expr

例如,这适用于GCC 7

#pragma omp declare reduction( + : arma::vec : omp_out += omp_in ) \
initializer( omp_priv = arma::zeros<arma::vec>(omp_orig.n_rows))

但是对于Clang 5.0,代码会挂起,所以我不确定Clang的问题是什么。我尝试了其他initializer-expr变体,但没有一个能让Clang正常工作。


我安装了clang7,OP的代码运行正常。总的来说,我认为将向量明确设置为零是一个更好的主意

initializer( omp_priv = arma::zeros<arma::vec>(omp_orig.n_rows))

而不是像这样隐含

initializer(omp_priv = omp_orig)

因为隐式情况假定构造函数初始化为零。

答案 1 :(得分:1)

由于最初的问题也询问了Eigen,因此这是一个使用gcc 5、6、7、8和clang 6的独立示例。它使用clang 5进行段错误,可能是clang 5方面的错误。这与Z Boson提出的解决方案基本相同。

#include <Eigen/Core>
#include <iostream>
using namespace Eigen;

typedef VectorXd vec;

#pragma omp declare reduction( + : vec : omp_out += omp_in ) \
  initializer( omp_priv = vec::Zero(omp_orig.size()) )

int main() {
    int N = 10000;
    int M = 100;
    vec v = vec::LinSpaced(M,0,M-1);

    #pragma omp parallel for reduction(+:v)
    for (int i = 0; i < N; ++i){
        v += vec::Ones(v.size());
    }

    std::cout << v.transpose() << std::endl;
    return 0;
}