Skip to content

Commit

Permalink
Merge pull request #41564 from makortel/alpakaBackendProduct
Browse files Browse the repository at this point in the history
Make every Alpaka EDProducer to store an unsigned short int for the backend
  • Loading branch information
cmsbuild authored Oct 23, 2023
2 parents e2d2171 + a8b3c73 commit bca672b
Show file tree
Hide file tree
Showing 16 changed files with 147 additions and 11 deletions.
10 changes: 10 additions & 0 deletions HeterogeneousCore/AlpakaCore/interface/alpaka/ProducerBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "HeterogeneousCore/AlpakaCore/interface/EventCache.h"
#include "HeterogeneousCore/AlpakaCore/interface/QueueCache.h"
#include "HeterogeneousCore/AlpakaCore/interface/module_backend_config.h"
#include "HeterogeneousCore/AlpakaInterface/interface/Backend.h"
#include "HeterogeneousCore/AlpakaInterface/interface/CopyToHost.h"

#include <memory>
Expand Down Expand Up @@ -44,6 +45,8 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE {
using Base = BaseT<Args..., edm::Transformer>;

public:
ProducerBase() : backendToken_(Base::produces("backend")) {}

template <edm::Transition Tr = edm::Transition::Event>
[[nodiscard]] auto produces() noexcept {
return ProducerBaseAdaptor<ProducerBase, Tr>(*this);
Expand All @@ -59,7 +62,14 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE {
cms::alpakatools::module_backend_config(descriptions);
}

protected:
void putBackend(edm::Event& iEvent) const {
iEvent.emplace(this->backendToken_, static_cast<unsigned short>(kBackend));
}

private:
edm::EDPutTokenT<unsigned short> const backendToken_;

template <typename TProducer, edm::Transition Tr>
friend class ProducerBaseAdaptor;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE {
device::Event ev(iEvent, sentry.metadata());
device::EventSetup const es(iSetup, ev.device());
produce(sid, ev, es);
this->putBackend(iEvent);
sentry.finish();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE {
device::Event ev(iEvent, sentry.metadata());
device::EventSetup const es(iSetup, ev.device());
produce(ev, es);
this->putBackend(iEvent);
sentry.finish();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE {
device::Event ev(iEvent, sentry.metadata());
device::EventSetup const es(iSetup, ev.device());
produce(ev, es);
this->putBackend(iEvent);
sentry.finish();
}

Expand Down
5 changes: 4 additions & 1 deletion HeterogeneousCore/AlpakaInterface/BuildFile.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<use name="alpaka"/>
<use name="boost_header"/>
<use name="FWCore/Utilities" source_only="1"/>
<use name="FWCore/Utilities"/>
<export>
<lib name="1"/>
</export>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef HeterogeneousCore_AlpakaInterface_interface_AllocatorConfig_h
#define HeterogeneousCore_AlpakaInterface_interface_AllocatorConfig_h

#include <cstddef>
#include <limits>

namespace cms::alpakatools {
Expand Down
14 changes: 14 additions & 0 deletions HeterogeneousCore/AlpakaInterface/interface/Backend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef HeterogeneousCore_AlpakaInterface_interface_Backend_h
#define HeterogeneousCore_AlpakaInterface_interface_Backend_h

#include <string_view>

namespace cms::alpakatools {
// Enumeration whose value EDModules can put in the event
enum class Backend : unsigned short { SerialSync = 0, CudaAsync = 1, ROCmAsync = 2, TbbAsync = 3, size };

Backend toBackend(std::string_view name);
std::string_view toString(Backend backend);
} // namespace cms::alpakatools

#endif
6 changes: 6 additions & 0 deletions HeterogeneousCore/AlpakaInterface/interface/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <alpaka/alpaka.hpp>

#include "HeterogeneousCore/AlpakaInterface/interface/Backend.h"
#include "FWCore/Utilities/interface/stringize.h"

namespace alpaka_common {
Expand Down Expand Up @@ -159,6 +160,11 @@ namespace alpaka_tbb_async {
// define a null-terminated string containing the backend-specific identifier
#define ALPAKA_TYPE_ALIAS_NAME(TYPE) EDM_STRINGIZE(ALPAKA_TYPE_ALIAS(TYPE))

// Ensure the enumeration names are consistent with type suffix
namespace ALPAKA_ACCELERATOR_NAMESPACE {
inline constexpr const cms::alpakatools::Backend kBackend = cms::alpakatools::Backend::ALPAKA_TYPE_SUFFIX;
}

#endif // ALPAKA_ACCELERATOR_NAMESPACE

#endif // HeterogeneousCore_AlpakaInterface_interface_config_h
2 changes: 2 additions & 0 deletions HeterogeneousCore/AlpakaInterface/interface/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <cassert>

#include <alpaka/alpaka.hpp>

namespace cms::alpakatools {

namespace detail {
Expand Down
34 changes: 34 additions & 0 deletions HeterogeneousCore/AlpakaInterface/src/Backend.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "FWCore/Utilities/interface/Exception.h"
#include "HeterogeneousCore/AlpakaInterface/interface/Backend.h"

#include <algorithm>
#include <array>

namespace {
constexpr const std::array<std::string_view, static_cast<short>(cms::alpakatools::Backend::size)> backendNames = {
{"SerialSync", "CudaAsync", "ROCmAsync", "TbbAsync"}};
}

namespace cms::alpakatools {
Backend toBackend(std::string_view name) {
auto found = std::find(backendNames.begin(), backendNames.end(), name);
if (found == backendNames.end()) {
cms::Exception ex("EnumNotFound");
ex << "Invalid backend name '" << name << "'";
ex.addContext("Calling cms::alpakatools::toBackend()");
throw ex;
}
return static_cast<Backend>(std::distance(backendNames.begin(), found));
}

std::string_view toString(Backend backend) {
auto val = static_cast<unsigned short>(backend);
if (val >= static_cast<unsigned short>(Backend::size)) {
cms::Exception ex("InvalidEnumValue");
ex << "Invalid backend enum value " << val;
ex.addContext("Calling cms::alpakatools::toString()");
throw ex;
}
return backendNames[val];
}
} // namespace cms::alpakatools
5 changes: 5 additions & 0 deletions HeterogeneousCore/AlpakaInterface/test/BuildFile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@
<use name="HeterogeneousCore/AlpakaInterface"/>
<flags ALPAKA_BACKENDS="1"/>
</bin>

<bin name="alpakaTestBackend" file="testBackend.cc">
<use name="catch2"/>
<use name="HeterogeneousCore/AlpakaInterface"/>
</bin>
30 changes: 30 additions & 0 deletions HeterogeneousCore/AlpakaInterface/test/testBackend.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#define CATCH_CONFIG_MAIN
#include <catch.hpp>

#include "HeterogeneousCore/AlpakaInterface/interface/Backend.h"

TEST_CASE("Test cms::alpakatools::toBackend", "cms::alpakatools::Backend") {
SECTION("Valid string") {
REQUIRE(cms::alpakatools::toBackend("SerialSync") == cms::alpakatools::Backend::SerialSync);
REQUIRE(cms::alpakatools::toBackend("CudaAsync") == cms::alpakatools::Backend::CudaAsync);
REQUIRE(cms::alpakatools::toBackend("ROCmAsync") == cms::alpakatools::Backend::ROCmAsync);
REQUIRE(cms::alpakatools::toBackend("TbbAsync") == cms::alpakatools::Backend::TbbAsync);
}
SECTION("Invalid string") {
REQUIRE_THROWS_WITH(cms::alpakatools::toBackend("Nonexistent"),
Catch::Contains("EnumNotFound") and Catch::Contains("Invalid backend name"));
}
}

TEST_CASE("Test cms::alpakatools::toString", "cms::alpakatools::Backend") {
SECTION("Valid enum") {
REQUIRE(cms::alpakatools::toString(cms::alpakatools::Backend::SerialSync) == "SerialSync");
REQUIRE(cms::alpakatools::toString(cms::alpakatools::Backend::CudaAsync) == "CudaAsync");
REQUIRE(cms::alpakatools::toString(cms::alpakatools::Backend::ROCmAsync) == "ROCmAsync");
REQUIRE(cms::alpakatools::toString(cms::alpakatools::Backend::TbbAsync) == "TbbAsync");
}
SECTION("Invalid enum") {
REQUIRE_THROWS_WITH(cms::alpakatools::toString(cms::alpakatools::Backend::size),
Catch::Contains("InvalidEnumValue") and Catch::Contains("Invalid backend enum value"));
}
}
1 change: 1 addition & 0 deletions HeterogeneousCore/AlpakaTest/plugins/BuildFile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<use name="FWCore/ParameterSet"/>
<use name="FWCore/Utilities"/>
<use name="HeterogeneousCore/AlpakaTest"/>
<use name="HeterogeneousCore/AlpakaInterface"/>
<flags EDM_PLUGIN="1"/>
</library>

Expand Down
21 changes: 20 additions & 1 deletion HeterogeneousCore/AlpakaTest/plugins/TestAlpakaAnalyzer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ class TestAlpakaAnalyzer : public edm::global::EDAnalyzer<> {
TestAlpakaAnalyzer(edm::ParameterSet const& config)
: source_{config.getParameter<edm::InputTag>("source")},
token_{consumes(source_)},
expectSize_(config.getParameter<int>("expectSize")) {}
expectSize_{config.getParameter<int>("expectSize")} {
if (std::string const& eb = config.getParameter<std::string>("expectBackend"); not eb.empty()) {
expectBackend_ = cms::alpakatools::toBackend(eb);
backendToken_ = consumes(edm::InputTag(source_.label(), "backend", source_.process()));
}
}

void analyze(edm::StreamID sid, edm::Event const& event, edm::EventSetup const&) const override {
portabletest::TestHostCollection const& product = event.get(token_);
Expand Down Expand Up @@ -134,19 +139,33 @@ class TestAlpakaAnalyzer : public edm::global::EDAnalyzer<> {
assert(vi.id() == i);
assert(vi.m() == matrix * i);
}

if (expectBackend_) {
auto backend = static_cast<cms::alpakatools::Backend>(event.get(backendToken_));
if (expectBackend_ != backend) {
throw cms::Exception("Assert") << "Expected input backend " << cms::alpakatools::toString(*expectBackend_)
<< ", got " << cms::alpakatools::toString(backend);
}
}
}

static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
edm::ParameterSetDescription desc;
desc.add<edm::InputTag>("source");
desc.add<int>("expectSize", -1)
->setComment("Expected size of the input collection. Values < 0 mean the check is not performed. Default: -1");
desc.add<std::string>("expectBackend", "")
->setComment(
"Expected backend of the input collection. Empty value means to not perform the check. Default: empty "
"string");
descriptions.addWithDefaultLabel(desc);
}

private:
const edm::InputTag source_;
const edm::EDGetTokenT<portabletest::TestHostCollection> token_;
edm::EDGetTokenT<unsigned short> backendToken_;
std::optional<cms::alpakatools::Backend> expectBackend_;
const int expectSize_;
};

Expand Down
3 changes: 2 additions & 1 deletion HeterogeneousCore/AlpakaTest/test/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

# analyse the second product
process.testAnalyzerSerial = cms.EDAnalyzer('TestAlpakaAnalyzer',
source = cms.InputTag('testProducerSerial')
source = cms.InputTag('testProducerSerial'),
expectBackend = cms.string('SerialSync')
)

process.cuda_path = cms.Path(process.testAnalyzer)
Expand Down
23 changes: 15 additions & 8 deletions HeterogeneousCore/AlpakaTest/test/testAlpakaModules_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,23 @@

process.alpakaGlobalConsumer = cms.EDAnalyzer("TestAlpakaAnalyzer",
source = cms.InputTag("alpakaGlobalProducer"),
expectSize = cms.int32(10)
expectSize = cms.int32(10),
expectBackend = cms.string("SerialSync")
)
process.alpakaStreamConsumer = cms.EDAnalyzer("TestAlpakaAnalyzer",
source = cms.InputTag("alpakaStreamProducer"),
expectSize = cms.int32(5)
expectSize = cms.int32(5),
expectBackend = cms.string("SerialSync")
)
process.alpakaStreamInstanceConsumer = cms.EDAnalyzer("TestAlpakaAnalyzer",
source = cms.InputTag("alpakaStreamInstanceProducer", "testInstance"),
expectSize = cms.int32(6)
expectSize = cms.int32(6),
expectBackend = cms.string("SerialSync")
)
process.alpakaStreamSynchronizingConsumer = cms.EDAnalyzer("TestAlpakaAnalyzer",
source = cms.InputTag("alpakaStreamSynchronizingProducer"),
expectSize = cms.int32(10)
expectSize = cms.int32(10),
expectBackend = cms.string("SerialSync")
)

if args.processAcceleratorBackend != "":
Expand All @@ -114,10 +118,13 @@
mod = getattr(process, "alpaka"+name)
mod.alpaka = cms.untracked.PSet(backend = cms.untracked.string(args.moduleBackend))
if args.expectBackend == "cuda_async":
process.alpakaGlobalConsumer.expectSize = 20
process.alpakaStreamConsumer.expectSize = 25
process.alpakaStreamInstanceConsumer.expectSize = 36
process.alpakaStreamSynchronizingConsumer.expectSize = 20
def setExpect(m, size):
m.expectSize = size
m.expectBackend = "CudaAsync"
setExpect(process.alpakaGlobalConsumer, size=20)
setExpect(process.alpakaStreamConsumer, size=25)
setExpect(process.alpakaStreamInstanceConsumer, size=36)
setExpect(process.alpakaStreamSynchronizingConsumer, size=20)

process.output = cms.OutputModule('PoolOutputModule',
fileName = cms.untracked.string('testAlpaka.root'),
Expand Down

0 comments on commit bca672b

Please sign in to comment.