2017-08-01 12:30:58 +00:00
|
|
|
#include "b3LauncherCL.h"
|
|
|
|
|
|
|
|
bool gDebugLauncherCL = false;
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
b3LauncherCL::b3LauncherCL(cl_command_queue queue, cl_kernel kernel, const char* name)
|
2019-01-03 13:26:51 +00:00
|
|
|
: m_commandQueue(queue),
|
|
|
|
m_kernel(kernel),
|
|
|
|
m_idx(0),
|
|
|
|
m_enableSerialization(false),
|
|
|
|
m_name(name)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
if (gDebugLauncherCL)
|
|
|
|
{
|
|
|
|
static int counter = 0;
|
|
|
|
printf("[%d] Prepare to launch OpenCL kernel %s\n", counter++, name);
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
m_serializationSizeInBytes = sizeof(int);
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
b3LauncherCL::~b3LauncherCL()
|
2019-01-03 13:26:51 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < m_arrays.size(); i++)
|
|
|
|
{
|
|
|
|
delete (m_arrays[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_arrays.clear();
|
|
|
|
if (gDebugLauncherCL)
|
|
|
|
{
|
2017-08-01 12:30:58 +00:00
|
|
|
static int counter = 0;
|
2019-01-03 13:26:51 +00:00
|
|
|
printf("[%d] Finished launching OpenCL kernel %s\n", counter++, m_name);
|
|
|
|
}
|
|
|
|
}
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
void b3LauncherCL::setBuffer(cl_mem clBuffer)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
if (m_enableSerialization)
|
|
|
|
{
|
|
|
|
b3KernelArgData kernelArg;
|
|
|
|
kernelArg.m_argIndex = m_idx;
|
|
|
|
kernelArg.m_isBuffer = 1;
|
|
|
|
kernelArg.m_clBuffer = clBuffer;
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
cl_mem_info param_name = CL_MEM_SIZE;
|
|
|
|
size_t param_value;
|
|
|
|
size_t sizeInBytes = sizeof(size_t);
|
|
|
|
size_t actualSizeInBytes;
|
|
|
|
cl_int err;
|
|
|
|
err = clGetMemObjectInfo(kernelArg.m_clBuffer,
|
|
|
|
param_name,
|
|
|
|
sizeInBytes,
|
|
|
|
¶m_value,
|
|
|
|
&actualSizeInBytes);
|
|
|
|
|
|
|
|
b3Assert(err == CL_SUCCESS);
|
|
|
|
kernelArg.m_argSizeInBytes = param_value;
|
|
|
|
|
|
|
|
m_kernelArguments.push_back(kernelArg);
|
|
|
|
m_serializationSizeInBytes += sizeof(b3KernelArgData);
|
|
|
|
m_serializationSizeInBytes += param_value;
|
|
|
|
}
|
|
|
|
cl_int status = clSetKernelArg(m_kernel, m_idx++, sizeof(cl_mem), &clBuffer);
|
|
|
|
b3Assert(status == CL_SUCCESS);
|
|
|
|
}
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
void b3LauncherCL::setBuffers(b3BufferInfoCL* buffInfo, int n)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
for (int i = 0; i < n; i++)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
if (m_enableSerialization)
|
|
|
|
{
|
|
|
|
b3KernelArgData kernelArg;
|
|
|
|
kernelArg.m_argIndex = m_idx;
|
|
|
|
kernelArg.m_isBuffer = 1;
|
|
|
|
kernelArg.m_clBuffer = buffInfo[i].m_clBuffer;
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
cl_mem_info param_name = CL_MEM_SIZE;
|
|
|
|
size_t param_value;
|
|
|
|
size_t sizeInBytes = sizeof(size_t);
|
|
|
|
size_t actualSizeInBytes;
|
|
|
|
cl_int err;
|
2019-01-03 13:26:51 +00:00
|
|
|
err = clGetMemObjectInfo(kernelArg.m_clBuffer,
|
|
|
|
param_name,
|
|
|
|
sizeInBytes,
|
|
|
|
¶m_value,
|
|
|
|
&actualSizeInBytes);
|
|
|
|
|
|
|
|
b3Assert(err == CL_SUCCESS);
|
2017-08-01 12:30:58 +00:00
|
|
|
kernelArg.m_argSizeInBytes = param_value;
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
m_kernelArguments.push_back(kernelArg);
|
2019-01-03 13:26:51 +00:00
|
|
|
m_serializationSizeInBytes += sizeof(b3KernelArgData);
|
|
|
|
m_serializationSizeInBytes += param_value;
|
|
|
|
}
|
|
|
|
cl_int status = clSetKernelArg(m_kernel, m_idx++, sizeof(cl_mem), &buffInfo[i].m_clBuffer);
|
|
|
|
b3Assert(status == CL_SUCCESS);
|
|
|
|
}
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct b3KernelArgDataUnaligned
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
int m_isBuffer;
|
|
|
|
int m_argIndex;
|
|
|
|
int m_argSizeInBytes;
|
2017-08-01 12:30:58 +00:00
|
|
|
int m_unusedPadding;
|
2019-01-03 13:26:51 +00:00
|
|
|
union {
|
|
|
|
cl_mem m_clBuffer;
|
|
|
|
unsigned char m_argData[B3_CL_MAX_ARG_SIZE];
|
|
|
|
};
|
2017-08-01 12:30:58 +00:00
|
|
|
};
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
int b3LauncherCL::deserializeArgs(unsigned char* buf, int bufSize, cl_context ctx)
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
int numArguments = *(int*)&buf[index];
|
|
|
|
index += sizeof(int);
|
|
|
|
|
|
|
|
for (int i = 0; i < numArguments; i++)
|
|
|
|
{
|
|
|
|
b3KernelArgDataUnaligned* arg = (b3KernelArgDataUnaligned*)&buf[index];
|
|
|
|
|
|
|
|
index += sizeof(b3KernelArgData);
|
|
|
|
if (arg->m_isBuffer)
|
|
|
|
{
|
|
|
|
b3OpenCLArray<unsigned char>* clData = new b3OpenCLArray<unsigned char>(ctx, m_commandQueue, arg->m_argSizeInBytes);
|
|
|
|
clData->resize(arg->m_argSizeInBytes);
|
|
|
|
|
|
|
|
clData->copyFromHostPointer(&buf[index], arg->m_argSizeInBytes);
|
|
|
|
|
|
|
|
arg->m_clBuffer = clData->getBufferCL();
|
|
|
|
|
|
|
|
m_arrays.push_back(clData);
|
|
|
|
|
|
|
|
cl_int status = clSetKernelArg(m_kernel, m_idx++, sizeof(cl_mem), &arg->m_clBuffer);
|
|
|
|
b3Assert(status == CL_SUCCESS);
|
|
|
|
index += arg->m_argSizeInBytes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cl_int status = clSetKernelArg(m_kernel, m_idx++, arg->m_argSizeInBytes, &arg->m_argData);
|
|
|
|
b3Assert(status == CL_SUCCESS);
|
|
|
|
}
|
2017-08-01 12:30:58 +00:00
|
|
|
b3KernelArgData b;
|
2019-01-03 13:26:51 +00:00
|
|
|
memcpy(&b, arg, sizeof(b3KernelArgDataUnaligned));
|
|
|
|
m_kernelArguments.push_back(b);
|
|
|
|
}
|
|
|
|
m_serializationSizeInBytes = index;
|
|
|
|
return index;
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int b3LauncherCL::validateResults(unsigned char* goldBuffer, int goldBufferCapacity, cl_context ctx)
|
2019-01-03 13:26:51 +00:00
|
|
|
{
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
int numArguments = *(int*)&goldBuffer[index];
|
|
|
|
index += sizeof(int);
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
if (numArguments != m_kernelArguments.size())
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
printf("failed validation: expected %d arguments, found %d\n", numArguments, m_kernelArguments.size());
|
2017-08-01 12:30:58 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
|
|
|
|
for (int ii = 0; ii < numArguments; ii++)
|
|
|
|
{
|
|
|
|
b3KernelArgData* argGold = (b3KernelArgData*)&goldBuffer[index];
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
if (m_kernelArguments[ii].m_argSizeInBytes != argGold->m_argSizeInBytes)
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
printf("failed validation: argument %d sizeInBytes expected: %d, found %d\n", ii, argGold->m_argSizeInBytes, m_kernelArguments[ii].m_argSizeInBytes);
|
2017-08-01 12:30:58 +00:00
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
int expected = argGold->m_isBuffer;
|
|
|
|
int found = m_kernelArguments[ii].m_isBuffer;
|
|
|
|
|
|
|
|
if (expected != found)
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
printf("failed validation: argument %d isBuffer expected: %d, found %d\n", ii, expected, found);
|
2017-08-01 12:30:58 +00:00
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
index += sizeof(b3KernelArgData);
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
if (argGold->m_isBuffer)
|
2019-01-03 13:26:51 +00:00
|
|
|
{
|
|
|
|
unsigned char* memBuf = (unsigned char*)malloc(m_kernelArguments[ii].m_argSizeInBytes);
|
2017-08-01 12:30:58 +00:00
|
|
|
unsigned char* goldBuf = &goldBuffer[index];
|
2019-01-03 13:26:51 +00:00
|
|
|
for (int j = 0; j < m_kernelArguments[j].m_argSizeInBytes; j++)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
memBuf[j] = 0xaa;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl_int status = 0;
|
2019-01-03 13:26:51 +00:00
|
|
|
status = clEnqueueReadBuffer(m_commandQueue, m_kernelArguments[ii].m_clBuffer, CL_TRUE, 0, m_kernelArguments[ii].m_argSizeInBytes,
|
|
|
|
memBuf, 0, 0, 0);
|
|
|
|
b3Assert(status == CL_SUCCESS);
|
|
|
|
clFinish(m_commandQueue);
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
for (int b = 0; b < m_kernelArguments[ii].m_argSizeInBytes; b++)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
int expected = goldBuf[b];
|
|
|
|
int found = memBuf[b];
|
|
|
|
if (expected != found)
|
|
|
|
{
|
|
|
|
printf("failed validation: argument %d OpenCL data at byte position %d expected: %d, found %d\n",
|
2019-01-03 13:26:51 +00:00
|
|
|
ii, b, expected, found);
|
2017-08-01 12:30:58 +00:00
|
|
|
return -4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
index += argGold->m_argSizeInBytes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-01 12:30:58 +00:00
|
|
|
//compare content
|
2019-01-03 13:26:51 +00:00
|
|
|
for (int b = 0; b < m_kernelArguments[ii].m_argSizeInBytes; b++)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
int expected = argGold->m_argData[b];
|
2019-01-03 13:26:51 +00:00
|
|
|
int found = m_kernelArguments[ii].m_argData[b];
|
2017-08-01 12:30:58 +00:00
|
|
|
if (expected != found)
|
|
|
|
{
|
|
|
|
printf("failed validation: argument %d const data at byte position %d expected: %d, found %d\n",
|
2019-01-03 13:26:51 +00:00
|
|
|
ii, b, expected, found);
|
2017-08-01 12:30:58 +00:00
|
|
|
return -5;
|
|
|
|
}
|
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return index;
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int b3LauncherCL::serializeArguments(unsigned char* destBuffer, int destBufferCapacity)
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
//initialize to known values
|
|
|
|
for (int i = 0; i < destBufferCapacity; i++)
|
|
|
|
destBuffer[i] = 0xec;
|
|
|
|
|
|
|
|
assert(destBufferCapacity >= m_serializationSizeInBytes);
|
|
|
|
|
|
|
|
//todo: use the b3Serializer for this to allow for 32/64bit, endianness etc
|
|
|
|
int numArguments = m_kernelArguments.size();
|
|
|
|
int curBufferSize = 0;
|
|
|
|
int* dest = (int*)&destBuffer[curBufferSize];
|
|
|
|
*dest = numArguments;
|
|
|
|
curBufferSize += sizeof(int);
|
|
|
|
|
|
|
|
for (int i = 0; i < this->m_kernelArguments.size(); i++)
|
|
|
|
{
|
|
|
|
b3KernelArgData* arg = (b3KernelArgData*)&destBuffer[curBufferSize];
|
|
|
|
*arg = m_kernelArguments[i];
|
|
|
|
curBufferSize += sizeof(b3KernelArgData);
|
|
|
|
if (arg->m_isBuffer == 1)
|
|
|
|
{
|
|
|
|
//copy the OpenCL buffer content
|
|
|
|
cl_int status = 0;
|
|
|
|
status = clEnqueueReadBuffer(m_commandQueue, arg->m_clBuffer, 0, 0, arg->m_argSizeInBytes,
|
|
|
|
&destBuffer[curBufferSize], 0, 0, 0);
|
|
|
|
b3Assert(status == CL_SUCCESS);
|
|
|
|
clFinish(m_commandQueue);
|
|
|
|
curBufferSize += arg->m_argSizeInBytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return curBufferSize;
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void b3LauncherCL::serializeToFile(const char* fileName, int numWorkItems)
|
|
|
|
{
|
|
|
|
int num = numWorkItems;
|
|
|
|
int buffSize = getSerializationBufferSize();
|
2019-01-03 13:26:51 +00:00
|
|
|
unsigned char* buf = new unsigned char[buffSize + sizeof(int)];
|
|
|
|
for (int i = 0; i < buffSize + 1; i++)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
unsigned char* ptr = (unsigned char*)&buf[i];
|
|
|
|
*ptr = 0xff;
|
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
// int actualWrite = serializeArguments(buf,buffSize);
|
|
|
|
|
|
|
|
// unsigned char* cptr = (unsigned char*)&buf[buffSize];
|
|
|
|
// printf("buf[buffSize] = %d\n",*cptr);
|
|
|
|
|
|
|
|
assert(buf[buffSize] == 0xff); //check for buffer overrun
|
2017-08-01 12:30:58 +00:00
|
|
|
int* ptr = (int*)&buf[buffSize];
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
*ptr = num;
|
2019-01-03 13:26:51 +00:00
|
|
|
|
|
|
|
FILE* f = fopen(fileName, "wb");
|
|
|
|
fwrite(buf, buffSize + sizeof(int), 1, f);
|
2017-08-01 12:30:58 +00:00
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
delete[] buf;
|
2019-01-03 13:26:51 +00:00
|
|
|
}
|