为什么一个简单的 CUDA 函数需要这么多本地内存
Why a simple CUDA function needs so much local memory?
我在 CUDA 上写了一个简单的函数。它将图像大小调整为双倍比例。对于 1920*1080 的图像,此函数需要 ~20ms 才能完成。我已经尝试了一些不同的方法来优化该功能。而我发现可能是本地内存的关键原因。
我尝试了三种不同的方法来获取图像。
- OpenCV 中的 GPU 模块
- 在OpenCV中与GpuMat的纹理绑定
- 从全局内存中直接获取 GpuMat
他们都不能给我带来一点改善。
然后我使用 nvvp 找出原因。在上述所有三种情况下,本地内存开销均为 ~95%。
所以我转向我的代码来了解 nvcc 如何使用内存。然后我发现一个简单的函数就像这样:
__global__ void performDoubleImage(float* outData, size_t step, const int cols, const int rows)
{
int x = threadIdx.x + blockIdx.x * blockDim.x;
if (x >= cols)
return;
int y = threadIdx.y + blockIdx.y * blockDim.y;
if (y >= rows)
return;
((float*)((size_t)outData+y*step))[x] = tex2D(texRef, x/2, y/2);
}
需要 80 字节的堆栈帧(它们在本地内存中(。
还有另一个像这样的函数:
__global__ void performFinalDoubleImage(const PtrStepSz<float> in, PtrStepSz<float> out)
{
out(out.rows-1, out.cols-1) = out(in.rows-1, in.cols-1);
}
还需要 88 字节的堆栈帧。
问题是,为什么我的函数在这个简单的任务中使用如此多的本地内存和寄存器?为什么OpenCV中的函数可以在不使用本地内存的情况下执行相同的功能(这是nvvp测试的,本地内存负载为零(?
我的代码是在调试模式下编译的。我的卡是GT650(192 SP/SM,2 SM(。
你发布的两个函数太简单了,不能使用那么多堆栈,事实上它们根本不应该使用堆栈。溢出如此多的最可能原因是您在禁用优化的情况下进行编译(例如,在调试模式下(。
作为参考,Robert Crovella 在发布和调试模式下编译了您的第一个内核:
调试:
ptxas 信息:_Z18performDoubleImagePfmii 256 字节堆栈帧、0 字节溢出存储、0 字节溢出加载的函数属性 ptxas 信息:已用 23 个寄存器、296 字节累积堆栈大小、56 字节 cmem[0]、1 个纹理
释放:
ptxas 信息:_Z18performDoubleImagePfmii 0 字节堆栈帧、0 字节溢出存储、0 字节溢出加载的函数属性 ptxas 信息:已用 9 个寄存器、56 字节 cmem[0]、1 个纹理
请注意堆栈和寄存器使用情况的差异。如注释中所述,在测量程序性能时,应始终针对最大优化级别进行编译,否则测量将毫无意义。
- 从构造函数抛出异常时如何克服内存泄漏
- 对具有动态分配的内存和析构函数的类对象的引用
- 调用析构函数以释放动态分配的内存
- std::unordered_map析构函数不释放内存?
- 为什么类和 main() 函数中也有动态内存分配
- 为什么此函数会导致内存泄漏?
- 给定一个指向堆分配内存的指针,智能指针实现如何为其找到合适的释放函数?
- 在函数中分配内存时出现问题
- 在没有动态内存的世界中,我是否需要虚拟析构函数?
- 如何为 std::vector 分配内存,然后稍后为某些元素调用构造函数?
- 具有相同特征的两个对象是否只在内存中存储一次?无论定义它们的函数是什么,都是不同的
- 在构造函数中分配内存失败是如何冒泡的
- 将 vector<vector<int>> 传递到函数中会产生内存错误
- 在 Microsoft Access SQL 中调用自定义 DLL 函数时传递的内存地址无效
- 如何在 c++ 中的析构函数中正确释放合并 LL 的内存?
- 为什么 free() 函数不将内存返回给操作系统?
- 从函数返回时C++内存管理
- 无法在循环中动态分配内存(函数会吃掉所有内存)
- 在c++中使用C动态内存函数避免分段错误
- 用C/ c++在Windows上解压缩内存函数