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