【问题标题】:Clang, OpenMP and custom vector/matrix reductionClang、OpenMP 和自定义向量/矩阵缩减
【发布时间】:2018-09-11 23:19:24
【问题描述】:

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

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

坏消息是过去有效的自定义缩减条款不再适用。我附上了下面的代码 sn-p 来演示我的问题。它在进入并行块时立即崩溃,出现段错误或以下错误:

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 子句可以正常工作。我正在使用犰狳 9.100.5。 Eigen 也会出现同样的问题。

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)

【问题讨论】:

    标签: c++ clang openmp eigen armadillo


    【解决方案1】:

    你可以像这样手动减少

    #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)
    

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

    【讨论】:

      【解决方案2】:

      由于最初的问题还询问了 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;
      }
      

      【讨论】:

      • 感谢您检查 clang6。 OP 的代码适用于 clang7,所以可能也适用于 clang6。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-11
      • 2018-12-05
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-09
      相关资源
      最近更新 更多