Я профилировал мою модель, и кажется, что это ядро составляет около 2/3 от моей общей продолжительности. Я искал предложения по его оптимизации. Код выглядит следующим образом.Как оптимизировать это ядро CUDA
__global__ void calcFlux(double* concs, double* fluxes, double* dt)
{
int idx = blockIdx.x * blockDim.x + threadIdx.x;
fluxes[idx]=knowles_flux(idx, concs);
//fluxes[idx]=flux(idx, concs);
}
__device__ double knowles_flux(int r, double *conc)
{
double frag_term = 0;
double flux = 0;
if (r == ((maxlength)-1))
{
//Calculation type : "Max"
flux = -km*(r)*conc[r]+2*(ka)*conc[r-1]*conc[0];
}
else if (r > ((nc)-1))
{
//Calculation type : "F"
//arrSum3(conc, &frag_term, r+1, maxlength-1);
for (int s = r+1; s < (maxlength); s++)
{
frag_term += conc[s];
}
flux = -(km)*(r)*conc[r] + 2*(km)*frag_term - 2*(ka)*conc[r]*conc[0] + 2*(ka)*conc[r-1]*conc[0];
}
else if (r == ((nc)-1))
{
//Calculation type : "N"
//arrSum3(conc, &frag_term, r+1, maxlength-1);
for (int s = r+1; s < (maxlength); s++)
{
frag_term += conc[s];
}
flux = (kn)*pow(conc[0],(nc)) + 2*(km)*frag_term - 2*(ka)*conc[r]*conc[0];
}
else if (r < ((nc)-1))
{
//Calculation type : "O"
flux = 0;
}
return flux;
}
Просто чтобы дать вам представление о том, почему цикл является проблемой, это ядро запускается на массиве около MAXLENGTH = 9000 элементов. В наших целях теперь nc находится в диапазоне 2-6. Вот иллюстрация того, как это ядро обрабатывает входящий массив (conc). Для этого массива необходимо использовать пять разных типов вычислений для разных групп элементов.
Array element : 0 1 2 3 4 5 6 7 8 9 ... 8955 8956 8957 8958 8959 8960
Type of calc : M O O O O O N F F F ... F F F F F Max
Потенциальные проблемы я пытался бороться с прямо сейчас ветвью дивергенция от четверки, если-то еще и для цикла.
Моя идея иметь дело с расходящимся ветвлением заключается в том, чтобы разбить это ядро на четыре отдельные функции устройства или ядра, которые обрабатывают каждый регион отдельно и все запускаются одновременно. Я не уверен, что это значительно лучше, чем просто позволить разветвлению отрасли, что, если я не ошибаюсь, приведет к запуску четырех типов вычислений в серийном режиме.
Чтобы справиться с циклом for, вы заметите, что есть прокомментированная функция arrSum3, которую я написал, основываясь на моем ранее (и, вероятно, плохо) написанном параллельном ядре сокращения. Использование его вместо цикла for резко увеличило время выполнения. Я чувствую, что есть умный способ добиться того, что я пытаюсь сделать с циклом for, но я просто не настолько умный, и мой советник устал от того, что я «теряю время», думая об этом.
Цените любую помощь.
EDIT
Полный код находится здесь: https://stackoverflow.com/q/21170233/1218689
Что такое конц? Массив парных? Часто ли этот массив изменяется? Если да, то как часто? Изменяется ли какой-либо элемент conc во время вычисления knowles_flux, т. Е. Происходит ли обновление параллельно? – Xephon
Кажется, что вы делаете много избыточного суммирования вашего массива conc. Если вы делаете префиксную сумму массива, как только вы можете найти сумму любой смежной подобласти массива из prefix_sum [high] - prefix_sum [low]. С очень большими массивами или очень разными значениями в массиве вы можете столкнуться с проблемами точности, но это может отлично работать для вашего случая. – mattnewport
@Xephon Conc действительно представляет собой массив двойников. Conc запускается через ядро, которое вычисляет потоки. Потоки затем используются для продвижения conc через шаг времени. Нет, conc не изменяется во время вычисления потока. conc - массив концентраций для этого временного шага и остается неизменным через пять итераций вычисления knowles_flux (5-6 раз для интегратора Рунге Кутта). –