DPC++ Runtime
Runtime libraries for oneAPI DPC++
scheduler.cpp
Go to the documentation of this file.
1 //===-- scheduler.cpp - SYCL Scheduler --------------------------*- 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 
12 #include <detail/queue_impl.hpp>
15 #include <detail/stream_impl.hpp>
16 
17 #include <chrono>
18 #include <cstdio>
19 #include <memory>
20 #include <mutex>
21 #include <set>
22 #include <thread>
23 #include <vector>
24 
26 namespace sycl {
27 namespace detail {
28 
29 void Scheduler::waitForRecordToFinish(MemObjRecord *Record,
30  ReadLockT &GraphReadLock) {
31 #ifdef XPTI_ENABLE_INSTRUMENTATION
32  // Will contain the list of dependencies for the Release Command
33  std::set<Command *> DepCommands;
34 #endif
35  std::vector<Command *> ToCleanUp;
36  for (Command *Cmd : Record->MReadLeaves) {
37  EnqueueResultT Res;
38  bool Enqueued = GraphProcessor::enqueueCommand(Cmd, Res, ToCleanUp);
39  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
40  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
41 #ifdef XPTI_ENABLE_INSTRUMENTATION
42  // Capture the dependencies
43  DepCommands.insert(Cmd);
44 #endif
45  GraphProcessor::waitForEvent(Cmd->getEvent(), GraphReadLock, ToCleanUp);
46  }
47  for (Command *Cmd : Record->MWriteLeaves) {
48  EnqueueResultT Res;
49  bool Enqueued = GraphProcessor::enqueueCommand(Cmd, Res, ToCleanUp);
50  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
51  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
52 #ifdef XPTI_ENABLE_INSTRUMENTATION
53  DepCommands.insert(Cmd);
54 #endif
55  GraphProcessor::waitForEvent(Cmd->getEvent(), GraphReadLock, ToCleanUp);
56  }
57  for (AllocaCommandBase *AllocaCmd : Record->MAllocaCommands) {
58  Command *ReleaseCmd = AllocaCmd->getReleaseCmd();
59  EnqueueResultT Res;
60  bool Enqueued = GraphProcessor::enqueueCommand(ReleaseCmd, Res, ToCleanUp);
61  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
62  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
63 #ifdef XPTI_ENABLE_INSTRUMENTATION
64  // Report these dependencies to the Command so these dependencies can be
65  // reported as edges
66  ReleaseCmd->resolveReleaseDependencies(DepCommands);
67 #endif
68  GraphProcessor::waitForEvent(ReleaseCmd->getEvent(), GraphReadLock,
69  ToCleanUp);
70  }
71 }
72 
73 EventImplPtr Scheduler::addCG(std::unique_ptr<detail::CG> CommandGroup,
74  QueueImplPtr Queue) {
75  EventImplPtr NewEvent = nullptr;
76  const CG::CGTYPE Type = CommandGroup->getType();
77  std::vector<Command *> AuxiliaryCmds;
78  std::vector<StreamImplPtr> Streams;
79 
80  if (Type == CG::Kernel) {
81  Streams = ((CGExecKernel *)CommandGroup.get())->getStreams();
82  // Stream's flush buffer memory is mainly initialized in stream's __init
83  // method. However, this method is not available on host device.
84  // Initializing stream's flush buffer on the host side in a separate task.
85  if (Queue->is_host()) {
86  for (const StreamImplPtr &Stream : Streams) {
87  initStream(Stream, Queue);
88  }
89  }
90  }
91 
92  {
93  WriteLockT Lock(MGraphLock, std::defer_lock);
94  acquireWriteLock(Lock);
95 
96  Command *NewCmd = nullptr;
97  switch (Type) {
98  case CG::UpdateHost:
99  NewCmd = MGraphBuilder.addCGUpdateHost(std::move(CommandGroup),
100  DefaultHostQueue, AuxiliaryCmds);
101  break;
102  case CG::CodeplayHostTask:
103  NewCmd = MGraphBuilder.addCG(std::move(CommandGroup), DefaultHostQueue,
104  AuxiliaryCmds);
105  break;
106  default:
107  NewCmd = MGraphBuilder.addCG(std::move(CommandGroup), std::move(Queue),
108  AuxiliaryCmds);
109  }
110  NewEvent = NewCmd->getEvent();
111  }
112 
113  std::vector<Command *> ToCleanUp;
114  {
115  ReadLockT Lock(MGraphLock);
116 
117  Command *NewCmd = static_cast<Command *>(NewEvent->getCommand());
118 
119  EnqueueResultT Res;
120  bool Enqueued;
121 
122  auto CleanUp = [&]() {
123  if (NewCmd && (NewCmd->MDeps.size() == 0 && NewCmd->MUsers.size() == 0)) {
124  NewEvent->setCommand(nullptr);
125  delete NewCmd;
126  }
127  };
128 
129  for (Command *Cmd : AuxiliaryCmds) {
130  Enqueued = GraphProcessor::enqueueCommand(Cmd, Res, ToCleanUp);
131  try {
132  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
133  throw runtime_error("Auxiliary enqueue process failed.",
135  } catch (...) {
136  // enqueueCommand() func and if statement above may throw an exception,
137  // so destroy required resources to avoid memory leak
138  CleanUp();
139  std::rethrow_exception(std::current_exception());
140  }
141  }
142 
143  if (NewCmd) {
144  // TODO: Check if lazy mode.
145  EnqueueResultT Res;
146  try {
147  bool Enqueued = GraphProcessor::enqueueCommand(NewCmd, Res, ToCleanUp);
148  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
149  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
150  } catch (...) {
151  // enqueueCommand() func and if statement above may throw an exception,
152  // so destroy required resources to avoid memory leak
153  CleanUp();
154  std::rethrow_exception(std::current_exception());
155  }
156 
157  // If there are no memory dependencies decouple and free the command.
158  // Though, dismiss ownership of native kernel command group as it's
159  // resources may be in use by backend and synchronization point here is
160  // at native kernel execution finish.
161  CleanUp();
162  }
163  }
164  cleanupCommands(ToCleanUp);
165 
166  for (auto StreamImplPtr : Streams) {
167  StreamImplPtr->flush();
168  }
169 
170  return NewEvent;
171 }
172 
173 EventImplPtr Scheduler::addCopyBack(Requirement *Req) {
174  std::vector<Command *> AuxiliaryCmds;
175  Command *NewCmd = nullptr;
176  {
177  WriteLockT Lock(MGraphLock, std::defer_lock);
178  acquireWriteLock(Lock);
179  NewCmd = MGraphBuilder.addCopyBack(Req, AuxiliaryCmds);
180  // Command was not creted because there were no operations with
181  // buffer.
182  if (!NewCmd)
183  return nullptr;
184  }
185 
186  std::vector<Command *> ToCleanUp;
187  try {
188  ReadLockT Lock(MGraphLock);
189  EnqueueResultT Res;
190  bool Enqueued;
191 
192  for (Command *Cmd : AuxiliaryCmds) {
193  Enqueued = GraphProcessor::enqueueCommand(Cmd, Res, ToCleanUp);
194  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
195  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
196  }
197 
198  Enqueued = GraphProcessor::enqueueCommand(NewCmd, Res, ToCleanUp);
199  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
200  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
201  } catch (...) {
202  NewCmd->getQueue()->reportAsyncException(std::current_exception());
203  }
204  EventImplPtr NewEvent = NewCmd->getEvent();
205  cleanupCommands(ToCleanUp);
206  return NewEvent;
207 }
208 
209 Scheduler &Scheduler::getInstance() {
210  return GlobalHandler::instance().getScheduler();
211 }
212 
213 void Scheduler::waitForEvent(EventImplPtr Event) {
214  ReadLockT Lock(MGraphLock);
215  // It's fine to leave the lock unlocked upon return from waitForEvent as
216  // there's no more actions to do here with graph
217  std::vector<Command *> ToCleanUp;
218  GraphProcessor::waitForEvent(std::move(Event), Lock, ToCleanUp,
219  /*LockTheLock=*/false);
220  cleanupCommands(ToCleanUp);
221 }
222 
223 static void deallocateStreams(
224  std::vector<std::shared_ptr<stream_impl>> &StreamsToDeallocate) {
225  // Deallocate buffers for stream objects of the finished commands. Iterate in
226  // reverse order because it is the order of commands execution.
227  for (auto StreamImplPtr = StreamsToDeallocate.rbegin();
228  StreamImplPtr != StreamsToDeallocate.rend(); ++StreamImplPtr)
229  detail::Scheduler::getInstance().deallocateStreamBuffers(
230  StreamImplPtr->get());
231 }
232 
233 void Scheduler::cleanupFinishedCommands(EventImplPtr FinishedEvent) {
234  // We are going to traverse a graph of finished commands. Gather stream
235  // objects from these commands if any and deallocate buffers for these stream
236  // objects, this is needed to guarantee that streamed data is printed and
237  // resources are released.
238  std::vector<std::shared_ptr<stream_impl>> StreamsToDeallocate;
239  // Similar to streams, we also collect the auxiliary resources used by the
240  // commands. Cleanup will make sure the commands do not own the resources
241  // anymore, so we just need them to survive the graph lock then they can die
242  // as they go out of scope.
243  std::vector<std::shared_ptr<const void>> AuxResourcesToDeallocate;
244  {
245  // Avoiding deadlock situation, where one thread is in the process of
246  // enqueueing (with a locked mutex) a currently blocked task that waits for
247  // another thread which is stuck at attempting cleanup.
248  WriteLockT Lock(MGraphLock, std::try_to_lock);
249  if (Lock.owns_lock()) {
250  auto FinishedCmd = static_cast<Command *>(FinishedEvent->getCommand());
251  // The command might have been cleaned up (and set to nullptr) by another
252  // thread
253  if (FinishedCmd)
254  MGraphBuilder.cleanupFinishedCommands(FinishedCmd, StreamsToDeallocate,
255  AuxResourcesToDeallocate);
256  }
257  }
258  deallocateStreams(StreamsToDeallocate);
259 }
260 
261 void Scheduler::removeMemoryObject(detail::SYCLMemObjI *MemObj) {
262  // We are going to traverse a graph of finished commands. Gather stream
263  // objects from these commands if any and deallocate buffers for these stream
264  // objects, this is needed to guarantee that streamed data is printed and
265  // resources are released.
266  std::vector<std::shared_ptr<stream_impl>> StreamsToDeallocate;
267  // Similar to streams, we also collect the auxiliary resources used by the
268  // commands. Cleanup will make sure the commands do not own the resources
269  // anymore, so we just need them to survive the graph lock then they can die
270  // as they go out of scope.
271  std::vector<std::shared_ptr<const void>> AuxResourcesToDeallocate;
272 
273  {
274  MemObjRecord *Record = nullptr;
275 
276  {
277  // This only needs a shared mutex as it only involves enqueueing and
278  // awaiting for events
279  ReadLockT Lock(MGraphLock);
280 
281  Record = MGraphBuilder.getMemObjRecord(MemObj);
282  if (!Record)
283  // No operations were performed on the mem object
284  return;
285 
286  waitForRecordToFinish(Record, Lock);
287  }
288 
289  {
290  WriteLockT Lock(MGraphLock, std::defer_lock);
291  acquireWriteLock(Lock);
292  MGraphBuilder.decrementLeafCountersForRecord(Record);
293  MGraphBuilder.cleanupCommandsForRecord(Record, StreamsToDeallocate,
294  AuxResourcesToDeallocate);
295  MGraphBuilder.removeRecordForMemObj(MemObj);
296  }
297  }
298  deallocateStreams(StreamsToDeallocate);
299 }
300 
301 EventImplPtr Scheduler::addHostAccessor(Requirement *Req) {
302  std::vector<Command *> AuxiliaryCmds;
303  EventImplPtr NewCmdEvent = nullptr;
304 
305  {
306  WriteLockT Lock(MGraphLock, std::defer_lock);
307  acquireWriteLock(Lock);
308 
309  Command *NewCmd = MGraphBuilder.addHostAccessor(Req, AuxiliaryCmds);
310  if (!NewCmd)
311  return nullptr;
312  NewCmdEvent = NewCmd->getEvent();
313  }
314 
315  std::vector<Command *> ToCleanUp;
316  {
317  ReadLockT ReadLock(MGraphLock);
318  EnqueueResultT Res;
319  bool Enqueued;
320 
321  for (Command *Cmd : AuxiliaryCmds) {
322  Enqueued = GraphProcessor::enqueueCommand(Cmd, Res, ToCleanUp);
323  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
324  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
325  }
326 
327  if (Command *NewCmd = static_cast<Command *>(NewCmdEvent->getCommand())) {
328  Enqueued = GraphProcessor::enqueueCommand(NewCmd, Res, ToCleanUp);
329  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
330  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
331  }
332  }
333 
334  cleanupCommands(ToCleanUp);
335  return NewCmdEvent;
336 }
337 
338 void Scheduler::releaseHostAccessor(Requirement *Req) {
339  Command *const BlockedCmd = Req->MBlockedCmd;
340 
341  std::vector<Command *> ToCleanUp;
342  {
343  ReadLockT Lock(MGraphLock);
344 
345  assert(BlockedCmd && "Can't find appropriate command to unblock");
346 
347  BlockedCmd->MEnqueueStatus = EnqueueResultT::SyclEnqueueReady;
348 
349  enqueueLeavesOfReqUnlocked(Req, ToCleanUp);
350  }
351  cleanupCommands(ToCleanUp);
352 }
353 
354 void Scheduler::enqueueLeavesOfReqUnlocked(const Requirement *const Req,
355  std::vector<Command *> &ToCleanUp) {
356  MemObjRecord *Record = Req->MSYCLMemObj->MRecord.get();
357  auto EnqueueLeaves = [&ToCleanUp](LeavesCollection &Leaves) {
358  for (Command *Cmd : Leaves) {
359  EnqueueResultT Res;
360  bool Enqueued = GraphProcessor::enqueueCommand(Cmd, Res, ToCleanUp);
361  if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
362  throw runtime_error("Enqueue process failed.", PI_INVALID_OPERATION);
363  }
364  };
365 
366  EnqueueLeaves(Record->MReadLeaves);
367  EnqueueLeaves(Record->MWriteLeaves);
368 }
369 
370 void Scheduler::allocateStreamBuffers(stream_impl *Impl,
371  size_t StreamBufferSize,
372  size_t FlushBufferSize) {
373  std::lock_guard<std::recursive_mutex> lock(StreamBuffersPoolMutex);
374  StreamBuffersPool.insert(
375  {Impl, new StreamBuffers(StreamBufferSize, FlushBufferSize)});
376 }
377 
378 void Scheduler::deallocateStreamBuffers(stream_impl *Impl) {
379  std::lock_guard<std::recursive_mutex> lock(StreamBuffersPoolMutex);
380  delete StreamBuffersPool[Impl];
381  StreamBuffersPool.erase(Impl);
382 }
383 
384 Scheduler::Scheduler() {
385  sycl::device HostDevice;
386  sycl::context HostContext{HostDevice};
387  DefaultHostQueue = QueueImplPtr(
388  new queue_impl(detail::getSyclObjImpl(HostDevice),
389  detail::getSyclObjImpl(HostContext), /*AsyncHandler=*/{},
390  /*PropList=*/{}));
391 }
392 
393 Scheduler::~Scheduler() {
394  // By specification there are several possible sync points: buffer
395  // destruction, wait() method of a queue or event. Stream doesn't introduce
396  // any synchronization point. It is guaranteed that stream is flushed and
397  // resources are released only if one of the listed sync points was used for
398  // the kernel. Otherwise resources for stream will not be released, issue a
399  // warning in this case.
401  std::lock_guard<std::recursive_mutex> lock(StreamBuffersPoolMutex);
402  if (!StreamBuffersPool.empty())
403  fprintf(
404  stderr,
405  "\nWARNING: Some commands may have not finished the execution and "
406  "not all resources were released. Please be sure that all kernels "
407  "have synchronization points.\n\n");
408  }
409  // There might be some commands scheduled for post enqueue cleanup that
410  // haven't been freed because of the graph mutex being locked at the time,
411  // clean them up now.
412  cleanupCommands({});
413 }
414 
415 void Scheduler::acquireWriteLock(WriteLockT &Lock) {
416 #ifdef _WIN32
417  // Avoiding deadlock situation for MSVC. std::shared_timed_mutex specification
418  // does not specify a priority for shared and exclusive accesses. It will be a
419  // deadlock in MSVC's std::shared_timed_mutex implementation, if exclusive
420  // access occurs after shared access.
421  // TODO: after switching to C++17, change std::shared_timed_mutex to
422  // std::shared_mutex and use std::lock_guard here both for Windows and Linux.
423  while (!Lock.try_lock_for(std::chrono::milliseconds(10))) {
424  // Without yield while loop acts like endless while loop and occupies the
425  // whole CPU when multiple command groups are created in multiple host
426  // threads
427  std::this_thread::yield();
428  }
429 #else
430  // It is a deadlock on UNIX in implementation of lock and lock_shared, if
431  // try_lock in the loop above will be executed, so using a single lock here
432  Lock.lock();
433 #endif // _WIN32
434 }
435 
436 MemObjRecord *Scheduler::getMemObjRecord(const Requirement *const Req) {
437  return Req->MSYCLMemObj->MRecord.get();
438 }
439 
440 void Scheduler::cleanupCommands(const std::vector<Command *> &Cmds) {
441  if (Cmds.empty())
442  return;
443  WriteLockT Lock(MGraphLock, std::try_to_lock);
444  // In order to avoid deadlocks related to blocked commands, defer cleanup if
445  // the lock wasn't acquired.
446  if (Lock.owns_lock()) {
447  for (Command *Cmd : Cmds) {
448  MGraphBuilder.cleanupCommand(Cmd);
449  }
450  std::vector<Command *> DeferredCleanupCommands;
451  {
452  std::lock_guard<std::mutex> Lock{MDeferredCleanupMutex};
453  std::swap(DeferredCleanupCommands, MDeferredCleanupCommands);
454  }
455  for (Command *Cmd : DeferredCleanupCommands) {
456  MGraphBuilder.cleanupCommand(Cmd);
457  }
458 
459  } else {
460  std::lock_guard<std::mutex> Lock{MDeferredCleanupMutex};
461  MDeferredCleanupCommands.insert(MDeferredCleanupCommands.end(),
462  Cmds.begin(), Cmds.end());
463  }
464 }
465 
466 } // namespace detail
467 } // namespace sycl
468 } // __SYCL_INLINE_NAMESPACE(cl)
cl::sycl::detail::Scheduler
DPC++ graph scheduler class.
Definition: scheduler.hpp:358
cl::sycl::detail::AllocaCommandBase::getReleaseCmd
ReleaseCommand * getReleaseCmd()
Definition: commands.hpp:369
cl::sycl::detail::stream_impl
Definition: stream_impl.hpp:25
cl::sycl::detail::Command::MUsers
std::unordered_set< Command * > MUsers
Contains list of commands that depend on the command.
Definition: commands.hpp:258
cl::sycl::detail::EnqueueResultT::MResult
ResultT MResult
Indicates the result of enqueueing.
Definition: commands.hpp:61
sycl_mem_obj_i.hpp
cl::sycl::detail::Scheduler::StreamBuffers
Stream buffers structure.
Definition: scheduler.hpp:783
cl::sycl::detail::CGExecKernel
"Execute kernel" command group class.
Definition: cg.hpp:241
PI_INVALID_OPERATION
@ PI_INVALID_OPERATION
Definition: pi.h:88
cl::sycl::detail::Command::getQueue
const QueueImplPtr & getQueue() const
Definition: commands.hpp:149
cl::sycl::detail::MemObjRecord
Memory Object Record.
Definition: scheduler.hpp:193
device_selector.hpp
cl::sycl::detail::Command::MEnqueueStatus
std::atomic< EnqueueResultT::ResultT > MEnqueueStatus
Describes the status of the command.
Definition: commands.hpp:279
cl::sycl::detail::Command::MDeps
std::vector< DepDesc > MDeps
Contains list of dependencies(edges)
Definition: commands.hpp:256
scheduler_helpers.hpp
cl::sycl::detail::pi::PI_TRACE_BASIC
@ PI_TRACE_BASIC
Definition: pi.hpp:56
cl::sycl::detail::MemObjRecord::MWriteLeaves
LeavesCollection MWriteLeaves
Definition: scheduler.hpp:206
sycl
Definition: invoke_simd.hpp:68
queue_impl.hpp
scheduler.hpp
cl::sycl::detail::MemObjRecord::MReadLeaves
LeavesCollection MReadLeaves
Definition: scheduler.hpp:203
cl::sycl::detail::EnqueueResultT
Result of command enqueueing.
Definition: commands.hpp:50
cl::sycl::detail::CG::CGTYPE
CGTYPE
Type of the command group.
Definition: cg.hpp:156
cl::sycl::detail::AccessorImplHost
Definition: accessor_impl.hpp:74
cl::sycl::device
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:35
cl::sycl::detail::StreamImplPtr
std::shared_ptr< detail::stream_impl > StreamImplPtr
Definition: commands.hpp:38
cl::sycl::detail::SYCLMemObjI::MRecord
std::shared_ptr< MemObjRecord > MRecord
Definition: sycl_mem_obj_i.hpp:74
cl::sycl::detail::EventImplPtr
std::shared_ptr< detail::event_impl > EventImplPtr
Definition: memory_manager.hpp:31
cl::sycl::detail::AllocaCommandBase
Base class for memory allocation commands.
Definition: commands.hpp:364
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
global_handler.hpp
cl::sycl::detail::AccessorImplHost::MSYCLMemObj
detail::SYCLMemObjI * MSYCLMemObj
Definition: accessor_impl.hpp:112
cl::sycl::detail::queue_impl
Definition: queue_impl.hpp:54
cl::sycl::detail::QueueImplPtr
std::shared_ptr< detail::queue_impl > QueueImplPtr
Definition: memory_manager.hpp:30
cl::sycl::detail::deallocateStreams
static void deallocateStreams(std::vector< std::shared_ptr< stream_impl >> &StreamsToDeallocate)
Definition: scheduler.cpp:223
cl::sycl::detail::Command::resolveReleaseDependencies
void resolveReleaseDependencies(std::set< Command * > &list)
Looks at all the dependencies for the release command and enables instrumentation to report these dep...
Definition: commands.cpp:781
cl::sycl::detail::Scheduler::ReadLockT
std::shared_lock< RWLockT > ReadLockT
Definition: scheduler.hpp:453
cl::sycl::detail::getSyclObjImpl
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: common.hpp:198
cl::sycl::detail::Scheduler::WriteLockT
std::unique_lock< RWLockT > WriteLockT
Definition: scheduler.hpp:454
cl::sycl::context
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:35
cl::sycl::detail::Command::getEvent
const EventImplPtr & getEvent() const
Definition: commands.hpp:153
cl::sycl::detail::MemObjRecord::MAllocaCommands
std::vector< AllocaCommandBase * > MAllocaCommands
Definition: scheduler.hpp:200
cl::sycl::detail::initStream
void initStream(StreamImplPtr Stream, QueueImplPtr Queue)
Definition: scheduler_helpers.cpp:19
cl::sycl::detail::AccessorImplHost::MBlockedCmd
Command * MBlockedCmd
Definition: accessor_impl.hpp:121
cl::sycl::detail::LeavesCollection
A wrapper for CircularBuffer class along with collection for host accessor's EmptyCommands.
Definition: leaves_collection.hpp:38
cl::sycl::detail::pi::trace
bool trace(TraceLevel level)
Definition: pi.cpp:368
cl::sycl::detail::SYCLMemObjI
Definition: sycl_mem_obj_i.hpp:28
stream_impl.hpp
__SYCL_INLINE_NAMESPACE
#define __SYCL_INLINE_NAMESPACE(X)
Definition: defines_elementary.hpp:12