Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-11-24 00:02:23

0001 #ifndef HeterogeneousCore_AlpakaCore_interface_alpaka_Event_h
0002 #define HeterogeneousCore_AlpakaCore_interface_alpaka_Event_h
0003 
0004 #include "DataFormats/Common/interface/Handle.h"
0005 #include "FWCore/Framework/interface/Event.h"
0006 #include "FWCore/Utilities/interface/EDGetToken.h"
0007 #include "FWCore/Utilities/interface/EDPutToken.h"
0008 #include "HeterogeneousCore/AlpakaCore/interface/alpaka/DeviceProductType.h"
0009 #include "HeterogeneousCore/AlpakaCore/interface/alpaka/EDGetToken.h"
0010 #include "HeterogeneousCore/AlpakaCore/interface/alpaka/EDMetadata.h"
0011 #include "HeterogeneousCore/AlpakaCore/interface/alpaka/EDPutToken.h"
0012 #include "HeterogeneousCore/AlpakaInterface/interface/config.h"
0013 
0014 namespace ALPAKA_ACCELERATOR_NAMESPACE::device {
0015   /**
0016    * The device::Event mimics edm::Event, and provides access to
0017    * EDProducts in the host memory space, and in the device memory
0018    * space defined by the backend (i.e. ALPAKA_ACCELERATOR_NAMESPACE).
0019    * The device::Event also gives access to the Queue object the
0020    * EDModule code should use to queue all the device operations.
0021    *
0022    * Access to device memory space products is synchronized properly.
0023    * For backends with synchronous Queue this is trivial. For
0024    * asynchronous Queue, either the Queue of the EDModule is taken
0025    * from the first data product, or a wait is inserted into the
0026    * EDModule's Queue to wait for the product's asynchronous
0027    * production to finish.
0028    *
0029    * Note that not full interface of edm::Event is replicated here. If
0030    * something important is missing, that can be added.
0031    */
0032   class Event {
0033   public:
0034     // To be called in produce()
0035     explicit Event(edm::Event& ev, std::shared_ptr<EDMetadata> metadata)
0036         : constEvent_(ev), event_(&ev), metadata_(std::move(metadata)) {}
0037 
0038     // To be called in acquire()
0039     explicit Event(edm::Event const& ev, std::shared_ptr<EDMetadata> metadata)
0040         : constEvent_(ev), metadata_(std::move(metadata)) {}
0041 
0042     Event(Event const&) = delete;
0043     Event& operator=(Event const&) = delete;
0044     Event(Event&&) = delete;
0045     Event& operator=(Event&&) = delete;
0046 
0047     auto streamID() const { return constEvent_.streamID(); }
0048     auto id() const { return constEvent_.id(); }
0049 
0050     Device device() const { return metadata_->device(); }
0051 
0052     // Alpaka operations do not accept a temporary as an argument
0053     // TODO: Returning non-const reference here is BAD
0054     Queue& queue() const {
0055       queueUsed_ = true;
0056       return metadata_->queue();
0057     }
0058 
0059     // get()
0060 
0061     template <typename T>
0062     T const& get(edm::EDGetTokenT<T> const& token) const {
0063       return constEvent_.get(token);
0064     }
0065 
0066     template <typename T>
0067     T const& get(device::EDGetToken<T> const& token) const {
0068       auto const& deviceProduct = constEvent_.get(token.underlyingToken());
0069       if constexpr (std::is_same_v<typename detail::DeviceProductType<T>::type, T>) {
0070         return deviceProduct;
0071       } else {
0072         // try to re-use queue from deviceProduct if our queue has not yet been used
0073         T const& product = deviceProduct.template getSynchronized<EDMetadata>(*metadata_, not queueUsed_);
0074         queueUsed_ = true;
0075         return product;
0076       }
0077     }
0078 
0079     // getHandle()
0080 
0081     template <typename T>
0082     edm::Handle<T> getHandle(edm::EDGetTokenT<T> const& token) const {
0083       return constEvent_.getHandle(token);
0084     }
0085 
0086     template <typename T>
0087     edm::Handle<T> getHandle(device::EDGetToken<T> const& token) const {
0088       auto deviceProductHandle = constEvent_.getHandle(token.underlyingToken());
0089       if constexpr (std::is_same_v<typename detail::DeviceProductType<T>::type, T>) {
0090         return deviceProductHandle;
0091       } else {
0092         if (not deviceProductHandle) {
0093           return edm::Handle<T>(deviceProductHandle.whyFailedFactory());
0094         }
0095         // try to re-use queue from deviceProduct if our queue has not yet been used
0096         T const& product = deviceProductHandle->getSynchronized(*metadata_, not queueUsed_);
0097         queueUsed_ = true;
0098         return edm::Handle<T>(&product, deviceProductHandle.provenance());
0099       }
0100     }
0101 
0102     // emplace()
0103 
0104     template <typename T, typename... Args>
0105     edm::OrphanHandle<T> emplace(edm::EDPutTokenT<T> const& token, Args&&... args) {
0106       return event_->emplace(token, std::forward<Args>(args)...);
0107     }
0108 
0109     // TODO: what to do about the returned OrphanHandle object?
0110     // The idea for Ref-like things in this domain differs from earlier Refs anyway
0111     template <typename T, typename... Args>
0112     void emplace(device::EDPutToken<T> const& token, Args&&... args) {
0113       if constexpr (std::is_same_v<typename detail::DeviceProductType<T>::type, T>) {
0114         event_->emplace(token.underlyingToken(), std::forward<Args>(args)...);
0115       } else {
0116         event_->emplace(token.underlyingToken(), metadata_, std::forward<Args>(args)...);
0117       }
0118     }
0119 
0120     // put()
0121 
0122     template <typename T>
0123     edm::OrphanHandle<T> put(edm::EDPutTokenT<T> const& token, std::unique_ptr<T> product) {
0124       return event_->put(token, std::move(product));
0125     }
0126 
0127     template <typename T>
0128     void put(device::EDPutToken<T> const& token, std::unique_ptr<T> product) {
0129       if constexpr (std::is_same_v<typename detail::DeviceProductType<T>::type, T>) {
0130         event_->emplace(token.underlyingToken(), std::move(*product));
0131       } else {
0132         event_->emplace(token.underlyingToken(), metadata_, std::move(*product));
0133       }
0134     }
0135 
0136   private:
0137     // Having both const and non-const here in order to serve the
0138     // clients with one device::Event class
0139     edm::Event const& constEvent_;
0140     edm::Event* event_ = nullptr;
0141 
0142     std::shared_ptr<EDMetadata> metadata_;
0143     // device::Event is not supposed to be const-thread-safe, so no
0144     // additional protection is needed.
0145     mutable bool queueUsed_ = false;
0146   };
0147 }  // namespace ALPAKA_ACCELERATOR_NAMESPACE::device
0148 
0149 #endif