每个CUDA线程的本地内存量

dev*_*484 3 memory cuda limit gpu-local-memory

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

我尝试用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;
}
Run Code Online (Sandbox Code Playgroud)

和编译命令行:

nvcc -o cuda_test_private_memory -Xptxas -v -O2 --compiler-options -Wall cuda_test_private_memory.cu
Run Code Online (Sandbox Code Playgroud)

编译没问题,并报告:

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]
Run Code Online (Sandbox Code Playgroud)

当我在每个线程达到65000字节时,我在GTX 580上运行时出现"内存不足"错误.以下是控制台中程序的确切输出:

MEMSIZE=65000 bytes.
GPUassert: out of memory cuda_test_private_memory.cu 48
Run Code Online (Sandbox Code Playgroud)

我还使用GTX 770 GPU(在Linux上使用CUDA 6.5)进行了测试.对于MEMSIZE = 200000,它运行没有错误,但是在MEMSIZE = 250000时,运行时发生了"内存不足错误".

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

Rob*_*lla 6

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

ptxas info:_Z19kernel_test_privatePc的函数属性

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

在这种情况下,您打算本地的变量位于(GPU线程)堆栈上.

基于由@njuffa提供的信息在这里,可用堆栈大小限制的较小者:

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

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

我怀疑你的GTX770上的类似计算会产生类似的结果,即最大堆栈大小在200000和250000之间.

  • 因为内核中的'malloc`与分配本地内存无关,所以唯一的方法似乎是在内核中使用静态分配,这受到线程堆栈的限制(我的GTX 580案例中为65 Ko).那么[文档]中报告的512 Ko"每个线程的本地内存量"是什么(http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical - 规格)适用于? (2认同)