Skip to content

Commit c4b5d90

Browse files
committed
remove dispatchOutstandingMUs and other cleanups to scheduling
1 parent dae4a93 commit c4b5d90

File tree

4 files changed

+26
-60
lines changed

4 files changed

+26
-60
lines changed

llvm/include/llvm/ExecutionEngine/Orc/Core.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,8 +1720,6 @@ class ExecutionSession {
17201720
logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
17211721
}
17221722

1723-
void dispatchOutstandingMUs();
1724-
17251723
static std::unique_ptr<MaterializationResponsibility>
17261724
createMaterializationResponsibility(ResourceTracker &RT,
17271725
SymbolFlagsMap Symbols,
@@ -1831,13 +1829,6 @@ class ExecutionSession {
18311829

18321830
std::vector<JITDylibSP> JDs;
18331831

1834-
// FIXME: Remove this (and runOutstandingMUs) once the linking layer works
1835-
// with callbacks from asynchronous queries.
1836-
mutable std::recursive_mutex OutstandingMUsMutex;
1837-
std::vector<std::pair<std::unique_ptr<MaterializationUnit>,
1838-
std::unique_ptr<MaterializationResponsibility>>>
1839-
OutstandingMUs;
1840-
18411832
mutable std::mutex JITDispatchHandlersMutex;
18421833
DenseMap<ExecutorAddr, std::shared_ptr<JITDispatchHandlerFunction>>
18431834
JITDispatchHandlers;

llvm/include/llvm/ExecutionEngine/Orc/TaskDispatch.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ class LLVM_ABI DynamicThreadPoolTaskDispatcher : public TaskDispatcher {
162162
bool Shutdown = false;
163163
size_t Outstanding = 0;
164164
std::condition_variable OutstandingCV;
165+
SmallVector<future_base *> WaitingFutures;
165166

166167
std::optional<size_t> MaxMaterializationThreads;
167168
size_t NumMaterializationThreads = 0;
@@ -171,13 +172,16 @@ class LLVM_ABI DynamicThreadPoolTaskDispatcher : public TaskDispatcher {
171172

172173
#endif // LLVM_ENABLE_THREADS
173174

175+
/// ORC-TaskDispatch aware promise/future class that can help with task dispatch while waiting
176+
// TODO: docs
177+
174178
/// Status for future/promise state
175179
enum class FutureStatus : uint8_t { NotReady = 0, Ready = 1, NotValid = 2 };
176180

177181
/// Type-erased base class for futures
178182
class future_base {
179183
public:
180-
bool is_ready() const {
184+
bool ready() const {
181185
return state_->status_.load(std::memory_order_acquire) !=
182186
FutureStatus::NotReady;
183187
}
@@ -191,9 +195,9 @@ class future_base {
191195
/// Wait for the future to be ready, helping with task dispatch
192196
void wait(TaskDispatcher &D) {
193197
// Keep helping with task dispatch until our future is ready
194-
if (!is_ready())
198+
if (!ready())
195199
D.work_until(*this);
196-
assert(is_ready());
200+
assert(ready());
197201
}
198202

199203
protected:

llvm/lib/ExecutionEngine/Orc/Core.cpp

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,11 +1816,6 @@ void ExecutionSession::lookup(
18161816
});
18171817
});
18181818

1819-
// lookup can be re-entered recursively if running on a single thread. Run any
1820-
// outstanding MUs in case this query depends on them, otherwise this lookup
1821-
// will starve waiting for a result from an MU that is stuck in the queue.
1822-
dispatchOutstandingMUs();
1823-
18241819
auto Unresolved = std::move(Symbols);
18251820
auto Q = std::make_shared<AsynchronousSymbolQuery>(Unresolved, RequiredState,
18261821
std::move(NotifyComplete));
@@ -2156,32 +2151,6 @@ bool ExecutionSession::verifySessionState(Twine Phase) {
21562151
}
21572152
#endif // EXPENSIVE_CHECKS
21582153

2159-
void ExecutionSession::dispatchOutstandingMUs() {
2160-
LLVM_DEBUG(dbgs() << "Dispatching MaterializationUnits...\n");
2161-
while (true) {
2162-
std::optional<std::pair<std::unique_ptr<MaterializationUnit>,
2163-
std::unique_ptr<MaterializationResponsibility>>>
2164-
JMU;
2165-
2166-
{
2167-
std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
2168-
if (!OutstandingMUs.empty()) {
2169-
JMU.emplace(std::move(OutstandingMUs.back()));
2170-
OutstandingMUs.pop_back();
2171-
}
2172-
}
2173-
2174-
if (!JMU)
2175-
break;
2176-
2177-
assert(JMU->first && "No MU?");
2178-
LLVM_DEBUG(dbgs() << " Dispatching \"" << JMU->first->getName() << "\"\n");
2179-
dispatchTask(std::make_unique<MaterializationTask>(std::move(JMU->first),
2180-
std::move(JMU->second)));
2181-
}
2182-
LLVM_DEBUG(dbgs() << "Done dispatching MaterializationUnits.\n");
2183-
}
2184-
21852154
Error ExecutionSession::removeResourceTracker(ResourceTracker &RT) {
21862155
LLVM_DEBUG({
21872156
dbgs() << "In " << RT.getJITDylib().getName() << " removing tracker "
@@ -2755,8 +2724,6 @@ void ExecutionSession::OL_completeLookup(
27552724

27562725
// Move the collected MUs to the OutstandingMUs list.
27572726
if (!CollectedUMIs.empty()) {
2758-
std::lock_guard<std::recursive_mutex> Lock(OutstandingMUsMutex);
2759-
27602727
LLVM_DEBUG(dbgs() << "Adding MUs to dispatch:\n");
27612728
for (auto &KV : CollectedUMIs) {
27622729
LLVM_DEBUG({
@@ -2768,8 +2735,9 @@ void ExecutionSession::OL_completeLookup(
27682735
auto MR = createMaterializationResponsibility(
27692736
*UMI->RT, std::move(UMI->MU->SymbolFlags),
27702737
std::move(UMI->MU->InitSymbol));
2771-
OutstandingMUs.push_back(
2772-
std::make_pair(std::move(UMI->MU), std::move(MR)));
2738+
LLVM_DEBUG(dbgs() << " Dispatching \"" << UMI->MU->getName() << "\"\n");
2739+
dispatchTask(std::make_unique<MaterializationTask>(std::move(UMI->MU),
2740+
std::move(MR)));
27732741
}
27742742
}
27752743
} else
@@ -2795,8 +2763,6 @@ void ExecutionSession::OL_completeLookup(
27952763
LLVM_DEBUG(dbgs() << "Completing query\n");
27962764
Q->handleComplete(*this);
27972765
}
2798-
2799-
dispatchOutstandingMUs();
28002766
}
28012767

28022768
void ExecutionSession::OL_completeLookupFlags(

llvm/lib/ExecutionEngine/Orc/TaskDispatch.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ void InPlaceTaskDispatcher::shutdown() {
4040
}
4141

4242
void InPlaceTaskDispatcher::work_until(future_base &F) {
43-
while (!F.is_ready()) {
43+
while (!F.ready()) {
4444
// First, process any tasks in our local queue
4545
// Process in LIFO order (most recently added first) to avoid deadlocks
4646
// when tasks have dependencies on each other
@@ -54,7 +54,7 @@ void InPlaceTaskDispatcher::work_until(future_base &F) {
5454
{
5555
std::lock_guard<std::mutex> Lock(DispatchMutex);
5656
bool ShouldNotify = llvm::any_of(
57-
WaitingFutures, [](future_base *F) { return F->is_ready(); });
57+
WaitingFutures, [](future_base *F) { return F->ready(); });
5858
if (ShouldNotify) {
5959
WaitingFutures.clear();
6060
WorkFinishedCV.notify_all();
@@ -63,23 +63,23 @@ void InPlaceTaskDispatcher::work_until(future_base &F) {
6363
#endif
6464

6565
// Check if our future is now ready
66-
if (F.is_ready())
66+
if (F.ready())
6767
return;
6868
}
6969

7070
// If we get here, our queue is empty but the future isn't ready
71-
// We need to wait for other threads to finish work that might complete our
71+
// We need to wait for other threads to finish work that should complete our
7272
// future
7373
#if LLVM_ENABLE_THREADS
7474
{
7575
std::unique_lock<std::mutex> Lock(DispatchMutex);
7676
WaitingFutures.push_back(&F);
77-
WorkFinishedCV.wait(Lock, [&F]() { return F.is_ready(); });
77+
WorkFinishedCV.wait(Lock, [&F]() { return F.ready(); });
7878
}
7979
#else
8080
// Without threading, if our queue is empty and future isn't ready,
81-
// we can't make progress
82-
return;
81+
// the library must have forgotten to schedule it, causing deadlock here
82+
report_fatal_error("waiting for future that was never dispatched");
8383
#endif
8484
}
8585
}
@@ -140,6 +140,13 @@ void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {
140140
--NumMaterializationThreads;
141141
--Outstanding;
142142

143+
bool ShouldNotify = Outstanding == 0 || llvm::any_of(
144+
WaitingFutures, [](future_base *F) { return F->ready(); });
145+
if (ShouldNotify) {
146+
WaitingFutures.clear();
147+
OutstandingCV.notify_all();
148+
}
149+
143150
if (!MaterializationTaskQueue.empty() && canRunMaterializationTaskNow()) {
144151
// If there are any materialization tasks running then steal that work.
145152
T = std::move(MaterializationTaskQueue.front());
@@ -153,8 +160,6 @@ void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) {
153160
TaskKind = Idle;
154161
++Outstanding;
155162
} else {
156-
if (Outstanding == 0)
157-
OutstandingCV.notify_all();
158163
return;
159164
}
160165
}
@@ -178,9 +183,9 @@ bool DynamicThreadPoolTaskDispatcher::canRunIdleTaskNow() {
178183
}
179184

180185
void DynamicThreadPoolTaskDispatcher::work_until(future_base &F) {
181-
// TODO: Implement efficient work_until for DynamicThreadPoolTaskDispatcher
182186
std::unique_lock<std::mutex> Lock(DispatchMutex);
183-
OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; });
187+
WaitingFutures.push_back(&F);
188+
OutstandingCV.wait(Lock, [&F]() { return F.ready(); });
184189
}
185190

186191
#endif

0 commit comments

Comments
 (0)