OpenACC 调度
OpenACC Scheduling
假设我有这样的构造:
for(int i=0;i<5000;i++){
const int upper_bound = f(i);
#pragma acc parallel loop
for(int j=0;j<upper_bound;j++){
//Do work...
}
}
其中 f
是 i
的单调递减函数。
由于 num_gangs
、num_workers
和 vector_length
未设置,OpenACC 选择它认为合适的调度。
但是它是每次遇到pragma就重新选择这样的调度,还是第一次遇到pragma就只选择一次?
查看PGI_ACC_TIME
的输出表明调度只执行一次。
根据 OpenAcc 2.6 规范[1] 第 1357 和 1358 行:
A loop associated with a loop construct that does not have a seq clause must be written such that the loop iteration count is computable when entering the loop construct.
似乎是这样,所以你的代码是有效的。
但是,请注意,实现定义了如何在帮派和工人之间分配工作,并且 PGI 编译器可能只是对迭代进行一些简单的划分。
您可以使用 num_gangs 和 num_workers 手动定义 gang/workers 的值,传递给这些子句的整数表达式可以取决于您的函数的值(参见 2.5.7 和 2.5.8 OpenACC 规范)。
[1] https://www.openacc.org/sites/default/files/inline-files/OpenACC.2.6.final.pdf
PGI 编译器会在编译时选择如何分解工作,但通常会在运行时确定帮派的数量。组本质上是可扩展的并行性,因此可以推迟到运行时决定有多少。向量长度和 worker 数量会影响底层内核的生成方式,因此通常在编译时选择它们以最大化优化机会。对于像这样的循环,在编译时实际上并不知道边界,编译器必须在内核中生成一些额外的代码以确保执行正确的迭代次数。
假设我有这样的构造:
for(int i=0;i<5000;i++){
const int upper_bound = f(i);
#pragma acc parallel loop
for(int j=0;j<upper_bound;j++){
//Do work...
}
}
其中 f
是 i
的单调递减函数。
由于 num_gangs
、num_workers
和 vector_length
未设置,OpenACC 选择它认为合适的调度。
但是它是每次遇到pragma就重新选择这样的调度,还是第一次遇到pragma就只选择一次?
查看PGI_ACC_TIME
的输出表明调度只执行一次。
根据 OpenAcc 2.6 规范[1] 第 1357 和 1358 行:
A loop associated with a loop construct that does not have a seq clause must be written such that the loop iteration count is computable when entering the loop construct.
似乎是这样,所以你的代码是有效的。
但是,请注意,实现定义了如何在帮派和工人之间分配工作,并且 PGI 编译器可能只是对迭代进行一些简单的划分。 您可以使用 num_gangs 和 num_workers 手动定义 gang/workers 的值,传递给这些子句的整数表达式可以取决于您的函数的值(参见 2.5.7 和 2.5.8 OpenACC 规范)。
[1] https://www.openacc.org/sites/default/files/inline-files/OpenACC.2.6.final.pdf
PGI 编译器会在编译时选择如何分解工作,但通常会在运行时确定帮派的数量。组本质上是可扩展的并行性,因此可以推迟到运行时决定有多少。向量长度和 worker 数量会影响底层内核的生成方式,因此通常在编译时选择它们以最大化优化机会。对于像这样的循环,在编译时实际上并不知道边界,编译器必须在内核中生成一些额外的代码以确保执行正确的迭代次数。