Domanda

Al momento sto iniziando a usare CUDA e devo ammettere che sono un po 'deluso dall'API C. Comprendo i motivi della scelta di C, ma se il linguaggio fosse basato su C ++, diversi aspetti sarebbero stati molto più semplici, ad es. allocazione della memoria del dispositivo (tramite cudaMalloc).

Il mio piano era di farlo da solo, usando un sovraccarico operator new con posizionamento new e RAII (due alternative). Mi chiedo se ci sono avvertimenti che non ho notato finora. Il codice sembra funzionare ma mi chiedo ancora potenziali perdite di memoria.

L'uso del codice RAII sarebbe il seguente:

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

Forse una classe è eccessiva in questo contesto (soprattutto perché dovresti ancora usare cudaMemcpy, la classe che incapsula solo RAII) quindi l'altro approccio sarebbe posizionamento cudaDevice :

float* device_data = new (cudaDevice) float[SIZE];
// Use `device_data` …
operator delete [](device_data, cudaDevice);

Qui, <=> agisce semplicemente come tag per innescare il sovraccarico. Tuttavia, poiché nel normale posizionamento <=> questo indicherebbe il posizionamento, trovo la sintassi stranamente coerente e forse anche preferibile usare una classe.

Apprezzerei le critiche di ogni tipo. Qualcuno forse sa se qualcosa in questa direzione è pianificato per la prossima versione di CUDA (che, come ho sentito, migliorerà il suo supporto C ++, qualunque cosa intendano con quello).

Quindi, la mia domanda è in realtà triplice:

  1. Il mio posizionamento <=> il sovraccarico è semanticamente corretto? Perdita di memoria?
  2. Qualcuno ha informazioni sui futuri sviluppi CUDA che vanno in questa direzione generale (ammettiamolo: interfacce C in C ++ s * ck)?
  3. Come posso andare oltre in modo coerente (ci sono altre API da considerare, ad es. non c'è solo la memoria del dispositivo ma anche un archivio di memoria costante e una memoria di trama)?

// 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&);
};

Informazioni sul singleton impiegato qui: Sì, sono consapevole dei suoi svantaggi. Tuttavia, questi non sono rilevanti in questo contesto. Tutto ciò di cui avevo bisogno qui era un tag di tipo piccolo che non fosse copiabile. Tutto il resto (ovvero considerazioni sul multithreading, tempo di inizializzazione) non si applica.

È stato utile?

Soluzione

Vorrei andare con il posizionamento nuovo approccio. Quindi definirei una classe conforme allo standard std :: allocator & Lt; & Gt; interfaccia. In teoria, potresti passare questa classe come parametro template in std :: vector & Lt; & Gt; e std :: map < > e così via.

Attenzione, ho sentito che fare queste cose è difficile, ma almeno imparerai molto di più sulla STL in questo modo. E non è necessario reinventare i contenitori e gli algoritmi.

Altri suggerimenti

Nel frattempo ci sono stati ulteriori sviluppi (non tanto in termini di API CUDA, ma almeno in termini di progetti che tentano un approccio di tipo STL alla gestione dei dati CUDA).

In particolare c'è un progetto della ricerca NVIDIA: thrust

  

Qualcuno ha informazioni sui futuri sviluppi CUDA che vanno in questa direzione generale (ammettiamolo: interfacce C in C ++ s * ck)?

Sì, ho fatto qualcosa del genere:

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

  

L'API runtime di nVIDIA per CUDA è destinata all'uso sia in codice C che C ++. Come tale, utilizza un'API di tipo C, il minimo comune denominatore (con alcune notevoli eccezioni di sovraccarichi della funzione basata su modelli).

     

Questa libreria di wrapper attorno all'API di runtime ha lo scopo di permetterci di abbracciare molte delle funzionalità di C ++ (incluso alcuni C ++ 11) per l'utilizzo dell'API di runtime - ma senza ridurre l'espressività o aumentare il livello di astrazione (come in, ad esempio, la libreria Thrust). Usando cuda-api-wrapper, hai ancora i tuoi dispositivi, stream, eventi e così via - ma saranno più convenienti lavorare con più C ++ - modi idiomatici.

Esistono diversi progetti che tentano qualcosa di simile, ad esempio CUDPP .

Nel frattempo, tuttavia, ho implementato il mio allocatore e funziona bene ed è stato semplice (& GT; 95% codice boilerplate).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top