Sunky Blog

Back

本节介绍由 ptxas 定义的 .pragma 字符串。

12.1. Pragma 字符串:“nounroll”#

"nounroll"

在优化后端编译器中禁用循环展开。

.pragma "nounroll";

"nounroll" pragma 是一条用于在优化后端编译器中禁用循环展开的 指示符。

"nounroll" pragma 允许出现在模块、入口函数和语句三个级别, 其含义如下:

模块作用域

禁用模块内所有循环的展开,包括位于 .pragma 之前的循环。

入口函数作用域

禁用入口函数体内所有循环的展开。

语句级 pragma

禁用以当前块为循环头的那个循环的展开。

注意,若要在语句级达到预期效果,"nounroll" 指示符必须出现在目标循环的循环头 基本块中任何指令语句之前。循环头块定义为支配循环体内所有块、且为循环回边目标的块。出现在 循环头块之外的语句级 "nounroll" 指示符会被静默忽略。

.entry foo (...)
.pragma "nounroll";  // do not unroll any loop in this function
{
...
}

.func bar (…) { … L1_head: .pragma “nounroll”; // do not unroll this loop … @p bra L1_end; L1_body: … L1_continue: bra L1_head; L1_end: … }

12.2. Pragma 字符串:“used_bytes_mask”#

"used_bytes_mask"

用于指示 ld 操作数据中被使用字节的掩码。

.pragma "used_bytes_mask mask";

"used_bytes_mask" pragma 是一条根据所提供的掩码指定加载操作中 被使用字节的指示符。

"used_bytes_mask" pragma 需要写在某条加载指令之前,且需要获知该加载 操作所使用字节的信息。 若其后的指令不是加载指令,则该 pragma 会被忽略。

对于没有此 pragma 的加载指令,假定加载操作的所有字节都会被使用。

操作数 mask 是一个 32 位整数,其中置位的比特指示加载操作数据中被使用的 字节。

Each bit in mask operand corresponds to a byte data where each set bit represents the used byte.
Most-significant bit corresponds to most-significant byte of data.

// For 4 bytes load with only lower 3 bytes used .pragma “used_bytes_mask 0x7”; ld.global.u32 %r0, [gbl]; // Higher 1 byte from %r0 is unused

// For vector load of 16 bytes with lower 12 bytes used .pragma “used_bytes_mask 0xfff”; ld.global.v4.u32 {%r0, %r1, %r2, %r3}, [gbl]; // %r3 unused

.pragma "used_bytes_mask 0xfff";
ld.global.v4.u32 {%r0, %r1, %r2, %r3}, [gbl]; // Only lower 12 bytes used

12.3. Pragma 字符串:“enable_smem_spilling”#

"enable_smem_spilling"

为 CUDA kernel 启用共享内存溢出。

.pragma "enable_smem_spilling";

"enable_smem_spilling" pragma 是一条启用向共享内存进行寄存器溢出的指示符。 在溢出过程中,寄存器首先溢出到共享内存,当分配的共享内存写满后,任何额外的溢出都会被重定向到 局部内存。由于共享内存访问比局部内存更快,这可以通过降低访存延迟来提升性能。

"enable_smem_spilling" pragma 仅允许在函数作用域内使用。应用后, 它为指定函数启用共享内存溢出。

该 pragma 仅在某些场景和特定编译模式下使用有效。在以下情况下不允许使用该 pragma, 否则可能导致错误:

  • 逐函数编译模式:例如分离编译、设备调试、含递归函数调用的整程序编译、可扩展整程序编译

  • 使用动态分配共享内存的 kernel

  • 使用 setmaxnreg 指令的 kernel

注意

如果未显式指定启动界限,编译器将假设每个 CTA 可能的最大线程数,据此估算每个 CTA 分配的 共享内存及相应的溢出大小。但是,如果 kernel 启动时每个 CTA 的线程数少于估算值,每个 CTA 分配的共享内存可能超出编译器估计的大小,从而可能限制一个 SM 上可启动的 CTA 数量。因此, 在未指定启动界限的情况下使用该 pragma 可能导致性能回退。故建议仅在显式指定启动界限时使用 此 pragma。

.entry foo (...)
{
    ...
    .pragma "enable_smem_spilling";   // Enable shared memory spilling for this function
    ...
}

12.4. Pragma 字符串:“frequency”#

"frequency"

指定基本块的执行频率。

.pragma "frequency n";

"frequency" pragma 是一条指定基本块被执行线程执行次数的指示符。 优化编译器后端将此 pragma 视为用于优化的提示。

操作数 n 是一个指定执行频率的 64 位非负整数常量。

注意,若要使该 pragma 达到预期效果,应将其指定在基本块的开头。基本块定义为只有单一入口 和单一出口的直线指令序列。

.entry foo (...)
{
    .pragma "frequency 32";
    ...
}

12.5. Pragma 字符串:“mma_throughput”#

"mma_throughput"

为 mma 操作启用编译器的循环优化。

.pragma "mma_throughput";

"mma_throughput" pragma 是一条用于在编译器中为 mma 操作启用 循环优化的指示符。

该 pragma 仅允许在入口函数作用域使用。指定该 pragma 的入口函数将启用编译器优化。

.entry test_kernel()
{
    ....
    ....
    .pragma "mma_throughput";
    ....
    ....
}
EN