Я публикую детализированный код для обзора. Я считаю, что он должен компилироваться и выполняться без каких-либо проблем, но поскольку я исключил все ненужные части, возможно, я допустил какую-то ошибку.
struct Users {
double A[96];
double B[32];
double C[32];
};
Это моя структура Users с массивами фиксированной длины. Ниже дана основная функция.
int main(int argc, char **argv) {
int numUsers = 10;
Users *users = new Users[numUsers];
double Step[96];
for (int i = 0; i < 32; i++) {
Step[i] = 0.8;
Step[i + 32] = 0.8;
Step[i + 64] = 0.8;
}
for (int usr = 0; usr < numUsers; usr++) {
for (int i = 0; i < 32; i++) {
users[usr].A[i] = 10;
users[usr].A[i + 32] = 20;
users[usr].A[i + 64] = 30;
}
memset(users[usr].B, 0, sizeof(double) * 32);
memset(users[usr].C, 0, sizeof(double) * 32);
}
double *d_Step;
cudaMalloc((void**)&d_Step, sizeof(double) * 96);
cudaMemcpy(d_Step, Step, sizeof(double) * 96, cudaMemcpyHostToDevice);
Users *deviceUsers;
cudaMalloc((void**)&deviceUsers, sizeof(Users) * numUsers);
cudaMemcpy(deviceUsers, users, sizeof(Users) * numUsers, cudaMemcpyHostToDevice);
dim3 grid;
dim3 block;
grid.x = 1;
grid.y = 1;
grid.z = 1;
block.x = 32;
block.y = 10;
block.z = 1;
calc<<<grid, block >>> (deviceUsers, d_Step, numUsers);
delete users;
return 0;
}
Обратите внимание, что массив Step представляет собой одномерный массив с 96 ячейками, и я охватываю 10 деформаций (32 потока в направлении x, и в моем блоке их 10). Каждая деформация будет обращаться к одному и тому же массиву шагов. Это можно увидеть ниже в ядре.
__global__ void calc(Users *users, double *Step, int numUsers) {
int tId = threadIdx.x + blockIdx.x * blockDim.x;
int uId = threadIdx.y;
while (uId < numUsers) {
double mean00 = users[uId].A[tId] * Step[tId];
double mean01 = users[uId].A[tId + 32] * Step[tId + 32];
double mean02 = users[uId].A[tId + 64] * Step[tId + 64];
users[uId].A[tId] = (mean00 == 0? 0 : 1 / mean00);
users[uId].A[tId + 32] = (mean01 == 0? 0 : 1 / mean01);
users[uId].A[tId + 64] = (mean02 == 0? 0 : 1 / mean02);
uId += 10;
}
}
Теперь, когда я использую NVIDIA Visual Profiler, объединенные извлечения составляют 47%. Я дополнительно исследовал и обнаружил, что массив Step, к которому обращается каждая деформация, вызывает эту проблему. Если я заменю его какой-либо константой, доступ будет объединен на 100%.
Q1) Насколько я понимаю, объединенные доступы связаны с байтовой строкой, т.е. байтовые строки должны быть кратны 32, независимо от того, являются ли они целыми или двухбайтовыми строками. Почему я не получаю объединенный доступ?
Насколько мне известно, cuda всякий раз, когда назначает блок памяти в глобальной памяти устройства, ему назначается четный адрес. Таким образом, до тех пор, пока начальная точка + 32 местоположения доступны через варп, доступ должен быть объединен. Я прав?
Аппаратное обеспечение
Geforce GTX 470, вычислительные возможности 2.0