Perbanyak array OpenCL 2-D

Saya baru saja mulai bereksperimen dengan OpenCL. Saya mencoba membuat kernel yang akan mengalikan dua array 2-d. Saya sudah melakukan ini dengan vektor, namun dalam 2-d saya hanya mendapatkan hasil dari baris pertama. Saya sudah mencoba menerapkan beberapa solusi yang saya temukan tetapi setiap solusi hanya mengacaukan baris pertama. Gambar dari eksekusi: http://i.imgur.com/lJqSURV.png

Ini file host saya:

#include "stdafx.h"
#include <CL/cl.hpp>

#include <vector>
#include <iostream>

#include "util.hpp" // utility library   

#define __CL_ENABLE_EXCEPTIONS
#define ROWS (5)
#define COLUMNS (5)

#include "metrics.h"

/*Start main()*/

int main(void)
{
    int A = 4;
    /*Define the vectors for operands and result*/

    float** h_x = new float*[ROWS];
    float** h_y = new float*[ROWS];
    float** h_s = new float*[ROWS];

    for (int i = 0; i < ROWS; ++i){
        h_x[i] = new float[COLUMNS];
    }

    for (int i = 0; i < ROWS; ++i){
        h_y[i] = new float[COLUMNS];
    }

    for (int i = 0; i < ROWS; ++i){
        h_s[i] = new float[COLUMNS];
    }

    // Fill vectors a and b with random float values

    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLUMNS; j++){
            h_x[i][j] = rand() / (float)RAND_MAX;
            h_y[i][j] = rand() / (float)RAND_MAX;
            h_s[i][j] = 0.0;
        }   
    }

    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

    // Get all platforms (drivers)

    std::vector<cl::Platform> all_platforms;
    cl::Platform::get(&all_platforms);


    if (all_platforms.size() == 0){ // Check for issues
        std::cout << " No platforms found. Check OpenCL installation!\n";
        exit(1);
    }

    cl::Platform default_platform = all_platforms[0];
    std::cout << "Using platform: " << default_platform.getInfo<CL_PLATFORM_NAME>() << "\n";

    // Get default device of the default platform

    std::vector<cl::Device> all_devices;
    default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);

    if (all_devices.size() == 0){ // Check for issues
        std::cout << " No devices found. Check OpenCL installation!\n";
        exit(1);
    }

    cl::Device default_device = all_devices[0];
    std::cout << "Using device: " << default_device.getInfo<CL_DEVICE_NAME>() << "\n";

    // Create an OpenCL context

    cl::Context context({ default_device });

    cl::Program program(context, util::loadProgram("saxy_kernel.cl"), true);

    if (program.build({ default_device }) != CL_SUCCESS){
        std::cout << " Error building: " << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device) << "\n";
        getchar();
        exit(1);
    }

    // create buffers on the device
    cl::Buffer buffer_X(context, CL_MEM_READ_WRITE, sizeof(float)* ROWS*COLUMNS);
    cl::Buffer buffer_Y(context, CL_MEM_READ_WRITE, sizeof(float)* ROWS*COLUMNS);
    cl::Buffer buffer_S(context, CL_MEM_READ_WRITE, sizeof(float)* ROWS*COLUMNS);
    cl::Buffer buffer_A(context, CL_MEM_READ_WRITE, sizeof(int));

    //create queue to which we will push commands for the device.
    cl::CommandQueue queue(context, default_device);


    StartCounter();
    //write arrays A and B to the device
    queue.enqueueWriteBuffer(buffer_X, CL_TRUE, 0, sizeof(float)* ROWS*COLUMNS, &h_x[0][0]);
    queue.enqueueWriteBuffer(buffer_Y, CL_TRUE, 0, sizeof(float)* ROWS*COLUMNS, &h_y[0][0]);
    queue.enqueueWriteBuffer(buffer_A, CL_TRUE, 0, sizeof(int), &A);

    //run the kernel
    cl::Kernel kernel_add = cl::Kernel(program, "simple_add");
    kernel_add.setArg(0, buffer_X);
    kernel_add.setArg(1, buffer_Y);
    kernel_add.setArg(2, buffer_S);
    kernel_add.setArg(3, buffer_A);

    queue.enqueueNDRangeKernel(kernel_add, cl::NullRange, cl::NDRange(5,5), cl::NullRange);
    queue.finish();

    //read result C from the device to array C
    queue.enqueueReadBuffer(buffer_S, CL_TRUE, 0, sizeof(float)* ROWS * COLUMNS, &h_s[0][0]);

    std::cout << "Kernel execution time: " << GetCounter() << "ms \n";

    /*Print vectors*/
    std::cout << "\nMatrix #1: \n";
    for (int i = 0; i<ROWS; i++){
        std::cout << "\n";
        for (int j = 0; j<COLUMNS; j++){
            std::cout << "" << h_x[i][j] << "\t ";
        }
    }

    std::cout << "\n\nMatrix #2: \n";
    for (int i = 0; i<ROWS; i++){
        std::cout << "\n";
        for (int j = 0; j<COLUMNS; j++){
            std::cout << "" << h_y[i][j] << "\t ";
        }
    }

    std::cout << "\n\nResult: \n";
    for (int i = 0; i<ROWS; i++){
        std::cout << "\n";
        for (int j = 0; j<COLUMNS; j++){
            std::cout << "" << h_s[i][j] << "\t ";
        }
    }
    getchar();
    return 0;
}

