lundi 12 août 2019

OpenCL Matrix Multiply runs, but answer is always zero

I am trying to learn/teach myself OpenCL and started with a program to do Matrix Multiply. No matter what I do, I end up with the answer of zero.

I know that a 1x3 and a 3x1 should yield a 1x1 answer, and it should be non zero with the way I have it setup to create random floats. Here is my main body, and the kernel. Other than the warnings; What am I missing, I have been over this for hours and can't see the problem.

#define CL_USE_DEPRECATED_OPENCL_2_0_APIS

#include <iostream>
#include <fstream>
#include <sstream>
#include "./cl.hpp"

int main() 
{

    int nX = 1;
    int nY = 3;
    int nZ = 1;

    // Get all platforms
    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);
    if(platforms.empty()){
        throw std::runtime_error("No Platforms found, check OpenCL installation.");
    }
    cl::Platform platform = platforms[0];
    std::cout << "Using Platform: " << platform.getInfo<CL_PLATFORM_NAME>() << std::endl;
    std::vector<cl::Device> devices;
    platform.getDevices(CL_DEVICE_TYPE_GPU, &devices);
    if(devices.empty()){
        throw std::runtime_error ("No Devices Found, check installation.");
    }
    cl::Device device = devices[0];

    // Create an execusion context
    cl::Context context(device);

    // create a command queue
    cl::CommandQueue queue(context, device);

    // Load the kernel sources, use global memory
    std::ifstream fs("mCrossProd.cl");
    if(!fs.is_open()) {
        throw  std::runtime_error("Can not open kernel source file.");
    }
    std::stringstream ss;
    ss << fs.rdbuf();
    std::string code = ss.str();
    cl::Program::Sources sources;
    sources.push_back({code.c_str(), code.length()});

    // Build the kernel
    cl::Program program(context, sources);
    try{
        program.build({device});
    } catch(std::exception &err){
        throw  std::runtime_error(program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device));
    }

    //Create Matrix arrays and fill with random float values
    float *A = new float[nX*nY];
    float *B = new float[nY*nZ];
    float *C = new float[nX*nZ];

    for(int i =0; i < nX; i++){
        for(int j = 0; j < nY; j++)
        {
            A[j + i*nY] = rand()/(float)RAND_MAX * 10 + 1;
            std::cout << " A[" << std::to_string(j + i * nY) << "] = ";
            std::cout << A[j + i*nY] << ' '; 
        }

        std::cout << std::endl;
    }

            std::cout << std::endl;


     for(int i =0; i < nY; i++){
        for(int j = 0; j < nZ; j++)
        {
            B[j + i*nY] = rand()/(float)RAND_MAX * 10 + 1 ;
            std::cout << " B[" + std::to_string(j + i * nY) + "] = " ;
            std::cout << B[j + i * nY] << " "; 
        }

        std::cout << std::endl;

    }

            std::cout << std::endl;


    //fill Matrix C with random values
    for(int i =0; i < nX; i++){
        for(int j = 0; j < nZ; j++)
        {
            C[j + i*nX] = rand()/(float)RAND_MAX * 10 + 1 ;
            std::cout << " C[" + std::to_string(j + i * nX) + "] = " ;
            std::cout << B[j + i * nX] << " "; 
        }

        std::cout << std::endl;

    }

    // Create data/memory buffers, and equeue them
    cl::Buffer bufA(context, CL_MEM_READ_ONLY, sizeof(float) * nX * nY);
    cl::Buffer bufB(context, CL_MEM_READ_ONLY, sizeof(float) * nY * nZ);
    cl::Buffer bufC(context, CL_MEM_READ_WRITE, sizeof(float) * nX * nZ);
    queue.enqueueWriteBuffer(bufA, CL_TRUE, 0, sizeof(float) * nX * nY, A);
    queue.enqueueWriteBuffer(bufA, CL_TRUE, 0, sizeof(float) * nY * nZ, B);

    // Select kernel, pass arguments
    cl::Kernel kernel = cl::Kernel(program, "mCrossProd");
    kernel.setArg(0, nX);
    kernel.setArg(1, nY);
    kernel.setArg(2, nZ);
    kernel.setArg(3, bufA);
    kernel.setArg(4, bufB);
    kernel.setArg(5, bufC);

    // Execute the kernel
    queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(nX, nY), cl::NDRange(16,16));

    // Retrieive results from global memory
    queue.enqueueReadBuffer(bufC, CL_TRUE,0, sizeof(float) * nX * nZ, C);
    queue.finish();

    fs.close();

    std::cout << "\nThe solution is" << std::endl;

    for(int i = 0; i < nX; i++){
        for(int j = 0; j < nZ; j++)
        {
            std::cout << "C[" + std::to_string(j*nZ+i) + "] = " ;
            std::cout << C[j*nZ+i] << " "; 

        }

        std::cout << std::endl;

    }
        std::cout << std::endl;

This is my Kernel function:

__kernel void mCrossProd(const int nX, const int nY, const int nZ, __global float* A, __global float* B, __global float* C) {
    int i = get_global_id(0);
    int j = get_global_id(1);

    for(int k = 0; k < nX; k++){
        C[j*nY+i] += A[j*nX+k] * B[k*nY+i];
    }
}

Aucun commentaire:

Enregistrer un commentaire