Estoy empezando a utilizar CUDA por el momento y tengo que admitir que estoy un poco decepcionado con la API C. Entiendo las razones para elegir C, pero el lenguaje se basó en C++, varios aspectos hubieran sido mucho más simples, por ej. asignación de memoria del dispositivo (a través de cudaMalloc
).CUDA: asignación de memoria del dispositivo de empaquetado en C++
Mi plan era hacer esto yo mismo, utilizando operator new
sobrecargado con la colocación new
y RAII (dos alternativas). Me pregunto si hay algunas advertencias que no haya notado hasta ahora. El código parece para funcionar, pero todavía me pregunto acerca de posibles pérdidas de memoria.
El uso del código RAII sería la siguiente:
CudaArray<float> device_data(SIZE);
// Use `device_data` as if it were a raw pointer.
Tal vez una clase es una exageración en este contexto (sobre todo porque todavía habría que utilizar cudaMemcpy
, la única clase que encapsula RAII) por lo que el otro enfoque sería colocación new
:
float* device_data = new (cudaDevice) float[SIZE];
// Use `device_data` …
operator delete [](device_data, cudaDevice);
Aquí, cudaDevice
simplemente actúa como una etiqueta para desencadenar la sobrecarga. Sin embargo, dado que en la colocación normal new
esto indicaría la ubicación, creo que la sintaxis es extrañamente consistente y tal vez incluso preferible al uso de una clase.
Agradecería las críticas de todo tipo. ¿Alguien quizás sabe si se planea algo en esta dirección para la próxima versión de CUDA (que, como he escuchado, mejorará su compatibilidad con C++, lo que sea que signifiquen con eso).
Por lo tanto, mi pregunta es en realidad tres:
- ¿Es mi sobrecarga de colocación
new
semánticamente correcto? ¿Pierde memoria? - ¿Alguien tiene información sobre futuros desarrollos de CUDA que van en esta dirección general (seamos sinceros: C interfaces en C++ s * ck)?
- ¿Cómo puedo llevar esto más allá de manera consistente (hay otras API a tener en cuenta, por ejemplo, no solo hay memoria del dispositivo, sino también un almacén de memoria constante y memoria de textura)?
// Singleton tag for CUDA device memory placement.
struct CudaDevice {
static CudaDevice const& get() { return instance; }
private:
static CudaDevice const instance;
CudaDevice() { }
CudaDevice(CudaDevice const&);
CudaDevice& operator =(CudaDevice const&);
} const& cudaDevice = CudaDevice::get();
CudaDevice const CudaDevice::instance;
inline void* operator new [](std::size_t nbytes, CudaDevice const&) {
void* ret;
cudaMalloc(&ret, nbytes);
return ret;
}
inline void operator delete [](void* p, CudaDevice const&) throw() {
cudaFree(p);
}
template <typename T>
class CudaArray {
public:
explicit
CudaArray(std::size_t size) : size(size), data(new (cudaDevice) T[size]) { }
operator T*() { return data; }
~CudaArray() {
operator delete [](data, cudaDevice);
}
private:
std::size_t const size;
T* const data;
CudaArray(CudaArray const&);
CudaArray& operator =(CudaArray const&);
};
Sobre el producto único empleado aquí: Sí, soy consciente de sus inconvenientes. Sin embargo, estos no son relevantes en este contexto. Todo lo que necesitaba aquí era una pequeña etiqueta de tipo que no se podía copiar. No se aplica todo lo demás (es decir, consideraciones de subprocesamiento múltiple, tiempo de inicialización).
Su implementación de singleton es peligrosa en el mejor de los casos. Consulte las muchas otras discusiones sobre cómo crear un singleton en C++. –
Sí, tienes razón. Sin embargo, vea mi nueva aclaración debajo del código. –