Dan ini kernelnya:

__kernel void kernel simple_add(
   __global float* X, 
   __global float* Y, 
   __global float* S, 
   __global int *A){

   S[get_global_id(0)] = X[get_global_id(0)] * Y[get_global_id(0)];

/* Var defs
   int k;
   int i = get_global_id(0);
   int j = get_global_id(1);
   float tmp;

   if ( (i < 5) && (j < 5))
   {
       tmp = 0.0;
       for(k=0;k<5;k++)
           tmp += X[i*5+k] * Y[k*5+j];
       S[i*5+j] = tmp;
   }*/
}

Saya yakin saya melakukan sesuatu yang benar-benar salah, namun saya tidak tahu apa kesalahannya. Bantuan apa pun akan sangat dihargai.


person Arkoudinos    schedule 14.07.2015    source sumber


Jawaban (1)


Kode kernel Anda baik-baik saja, begitu pula cara Anda membuat buffer OpenCL dan meluncurkan kernel. Masalahnya terletak pada cara data Anda direpresentasikan di host, dan cara Anda menyalinnya ke perangkat.

Buffer OpenCL Anda adalah array 1D, yang diperlukan. Namun array host Anda adalah 2D, yang berarti bahwa baris-baris yang berdekatan tidak bersebelahan (array 2D adalah array pointer).

Perbaikan (yang paling sederhana) adalah dengan menyelaraskan penyimpanan Anda di host, agar sesuai dengan tata letak data perangkat:

float* h_x = new float[ROWS*COLUMNS];
for (int i = 0; i < ROWS; ++i){
    for (int j = 0; j < COLUMNS; ++j){
      h_x[j + i*COLUMNS] = rand() / (float)RAND_MAX;;
    }
}
person jprice    schedule 14.07.2015
comment
Terima kasih banyak. Hanya beberapa detik sebelum membaca jawaban Anda, saya menemukan bahwa kernel OpenCL hanya menerima buffer 1-D. Adakah yang tahu mengapa mereka memilih melakukan itu? - person Arkoudinos; 14.07.2015
comment
Karena array 2D adalah array pointer, bukan wilayah data yang berdekatan. Petunjuk yang dialokasikan pada host tidak akan masuk akal pada perangkat. OpenCL 2.0 memperkenalkan Shared Virtual Memory (SVM), yang memungkinkan memungkinkan pointer untuk dibagikan antara host dan perangkat dengan cara yang bermakna. - person jprice; 14.07.2015