-
Notifications
You must be signed in to change notification settings - Fork 744
/
event_impl.hpp
428 lines (354 loc) · 15.4 KB
/
event_impl.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
//==---------------- event_impl.hpp - SYCL event ---------------------------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#pragma once
#include <detail/plugin.hpp>
#include <sycl/detail/cl.h>
#include <sycl/detail/common.hpp>
#include <sycl/detail/host_profiling_info.hpp>
#include <sycl/detail/ur.hpp>
#include <sycl/info/info_desc.hpp>
#include <atomic>
#include <cassert>
#include <condition_variable>
#include <optional>
namespace sycl {
inline namespace _V1 {
namespace ext::oneapi::experimental::detail {
class graph_impl;
}
class context;
namespace detail {
class plugin;
class context_impl;
using ContextImplPtr = std::shared_ptr<sycl::detail::context_impl>;
class queue_impl;
using QueueImplPtr = std::shared_ptr<sycl::detail::queue_impl>;
class event_impl;
using EventImplPtr = std::shared_ptr<sycl::detail::event_impl>;
class event_impl {
public:
enum HostEventState : int {
HES_NotComplete = 0,
HES_Complete,
HES_Discarded
};
/// Constructs a ready SYCL event.
///
/// If the constructed SYCL event is waited on it will complete immediately.
/// Normally constructs a host event, use std::nullopt to instead instantiate
/// a device event.
event_impl(std::optional<HostEventState> State = HES_Complete)
: MIsFlushed(true), MState(State.value_or(HES_Complete)),
MIsDefaultConstructed(!State), MIsHostEvent(State) {
// Need to fail in event() constructor if there are problems with the
// ONEAPI_DEVICE_SELECTOR. Deferring may lead to conficts with noexcept
// event methods. This ::get() call uses static vars to read and parse the
// ODS env var exactly once.
SYCLConfig<ONEAPI_DEVICE_SELECTOR>::get();
}
/// Constructs an event instance from a plug-in event handle.
///
/// The SyclContext must match the plug-in context associated with the
/// ClEvent.
///
/// \param Event is a valid instance of plug-in event.
/// \param SyclContext is an instance of SYCL context.
event_impl(ur_event_handle_t Event, const context &SyclContext);
event_impl(const QueueImplPtr &Queue);
/// Waits for the event.
///
/// Self is needed in order to pass shared_ptr to Scheduler.
///
/// \param Self is a pointer to this event.
/// \param Success is an optional parameter that, when set to a non-null
/// pointer, indicates that failure is a valid outcome for this wait
/// (e.g., in case of a non-blocking read from a pipe), and the value
/// it's pointing to is then set according to the outcome.
void wait(std::shared_ptr<sycl::detail::event_impl> Self,
bool *Success = nullptr);
/// Waits for the event.
///
/// If any uncaught asynchronous errors occurred on the context that the
/// event is waiting on executions from, then call that context's
/// asynchronous error handler with those errors. Self is needed in order to
/// pass shared_ptr to Scheduler.
///
/// \param Self is a pointer to this event.
void wait_and_throw(std::shared_ptr<sycl::detail::event_impl> Self);
/// Queries this event for profiling information.
///
/// If the requested info is not available when this member function is
/// called due to incompletion of command groups associated with the event,
/// then the call to this member function will block until the requested
/// info is available. If the queue which submitted the command group this
/// event is associated with was not constructed with the
/// property::queue::enable_profiling property, a SYCL exception with
/// errc::invalid error code is thrown.
///
/// \return depends on template parameter.
template <typename Param> typename Param::return_type get_profiling_info();
/// Queries this SYCL event for information.
///
/// \return depends on the information being requested.
template <typename Param> typename Param::return_type get_info();
/// Queries this SYCL event for SYCL backend-specific information.
///
/// \return depends on information being queried.
template <typename Param>
typename Param::return_type get_backend_info() const;
~event_impl();
/// Waits for the event with respect to device type.
/// \param Success is an optional parameter that, when set to a non-null
/// pointer, indicates that failure is a valid outcome for this wait
/// (e.g., in case of a non-blocking read from a pipe), and the value
/// it's pointing to is then set according to the outcome.
void waitInternal(bool *Success = nullptr);
/// Marks this event as completed.
void setComplete();
/// Returns raw interoperability event handle. Returned reference will be
/// invalid if event_impl was destroyed.
///
/// \return a reference to an instance of plug-in event handle.
ur_event_handle_t &getHandleRef();
/// Returns raw interoperability event handle. Returned reference will be
/// invalid if event_impl was destroyed.
///
/// \return a const reference to an instance of plug-in event handle.
const ur_event_handle_t &getHandleRef() const;
/// Returns context that is associated with this event.
///
/// \return a shared pointer to a valid context_impl.
const ContextImplPtr &getContextImpl();
/// \return the Plugin associated with the context of this event.
/// Should be called when this is not a Host Event.
const PluginPtr &getPlugin();
/// Associate event with the context.
///
/// Provided UrContext inside ContextImplPtr must be associated
/// with the UrEvent object stored in this class
///
/// @param Context is a shared pointer to an instance of valid context_impl.
void setContextImpl(const ContextImplPtr &Context);
/// Clear the event state
void setStateIncomplete();
/// Returns command that is associated with the event.
///
/// Scheduler mutex must be locked in read mode when this is called.
///
/// @return a generic pointer to Command object instance.
void *getCommand() { return MCommand; }
/// Associates this event with the command.
///
/// Scheduler mutex must be locked in write mode when this is called.
///
/// @param Command is a generic pointer to Command object instance.
void setCommand(void *Command);
/// Returns host profiling information.
///
/// @return a pointer to HostProfilingInfo instance.
HostProfilingInfo *getHostProfilingInfo() { return MHostProfilingInfo.get(); }
/// Gets the native handle of the SYCL event.
///
/// \return a native handle.
ur_native_handle_t getNative();
/// Returns vector of event dependencies.
///
/// @return a reference to MPreparedDepsEvents.
std::vector<std::shared_ptr<event_impl>> &getPreparedDepsEvents() {
return MPreparedDepsEvents;
}
/// Returns vector of host event dependencies.
///
/// @return a reference to MPreparedHostDepsEvents.
std::vector<std::shared_ptr<event_impl>> &getPreparedHostDepsEvents() {
return MPreparedHostDepsEvents;
}
/// Returns vector of event_impl that this event_impl depends on.
///
/// @return a vector of "immediate" dependencies for this event_impl.
std::vector<EventImplPtr> getWaitList();
/// Performs a flush on the queue associated with this event if the user queue
/// is different and the task associated with this event hasn't been submitted
/// to the device yet.
void flushIfNeeded(const QueueImplPtr &UserQueue);
/// Cleans dependencies of this event_impl.
void cleanupDependencyEvents();
/// Cleans dependencies of this event's dependencies.
void cleanDepEventsThroughOneLevel();
/// Checks if this event is discarded by SYCL implementation.
///
/// \return true if this event is discarded.
bool isDiscarded() const { return MState == HES_Discarded; }
/// Returns worker queue for command.
///
/// @return shared_ptr to MWorkerQueue, please be aware it can be empty
/// pointer
QueueImplPtr getWorkerQueue() { return MWorkerQueue.lock(); };
/// Sets worker queue for command.
///
/// @return
void setWorkerQueue(const QueueImplPtr &WorkerQueue) {
MWorkerQueue = WorkerQueue;
};
/// Sets original queue used for submission.
///
/// @return
void setSubmittedQueue(const QueueImplPtr &SubmittedQueue) {
MSubmittedQueue = SubmittedQueue;
};
/// Indicates if this event is not associated with any command and doesn't
/// have native handle.
///
/// @return true if no associated command and no event handle.
bool isNOP() { return !MCommand && !getHandleRef(); }
/// Calling this function queries the current device timestamp and sets it as
/// submission time for the command associated with this event.
void setSubmissionTime();
/// Calling this function to capture the host timestamp to use
/// profiling base time. See MFallbackProfiling
void setHostEnqueueTime();
/// @return Submission time for command associated with this event
uint64_t getSubmissionTime();
QueueImplPtr getSubmittedQueue() const { return MSubmittedQueue.lock(); };
/// Checks if this event is complete.
///
/// \return true if this event is complete.
bool isCompleted();
/// Checks if associated command is enqueued
///
/// \return true if command passed enqueue
bool isEnqueued() const noexcept { return MIsEnqueued; };
void attachEventToComplete(const EventImplPtr &Event) {
std::lock_guard<std::mutex> Lock(MMutex);
MPostCompleteEvents.push_back(Event);
}
void attachEventToCompleteWeak(const std::weak_ptr<event_impl> &Event) {
std::lock_guard<std::mutex> Lock(MMutex);
MWeakPostCompleteEvents.push_back(Event);
}
bool isDefaultConstructed() const noexcept { return MIsDefaultConstructed; }
ContextImplPtr getContextImplPtr() {
if (MIsDefaultConstructed)
initContextIfNeeded();
return MContext;
}
// Sets a sync point which is used when this event represents an enqueue to a
// Command Buffer.
void setSyncPoint(ur_exp_command_buffer_sync_point_t SyncPoint) {
MSyncPoint = SyncPoint;
}
// Get the sync point associated with this event.
ur_exp_command_buffer_sync_point_t getSyncPoint() const { return MSyncPoint; }
void setCommandGraph(
std::shared_ptr<ext::oneapi::experimental::detail::graph_impl> Graph) {
MGraph = Graph;
}
std::shared_ptr<ext::oneapi::experimental::detail::graph_impl>
getCommandGraph() const {
return MGraph.lock();
}
void setEventFromSubmittedExecCommandBuffer(bool value) {
MEventFromSubmittedExecCommandBuffer = value;
}
bool isEventFromSubmittedExecCommandBuffer() const {
return MEventFromSubmittedExecCommandBuffer;
}
void setProfilingEnabled(bool Value) { MIsProfilingEnabled = Value; }
// Sets a command-buffer command when this event represents an enqueue to a
// Command Buffer.
void setCommandBufferCommand(ur_exp_command_buffer_command_handle_t Command) {
MCommandBufferCommand = Command;
}
ur_exp_command_buffer_command_handle_t getCommandBufferCommand() const {
return MCommandBufferCommand;
}
const std::vector<EventImplPtr> &getPostCompleteEvents() const {
return MPostCompleteEvents;
}
void setEnqueued() { MIsEnqueued = true; }
bool isHost() { return MIsHostEvent; }
void markAsProfilingTagEvent() { MProfilingTagEvent = true; }
bool isProfilingTagEvent() const noexcept { return MProfilingTagEvent; }
protected:
// When instrumentation is enabled emits trace event for event wait begin and
// returns the telemetry event generated for the wait
void *instrumentationProlog(std::string &Name, int32_t StreamID,
uint64_t &instance_id) const;
// Uses events generated by the Prolog and emits event wait done event
void instrumentationEpilog(void *TelementryEvent, const std::string &Name,
int32_t StreamID, uint64_t IId) const;
void checkProfilingPreconditions() const;
ur_event_handle_t MEvent = nullptr;
// Stores submission time of command associated with event
uint64_t MSubmitTime = 0;
uint64_t MHostBaseTime = 0;
ContextImplPtr MContext;
std::unique_ptr<HostProfilingInfo> MHostProfilingInfo;
void *MCommand = nullptr;
std::weak_ptr<queue_impl> MQueue;
bool MIsProfilingEnabled = false;
bool MFallbackProfiling = false;
std::weak_ptr<queue_impl> MWorkerQueue;
std::weak_ptr<queue_impl> MSubmittedQueue;
/// Dependency events prepared for waiting by backend.
std::vector<EventImplPtr> MPreparedDepsEvents;
std::vector<EventImplPtr> MPreparedHostDepsEvents;
std::vector<EventImplPtr> MPostCompleteEvents;
// short term WA for stream:
// MPostCompleteEvents is split into two storages now. Original storage is
// used by graph extension and represents backward links.
// MWeakPostCompleteEvents represents weak forward references (used in stream
// only). Used only for host tasks now since they do not support post enqueue
// cleanup and event == nullptr could happen only when host task is completed
// (and Command that holding reference to its event is deleted). TO DO: to
// eliminate forward references from stream implementation and remove this
// storage.
std::vector<std::weak_ptr<event_impl>> MWeakPostCompleteEvents;
/// Indicates that the task associated with this event has been submitted by
/// the queue to the device.
std::atomic<bool> MIsFlushed = false;
// State of host event. Employed only for host events and event with no
// backend's representation (e.g. alloca). Used values are listed in
// HostEventState enum.
std::atomic<int> MState;
std::mutex MMutex;
std::condition_variable cv;
/// Store the command graph associated with this event, if any.
/// This event is also be stored in the graph so a weak_ptr is used.
std::weak_ptr<ext::oneapi::experimental::detail::graph_impl> MGraph;
/// Indicates that the event results from a command graph submission.
bool MEventFromSubmittedExecCommandBuffer = false;
// If this event represents a submission to a
// ur_exp_command_buffer_sync_point_t the sync point for that submission is
// stored here.
ur_exp_command_buffer_sync_point_t MSyncPoint;
// If this event represents a submission to a
// ur_exp_command_buffer_command_handle_t the command-buffer command
// (if any) associated with that submission is stored here.
ur_exp_command_buffer_command_handle_t MCommandBufferCommand = nullptr;
// Signifies whether this event is the result of a profiling tag command. This
// allows for profiling, even if the queue does not have profiling enabled.
bool MProfilingTagEvent = false;
std::atomic_bool MIsEnqueued{false};
// Events constructed without a context will lazily use the default context
// when needed.
void initContextIfNeeded();
// Event class represents 3 different kinds of operations:
// | type | has UR event | MContext | MIsHostTask | MIsDefaultConstructed |
// | dev | true | !nullptr | false | false |
// | host | false | nullptr | true | false |
// |default| * | * | false | true |
// Default constructed event is created with empty ctor in host code, MContext
// is lazily initialized with default device context on first context query.
// MEvent is lazily created in first ur handle query.
bool MIsDefaultConstructed = false;
bool MIsHostEvent = false;
};
} // namespace detail
} // namespace _V1
} // namespace sycl