Memory CUDA常量内存分配是如何工作的?
我想了解一下如何分配常量内存(使用CUDA4.2)。我知道总可用的固定内存是64KB。但是这个内存实际上是什么时候分配到设备上的呢?这个限制适用于每个内核、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动态库,其中有许多内核,每个内核使用不同数量的常量内存,会发生什么 如果有两个应用程序各自需要超过一半的可用常量内存,会发生什
.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内存库,每个积木都有固定的内存分配,但我仍然不清楚这些如何回答我最初的问题。。。