Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:50:22

0001 #ifndef HeterogeneousCore_AlpakaCore_interface_alpaka_EDMetadata_h
0002 #define HeterogeneousCore_AlpakaCore_interface_alpaka_EDMetadata_h
0003 
0004 #include <atomic>
0005 #include <memory>
0006 
0007 #include <alpaka/alpaka.hpp>
0008 
0009 #include "FWCore/Concurrency/interface/WaitingTaskWithArenaHolder.h"
0010 #include "HeterogeneousCore/AlpakaInterface/interface/config.h"
0011 #include "HeterogeneousCore/AlpakaInterface/interface/HostOnlyTask.h"
0012 
0013 namespace ALPAKA_ACCELERATOR_NAMESPACE {
0014   /**
0015    * The EDMetadata class provides the exact synchronization
0016    * mechanisms for Event data products for backends with asynchronous
0017    * Queue. These include
0018    * - adding a notification for edm::WaitingTaskWithArenaHolder
0019    * - recording an Event
0020    * - synchronizing an Event data product and a consuming EDModule
0021    *
0022    * For synchronous backends the EDMetadata acts as an owner of the
0023    * Queue object, as no further synchronization is needed.
0024    *
0025    * EDMetadata is used as the Metadata class for
0026    * edm::DeviceProduct<T>, and is an implementation detail (not
0027    * visible to user code).
0028    *
0029    * TODO: What to do with device-synchronous backends? The data
0030    * product needs to be wrapped into the edm::DeviceProduct, but the
0031    * EDMetadata class used there does not need anything except "dummy"
0032    * implementation of synchronize(). The question is clearly
0033    * solvable, so maybe leave it to the time we would actually need
0034    * one?
0035    */
0036 
0037 #ifdef ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
0038   // Host backends with a synchronous queue
0039 
0040   class EDMetadata {
0041   public:
0042     EDMetadata(std::shared_ptr<Queue> queue) : queue_(std::move(queue)) {}
0043 
0044     Device device() const { return alpaka::getDev(*queue_); }
0045 
0046     // Alpaka operations do not accept a temporary as an argument
0047     // TODO: Returning non-const reference here is BAD
0048     Queue& queue() const { return *queue_; }
0049 
0050     void recordEvent() {}
0051 
0052   private:
0053     std::shared_ptr<Queue> queue_;
0054   };
0055 
0056   // TODO: else if device backends with a synchronous queue
0057 
0058 #else
0059   // All backends with an asynchronous queue
0060 
0061   class EDMetadata {
0062   public:
0063     EDMetadata(std::shared_ptr<Queue> queue, std::shared_ptr<Event> event)
0064         : queue_(std::move(queue)), event_(std::move(event)) {}
0065     ~EDMetadata();
0066 
0067     Device device() const { return alpaka::getDev(*queue_); }
0068 
0069     // Alpaka operations do not accept a temporary as an argument
0070     // TODO: Returning non-const reference here is BAD
0071     Queue& queue() const { return *queue_; }
0072 
0073     void enqueueCallback(edm::WaitingTaskWithArenaHolder holder);
0074 
0075     void recordEvent() { alpaka::enqueue(*queue_, *event_); }
0076 
0077     /**
0078      * Synchronizes 'consumer' metadata wrt. 'this' in the event product
0079      */
0080     void synchronize(EDMetadata& consumer, bool tryReuseQueue) const;
0081 
0082   private:
0083     /**
0084      * Returns a shared_ptr to the Queue if it can be reused, or a
0085      * null shared_ptr if not
0086      */
0087     std::shared_ptr<Queue> tryReuseQueue_() const;
0088 
0089     std::shared_ptr<Queue> queue_;
0090     std::shared_ptr<Event> event_;
0091     // This flag tells whether the Queue may be reused by a
0092     // consumer or not. The goal is to have a "chain" of modules to
0093     // queue their work to the same queue.
0094     mutable std::atomic<bool> mayReuseQueue_ = true;
0095   };
0096 #endif
0097 }  // namespace ALPAKA_ACCELERATOR_NAMESPACE
0098 
0099 #endif