#include #include #include #include #include #include #include #include #include #include "pcloudStimulusBuffer.h" #include "frameAssemblyDesc.h" namespace smo { namespace stim_buff { extern const SmoCallbacks* smoHooksPtr; // OpenCL kernels are used to collate and produce our StimFrames. static SpMcRingBuffer::InputEngineConstraints openClInputConstraints( static_cast(sysconf(_SC_PAGE_SIZE)), sizeof(void *)); PcloudStimulusBuffer::PcloudStimulusBuffer( const std::shared_ptr &deviceAttachmentSpec, std::shared_ptr &device, const PcloudFormatDesc& formatDesc, int histbuffMs, size_t nDgramsPerStagingBufferFrame) : StimulusBuffer( deviceAttachmentSpec, static_cast(histbuffMs / CONFIG_STIMBUFF_FRAME_PERIOD_MS), openClInputConstraints, device->componentThread->getIoService()), device(device), formatDesc(formatDesc), openClCollatingAndMeshingEngine(*this), assemblyBuffer( StagingBuffer::IOEngineConstraints::ioUringConstraints, StagingBuffer::IOEngineConstraints::openClInputConstraints, nDgramsPerStagingBufferFrame), ioUringAssemblyEngine(*this, nDgramsPerStagingBufferFrame), collationBuffer( StagingBuffer::IOEngineConstraints::openClInputConstraints, StagingBuffer::IOEngineConstraints::openClInputConstraints, nDgramsPerStagingBufferFrame) { if (smoHooksPtr->OptionParser_getOptions().verbose) { std::cout << __func__ << ": assembly buffer : " << assemblyBuffer.stringify() << "\n\tcollation buffer : " << collationBuffer.stringify() << "\n"; } std::cout << __func__ << ": Device's component thread is " << device->componentThread->name << std::endl; #ifndef CONFIG_WORLD_USE_BODY_THREAD if (smoHooksPtr->ComponentThread_getSelf()->id != ComponentThread::WORLD) #else if (smoHooksPtr->ComponentThread_getSelf()->id != ComponentThread::BODY) #endif { std::string errMsg = std::string(__func__) + ": PcloudStimulusBuffer constructor called on non-world/body thread " + smoHooksPtr->ComponentThread_getSelf()->name; std::cout << errMsg << std::endl; // throw std::runtime_error(errMsg); } } void PcloudStimulusBuffer::start() { // Call ioUringAssemblyEngine setup() as the first step ioUringAssemblyEngine.setup(); openClCollatingAndMeshingEngine.setup(); // Call base class start() as the final step StimulusBuffer::start(); } void PcloudStimulusBuffer::stop() { // Call base class stop() as the first step StimulusBuffer::stop(); // Call ioUringAssemblyEngine stop() as the final step openClCollatingAndMeshingEngine.finalize(); ioUringAssemblyEngine.finalize(); } void produceStimFrameAck(void) { } void PcloudStimulusBuffer::stimFrameProductionTimesliceInd() { produceFrameReq({nullptr, nullptr}); } class PcloudStimulusBuffer::ProduceFrameReq : public PostedAsynchronousContinuation { private: PcloudStimulusBuffer& stimBuff; AsynchronousLoop frameAssemblyResult; StimulusFrame& stimulusFrame; public: ProduceFrameReq( PcloudStimulusBuffer& buffer, const std::shared_ptr& caller, Callback cb) : PostedAsynchronousContinuation(caller, cb), stimBuff(buffer), frameAssemblyResult(0), stimulusFrame(buffer.frames_[0]) {} public: void callOriginalCallback() { stimBuff.allowNextStimulusFrame(); callOriginalCb(); } public: void produceFrameReq1_doAssemble_posted( std::shared_ptr context) { stimBuff.ioUringAssemblyEngine.assembleFrameReq( {context, std::bind( &ProduceFrameReq::produceFrameReq2_assembleDone, context.get(), context, std::placeholders::_1, std::placeholders::_2)}); } void produceFrameReq2_assembleDone( std::shared_ptr context, bool success, AsynchronousLoop loop) { if (!success) { std::cerr << __func__ << ": Failed to assemble frame" << std::endl; callOriginalCallback(); return; } context->frameAssemblyResult = loop; stimBuff.openClCollatingAndMeshingEngine.compactCollateAndMeshFrameReq( loop, stimulusFrame, {context, std::bind( &ProduceFrameReq::produceFrameReq3_compactCollateDone, context.get(), context, std::placeholders::_1, std::placeholders::_2)}); } void produceFrameReq3_compactCollateDone( [[maybe_unused]] std::shared_ptr context, bool success, StimulusFrame& /*stimulusFrame*/) { if (!success) { std::cerr << __func__ << ": Failed to compact and collate frame" << std::endl; } else { std::cout << __func__ << ": Successfully compacted and collated frame" << std::endl; } // Print kernel execution durations auto compactDuration = stimBuff.openClCollatingAndMeshingEngine.getCompactKernelDuration(); auto collateDuration = stimBuff.openClCollatingAndMeshingEngine.getCollateKernelDuration(); std::cout << __func__ << ": compactKernelDuration=" << compactDuration.count() << "ms, collateKernelDuration=" << collateDuration.count() << "ms" << std::endl; callOriginalCallback(); } }; void PcloudStimulusBuffer::produceFrameReq( smo::Callback callback) { auto caller = smoHooksPtr->ComponentThread_getSelf(); auto request = std::make_shared( *this, caller, std::move(callback)); // Post the doAssemble method to the component thread device->componentThread->getIoService().post( STC(std::bind( &ProduceFrameReq::produceFrameReq1_doAssemble_posted, request.get(), request))); } } // namespace stim_buff } // namespace smo