以下程序连续3次调用" test"执行某些推力操作的功能。这3个调用中的每一个都为问题提供了不同的大小:
第二次调用预计会失败,但如果我正确清理了GPU的状态,第三次调用应该会成功(就像第一次调用一样)。不幸的是,它也失败了。此外,在我退出流程并重新开始之前,连续调用也会导致失败。
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <cuda.h>
#include <thrust/system_error.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/execution_policy.h>
#define CUDA_CALL(x)do { if((x) != cudaSuccess) { return -11;}} while(0)
typedef typename thrust::device_vector<size_t> tDevVecInt;
typedef typename thrust::device_vector<float> tDevVecFlt;
struct modSim : public thrust::unary_function<int, int>
{
int szMat;
int p;
modSim(int in1, int in2)
{
this->p = in1;
this->szMat = in2;
}
__host__ __device__ int operator()(const int &x)
{
return (x/szMat)*p+(x%p);
}
};
int test(size_t szData)
{
modSim moduloCol(3, 33);
CUDA_CALL(cudaSetDevice(0));
try
{
tDevVecFlt devRand(szData);
tDevVecInt devIndices(szData);
tDevVecFlt devData(szData);
thrust::sequence(devRand.begin(), devRand.end());
thrust::tabulate(devIndices.begin(), devIndices.end(), moduloCol);
thrust::sort_by_key(devIndices.begin(), devIndices.end(), devRand.begin());
}
catch(std::bad_alloc &e)
{
std::cout << e.what() << std::endl;
CUDA_CALL(cudaDeviceReset());
CUDA_CALL(cudaSetDevice(0));
return -3;
}
catch(thrust::system_error &e)
{
std::cout << e.what() << std::endl;
CUDA_CALL(cudaDeviceReset());
CUDA_CALL(cudaSetDevice(0));
return -2;
}
CUDA_CALL(cudaDeviceReset());
return 0;
}
int main(void)
{
size_t n;
int retVal;
n = 3000;
retVal = test(n);
std::cout << retVal << std::endl;
n = 300000000;
retVal = test(n);
std::cout << retVal << std::endl;
n = 3000;
retVal = test(n);
std::cout << retVal << std::endl;
return(0);
}
在我的设置上(Windows 8,带有2GB专用VRAM的NVIDIA GeForce 820m,使用nvcc编译的CUDA 7.0,命令行是&#34; $ nvcc -arch = compute_20 test.cu -run&#34;),我得到了这个:
bad allocation: out of memory
; thrust::system error : after cub_::DeviceRadixSort::SortPairs(1): out of memory
。所以输出如下:
0
bad allocation: out of memory
-3
after cub_::DeviceRadixSort::SortPairs(1): out of memory
-2
如上所述,第三个呼叫不应该失败,因为它与成功的第一个呼叫相同。
此失败似乎是上一次调用(发出bad alloc
的调用)的结果,但我在bad alloc
之后用cudaDeviceReset()
和{{1}清除了所有内容}}。
尽管有清洁说明,设备仍未恢复功能状态,我不明白为什么。
如果我做错了什么,在第一次失败后将GPU恢复到功能状态而不结束我的过程会是什么?
有人重现这个吗?
答案 0 :(得分:1)
此行为已报告给NVIDIA问题列表。来自NVIDIA的人们重现了这种行为,乍看之下无法解释。
然而,他们为我提供了一个我想与之分享可能感兴趣的解决方法。我的想法只是在检测到异常时添加对cudaGetLastError()
的调用,而不是(或在我的情况下,之前)调用cudaDeviceReset()
。
catch(std::bad_alloc &e)
{
std::cout << e.what() << std::endl;
CUDA_CALL(cudaGetLastError());
CUDA_CALL(cudaDeviceReset());
CUDA_CALL(cudaSetDevice(0));
return -3;
}
然后,经过进一步调查,他们发现实际上cudaDeviceReset()
函数不是真正的问题,并给了我以下解释:
cudaDeviceReset()
显式销毁并清除当前进程中与当前设备关联的所有资源。调用此函数时,调用者有责任确保进程中的任何其他主机线程不访问该设备。此外,Cuda运行时调用的任何错误都在内部注册,可以使用cudaPeekAtLastError()
或cudaGetLastError()
进行查看。第一个可以多次调用以读取相同的错误,而后者则用于读取和清除错误。建议在使用cudaGetLastError()
进行后续Cuda运行时调用之前清除先前的错误。
然后从这一点开始,我发现了一个我之前没有达到过的讨论here,它处理了类似的问题。答案也值得一读。