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 
17 namespace sycl {
18 namespace detail {
19 
20 static Command *getCommand(const EventImplPtr &Event) {
21  return (Command *)Event->getCommand();
22 }
23 
24 void Scheduler::GraphProcessor::waitForEvent(EventImplPtr Event,
25  ReadLockT &GraphReadLock,
26  std::vector<Command *> &ToCleanUp,
27  bool LockTheLock) {
28  Command *Cmd = getCommand(Event);
29  // Command can be nullptr if user creates cl::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 = enqueueCommand(Cmd, Res, ToCleanUp, BLOCKING);
36  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
37  // TODO: Reschedule commands.
38  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
39 
40  assert(Cmd->getEvent() == Event);
41 
42  GraphReadLock.unlock();
43  Event->waitInternal();
44 
45  if (LockTheLock)
46  GraphReadLock.lock();
47 }
48 
49 bool Scheduler::GraphProcessor::enqueueCommand(
50  Command *Cmd, EnqueueResultT &EnqueueResult,
51  std::vector<Command *> &ToCleanUp, BlockingT Blocking) {
52  if (!Cmd || Cmd->isSuccessfullyEnqueued())
53  return true;
54 
55  // Exit early if the command is blocked and the enqueue type is non-blocking
56  if (Cmd->isEnqueueBlocked() && !Blocking) {
57  EnqueueResult = EnqueueResultT(EnqueueResultT::SyclEnqueueBlocked, Cmd);
58  return false;
59  }
60 
61  // Recursively enqueue all the dependencies first and
62  // exit immediately if any of the commands cannot be enqueued.
63  for (DepDesc &Dep : Cmd->MDeps) {
64  if (!enqueueCommand(Dep.MDepCommand, EnqueueResult, ToCleanUp, Blocking))
65  return false;
66  }
67 
68  // Asynchronous host operations (amongst dependencies of an arbitrary command)
69  // are not supported (see Command::processDepEvent method). This impacts
70  // operation of host-task feature a lot with hangs and long-runs. Hence we
71  // have this workaround here.
72  // This workaround is safe as long as the only asynchronous host operation we
73  // have is a host task.
74  // This may iterate over some of dependencies in Cmd->MDeps. Though, the
75  // enqueue operation is idempotent and the second call will result in no-op.
76  // TODO remove the workaround when proper fix for host-task dispatching is
77  // implemented.
78  for (const EventImplPtr &Event : Cmd->getPreparedHostDepsEvents()) {
79  if (Command *DepCmd = static_cast<Command *>(Event->getCommand()))
80  if (!enqueueCommand(DepCmd, EnqueueResult, ToCleanUp, Blocking))
81  return false;
82  }
83 
84  // Only graph read lock is to be held here.
85  // Enqueue process of a command may last quite a time. Having graph locked can
86  // introduce some thread starving (i.e. when the other thread attempts to
87  // acquire write lock and add a command to graph). Releasing read lock without
88  // other safety measures isn't an option here as the other thread could go
89  // into graph cleanup process (due to some event complete) and remove some
90  // dependencies from dependencies of the user of this command.
91  // An example: command A depends on commands B and C. This thread wants to
92  // enqueue A. Hence, it needs to enqueue B and C. So this thread gets into
93  // dependency list and starts enqueueing B right away. The other thread waits
94  // on completion of C and starts cleanup process. This thread is still in the
95  // middle of enqueue of B. The other thread modifies dependency list of A by
96  // removing C out of it. Iterators become invalid.
97  return Cmd->enqueue(EnqueueResult, Blocking, ToCleanUp);
98 }
99 
100 } // namespace detail
101 } // namespace sycl
102 } // __SYCL_INLINE_NAMESPACE(cl)
event_impl.hpp
cl::sycl::detail::EnqueueResultT::MResult
ResultT MResult
Indicates the result of enqueueing.
Definition: commands.hpp:61
cl::sycl::detail::BlockingT
BlockingT
Definition: commands.hpp:47
PI_INVALID_OPERATION
@ PI_INVALID_OPERATION
Definition: pi.h:88
cl::sycl::detail::Command::MDeps
std::vector< DepDesc > MDeps
Contains list of dependencies(edges)
Definition: commands.hpp:256
cl::sycl::detail::Command::isSuccessfullyEnqueued
bool isSuccessfullyEnqueued() const
Definition: commands.hpp:141
cl::sycl::detail::Command::enqueue
virtual bool enqueue(EnqueueResultT &EnqueueResult, BlockingT Blocking, std::vector< Command * > &ToCleanUp)
Checks if the command is enqueued, and calls enqueueImp.
Definition: commands.cpp:695
sycl
Definition: invoke_simd.hpp:68
queue_impl.hpp
scheduler.hpp
cl::sycl::detail::getCommand
static Command * getCommand(const EventImplPtr &Event)
Definition: graph_processor.cpp:20
cl::sycl::detail::EnqueueResultT
Result of command enqueueing.
Definition: commands.hpp:50
cl::sycl::detail::DepDesc
Dependency between two commands.
Definition: commands.hpp:69
cl::sycl::detail::EventImplPtr
std::shared_ptr< detail::event_impl > EventImplPtr
Definition: memory_manager.hpp:31
cl::sycl::detail::Command
The Command class represents some action that needs to be performed on one or more memory objects.
Definition: commands.hpp:95
cl
We provide new interfaces for matrix muliply in this patch:
Definition: access.hpp:13
cl::sycl::detail::Command::getPreparedHostDepsEvents
const std::vector< EventImplPtr > & getPreparedHostDepsEvents() const
Definition: commands.hpp:251
cl::sycl::detail::Scheduler::ReadLockT
std::shared_lock< RWLockT > ReadLockT
Definition: scheduler.hpp:453
cl::sycl::detail::BLOCKING
@ BLOCKING
Definition: commands.hpp:47
cl::sycl::detail::DepDesc::MDepCommand
Command * MDepCommand
The actual dependency command.
Definition: commands.hpp:80
cl::sycl::detail::Command::getEvent
const EventImplPtr & getEvent() const
Definition: commands.hpp:153
cl::sycl::detail::Command::isEnqueueBlocked
bool isEnqueueBlocked() const
Definition: commands.hpp:145
__SYCL_INLINE_NAMESPACE
#define __SYCL_INLINE_NAMESPACE(X)
Definition: defines_elementary.hpp:12