[C++] CUDA: asignación de memoria del dispositivo de empaquetado en C ++


Answers

Mientras tanto hubo algunos desarrollos adicionales (no tanto en términos de la API de CUDA, sino al menos en términos de proyectos que intentan un enfoque tipo STL para la administración de datos de CUDA).

Lo más notable es que hay un proyecto de investigación de NVIDIA: empuje

Question

Estoy empezando a usar CUDA en este 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 ejemplo, la asignación de memoria del dispositivo (a través de cudaMalloc ).

Mi plan era hacer esto yo mismo, utilizando un operator new sobrecargado operator new con ubicación new y RAII (dos alternativas). Me pregunto si hay algunas advertencias que no haya notado hasta ahora. El código parece funcionar, pero todavía me estoy preguntando sobre posibles pérdidas de memoria.

El uso del código RAII sería el siguiente:

CudaArray<float> device_data(SIZE);
// Use `device_data` as if it were a raw pointer.

Tal vez una clase es exagerada en este contexto (especialmente porque todavía tendría que usar cudaMemcpy , la clase que solo encapsula RAII), por lo que el otro enfoque sería la ubicació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 activar la sobrecarga. Sin embargo, dado que en una ubicación normal, esto indicaría la ubicación, creo que la sintaxis es extrañamente consistente y quizás 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).

Entonces, mi pregunta es en realidad triple:

  1. ¿Es mi sobrecarga una new semánticamente correcta? ¿Pierde memoria?
  2. ¿Alguien tiene información sobre futuros desarrollos de CUDA que vayan en esta dirección general (seamos sinceros: interfaces C en C ++ s * ck)?
  3. ¿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 singleton 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. Todo lo demás (es decir, consideraciones de subprocesamiento múltiple, tiempo de inicialización) no se aplica.




Ya hay dos proyectos que intentan algo similar:

Mientras tanto, sin embargo, he implementado mi asignador y funciona muy bien y fue completamente sencillo (> 95% de código repetitivo).