У меня есть простое ядро CUDA, которое, как я думал, эффективно обращается к глобальной памяти. Однако профилировщик Nvidia сообщает, что я выполняю неэффективный доступ к глобальной памяти. Мой код ядра:
__global__ void update_particles_kernel
(
float4 *pos,
float4 *vel,
float4 *acc,
float dt,
int numParticles
)
{
int index = threadIdx.x + blockIdx.x * blockDim.x;
int offset = 0;
while(index + offset < numParticles)
{
vel[index + offset].x += dt*acc[index + offset].x; // line 247
vel[index + offset].y += dt*acc[index + offset].y;
vel[index + offset].z += dt*acc[index + offset].z;
pos[index + offset].x += dt*vel[index + offset].x; // line 251
pos[index + offset].y += dt*vel[index + offset].y;
pos[index + offset].z += dt*vel[index + offset].z;
offset += blockDim.x * gridDim.x;
}
В частности, профайлер сообщает следующее:
Из лучшего практическое руководство говорит:
"Для устройств с вычислительными возможностями 2.x требования можно сформулировать довольно просто: одновременный доступ потоков варпа будет объединяться в количество транзакций, равное количеству строк кэша, необходимых для обслуживания всех потоков варпа. По умолчанию все обращения кешируются через L1, который представляет собой 128-байтовые строки. Для разрозненных шаблонов доступа, чтобы уменьшить перевыборку, иногда может быть полезно кэшировать только в L2, который кеширует более короткие 32-байтовые сегменты ( см. Руководство по программированию CUDA C).
Для устройств с вычислительными возможностями 3.x доступ к глобальной памяти кэшируется только в L2; L1 зарезервирован для доступа к локальной памяти. Некоторые устройства с вычислительными возможностями 3.5, 3.7 или 5.2 также допускают кэширование глобальных переменных в L1."
Теперь, основываясь на этой информации, я ожидаю, что в моем ядре потребуется 16 доступов для обслуживания 32-поточного деформирования, потому что float4 составляет 16 байт, а на моей карте (770 м вычислительных возможностей 3.0) чтение из кеша L2 выполняется фрагментами по 32 байта ( 16 байт * 32 потока / 32 байта строк кэша = 16 обращений). Действительно, как вы можете видеть, профилировщик сообщает, что я выполняю 16 доступов. Чего я не понимаю, так это того, почему профилировщик сообщает, что идеальный доступ будет включать 8 транзакций L2 за доступ к строке 247 и только 4 транзакции L2 за доступ к остальным строкам. Может кто-нибудь объяснить, что мне здесь не хватает?