Я пытаюсь использовать cublas
функцию cublasSgemmBatched
в моем примере игрушки. В этом примере я сначала выделяю двумерные массивы: h_AA, h_BB
размера [6
] [] и h_CC
размера [6
] [1
]. После этого я скопировал его на устройство, выполнив cublasSgemmBatched
и попытался скопировать массив d_CC
обратно в массив хоста h_CC
. Тем не менее, я получил ошибку (cudaErrorLaunchFailure
) с устройством для размещения копирования и я не уверен, что я скопировал массивы в устройство правильно:Копирование массива указателей в память устройства и обратно (CUDA)
int main(){
cublasHandle_t handle;
cudaError_t cudaerr;
cudaEvent_t start, stop;
cublasStatus_t stat;
const float alpha = 1.0f;
const float beta = 0.0f;
float **h_AA, **h_BB, **h_CC;
h_AA = new float*[6];
h_BB = new float*[6];
h_CC = new float*[6];
for (int i = 0; i < 6; i++){
h_AA[i] = new float[5];
h_BB[i] = new float[5];
h_CC[i] = new float[1];
for (int j = 0; j < 5; j++){
h_AA[i][j] = j;
h_BB[i][j] = j;
}
h_CC[i][0] = 1;
}
float **d_AA, **d_BB, **d_CC;
cudaMalloc(&d_AA, 6 * sizeof(float*));
cudaMalloc(&d_BB, 6 * sizeof(float*));
cudaMalloc(&d_CC, 6 * sizeof(float*));
cudaerr = cudaMemcpy(d_AA, h_AA, 6 * sizeof(float*), cudaMemcpyHostToDevice);
cudaerr = cudaMemcpy(d_BB, h_BB, 6 * sizeof(float*), cudaMemcpyHostToDevice);
cudaerr = cudaMemcpy(d_CC, h_CC, 6 * sizeof(float*), cudaMemcpyHostToDevice);
stat = cublasCreate(&handle);
stat = cublasSgemmBatched(handle, CUBLAS_OP_N, CUBLAS_OP_N, 1, 1, 5, &alpha,
(const float**)d_AA, 1, (const float**)d_BB, 5, &beta, d_CC, 1, 6);
cudaerr = cudaMemcpy(h_CC, d_CC, 6 * sizeof(float*), cudaMemcpyDeviceToHost);
cublasDestroy(handle);
}
Так что этот код работает, однако последний cudaerr
возвращается cudaErrorLaunchFailure
. Я пытался следовать этому образцу кода на Github.
P.S. Что я не понимаю, что такое sizeof(float*)
и как cudaMalloc
знает, сколько памяти требуется для каждого массива (например, здесь я определяю только размер 1).
UPDATE: Я сделал это !!:
cublasHandle_t handle;
cudaError_t cudaerr;
cudaEvent_t start, stop;
cublasStatus_t stat;
const float alpha = 1.0f;
const float beta = 0.0f;
float *h_A = new float[5];
float *h_B = new float[5];
float *h_C = new float[6];
for (int i = 0; i < 5; i++)
{
h_A[i] = i;
h_B[i] = i;
}
float **h_AA, **h_BB, **h_CC;
h_AA = (float**)malloc(6* sizeof(float*));
h_BB = (float**)malloc(6 * sizeof(float*));
h_CC = (float**)malloc(6 * sizeof(float*));
for (int i = 0; i < 6; i++){
cudaMalloc((void **)&h_AA[i], 5 * sizeof(float));
cudaMalloc((void **)&h_BB[i], 5 * sizeof(float));
cudaMalloc((void **)&h_CC[i], sizeof(float));
cudaMemcpy(h_AA[i], h_A, 5 * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(h_BB[i], h_B, 5 * sizeof(float), cudaMemcpyHostToDevice);
}
float **d_AA, **d_BB, **d_CC;
cudaMalloc(&d_AA, 6 * sizeof(float*));
cudaMalloc(&d_BB, 6 * sizeof(float*));
cudaMalloc(&d_CC, 6 * sizeof(float*));
cudaerr = cudaMemcpy(d_AA, h_AA, 6 * sizeof(float*), cudaMemcpyHostToDevice);
cudaerr = cudaMemcpy(d_BB, h_BB, 6 * sizeof(float*), cudaMemcpyHostToDevice);
cudaerr = cudaMemcpy(d_CC, h_CC, 6 * sizeof(float*), cudaMemcpyHostToDevice);
stat = cublasCreate(&handle);
stat = cublasSgemmBatched(handle, CUBLAS_OP_N, CUBLAS_OP_N, 1, 1, 5, &alpha,
(const float**)d_AA, 1, (const float**)d_BB, 5, &beta, d_CC, 1, 6);
cudaerr = cudaMemcpy(h_CC, d_CC, sizeof(float), cudaMemcpyDeviceToHost);
for (int i = 0; i < 6;i++)
cudaMemcpy(h_C+i, h_CC[i], sizeof(float), cudaMemcpyDeviceToHost);
cublasDestroy(handle);
Перепутанные данные, которые вы передаете, вызывают одно из ядер, запускаемых при вызове группового гемма. Как асинхронная ошибка, вы не можете получать уведомление об этом до следующего вызова cuda. Изучали ли вы пакетные кубы [образец кода cuda] (http://docs.nvidia.com/cuda/cuda-samples/index.html#batchcublas)? –
Я этого не делал сейчас –
Я сделал это! Благодарю. Итак, правильно ли я понимаю: для того, чтобы иметь дело с двумерными массивами устройств, вы должны создать массив узлов указателей на массивы устройств и после этого скопировать этот массив в память массива 2D-устройств. Чтобы получить массив 2D-хоста из массива 2D-устройств, вы должны снова использовать промежуточный 2D-массив, который представляет собой массив указателей узлов на массивы устройств. Я опубликовал рабочий код в Update –