全局变量
Host侧的全局变量与C++语言的全局变量特性相同,本节介绍的全局变量特指Device侧支持的全局变量。
Device侧的全局变量必须定义在命名空间作用域或者顶层作用域。由于异构结构的存在,用于区分Device侧和Host侧全局变量,所有Device侧的全局变量都需要关键字__gm__修饰。
__gm__ int g_device; //device side global variable int g_host; //host side global variable
全局变量的代码示例如下:
// built-in type global variable __gm__ bool bool_noinit; __gm__ int8_t int8_t_init = -8; __gm__ int32_t int32_t_arr_a[3] = {-321, -322}; __gm__ int64_t int64_t_arr_twodim[3][4] = {{-641, -642, -643, -644}}; enum DAY {MON=1,TUE,WED,THU,FRI,SAT,SUN}; // user defined type global variable __gm__ enum DAY day = FRI; struct SIMPLE{int32_t i32;uint8_t ui8;int16_t i16;}; struct COMPLEX{bool b;struct SIMPLE simple;}; __gm__ struct COMPLEX complex = {true, {-32, 8, -16 }}; union DATA{int32_t u_i32;uint64_t u_ui64;uint8_t arr_ui8[16];}; __gm__ union DATA data = {.u_i32 = 32}; // pointers __gm__ int* __gm__ p; // declares a pointer p in the gm address space //that points to an object in the gm address space int * __gm__ p2; // declares a pointer p2 in the gm address space //that points to an object in the private address space, //usually on the stack // reference global variable __global__ [aicore] void kernel(__gm__ int* hbm_out) { *hbm_out++ = int32_t_arr_a[1]; *hbm_out++ = complex.simple.i32; }
由于异构程序中Device侧代码和runtime配合模式的特殊性,Device侧全局变量的使用需参见注意事项。
注意事项
- 在Host侧,main函数前会有一些初始化代码运行,用于调用如全局的类的构造等。然而,对于异构程序的代码运行,并没有初始化阶段,runtime在Device直接加载并运行kernel,所以Device侧全局变量只支持POD(Plain Old Data,没有构造函数)类型的全局变量。
struct A { int m; }; __gm__ struct A a={1}; //OK class B: public A { int m; }; __gm__ struct B b; //Error, B is not a POD class struct C { virtual void foo(); }; __gm__ struct C c; //Error, C is not a POD class
- 在通用CPU上,未初始化的全局变量通常是没有大小的,系统在加载的时候给它们分配的空间,当前昇腾AI处理器不支持加载.bss段,因此未初始化的全局变量也会一并放在.data段。此约束会导致编译出来的二进制较大。
- 只读的全局变量(常量)在.rodata段。
- 当前芯片的实现当数据从Cacheline逐出时,是整条Cacheline一起反刷到DDR,为了防止反刷时弄脏DDR上的数据,全局变量必须是Cacheline长度对齐。芯片Cacheline是256Byte。
- 开发者需要注意,多个block之间写同一个全局变量,最后的结果是跟调度相关的。
父主题: CCE Intrinsic特性