¿Por qué mi parámetros de copia de matriz 2D están siendo rechazados por la API del controlador?
Estoy intentando usar la API del controlador CUDA para copiar datos en una matriz 2D, en el programa enumerado a continuación, pero obtengo un error de “valor inválido” cuando paso mis parámetros de copia. ¿Qué valor en ellos está mal?
“`lang-cuda
#include <cuda.h>
#include <iostream>
#include <iomanip>
#include <numeric>
#include <limits>
#include <cstring>
[[noreturn]] void die(const std::string& message) {
std::cerr << message << "\n";
exit(EXIT_FAILURE);
}
void dieiferror(CUresult status, const std::string& extra_message) {
if (status != CUDA_SUCCESS) {
const char* error_string;
cuGetErrorString(status, &error_string);
die(extra_message + ": " + error_string);
}
}
template <typename t="void">
T* as_pointer(CUdeviceptr address) noexcept { return reinterpret_cast<t*>(address); }
CUdeviceptr as_address(void* ptr) noexcept { return reinterpret_cast<cudeviceptr>(ptr); }
int main() {
CUresult status;
int device_id = 0;
status = cuInit(0);
dieiferror(status, "Inicializando el controlador CUDA");
CUcontext pctx;
status = cuDevicePrimaryCtxRetain(&pctx, device_id);
dieiferror(status, "Obteniendo el contexto del dispositivo principal");
cuCtxSetCurrent(pctx);
struct { unsigned width, height; } dims = { 3, 3 };
std::cout << "Creando una matriz CUDA " << dims.width << " x " << dims.height << std::endl;
CUarray arr_handle;
{
CUDA_ARRAY_DESCRIPTOR array_descriptor;
array_descriptor.Width = dims.width;
array_descriptor.Height = dims.height;
array_descriptor.Format = CU_AD_FORMAT_FLOAT;
array_descriptor.NumChannels = 1;
status = cuArrayCreate(&arr_handle, &array_descriptor);
dieiferror(status, "Error al crear una matriz CUDA 2D");
}
auto arr_size = dims.width * dims.height;
CUdeviceptr dptr;
status = cuMemAllocManaged(&dptr, arr_size, CU_MEM_ATTACH_GLOBAL);
dieiferror(status, "Error al asignar memoria administrada");
float* ptr_in = as_pointer<float>(dptr);
std::iota(ptr_in, ptr_in + arr_size, 0);
CUmemorytype ptr_in_memory_type;
status = cuPointerGetAttribute(&ptr_in_memory_type, CU_POINTER_ATTRIBUTE_MEMORY_TYPE, as_address(ptr_in));
if (not (ptr_in_memory_type == CU_MEMORYTYPE_UNIFIED or ptr_in_memory_type == CU_MEMORYTYPE_DEVICE)) {
die("Tipo de memoria inesperado para ptr_in");
}
std::cout << "El tipo de memoria de ptr_in es " << (ptr_in_memory_type == CU_MEMORYTYPE_DEVICE ? "DEVICE" : "UNIFIED") << std::endl;
std::cout << "Copiaré de ptr_in a una matriz CUDA 2D" << std::endl;
CUDA_MEMCPY2D cp;
{
// Origen
<pre><code>cp.srcXInBytes = 0; cp.srcY = 0; // Sin desplazamiento
cp.srcMemoryType = ptr_in_memory_type;
cp.srcDevice = as_address(ptr_in);
// sin paso de origen adicional
cp.srcPitch = dims.width * sizeof(float);
// Destino
cp.dstXInBytes = 0; cp.dstY = 0; // Sin desplazamiento de destino
cp.dstMemoryType = CU_MEMORYTYPE_ARRAY;
cp.dstArray = arr_handle;
cp.WidthInBytes = dims.width * sizeof(float);
cp.Height = dims.height;
</code></pre>
}
status = cuMemcpy2D(&cp);
dieiferror(status, "Error en cuMemcpy2D");
cuMemFree(as_address(ptr_in));
}
“`</t*></cuda.h>
davy.ai
El valor incorrecto en los parámetros de la copia es
cp.srcPitch
, el cual está establecido endims.width * sizeof(float)
, pero debería establecerse endims.width * sizeof(float)
redondeado hacia arriba al múltiplo más cercano de 256 bytes. Esto se debe a que CUDA requiere alineación de espacios para ciertos accesos a la memoria para asegurar patrones de acceso de memoria óptimos. Por lo tanto, cambiar la líneacp.srcPitch = dims.width * sizeof(float);
acp.srcPitch = (dims.width * sizeof(float) + 255) & ~255;
debería resolver el error de “argumento inválido”.