17 Stimmen

CUDA: Die Zuweisung von Gerätespeicher in C++

Ich fange gerade an, CUDA zu verwenden und muss zugeben, dass ich von der C-API ein wenig enttäuscht bin. Ich verstehe die Gründe für die Wahl von C, aber wenn die Sprache stattdessen auf C++ basieren würde, wären einige Aspekte viel einfacher gewesen, z. B. die Zuweisung von Gerätespeicher (über cudaMalloc ).

Mein Plan war es, dies selbst zu tun, indem ich überladene operator new mit Platzierung new und RAII (zwei Alternativen). Ich frage mich, ob es irgendwelche Vorbehalte gibt, die ich bisher noch nicht bemerkt habe. Der Code scheint zu arbeiten, aber ich bin immer noch über mögliche Speicherlecks wundern.

Die Verwendung des RAII Der Code würde wie folgt aussehen:

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

Vielleicht ist eine Klasse in diesem Zusammenhang zu viel des Guten (vor allem, weil man immer noch die cudaMemcpy (die Klasse kapselt nur RAII), so dass der andere Ansatz darin bestehen würde Platzierung new :

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

Hier, cudaDevice dient lediglich als Markierung, um die Überlastung auszulösen. Da jedoch bei normaler Platzierung new dies würde auf die Platzierung hinweisen, finde ich die Syntax seltsam konsistent und vielleicht sogar besser als die Verwendung einer Klasse.

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

Meine Frage ist also eigentlich eine dreifache:

  1. Ist meine Platzierung new Überlastung semantisch korrekt? Geht dabei Speicherplatz verloren?
  2. Hat jemand Informationen über zukünftige CUDA-Entwicklungen, die in diese allgemeine Richtung gehen (seien wir ehrlich: C-Schnittstellen in C++ sind Mist)?
  3. Wie kann ich dies auf konsistente Weise weiterführen (es gibt noch 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 beschäftigten Singleton: Ja, ich bin mir seiner Nachteile bewusst. Allerdings sind diese in diesem Zusammenhang nicht relevant. Alles, was ich hier brauchte, war ein kleines Typ-Tag, das nicht kopierbar war. Alles andere (d.h. Multithreading-Überlegungen, Zeit der Initialisierung) trifft nicht zu.

1 Stimmen

Ihre Implementierung von Singleton ist bestenfalls gefährlich. Bitte lesen Sie die vielen anderen Diskussionen darüber, wie man ein Singleton in C++ erstellt.

0 Stimmen

Ja, du hast Recht. Siehe jedoch meine neue Klarstellung unterhalb des Codes.

7voto

kynan Punkte 12437

In der Zwischenzeit gab es einige weitere Entwicklungen (nicht so sehr in Bezug auf die CUDA-API, aber zumindest in Bezug auf Projekte, die einen STL-ähnlichen Ansatz für die CUDA-Datenverwaltung versuchten).

Besonders erwähnenswert ist ein Projekt der NVIDIA-Forschung: Schubkraft

5voto

coryan Punkte 1173

Ich würde mich für den neuen Ansatz der Vermittlung entscheiden. Dann würde ich eine Klasse definieren, die mit der Schnittstelle std::allocator<> konform ist. Theoretisch könnte man diese Klasse als Template-Parameter an std::vector<> und std::map<> und so weiter übergeben.

Vorsicht, ich habe gehört, dass solche Dinge mit Schwierigkeiten verbunden sind, aber zumindest werden Sie auf diese Weise viel mehr über die STL lernen. Und Sie müssen Ihre Container und Algorithmen nicht neu erfinden.

0 Stimmen

An einen Allokator hatte ich nicht gedacht. Ich habe dies tatsächlich vor getan, so sollte es nicht zu schwierig sein.

2voto

Konrad Rudolph Punkte 503837

Es gibt mehrere Projekte, die etwas Ähnliches versuchen, zum Beispiel CUDPP .

In der Zwischenzeit habe ich jedoch meinen eigenen Allokator implementiert und es funktioniert gut und war einfach (> 95% Boilerplate-Code).

0 Stimmen

Der stdcuda-Link ist tot.

0 Stimmen

@einpoklum Danke. Logisch, dass eine 10 Jahre alte Antwort irgendwann veraltet ist. Ich habe den Link entfernt.

2voto

einpoklum Punkte 100527

Hat jemand Informationen über zukünftige CUDA-Entwicklungen, die in diese allgemeine Richtung gehen (seien wir ehrlich: C-Schnittstellen in C++ sind Mist)?

Ja, so etwas habe ich auch schon gemacht:

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

nVIDIAs Runtime API für CUDA ist sowohl für die Verwendung in C- als auch in C++-Code vorgesehen. Als solche verwendet sie eine API im C-Stil, den kleinsten gemeinsamen Nenner (mit einigen bemerkenswerten Ausnahmen von schablonenartigen Funktionsüberladungen).

Diese Bibliothek mit Wrappern für die Laufzeit-API soll es uns ermöglichen, viele der Funktionen von C++ (einschließlich einiger C++11-Funktionen) für die Verwendung der Laufzeit-API zu nutzen, ohne jedoch die Ausdrucksfähigkeit zu verringern oder das Abstraktionsniveau zu erhöhen (wie z. B. bei der Thrust-Bibliothek). Mit cuda-api-wrappers haben Sie immer noch Ihre Geräte, Streams, Ereignisse und so weiter - aber sie werden bequemer sein, um mit ihnen auf C++-idiomatischere Weise zu arbeiten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X