2015-03-08 2 views
1

Я хотел бы реализовать класс векторных векторов устройств, который инкапсулирует указатель на элементы контейнера.
Указатель устройства в классе устройства (Cuda C++)

После того как я создаю объект этого класса, у меня нет доступа к внутреннему указателю. Он всегда говорит: «Место нарушения прав доступа - адрес памяти устройства».

Мой код выглядит следующим образом:

#include <iostream> 
#include <cuda_runtime.h> 

template <typename T> 
class DeviceVector 
{ 
private: 
    T* m_bValues; 
    std::size_t m_bSize; 

public: 
    __host__ 
    void* operator new(std::size_t size) 
    { 
     DeviceVector<T>* object = nullptr; 
     cudaMalloc((void**)&object, size); 
     return object; 
    } 

    __host__ 
    void operator delete(void* object) 
    { 
     cudaFree(object); 
    } 

    __host__ 
    DeviceVector(std::size_t size = 1) 
    { 
     cudaMemcpy(&m_bSize, &size, sizeof(std::size_t), cudaMemcpyHostToDevice); 

     // At this cudaMalloc I get Access violation writing location... 
     cudaMalloc((void**)&m_bValues, size * sizeof(T)); 

     // It's an alternative solution here 
     T* ptr; 
     cudaMalloc((void**)&ptr, size * sizeof(T)); 
     cudaMemcpy(&m_bValues, &ptr, sizeof(T*), cudaMemcpyHostToDevice); 
     // The memory is allocated 
     // But I can't access it through m_bValues pointer 
     // It is also Access violation writing location... 
    } 

    __host__ 
    ~DeviceVector() 
    { 
     // Access violation here if I use the second solution in the constructor 
     cudaFree(m_bValues); 
    } 
}; 

int main() 
{ 
    DeviceVector<int>* vec = new DeviceVector<int>(); 

    delete vec; 

    return 0; 
} 

Примечание: У меня есть доступ к атрибуту размера.

Так что мои вопросы:
Как выделить память для этого класса, чтобы получить доступ к указателю внутри?
Можно ли даже инкапсулировать указатель на класс на устройстве?

+1

SO [ожидает] (http://stackoverflow.com/help/on-topic) для таких вопросов («почему этот код не работает?»), Что вы предоставляете [MCVE] (http://stackoverflow.com/help/mcve). –

+0

Почему ваш конструктор пытается скопировать в 'm_bSize' с помощью API CUDA? – talonmies

+0

Поскольку параметр 'size' конструктора находится в памяти хоста, а атрибут' m_bSize' находится в памяти устройства. –

ответ

3

Эта линия является незаконным:

cudaMalloc((void**)&m_bValues, size * sizeof(T)); 

, потому что ваш оператор new выделен объект на устройстве:

cudaMalloc((void**)&object, size); 
    return object; 

и конструктор был призван работать на , что распределение. Поэтому &m_bValues берет адрес устройства переменная в коде хоста, которая является незаконной в CUDA. Если вы это сделаете, а затем попытайтесь использовать его в главном коде (т. Е. Операция cudaMalloc), вы получите ошибку seg. cudaMalloc создает распределение устройства определенного размера, а затем сохраняет указатель устройства на это распределение в переменной, которая, как ожидается, будет , проживающей на хосте. Если вы передадите ему адрес устройства, чтобы вместо этого сохранить этот указатель, cudaMalloc выполнит segfault, пытаясь записать значение указателя.

Ваше альтернативное решение является несколько лучшим подходом и является общей идеей, когда необходимо скопировать указатель на распределение устройства переменной, находящейся на этом устройстве.

Но вы по-прежнему в основном сделали выделение, которое m_bValues указывает на inaccessible с хоста. (ptr, являющийся временной переменной, не поможет, и создание другой переменной в классе для хранения значения, такого как ptr, не поможет ни потому, что весь класс выделен и расположен на нем.) По той же причине что вам не разрешено использовать &m_bValues в предыдущей операции cudaMalloc, вы не сможете использовать его напрямую в любом другом хост-коде (кроме как для объекта cudaMempcy host-> при копировании самого значения указателя).

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

Также кажется, что вы изобретаете колесо. Вы можете изучить thrust device vectors (которые легко использовать с обычным кодом CUDA.)

Во всяком случае, это было ближе всего я мог придумать:

#include <iostream> 
#include <cuda_runtime.h> 
#include <stdio.h> 

#define cudaCheckErrors(msg) \ 
    do { \ 
     cudaError_t __err = cudaGetLastError(); \ 
     if (__err != cudaSuccess) { \ 
      fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \ 
       msg, cudaGetErrorString(__err), \ 
       __FILE__, __LINE__); \ 
      fprintf(stderr, "*** FAILED - ABORTING\n"); \ 
      exit(1); \ 
     } \ 
    } while (0) 

template <typename T> 
class DeviceVector 
{ 
private: 
    T* m_bValues; 
    std::size_t m_bSize; 
    std::size_t eleSize; 
public: 
    __host__ 
    void* operator new(std::size_t size) 
    { 
     DeviceVector<T>* object = NULL; 
     object = (DeviceVector<T> *)malloc(size*sizeof(DeviceVector<T>)); 
     return object; 
    } 

    __host__ 
    void operator delete(void* object) 
    { 
     free(object); 
    } 

    __host__ 
    DeviceVector(std::size_t size = 1) 
    { 
     m_bSize = size; 
     eleSize = sizeof(T); 
     cudaMalloc(&m_bValues, m_bSize*sizeof(T)); 
     cudaCheckErrors("constructor cudaMalloc fail"); 
     cudaMemset(m_bValues, 0, m_bSize*sizeof(T)); 
    } 

    __host__ 
    ~DeviceVector() 
    { 
     cudaFree(m_bValues); 
     cudaCheckErrors("destructor cudaFree fail"); 
    } 

    __host__ 
    T* getDevPtr(){ 
     return m_bValues;} 

    __host__ 
    std::size_t getSize(){ 
     return m_bSize;} 

    __host__ 
    std::size_t geteleSize(){ 
     return eleSize;} 
}; 

int main() 
{ 
    DeviceVector<int>* vec = new DeviceVector<int>(); 
    cudaMemset(vec->getDevPtr(), 0xFF, vec->getSize()*vec->geteleSize()); 
    cudaCheckErrors("vector fill fail"); 
    delete vec; 

    return 0; 
} 

Вы показали очень мало о том, как вы хотите, чтобы взаимодействовать с объектом данного класса, так что я просто предполагаю здесь ,

+0

Я хотел бы использовать объекты этого класса только в '__global__'. Я пытаюсь выделить всю память на устройстве, чтобы избежать копирования между хостом и устройством. Возможно ли иметь объект на устройстве с указателем, который имеет адрес в памяти устройства? Если да, то как? :) –

+0

Хорошо, я понял, что лучшим решением является то, что объект живет на хосте, а выделенная внутри него память будет находиться на устройстве. Спасибо за помощь. –

Смежные вопросы