gpt4 book ai didi

cuda - 了解每个线程的 cuda 堆内存限制

转载 作者:行者123 更新时间:2023-12-04 04:47:44 24 4
gpt4 key购买 nike

这个问题是关于 cuda 中的堆大小限制。
访问了有关此主题的一些问题,包括以下问题:
new operator in kernel .. strange behaviour
我做了一些测试。给定一个内核如下:

#include <cuda.h>
#include <cuda_runtime.h>
#define CUDA_CHECK( err ) __cudaSafeCall( err, __FILE__, __LINE__ )
#define CUDA_CHECK_ERROR() __cudaCheckError( __FILE__, __LINE__ )
inline void __cudaSafeCall( cudaError err, const char *file, const int line )
{
if ( cudaSuccess != err )
{
fprintf( stderr, "cudaSafeCall() failed at %s:%i : %s\n",
file, line, cudaGetErrorString( err ) );
exit( -1 );
}
return;
}

inline void __cudaCheckError( const char *file, const int line )
{
cudaError err = cudaGetLastError();
if ( cudaSuccess != err )
{
fprintf( stderr, "cudaCheckError() failed at %s:%i : %s\n",
file, line, cudaGetErrorString( err ) );
exit( -1 );
}
return;
}
#include <stdio>
#define NP 900000
__device__ double *temp;
__device__ double *temp2;
__global__
void test(){
int i = blockDim.x*blockIdx.x + threadIdx.x;
if(i==0){
temp = new double[NP];
//temp2 = new double[NP];
}

if(i==0){
for(int k=0;k<NP;k++){
temp[i] = 1.;
if(k%1000 == 0){
printf("%d : %g\n", k, temp[i]);
}
}
}
if(i==0){
delete(temp);
//delete(temp2);
}
}
int main(){
//cudaDeviceSetLimit(cudaLimitMallocHeapSize, 32*1024*1024);
//for(int k=0;k<2;k++){
test<<<ceil((float)NP/512), 512>>>();
CUDA_CHECK_ERROR();
//}
return 0;
}
我想测试堆大小限制。
  • 用一个线程动态分配一个数组(临时),其大小为
    大约超过 960,000*sizeof(double)(接近 8MB,这是
    堆大小的默认限制)给出一个错误:好的。 900,000 件作品。 (有人知道如何计算真正的极限吗?)
  • 提高堆大小限制允许分配更多内存:正常,好的。
  • 回到 8MB 堆大小,为每个线程分配一个数组和两个线程(因此,将 if (i==0) 替换为 if(i==0 || i==1),每个 900,000 * sizeof(double) 失败. 但是每个 450,000*sizeof(double) 都有效。仍然可以。
  • 我的问题来了:用一个线程分配两个数组(因此,线程 0 的 temp 和 temp2),每个 900,000 * sizeof(double) 也可以工作,但不应该吗?实际上,当我尝试在两个数组中写入时,它都失败了。但是任何人都知道为什么在使用两个数组和一个线程而不是两个数组和两个线程时在分配中会有这种不同的行为?

  • 编辑:另一个测试,我觉得对于像我一样将学习 heap 用法的人来说很有趣:
    5、内核执行两次,单线程0分配一个大小为900,000 * sizeof(double)的数组,如果有delete就可以工作。如果省略删除,第二次会失败,但会执行第一次调用。
    编辑 2:如何分配一个设备范围的变量一次但可由所有线程写入(不是来自主机,在设备代码中使用动态分配)?

    最佳答案

    可能您没有在 new 上测试返回的空指针操作,这是一个 valid method in C++ for the operator to report a failure .

    当我按如下方式修改您的代码时,我收到消息“第二个新失败”:

    #include <stdio.h>

    #define NP 900000
    __device__ double *temp;
    __device__ double *temp2;
    __global__
    void test(){
    int i = blockDim.x*blockIdx.x + threadIdx.x;
    if(i==0){
    temp = new double[NP];
    if (temp == 0) {printf("first new failed\n"); return;}
    temp2 = new double[NP];
    if (temp2 == 0) {printf("second new failed\n"); return;}
    }

    if(i==0){
    for(int k=0;k<NP;k++){
    temp[i] = 1.;
    if(k%1000 == 0){
    printf("%d : %g\n", k, temp[i]);
    }
    }
    }
    if(i==0){
    delete(temp);
    delete(temp2);
    }
    }

    int main() {

    test<<<1,1>>>();
    cudaDeviceSynchronize();
    return 0;
    }

    如果您像我一样提供完整的、可编译的代码供其他人使用,那会很方便。

    对于您的第一个 EDIT 问题,如果删除第一个,第二个 new 将起作用也就不足为奇了。第一个分配了几乎所有可用的 8MB。如果您删除该分配,则第二个分配将成功。引用 documentation ,我们看到以这种方式动态分配的内存在 cuda 上下文的整个生命周期内都存在,或者直到执行相应的删除操作(即不仅仅是单个内核调用。内核的完成不一定释放分配。)

    对于您的第二个编辑问题,您已经在演示一种方法,使用您的 __device__ double *temp;指针,通过它一个线程可以分配所有线程都可以访问的存储空间。但是,跨块会遇到问题,因为无法保证块之间的同步顺序或块之间的执行顺序,因此如果从块 0 中的线程 0 分配,则仅当块 0 在其他块之前执行时才有用。您可以想出一个复杂的方案来检查变量分配是否已经完成(可能通过测试指针是否为 NULL,也可能使用原子),但它会创建脆弱的代码。最好提前计划您的全局分配,并从主机进行相应的分配。

    关于cuda - 了解每个线程的 cuda 堆内存限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17929054/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com