OClCollMeshEngn: use the central ComputeMgr APIs

We no longer create our own context and get our own OpenCL device
in OClCollMeshEngn::setup. We now request a device from the central
ComputeManager.
This commit is contained in:
2025-11-20 00:55:19 -04:00
parent 2c7e090ef1
commit ee6405048a
3 changed files with 101 additions and 188 deletions
+1
View File
@@ -60,6 +60,7 @@ target_link_libraries(smocore PRIVATE
Boost::system
Boost::log
${OPENCL_LIBRARIES}
attachmentSupport
)
target_link_directories(smocore PRIVATE
${OPENCL_LIBRARY_DIRS}
@@ -18,79 +18,21 @@
#include "openClKernels.h"
#include <user/frameAssemblyDesc.h>
#include "ioUringAssemblyEngine.h"
#include <user/senseApiDesc.h>
extern const smo::stim_buff::SmoCallbacks* smoHooksPtr;
namespace smo {
namespace stim_buff {
/* @brief Helper function to parse OpenCL version string.
* Expected format: "OpenCL <major>.<minor> <vendor info>"
* @param versionStr The OpenCL version string to parse.
* @return A pair of (major, minor) version numbers.
* If parsing fails, returns (-1, -1).
*/
static std::pair<int, int> parseOpenClVersion(const std::string& versionStr)
{
size_t spacePos = versionStr.find(' ');
if (spacePos == std::string::npos) { return {-1, -1}; }
std::string versionNum = versionStr.substr(spacePos + 1);
size_t dotPos = versionNum.find('.');
if (dotPos == std::string::npos) { return {-1, -1}; }
try {
int major = std::stoi(versionNum.substr(0, dotPos));
int minor = std::stoi(versionNum.substr(dotPos + 1));
return {major, minor};
} catch (const std::exception&) {
return {-1, -1};
}
}
/*
* @brief Validates OpenCL version string and checks if it meets minimum requirement.
* @param versionStr The OpenCL version string to validate.
* @param versionType Description of version type (e.g., "platform", "device") for error messages.
* @param minMajor Minimum major version required.
* @param minMinor Minimum minor version required (for the given major version).
* @return true if version is valid and meets minimum requirement, false otherwise.
*/
static bool validateOpenClVersion(
std::string_view versionStr, std::string_view versionType,
int minMajor, int minMinor)
{
auto [major, minor] = parseOpenClVersion(std::string(versionStr));
// Early return if version couldn't be parsed
if (major == -1 && minor == -1)
{
std::cerr << __func__ << ": failed to parse OpenCL " << versionType
<< " version: " << versionStr << std::endl;
return false;
}
// Require minimum version
if (major < minMajor || (major == minMajor && minor < minMinor))
{
std::cerr << __func__ << ": OpenCL " << versionType << " version "
<< major << "." << minor << " found, but " << minMajor << "."
<< minMinor << " or higher is required" << std::endl;
return false;
}
std::cout << __func__ << ": OpenCL " << versionType << " version: "
<< versionStr << std::endl;
return true;
}
OpenClCollatingAndMeshingEngine::OpenClCollatingAndMeshingEngine(
PcloudStimulusProducer& parent_)
: parent(parent_),
platform(nullptr),
device(nullptr),
context(nullptr),
commandQueue(nullptr),
computeDevice(nullptr),
slotCompactorProgram(nullptr), collateProgram(nullptr),
slotCompactorKernel(nullptr), collateKernel(nullptr),
clAssemblyBufferClBuffer(nullptr),
clCollationBufferClBuffer(nullptr),
clAssemblyBuffer(nullptr),
clCollationBuffer(nullptr),
shouldAcceptRequests(false),
@@ -124,77 +66,23 @@ bool OpenClCollatingAndMeshingEngine::setup()
}
}
cl_int err;
cl_command_queue_properties queueProps = 0;
// Get platform
cl_uint numPlatforms;
err = clGetPlatformIDs(1, &platform, &numPlatforms);
if (err != CL_SUCCESS || numPlatforms == 0)
if (!smoHooksPtr || !smoHooksPtr->ComputeManager_getDevice)
{
std::cerr << __func__ << ": failed to get OpenCL platform: "
<< err << std::endl;
std::cerr << __func__ << ": smo hooks not available" << std::endl;
return false;
}
// Get device
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr);
if (err != CL_SUCCESS)
// Get ComputeDevice from smo hooks
computeDevice = smoHooksPtr->ComputeManager_getDevice();
if (!computeDevice)
{
std::cerr << __func__ << ": failed to get GPU device: "
<< err << std::endl;
std::cerr << __func__ << ": failed to get compute device" << std::endl;
return false;
}
// Check OpenCL version - require 1.2 or higher
char platformVersion[128];
err = clGetPlatformInfo(platform, CL_PLATFORM_VERSION,
sizeof(platformVersion), platformVersion, nullptr);
if (err == CL_SUCCESS)
{
if (!validateOpenClVersion(platformVersion, "platform", 1, 2)) {
return false;
}
}
// Also check device version
char deviceVersion[128];
err = clGetDeviceInfo(device, CL_DEVICE_VERSION,
sizeof(deviceVersion), deviceVersion, nullptr);
if (err == CL_SUCCESS)
{
if (!validateOpenClVersion(deviceVersion, "device", 1, 2)) {
return false;
}
}
// Create context
context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
if (err != CL_SUCCESS || !context)
{
std::cerr << __func__ << ": failed to create OpenCL context: "
<< err << std::endl;
goto cleanup;
}
// Create command queue (OpenCL 1.2 API)
commandQueue = clCreateCommandQueue(
context, device, queueProps, &err);
if (err != CL_SUCCESS || !commandQueue)
{
std::cerr << __func__ << ": failed to create command queue: "
<< err << std::endl;
goto cleanup;
}
// Declare variables early to avoid goto crossing initialization
struct iovec assemblyIov;
struct iovec collationIov;
// Get StagingBuffer memory pointers from parent
assemblyIov = parent.assemblyBuffer.getClEngineIovec();
collationIov = parent.collationBuffer.getClEngineIovec();
struct iovec assemblyIov = parent.assemblyBuffer.getClEngineIovec();
struct iovec collationIov = parent.collationBuffer.getClEngineIovec();
assemblyBufferPtr = assemblyIov.iov_base;
assemblyBufferSize = assemblyIov.iov_len;
@@ -211,30 +99,46 @@ bool OpenClCollatingAndMeshingEngine::setup()
goto cleanup;
}
// Create OpenCL buffers using CL_MEM_USE_HOST_PTR for zero-copy
clAssemblyBuffer = clCreateBuffer(
context,
CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE,
assemblyBufferSize, assemblyBufferPtr,
&err);
if (err != CL_SUCCESS || !clAssemblyBuffer)
// Create OpenCL buffers using smo hooks
if (!smoHooksPtr->ComputeManager_createUseHostPtrBuffer)
{
std::cerr << __func__ << ": failed to create assembly buffer: "
<< err << std::endl;
std::cerr << __func__ << ": createUseHostPtrBuffer hook not available"
<< std::endl;
goto cleanup;
}
clCollationBuffer = clCreateBuffer(
context,
CL_MEM_USE_HOST_PTR | CL_MEM_WRITE_ONLY,
collationBufferSize, collationBufferPtr,
&err);
clAssemblyBufferClBuffer = smoHooksPtr
->ComputeManager_createUseHostPtrBuffer(
assemblyBufferPtr, assemblyBufferSize, CL_MEM_READ_WRITE);
if (err != CL_SUCCESS || !clCollationBuffer)
if (!clAssemblyBufferClBuffer)
{
std::cerr << __func__ << ": failed to create collation buffer: "
<< err << std::endl;
std::cerr << __func__ << ": failed to create assembly buffer"
<< std::endl;
goto cleanup;
}
clCollationBufferClBuffer = smoHooksPtr
->ComputeManager_createUseHostPtrBuffer(
collationBufferPtr, collationBufferSize, CL_MEM_WRITE_ONLY);
if (!clCollationBufferClBuffer)
{
std::cerr << __func__ << ": failed to create collation buffer"
<< std::endl;
goto cleanup;
}
// Cache cl_mem handles for the device we're using
clAssemblyBuffer = clAssemblyBufferClBuffer
->getAssociatedBufferHandleForDevice(computeDevice);
clCollationBuffer = clCollationBufferClBuffer
->getAssociatedBufferHandleForDevice(computeDevice);
if (!clAssemblyBuffer || !clCollationBuffer)
{
std::cerr << __func__ << ": failed to get buffer handles for device"
<< std::endl;
goto cleanup;
}
@@ -243,8 +147,8 @@ bool OpenClCollatingAndMeshingEngine::setup()
goto cleanup;
}
clFlush(commandQueue);
clFinish(commandQueue);
clFlush(computeDevice->commandQueue);
clFinish(computeDevice->commandQueue);
shouldAcceptRequests = true;
return true;
@@ -263,17 +167,26 @@ void OpenClCollatingAndMeshingEngine::finalize()
if (compactIsRunning) { compactKernelComplete(true); }
if (collateIsRunning) { collateKernelComplete(true); }
// Release OpenCL buffers in reverse order
if (clCollationBuffer)
// Release OpenCL buffers via smo hooks
if (smoHooksPtr && smoHooksPtr->ComputeManager_releaseUseHostPtrBuffer)
{
clReleaseMemObject(clCollationBuffer);
if (clCollationBufferClBuffer)
{
smoHooksPtr->ComputeManager_releaseUseHostPtrBuffer(
clCollationBufferClBuffer);
clCollationBufferClBuffer.reset();
}
if (clAssemblyBufferClBuffer)
{
smoHooksPtr->ComputeManager_releaseUseHostPtrBuffer(
clAssemblyBufferClBuffer);
clAssemblyBufferClBuffer.reset();
}
}
// Reset cached cl_mem handles
clCollationBuffer = nullptr;
}
if (clAssemblyBuffer)
{
clReleaseMemObject(clAssemblyBuffer);
clAssemblyBuffer = nullptr;
}
// Release kernels
if (slotCompactorKernel)
@@ -299,23 +212,15 @@ void OpenClCollatingAndMeshingEngine::finalize()
collateProgram = nullptr;
}
// Release command queue
if (commandQueue)
// Release compute device via smo hooks
if (smoHooksPtr && smoHooksPtr->ComputeManager_releaseDevice
&& computeDevice)
{
clReleaseCommandQueue(commandQueue);
commandQueue = nullptr;
}
// Release context
if (context)
{
clReleaseContext(context);
context = nullptr;
smoHooksPtr->ComputeManager_releaseDevice(computeDevice);
computeDevice.reset();
}
// Reset state variables
device = nullptr;
platform = nullptr;
compactIsRunning = false;
collateIsRunning = false;
currentCompactKernelEvent = nullptr;
@@ -494,7 +399,7 @@ bool OpenClCollatingAndMeshingEngine::compileAndPrepareKernel(
// Create program from source
program = clCreateProgramWithSource(
context, 1, &kernelSource, &kernelSourceLen, &err);
computeDevice->context, 1, &kernelSource, &kernelSourceLen, &err);
if (err != CL_SUCCESS || !program)
{
@@ -504,7 +409,9 @@ bool OpenClCollatingAndMeshingEngine::compileAndPrepareKernel(
}
// Build program
err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr);
err = clBuildProgram(program, 1, &computeDevice->device,
nullptr, nullptr, nullptr);
if (err != CL_SUCCESS)
{
std::cerr << __func__ << ": failed to build " << kernelName
@@ -512,13 +419,15 @@ bool OpenClCollatingAndMeshingEngine::compileAndPrepareKernel(
// Print build log if available
size_t logSize = 0;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,
clGetProgramBuildInfo(
program, computeDevice->device, CL_PROGRAM_BUILD_LOG,
0, nullptr, &logSize);
if (logSize > 0)
{
std::vector<char> log(logSize);
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,
clGetProgramBuildInfo(
program, computeDevice->device, CL_PROGRAM_BUILD_LOG,
logSize, log.data(), nullptr);
std::cerr << kernelName << " build log: " << log.data()
<< std::endl;
@@ -726,7 +635,7 @@ void OpenClCollatingAndMeshingEngine::compactKernelComplete(bool isFinalizing)
mapAssemblyBuffer(mapFlags);
unmapAssemblyBuffer();
clFlush(commandQueue);
clFlush(computeDevice->commandQueue);
// Stop only compact kernel
if (compactIsRunning && currentCompactKernelEvent)
@@ -736,7 +645,7 @@ void OpenClCollatingAndMeshingEngine::compactKernelComplete(bool isFinalizing)
currentCompactKernelEvent = nullptr;
}
clFinish(commandQueue);
clFinish(computeDevice->commandQueue);
compactKernelCb = [](cl_int){};
compactIsRunning = false;
}
@@ -753,7 +662,7 @@ void OpenClCollatingAndMeshingEngine::collateKernelComplete(bool isFinalizing)
mapCollationBuffer(mapFlags);
unmapCollationBuffer();
clFlush(commandQueue);
clFlush(computeDevice->commandQueue);
// Stop only collate kernel
if (collateIsRunning && currentCollateKernelEvent)
@@ -763,7 +672,7 @@ void OpenClCollatingAndMeshingEngine::collateKernelComplete(bool isFinalizing)
currentCollateKernelEvent = nullptr;
}
clFinish(commandQueue);
clFinish(computeDevice->commandQueue);
collateKernelCb = [](cl_int){};
collateIsRunning = false;
}
@@ -771,7 +680,7 @@ void OpenClCollatingAndMeshingEngine::collateKernelComplete(bool isFinalizing)
bool OpenClCollatingAndMeshingEngine::mapBuffer(
cl_mem buffer, size_t size, cl_map_flags mapFlags, void*& mappedPtr)
{
if (!commandQueue || !buffer)
if (!computeDevice->commandQueue || !buffer)
{
std::cerr << __func__ << ": engine not set up or invalid buffer"
<< std::endl;
@@ -784,7 +693,7 @@ bool OpenClCollatingAndMeshingEngine::mapBuffer(
cl_int err;
mappedPtr = clEnqueueMapBuffer(
commandQueue, buffer, CL_TRUE, mapFlags,
computeDevice->commandQueue, buffer, CL_TRUE, mapFlags,
0, size, 0, nullptr, nullptr, &err);
if (err != CL_SUCCESS || !mappedPtr)
@@ -811,7 +720,7 @@ bool OpenClCollatingAndMeshingEngine::unmapBuffer(
return true;
}
if (!commandQueue || !buffer)
if (!computeDevice->commandQueue || !buffer)
{
std::cerr << __func__ << ": engine not set up or invalid buffer.\n";
return false;
@@ -820,7 +729,7 @@ bool OpenClCollatingAndMeshingEngine::unmapBuffer(
cl_int err;
cl_event unmapEvent = nullptr;
err = clEnqueueUnmapMemObject(
commandQueue, buffer, mappedPtr,
computeDevice->commandQueue, buffer, mappedPtr,
0, nullptr, &unmapEvent);
if (err != CL_SUCCESS)
@@ -17,6 +17,8 @@
#include <user/stimulusFrame.h>
#include <user/stagingBuffer.h>
#include <user/frameAssemblyDesc.h>
#include <user/compute.h>
#include <user/senseApiDesc.h>
namespace smo {
namespace stim_buff {
@@ -72,17 +74,17 @@ public:
private:
PcloudStimulusProducer& parent;
// OpenCL infrastructure
cl_platform_id platform;
cl_device_id device;
cl_context context;
cl_command_queue commandQueue;
// OpenCL infrastructure (managed by ComputeManager)
std::shared_ptr<smo::compute::ComputeDevice> computeDevice;
cl_program slotCompactorProgram;
cl_program collateProgram;
cl_kernel slotCompactorKernel;
cl_kernel collateKernel;
// OpenCL buffers
// OpenCL buffers (managed by ComputeManager)
std::shared_ptr<smo::compute::ClBuffer> clAssemblyBufferClBuffer;
std::shared_ptr<smo::compute::ClBuffer> clCollationBufferClBuffer;
// Cached cl_mem handles for the device we're using
cl_mem clAssemblyBuffer;
cl_mem clCollationBuffer;
@@ -174,7 +176,8 @@ private:
// Enqueue kernel execution
cl_int err = clEnqueueNDRangeKernel(
commandQueue, kernel, 1, nullptr, &globalWorkSize, nullptr,
computeDevice->commandQueue, kernel,
1, nullptr, &globalWorkSize, nullptr,
0, nullptr, eventPtr);
if (err != CL_SUCCESS)
@@ -198,7 +201,7 @@ private:
}
// Force queue flush to ensure event processing and callback invocation
err = clFlush(commandQueue);
err = clFlush(computeDevice->commandQueue);
if (err != CL_SUCCESS)
{
std::cerr << __func__ << ": failed to flush queue: " << err