Memory CUDA常量内存分配是如何工作的?

Memory CUDA常量内存分配是如何工作的?,memory,cuda,constants,nvidia,gpu-constant-memory,Memory,Cuda,Constants,Nvidia,Gpu Constant Memory,我想了解一下如何分配常量内存(使用CUDA4.2)。我知道总可用的固定内存是64KB。但是这个内存实际上是什么时候分配到设备上的呢?这个限制适用于每个内核、cuda上下文还是整个应用程序 假设一个.cu文件中有几个内核,每个内核使用的常量内存少于64K。但总的恒定内存使用量超过64K。可以按顺序调用这些内核吗?如果使用不同的流并发调用它们会发生什么 如果有一个大型CUDA动态库,其中有许多内核,每个内核使用不同数量的常量内存,会发生什么 如果有两个应用程序各自需要超过一半的可用常量内存,会发生什

我想了解一下如何分配常量内存(使用CUDA4.2)。我知道总可用的固定内存是64KB。但是这个内存实际上是什么时候分配到设备上的呢?这个限制适用于每个内核、cuda上下文还是整个应用程序

假设一个
.cu
文件中有几个内核,每个内核使用的常量内存少于64K。但总的恒定内存使用量超过64K。可以按顺序调用这些内核吗?如果使用不同的流并发调用它们会发生什么

如果有一个大型CUDA动态库,其中有许多内核,每个内核使用不同数量的常量内存,会发生什么

如果有两个应用程序各自需要超过一半的可用常量内存,会发生什么情况?第一个应用程序运行正常,但第二个应用程序何时会失败?在应用程序启动时,在调用cudaMemcpyToSymbol()时或在内核执行时?

第5.1.3节讨论了常量库

恒定内存的大小受到限制,当前限制为64KB 可用于保存静态大小的常量变量。有一个 额外的640KB恒定内存,组织为十个独立的64KB 区域。驱动程序可以在内存中分配和初始化常量缓冲区 这些区域并将指针作为内核函数传递到缓冲区 参数。由于这十个区域不连续,因此驱动程序 必须确保分配常量缓冲区,以便每个缓冲区 完全适合64KB区域,不跨区域 边界

一个简单的程序可以用来说明常量内存的使用

__constant__ int    kd_p1;
__constant__ short  kd_p2;
__constant__ char   kd_p3;
__constant__ double kd_p4;

__constant__ float kd_floats[8];

__global__ void parameters(int p1, short p2, char p3, double p4, int* pp1, short* pp2, char* pp3,     double* pp4)
{
    *pp1 = p1;
    *pp2 = p2;
    *pp3 = p3;
    *pp4 = p4;
    return;
}

__global__ void constants(int* pp1, short* pp2, char* pp3, double* pp4)
{
    *pp1 = kd_p1;
    *pp2 = kd_p2;
    *pp3 = kd_p3;
    *pp4 = kd_p4;
    return;
}
为compute_30、sm_30编译此文件,并执行
cuobjdump-sass
进行反汇编,您应该看到

Fatbin elf code:
================
arch = sm_30
code version = [1,6]
producer = cuda
host = windows
compile_size = 32bit
identifier = c:/dev/constant_banks/kernel.cu

    code for sm_30
            Function : _Z10parametersiscdPiPsPcPd
    /*0008*/     /*0x10005de428004001*/     MOV R1, c [0x0] [0x44];        // stack pointer
    /*0010*/     /*0x40001de428004005*/     MOV R0, c [0x0] [0x150];       // pp1
    /*0018*/     /*0x50009de428004005*/     MOV R2, c [0x0] [0x154];       // pp2
    /*0020*/     /*0x0001dde428004005*/     MOV R7, c [0x0] [0x140];       // p1
    /*0028*/     /*0x13f0dc4614000005*/     LDC.U16 R3, c [0x0] [0x144];   // p2
    /*0030*/     /*0x60011de428004005*/     MOV R4, c [0x0] [0x158];       // pp3
    /*0038*/     /*0x70019de428004005*/     MOV R6, c [0x0] [0x15c];       // pp4
    /*0048*/     /*0x20021de428004005*/     MOV R8, c [0x0] [0x148];       // p4
    /*0050*/     /*0x30025de428004005*/     MOV R9, c [0x0] [0x14c];       // p4
    /*0058*/     /*0x1bf15c0614000005*/     LDC.U8 R5, c [0x0] [0x146];    // p3
    /*0060*/     /*0x0001dc8590000000*/     ST [R0], R7;                   // *pp1 = p1
    /*0068*/     /*0x0020dc4590000000*/     ST.U16 [R2], R3;               // *pp2 = p2
    /*0070*/     /*0x00415c0590000000*/     ST.U8 [R4], R5;                // *pp3 = p3
    /*0078*/     /*0x00621ca590000000*/     ST.64 [R6], R8;                // *pp4 = p4
    /*0088*/     /*0x00001de780000000*/     EXIT;
    /*0090*/     /*0xe0001de74003ffff*/     BRA 0x90;
    /*0098*/     /*0x00001de440000000*/     NOP CC.T;
    /*00a0*/     /*0x00001de440000000*/     NOP CC.T;
    /*00a8*/     /*0x00001de440000000*/     NOP CC.T;
    /*00b0*/     /*0x00001de440000000*/     NOP CC.T;
    /*00b8*/     /*0x00001de440000000*/     NOP CC.T;
            ...........................................


            Function : _Z9constantsPiPsPcPd
    /*0008*/     /*0x10005de428004001*/     MOV R1, c [0x0] [0x44];       // stack pointer
    /*0010*/     /*0x00001de428004005*/     MOV R0, c [0x0] [0x140];      // p1
    /*0018*/     /*0x10009de428004005*/     MOV R2, c [0x0] [0x144];      // p2
    /*0020*/     /*0x0001dde428004c00*/     MOV R7, c [0x3] [0x0];        // kd_p1
    /*0028*/     /*0x13f0dc4614000c00*/     LDC.U16 R3, c [0x3] [0x4];    // kd_p2
    /*0030*/     /*0x20011de428004005*/     MOV R4, c [0x0] [0x148];      // p3
    /*0038*/     /*0x30019de428004005*/     MOV R6, c [0x0] [0x14c];      // p4
    /*0048*/     /*0x20021de428004c00*/     MOV R8, c [0x3] [0x8];        // kd_p4
    /*0050*/     /*0x30025de428004c00*/     MOV R9, c [0x3] [0xc];        // kd_p4
    /*0058*/     /*0x1bf15c0614000c00*/     LDC.U8 R5, c [0x3] [0x6];     // kd_p3
    /*0060*/     /*0x0001dc8590000000*/     ST [R0], R7;
    /*0068*/     /*0x0020dc4590000000*/     ST.U16 [R2], R3;
    /*0070*/     /*0x00415c0590000000*/     ST.U8 [R4], R5;
    /*0078*/     /*0x00621ca590000000*/     ST.64 [R6], R8;
    /*0088*/     /*0x00001de780000000*/     EXIT;
    /*0090*/     /*0xe0001de74003ffff*/     BRA 0x90;
    /*0098*/     /*0x00001de440000000*/     NOP CC.T;
    /*00a0*/     /*0x00001de440000000*/     NOP CC.T;
    /*00a8*/     /*0x00001de440000000*/     NOP CC.T;
    /*00b0*/     /*0x00001de440000000*/     NOP CC.T;
    /*00b8*/     /*0x00001de440000000*/     NOP CC.T;
            .....................................
