Вопрос

В данный момент я начинаю использовать 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), поэтому другим подходом было бы размещение cudaDevice :

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

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

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

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

<Ол>
  • Правильно ли семантически корректна перегрузка моего места размещения <=>? Это утечка памяти?
  • У кого-нибудь есть информация о будущих разработках 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&);
    };
    

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

    Это было полезно?

    Решение

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

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

    Другие советы

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

    В частности, есть проект исследования NVIDIA: тяга

      

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

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

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

      

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

         

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

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

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

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top