Объединение памяти при внедрении уравнений FDTD
Я пытался реализовать уравнения FDTD на графическом процессоре. Сначала я реализовал ядро, которое использовало глобальную память. Объединение памяти было не так уж велико. Поэтому я реализовал другое ядро, которое использовало разделяемую память для загрузки значений. Я работаю над сеткой 1024x1024
.
Код ниже
__global__ void update_Hx(float *Hx, float *Ez, float *coef1, float* coef2){
int x = threadIdx.x + blockIdx.x * blockDim.x;
int y = threadIdx.y + blockIdx.y * blockDim.y;
int offset = x + y * blockDim.x * gridDim.x;
__shared__ float Ez_shared[BLOCKSIZE_HX][BLOCKSIZE_HY + 1];
/*int top = offset + x_index_dim;*/
if(threadIdx.y == (blockDim.y - 1)){
Ez_shared[threadIdx.x][threadIdx.y] = Ez[offset];
Ez_shared[threadIdx.x][threadIdx.y + 1] = Ez[offset + x_index_dim];
}
else{
Ez_shared[threadIdx.x][threadIdx.y] = Ez[offset];
}
}
Константы BLOCKSIZE_HX
= 16
и BLOCKSIZE_HY
= 16
.
Когда я запускаю визуальный профайлер, он все еще говорит, что память не объединена.
EDIT: Я использую графическую карту GT 520 с вычислительной способностью cuda 2.1. Мои глобальные транзакции L2/Access = 7.5
т.е. есть 245 760
транзакций L2 для 32768
исполнений строки Ez_shared[threadIdx.x][threadIdx.y] = Ez[offset];
Global memory load efficiency
составляет 50%
.
Global memory load efficiency
= 100 * gld_requested_throughput/gld_throughput
Я не могу понять, почему так много обращений к памяти, хотя мои потоки ищут 16 последовательных значений. Может ли кто-нибудь указать мне, что я делаю неправильно?
EDIT: Спасибо за помощь.
Здесь проблема с шаблоном доступа к памяти. Вы получаете только 50% эффективности (как для L1, так и для L2), потому что вы получаете доступ к последовательным регионам из 16 поплавков, то есть 64 байта, но размер транзакции L1 составляет 128 байт. Это означает, что для каждых 64 байтов 128 байтов должны быть загружены в L1 (и, следовательно, также в L2).
У вас также есть проблемы с конфликтами в банках с разделяемой памятью, но это в настоящее время не отрицательно влияет на эффективность глобальной загрузки памяти.
Вы можете решить проблему эффективности загрузки несколькими способами. Проще всего было бы изменить размер блока размера x на 32. Если это не вариант, вы можете изменить расположение данных глобальной памяти, чтобы каждый два последовательных блока blockIdx.y([0, 1], [2,3] и т.д. ) будут отображены в непрерывный блок памяти. Если даже это не вариант, и вы должны загружать глобальные данные только один раз, вы могли бы использовать не кэшированные нагрузки глобальной памяти для обхода L1 - это поможет, потому что L2 использует транзакции по 32 байта, поэтому ваши 64 байта будут загружены в два L2 транзакции без накладных расходов.