CUDA: выделение памяти для устройства в C ++
Сейчас я начинаю использовать 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 ++, что бы они ни подразумевали под этим).
Итак, мой вопрос на самом деле тройной:
Мое место размещенияnew
перегрузить семантически правильно? Это утечка памяти?У кого-нибудь есть информация о будущих разработках CUDA, которые идут в этом общем направлении (давайте посмотрим правде в глаза: интерфейсы C в C ++ s * ck)?Как я могу продолжить это согласованным образом (есть другие 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&);
};
О синглтоне, работающем здесь: да, я знаю о его недостатках. Тем не менее, они не актуальны в этом контексте. Все, что мне было нужно, - это маленький тег типа, который нельзя было скопировать. Все остальное (т.е. многопоточность, время инициализации) не применяется.