Я новичок в Cuda и читаю учебные пособия и другой открытый исходный код, чтобы попытаться понять вещи.Я знаю общую концепцию иерархий потоков.
TL; DR, все прочитанные мною учебные пособия предполагали, что данные, отправляемые в ядро, также организованы в этой иерархии, без явного указания перед запуском ядра.Разве данные, передаваемые ядру, не должны быть переупорядочены в иерархии grid> block> thread перед передачей в ядро?Ниже приведены два фрагмента, которые смутили меня в этом отношении.
Я следовал этому x_plus_y
уроку здесь .В этом уроке следующий фрагмент:
_global__
void add(int n, float *x, float *y)
{
int index = blockIdx.x * blockDim.x + threadIdx.x;
int stride = blockDim.x * gridDim.x;
for (int i = index; i < n; i += stride)
y[i] = x[i] + y[i];
}
В приведенном выше фрагменте мы хотим добавить соответствующие элементы в x
и y
, но как мне узнать, что x
и y
помещены в графический процессор так, что индекс i
(который вычисляется с использованием blockIdx, blockDim и т. д.) фактически указывает на соответствующие элементы x
и y
.Если x
и y
помещаются один за другим в память, не должен ли индекс, используемый для y
, учитывать длину x
?Мне не хватает некоторого ключевого интуитивного понимания здесь.Кроме того, как мне узнать, где в графическом процессоре был отображен какой-то случайный элемент массива, скажем, x [1011]?Или мне не нужно заботиться о точном позиционировании моих данных из-за какой-то абстракции?
Я также расскажу о другом фрагменте из репозитория с открытым исходным кодом.Это ядро для вычисления метрики расстояния между двумя наборами облаков точек.Каждое облако представляет собой матрицу Nx3
(имеет N
3-D точек).
b
- размер пакета (таким образом, b
количество облаков передается ядру)
n
- количество точек в каждом облаке первого набора
m
- количество точек в каждом облаке второго сета.
Например, первый набор облаков может быть (16,1024,3), а второй набор (16,512,3):
__global__ void NmDistanceKernel(int b,int n,const float * xyz,int m,const float * xyz2,float * result,int * result_i){
const int batch=512;
__shared__ float buf[batch*3];
for (int i=blockIdx.x;i<b;i+=gridDim.x){
for (int k2=0;k2<m;k2+=batch){
int end_k=min(m,k2+batch)-k2;
for (int j=threadIdx.x;j<end_k*3;j+=blockDim.x){
buf[j]=xyz2[(i*m+k2)*3+j];
}
for (int j=threadIdx.x+blockIdx.y*blockDim.x;j<n;j+=blockDim.x*gridDim.y){
float x1=xyz[(i*n+j)*3+0];
float y1=xyz[(i*n+j)*3+1];
float z1=xyz[(i*n+j)*3+2];
}
}
}
Вышеприведенное ядро запускается следующим образом:
NmDistanceKernel<<<dim3(32,16,1),512>>>(batch_size, n, xyz1.data<float>(), m, xyz2.data<float>(), dist1.data<float>(), idx1.data<int>());
Опять же, в вышеупомянутом ядре автор предположил, что данные, которые они передали ядру, организованы так, что механизм индексации будет работать.Они явно не помещали каждую точку в каждом потоке, а затем группу точек внутри блока и группу облаков внутри сетки.Эта структура, однако, предполагается внутри ядра.