我正在尝试OpenCL中的基本矩阵乘法程序。我相信我的问题在于我的入队和/或缓冲区读取,因为我得到的结果矩阵的输出完全不正确,以及矩阵A和B的第一行不正确。我是OpenCL的新手而且我一直在敲打我现在反对这个问题很长一段时间了,也许这里有人可以给我一个关于我哪里出错的提示?
主机代码:
#define __NO_STD_VECTOR // Uses cl::vector instead of standard version
#include <CL/cl.hpp>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <iostream>
#include <math.h>
#include <string>
/* Defined matrix width/height constants */
#define numRowsA 3
#define numColsA 3
#define numRowsB 3
#define numColsB 3
#define numRowsC numRowsA
#define numColsC numColsB
using namespace std;
/* Function declarations */
inline void checkErr(cl_int err, string name);
void initMatrix (float* matrix, int numIndices);
void printMatrix (string displayName, float* matrix, int numIndices,
int rowSize);
//*************
// Main Program
//*************
int main(int argc, char* argv[]) {
/* Check for valid matrix sizes */
if (numColsA != numRowsB) {
cout << "ERROR: Invalid matrix dimensions." << endl;
} else {
srand(2013); // Set random seed
/* Allocate memory for matrices A, B, and C */
unsigned int sizeA = numRowsA * numColsA;
unsigned int sizeB = numRowsB * numColsB;
unsigned int sizeC = numRowsC * numColsC;
unsigned int memoryA = sizeof(float) * sizeA;
unsigned int memoryB = sizeof(float) * sizeB;
unsigned int memoryC = sizeof(float) * sizeC;
/*
Allocate memoryA/memoryB/memoryC size blocks of bytes
(cast from void*)
*/
float* blockA = (float*) malloc(memoryA);
float* blockB = (float*) malloc(memoryB);
float* blockC = (float*) malloc(memoryC);
/* Initialize matrices A and B */
initMatrix(blockA, sizeA);
initMatrix(blockB, sizeB);
/* Display matrices A and B */
printMatrix("Matrix A", blockA, sizeA, numColsA);
printMatrix("Matrix B", blockB, sizeB, numColsB);
cl_int err; // Error code
string platformVendor; // Platform vendor
/* Create list of platforms */
cl::vector < cl::Platform > platformList;
cl::Platform::get(&platformList);
/*
Display potential Platform list generation error. If the
platform list size does not equal 0, CL_SUCCESS (0) is
sent to the function. If the platform list size does
equal 0, -1 is sent to the function.
*/
checkErr(platformList.size()!=0 ? CL_SUCCESS : -1,
"Platform");
/*
Replace empty value of platformVendor with device vendor
name
*/
platformList[0].getInfo((cl_platform_info) CL_PLATFORM_VENDOR,
&platformVendor);
/* Properties for Context constructor (Use unknown) */
cl_context_properties cprops[3] =
{
CL_CONTEXT_PLATFORM,
(cl_context_properties) (platformList[0]) (),
0
};
/* Create context */
cl::Context context(CL_DEVICE_TYPE_GPU, cprops, NULL, NULL,
&err);
/* Display potential Context constructor error */
checkErr(err, "Context");
/* Create buffer for matrix A */
cl::Buffer deviceMemA(context,
CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeA, blockA, &err);
/* Create buffer for matrix B */
cl::Buffer deviceMemB(context,
CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeB, blockB, &err);
/* Create buffer for matrix C */
cl::Buffer deviceMemC(context,
CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, sizeC, blockC, &err);
/* Create buffer for row (A) and col (C) */
cl::Buffer rowA(context, CL_MEM_READ_ONLY, sizeof(int),
(void *) numRowsA, &err);
cl::Buffer colC(context, CL_MEM_READ_ONLY, sizeof(int),
(void *) numColsC, &err);
/* Display potential Buffer constructor error */
checkErr(err, "Buffers");
/* Get list of devices */
cl::vector<cl::Device> devices =
context.getInfo<CL_CONTEXT_DEVICES>();
/* Check for at least one device, if not throw error */
checkErr(devices.size() > 0 ? CL_SUCCESS : -1, "No Devices");
/* Read input from .cl file */
ifstream file("matrixMult1_kernels.cl");
/* Check for potential problem opening .cl input file */
checkErr(file.is_open() ? CL_SUCCESS:-1, "File Not Open");
/* Store file contents in a string */
string prog(istreambuf_iterator<char>(file),
(istreambuf_iterator<char>()));
/* Create source object */
cl::Program::Sources source(1, make_pair(prog.c_str(),
prog.length()+1));
/* Create program for given context and source */
cl::Program program(context, source);
err = program.build(devices, ""); // Check for build error
/* Display potential program build error */
checkErr(err, "Program Build");
/* Create kernel */
cl::Kernel kernel(program, "matrixMul", &err);
/* Display potential Kernel constructor error */
checkErr(err, "Kernel");
/*
Set matrixMul arguments, error checking after each
argument
*/
err = kernel.setArg(0, deviceMemA);
checkErr(err, "Arg0");
err = kernel.setArg(1, deviceMemB);
checkErr(err, "Arg1");
err = kernel.setArg(2, deviceMemC);
checkErr(err, "Arg2");
err = kernel.setArg(3, rowA);
checkErr(err, "Arg3");
err = kernel.setArg(4, colC);
checkErr(err, "Arg4");
/* Create command queue */
cl::CommandQueue queue(context, devices[0], 0, &err);
/* Display potential CommandQueue constructor error */
checkErr(err, "Command Queue");
/* Create event object */
cl::Event event;
cl::NDRange global(3, 3);
cl::NDRange local(1, 1);
/* Enqueue the kernel */
err = queue.enqueueNDRangeKernel(kernel, 2, global, local,
NULL, &event);
/* Display potential enqueueing error */
checkErr(err, "Enqueue");
/* Wait until kernel has completed execution before continuing */
event.wait();
/* Read kernel result back into host memory */
err = queue.enqueueReadBuffer(deviceMemC, CL_TRUE, 0, memoryC,
blockC, NULL, &event);
checkErr(err, "C");
err = queue.enqueueReadBuffer(deviceMemA, CL_TRUE, 0, sizeA,
blockA, NULL, &event);
err = queue.enqueueReadBuffer(deviceMemB, CL_TRUE, 0, sizeB,
blockB, NULL, &event);
/* Display potential kernel read error */
checkErr(err, "Read Buffer");
/* Display matrices */
cout << endl;
cout << "After:" << endl;
printMatrix("Matrix A", blockA, sizeA, numColsA);
printMatrix("Matrix B", blockB, sizeB, numColsB);
printMatrix("Matrix C", blockC, sizeC, numColsC);
/* Free up memory */
free(blockA);
free(blockB);
free(blockC);
}
}
//--------------------------------------------------------------------
// checkErr - Inline error checking function for OpenCL portion of
// host program.
//
// PRE: err is of type int in OpenCL; name is a string.
// POST: The program is terminated after display an error message
// indicating the location of the error and the error code.
//--------------------------------------------------------------------
inline void checkErr(cl_int err, string name) {
/* Check error code against OpenCL success constant */
if (err != CL_SUCCESS) {
/*
Display an error message stating the error origin and
error number.
*/
std::cerr << "ERROR: " << name << " (" << err << ")"
<< std::endl;
exit(EXIT_FAILURE); // Terminates process with status code 0
}
}
//--------------------------------------------------------------------
// initMatrix - Assigns a random float value to each indice of the
// matrix.
//
// PRE: matrix is a pointer to a block of bytes in memory; numIndices
// is the number of indicies in the matrix being instantiated.
// POST: Each index of the matrix has been instantiated with a random
// float value.
//--------------------------------------------------------------------
void initMatrix (float* matrix, int numIndices) {
/*
Loop through the block of bytes, assigning a random float
for each index of the matrix
*/
for (int i = 0; i < numIndices; i++) {
/* Assign a random float between 0 and 1 at this byte */
matrix[i] = rand() / (float) RAND_MAX;
}
}
//--------------------------------------------------------------------
// printMatrix - Outputs a readable version of the matrix.
//
// PRE: displayName is a string; matrix is a pointer to a block of
// bytes in memory; numIndices an integer indicating the number
// of indices in the matrix being displayed (read left-to-right,
// top-to-bottom); rowSize is an integer indicating the number
// of elements in one row of the matrix.
// POST: A readable version of the matrix is displayed.
//--------------------------------------------------------------------
void printMatrix (string displayName, float* matrix, int numIndices,
int rowSize) {
/* Output display name of matrix */
cout << "\n" << displayName << ":" << endl;
/* Loop through each indice of the matrix */
for (int i = 0; i < numIndices; i++) {
cout << matrix[i]; // Display value at this indice
/* Check for next row of the matrix */
if (((i + 1) % rowSize) == 0) {
cout << endl; // Line break
} else {
cout << " | "; // Indice separator
}
}
}
内核:
// matrixMult1_kernels.cl
// Multiply two matrices A * B = C
// Device code.
// OpenCL Kernel
__kernel void
matrixMul(__global float* A,
__global float* B,
__global float* C,
int wA, int wB) {
// 2D Thread ID
int tx = get_local_id(0);
int ty = get_local_id(1);
// value stores the element
// that is computed by the thread
float value = 0;
for (int k = 0; k < wA; ++k)
{
float elementA = A[ty * wA + k];
float elementB = B[k * wB + tx];
value += elementA * elementB;
}
// Write the matrix to device memory each
// thread writes one element
C[ty * wA + tx] = value;
}
示例输出:
矩阵A:
0.398748 | 0.999793 | 0.206833
0.354238 | 0.674347 | 0.492022
0.707017 | 0.353635 | 0.430668
矩阵B:
0.91598 | 0.0260167 | 0.881732
0.810974 | 0.193091 | 0.589857
0.229151 | 0.0657822 | 0.965835
错误:C(-30)
我正在使用仅支持OpenCL 1.1的NVIDIA GeForce 9800 GT。这里的任何帮助将不胜感激。
谢谢,
乔
答案 0 :(得分:2)
输入矩阵A和B的数据不会传递给设备。创建缓冲区时:
cl::Buffer deviceMemA(context, CL_MEM_READ_WRITE, memoryA,blockA, &err)
忽略 blockA 参数,因为标志未指定如何使用它。您需要添加至少 CL_MEM_COPY_HOST_PTR 以使用 blockA 的内容初始化缓冲区。
或者,您可以在创建缓冲区后调用 clEnqueueWriteBuffer 来发送数据。