Планирование OpenACC
Скажи, что у меня есть такая конструкция:
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 выбирает то, что он считает соответствующим планированием.
Но выбирает ли он такое расписание заново каждый раз, когда сталкивается с прагмой, или только один раз, когда встречается прагма?
Глядя на вывод PGI_ACC_TIME
предполагает, что планирование выполняется только один раз.
2 ответа
Компилятор PGI выберет, как разложить работу во время компиляции, но, как правило, определит количество банд во время выполнения. Банды по своей сути являются масштабируемым параллелизмом, поэтому решение о том, сколько их можно отложить до времени выполнения. Длина вектора и количество рабочих влияет на то, как генерируется базовое ядро, поэтому они обычно выбираются во время компиляции, чтобы максимизировать возможности оптимизации. С такими циклами, когда границы на самом деле не известны во время компиляции, компилятор должен сгенерировать дополнительный код в ядре, чтобы точно выполнить правильное количество итераций.
Согласно спецификации OpenAcc 2.6 [1] строки 1357 и 1358:
Цикл, связанный с конструкцией цикла, у которой нет предложения seq, должен быть написан так, чтобы счетчик итераций цикла вычислялся при входе в конструкцию цикла.
Кажется, что это так, поэтому ваш код действителен.
Однако обратите внимание, что реализация определена как распределять работу между бандами и работниками, и может случиться так, что компилятор PGI просто делает простое разбиение итераций. Вы можете вручную определить значения gang/worker с помощью num_gangs и num_workers, и целочисленное выражение, переданное в эти предложения, может зависеть от значения вашей функции (см. 2.5.7 и 2.5.8 по спецификации OpenACC).
[1] https://www.openacc.org/sites/default/files/inline-files/OpenACC.2.6.final.pdf