Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-02-02 16:37:49

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