CUDA: Umbrechen der Gerätespeicherzuordnung in C ++

Ich fange gerade an, CUDA zu verwenden und muss zugeben, dass ich von der C-API etwas enttäuscht bin. Ich verstehe die Gründe für die Wahl von C, aber wenn die Sprache stattdessen auf C ++ basiert hätte, wären einige Aspekte viel einfacher gewesen, z. Gerätespeicherzuordnung (übercudaMalloc).

Mein Plan war es, dies selbst zu tun, mit überladenenoperator new mit Platzierungnew und RAII (zwei Alternativen). Ich frage mich, ob es irgendwelche Vorbehalte gibt, die ich bisher nicht bemerkt habe. Der Code scheint zur Arbeit, aber ich frage mich immer noch über mögliche Speicherlecks.

Die Verwendung des RAII code wäre wie folgt:

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

Vielleicht ist eine Klasse in diesem Zusammenhang übertrieben (zumal Sie noch @ verwenden müsstencudaMemcpy, die Klasse kapselt nur RAII), der andere Ansatz wäre alsoplacementnew:

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

Hier,cudaDevice fungiert lediglich als Tag, um die Überladung auszulösen. Da jedoch bei normaler Platzierungnew dies würde die Platzierung anzeigen, ich finde die Syntax seltsamerweise konsistent und vielleicht sogar vorzuziehen, eine Klasse zu verwenden.

Ich würde mich über Kritik jeglicher Art freuen. Weiß jemand vielleicht, ob für die nächste Version von CUDA etwas in diese Richtung geplant ist (was, wie ich gehört habe, die C ++ - Unterstützung verbessern wird, was immer sie damit meinen)?

Also, meine Frage ist eigentlich dreifach:

Ist meine Platzierungnew Überladung semantisch korrekt? Verliert Speicher? Hat jemand Informationen über zukünftige CUDA-Entwicklungen, die in diese allgemeine Richtung gehen (seien wir ehrlich: C-Schnittstellen in C ++ s * ck)?Wie kann ich dies auf konsistente Weise weiterführen (es sind andere APIs zu berücksichtigen, z. B. gibt es nicht nur Gerätespeicher, sondern auch einen konstanten Speicher und Texturspeicher)?
// 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&);
};

Über den hier verwendeten Singleton: Ja, ich bin mir seiner Nachteile bewusst. Diese sind in diesem Zusammenhang jedoch nicht relevant. Alles, was ich hier brauchte, war ein kleines Typenschild, das nicht kopierbar war. Alles andere (d. H. Überlegungen zum Multithreading, Zeitpunkt der Initialisierung) trifft nicht zu.

Antworten auf die Frage(8)

Ihre Antwort auf die Frage