1 | #pragma once |
2 | |
3 | #include <c10/core/impl/InlineEvent.h> |
4 | #include <c10/core/impl/VirtualGuardImpl.h> |
5 | |
6 | namespace c10 { |
7 | |
8 | /** |
9 | * A backend-generic movable, not copyable, not thread-safe event. |
10 | * |
11 | * The design of this event follows that of CUDA and HIP events. These events |
12 | * are recorded and waited on by streams and can be rerecorded to, |
13 | * each rerecording essentially creating a new version of the event. |
14 | * For example, if (in CPU time), stream X is asked to record E, |
15 | * stream Y waits on E, and stream X is asked to record E again, then Y will |
16 | * wait for X to finish the first call to record and not the second, because |
17 | * it's waiting on the first version of event E, not the second. |
18 | * Querying an event only returns the status of its most recent version. |
19 | * |
20 | * Backend-generic events are implemented by this class and |
21 | * impl::InlineEvent. In addition to these events there are also |
22 | * some backend-specific events, like ATen's CUDAEvent. Each of these |
23 | * classes has its own use. |
24 | * |
25 | * impl::InlineEvent<...> or a backend-specific event should be |
26 | * preferred when the backend is known at compile time and known to |
27 | * be compiled. Backend-specific events may have additional functionality. |
28 | * |
29 | * This Event should be used if a particular backend may not be available, |
30 | * or the backend required is not known at compile time. |
31 | * |
32 | * These generic events are built on top of DeviceGuardImpls, analogous |
33 | * to DeviceGuard and InlineDeviceGuard. The name "DeviceGuardImpls," |
34 | * is no longer entirely accurate, as these classes implement the |
35 | * backend-specific logic for a generic backend interface. |
36 | * |
37 | * See DeviceGuardImplInterface.h for a list of all supported flags. |
38 | */ |
39 | |
40 | struct Event final { |
41 | // Constructors |
42 | Event() = delete; |
43 | Event( |
44 | const DeviceType _device_type, |
45 | const EventFlag _flag = EventFlag::PYTORCH_DEFAULT) |
46 | : impl_{_device_type, _flag} {} |
47 | |
48 | // Copy constructor and copy assignment operator (deleted) |
49 | Event(const Event&) = delete; |
50 | Event& operator=(const Event&) = delete; |
51 | |
52 | // Move constructor and move assignment operator |
53 | Event(Event&& other) noexcept : impl_{std::move(other.impl_)} {} |
54 | Event& operator=(Event&& other) noexcept { |
55 | impl_.swap(std::move(other.impl_)); |
56 | return *this; |
57 | } |
58 | |
59 | // Destructor |
60 | ~Event() = default; |
61 | |
62 | // Getters |
63 | Device device() const noexcept { |
64 | return Device(device_type(), device_index()); |
65 | } |
66 | DeviceType device_type() const noexcept { |
67 | return impl_.device_type(); |
68 | } |
69 | DeviceIndex device_index() const noexcept { |
70 | return impl_.device_index(); |
71 | } |
72 | EventFlag flag() const noexcept { |
73 | return impl_.flag(); |
74 | } |
75 | bool was_marked_for_recording() const noexcept { |
76 | return impl_.was_marked_for_recording(); |
77 | } |
78 | |
79 | /** |
80 | * Calls record() if and only if record() has never been called for this |
81 | * event. Note: because Event is not thread-safe recordOnce() may call |
82 | * record() multiple times if called from multiple threads. |
83 | */ |
84 | void recordOnce(const Stream& stream) { |
85 | impl_.recordOnce(stream); |
86 | } |
87 | |
88 | /** |
89 | * Increments the event's version and enqueues a job with this version |
90 | * in the stream's work queue. When the stream process that job |
91 | * it nofifies all streams waiting on / blocked by that version of the |
92 | * event to continue and marks that version as recorded. |
93 | * */ |
94 | void record(const Stream& stream) { |
95 | impl_.record(stream); |
96 | } |
97 | |
98 | /** |
99 | * Does nothing if the event has not been scheduled to be recorded. |
100 | * If the event was previously enqueued to be recorded, a command |
101 | * to wait for the version of the event that exists at the time of this call |
102 | * is inserted in the stream's work queue. |
103 | * When the stream reaches this command it will stop processing |
104 | * additional commands until that version of the event is marked as recorded. |
105 | */ |
106 | void block(const Stream& stream) const { |
107 | impl_.block(stream); |
108 | } |
109 | |
110 | /** |
111 | * Returns true if (and only if) |
112 | * (1) the event has never been scheduled to be recorded |
113 | * (2) the current version is marked as recorded. |
114 | * Returns false otherwise. |
115 | */ |
116 | bool query() const { |
117 | return impl_.query(); |
118 | } |
119 | |
120 | private: |
121 | impl::InlineEvent<impl::VirtualGuardImpl> impl_; |
122 | }; |
123 | |
124 | } // namespace c10 |
125 | |