简单循环的 OpenAcc 错误:内核执行期间的非法地址
OpenAcc error from simple loop: illegal address during kernel execution
当我尝试并行化这个简单循环时出现 "call to cuMemcpyDtoHsync returned error 700: Illegal address during kernel execution" 错误。
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<float> xF = {0, 1, 2, 3};
#pragma acc parallel loop
for (int i = 0; i < 4; ++i) {
xF[i] = 0.0;
}
return 0;
}
编译:$ pgc++ -fast -acc -std=c++11 -Minfo=accel -o test test.cpp
main:
6, Accelerator kernel generated
Generating Tesla code
9, #pragma acc loop gang, vector(4) /* blockIdx.x threadIdx.x */
std::vector<float, std::allocator<float>>::operator [](unsigned long):
1, include "vector"
64, include "stl_vector.h"
771, Generating implicit acc routine seq
Generating acc routine seq
Generating Tesla code
T3 std::__copy_move_a2<(bool)0, const float *, decltype((std::allocator_traits<std::allocator<float>>::_S_pointer_helper<std::allocator<float>>((std::allocator<float>*)0)))>(T2, T2, T3):
1, include "vector"
64, include "stl_vector.h"
/usr/bin/ld: error in /tmp/pgc++cAUEgAXViQSY.o(.eh_frame); no .eh_frame_hdr table will be created.
$ ./test
call to cuStreamSynchronize returned error 700: Illegal address during kernel execution
代码在没有#pragma 的情况下运行正常,但我想让它并行。我做错了什么?
尝试使用“-ta=tesla:managed”进行编译。
这里的问题是您没有显式管理主机和设备之间的数据移动,并且编译器无法为您隐式管理它,因为 std::vector 只是一个 class指针,因此编译器无法判断数据的大小。因此,设备正在使用主机地址,从而导致非法内存访问。
虽然您可以通过获取向量的原始指针然后使用数据子句复制向量的数据以及将向量本身复制到设备来自己管理数据,但使用 CUDA 统一内存(即"managed" 标志)并让 CUDA 运行时为您管理数据移动。
正如 Jerry 所说,通常不建议在并行代码中使用向量,因为它们不是线程安全的。在这种情况下没问题,但您可能会遇到其他问题,尤其是当您尝试推送或弹出数据时。最好使用数组。 Plus 阵列更易于在主机和设备副本之间进行管理。
% cat test.cpp
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<float> xF = {0, 1, 2, 3};
#pragma acc parallel loop
for (int i = 0; i < 4; ++i) {
xF[i] = 0.0;
}
for (int i = 0; i < 4; ++i) {
std::cout << xF[i] << std::endl;
}
return 0;
}
% pgc++ -ta=tesla:cc70,managed -Minfo=accel test.cpp --c++11 ; a.out
main:
6, Accelerator kernel generated
Generating Tesla code
9, #pragma acc loop gang, vector(4) /* blockIdx.x threadIdx.x */
6, Generating implicit copy(xF)
std::vector<float, std::allocator<float>>::operator [](unsigned long):
1, include "vector"
64, include "stl_vector.h"
771, Generating implicit acc routine seq
Generating acc routine seq
Generating Tesla code
0
0
0
0
当我尝试并行化这个简单循环时出现 "call to cuMemcpyDtoHsync returned error 700: Illegal address during kernel execution" 错误。
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<float> xF = {0, 1, 2, 3};
#pragma acc parallel loop
for (int i = 0; i < 4; ++i) {
xF[i] = 0.0;
}
return 0;
}
编译:$ pgc++ -fast -acc -std=c++11 -Minfo=accel -o test test.cpp
main:
6, Accelerator kernel generated
Generating Tesla code
9, #pragma acc loop gang, vector(4) /* blockIdx.x threadIdx.x */
std::vector<float, std::allocator<float>>::operator [](unsigned long):
1, include "vector"
64, include "stl_vector.h"
771, Generating implicit acc routine seq
Generating acc routine seq
Generating Tesla code
T3 std::__copy_move_a2<(bool)0, const float *, decltype((std::allocator_traits<std::allocator<float>>::_S_pointer_helper<std::allocator<float>>((std::allocator<float>*)0)))>(T2, T2, T3):
1, include "vector"
64, include "stl_vector.h"
/usr/bin/ld: error in /tmp/pgc++cAUEgAXViQSY.o(.eh_frame); no .eh_frame_hdr table will be created.
$ ./test
call to cuStreamSynchronize returned error 700: Illegal address during kernel execution
代码在没有#pragma 的情况下运行正常,但我想让它并行。我做错了什么?
尝试使用“-ta=tesla:managed”进行编译。
这里的问题是您没有显式管理主机和设备之间的数据移动,并且编译器无法为您隐式管理它,因为 std::vector 只是一个 class指针,因此编译器无法判断数据的大小。因此,设备正在使用主机地址,从而导致非法内存访问。
虽然您可以通过获取向量的原始指针然后使用数据子句复制向量的数据以及将向量本身复制到设备来自己管理数据,但使用 CUDA 统一内存(即"managed" 标志)并让 CUDA 运行时为您管理数据移动。
正如 Jerry 所说,通常不建议在并行代码中使用向量,因为它们不是线程安全的。在这种情况下没问题,但您可能会遇到其他问题,尤其是当您尝试推送或弹出数据时。最好使用数组。 Plus 阵列更易于在主机和设备副本之间进行管理。
% cat test.cpp
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector<float> xF = {0, 1, 2, 3};
#pragma acc parallel loop
for (int i = 0; i < 4; ++i) {
xF[i] = 0.0;
}
for (int i = 0; i < 4; ++i) {
std::cout << xF[i] << std::endl;
}
return 0;
}
% pgc++ -ta=tesla:cc70,managed -Minfo=accel test.cpp --c++11 ; a.out
main:
6, Accelerator kernel generated
Generating Tesla code
9, #pragma acc loop gang, vector(4) /* blockIdx.x threadIdx.x */
6, Generating implicit copy(xF)
std::vector<float, std::allocator<float>>::operator [](unsigned long):
1, include "vector"
64, include "stl_vector.h"
771, Generating implicit acc routine seq
Generating acc routine seq
Generating Tesla code
0
0
0
0