我在SASS的右边加了注释

在sm30上,您可以看到参数从偏移量0x140开始在常量列0中传递

用户定义的常量变量在常量组3中定义

如果执行
cuobjdump--dump elf
,您可以找到其他有趣的常量信息

32bit elf: abi=6, sm=30, flags = 0x1e011e
Sections:
Index Offset   Size ES Align   Type   Flags Link     Info Name
    1     34    142  0  1    STRTAB       0    0        0 .shstrtab
    2    176    19b  0  1    STRTAB       0    0        0 .strtab
    3    314     d0 10  4    SYMTAB       0    2        a .symtab
    4    3e4     50  0  4 CUDA_INFO       0    3        b .nv.info._Z9constantsPiPsPcPd
    5    434     30  0  4 CUDA_INFO       0    3        0 .nv.info
    6    464     90  0  4 CUDA_INFO       0    3        a .nv.info._Z10parametersiscdPiPsPcPd
    7    4f4    160  0  4  PROGBITS       2    0        a .nv.constant0._Z10parametersiscdPiPsPcPd
    8    654    150  0  4  PROGBITS       2    0        b .nv.constant0._Z9constantsPiPsPcPd
    9    7a8     30  0  8  PROGBITS       2    0        0 .nv.constant3
    a    7d8     c0  0  4  PROGBITS       6    3  a00000b .text._Z10parametersiscdPiPsPcPd
    b    898     c0  0  4  PROGBITS       6    3  a00000c .text._Z9constantsPiPsPcPd

.section .strtab

.section .shstrtab

.section .symtab
 index     value     size      info    other  shndx    name
   0          0        0        0        0      0     (null)
   1          0        0        3        0      a     .text._Z10parametersiscdPiPsPcPd
   2          0        0        3        0      7     .nv.constant0._Z10parametersiscdPiPsPcPd
   3          0        0        3        0      b     .text._Z9constantsPiPsPcPd
   4          0        0        3        0      8     .nv.constant0._Z9constantsPiPsPcPd
   5          0        0        3        0      9     .nv.constant3
   6          0        4        1        0      9     kd_p1
   7          4        2        1        0      9     kd_p2
   8          6        1        1        0      9     kd_p3
   9          8        8        1        0      9     kd_p4
  10         16       32        1        0      9     kd_floats
  11          0      192       12       10      a     _Z10parametersiscdPiPsPcPd
  12          0      192       12       10      b     _Z9constantsPiPsPcPd

内核参数常量库在每次启动时都会进行版本控制,以便可以执行并发内核。编译器和用户常量是每个CUmodule的。开发人员有责任管理这些数据的一致性。例如,开发人员必须确保以安全的方式更新cudaMemcpyToSymbol。

常量内存是上下文的属性,而不是特定的内核。在较新的硬件上,内核不会“使用”参数列表之外的常量内存,并且该内存的最大值总是限制为4kb。@Talonmes。。。恒定内存不是64KB吗?@sgar91:是的。但我没有说别的。我说的是,在费米/开普勒上,内核参数驻留在恒定内存中,每个内核的最大内存限制为4kb。有关于恒定记忆的有趣信息。但是,它并没有说明当您尝试使用超过64KB的内存时会发生什么。谢谢!我只熟悉运行时API,所以我将做一些研究来解释您的答案。我知道有10个64k内存库,每个积木都有固定的内存分配,但我仍然不清楚这些如何回答我最初的问题。。。