使用nvc++运行带OpenACC的C++程序报错libgomp: TODO求助
libgomp: TODO错误的解决思路 问题概述
使用nvc编译运行包含OpenACC的C程序时,出现libgomp: TODO运行错误,同时编译输出中出现Generating implicit copyin(duplicate.step.p[:1],srcImg.step.p[:1],srcImg,duplicate)[if not already present]的提示,已尝试显式为srcImg分配GPU内存,但问题仍存在。
测试代码
#include <opencv2/imgcodecs.hpp> #include <opencv2/highgui.hpp> #include <openacc.h> using namespace std; using namespace cv; int main(){ cv::Mat srcImg=cv::imread("/home/testSpace/images/blue-mountains.jpg"); if(!srcImg.data){ cout<<"The file is not loaded or does not exist"<<endl; return -1; } cout<<"Matrix"<<srcImg.rows<<" "<<srcImg.cols<<endl; Mat duplicate(srcImg.rows,srcImg.cols, CV_8UC1,Scalar::all(255) ); #pragma acc enter data copyin(srcImg[:srcImg.rows][:srcImg.cols]) #pragma acc enter data copyin(duplicate[:duplicate.rows][:duplicate.cols]) #pragma acc parallel { #pragma acc loop for(int i=0;i<srcImg.rows;i++){ #pragma acc loop for(int j=0;j<srcImg.cols;j++){ duplicate.at<uchar>(i,j)=srcImg.at<uchar>(i,j); } } #pragma acc data copyout(duplicate[:duplicate.rows][:duplicate.cols]) #pragma acc data copyout(srcImg[:srcImg.rows][:srcImg.cols]) } cout<<"duplicate"<<": "<<(int)duplicate.at<uchar>(23,45)<<endl; return 0; }
编译输出
main: 2216, Loop unrolled 4 times (completely unrolled) 36, Generating enter data copyin(duplicate,srcImg) Generating NVIDIA GPU code 38, #pragma acc loop gang /* blockIdx.x */ 40, #pragma acc loop vector(128) /* threadIdx.x */ 36, Generating implicit copyin(duplicate.step.p[:1],srcImg.step.p[:1],srcImg,duplicate)[if not already present] 40, Loop is parallelizable Loop not vectorized/parallelized: not countable cv::Matx<double, (int)4, (int)1>::Matx():
运行结果
Matrix810 1440 libgomp: TODO
编译命令
nvc++ -g -O3 -acc -gpu=cc60,cc70 -Minfo `pkg-config opencv4 --cflags --libs` -nomp -o nvcpp.out test.cpp
问题分析与解决建议
1. 隐式copyin提示的原因
cv::Mat是包含元数据(rows、cols、step等)和数据指针(data)的结构体。你使用srcImg[:srcImg.rows][:srcImg.cols]的写法,编译器会误解为复制结构体的切片,而非实际图像数据。当GPU代码需要访问step.p等结构体成员时,编译器会自动生成隐式copyin操作,将这些元数据复制到GPU。
2. libgomp: TODO错误的原因
尽管添加了-nomp参数,但代码中可能存在触发OpenMP运行时调用的逻辑,或者nvc++在特定场景下仍会链接libgomp库。另外,OpenACC数据区域的使用错误也可能间接导致该问题:
- 嵌套使用
#pragma acc data指令(parallel区域内又定义copyout),违反OpenACC数据区域的使用规则。 - 使用
Mat::at()成员函数在GPU区域内,该函数包含主机端的边界检查逻辑,无法在设备上正确执行。 - 数据区域的范围指定错误,未正确复制图像的实际数据。
3. 具体修复步骤
修正数据区域的写法:显式复制
cv::Mat结构体和实际数据:// 先复制结构体元数据 #pragma acc enter data copyin(srcImg, duplicate) // 再复制图像数据 #pragma acc enter data copyin(srcImg.data[:srcImg.rows * srcImg.cols], duplicate.data[:duplicate.rows * duplicate.cols])替换
Mat::at()为直接指针访问:在GPU区域内避免使用成员函数,直接通过数据指针计算偏移:uchar* src_data = srcImg.data; uchar* dup_data = duplicate.data; int src_step = srcImg.step; int dup_step = duplicate.step; #pragma acc parallel present(srcImg, duplicate, src_data, dup_data, src_step, dup_step) { #pragma acc loop gang vector(128) collapse(2) for(int i=0; i<srcImg.rows; i++){ for(int j=0; j<srcImg.cols; j++){ dup_data[i * dup_step + j] = src_data[i * src_step + j]; } } }修正数据区域生命周期:将copyout操作移到parallel区域外,使用
exit data指令:#pragma acc exit data copyout(duplicate.data[:duplicate.rows * duplicate.cols]) // 不需要copyout srcImg,因为是只读输入 #pragma acc exit data delete(srcImg, duplicate, src_data, dup_data, src_step, dup_step)确保禁用OpenMP运行时:改用
-mp=noopenmp参数替代-nomp,强制不链接libgomp:nvc++ -g -O3 -acc -gpu=cc60,cc70 -Minfo `pkg-config opencv4 --cflags --libs` -mp=noopenmp -o nvcpp.out test.cpp验证GPU架构匹配:确认编译时指定的
cc60,cc70与实际使用的GPU架构一致,若架构不匹配,会导致运行时错误。
内容的提问来源于stack exchange,提问作者Lance

