Pregunta

Estoy empezando a usar CUDA en este momento y debo admitir que estoy un poco decepcionado con la API C.Entiendo las razones para elegir C, pero si el lenguaje se hubiera basado en C++, varios aspectos habrían sido mucho más simples, por ejemplo.asignación de memoria del dispositivo (a través de cudaMalloc).

Mi plan era hacer esto yo mismo, usando sobrecargado operator new con colocación new y RAII (dos alternativas).Me pregunto si hay alguna advertencia 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 de la RAII El código sería el siguiente:

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

Quizás una clase sea excesiva en este contexto (especialmente porque aún tendrías que usar cudaMemcpy, la clase solo 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 una colocación normal new esto indicaría la ubicación, encuentro la sintaxis extrañamente consistente y quizás incluso preferible al uso de una clase.

Agradecería críticas de todo tipo.¿Quizás alguien sepa si se planea algo en esta dirección para la próxima versión de CUDA (que, según he oído, mejorará su compatibilidad con C++, independientemente de lo que quieran decir con eso)?

Entonces, mi pregunta es en realidad triple:

  1. es mi ubicacion new sobrecarga semánticamente correcta?¿Perde memoria?
  2. ¿Alguien tiene información sobre futuros desarrollos de CUDA que vayan en esta dirección general (seamos realistas:¿Interfaces C en C++ mierda)?
  3. ¿Cómo puedo llevar esto más lejos de manera consistente? (Hay otras API a considerar, p. ej.¿No solo hay memoria del dispositivo sino también un almacenamiento de memoria constante y una 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&);
};

Acerca del 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 etiqueta pequeña que no se pudiera copiar.Todo lo demás (es decirconsideraciones de subprocesos múltiples, tiempo de inicialización) no se aplican.

¿Fue útil?

Solución

Me gustaría ir con el nuevo enfoque de colocación. Luego definiría una clase que se ajuste a std :: allocator & Lt; & Gt; interfaz. En teoría, podría pasar esta clase como parámetro de plantilla a std :: vector & Lt; & Gt; y std :: map < > y así sucesivamente.

Cuidado, he escuchado que hacer tales cosas está lleno de dificultades, pero al menos aprenderás mucho más sobre el STL de esta manera. Y no necesita reinventar sus contenedores y algoritmos.

Otros consejos

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 similar a STL para la gestión de datos de CUDA).

En particular, hay un proyecto de investigación de NVIDIA: empuje

  

¿Alguien tiene información sobre futuros desarrollos de CUDA que vayan en esta dirección general (seamos sinceros: interfaces C en C ++ s * ck)?

Sí, he hecho algo así:

https://github.com/eyalroz/cuda-api-wrappers/

  

La API de tiempo de ejecución de nVIDIA para CUDA está diseñada para usarse tanto en código C como en C ++. Como tal, utiliza una API de estilo C, el denominador común más bajo (con algunas excepciones notables de sobrecargas de funciones con plantilla).

     

Esta biblioteca de envoltorios alrededor de la API de tiempo de ejecución está destinada a permitirnos abarcar muchas de las características de C ++ (incluyendo algunas C ++ 11) para usar la API de tiempo de ejecución, pero sin reducir la expresividad o aumentar el nivel de abstracción (como en, por ejemplo, la biblioteca Thrust). Al usar cuda-api-wrappers, todavía tiene sus dispositivos, transmisiones, eventos, etc., pero será más conveniente trabajar con ellos en más C ++ - formas idiomáticas.

Hay varios proyectos que intentan algo similar, por ejemplo CUDPP .

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top