CUDA: выделение памяти для устройства в C ++ - PullRequest
17 голосов
/ 18 ноября 2008

Сейчас я начинаю использовать CUDA и должен признать, что немного разочарован в C API. Я понимаю причины выбора C, но если бы язык основывался на C ++, некоторые аспекты были бы намного проще, например. распределение памяти устройства (через cudaMalloc).

Я планировал сделать это сам, используя перегруженные operator new с размещением new и RAII (две альтернативы). Мне интересно, есть ли какие-то предостережения, которые я до сих пор не заметил. Код кажется работает, но я все еще задаюсь вопросом о потенциальных утечках памяти.

Использование кода RAII будет выглядеть следующим образом:

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

Возможно, в этом контексте класс является избыточным (особенно если учесть, что вам все равно придется использовать cudaMemcpy, класс, инкапсулирующий только RAII), поэтому другим подходом будет размещение new:

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

Здесь cudaDevice просто действует как тег для запуска перегрузки. Однако, поскольку при обычном размещении new это будет означать размещение, я нахожу синтаксис странным образом согласованным и, возможно, даже предпочтительным по сравнению с использованием класса.

Буду признателен за критику любого рода. Возможно, кто-нибудь знает, планируется ли что-то в этом направлении для следующей версии CUDA (которая, как я слышал, улучшит поддержку C ++, что бы они ни подразумевали под этим).

Итак, мой вопрос на самом деле тройной:

  1. Является ли мое размещение new перегрузкой семантически правильным? Это утечка памяти?
  2. Есть ли у кого-нибудь информация о будущих разработках CUDA, которые идут в этом общем направлении (давайте посмотрим правде в глаза: интерфейсы C в C ++ s * ck)?
  3. Как я могу продвинуться в этом последовательным образом (есть другие API, на которые следует обратить внимание, например, есть не только память устройства, но также постоянное хранилище памяти и память текстур)?

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

Об используемом здесь синглтоне: Да, я знаю о его недостатках. Тем не менее, они не актуальны в этом контексте. Все, что мне было нужно, - это маленький тег типа, который нельзя было скопировать. Все остальное (то есть соображения о многопоточности, время инициализации) не применимо.

Ответы [ 4 ]

7 голосов
/ 22 июля 2010

Тем временем произошли некоторые дальнейшие разработки (не столько с точки зрения API CUDA, сколько по крайней мере с точки зрения проектов, в которых используется STL-подобный подход к управлению данными CUDA).

Наиболее заметным является проект исследования NVIDIA: тяга

5 голосов
/ 19 ноября 2008

Я бы пошел с размещением нового подхода. Затем я бы определил класс, который соответствует интерфейсу std :: allocator <>. Теоретически вы можете передать этот класс в качестве параметра шаблона в std :: vector <> и std :: map <> и т. Д.

Осторожно, я слышал, что делать такие вещи сопряжено с трудностями, но по крайней мере вы узнаете намного больше о STL таким образом. И вам не нужно заново изобретать свои контейнеры и алгоритмы.

2 голосов
/ 19 ноября 2008

Есть несколько проектов, которые пытаются что-то подобное, например CUDPP .

Тем временем, однако, я реализовал свой собственный распределитель, и он работает хорошо и был простым (> 95% стандартного кода).

1 голос
/ 22 февраля 2018

Есть ли у кого-нибудь информация о будущих разработках CUDA, которые идут в этом общем направлении (давайте посмотрим правде в глаза: интерфейсы C в C ++ s * ck)?

Да, я сделал что-то подобное:

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

nVIDIA Runtime API для CUDA предназначен для использования как в коде C, так и в C ++. Таким образом, он использует API в стиле C, нижний общий знаменатель (с несколькими заметными исключениями перегрузок шаблонных функций).

Эта библиотека оберток вокруг API времени выполнения предназначена для того, чтобы позволить нам охватить многие функции C ++ (включая некоторые C ++ 11) для использования API времени выполнения - но без снижения выразительности или повышения уровня абстракции (как например, в библиотеке Thrust). Используя cuda-api-wrappers, у вас все еще есть свои устройства, потоки, события и т. Д., Но с ними будет удобнее работать в C ++ - идиоматическими способами.

...