Skip to content

Commit 2af3dec

Browse files
Move check-lock-check logic to a separate template.
1 parent 5dfc457 commit 2af3dec

File tree

2 files changed

+60
-39
lines changed

2 files changed

+60
-39
lines changed

sycl/source/detail/queue_impl.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -284,13 +284,13 @@ event queue_impl::memcpyFromDeviceGlobal(
284284
}
285285

286286
sycl::detail::optional<event> queue_impl::getLastEvent() {
287-
{
288-
// The external event is required to finish last if set, so it is considered
289-
// the last event if present.
290-
std::lock_guard<std::mutex> Lock(MInOrderExternalEventMtx);
291-
if (MInOrderExternalEvent)
292-
return *MInOrderExternalEvent;
293-
}
287+
// The external event is required to finish last if set, so it is considered
288+
// the last event if present.
289+
if (std::optional<event> ExternalEvent =
290+
MInOrderExternalEvent.read([](std::optional<event> &InOrderExternalEvent) {
291+
return InOrderExternalEvent;
292+
}))
293+
return ExternalEvent;
294294

295295
std::lock_guard<std::mutex> Lock{MMutex};
296296
if (MGraph.expired() && !MDefaultGraphDeps.LastEventPtr)
@@ -618,13 +618,11 @@ void queue_impl::wait(const detail::code_location &CodeLoc) {
618618
WeakEvents.swap(MEventsWeak);
619619
SharedEvents.swap(MEventsShared);
620620

621-
if (MAreCleanupRequestsMissed.load(std::memory_order_acquire)) {
622-
std::lock_guard<std::mutex> RequestLock(MMissedCleanupRequestsMtx);
623-
MAreCleanupRequestsMissed.store(false, std::memory_order_release);
624-
for (auto &UpdatedGraph : MMissedCleanupRequests)
621+
MMissedCleanupRequests.get([this](MissedCleanupRequestsType &MissedCleanupRequests){
622+
for (auto &UpdatedGraph : MissedCleanupRequests)
625623
doUnenqueuedCommandCleanup(UpdatedGraph);
626-
MMissedCleanupRequests.clear();
627-
}
624+
MissedCleanupRequests.clear();
625+
});
628626
}
629627
// If the queue is either a host one or does not support OOO (and we use
630628
// multiple in-order queues as a result of that), wait for each event
@@ -800,9 +798,9 @@ void queue_impl::revisitUnenqueuedCommandsState(
800798
if (Lock.owns_lock())
801799
doUnenqueuedCommandCleanup(CompletedHostTask->getCommandGraph());
802800
else {
803-
std::lock_guard<std::mutex> RequestLock(MMissedCleanupRequestsMtx);
804-
MMissedCleanupRequests.push_back(CompletedHostTask->getCommandGraph());
805-
MAreCleanupRequestsMissed.store(true, std::memory_order_release);
801+
MMissedCleanupRequests.put([CompletedHostTask](MissedCleanupRequestsType &MissedCleanupRequests){
802+
MissedCleanupRequests.push_back(CompletedHostTask->getCommandGraph());
803+
});
806804
}
807805
}
808806

sycl/source/detail/queue_impl.hpp

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -710,19 +710,17 @@ class queue_impl {
710710
void *getTraceEvent() { return MTraceEvent; }
711711

712712
void setExternalEvent(const event &Event) {
713-
std::lock_guard<std::mutex> Lock(MInOrderExternalEventMtx);
714-
MHasValueInOrderExternalEvent.store(true, std::memory_order_release);
715-
MInOrderExternalEvent = Event;
713+
MInOrderExternalEvent.put([&Event](std::optional<event> &InOrderExternalEvent){
714+
InOrderExternalEvent = Event;
715+
});
716716
}
717717

718718
std::optional<event> popExternalEvent() {
719719
std::optional<event> Result = std::nullopt;
720720

721-
if (MHasValueInOrderExternalEvent.load(std::memory_order_acquire)) {
722-
std::lock_guard<std::mutex> Lock(MInOrderExternalEventMtx);
723-
MHasValueInOrderExternalEvent.store(false, std::memory_order_release);
724-
std::swap(Result, MInOrderExternalEvent);
725-
}
721+
MInOrderExternalEvent.get([&Result](std::optional<event> &InOrderExternalEvent) {
722+
std::swap(Result, InOrderExternalEvent);
723+
});
726724
return Result;
727725
}
728726

@@ -838,14 +836,11 @@ class queue_impl {
838836
// dependency so in the case where some commands were not enqueued
839837
// (blocked), we track them to prevent barrier from being enqueued
840838
// earlier.
841-
if (MAreCleanupRequestsMissed.load(std::memory_order_acquire))
842-
{
843-
std::lock_guard<std::mutex> RequestLock(MMissedCleanupRequestsMtx);
844-
MAreCleanupRequestsMissed.store(false, std::memory_order_release);
845-
for (auto &UpdatedGraph : MMissedCleanupRequests)
839+
MMissedCleanupRequests.get([this](MissedCleanupRequestsType &MissedCleanupRequests){
840+
for (auto &UpdatedGraph : MissedCleanupRequests)
846841
doUnenqueuedCommandCleanup(UpdatedGraph);
847-
MMissedCleanupRequests.clear();
848-
}
842+
MissedCleanupRequests.clear();
843+
});
849844
auto &Deps = MGraph.expired() ? MDefaultGraphDeps : MExtGraphDeps;
850845
if (Type == CGType::Barrier && !Deps.UnenqueuedCmdEvents.empty()) {
851846
Handler.depends_on(Deps.UnenqueuedCmdEvents);
@@ -1029,6 +1024,38 @@ class queue_impl {
10291024
}
10301025
} MDefaultGraphDeps, MExtGraphDeps;
10311026

1027+
// implement check-lock-check pattern to not lock empty MData
1028+
template <typename DataType>
1029+
class CheckLockCheck {
1030+
DataType MData;
1031+
std::atomic_bool MDataPresent = false;
1032+
mutable std::mutex MDataMtx;
1033+
public:
1034+
template <typename F>
1035+
void put(F &&func) {
1036+
std::lock_guard<std::mutex> Lock(MDataMtx);
1037+
MDataPresent.store(true, std::memory_order_release);
1038+
func(MData);
1039+
}
1040+
template <typename F>
1041+
void get(F &&func) {
1042+
if (MDataPresent.load(std::memory_order_acquire)) {
1043+
std::lock_guard<std::mutex> Lock(MDataMtx);
1044+
if (MDataPresent.load(std::memory_order_acquire)) {
1045+
func(MData);
1046+
MDataPresent.store(false, std::memory_order_release);
1047+
}
1048+
}
1049+
}
1050+
template <typename F>
1051+
DataType read(F &&func) {
1052+
if (!MDataPresent.load(std::memory_order_acquire))
1053+
return DataType{};
1054+
std::lock_guard<std::mutex> Lock(MDataMtx);
1055+
return func(MData);
1056+
}
1057+
};
1058+
10321059
const bool MIsInorder;
10331060

10341061
std::vector<EventImplPtr> MStreamsServiceEvents;
@@ -1047,14 +1074,11 @@ class queue_impl {
10471074
// the fallback implementation of profiling info
10481075
bool MFallbackProfiling = false;
10491076

1050-
// Is value presented in MInOrderExternalEvent?
1051-
std::atomic_bool MHasValueInOrderExternalEvent = false;
10521077
// This event can be optionally provided by users for in-order queues to add
10531078
// an additional dependency for the subsequent submission in to the queue.
10541079
// Access to the event should be guarded with MInOrderExternalEventMtx.
10551080
// NOTE: std::optional must not be exposed in the ABI.
1056-
std::optional<event> MInOrderExternalEvent;
1057-
mutable std::mutex MInOrderExternalEventMtx;
1081+
CheckLockCheck<std::optional<event>> MInOrderExternalEvent;
10581082

10591083
public:
10601084
// Queue constructed with the discard_events property
@@ -1077,10 +1101,9 @@ class queue_impl {
10771101
unsigned long long MQueueID;
10781102
static std::atomic<unsigned long long> MNextAvailableQueueID;
10791103

1080-
std::deque<std::shared_ptr<ext::oneapi::experimental::detail::graph_impl>>
1081-
MMissedCleanupRequests;
1082-
std::mutex MMissedCleanupRequestsMtx;
1083-
std::atomic_bool MAreCleanupRequestsMissed = false;
1104+
using MissedCleanupRequestsType =
1105+
std::deque<std::shared_ptr<ext::oneapi::experimental::detail::graph_impl>>;
1106+
CheckLockCheck<MissedCleanupRequestsType> MMissedCleanupRequests;
10841107

10851108
friend class sycl::ext::oneapi::experimental::detail::node_impl;
10861109

0 commit comments

Comments
 (0)