Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-05-29 23:12:53

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