Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-30 04:10:32

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     // To be able to interact with non-Alpaka helper code that needs
0051     // to access edm::Event
0052     operator edm::Event const&() const { return constEvent_; }
0053 
0054     Device device() const { return metadata_->device(); }
0055 
0056     // Alpaka operations do not accept a temporary as an argument
0057     // TODO: Returning non-const reference here is BAD
0058     Queue& queue() const {
0059       queueUsed_ = true;
0060       return metadata_->queue();
0061     }
0062 
0063     // get()
0064 
0065     template <typename T>
0066     T const& get(edm::EDGetTokenT<T> const& token) const {
0067       return constEvent_.get(token);
0068     }
0069 
0070     template <typename T>
0071     T const& get(device::EDGetToken<T> const& token) const {
0072       auto const& deviceProduct = constEvent_.get(token.underlyingToken());
0073       if constexpr (detail::useProductDirectly<T>) {
0074         return deviceProduct;
0075       } else {
0076         // try to re-use queue from deviceProduct if our queue has not yet been used
0077         T const& product = deviceProduct.template getSynchronized<EDMetadata>(*metadata_, not queueUsed_);
0078         queueUsed_ = true;
0079         return product;
0080       }
0081     }
0082 
0083     // getHandle()
0084 
0085     template <typename T>
0086     edm::Handle<T> getHandle(edm::EDGetTokenT<T> const& token) const {
0087       return constEvent_.getHandle(token);
0088     }
0089 
0090     template <typename T>
0091     edm::Handle<T> getHandle(device::EDGetToken<T> const& token) const {
0092       auto deviceProductHandle = constEvent_.getHandle(token.underlyingToken());
0093       if constexpr (detail::useProductDirectly<T>) {
0094         return deviceProductHandle;
0095       } else {
0096         if (not deviceProductHandle) {
0097           return edm::Handle<T>(deviceProductHandle.whyFailedFactory());
0098         }
0099         // try to re-use queue from deviceProduct if our queue has not yet been used
0100         T const& product = deviceProductHandle->getSynchronized(*metadata_, not queueUsed_);
0101         queueUsed_ = true;
0102         return edm::Handle<T>(&product, deviceProductHandle.provenance());
0103       }
0104     }
0105 
0106     // emplace()
0107 
0108     template <typename T, typename... Args>
0109     edm::OrphanHandle<T> emplace(edm::EDPutTokenT<T> const& token, Args&&... args) {
0110       return event_->emplace(token, std::forward<Args>(args)...);
0111     }
0112 
0113     // TODO: what to do about the returned OrphanHandle object?
0114     // The idea for Ref-like things in this domain differs from earlier Refs anyway
0115     template <typename T, typename... Args>
0116     void emplace(device::EDPutToken<T> const& token, Args&&... args) {
0117       if constexpr (detail::useProductDirectly<T>) {
0118         event_->emplace(token.underlyingToken(), std::forward<Args>(args)...);
0119       } else {
0120         event_->emplace(token.underlyingToken(), metadata_, std::forward<Args>(args)...);
0121       }
0122     }
0123 
0124     // put()
0125 
0126     template <typename T>
0127     edm::OrphanHandle<T> put(edm::EDPutTokenT<T> const& token, std::unique_ptr<T> product) {
0128       return event_->put(token, std::move(product));
0129     }
0130 
0131     template <typename T>
0132     void put(device::EDPutToken<T> const& token, std::unique_ptr<T> product) {
0133       if constexpr (detail::useProductDirectly<T>) {
0134         event_->emplace(token.underlyingToken(), std::move(*product));
0135       } else {
0136         event_->emplace(token.underlyingToken(), metadata_, std::move(*product));
0137       }
0138     }
0139 
0140     // implementation details
0141     bool wasQueueUsed() const { return queueUsed_; }
0142 
0143   private:
0144     // Having both const and non-const here in order to serve the
0145     // clients with one device::Event class
0146     edm::Event const& constEvent_;
0147     edm::Event* event_ = nullptr;
0148 
0149     std::shared_ptr<EDMetadata> metadata_;
0150 
0151     // device::Event is not supposed to be const-thread-safe, so no
0152     // additional protection is needed.
0153     mutable bool queueUsed_ = false;
0154   };
0155 }  // namespace ALPAKA_ACCELERATOR_NAMESPACE::device
0156 
0157 #endif