diff --git a/sycl/plugins/level_zero/pi_level_zero.cpp b/sycl/plugins/level_zero/pi_level_zero.cpp index 67b7a9cad7da7..9d7a4cdcfb0ab 100644 --- a/sycl/plugins/level_zero/pi_level_zero.cpp +++ b/sycl/plugins/level_zero/pi_level_zero.cpp @@ -924,12 +924,18 @@ pi_result _pi_ze_event_list_t::createAndRetainPiZeEventList( this->ZeEventList = nullptr; this->PiEventList = nullptr; - if (EventListLength > 0) { - try { + try { + if (CurQueue->isInOrderQueue() && CurQueue->LastCommandEvent != nullptr) { + this->ZeEventList = new ze_event_handle_t[EventListLength + 1]; + this->PiEventList = new pi_event[EventListLength + 1]; + } else if (EventListLength > 0) { this->ZeEventList = new ze_event_handle_t[EventListLength]; this->PiEventList = new pi_event[EventListLength]; - pi_uint32 TmpListLength = 0; + } + pi_uint32 TmpListLength = 0; + + if (EventListLength > 0) { for (pi_uint32 I = 0; I < EventListLength; I++) { auto ZeEvent = EventList[I]->ZeEvent; @@ -961,15 +967,25 @@ pi_result _pi_ze_event_list_t::createAndRetainPiZeEventList( this->PiEventList[TmpListLength] = EventList[I]; TmpListLength += 1; } - - this->Length = TmpListLength; - } catch (...) { - return PI_OUT_OF_HOST_MEMORY; } - for (pi_uint32 I = 0; I < this->Length; I++) { - PI_CALL(piEventRetain(this->PiEventList[I])); + // For in-order queues, every command should be executed once after the + // previous command has finished. The event associated with the last + // enqued command is added into the waitlist to ensure in-order semantics. + if (CurQueue->isInOrderQueue() && CurQueue->LastCommandEvent != nullptr) { + this->ZeEventList[TmpListLength] = CurQueue->LastCommandEvent->ZeEvent; + this->PiEventList[TmpListLength] = CurQueue->LastCommandEvent; + TmpListLength += 1; } + + this->Length = TmpListLength; + + } catch (...) { + return PI_OUT_OF_HOST_MEMORY; + } + + for (pi_uint32 I = 0; I < this->Length; I++) { + PI_CALL(piEventRetain(this->PiEventList[I])); } return PI_SUCCESS; @@ -3691,11 +3707,6 @@ piEnqueueKernelLaunch(pi_queue Queue, pi_kernel Kernel, pi_uint32 WorkDim, PI_ASSERT(Event, PI_INVALID_EVENT); PI_ASSERT((WorkDim > 0) && (WorkDim < 4), PI_INVALID_WORK_DIMENSION); - _pi_ze_event_list_t TmpWaitList; - if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, - EventWaitList, Queue)) - return Res; - if (GlobalWorkOffset != NULL) { for (pi_uint32 i = 0; i < WorkDim; i++) { if (GlobalWorkOffset[i] != 0) { @@ -3771,6 +3782,12 @@ piEnqueueKernelLaunch(pi_queue Queue, pi_kernel Kernel, pi_uint32 WorkDim, // Lock automatically releases when this goes out of scope. std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; + + if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, + EventWaitList, Queue)) + return Res; + // Get a new command list to be used on this call ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; @@ -3808,6 +3825,8 @@ piEnqueueKernelLaunch(pi_queue Queue, pi_kernel Kernel, pi_uint32 WorkDim, pi_cast(ZeEvent)); printZeEventList((*Event)->WaitList); + Queue->LastCommandEvent = *Event; + // Execute command list asynchronously, as the event will be used // to track down its completion. if (auto Res = Queue->executeCommandList(ZeCommandList, ZeFence, false, true)) @@ -4053,6 +4072,7 @@ pi_result piEventsWait(pi_uint32 NumEvents, const pi_event *EventList) { // sooner in case run-time is not calling piEventRelease soon enough. cleanupAfterEvent(EventList[I]); } + return PI_SUCCESS; } @@ -4290,14 +4310,14 @@ pi_result piEnqueueEventsWait(pi_queue Queue, pi_uint32 NumEventsInWaitList, if (EventWaitList) { PI_ASSERT(NumEventsInWaitList > 0, PI_INVALID_VALUE); + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList = {}; if (auto Res = TmpWaitList.createAndRetainPiZeEventList( NumEventsInWaitList, EventWaitList, Queue)) return Res; - // Lock automatically releases when this goes out of scope. - std::lock_guard lock(Queue->PiQueueMutex); - // Get a new command list to be used on this call ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; @@ -4319,6 +4339,8 @@ pi_result piEnqueueEventsWait(pi_queue Queue, pi_uint32 NumEventsInWaitList, ZE_CALL(zeCommandListAppendSignalEvent, (ZeCommandList, ZeEvent)); + Queue->LastCommandEvent = *Event; + // Execute command list asynchronously as the event will be used // to track down its completion. return Queue->executeCommandList(ZeCommandList, ZeFence); @@ -4328,6 +4350,10 @@ pi_result piEnqueueEventsWait(pi_queue Queue, pi_uint32 NumEventsInWaitList, // all previous enqueued commands to the command-queue have completed. // // TODO: find a way to do that without blocking the host. + + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + auto Res = createEventAndAssociateQueue(Queue, Event, PI_COMMAND_TYPE_USER, nullptr); if (Res != PI_SUCCESS) @@ -4337,6 +4363,8 @@ pi_result piEnqueueEventsWait(pi_queue Queue, pi_uint32 NumEventsInWaitList, if (Queue->ZeCopyCommandQueue) ZE_CALL(zeHostSynchronize, (Queue->ZeCopyCommandQueue)); + Queue->LastCommandEvent = *Event; + ZE_CALL(zeEventHostSignal, ((*Event)->ZeEvent)); return PI_SUCCESS; } @@ -4348,14 +4376,14 @@ pi_result piEnqueueEventsWaitWithBarrier(pi_queue Queue, PI_ASSERT(Queue, PI_INVALID_QUEUE); PI_ASSERT(Event, PI_INVALID_EVENT); + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, EventWaitList, Queue)) return Res; - // Lock automatically releases when this goes out of scope. - std::lock_guard lock(Queue->PiQueueMutex); - // Get a new command list to be used on this call ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; @@ -4375,6 +4403,8 @@ pi_result piEnqueueEventsWaitWithBarrier(pi_queue Queue, (ZeCommandList, ZeEvent, (*Event)->WaitList.Length, (*Event)->WaitList.ZeEventList)); + Queue->LastCommandEvent = *Event; + // Execute command list asynchronously as the event will be used // to track down its completion. return Queue->executeCommandList(ZeCommandList, ZeFence); @@ -4427,14 +4457,14 @@ static pi_result enqueueMemCopyHelper(pi_command_type CommandType, PI_ASSERT(Queue, PI_INVALID_QUEUE); PI_ASSERT(Event, PI_INVALID_EVENT); + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, EventWaitList, Queue)) return Res; - // Lock automatically releases when this goes out of scope. - std::lock_guard lock(Queue->PiQueueMutex); - // Get a new command list to be used on this call ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; @@ -4452,6 +4482,7 @@ static pi_result enqueueMemCopyHelper(pi_command_type CommandType, const auto &WaitList = (*Event)->WaitList; if (WaitList.Length) { + ZE_CALL(zeCommandListAppendWaitOnEvents, (ZeCommandList, WaitList.Length, WaitList.ZeEventList)); } @@ -4464,6 +4495,8 @@ static pi_result enqueueMemCopyHelper(pi_command_type CommandType, pi_cast(ZeEvent)); printZeEventList(WaitList); + Queue->LastCommandEvent = *Event; + if (auto Res = Queue->executeCommandList(ZeCommandList, ZeFence, BlockingWrite)) return Res; @@ -4484,13 +4517,14 @@ static pi_result enqueueMemCopyRectHelper( PI_ASSERT(Region && SrcOrigin && DstOrigin && Queue, PI_INVALID_VALUE); PI_ASSERT(Event, PI_INVALID_EVENT); + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, EventWaitList, Queue)) return Res; - // Lock automatically releases when this goes out of scope. - std::lock_guard lock(Queue->PiQueueMutex); // Get a new command list to be used on this call ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; @@ -4507,6 +4541,7 @@ static pi_result enqueueMemCopyRectHelper( (*Event)->WaitList = TmpWaitList; const auto &WaitList = (*Event)->WaitList; + if (WaitList.Length) { ZE_CALL(zeCommandListAppendWaitOnEvents, (ZeCommandList, WaitList.Length, WaitList.ZeEventList)); @@ -4559,6 +4594,8 @@ static pi_result enqueueMemCopyRectHelper( zePrint("calling zeCommandListAppendBarrier() with Event %#lx\n", pi_cast(ZeEvent)); + Queue->LastCommandEvent = *Event; + if (auto Res = Queue->executeCommandList(ZeCommandList, ZeFence, Blocking)) return Res; @@ -4655,14 +4692,14 @@ enqueueMemFillHelper(pi_command_type CommandType, pi_queue Queue, void *Ptr, PI_ASSERT(Queue, PI_INVALID_QUEUE); PI_ASSERT(Event, PI_INVALID_EVENT); + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, EventWaitList, Queue)) return Res; - // Lock automatically releases when this goes out of scope. - std::lock_guard lock(Queue->PiQueueMutex); - // Get a new command list to be used on this call ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; @@ -4681,6 +4718,7 @@ enqueueMemFillHelper(pi_command_type CommandType, pi_queue Queue, void *Ptr, (*Event)->WaitList = TmpWaitList; const auto &WaitList = (*Event)->WaitList; + if (WaitList.Length) { ZE_CALL(zeCommandListAppendWaitOnEvents, (ZeCommandList, WaitList.Length, WaitList.ZeEventList)); @@ -4698,6 +4736,8 @@ enqueueMemFillHelper(pi_command_type CommandType, pi_queue Queue, void *Ptr, pi_cast(ZeEvent)); printZeEventList(WaitList); + Queue->LastCommandEvent = *Event; + // Execute command list asynchronously, as the event will be used // to track down its completion. if (auto Res = Queue->executeCommandList(ZeCommandList, ZeFence)) @@ -4738,12 +4778,7 @@ pi_result piEnqueueMemBufferMap(pi_queue Queue, pi_mem Buffer, PI_ASSERT(Queue, PI_INVALID_QUEUE); PI_ASSERT(Event, PI_INVALID_EVENT); - _pi_ze_event_list_t TmpWaitList; - if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, - EventWaitList, Queue)) - return Res; - - // For discrete devices we don't need a commandlist + // For integrated devices we don't need a commandlist ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; ze_event_handle_t ZeEvent = nullptr; @@ -4752,6 +4787,11 @@ pi_result piEnqueueMemBufferMap(pi_queue Queue, pi_mem Buffer, // Lock automatically releases when this goes out of scope. std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; + if (auto Res = TmpWaitList.createAndRetainPiZeEventList( + NumEventsInWaitList, EventWaitList, Queue)) + return Res; + auto Res = createEventAndAssociateQueue( Queue, Event, PI_COMMAND_TYPE_MEM_BUFFER_MAP, ZeCommandList); if (Res != PI_SUCCESS) @@ -4776,6 +4816,21 @@ pi_result piEnqueueMemBufferMap(pi_queue Queue, pi_mem Buffer, if (Buffer->OnHost) { // Wait on incoming events before doing the copy PI_CALL(piEventsWait(NumEventsInWaitList, EventWaitList)); + + if (Queue->isInOrderQueue()) { + pi_event TmpLastCommandEvent = nullptr; + + { + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + TmpLastCommandEvent = Queue->LastCommandEvent; + } + + if (TmpLastCommandEvent != nullptr) { + PI_CALL(piEventsWait(1, &TmpLastCommandEvent)); + } + } + if (Buffer->MapHostPtr) { *RetMap = Buffer->MapHostPtr + Offset; if (!(MapFlags & PI_MAP_WRITE_INVALIDATE_REGION)) @@ -4814,15 +4869,19 @@ pi_result piEnqueueMemBufferMap(pi_queue Queue, pi_mem Buffer, } const auto &WaitList = (*Event)->WaitList; + if (WaitList.Length) { ZE_CALL(zeCommandListAppendWaitOnEvents, (ZeCommandList, WaitList.Length, WaitList.ZeEventList)); } + ZE_CALL(zeCommandListAppendMemoryCopy, (ZeCommandList, *RetMap, pi_cast(Buffer->getZeHandle()) + Offset, Size, ZeEvent, 0, nullptr)); + Queue->LastCommandEvent = *Event; + if (auto Res = Queue->executeCommandList(ZeCommandList, ZeFence, BlockingMap)) return Res; @@ -4835,11 +4894,6 @@ pi_result piEnqueueMemUnmap(pi_queue Queue, pi_mem MemObj, void *MappedPtr, PI_ASSERT(Queue, PI_INVALID_QUEUE); PI_ASSERT(Event, PI_INVALID_EVENT); - _pi_ze_event_list_t TmpWaitList; - if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, - EventWaitList, Queue)) - return Res; - // Integrated devices don't need a command list. // If discrete we will get a commandlist later. ze_command_list_handle_t ZeCommandList = nullptr; @@ -4855,6 +4909,11 @@ pi_result piEnqueueMemUnmap(pi_queue Queue, pi_mem MemObj, void *MappedPtr, // Lock automatically releases when this goes out of scope. std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; + if (auto Res = TmpWaitList.createAndRetainPiZeEventList( + NumEventsInWaitList, EventWaitList, Queue)) + return Res; + auto Res = createEventAndAssociateQueue( Queue, Event, PI_COMMAND_TYPE_MEM_BUFFER_UNMAP, ZeCommandList); if (Res != PI_SUCCESS) @@ -4881,6 +4940,21 @@ pi_result piEnqueueMemUnmap(pi_queue Queue, pi_mem MemObj, void *MappedPtr, if (MemObj->OnHost) { // Wait on incoming events before doing the copy PI_CALL(piEventsWait(NumEventsInWaitList, EventWaitList)); + + if (Queue->isInOrderQueue()) { + pi_event TmpLastCommandEvent = nullptr; + + { + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + TmpLastCommandEvent = Queue->LastCommandEvent; + } + + if (TmpLastCommandEvent != nullptr) { + PI_CALL(piEventsWait(1, &TmpLastCommandEvent)); + } + } + if (MemObj->MapHostPtr) memcpy(pi_cast(MemObj->getZeHandle()) + MapInfo.Offset, MappedPtr, MapInfo.Size); @@ -4906,6 +4980,7 @@ pi_result piEnqueueMemUnmap(pi_queue Queue, pi_mem MemObj, void *MappedPtr, (ZeCommandList, (*Event)->WaitList.Length, (*Event)->WaitList.ZeEventList)); } + // TODO: Level Zero is missing the memory "mapping" capabilities, so we are // left to doing copy (write back to the device). // @@ -4917,6 +4992,8 @@ pi_result piEnqueueMemUnmap(pi_queue Queue, pi_mem MemObj, void *MappedPtr, pi_cast(MemObj->getZeHandle()) + MapInfo.Offset, MappedPtr, MapInfo.Size, ZeEvent, 0, nullptr)); + Queue->LastCommandEvent = *Event; + // Execute command list asynchronously, as the event will be used // to track down its completion. if (auto Res = Queue->executeCommandList(ZeCommandList, ZeFence)) @@ -4995,14 +5072,14 @@ static pi_result enqueueMemImageCommandHelper( PI_ASSERT(Queue, PI_INVALID_QUEUE); PI_ASSERT(Event, PI_INVALID_EVENT); + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, EventWaitList, Queue)) return Res; - // Lock automatically releases when this goes out of scope. - std::lock_guard lock(Queue->PiQueueMutex); - // Get a new command list to be used on this call ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; @@ -5019,6 +5096,7 @@ static pi_result enqueueMemImageCommandHelper( (*Event)->WaitList = TmpWaitList; const auto &WaitList = (*Event)->WaitList; + if (WaitList.Length) { ZE_CALL(zeCommandListAppendWaitOnEvents, (ZeCommandList, WaitList.Length, WaitList.ZeEventList)); @@ -5112,6 +5190,8 @@ static pi_result enqueueMemImageCommandHelper( return PI_INVALID_OPERATION; } + Queue->LastCommandEvent = *Event; + if (auto Res = Queue->executeCommandList(ZeCommandList, ZeFence, IsBlocking)) return Res; @@ -5609,14 +5689,14 @@ pi_result piextUSMEnqueuePrefetch(pi_queue Queue, const void *Ptr, size_t Size, PI_ASSERT(Queue, PI_INVALID_QUEUE); PI_ASSERT(Event, PI_INVALID_EVENT); + // Lock automatically releases when this goes out of scope. + std::lock_guard lock(Queue->PiQueueMutex); + _pi_ze_event_list_t TmpWaitList; if (auto Res = TmpWaitList.createAndRetainPiZeEventList(NumEventsInWaitList, EventWaitList, Queue)) return Res; - // Lock automatically releases when this goes out of scope. - std::lock_guard lock(Queue->PiQueueMutex); - // Get a new command list to be used on this call ze_command_list_handle_t ZeCommandList = nullptr; ze_fence_handle_t ZeFence = nullptr; @@ -5639,6 +5719,7 @@ pi_result piextUSMEnqueuePrefetch(pi_queue Queue, const void *Ptr, size_t Size, return Res; const auto &WaitList = (*Event)->WaitList; + if (WaitList.Length) { ZE_CALL(zeCommandListAppendWaitOnEvents, (ZeCommandList, WaitList.Length, WaitList.ZeEventList)); @@ -5650,6 +5731,8 @@ pi_result piextUSMEnqueuePrefetch(pi_queue Queue, const void *Ptr, size_t Size, // so manually add command to signal our event. ZE_CALL(zeCommandListAppendSignalEvent, (ZeCommandList, ZeEvent)); + Queue->LastCommandEvent = *Event; + if (auto Res = Queue->executeCommandList(ZeCommandList, ZeFence, false)) return Res; @@ -5693,9 +5776,22 @@ pi_result piextUSMEnqueueMemAdvise(pi_queue Queue, const void *Ptr, return Res; ZeEvent = (*Event)->ZeEvent; + if (auto Res = + (*Event)->WaitList.createAndRetainPiZeEventList(0, nullptr, Queue)) + return Res; + + const auto &WaitList = (*Event)->WaitList; + + if (WaitList.Length) { + ZE_CALL(zeCommandListAppendWaitOnEvents, + (ZeCommandList, WaitList.Length, WaitList.ZeEventList)); + } + ZE_CALL(zeCommandListAppendMemAdvise, (ZeCommandList, Queue->Device->ZeDevice, Ptr, Length, ZeAdvice)); + Queue->LastCommandEvent = *Event; + // TODO: Level Zero does not have a completion "event" with the advise API, // so manually add command to signal our event. ZE_CALL(zeCommandListAppendSignalEvent, (ZeCommandList, ZeEvent)); diff --git a/sycl/plugins/level_zero/pi_level_zero.hpp b/sycl/plugins/level_zero/pi_level_zero.hpp index 16fcc805daad8..704b25330a352 100644 --- a/sycl/plugins/level_zero/pi_level_zero.hpp +++ b/sycl/plugins/level_zero/pi_level_zero.hpp @@ -331,6 +331,12 @@ struct _pi_queue : _pi_object { // needed/used for the queue data structures. std::mutex PiQueueMutex; + // Keeps track of the event associated with the last enqueued command into + // this queue. this is used to add dependency with the last command to add + // in-order semantics and updated with the latest event each time a new + // command is enqueued. + pi_event LastCommandEvent = nullptr; + // Open command list field for batching commands into this queue. ze_command_list_handle_t ZeOpenCommandList = {nullptr}; ze_fence_handle_t ZeOpenCommandListFence = {nullptr}; diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index 99b6f13a4c823..37c3f33e7e542 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -497,14 +497,9 @@ void Command::processDepEvent(EventImplPtr DepEvent, const DepDesc &Dep) { } // Do not add redundant event dependencies for in-order queues. - // TODO temporarily disabled with Level Zero since the enqueued operations - // that are implemented directly in the plugin (e.g. map/unmap) do not satisfy - // in-order queue requirements. - if (WorkerQueue->is_host() || - WorkerQueue->getPlugin().getBackend() != backend::level_zero) - if (Dep.MDepCommand && Dep.MDepCommand->getWorkerQueue() == WorkerQueue && - WorkerQueue->has_property()) - return; + if (Dep.MDepCommand && Dep.MDepCommand->getWorkerQueue() == WorkerQueue && + WorkerQueue->has_property()) + return; ContextImplPtr DepEventContext = DepEvent->getContextImpl(); // If contexts don't match we'll connect them using host task diff --git a/sycl/unittests/scheduler/InOrderQueueDeps.cpp b/sycl/unittests/scheduler/InOrderQueueDeps.cpp index 009fd8cf42c27..cec7c1772852c 100644 --- a/sycl/unittests/scheduler/InOrderQueueDeps.cpp +++ b/sycl/unittests/scheduler/InOrderQueueDeps.cpp @@ -83,13 +83,6 @@ TEST_F(SchedulerTest, InOrderQueueDeps) { std::cout << "Not run due to host-only environment\n"; return; } - if (detail::getSyclObjImpl(Plt)->getPlugin().getBackend() == - backend::level_zero) { - std::cout << "Removal of redundant dependencies in in-order queues is " - "disabled for Level Zero until it is supported by the plugin" - << std::endl; - return; - } unittest::PiMock Mock{Plt}; Mock.redefine(redefinedMemBufferCreate);