Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-06-07 02:29:40

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 
0012 namespace ALPAKA_ACCELERATOR_NAMESPACE {
0013   /**
0014    * The EDMetadata class provides the exact synchronization
0015    * mechanisms for Event data products for backends with asynchronous
0016    * Queue. These include
0017    * - adding a notification for edm::WaitingTaskWithArenaHolder
0018    * - recording an Event
0019    * - synchronizing an Event data product and a consuming EDModule
0020    *
0021    * For synchronous backends the EDMetadata acts as an owner of the
0022    * Queue object, as no further synchronization is needed.
0023    *
0024    * EDMetadata is used as the Metadata class for
0025    * edm::DeviceProduct<T>, and is an implementation detail (not
0026    * visible to user code).
0027    *
0028    * TODO: What to do with device-synchronous backends? The data
0029    * product needs to be wrapped into the edm::DeviceProduct, but the
0030    * EDMetadata class used there does not need anything except "dummy"
0031    * implementation of synchronize(). The question is clearly
0032    * solvable, so maybe leave it to the time we would actually need
0033    * one?
0034    */
0035 
0036 #ifdef ALPAKA_ACC_CPU_B_SEQ_T_SEQ_ENABLED
0037   // Host backends with a synchronous queue
0038 
0039   class EDMetadata {
0040   public:
0041     EDMetadata(std::shared_ptr<Queue> queue) : queue_(std::move(queue)) {}
0042 
0043     Device device() const { return alpaka::getDev(*queue_); }
0044 
0045     // Alpaka operations do not accept a temporary as an argument
0046     // TODO: Returning non-const reference here is BAD
0047     Queue& queue() const { return *queue_; }
0048 
0049     void recordEvent() {}
0050     void discardEvent() {}
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     void discardEvent() { event_.reset(); }
0077 
0078     /**
0079      * Synchronizes 'consumer' metadata wrt. 'this' in the event product
0080      */
0081     void synchronize(EDMetadata& consumer, bool tryReuseQueue) const;
0082 
0083   private:
0084     /**
0085      * Returns a shared_ptr to the Queue if it can be reused, or a
0086      * null shared_ptr if not
0087      */
0088     std::shared_ptr<Queue> tryReuseQueue_() const;
0089 
0090     std::shared_ptr<Queue> queue_;
0091     std::shared_ptr<Event> event_;
0092     // This flag tells whether the Queue may be reused by a
0093     // consumer or not. The goal is to have a "chain" of modules to
0094     // queue their work to the same queue.
0095     mutable std::atomic<bool> mayReuseQueue_ = true;
0096     // Cache to potentially reduce alpaka::wait() calls
0097     mutable std::atomic<bool> eventComplete_ = false;
0098   };
0099 #endif
0100 }  // namespace ALPAKA_ACCELERATOR_NAMESPACE
0101 
0102 #endif