Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #ifndef HeterogeneousCore_AlpakaCore_interface_ProducerBase_h
0002 #define HeterogeneousCore_AlpakaCore_interface_ProducerBase_h
0003 
0004 #include "DataFormats/Common/interface/DeviceProduct.h"
0005 #include "FWCore/Framework/interface/FrameworkfwdMostUsed.h"
0006 #include "FWCore/Framework/interface/moduleAbilities.h"
0007 #include "FWCore/Utilities/interface/EDPutToken.h"
0008 #include "FWCore/Utilities/interface/Transition.h"
0009 #include "HeterogeneousCore/AlpakaCore/interface/alpaka/DeviceProductType.h"
0010 #include "HeterogeneousCore/AlpakaCore/interface/alpaka/EDMetadataAcquireSentry.h"
0011 #include "HeterogeneousCore/AlpakaCore/interface/EventCache.h"
0012 #include "HeterogeneousCore/AlpakaCore/interface/QueueCache.h"
0013 #include "HeterogeneousCore/AlpakaCore/interface/module_backend_config.h"
0014 #include "HeterogeneousCore/AlpakaInterface/interface/Backend.h"
0015 #include "HeterogeneousCore/AlpakaInterface/interface/CopyToHost.h"
0016 
0017 #include <memory>
0018 #include <tuple>
0019 
0020 namespace ALPAKA_ACCELERATOR_NAMESPACE {
0021   template <typename Producer, edm::Transition Tr>
0022   class ProducerBaseAdaptor;
0023 
0024   /**
0025    * The ProducerBase acts as a common base class for all Alpaka
0026    * EDProducers. The main benefit is to have a single place for the
0027    * definition of produces() functions.
0028    *
0029    * The produces() functions return a custom ProducerBaseAdaptor in
0030    * order to call the deviceProduces(). For device or asynchronous
0031    * backends the deviceProduces() registers the automatic copy to
0032    * host and a transformation from edm::DeviceProduct<T> to U, where
0033    * U is the host-equivalent of T. The transformation from T to U is
0034    * done by a specialization of cms::alpakatools::CopyToHost<T> class
0035    * template, that should be provided in the same file where T is
0036    * defined
0037    *
0038    * TODO: add "override" for labelsForToken()
0039    */
0040   template <template <typename...> class BaseT, typename... Args>
0041   class ProducerBase : public BaseT<Args..., edm::Transformer> {
0042     static_assert(not edm::CheckAbility<edm::module::Abilities::kTransformer>::kHasIt,
0043                   "ALPAKA_ACCELERATOR_NAMESPACE::ProducerBase can not be used with Transformer ability (as it is "
0044                   "used internally)");
0045     using Base = BaseT<Args..., edm::Transformer>;
0046 
0047   public:
0048     ProducerBase() : backendToken_(Base::produces("backend")) {}
0049 
0050     template <edm::Transition Tr = edm::Transition::Event>
0051     [[nodiscard]] auto produces() noexcept {
0052       return ProducerBaseAdaptor<ProducerBase, Tr>(*this);
0053     }
0054 
0055     template <edm::Transition Tr = edm::Transition::Event>
0056     [[nodiscard]] auto produces(std::string instanceName) noexcept {
0057       return ProducerBaseAdaptor<ProducerBase, Tr>(*this, std::move(instanceName));
0058     }
0059 
0060     static void prevalidate(edm::ConfigurationDescriptions& descriptions) {
0061       Base::prevalidate(descriptions);
0062       cms::alpakatools::module_backend_config(descriptions);
0063     }
0064 
0065   protected:
0066     void putBackend(edm::Event& iEvent) const {
0067       iEvent.emplace(this->backendToken_, static_cast<unsigned short>(kBackend));
0068     }
0069 
0070   private:
0071     edm::EDPutTokenT<unsigned short> const backendToken_;
0072 
0073     template <typename TProducer, edm::Transition Tr>
0074     friend class ProducerBaseAdaptor;
0075 
0076     // Host products
0077     //
0078     // intentionally not returning BranchAliasSetter
0079     // can think of it later if really needed
0080     template <typename TProduct, edm::Transition Tr>
0081     edm::EDPutTokenT<TProduct> produces(std::string instanceName) {
0082       return Base::template produces<TProduct, Tr>(std::move(instanceName));
0083     }
0084 
0085     // Device products
0086     //
0087     // intentionally not returning BranchAliasSetter
0088     // can think of it later if really needed
0089     template <typename TProduct, typename TToken, edm::Transition Tr>
0090     edm::EDPutTokenT<TToken> deviceProduces(std::string instanceName) {
0091       if constexpr (detail::useProductDirectly<TProduct>) {
0092         return Base::template produces<TToken, Tr>(std::move(instanceName));
0093       } else {
0094         edm::EDPutTokenT<TToken> token = Base::template produces<TToken, Tr>(instanceName);
0095         this->registerTransformAsync(
0096             token,
0097             [](TToken const& deviceProduct, edm::WaitingTaskWithArenaHolder holder) {
0098               auto const& device = alpaka::getDev(deviceProduct.template metadata<EDMetadata>().queue());
0099               detail::EDMetadataAcquireSentry sentry(device, std::move(holder));
0100               auto metadataPtr = sentry.metadata();
0101               constexpr bool tryReuseQueue = true;
0102               TProduct const& productOnDevice =
0103                   deviceProduct.template getSynchronized<EDMetadata>(*metadataPtr, tryReuseQueue);
0104 
0105               using CopyT = cms::alpakatools::CopyToHost<TProduct>;
0106               auto productOnHost = CopyT::copyAsync(metadataPtr->queue(), productOnDevice);
0107 
0108               // Need to keep the EDMetadata object from sentry.finish()
0109               // alive until the synchronization
0110               using TplType = std::tuple<decltype(productOnHost), std::shared_ptr<EDMetadata>>;
0111               // Wrap possibly move-only type into a copyable type
0112               return std::make_shared<TplType>(std::move(productOnHost), sentry.finish());
0113             },
0114             [](auto tplPtr) { return std::move(std::get<0>(*tplPtr)); },
0115             std::move(instanceName));
0116         return token;
0117       }
0118     }
0119   };
0120 
0121   // Adaptor class to make the type-deducing produces() calls to work
0122   template <typename TProducer, edm::Transition Tr>
0123   class ProducerBaseAdaptor {
0124   public:
0125     // for host-only products
0126     template <typename Type>
0127     edm::EDPutTokenT<Type> produces() {
0128       return producer_.template produces<Type, Tr>(label_);
0129     }
0130 
0131     // for device products
0132     template <typename TProduct, typename TToken>
0133     edm::EDPutTokenT<TToken> deviceProduces() {
0134       return producer_.template deviceProduces<TProduct, TToken, Tr>(label_);
0135     }
0136 
0137   private:
0138     // only ProducerBase is allowed to make an instance of this class
0139     friend TProducer;
0140 
0141     ProducerBaseAdaptor(TProducer& producer, std::string label) : producer_(producer), label_(std::move(label)) {}
0142     explicit ProducerBaseAdaptor(TProducer& producer) : producer_(producer) {}
0143 
0144     TProducer& producer_;
0145     std::string const label_;
0146   };
0147 }  // namespace ALPAKA_ACCELERATOR_NAMESPACE
0148 
0149 #endif