DPC++ Runtime
Runtime libraries for oneAPI DPC++
event_impl.cpp
Go to the documentation of this file.
1 //==---------------- event_impl.cpp - SYCL event ---------------------------==//
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/event_info.hpp>
11 #include <detail/plugin.hpp>
12 #include <detail/queue_impl.hpp>
14 #include <sycl/context.hpp>
15 #include <sycl/device_selector.hpp>
16 
17 #include "detail/config.hpp"
18 
19 #include <chrono>
20 
21 #ifdef XPTI_ENABLE_INSTRUMENTATION
22 #include "xpti/xpti_trace_framework.hpp"
23 #include <atomic>
24 #include <detail/xpti_registry.hpp>
25 #include <sstream>
26 #endif
27 
28 namespace sycl {
29 inline namespace _V1 {
30 namespace detail {
31 #ifdef XPTI_ENABLE_INSTRUMENTATION
32 extern xpti::trace_event_data_t *GSYCLGraphEvent;
33 #endif
34 
35 // If we do not yet have a context, use the default one.
38  return;
39 
40  const device SyclDevice;
41  this->setContextImpl(
43 }
44 
46  try {
47  if (MEvent)
48  getPlugin()->call(urEventRelease, MEvent);
49  } catch (std::exception &e) {
50  __SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~event_impl", e);
51  }
52 }
53 
54 void event_impl::waitInternal(bool *Success) {
55  if (!MIsHostEvent && MEvent) {
56  // Wait for the native event
57  ur_result_t Err = getPlugin()->call_nocheck(urEventWait, 1, &MEvent);
58  // TODO drop the UR_RESULT_ERROR_UKNOWN from here (this was waiting for
59  // https://github.com/oneapi-src/unified-runtime/issues/1459 which is now
60  // closed).
61  if (Success != nullptr &&
62  (Err == UR_RESULT_ERROR_UNKNOWN ||
63  Err == UR_RESULT_ERROR_IN_EVENT_LIST_EXEC_STATUS))
64  *Success = false;
65  else {
66  getPlugin()->checkUrResult(Err);
67  if (Success != nullptr)
68  *Success = true;
69  }
70  } else if (MState == HES_Discarded) {
71  // Waiting for the discarded event is invalid
72  throw sycl::exception(
74  "waitInternal method cannot be used for a discarded event.");
75  } else if (MState != HES_Complete) {
76  // Wait for the host event
77  std::unique_lock<std::mutex> lock(MMutex);
78  cv.wait(lock, [this] { return MState == HES_Complete; });
79  }
80 
81  // Wait for connected events(e.g. streams prints)
82  for (const EventImplPtr &Event : MPostCompleteEvents)
83  Event->wait(Event);
84 }
85 
87  if (MIsHostEvent || !MEvent) {
88  {
89  std::unique_lock<std::mutex> lock(MMutex);
90 #ifndef NDEBUG
91  int Expected = HES_NotComplete;
92  int Desired = HES_Complete;
93 
94  bool Succeeded = MState.compare_exchange_strong(Expected, Desired);
95 
96  assert(Succeeded && "Unexpected state of event");
97 #else
98  MState.store(static_cast<int>(HES_Complete));
99 #endif
100  }
101  cv.notify_all();
102  return;
103  }
104 
105  assert(false && "setComplete is not supported for non-host event");
106 }
107 
108 static uint64_t inline getTimestamp() {
109  auto Timestamp = std::chrono::high_resolution_clock::now().time_since_epoch();
110  return std::chrono::duration_cast<std::chrono::nanoseconds>(Timestamp)
111  .count();
112 }
113 
114 const ur_event_handle_t &event_impl::getHandleRef() const { return MEvent; }
115 ur_event_handle_t &event_impl::getHandleRef() { return MEvent; }
116 
119  return MContext;
120 }
121 
124  return MContext->getPlugin();
125 }
126 
128 
130  MIsHostEvent = Context == nullptr;
131  MContext = Context;
132 }
133 
134 event_impl::event_impl(ur_event_handle_t Event, const context &SyclContext)
135  : MEvent(Event), MContext(detail::getSyclObjImpl(SyclContext)),
136  MIsFlushed(true), MState(HES_Complete) {
137 
138  ur_context_handle_t TempContext;
139  getPlugin()->call(urEventGetInfo, MEvent, UR_EVENT_INFO_CONTEXT,
140  sizeof(ur_context_handle_t), &TempContext, nullptr);
141 
142  if (MContext->getHandleRef() != TempContext) {
143  throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
144  "The syclContext must match the OpenCL context "
145  "associated with the clEvent. " +
146  codeToString(UR_RESULT_ERROR_INVALID_CONTEXT));
147  }
148 }
149 
151  : MQueue{Queue}, MIsProfilingEnabled{!Queue || Queue->MIsProfilingEnabled},
152  MFallbackProfiling{MIsProfilingEnabled && Queue &&
153  Queue->isProfilingFallback()} {
154  if (Queue)
155  this->setContextImpl(Queue->getContextImplPtr());
156  else {
157  MState.store(HES_NotComplete);
159  if (!MHostProfilingInfo)
160  throw sycl::exception(
161  sycl::make_error_code(sycl::errc::runtime),
162  "Out of host memory " +
163  codeToString(UR_RESULT_ERROR_OUT_OF_HOST_MEMORY));
164  return;
165  }
166  MState.store(HES_Complete);
167 }
168 
169 void *event_impl::instrumentationProlog(std::string &Name, int32_t StreamID,
170  uint64_t &IId) const {
171  void *TraceEvent = nullptr;
172 #ifdef XPTI_ENABLE_INSTRUMENTATION
173  constexpr uint16_t NotificationTraceType = xpti::trace_wait_begin;
174  if (!xptiCheckTraceEnabled(StreamID, NotificationTraceType))
175  return TraceEvent;
176  // Use a thread-safe counter to get a unique instance ID for the wait() on the
177  // event
178  static std::atomic<uint64_t> InstanceID = {1};
179  xpti::trace_event_data_t *WaitEvent = nullptr;
180 
181  // Create a string with the event address so it
182  // can be associated with other debug data
183  xpti::utils::StringHelper SH;
184  Name = SH.nameWithAddress<ur_event_handle_t>("event.wait", MEvent);
185 
186  // We can emit the wait associated with the graph if the
187  // event does not have a command object or associated with
188  // the command object, if it exists
189  if (MCommand) {
190  Command *Cmd = (Command *)MCommand;
191  WaitEvent = Cmd->MTraceEvent ? static_cast<xpti_td *>(Cmd->MTraceEvent)
192  : GSYCLGraphEvent;
193  } else
194  WaitEvent = GSYCLGraphEvent;
195 
196  // Record the current instance ID for use by Epilog
197  IId = InstanceID++;
198  xptiNotifySubscribers(StreamID, NotificationTraceType, nullptr, WaitEvent,
199  IId, static_cast<const void *>(Name.c_str()));
200  TraceEvent = (void *)WaitEvent;
201 #endif
202  return TraceEvent;
203 }
204 
205 void event_impl::instrumentationEpilog(void *TelemetryEvent,
206  const std::string &Name,
207  int32_t StreamID, uint64_t IId) const {
208 #ifdef XPTI_ENABLE_INSTRUMENTATION
209  constexpr uint16_t NotificationTraceType = xpti::trace_wait_end;
210  if (!(xptiCheckTraceEnabled(StreamID, NotificationTraceType) &&
211  TelemetryEvent))
212  return;
213  // Close the wait() scope
214  xpti::trace_event_data_t *TraceEvent =
215  (xpti::trace_event_data_t *)TelemetryEvent;
216  xptiNotifySubscribers(StreamID, NotificationTraceType, nullptr, TraceEvent,
217  IId, static_cast<const void *>(Name.c_str()));
218 #endif
219 }
220 
221 void event_impl::wait(std::shared_ptr<sycl::detail::event_impl> Self,
222  bool *Success) {
223  if (MState == HES_Discarded)
225  "wait method cannot be used for a discarded event.");
226 
227  if (!MGraph.expired()) {
229  "wait method cannot be used for an event associated "
230  "with a command graph.");
231  }
232 
233 #ifdef XPTI_ENABLE_INSTRUMENTATION
234  void *TelemetryEvent = nullptr;
235  uint64_t IId = 0;
236  std::string Name;
237  int32_t StreamID = xptiRegisterStream(SYCL_STREAM_NAME);
238  TelemetryEvent = instrumentationProlog(Name, StreamID, IId);
239 #endif
240 
241  if (MEvent)
242  // presence of MEvent means the command has been enqueued, so no need to
243  // go via the slow path event waiting in the scheduler
244  waitInternal(Success);
245  else if (MCommand)
247 
248 #ifdef XPTI_ENABLE_INSTRUMENTATION
249  instrumentationEpilog(TelemetryEvent, Name, StreamID, IId);
250 #endif
251 }
252 
254  std::shared_ptr<sycl::detail::event_impl> Self) {
255  wait(Self);
256 
257  if (QueueImplPtr SubmittedQueue = MSubmittedQueue.lock())
258  SubmittedQueue->throw_asynchronous();
259 }
260 
262  std::weak_ptr<queue_impl> EmptyPtr;
263 
264  if (!MIsHostEvent && !EmptyPtr.owner_before(MQueue) &&
265  !MQueue.owner_before(EmptyPtr)) {
266  throw sycl::exception(make_error_code(sycl::errc::invalid),
267  "Profiling information is unavailable as the event "
268  "has no associated queue.");
269  }
271  throw sycl::exception(
272  make_error_code(sycl::errc::invalid),
273  "Profiling information is unavailable as the queue associated with "
274  "the event does not have the 'enable_profiling' property.");
275  }
276 }
277 
278 template <>
279 uint64_t
280 event_impl::get_profiling_info<info::event_profiling::command_submit>() {
281  checkProfilingPreconditions();
282  if (isProfilingTagEvent()) {
283  // For profiling tag events we rely on the submission time reported as
284  // the start time has undefined behavior.
285  return get_event_profiling_info<info::event_profiling::command_submit>(
286  this->getHandleRef(), this->getPlugin());
287  }
288 
289  // The delay between the submission and the actual start of a CommandBuffer
290  // can be short. Consequently, the submission time, which is based on
291  // an estimated clock and not on the real device clock, may be ahead of the
292  // start time, which is based on the actual device clock.
293  // MSubmitTime is set in a critical performance path.
294  // Force reading the device clock when setting MSubmitTime may deteriorate
295  // the performance.
296  // Since submit time is an estimated time, we implement this little hack
297  // that allows all profiled time to be meaningful.
298  // (Note that the observed time deviation between the estimated clock and
299  // the real device clock is typically less than 0.5ms. The approximation we
300  // made by forcing the re-sync of submit time to start time is less than
301  // 0.5ms. These timing values were obtained empirically using an integrated
302  // Intel GPU).
303  if (MEventFromSubmittedExecCommandBuffer && !MIsHostEvent && MEvent) {
304  uint64_t StartTime =
305  get_event_profiling_info<info::event_profiling::command_start>(
306  this->getHandleRef(), this->getPlugin());
307  if (StartTime < MSubmitTime)
308  MSubmitTime = StartTime;
309  }
310  return MSubmitTime;
311 }
312 
313 template <>
314 uint64_t
315 event_impl::get_profiling_info<info::event_profiling::command_start>() {
316  checkProfilingPreconditions();
317  if (!MIsHostEvent) {
318  if (MEvent) {
319  auto StartTime =
320  get_event_profiling_info<info::event_profiling::command_start>(
321  this->getHandleRef(), this->getPlugin());
322  if (!MFallbackProfiling) {
323  return StartTime;
324  } else {
325  auto DeviceBaseTime =
326  get_event_profiling_info<info::event_profiling::command_submit>(
327  this->getHandleRef(), this->getPlugin());
328  return MHostBaseTime - DeviceBaseTime + StartTime;
329  }
330  }
331  return 0;
332  }
333  if (!MHostProfilingInfo)
334  throw sycl::exception(
335  sycl::make_error_code(sycl::errc::invalid),
336  "Profiling info is not available. " +
337  codeToString(UR_RESULT_ERROR_PROFILING_INFO_NOT_AVAILABLE));
338  return MHostProfilingInfo->getStartTime();
339 }
340 
341 template <>
342 uint64_t event_impl::get_profiling_info<info::event_profiling::command_end>() {
343  checkProfilingPreconditions();
344  if (!MIsHostEvent) {
345  if (MEvent) {
346  auto EndTime =
347  get_event_profiling_info<info::event_profiling::command_end>(
348  this->getHandleRef(), this->getPlugin());
349  if (!MFallbackProfiling) {
350  return EndTime;
351  } else {
352  auto DeviceBaseTime =
353  get_event_profiling_info<info::event_profiling::command_submit>(
354  this->getHandleRef(), this->getPlugin());
355  return MHostBaseTime - DeviceBaseTime + EndTime;
356  }
357  }
358  return 0;
359  }
360  if (!MHostProfilingInfo)
361  throw sycl::exception(
362  sycl::make_error_code(sycl::errc::invalid),
363  "Profiling info is not available. " +
364  codeToString(UR_RESULT_ERROR_PROFILING_INFO_NOT_AVAILABLE));
365  return MHostProfilingInfo->getEndTime();
366 }
367 
368 template <> uint32_t event_impl::get_info<info::event::reference_count>() {
369  if (!MIsHostEvent && MEvent) {
370  return get_event_info<info::event::reference_count>(this->getHandleRef(),
371  this->getPlugin());
372  }
373  return 0;
374 }
375 
376 template <>
378 event_impl::get_info<info::event::command_execution_status>() {
379  if (MState == HES_Discarded)
381 
382  if (!MIsHostEvent) {
383  // Command is enqueued and UrEvent is ready
384  if (MEvent)
385  return get_event_info<info::event::command_execution_status>(
386  this->getHandleRef(), this->getPlugin());
387  // Command is blocked and not enqueued, UrEvent is not assigned yet
388  else if (MCommand)
389  return sycl::info::event_command_status::submitted;
390  }
391 
392  return MIsHostEvent && MState.load() != HES_Complete
393  ? sycl::info::event_command_status::submitted
395 }
396 
397 template <>
398 typename info::platform::version::return_type
399 event_impl::get_backend_info<info::platform::version>() const {
400  if (!MContext) {
401  return "Context not initialized, no backend info available";
402  }
403  if (MContext->getBackend() != backend::opencl) {
405  "the info::platform::version info descriptor can "
406  "only be queried with an OpenCL backend");
407  }
408  if (QueueImplPtr Queue = MQueue.lock()) {
409  return Queue->getDeviceImplPtr()
410  ->get_platform()
411  .get_info<info::platform::version>();
412  }
413  // If the queue has been released, no platform will be associated
414  // so return empty string.
415  return "";
416 }
417 
418 template <>
419 typename info::device::version::return_type
420 event_impl::get_backend_info<info::device::version>() const {
421  if (!MContext) {
422  return "Context not initialized, no backend info available";
423  }
424  if (MContext->getBackend() != backend::opencl) {
426  "the info::device::version info descriptor can only "
427  "be queried with an OpenCL backend");
428  }
429  if (QueueImplPtr Queue = MQueue.lock()) {
430  return Queue->getDeviceImplPtr()->get_info<info::device::version>();
431  }
432  return ""; // If the queue has been released, no device will be associated so
433  // return empty string
434 }
435 
436 template <>
437 typename info::device::backend_version::return_type
438 event_impl::get_backend_info<info::device::backend_version>() const {
439  if (!MContext) {
440  return "Context not initialized, no backend info available";
441  }
442  if (MContext->getBackend() != backend::ext_oneapi_level_zero) {
444  "the info::device::backend_version info descriptor "
445  "can only be queried with a Level Zero backend");
446  }
447  return "";
448  // Currently The Level Zero backend does not define the value of this
449  // information descriptor and implementations are encouraged to return the
450  // empty string as per specification.
451 }
452 
453 void HostProfilingInfo::start() { StartTime = getTimestamp(); }
454 
455 void HostProfilingInfo::end() { EndTime = getTimestamp(); }
456 
457 ur_native_handle_t event_impl::getNative() {
458  if (isHost())
459  return {};
461 
462  auto Plugin = getPlugin();
463  if (MIsDefaultConstructed && !MEvent) {
464  auto TempContext = MContext.get()->getHandleRef();
465  ur_event_native_properties_t NativeProperties{};
466  Plugin->call(urEventCreateWithNativeHandle, 0, TempContext,
467  &NativeProperties, &MEvent);
468  }
469  if (MContext->getBackend() == backend::opencl)
470  Plugin->call(urEventRetain, getHandleRef());
471  ur_native_handle_t Handle;
472  Plugin->call(urEventGetNativeHandle, getHandleRef(), &Handle);
473  return Handle;
474 }
475 
476 std::vector<EventImplPtr> event_impl::getWaitList() {
477  if (MState == HES_Discarded)
478  throw sycl::exception(
480  "get_wait_list() cannot be used for a discarded event.");
481 
482  std::lock_guard<std::mutex> Lock(MMutex);
483 
484  std::vector<EventImplPtr> Result;
485  Result.reserve(MPreparedDepsEvents.size() + MPreparedHostDepsEvents.size());
486  Result.insert(Result.end(), MPreparedDepsEvents.begin(),
487  MPreparedDepsEvents.end());
488  Result.insert(Result.end(), MPreparedHostDepsEvents.begin(),
490 
491  return Result;
492 }
493 
494 void event_impl::flushIfNeeded(const QueueImplPtr &UserQueue) {
495  // Some events might not have a native handle underneath even at this point,
496  // e.g. those produced by memset with 0 size (no UR call is made).
497  if (MIsFlushed || !MEvent)
498  return;
499 
500  QueueImplPtr Queue = MQueue.lock();
501  // If the queue has been released, all of the commands have already been
502  // implicitly flushed by urQueueRelease.
503  if (!Queue) {
504  MIsFlushed = true;
505  return;
506  }
507  if (Queue == UserQueue)
508  return;
509 
510  // Check if the task for this event has already been submitted.
511  ur_event_status_t Status = UR_EVENT_STATUS_QUEUED;
512  getPlugin()->call(urEventGetInfo, MEvent,
513  UR_EVENT_INFO_COMMAND_EXECUTION_STATUS,
514  sizeof(ur_event_status_t), &Status, nullptr);
515  if (Status == UR_EVENT_STATUS_QUEUED) {
516  getPlugin()->call(urQueueFlush, Queue->getHandleRef());
517  }
518  MIsFlushed = true;
519 }
520 
522  std::lock_guard<std::mutex> Lock(MMutex);
523  MPreparedDepsEvents.clear();
524  MPreparedHostDepsEvents.clear();
525 }
526 
528  std::lock_guard<std::mutex> Lock(MMutex);
529  for (auto &Event : MPreparedDepsEvents) {
530  Event->cleanupDependencyEvents();
531  }
532  for (auto &Event : MPreparedHostDepsEvents) {
533  Event->cleanupDependencyEvents();
534  }
535 }
536 
539  return;
540  if (!MFallbackProfiling) {
541  if (QueueImplPtr Queue = MQueue.lock()) {
542  try {
543  MSubmitTime = Queue->getDeviceImplPtr()->getCurrentDeviceTime();
544  } catch (sycl::exception &e) {
545  if (e.code() == sycl::errc::feature_not_supported)
546  throw sycl::exception(
548  std::string("Unable to get command group submission time: ") +
549  e.what());
550  std::rethrow_exception(std::current_exception());
551  }
552  } else {
553  // Returning host time
554  using namespace std::chrono;
555  MSubmitTime =
556  duration_cast<nanoseconds>(steady_clock::now().time_since_epoch())
557  .count();
558  }
559  } else {
560  // Capture the host timestamp for a return value of function call
561  // <info::event_profiling::command_submit>. See MFallbackProfiling
563  }
564 }
565 
568  return;
569  // Capture a host timestamp to use normalize profiling time in
570  // <command_start> and <command_end>. See MFallbackProfiling
572 }
573 
575 
577  return get_info<info::event::command_execution_status>() ==
579 }
580 
581 void event_impl::setCommand(void *Cmd) {
582  MCommand = Cmd;
583  auto TypedCommand = static_cast<Command *>(Cmd);
584  if (TypedCommand)
585  MIsHostEvent = TypedCommand->getWorkerContext() == nullptr;
586 }
587 
588 } // namespace detail
589 } // namespace _V1
590 } // namespace sycl
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:50
The Command class represents some action that needs to be performed on one or more memory objects.
Definition: commands.hpp:109
void * MTraceEvent
The event for node_create and task_begin.
Definition: commands.hpp:350
Profiling info for the host execution.
void end()
Measures event's end time.
Definition: event_impl.cpp:455
void start()
Measures event's start time.
Definition: event_impl.cpp:453
void waitForEvent(const EventImplPtr &Event, bool *Success=nullptr)
Waits for the event.
Definition: scheduler.cpp:256
static Scheduler & getInstance()
Definition: scheduler.cpp:248
void checkProfilingPreconditions() const
Definition: event_impl.cpp:261
std::vector< EventImplPtr > getWaitList()
Returns vector of event_impl that this event_impl depends on.
Definition: event_impl.cpp:476
void * instrumentationProlog(std::string &Name, int32_t StreamID, uint64_t &instance_id) const
Definition: event_impl.cpp:169
std::vector< EventImplPtr > MPostCompleteEvents
Definition: event_impl.hpp:360
void cleanDepEventsThroughOneLevel()
Cleans dependencies of this event's dependencies.
Definition: event_impl.cpp:527
void waitInternal(bool *Success=nullptr)
Waits for the event with respect to device type.
Definition: event_impl.cpp:54
void setComplete()
Marks this event as completed.
Definition: event_impl.cpp:86
std::unique_ptr< HostProfilingInfo > MHostProfilingInfo
Definition: event_impl.hpp:347
void setContextImpl(const ContextImplPtr &Context)
Associate event with the context.
Definition: event_impl.cpp:129
void setHostEnqueueTime()
Calling this function to capture the host timestamp to use profiling base time.
Definition: event_impl.cpp:566
std::weak_ptr< ext::oneapi::experimental::detail::graph_impl > MGraph
Store the command graph associated with this event, if any.
Definition: event_impl.hpp:376
const ContextImplPtr & getContextImpl()
Returns context that is associated with this event.
Definition: event_impl.cpp:117
void flushIfNeeded(const QueueImplPtr &UserQueue)
Performs a flush on the queue associated with this event if the user queue is different and the task ...
Definition: event_impl.cpp:494
std::weak_ptr< queue_impl > MSubmittedQueue
Definition: event_impl.hpp:354
std::atomic< int > MState
Definition: event_impl.hpp:369
void instrumentationEpilog(void *TelementryEvent, const std::string &Name, int32_t StreamID, uint64_t IId) const
Definition: event_impl.cpp:205
event_impl(std::optional< HostEventState > State=HES_Complete)
Constructs a ready SYCL event.
Definition: event_impl.hpp:51
bool isCompleted()
Checks if this event is complete.
Definition: event_impl.cpp:576
ur_native_handle_t getNative()
Gets the native handle of the SYCL event.
Definition: event_impl.cpp:457
ur_event_handle_t & getHandleRef()
Returns raw interoperability event handle.
Definition: event_impl.cpp:115
std::vector< EventImplPtr > MPreparedHostDepsEvents
Definition: event_impl.hpp:358
void wait(std::shared_ptr< sycl::detail::event_impl > Self, bool *Success=nullptr)
Waits for the event.
Definition: event_impl.cpp:221
void setStateIncomplete()
Clear the event state.
Definition: event_impl.cpp:127
std::condition_variable cv
Definition: event_impl.hpp:372
std::vector< EventImplPtr > MPreparedDepsEvents
Dependency events prepared for waiting by backend.
Definition: event_impl.hpp:357
void setSubmissionTime()
Calling this function queries the current device timestamp and sets it as submission time for the com...
Definition: event_impl.cpp:537
void cleanupDependencyEvents()
Cleans dependencies of this event_impl.
Definition: event_impl.cpp:521
void wait_and_throw(std::shared_ptr< sycl::detail::event_impl > Self)
Waits for the event.
Definition: event_impl.cpp:253
void setCommand(void *Command)
Associates this event with the command.
Definition: event_impl.cpp:581
const PluginPtr & getPlugin()
Definition: event_impl.cpp:122
std::atomic< bool > MIsFlushed
Indicates that the task associated with this event has been submitted by the queue to the device.
Definition: event_impl.hpp:364
std::weak_ptr< queue_impl > MQueue
Definition: event_impl.hpp:349
static ContextImplPtr getDefaultOrNew(const DeviceImplPtr &Device)
Definition: queue_impl.hpp:75
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
const char * what() const noexcept final
Definition: exception.cpp:49
const std::error_code & code() const noexcept
Definition: exception.cpp:43
#define __SYCL_REPORT_EXCEPTION_TO_STREAM(str, e)
Definition: common.hpp:367
decltype(Obj::impl) const & getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:31
std::string codeToString(int32_t code)
Definition: exception.hpp:57
constexpr const char * SYCL_STREAM_NAME
static uint64_t getTimestamp()
Definition: event_impl.cpp:108
std::shared_ptr< sycl::detail::context_impl > ContextImplPtr
Definition: event_impl.hpp:32
static const PluginPtr & getPlugin(backend Backend)
Definition: backend.cpp:32
std::shared_ptr< event_impl > EventImplPtr
Definition: handler.hpp:183
std::shared_ptr< plugin > PluginPtr
Definition: ur.hpp:60
std::shared_ptr< sycl::detail::queue_impl > QueueImplPtr
Definition: helpers.hpp:45
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:65
Definition: access.hpp:18