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

Clang, OpenMP and custom vector/matrix reduction

本文关键字:OpenMP 自定义 Clang      更新时间:2023-10-16

直到现在,我不得不使用自制的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

有没有办法解决这种减少问题?更简单的 OMP 子句,如#pragma omp parallel for工作正常。我正在使用犰狳 9.100.5。同样的问题也发生在本征身上。

主要.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)

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

#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。这可以帮助您弄清楚如何定义初始值设定项 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的问题是什么。我尝试了其他初始化器-expr 变体,但没有一个让 Clang 工作。


我安装了 clang7,OP 的代码工作正常。一般来说,我认为像这样明确地将向量设置为零是一个更好的主意

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

而不是像这样隐含

initializer(omp_priv = omp_orig)

因为隐式大小写假定构造函数初始化为零。

由于最初的问题也问到了 Eigen,这里有一个使用 gcc 5、6、7、8 和 clang 6 的独立示例。它与 clang 5 存在段错误,可能是 clang 5 侧的错误。这基本上与Z玻色子提出的解决方案相同。

#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;
}