鲲鹏社区首页
中文
注册
开发者
我要评分
获取效率
正确性
完整性
易理解
在线提单
论坛求助

用法介绍

1. “hbm” 和 “nohbm” 关键字属性

全局变量

1
2
int __attribute__((hbm)) GlobalHBMArr[100];
int __attribute__((nohbm))GlobalNoHBMArr[100];

局部变量

1
2
int *__attribute__((nohbm)) Ptr1 = (int *)malloc(100*sizeof(int));
int * __attribute__((hbm)) Ptr2 = (int *)malloc(100*sizeof(int));

函数参数

1
2
3
4
5
void foo(int *  __attribute__((nohbm))Output, int * __attribute__((hbm)) Input) {
	for (int i = 0; i < 100; i++) {
		Output[i] = i * (i + 1) + Input[i];
	}
}

5.0.0版本起新增支持flat模式下通过导语将全局数组和栈数组内存申请至HBM功能,编译器默认使能,用户可以通过添加”-mllvm -enable-gv-hbm-attr=false”和”-mllvm -enable-lsv-hbm-attr=false”手动关闭。

2. __builtin_hbm_prefetch(address, distance)

address: 需要预取的数据,指针或数组, 必选参数

distance:预取提前量,指的是提前的cycle数, 必选参数

1
2
3
4
5
// 预取数据ArrB,提前量为100
for(int i = 0; i < 1000; i++) {
  __builtin_hbm_prefetch(ArrB, 100);
  ArrA[i] += ArrB[i] + ArrC[i];
}

3. pragma clang loop prefetch(variable, locality, distance)

variable: 必选参数。要预取的数据,必须是一个已经声明的指针或数组变量,支持load/store访存和intrinsic类型访存。

locality: 可选参数。指定cache级别,如果不指定,则编译器自动判断。‘0’: no reuse , ‘1’ : L1 cache , ‘2’: L2 cache , ‘3’: L3 cache, ‘4’: HBM cache

distance: 可选参数。指定循环迭代提前量。使用该参数,必须指定locality。参数必须为大于0的整数。

pragma clang loop noprefetch(variable)

variable: 必选参数。不做预取优化的数据,必须是一个已经声明的指针或数组变量。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 预取数据"a"、"b"到HBM缓存, 预取提前量为默认值
#pragma clang loop prefetch(a, 4)
#pragma clang loop prefetch(b, 4)
for (int i = 0; i < n; i++) {
    sum += a[i] + b[i];
}

// 数据"a"不做软件预取优化
#pragma clang loop noprefetch(a)
for (int i = 0; i < n; i++) {
    sum += a[i] + b[i];
}

Fortran当前也支持预取导语,对应的格式是:

1
2
!$mem prefetch(variable, locality, distance)
!$mem noprefetch(variable)

4.编译器自动预取选项“-fhbm-mode=cache”

添加该选项编译器会分析函数中循环的访存特征,并根据代价模型对数据进行优先级排序,并为优先级高的数据插入预取指令。编译器代价模型中包含以下因素:

  • 循环在并行域中,比如OpenMP导语指定的并行区域
  • 访存特征:直接访存、间接访存,间接访存计算权重更大
  • 访存stride越大计算权重越大
  • 写内存比读内存有更高的权重
  • 循环深度:内层循环计算权重更大
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// case1中,ApsiPtr,psiPtr是间接访存,具有较高优先级,而ApsiPtr是写内存,所以优先级最高。
// 优先级顺序为ApsiPtr > psiPtr > 其他
void case1(double *diagPtr, double *psiPtr, double *ApsiPtr, int *lPtr, int *uPtr, double *lowerPtr, double *upperPtr, int nFaces)
{
    for (int face=0; face<nFaces; face++)
    {
        ApsiPtr[uPtr[face]] += lowerPtr[face]*psiPtr[lPtr[face]];
        ApsiPtr[lPtr[face]] += upperPtr[face]*psiPtr[uPtr[face]];
    }
}

// case2中,ApsiPtr两处访存其中一处为写内存,优先级最高。psiPtr两处访存优先级次之
// 优先级顺序为 ApsiPtr > psiPtr > lPtr > diagPtr
void case2(double *diagPtr, double *psiPtr, double *ApsiPtr, int *lPtr, int nCells)
{
    for (int cell=0; cell<nCells; cell++) {
        ApsiPtr[cell] = diagPtr[cell]*psiPtr[cell];
    }
    for (int cell=0; cell<nCells; cell++) {
        lPtr[cell] = ApsiPtr[cell] * psiPtr[cell];
    }
}

用户可以通过一些选项调整编译器cost model:

-mllvm -hbm-prefetch-percentage=$value:指定插入预取指令的比例,数值越大插入的预取指令越多,默认值0.25

-mllvm -hbm-prefetch-max-num=$value: 指定预取的最大数量,默认值10

-mllvm -filter-hbm-functions=$"func1, func2":指定过滤掉的函数名称,对于过滤掉的函数不做自动预取。

-mllvm -loop-prefetch-writes: 指定为写内存操作插入预取,默认值不插入。

-mllvm -indirect-load-prefetch: 指定为间接访存操作插入预取,默认不插入。

5. malloc自动替换选项“-fhbm-mode=flat”

编译器根据代价模型识别需要替换的malloc调用,将其替换为hbw_malloc,用于分配HBM内存。当前只有在OpenMP导语指定的并行区域中存在use的数据会做替换。编译时需要加"-lmemkind"链接选项,并保证环境中包含对应的库。