GPU Memory and Data Transfer

  • Veri akışı genelde CPU <-> RAM arasında olur.
  • GPU’nun ise kendine ait RAM’i vardır ve biz buna dümdüz erişemiyoruz.
  • Şöyle bir akış var:
  1. CPU’da işlenecek data’yı oluştur -> host data -> h_data
  2. h_data’nın boyutu kadar GPU’da memory allocate et-> device data -> d_data
  3. CPU’daki datayı GPU’ya kopyala => h_data->d_data
  4. Kernel’ı çalıştır ve d_data’yı manipüle et
  5. GPU’daki datayı CPU’ya kopyala => d_data->h_data
  6. GPU’daki belleği free et
  7. İşlenmiş h_data’yı kullan

#include <cstdio>
#include <iostream>
#include <vector>

__global__ void hello(int* i)
{
    int xID = blockDim.x * blockIdx.x + threadIdx.x;
    
    i[xID] *= 2;
}

int main()
{
    // datamızın sayısı ve byte cinsinden boyutu
    int dataSize = 16; 
    int byteSize = dataSize * sizeof(int);

    // CPU tarafından memory initialize ettik
    std::vector<int> h_data(dataSize);    
    for(int i = 0; i < h_data.size(); i++)
        h_data[i] = i;

    // GPU tarafından memory allocate ettik
    int* d_data = nullptr;
    cudaMalloc(&d_data, byteSize);

    // CPU --data--> GPU
    cudaMemcpy(
        d_data, 
        h_data.data(), 
        byteSize,
        cudaMemcpyHostToDevice
    );

    // kernel'ı çalıştırdık
    hello<<<1, dataSize>>>(d_data);
    cudaError_t err = cudaDeviceSynchronize();

    if (err != cudaSuccess)
    {
        printf("CUDA error: %s\n", cudaGetErrorString(err));
        return 1;
    }

    // GPU --data--> CPU
    cudaMemcpy(
        h_data.data(), 
        d_data, 
        byteSize,
        cudaMemcpyDeviceToHost
    );

    // Free GPU memory
    cudaFree(d_data);

    // print values to console
    for(const int& i : h_data)
        std::cout << i << ", ";
    std::cout << std::endl;

    return 0;
}
// ÇIKTI:
// 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
C++
  • dataSize: Kaç tane int var
  • byteSize: Bu kadar int kaç byte eder
  • h_data: Host data. Vector olarak tanımladık ama direk pointer yapıp malloc /new gibi şeylerle bu kısmını halledebilirdik.
  • d_data : GPU’daki datanın pointer’ı
  • cudaMalloc(&d_data, byteSize) : GPU’da memory allocate eden fonksiyon
    • &d_data : d_data’nın adresini veriyoruz. Böylece fonksiyon pointer’ın değerini değiştirebilir.
    • byteSize : data’nın byte cinsinden boyutu
  • cudaMemcpy() : Bellek kopyalama yapan fonksiyon.
    • cudaMemcpyHostToDevice : CPU->GPU
    • cudaMemcpyDeviceToHost : GPU->CPU
    • cudaMemcpyDeviceToDevice : GPU->GPU
  • cudaFree() : GPU belleğini serbest bırakır.

Bazen tek başına bir array atmak yeterli olmaz yanında size da göndermemiz gerekir:

__global__ void hello(int* i, int size)
{
    int xID = blockDim.x * blockIdx.x + threadIdx.x;
    if(xID<size)
        i[xID] *= 2;
}

int main()
{
    // ...
    int mySize = 12;
    hello<<<1, dataSize>>>(d_data, mySize);
    // ...
}
C++


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *