Pergunta

Eu estou começando a usar CUDA no momento e tenho que admitir que estou um pouco decepcionado com a API C. Eu entendo as razões para a escolha de C, mas teve a língua sido baseada em C ++ em vez disso, vários aspectos teria sido muito mais simples, por exemplo, alocação de memória do dispositivo (via cudaMalloc).

Meu plano era fazer isso sozinho, usando operator new sobrecarregado com new colocação e RAII (duas alternativas). Eu estou querendo saber se existem quaisquer ressalvas que eu não tenha notado até agora. O código parece para o trabalho, mas eu ainda estou querendo saber sobre potenciais vazamentos de memória.

O uso do RAII código seria da seguinte forma:

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

Talvez uma classe é um exagero neste contexto (especialmente desde que você ainda tem que usar cudaMemcpy, a única classe encapsulando RAII) para a outra abordagem seria colocação new :

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

Aqui, cudaDevice simplesmente age como um tag para acionar a sobrecarga. No entanto, uma vez que em new colocação normal, isso indicaria a colocação, acho que a sintaxe estranhamente consistente e talvez até mesmo preferível ao uso de uma classe.

Eu apreciaria críticas de todo o tipo. Será que alguém, talvez, saber se algo nesse sentido está prevista para a próxima versão do CUDA (que, como eu ouvi, vai melhorar o seu apoio C ++, o que quer dizer com isso).

Então, minha pergunta é, na verdade, tríplice:

  1. É a minha colocação sobrecarga new semanticamente correto? Será que vazamento de memória?
  2. Alguém tem informações sobre desenvolvimentos futuros CUDA que vão nessa direção geral (vamos enfrentá-lo: interfaces C em * ck C ++ s)?
  3. Como posso levar isso mais de uma forma consistente (há outras APIs a considerar, por exemplo, há não só a memória do dispositivo, mas também um armazenamento de memória constante e memória de textura)?

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

Sobre o singleton empregada aqui: Sim, eu estou ciente de suas desvantagens. No entanto, estes não são relevantes neste contexto. Tudo que eu precisava aqui era um pequeno tipo de tag que não foi copiável. Tudo o resto (ou seja, multithreading considerações, o tempo de inicialização) não se aplicam.

Foi útil?

Solução

Eu iria com a nova abordagem colocação. Então gostaria de definir uma classe que está em conformidade com o std :: allocator <> interface. Em teoria, você poderia passar essa classe como um parâmetro de modelo em std :: vector <> e std :: map <> e assim por diante.

Cuidado, eu ouvi dizer que fazer tais coisas é repleto de dificuldades, mas pelo menos você vai aprender muito mais sobre a STL desta forma. E você não precisa re-inventar os seus contentores e algoritmos.

Outras dicas

Entretanto houve alguns desenvolvimentos adicionais (não tanto em termos de API CUDA, mas pelo menos em termos de projectos de tentar uma STL-como abordagem para o gerenciamento de dados CUDA).

Mais notavelmente há um projeto de pesquisa NVIDIA: impulso

Alguém tem informações sobre desenvolvimentos futuros CUDA que vão nessa direção geral (vamos enfrentá-lo: interfaces C em * ck C ++ s)?

Sim, eu fiz algo assim:

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

API Runtime da Nvidia para CUDA é destinado para uso tanto em código C e C ++. Como tal, ele usa uma API de estilo C, o denominador comum mais baixo (com algumas exceções notáveis ??de sobrecargas de função templated).

Esta biblioteca de wrappers em torno da API Runtime se destina a permitir-nos para abraçar muitas das características de C ++ (incluindo alguns C ++ 11) para usar a API de tempo de execução - mas sem reduzir a expressividade ou aumentar o nível de abstração (como em, por exemplo, a biblioteca Thrust). Usando CUDA api-wrappers, você ainda tem seus dispositivos, correntes, eventos e assim por diante -, mas eles vão ser mais conveniente para trabalhar com mais C ++ -. Formas idiomáticas

Existem vários projetos que tentativa algo semelhante, por exemplo CUDPP .

Enquanto isso, no entanto, eu tenho implementado minha própria alocador e ele funciona bem e foi direto (> 95% código clichê).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top