Back to home page

Project CMSSW displayed by LXR

 
 

    


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

0001 #ifndef HeterogeneousCore_AlpakaCore_interface_alpaka_ESProducer_h
0002 #define HeterogeneousCore_AlpakaCore_interface_alpaka_ESProducer_h
0003 
0004 #include "FWCore/Framework/interface/ESProducer.h"
0005 #include "FWCore/Framework/interface/produce_helpers.h"
0006 #include "HeterogeneousCore/AlpakaCore/interface/module_backend_config.h"
0007 #include "HeterogeneousCore/AlpakaCore/interface/alpaka/ESDeviceProduct.h"
0008 #include "HeterogeneousCore/AlpakaCore/interface/alpaka/Record.h"
0009 #include "HeterogeneousCore/AlpakaInterface/interface/devices.h"
0010 
0011 #include <functional>
0012 
0013 namespace ALPAKA_ACCELERATOR_NAMESPACE {
0014   /**
0015    * The ESProducer is a base class for modules producing data into
0016    * the host memory space and/or the device memory space defined by
0017    * the backend (i.e. ALPAKA_ACCELERATOR_NAMESPACE). The interface
0018    * looks similar to the normal edm::ESProducer.
0019    *
0020    * When producing a host product, the produce function should have
0021    * the the usual Record argument. For producing a device product,
0022    * the produce funtion should have device::Record<Record> argument.
0023    */
0024   class ESProducer : public edm::ESProducer {
0025     using Base = edm::ESProducer;
0026 
0027   public:
0028     static void prevalidate(edm::ConfigurationDescriptions& descriptions) {
0029       Base::prevalidate(descriptions);
0030       cms::alpakatools::module_backend_config(descriptions);
0031     }
0032 
0033   protected:
0034     template <typename T>
0035     auto setWhatProduced(T* iThis, edm::es::Label const& label = {}) {
0036       return setWhatProduced(iThis, &T::produce, label);
0037     }
0038 
0039     template <typename T, typename TReturn, typename TRecord>
0040     auto setWhatProduced(T* iThis, TReturn (T ::*iMethod)(TRecord const&), edm::es::Label const& label = {}) {
0041       return Base::setWhatProduced(iThis, iMethod, label);
0042     }
0043 
0044     template <typename T, typename TReturn, typename TRecord>
0045     auto setWhatProduced(T* iThis,
0046                          TReturn (T ::*iMethod)(device::Record<TRecord> const&),
0047                          edm::es::Label const& label = {}) {
0048       using TProduct = typename edm::eventsetup::produce::smart_pointer_traits<TReturn>::type;
0049       using ProductType = ESDeviceProduct<TProduct>;
0050       using ReturnType = detail::ESDeviceProductWithStorage<TProduct, TReturn>;
0051       return Base::setWhatProduced(
0052           [iThis, iMethod](TRecord const& record) -> std::unique_ptr<ProductType> {
0053             // TODO: move the multiple device support into EventSetup system itself
0054             auto const& devices = cms::alpakatools::devices<Platform>();
0055             std::vector<std::shared_ptr<Queue>> queues;
0056             queues.reserve(devices.size());
0057             auto ret = std::make_unique<ReturnType>(devices.size());
0058             bool allnull = true;
0059             bool anynull = false;
0060             for (auto const& dev : devices) {
0061               device::Record<TRecord> const deviceRecord(record, dev);
0062               auto prod = std::invoke(iMethod, iThis, deviceRecord);
0063               if (prod) {
0064                 allnull = false;
0065                 ret->insert(dev, std::move(prod));
0066               } else {
0067                 anynull = true;
0068               }
0069               queues.push_back(deviceRecord.queuePtr());
0070             }
0071             // TODO: to be changed asynchronous later
0072             for (auto& queuePtr : queues) {
0073               alpaka::wait(*queuePtr);
0074             }
0075             if (allnull) {
0076               return nullptr;
0077             } else if (anynull) {
0078               // TODO: throwing an exception if the iMethod() returns
0079               // null for some of th devices of one backend is
0080               // suboptimal. On the other hand, in the near term
0081               // multiple devices per backend is useful only for
0082               // private tests (not production), and the plan is to
0083               // make the EventSetup system itself aware of multiple
0084               // devies (or memory spaces). I hope this exception
0085               // would be good-enough until we get there.
0086               ESProducer::throwSomeNullException();
0087             }
0088             return ret;
0089           },
0090           label);
0091     }
0092 
0093   private:
0094     static void throwSomeNullException();
0095   };
0096 }  // namespace ALPAKA_ACCELERATOR_NAMESPACE
0097 
0098 #endif