DPC++ Runtime
Runtime libraries for oneAPI DPC++
graph_processor.cpp
Go to the documentation of this file.
1 //===-- graph_processor.cpp - SYCL Graph Processor --------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <detail/event_impl.hpp>
10 #include <detail/queue_impl.hpp>
12 
13 #include <memory>
14 #include <vector>
15 
16 namespace sycl {
17 inline namespace _V1 {
18 namespace detail {
19 
20 static Command *getCommand(const EventImplPtr &Event) {
21  return (Command *)Event->getCommand();
22 }
23 
25  ReadLockT &GraphReadLock,
26  std::vector<Command *> &ToCleanUp,
27  bool LockTheLock, bool *Success) {
28  Command *Cmd = getCommand(Event);
29  // Command can be nullptr if user creates sycl::event explicitly or the
30  // event has been waited on by another thread
31  if (!Cmd)
32  return;
33 
34  EnqueueResultT Res;
35  bool Enqueued =
36  enqueueCommand(Cmd, GraphReadLock, Res, ToCleanUp, Cmd, BLOCKING);
37  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
38  // TODO: Reschedule commands.
39  throw runtime_error("Enqueue process failed.", PI_ERROR_INVALID_OPERATION);
40 
41  assert(Cmd->getEvent() == Event);
42 
43  GraphReadLock.unlock();
44  Event->waitInternal(Success);
45 
46  if (LockTheLock)
47  GraphReadLock.lock();
48 }
49 
51  EnqueueResultT &EnqueueResult,
52  Command *RootCommand,
53  BlockingT Blocking) {
54  if (Cmd == RootCommand || Blocking)
55  return true;
56  {
57  std::lock_guard<std::mutex> Guard(Cmd->MBlockedUsersMutex);
58  if (Cmd->isBlocking()) {
59  const EventImplPtr &RootCmdEvent = RootCommand->getEvent();
60  Cmd->addBlockedUserUnique(RootCmdEvent);
62 
63  // Blocked command will be enqueued asynchronously from submission so we
64  // need to keep current root code location to report failure properly.
65  RootCommand->copySubmissionCodeLocation();
66  return false;
67  }
68  }
69  return true;
70 }
71 
73  Command *Cmd, ReadLockT &GraphReadLock, EnqueueResultT &EnqueueResult,
74  std::vector<Command *> &ToCleanUp, Command *RootCommand,
75  BlockingT Blocking) {
76  if (!Cmd)
77  return true;
78  if (Cmd->isSuccessfullyEnqueued())
79  return handleBlockingCmd(Cmd, EnqueueResult, RootCommand, Blocking);
80 
81  if (KernelFusionCommand *FusionCmd = isPartOfActiveFusion(Cmd)) {
82  // The fusion is still in-flight, but some other event/command depending
83  // on one of the kernels in the fusion list has triggered it to be
84  // enqueued. To avoid circular dependencies and deadlocks, we will need to
85  // cancel fusion here and enqueue the kernels in the fusion list right
86  // away.
87  printFusionWarning("Aborting fusion because synchronization with one of "
88  "the kernels in the fusion list was requested");
89  // We need to unlock the read lock, as cancelFusion in the scheduler will
90  // acquire a write lock to alter the graph.
91  GraphReadLock.unlock();
92  // Cancel fusion will take care of enqueueing all the kernels.
93  Scheduler::getInstance().cancelFusion(FusionCmd->getQueue());
94  // Lock the read lock again.
95  GraphReadLock.lock();
96  // The fusion (placeholder) command should have been enqueued by
97  // cancelFusion.
98  if (FusionCmd->isSuccessfullyEnqueued()) {
99  return true;
100  }
101  }
102 
103  // Exit early if the command is blocked and the enqueue type is non-blocking
104  if (Cmd->isEnqueueBlocked() && !Blocking) {
106  return false;
107  }
108 
109  // Recursively enqueue all the implicit + explicit backend level dependencies
110  // first and exit immediately if any of the commands cannot be enqueued.
111  for (const EventImplPtr &Event : Cmd->getPreparedDepsEvents()) {
112  if (Command *DepCmd = static_cast<Command *>(Event->getCommand()))
113  if (!enqueueCommand(DepCmd, GraphReadLock, EnqueueResult, ToCleanUp,
114  RootCommand, Blocking))
115  return false;
116  }
117 
118  // Recursively enqueue all the implicit + explicit host dependencies and
119  // exit immediately if any of the commands cannot be enqueued.
120  // Host task execution is asynchronous. In current implementation enqueue for
121  // this command will wait till host task completion by waitInternal call on
122  // MHostDepsEvents. TO FIX: implement enqueue of blocked commands on host task
123  // completion stage and eliminate this event waiting in enqueue.
124  for (const EventImplPtr &Event : Cmd->getPreparedHostDepsEvents()) {
125  if (Command *DepCmd = static_cast<Command *>(Event->getCommand()))
126  if (!enqueueCommand(DepCmd, GraphReadLock, EnqueueResult, ToCleanUp,
127  RootCommand, Blocking))
128  return false;
129  }
130 
131  // Only graph read lock is to be held here.
132  // Enqueue process of a command may last quite a time. Having graph locked can
133  // introduce some thread starving (i.e. when the other thread attempts to
134  // acquire write lock and add a command to graph). Releasing read lock without
135  // other safety measures isn't an option here as the other thread could go
136  // into graph cleanup process (due to some event complete) and remove some
137  // dependencies from dependencies of the user of this command.
138  // An example: command A depends on commands B and C. This thread wants to
139  // enqueue A. Hence, it needs to enqueue B and C. So this thread gets into
140  // dependency list and starts enqueueing B right away. The other thread waits
141  // on completion of C and starts cleanup process. This thread is still in the
142  // middle of enqueue of B. The other thread modifies dependency list of A by
143  // removing C out of it. Iterators become invalid.
144  bool Result = Cmd->enqueue(EnqueueResult, Blocking, ToCleanUp);
145  if (Result)
146  Result = handleBlockingCmd(Cmd, EnqueueResult, RootCommand, Blocking);
147  return Result;
148 }
149 
150 } // namespace detail
151 } // namespace _V1
152 } // namespace sycl
The Command class represents some action that needs to be performed on one or more memory objects.
Definition: commands.hpp:107
bool isSuccessfullyEnqueued() const
Definition: commands.hpp:158
const std::vector< EventImplPtr > & getPreparedDepsEvents() const
Definition: commands.hpp:300
const std::vector< EventImplPtr > & getPreparedHostDepsEvents() const
Definition: commands.hpp:296
virtual bool enqueue(EnqueueResultT &EnqueueResult, BlockingT Blocking, std::vector< Command * > &ToCleanUp)
Checks if the command is enqueued, and calls enqueueImp.
Definition: commands.cpp:818
const EventImplPtr & getEvent() const
Definition: commands.hpp:180
bool isEnqueueBlocked() const
Definition: commands.hpp:164
void addBlockedUserUnique(const EventImplPtr &NewUser)
Definition: commands.hpp:171
The KernelFusionCommand is placed in the execution graph together with the individual kernels of the ...
Definition: commands.hpp:724
static void waitForEvent(const EventImplPtr &Event, ReadLockT &GraphReadLock, std::vector< Command * > &ToCleanUp, bool LockTheLock=true, bool *Success=nullptr)
Waits for the command, associated with Event passed, is completed.
static bool enqueueCommand(Command *Cmd, ReadLockT &GraphReadLock, EnqueueResultT &EnqueueResult, std::vector< Command * > &ToCleanUp, Command *RootCommand, BlockingT Blocking=NON_BLOCKING)
Enqueues the command and all its dependencies.
static bool handleBlockingCmd(Command *Cmd, EnqueueResultT &EnqueueResult, Command *RootCommand, BlockingT Blocking)
Check if successfully enqueued command is expected to be blocking for the dependent commands before i...
void cancelFusion(QueueImplPtr Queue)
Definition: scheduler.cpp:621
std::shared_lock< RWLockT > ReadLockT
Definition: scheduler.hpp:496
static Scheduler & getInstance()
Definition: scheduler.cpp:261
static Command * getCommand(const EventImplPtr &Event)
std::shared_ptr< event_impl > EventImplPtr
Definition: cg.hpp:43
Definition: access.hpp:18
Result of command enqueueing.
Definition: commands.hpp:62
ResultT MResult
Indicates the result of enqueueing.
Definition: commands.hpp:73