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