我有一个内核,可以根据它们的位置(对角线或非对角线)来计算矩阵的不同元素。计算大小矩阵时,内核按预期工作:
但是,当我尝试计算大小为2383 x 2383的矩阵时,内核崩溃。具体来说,在cudaMemcpy()行上引发了错误“未指定的启动失败”,以将结果从设备返回到主机。通过研究,我了解到该错误通常是在内存访问超出范围的情况下发生的(例如在数组中),但是,我没有得到的是它适用于前三种情况,但不适用于2383 x 2383例。内核代码如下所示:
__global__ void createYBus(float *R, float *X, float *B, int numberOfBuses, int numberOfBranches, int *fromBus, int *toBus, cuComplex *y)
{
int rowIdx = blockIdx.y*blockDim.y + threadIdx.y;
int colIdx = blockIdx.x*blockDim.x + threadIdx.x;
int index = rowIdx*numberOfBuses + colIdx;
if (rowIdx<numberOfBuses && colIdx<numberOfBuses)
{
for (int i=0; i<numberOfBranches; ++i)
{
if (rowIdx==fromBus[i] && colIdx==fromBus[i]) { //diagonal element
y[index] = cuCaddf(y[index], make_cuComplex((R[i]/((R[i]*R[i])+(X[i]*X[i]))), (-(X[i]/((R[i]*R[i])+(X[i]*X[i])))+ (B[i]/2))));
}
if (rowIdx==toBus[i] && colIdx==toBus[i]) { //diagonal element
y[index] = cuCaddf(y[index], make_cuComplex((R[i]/((R[i]*R[i])+(X[i]*X[i]))), (-(X[i]/((R[i]*R[i])+(X[i]*X[i])))+ (B[i]/2))));
}
if (rowIdx==fromBus[i] && colIdx==toBus[i]) { //off-diagonal element
y[index] = make_cuComplex(-(R[i]/((R[i]*R[i])+(X[i]*X[i]))), X[i]/((R[i]*R[i])+(X[i]*X[i])));
}
if (rowIdx==toBus[i] && colIdx==fromBus[i]) { //off-diagonal element
y[index] = make_cuComplex(-(R[i]/((R[i]*R[i])+(X[i]*X[i]))), X[i]/((R[i]*R[i])+(X[i]*X[i])));
}
}
}
}
全局内存分配是通过对cudaMalloc()的调用完成的。代码中的分配如下:
cudaStat1 = cudaMalloc((void**)&dev_fromBus, numLines*sizeof(int));
cudaStat2 = cudaMalloc((void**)&dev_toBus, numLines*sizeof(int));
cudaStat3 = cudaMalloc((void**)&dev_R, numLines*sizeof(float));
cudaStat4 = cudaMalloc((void**)&dev_X, numLines*sizeof(float));
cudaStat5 = cudaMalloc((void**)&dev_B, numLines*sizeof(float));
cudaStat6 = cudaMalloc((void**)&dev_y, numberOfBuses*numberOfBuses*sizeof(cuComplex));
cudaStat7 = cudaMalloc((void**)&dev_Pd, numberOfBuses*sizeof(float));
cudaStat8 = cudaMalloc((void**)&dev_Qd, numberOfBuses*sizeof(float));
cudaStat9 = cudaMalloc((void**)&dev_Vmag, numberOfBuses*sizeof(float));
cudaStat10 = cudaMalloc((void**)&dev_theta, numberOfBuses*sizeof(float));
cudaStat11 = cudaMalloc((void**)&dev_Peq, numberOfBuses*sizeof(float));
cudaStat12 = cudaMalloc((void**)&dev_Qeq, numberOfBuses*sizeof(float));
cudaStat13 = cudaMalloc((void**)&dev_Peq1, numberOfBuses*sizeof(float));
cudaStat14 = cudaMalloc((void**)&dev_Qeq1, numberOfBuses*sizeof(float));
...
...
cudaStat15 = cudaMalloc((void**)&dev_powerMismatch, jacSize*sizeof(float));
cudaStat16 = cudaMalloc((void**)&dev_jacobian, jacSize*jacSize*sizeof(float));
cudaStat17 = cudaMalloc((void**)&dev_stateVector, jacSize*sizeof(float));
cudaStat18 = cudaMalloc((void**)&dev_PQindex, jacSize*sizeof(int));
其中cudaStatN的类型为cudaError_t以捕获错误。最后的四个分配是在代码的后面完成的,并且是针对另一个内核的。但是,这些分配是在调用相关内核之前完成的。
启动参数如下:
dim3 dimBlock(16, 16); //number of threads
dim3 dimGrid((numberOfBuses+15)/16, (numberOfBuses+15)/16); //number of blocks
//launch kernel once data has been copied to GPU
createYBus<<<dimGrid, dimBlock>>>(dev_R, dev_X, dev_B, numberOfBuses, numLines, dev_fromBus, dev_toBus, dev_y);
//copy results back to CPU
cudaStat6 = cudaMemcpy(y_bus, dev_y, numberOfBuses*numberOfBuses*sizeof(cuComplex), cudaMemcpyDeviceToHost);
if (cudaStat6 != cudaSuccess) {
cout<<"Device memcpy failed"<<endl;
cout<<cudaGetErrorString(cudaStat6)<<endl;
return 1;
}
我删除了时序代码,只是为了显示所使用的块和网格尺寸以及错误检查技术。
我还具有该函数的主机(C ++代码)版本,我将数据传递给两个函数,然后比较结果,首先,确保内核产生正确的结果,其次,在执行时间方面比较性能。我已经仔细检查了2383 x 2383情况的数据(正在从文本文件中读取数据并将其复制到全局内存中),但在数组访问/索引编制中未发现任何异常。
我使用的是Visual Studio 2010,因此尝试使用Nsight查找错误(我不太熟悉Nsight)。摘要报告概述指出:“报告了1个运行时API调用错误。(有关更多信息,请参阅CUDA运行时API调用报告。)在运行时API调用列表中,cudaMemcpy返回错误4-不确定线程ID( 5012)在表中具有任何意义-该数字随每次运行而变化。CUDAmemcheck工具(在命令行中)返回以下内容:
Thank you for using this program
========= Program hit cudaErrorLaunchFailure (error 4) due to "unspecified launch failure" on CUDA API call to cudaMemcpy.
========= Saved host backtrace up to driver entry point at error
=========
========= ERROR SUMMARY: 1 error
我知道我的内核不是最高效的,因为有许多全局内存访问。为什么更大的矩阵会导致内核崩溃?是否缺少我缺少的数组访问权限?任何帮助将不胜感激。
解决了问题。事实证明启用了WDDM TDR(超时检测恢复)并将延迟设置为2秒。这意味着如果内核执行时间超过2s,驱动程序将崩溃并恢复。这适用于图形和渲染(用于GPU的通用用途)。但是,在这种情况下,必须禁用TDR或增加延迟。通过将延迟增加到10s,崩溃错误“未指定的启动失败”不再出现,内核继续执行。
可以通过Nsight监视器中的Nsight选项或通过注册表(HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ GraphicsDrivers)-DWORDS Tdrdelay和Tdrlevel来完成TDR延迟(以及启用/禁用)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句