2015-07-14 5 views
0

Я только начал экспериментировать с OpenCL. Я пытаюсь создать ядро, которое будет умножать два массива 2-d. Я уже делал это с помощью векторов, однако в 2-й я получаю только результаты из первой строки. Я попытался реализовать некоторые из решений, которые я нашел, но каждый из них продолжает беспорядок только с первой строкой. Изображение от исполнения: http://i.imgur.com/lJqSURV.pngOpenCL 2-D массив умножить

Вот мой хост-файл:

#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; 
} 

А вот ядро:

__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; 
    }*/ 
} 

Я уверен, что я делаю что-то действительно неправильно, но я не могу понять, что это такое. Любая помощь будет оценена.

ответ

1

Код ядра в порядке, так же как вы создаете свои буферы OpenCL и запускаете ядро. Проблема заключается в том, что ваши данные представлены на хосте и как вы копируете их на устройство.

Ваши буферы OpenCL - это 1D массивы, что необходимо. Однако ваши массивы хоста - это 2D, что означает, что соседние строки: не смежный (2D-массив - это массив указателей).

The (простейшая) исправить будет линеаризовать ваше хранилище на хосте, чтобы соответствовать данному макету устройства:

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;; 
    } 
} 
+0

Спасибо очень много. За несколько секунд до чтения вашего ответа я узнал, что ядро ​​OpenCL принимает только одномерные буферы. Любая идея, почему они решили это сделать? – Arkoudinos

+0

Поскольку 2D-массив представляет собой массив указателей, а не смежную область данных. Эти указатели, размещенные на хосте, не будут иметь никакого смысла на устройстве. OpenCL 2.0 представляет общую виртуальную память (SVM), которая * позволяет * указывать указатели для совместного использования между хостом и устройством значимым образом. – jprice

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

  • Нет связанных вопросов^_^