【问题标题】:Amount of local memory per CUDA thread每个 CUDA 线程的本地内存量
【发布时间】:2018-06-04 00:29:29
【问题描述】:

我在 NVIDIA 文档(http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical-specifications,表 #12)中读到,对于我的 GPU(GTX 580,计算能力 2.0),每个线程的本地内存量为 512 Ko。

我尝试在使用 CUDA 6.5 的 Linux 上检查此限制,但未成功。

这是我使用的代码(它的唯一目的是测试本地内存限制,它不会进行任何有用的计算):

#include <iostream>
#include <stdio.h>

#define MEMSIZE 65000  // 65000 -> out of memory, 60000 -> ok

inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=false)
{
    if (code != cudaSuccess) 
    {
        fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
        if( abort )
            exit(code);
    }
}

inline void gpuCheckKernelExecutionError( const char *file, int line)
{
    gpuAssert( cudaPeekAtLastError(), file, line);
    gpuAssert( cudaDeviceSynchronize(), file, line);    
}


__global__ void kernel_test_private(char *output)
{
    int c = blockIdx.x*blockDim.x + threadIdx.x; // absolute col
    int r = blockIdx.y*blockDim.y + threadIdx.y; // absolute row

    char tmp[MEMSIZE];
    for( int i = 0; i < MEMSIZE; i++)
        tmp[i] = 4*r + c; // dummy computation in local mem
    for( int i = 0; i < MEMSIZE; i++)
        output[i] = tmp[i];
}

int main( void)
{
    printf( "MEMSIZE=%d bytes.\n", MEMSIZE);

    // allocate memory
    char output[MEMSIZE];
    char *gpuOutput;
    cudaMalloc( (void**) &gpuOutput, MEMSIZE);

    // run kernel
    dim3 dimBlock( 1, 1);
    dim3 dimGrid( 1, 1);
    kernel_test_private<<<dimGrid, dimBlock>>>(gpuOutput);
    gpuCheckKernelExecutionError( __FILE__, __LINE__);

    // transfer data from GPU memory to CPU memory
    cudaMemcpy( output, gpuOutput, MEMSIZE, cudaMemcpyDeviceToHost);

    // release resources
    cudaFree(gpuOutput);
    cudaDeviceReset();

    return 0;
}

以及编译命令行:

nvcc -o cuda_test_private_memory -Xptxas -v -O2 --compiler-options -Wall cuda_test_private_memory.cu

编译没问题,报告:

ptxas info    : 0 bytes gmem
ptxas info    : Compiling entry function '_Z19kernel_test_privatePc' for 'sm_20'
ptxas info    : Function properties for _Z19kernel_test_privatePc
    65000 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas info    : Used 21 registers, 40 bytes cmem[0]

当我达到每个线程 65000 字节时,我在 GTX 580 上运行时遇到“内存不足”错误。这是控制台中程序的确切输出:

MEMSIZE=65000 bytes.
GPUassert: out of memory cuda_test_private_memory.cu 48

我还使用 GTX 770 GPU(在具有 CUDA 6.5 的 Linux 上)进行了测试。 MEMSIZE=200000 运行时没有错误,但 MEMSIZE=250000 在运行时出现“内存不足错误”。

如何解释这种行为?难道我做错了什么 ?

【问题讨论】:

  • 您使用的是哪个 CUDA 版本?这是linux还是windows?您是否在编译代码或运行代码时遇到“内存不足错误”? (将确切的错误文本粘贴到问题中)您用于编译代码的命令行是什么?我的猜测是您正在为 pre-cc2.0 架构进行编译。如果我为 cc1.1 架构编译此代码,我会在编译时收到“内存不足错误”,因为 cc1.x 设备对每个线程的本地内存 (16KB) 的限制更小。如果我为 cc2.0 架构编译,你的代码对我来说可以正常编译和运行。
  • 您的问题也可能来自这行代码:char output[MEMSIZE]; 这(主机代码)创建了一个基于堆栈的分配,这些类型的分配可能会因平台而受到限制。将确切的错误文本粘贴到问题中会有所帮助。 (您可以编辑自己的问题。)
  • @RobertCrovella 感谢您对我的问题感兴趣。我已经编辑了我的问题以添加缺失的信息。 cudaGetErrorString() 在运行时报告的确切错误文本是“内存不足”。
  • 这是一个非常棒的问答,几乎可以肯定是 cuda 程序员(包括我自己)的常见问题。我希望它能得到更多的关注!

标签: memory cuda limit gpu-local-memory


【解决方案1】:

看来您遇到的不是本地内存限制,而是堆栈大小限制:

ptxas info : _Z19kernel_test_privatePc 的函数属性

65000 字节堆栈帧,0 字节溢出存储,0 字节溢出加载

在本例中,您原本打算成为本地的变量位于(GPU 线程)堆栈上。

根据@njuffa here 提供的信息,可用堆栈大小限制是以下两者中的较小者:

  1. 最大本地内存大小(cc2.x 及更高版本为 512KB)
  2. GPU 内存/(#of SM)/(每个 SM 的最大线程数)

显然,第一个限制不是问题。我假设你有一个“标准”GTX580,它有 1.5GB 内存和 16 个 SM。 cc2.x 设备的每个多处理器最多有 1536 个常驻线程。这意味着我们有 1536MB/16/1536 = 1MB/16 = 65536 字节的堆栈。从总可用内存中减去一些开销和其他内存使用,因此堆栈大小限制低于 65536,显然在您的情况下介于 60000 和 65000 之间。

我怀疑在您的 GTX770 上进行类似的计算会产生类似的结果,即最大堆栈大小在 200000 到 250000 之间。

【讨论】:

  • 谢谢你的解释。我对 GTX 770(4 GB RAM,8 个 SM,每个 SM 最多 2048 个线程)进行了相同的计算,得到了 262144 字节的堆栈大小。这与我在 GTX 770 上遇到的 200000 字节和 250000 字节之间(更准确地说是 242000 字节和 245000 字节之间)的限制一致。我还使用 malloc() 将内核中的静态分配替换为动态分配:然后我能够分配 512 Ko 的本地内存(甚至更多,最多 7 Mo!)。
  • 如果您想要比内核中malloc 更多的内存,请查看the documentation 以提高堆内存分配限制。
  • 好的。我认为对malloc 的内核调用会分配local 内存。现在我知道内核内malloc 分配了全局内存堆,默认大小为 8 Mo。
  • 因为内核内malloc与分配本地内存无关,唯一的方法似乎是在内核中使用静态分配,受线程堆栈限制(我的GTX中为65 Ko 580 箱)。那么documentation 中报告的 512 Ko “每个线程的本地内存量”适用于什么?
猜你喜欢
  • 1970-01-01
  • 2011-12-31
  • 2013-07-29
  • 2013-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多