[Openmp-commits] [openmp] 2a539ee - [OpenMP][libomptarget] Implement memory lock/unlock API in NextGen plugins
Kevin Sala via Openmp-commits
openmp-commits at lists.llvm.org
Tue Jan 24 15:12:09 PST 2023
Author: Kevin Sala
Date: 2023-01-25T00:11:38+01:00
New Revision: 2a539ee17d8a6f0e4b99e1f8e8df593500b9154b
URL: https://github.com/llvm/llvm-project/commit/2a539ee17d8a6f0e4b99e1f8e8df593500b9154b
DIFF: https://github.com/llvm/llvm-project/commit/2a539ee17d8a6f0e4b99e1f8e8df593500b9154b.diff
LOG: [OpenMP][libomptarget] Implement memory lock/unlock API in NextGen plugins
This patch implements the memory lock/unlock API, introduced in patch https://reviews.llvm.org/D139208,
in the NextGen plugins. Locked buffers feature reference counting and we allow certain overlapping. Given
an already locked buffer A, other buffers that are fully contained inside A can be locked again, even if
they are smaller than A. In this case, the reference count of locked buffer A will be incremented. However,
extending an existing locked buffer is not allowed. The original buffer is actually unlocked once all its
users have released the locked buffer and sub-buffers (i.e., the reference counter becomes zero).
Differential Revision: https://reviews.llvm.org/D141227
Added:
Modified:
openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp
openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp
openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.h
openmp/libomptarget/plugins-nextgen/cuda/src/rtl.cpp
openmp/libomptarget/plugins-nextgen/generic-elf-64bit/src/rtl.cpp
Removed:
################################################################################
diff --git a/openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp b/openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp
index 4374e110628d2..ca313f553b041 100644
--- a/openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp
+++ b/openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp
@@ -1826,14 +1826,33 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
return Plugin::success();
}
+ /// Pin the host buffer and return the device pointer that should be used for
+ /// device transfers.
+ Expected<void *> dataLockImpl(void *HstPtr, int64_t Size) override {
+ void *PinnedPtr = nullptr;
+
+ hsa_status_t Status =
+ hsa_amd_memory_lock(HstPtr, Size, nullptr, 0, &PinnedPtr);
+ if (auto Err = Plugin::check(Status, "Error in hsa_amd_memory_lock: %s\n"))
+ return Err;
+
+ return PinnedPtr;
+ }
+
+ /// Unpin the host buffer.
+ Error dataUnlockImpl(void *HstPtr) override {
+ hsa_status_t Status = hsa_amd_memory_unlock(HstPtr);
+ return Plugin::check(Status, "Error in hsa_amd_memory_unlock: %s\n");
+ }
+
/// Submit data to the device (host to device transfer).
Error dataSubmitImpl(void *TgtPtr, const void *HstPtr, int64_t Size,
AsyncInfoWrapperTy &AsyncInfoWrapper) override {
-
// Use one-step asynchronous operation when host memory is already pinned.
- if (isHostPinnedMemoryBuffer(HstPtr)) {
+ if (void *PinnedPtr =
+ PinnedAllocs.getDeviceAccessiblePtrFromPinnedBuffer(HstPtr)) {
AMDGPUStreamTy &Stream = getStream(AsyncInfoWrapper);
- return Stream.pushPinnedMemoryCopyAsync(TgtPtr, HstPtr, Size);
+ return Stream.pushPinnedMemoryCopyAsync(TgtPtr, PinnedPtr, Size);
}
void *PinnedHstPtr = nullptr;
@@ -1887,10 +1906,10 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
AsyncInfoWrapperTy &AsyncInfoWrapper) override {
// Use one-step asynchronous operation when host memory is already pinned.
- if (isHostPinnedMemoryBuffer(HstPtr)) {
- // Use one-step asynchronous operation when host memory is already pinned.
+ if (void *PinnedPtr =
+ PinnedAllocs.getDeviceAccessiblePtrFromPinnedBuffer(HstPtr)) {
AMDGPUStreamTy &Stream = getStream(AsyncInfoWrapper);
- return Stream.pushPinnedMemoryCopyAsync(HstPtr, TgtPtr, Size);
+ return Stream.pushPinnedMemoryCopyAsync(PinnedPtr, TgtPtr, Size);
}
void *PinnedHstPtr = nullptr;
diff --git a/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp b/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp
index 66d7049f37d2f..d1f5996f3b900 100644
--- a/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp
+++ b/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.cpp
@@ -333,7 +333,8 @@ GenericDeviceTy::GenericDeviceTy(int32_t DeviceId, int32_t NumDevices,
OMPX_InitialNumStreams("LIBOMPTARGET_NUM_INITIAL_STREAMS", 32),
OMPX_InitialNumEvents("LIBOMPTARGET_NUM_INITIAL_EVENTS", 32),
DeviceId(DeviceId), GridValues(OMPGridValues),
- PeerAccesses(NumDevices, PeerAccessState::PENDING), PeerAccessesLock() {
+ PeerAccesses(NumDevices, PeerAccessState::PENDING), PeerAccessesLock(),
+ PinnedAllocs(*this) {
if (OMP_NumTeams > 0)
GridValues.GV_Max_Teams =
std::min(GridValues.GV_Max_Teams, uint32_t(OMP_NumTeams));
@@ -581,23 +582,110 @@ GenericDeviceTy::getExecutionModeForKernel(StringRef Name,
return ExecModeGlobal.getValue();
}
-Error GenericDeviceTy::registerHostPinnedMemoryBuffer(const void *Buffer,
- size_t Size) {
- std::lock_guard<std::shared_mutex> Lock(HostAllocationsMutex);
+Error PinnedAllocationMapTy::registerHostBuffer(void *HstPtr,
+ void *DevAccessiblePtr,
+ size_t Size) {
+ assert(HstPtr && "Invalid pointer");
+ assert(DevAccessiblePtr && "Invalid pointer");
- auto Res = HostAllocations.insert({Buffer, Size});
+ std::lock_guard<std::shared_mutex> Lock(Mutex);
+
+ // No pinned allocation should intersect.
+ auto Res = Allocs.insert({HstPtr, DevAccessiblePtr, Size});
if (!Res.second)
- return Plugin::error("Registering an already registered pinned buffer");
+ return Plugin::error("Cannot register locked buffer");
+
+ return Plugin::success();
+}
+
+Error PinnedAllocationMapTy::unregisterHostBuffer(void *HstPtr) {
+ assert(HstPtr && "Invalid pointer");
+
+ std::lock_guard<std::shared_mutex> Lock(Mutex);
+
+ // Find the pinned allocation starting at the host pointer address.
+ auto It = Allocs.find({HstPtr});
+ if (It == Allocs.end())
+ return Plugin::error("Cannot find locked buffer");
+
+ const EntryTy &Entry = *It;
+
+ // There should be no other references to the pinned allocation.
+ if (Entry.References > 1)
+ return Plugin::error("The locked buffer is still being used");
+
+ // Remove the entry from the map.
+ Allocs.erase(It);
return Plugin::success();
}
-Error GenericDeviceTy::unregisterHostPinnedMemoryBuffer(const void *Buffer) {
- std::lock_guard<std::shared_mutex> Lock(HostAllocationsMutex);
+Expected<void *> PinnedAllocationMapTy::lockHostBuffer(void *HstPtr,
+ size_t Size) {
+ assert(HstPtr && "Invalid pointer");
+
+ std::lock_guard<std::shared_mutex> Lock(Mutex);
+
+ auto It = findIntersecting(HstPtr);
+
+ // No intersecting registered allocation found in the map. We must lock and
+ // register the memory buffer into the map.
+ if (It == Allocs.end()) {
+ // First, lock the host buffer and retrieve the device accessible pointer.
+ auto PinnedPtrOrErr = Device.dataLockImpl(HstPtr, Size);
+ if (!PinnedPtrOrErr)
+ return PinnedPtrOrErr.takeError();
+
+ // Then, insert the host buffer entry into the map.
+ auto Res = Allocs.insert({HstPtr, *PinnedPtrOrErr, Size});
+ if (!Res.second)
+ return Plugin::error("Cannot register locked buffer");
+
+ // Return the device accessible pointer.
+ return *PinnedPtrOrErr;
+ }
+
+ const EntryTy &Entry = *It;
+
+#ifdef OMPTARGET_DEBUG
+ // Do not allow partial overlapping among host pinned buffers.
+ if (advanceVoidPtr(HstPtr, Size) > advanceVoidPtr(Entry.HstPtr, Entry.Size))
+ return Plugin::error("Partial overlapping not allowed in locked memory");
+#endif
+
+ // Increase the number of references.
+ Entry.References++;
+
+ // Return the device accessible pointer after applying the correct offset.
+ return advanceVoidPtr(Entry.DevAccessiblePtr,
+ getPtrDiff(HstPtr, Entry.HstPtr));
+}
+
+Error PinnedAllocationMapTy::unlockHostBuffer(void *HstPtr) {
+ assert(HstPtr && "Invalid pointer");
+
+ std::lock_guard<std::shared_mutex> Lock(Mutex);
- size_t Erased = HostAllocations.erase(Buffer);
+ auto It = findIntersecting(HstPtr);
+ if (It == Allocs.end())
+ return Plugin::error("Cannot find locked buffer");
+
+ const EntryTy &Entry = *It;
+
+ // Decrease the number of references. No need to do anything if there are
+ // others using the allocation.
+ if (--Entry.References > 0)
+ return Plugin::success();
+
+ // This was the last user of the allocation. Unlock the original locked memory
+ // buffer, which is the host pointer stored in the entry.
+ if (auto Err = Device.dataUnlockImpl(Entry.HstPtr))
+ return Err;
+
+ // Remove the entry from the map.
+ size_t Erased = Allocs.erase(Entry);
if (!Erased)
- return Plugin::error("Cannot find a registered host pinned buffer");
+ return Plugin::error("Cannot find locked buffer");
return Plugin::success();
}
@@ -648,7 +736,7 @@ Expected<void *> GenericDeviceTy::dataAlloc(int64_t Size, void *HostPtr,
// Register allocated buffer as pinned memory if the type is host memory.
if (Kind == TARGET_ALLOC_HOST)
- if (auto Err = registerHostPinnedMemoryBuffer(Alloc, Size))
+ if (auto Err = PinnedAllocs.registerHostBuffer(Alloc, Alloc, Size))
return Err;
return Alloc;
@@ -670,7 +758,7 @@ Error GenericDeviceTy::dataDelete(void *TgtPtr, TargetAllocTy Kind) {
// Unregister deallocated pinned memory buffer if the type is host memory.
if (Kind == TARGET_ALLOC_HOST)
- if (auto Err = unregisterHostPinnedMemoryBuffer(TgtPtr))
+ if (auto Err = PinnedAllocs.unregisterHostBuffer(TgtPtr))
return Err;
return Plugin::success();
@@ -998,6 +1086,36 @@ int32_t __tgt_rtl_data_delete(int32_t DeviceId, void *TgtPtr, int32_t Kind) {
return OFFLOAD_SUCCESS;
}
+int32_t __tgt_rtl_data_lock(int32_t DeviceId, void *Ptr, int64_t Size,
+ void **LockedPtr) {
+ auto LockedPtrOrErr = Plugin::get().getDevice(DeviceId).dataLock(Ptr, Size);
+ if (!LockedPtrOrErr) {
+ auto Err = LockedPtrOrErr.takeError();
+ REPORT("Failure to lock memory %p: %s\n", Ptr,
+ toString(std::move(Err)).data());
+ return OFFLOAD_FAIL;
+ }
+
+ if (!(*LockedPtrOrErr)) {
+ REPORT("Failure to lock memory %p: obtained a null locked pointer\n", Ptr);
+ return OFFLOAD_FAIL;
+ }
+ *LockedPtr = *LockedPtrOrErr;
+
+ return OFFLOAD_SUCCESS;
+}
+
+int32_t __tgt_rtl_data_unlock(int32_t DeviceId, void *Ptr) {
+ auto Err = Plugin::get().getDevice(DeviceId).dataUnlock(Ptr);
+ if (Err) {
+ REPORT("Failure to unlock memory %p: %s\n", Ptr,
+ toString(std::move(Err)).data());
+ return OFFLOAD_FAIL;
+ }
+
+ return OFFLOAD_SUCCESS;
+}
+
int32_t __tgt_rtl_data_submit(int32_t DeviceId, void *TgtPtr, void *HstPtr,
int64_t Size) {
return __tgt_rtl_data_submit_async(DeviceId, TgtPtr, HstPtr, Size,
diff --git a/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.h b/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.h
index 321b9bca274b5..11157e5d0f390 100644
--- a/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.h
+++ b/openmp/libomptarget/plugins-nextgen/common/PluginInterface/PluginInterface.h
@@ -252,6 +252,146 @@ struct GenericKernelTy {
uint32_t MaxNumThreads;
};
+/// Class representing a map of host pinned allocations. We track these pinned
+/// allocations, so memory tranfers invloving these buffers can be optimized.
+class PinnedAllocationMapTy {
+
+ /// Struct representing a map entry.
+ struct EntryTy {
+ /// The host pointer of the pinned allocation.
+ void *HstPtr;
+
+ /// The pointer that devices' driver should use to transfer data from/to the
+ /// pinned allocation. In most plugins, this pointer will be the same as the
+ /// host pointer above.
+ void *DevAccessiblePtr;
+
+ /// The size of the pinned allocation.
+ size_t Size;
+
+ /// The number of references to the pinned allocation. The allocation should
+ /// remain pinned and registered to the map until the number of references
+ /// becomes zero.
+ mutable size_t References;
+
+ /// Create an entry with the host and device acessible pointers, and the
+ /// buffer size.
+ EntryTy(void *HstPtr, void *DevAccessiblePtr, size_t Size)
+ : HstPtr(HstPtr), DevAccessiblePtr(DevAccessiblePtr), Size(Size),
+ References(1) {}
+
+ /// Utility constructor used for std::set searches.
+ EntryTy(void *HstPtr)
+ : HstPtr(HstPtr), DevAccessiblePtr(nullptr), Size(0), References(0) {}
+ };
+
+ /// Comparator of mep entries. Use the host pointer to enforce an order
+ /// between entries.
+ struct EntryCmpTy {
+ bool operator()(const EntryTy &Left, const EntryTy &Right) const {
+ return Left.HstPtr < Right.HstPtr;
+ }
+ };
+
+ typedef std::set<EntryTy, EntryCmpTy> PinnedAllocSetTy;
+
+ /// The map of host pinned allocations.
+ PinnedAllocSetTy Allocs;
+
+ /// The mutex to protect accesses to the map.
+ mutable std::shared_mutex Mutex;
+
+ /// Reference to the corresponding device.
+ GenericDeviceTy &Device;
+
+ /// Find an allocation that intersects with \p Buffer pointer. Assume
+ /// the map's mutex is acquired.
+ PinnedAllocSetTy::iterator findIntersecting(const void *Buffer) const {
+ if (Allocs.empty())
+ return Allocs.end();
+
+ // Search the first allocation with starting address that is not less than
+ // the buffer address.
+ auto It = Allocs.lower_bound({const_cast<void *>(Buffer)});
+
+ // Direct match of starting addresses.
+ if (It != Allocs.end() && It->HstPtr == Buffer)
+ return It;
+
+ // Not direct match but may be a previous pinned allocation in the map which
+ // contains the buffer. Return false if there is no such a previous
+ // allocation.
+ if (It == Allocs.begin())
+ return Allocs.end();
+
+ // Move to the previous pinned allocation.
+ --It;
+
+ // The buffer is not contained in the pinned allocation.
+ if (advanceVoidPtr(It->HstPtr, It->Size) > Buffer)
+ return It;
+
+ // None found.
+ return Allocs.end();
+ }
+
+public:
+ /// Create the map of pinned allocations corresponding to a specific device.
+ PinnedAllocationMapTy(GenericDeviceTy &Device) : Device(Device) {}
+
+ /// Register a host buffer that was recently locked. None of the already
+ /// registered pinned allocations should intersect with this new one. The
+ /// registration requires the host pointer in \p HstPtr, the pointer that the
+ /// devices should use when transferring data from/to the allocation in
+ /// \p DevAccessiblePtr, and the size of the allocation in \p Size. Notice
+ /// that some plugins may use the same pointer for the \p HstPtr and
+ /// \p DevAccessiblePtr. The allocation must be unregistered using the
+ /// unregisterHostBuffer function.
+ Error registerHostBuffer(void *HstPtr, void *DevAccessiblePtr, size_t Size);
+
+ /// Unregister a host pinned allocation passing the host pointer which was
+ /// previously registered using the registerHostBuffer function. When calling
+ /// this function, the pinned allocation cannot have any other user.
+ Error unregisterHostBuffer(void *HstPtr);
+
+ /// Lock the host buffer at \p HstPtr or register a new user if it intersects
+ /// with an already existing one. A partial overlapping with extension is not
+ /// allowed. The function returns the device accessible pointer of the pinned
+ /// buffer. The buffer must be unlocked using the unlockHostBuffer function.
+ Expected<void *> lockHostBuffer(void *HstPtr, size_t Size);
+
+ /// Unlock the host buffer at \p HstPtr or unregister a user if other users
+ /// are still using the pinned allocation. If this was the last user, the
+ /// pinned allocation is removed from the map and the memory is unlocked.
+ Error unlockHostBuffer(void *HstPtr);
+
+ /// Return the device accessible pointer associated to the host pinned
+ /// allocation which the \p HstPtr belongs, if any. Return null in case the
+ /// \p HstPtr does not belong to any host pinned allocation. The device
+ /// accessible pointer is the one that devices should use for data transfers
+ /// that involve a host pinned buffer.
+ void *getDeviceAccessiblePtrFromPinnedBuffer(const void *HstPtr) const {
+ std::shared_lock<std::shared_mutex> Lock(Mutex);
+
+ // Find the intersecting allocation if any.
+ auto It = findIntersecting(HstPtr);
+ if (It == Allocs.end())
+ return nullptr;
+
+ const EntryTy &Entry = *It;
+ return advanceVoidPtr(Entry.DevAccessiblePtr,
+ getPtrDiff(HstPtr, Entry.HstPtr));
+ }
+
+ /// Check whether a buffer belongs to a registered host pinned allocation.
+ bool isHostPinnedBuffer(const void *HstPtr) const {
+ std::shared_lock<std::shared_mutex> Lock(Mutex);
+
+ // Return whether there is an intersecting allocation.
+ return (findIntersecting(const_cast<void *>(HstPtr)) != Allocs.end());
+ }
+};
+
/// Class implementing common functionalities of offload devices. Each plugin
/// should define the specific device class, derive from this generic one, and
/// implement the necessary virtual function members.
@@ -310,6 +450,22 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
/// Deallocate data from the device or involving the device.
Error dataDelete(void *TgtPtr, TargetAllocTy Kind);
+ /// Pin host memory to optimize transfers and return the device accessible
+ /// pointer that devices should use for memory transfers involving the host
+ /// pinned allocation.
+ Expected<void *> dataLock(void *HstPtr, int64_t Size) {
+ return PinnedAllocs.lockHostBuffer(HstPtr, Size);
+ }
+
+ virtual Expected<void *> dataLockImpl(void *HstPtr, int64_t Size) = 0;
+
+ /// Unpin a host memory buffer that was previously pinned.
+ Error dataUnlock(void *HstPtr) {
+ return PinnedAllocs.unlockHostBuffer(HstPtr);
+ }
+
+ virtual Error dataUnlockImpl(void *HstPtr) = 0;
+
/// Submit data to the device (host to device transfer).
Error dataSubmit(void *TgtPtr, const void *HstPtr, int64_t Size,
__tgt_async_info *AsyncInfo);
@@ -420,12 +576,6 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
/// setupDeviceEnvironment() function.
virtual bool shouldSetupDeviceEnvironment() const { return true; }
- /// Register a host buffer as host pinned allocation.
- Error registerHostPinnedMemoryBuffer(const void *Buffer, size_t Size);
-
- /// Unregister a host pinned allocations.
- Error unregisterHostPinnedMemoryBuffer(const void *Buffer);
-
/// Pointer to the memory manager or nullptr if not available.
MemoryManagerTy *MemoryManager;
@@ -440,40 +590,7 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
UInt64Envar OMPX_TargetStackSize;
UInt64Envar OMPX_TargetHeapSize;
- /// Map of host pinned allocations. We track these pinned allocations so that
- /// memory transfers involving these allocations can be optimized.
- std::map<const void *, size_t> HostAllocations;
- mutable std::shared_mutex HostAllocationsMutex;
-
protected:
- /// Check whether a buffer has been registered as host pinned memory.
- bool isHostPinnedMemoryBuffer(const void *Buffer) const {
- std::shared_lock<std::shared_mutex> Lock(HostAllocationsMutex);
-
- if (HostAllocations.empty())
- return false;
-
- // Search the first allocation with starting address that is not less than
- // the buffer address.
- auto It = HostAllocations.lower_bound(Buffer);
-
- // Direct match of starting addresses.
- if (It != HostAllocations.end() && It->first == Buffer)
- return true;
-
- // Not direct match but may be a previous pinned allocation in the map which
- // contains the buffer. Return false if there is no such a previous
- // allocation.
- if (It == HostAllocations.begin())
- return false;
-
- // Move to the previous pinned allocation.
- --It;
-
- // Evaluate whether the buffer is contained in the pinned allocation.
- return (advanceVoidPtr(It->first, It->second) > (const char *)Buffer);
- }
-
/// Return the execution mode used for kernel \p Name.
Expected<OMPTgtExecModeFlags> getExecutionModeForKernel(StringRef Name,
DeviceImageTy &Image);
@@ -507,6 +624,9 @@ struct GenericDeviceTy : public DeviceAllocatorTy {
/// does not mean that device J can access device I's memory directly.
llvm::SmallVector<PeerAccessState> PeerAccesses;
std::mutex PeerAccessesLock;
+
+ /// Map of host pinned allocations used for optimize device transfers.
+ PinnedAllocationMapTy PinnedAllocs;
};
/// Class implementing common functionalities of offload plugins. Each plugin
diff --git a/openmp/libomptarget/plugins-nextgen/cuda/src/rtl.cpp b/openmp/libomptarget/plugins-nextgen/cuda/src/rtl.cpp
index 8a6479ebd2722..672a44b9919c2 100644
--- a/openmp/libomptarget/plugins-nextgen/cuda/src/rtl.cpp
+++ b/openmp/libomptarget/plugins-nextgen/cuda/src/rtl.cpp
@@ -493,6 +493,13 @@ struct CUDADeviceTy : public GenericDeviceTy {
return Plugin::check(Res, "Error in cuStreamQuery: %s");
}
+ Expected<void *> dataLockImpl(void *HstPtr, int64_t Size) override {
+ // TODO: Register the buffer as CUDA host memory.
+ return HstPtr;
+ }
+
+ Error dataUnlockImpl(void *HstPtr) override { return Plugin::success(); }
+
/// Submit data to the device (host to device transfer).
Error dataSubmitImpl(void *TgtPtr, const void *HstPtr, int64_t Size,
AsyncInfoWrapperTy &AsyncInfoWrapper) override {
diff --git a/openmp/libomptarget/plugins-nextgen/generic-elf-64bit/src/rtl.cpp b/openmp/libomptarget/plugins-nextgen/generic-elf-64bit/src/rtl.cpp
index cd1716198b83d..7bc18b6bcbb92 100644
--- a/openmp/libomptarget/plugins-nextgen/generic-elf-64bit/src/rtl.cpp
+++ b/openmp/libomptarget/plugins-nextgen/generic-elf-64bit/src/rtl.cpp
@@ -215,6 +215,15 @@ struct GenELF64DeviceTy : public GenericDeviceTy {
return OFFLOAD_SUCCESS;
}
+ /// This plugin does nothing to lock buffers. Do not return an error, just
+ /// return the same pointer as the device pointer.
+ Expected<void *> dataLockImpl(void *HstPtr, int64_t Size) override {
+ return HstPtr;
+ }
+
+ /// Nothing to do when unlocking the buffer.
+ Error dataUnlockImpl(void *HstPtr) override { return Plugin::success(); }
+
/// Submit data to the device (host to device transfer).
Error dataSubmitImpl(void *TgtPtr, const void *HstPtr, int64_t Size,
AsyncInfoWrapperTy &AsyncInfoWrapper) override {
More information about the Openmp-commits
mailing list