CUDA: разделяемый элемент данных структуры и элемент ссылки на эту структуру имеют разные адреса, значения
Хорошо, вот в чем проблема: используя CUDA 1.1 compute gpu, я пытаюсь поддерживать набор (возможно, различное количество, здесь фиксированное значение 4) индексов для потока, ссылку на которые я сохраняю как член struct var. Моя проблема в том, что получение ссылки на структуру приводит к неправильным результатам при доступе к массиву-члену: я инициализирую значения массива-члена с 0, когда я читаю значения массива, используя исходную структуру var, я получаю правильное значение (0), но когда я читаю его, используя ссылку на struct var, я получаю мусор (-8193). Это происходит даже при использовании класса вместо структуры.
почему тмп ниже!= 0??
С ++ не мой основной язык, так что это может быть концептуальная проблема, или это может быть причудой работы в cuda
struct DataIdx {
int numFeats;
int* featIdx;
};
extern __shared__ int sharedData[];
__global__ void myFn(){
int tidx = blockIdx.x * blockDim.x + threadIdx.x;
DataIdx myIdx; //instantiate the struct var in the context of the current thread
myIdx.numFeats = 4;
size_t idxArraySize = sizeof(int)*4;
//get a reference to my array for this thread. Parallel Nsight debugger shows myIdx.featIdx address = 0x0000000000000000e0
myIdx.featIdx = (int*)(&sharedData[tidx*idxArraySize]);
myIdx.featIdx[0] = 0x0; //set first value to 0
int tmp = myIdx.featIdx[0]; // tmp is correctly eq to 0 in Nsight debugger -- As Expected!!
tmp = 2*tmp; antIdx.featIdx[0] = tmp; //ensure compiler doesn't elide out tmp
DataIdx *tmpIdx = &myIdx; //create a reference to my struct var
tmp = tmpIdx.featIdx[0]; // expected 0, but tmp = -8193 in debugger !! why? debugger shows address of tmpIdx.featIdx = __devicea__ address=8
tmpIdx.featIdx[0] = 0x0;
tmp = tmpIdx.featIdx[0]; // tmp = -1; cant even read what we just set
//forcing the same reference as myIdx.featIdx, still gives a problem! debugger shows address of tmpIdx.featIdx = __devicea__ address=8
tmpIdx->featIdx = (int*)(&sharedData[tidx*idxArraySize]);
tmp = tmpIdx.featIdx[0]; //tmp = -8193!! why != 0?
DataIdx tmpIdxAlias = myIdx;
tmp = tmpIdx.featIdx[0]; //aliasing the original var gives correct results, tmp=0
myIdx.featIdx[0] = 0x0;
mySubfn(&myIdx); //this is a problem because it happens when passing the struct by reference to subfns
mySubfn2(myIdx);
}
__device__ mySubfn(struct DataIdx *myIdx){
int tmp = myIdx->featIdx[0]; //tmp == -8193!! should be 0
}
__device__ mySubfn2(struct DataIdx &myIdx){
int tmp = myIdx.featIdx[0]; //tmp == -8193!! should be 0
}
1 ответ
Мне пришлось изменить ваш код для компиляции. В соответствии
tmpIdx->featIdx[0] = 0x0
компилятор не понимает указатель на разделяемую память. Вместо сохранения в общую память (R2G) он сохраняет глобальный адрес 0x10, выходящий за пределы.
DataIdx *tmpIdx = &myIdx;
0x000024c8 MOV32 R2, R31;
0x000024cc MOV32 R2, R2;
tmp = tmpIdx->featIdx[0];
tmpIdx->featIdx[0] = 0x0;
0x000024d0 MOV32 R3, R31;
0x000024d4 MOV32 R2, R2;
0x000024d8 IADD32I R4, R2, 0x4;
0x000024e0 R2A A1, R4;
0x000024e8 LLD.U32 R4, local [A1+0x0];
0x000024f0 IADD R4, R4, R31;
0x000024f8 SHL R4, R4, R31;
0x00002500 IADD R4, R4, R31;
0x00002508 GST.U32 global14 [R4], R3; // <<== GLOBAL STORE vs. R2G (register to global register file)
tmp = tmpIdx->featIdx[0];
Средство проверки памяти Nsight CUDA перехватывает хранилище за пределами глобальной памяти.
Проверка памяти обнаружила 1 нарушение прав доступа. ошибка = нарушение прав доступа в хранилище (глобальной памяти) blockIdx = {0,0,0} threadIdx = {0,0,0} address = 0x00000010 accessSize = 0
Если вы компилируете для compute_10,sm_10
(на самом деле <= 1.3) вы должны увидеть следующее предупреждение для каждой строки, что компилятор не может определить, является ли доступ к общей памяти:
kernel.cu(46): warning : Cannot tell what pointer points to, assuming global memory space
Если вы добавите cudaDeviceSynchronize после запуска, вы должны увидеть код ошибки cudaErrorUnknown, вызванный выходом за пределы памяти.
__shared__
это спецификатор переменной памяти, а не спецификатор типа, так что я знаю, как бы вы сказали компилятору, что featIdx всегда будет указывать на разделяемую память. В CC >= 2.0 компилятор должен преобразовать (int*)(&sharedData[tidx*idxArraySize]) в универсальный указатель.