首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >利用__forceinline__增加CUDA栈帧大小

利用__forceinline__增加CUDA栈帧大小
EN

Stack Overflow用户
提问于 2013-11-22 12:13:40
回答 1查看 1.1K关注 0票数 2

当我用__forceinline__声明设备功能时,链接器输出以下信息:

代码语言:javascript
复制
2>  nvlink : info : Function properties for '_ZN3GPU4Flux4calcILj512EEEvv':
2>  nvlink : info : used 28 registers, 456 stack, 15776 bytes smem, 320 bytes cmem[0], 0 bytes lmem

没有它,输出是:

代码语言:javascript
复制
2>  nvlink : info : Function properties for '_ZN3GPU4Flux4calcILj512EEEvv':
2>  nvlink : info : used 23 registers, 216 stack, 15776 bytes smem, 320 bytes cmem[0], 0 bytes lmem

当不使用__forceinline__时,为什么堆栈帧的大小更小?保持堆栈帧尽可能小有多重要?谢谢你的帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-11-23 22:39:41

减少堆栈帧的主要原因是堆栈被分配到驻留在片外设备内存中的本地内存中。这使得对堆栈(如果没有缓存)的访问变得缓慢。

为了说明这一点,让我举一个简单的例子。考虑以下情况:

代码语言:javascript
复制
__device__ __noinline__ void func(float* d_a, float* test, int tid) {
    d_a[tid]=test[tid]*d_a[tid];
}

__global__ void kernel_function(float* d_a) {
    float test[16];
    test[threadIdx.x] = threadIdx.x;
    func(d_a,test,threadIdx.x);
}

注意,__device__函数被声明为__noinline__。在这种情况下

代码语言:javascript
复制
ptxas : info : Function properties for _Z15kernel_functionPf
    64 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads
ptxas : info : Used 7 registers, 36 bytes cmem[0]

也就是说,我们有堆栈帧的64字节。相应的解压缩代码是

代码语言:javascript
复制
MOV R1, c[0x1][0x100];
ISUB R1, R1, 0x40;
S2R R6, SR_TID.X;                    R6 = ThreadIdx.x
MOV R4, c[0x0][0x20];
IADD R5, R1, c[0x0][0x4];
I2F.F32.U32 R2, R6;                  R2 = R6 (integer to float conversion)              
ISCADD R0, R6, R1, 0x2;
STL [R0], R2;                        stores R2 to test[ThreadIdx.x]                                
CAL 0x50; 
EXIT ;                               __device__ function part
ISCADD R2, R6, R5, 0x2;
ISCADD R3, R6, R4, 0x2;
LD R2, [R2];                         loads d_a[tid]
LD R0, [R3];                         loads test[tid]
FMUL R0, R2, R0;                     d_a[tid] = d_a[tid]*test[tid]
ST [R3], R0;                         store the new value of d_a[tid] to global memory
RET ;

如您所见,test是从全局内存存储和加载的,形成堆栈框架(它是16 floats = 64 bytes)。

现在将设备功能更改为

代码语言:javascript
复制
__device__ __forceinline__ void func(float* d_a, float* test, int tid) {
    d_a[tid]=test[tid]*d_a[tid];
}

也就是说,将__device__函数从__noinline__更改为__forceinline__。在这种情况下,我们

代码语言:javascript
复制
ptxas : info : Compiling entry function '_Z15kernel_functionPf' for 'sm_20'
ptxas : info : Function properties for _Z15kernel_functionPf
    0 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads

也就是说,我们现在有一个空的堆栈框架。实际上,分解后的代码变成:

代码语言:javascript
复制
MOV R1, c[0x1][0x100];               
S2R R2, SR_TID.X;                    R2 = ThreadIdx.x
ISCADD R3, R2, c[0x0][0x20], 0x2;    
I2F.F32.U32 R2, R2;                  R2 = R2 (integer to float conversion)
LD R0, [R3];                         R2 = d_a[ThreadIdx.x] (load from global memory)
FMUL R0, R2, R0;                     d_a[ThreadIdx.x] = d_a[ThreadIdx.x] * ThreadIdx.x
ST [R3], R0;                         stores the new value of d_a[ThreadIdx.x] to global memory
EXIT ;

正如您所看到的,强制内联使编译器能够执行适当的优化,从而使test从代码中完全丢弃。

在上面的例子中,__forceinline__有一个与您正在经历的相反的效果,这也表明,如果没有任何进一步的信息,第一个问题是无法回答的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20144661

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档