Skip to content

Commit f950141

Browse files
committed
Add a test for writing and reading a PortableTestObject
1 parent c3aebf8 commit f950141

File tree

6 files changed

+155
-22
lines changed

6 files changed

+155
-22
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include <cassert>
2+
3+
#include "DataFormats/PortableTestObjects/interface/TestHostObject.h"
4+
#include "FWCore/Framework/interface/Event.h"
5+
#include "FWCore/Framework/interface/EventSetup.h"
6+
#include "FWCore/Framework/interface/Frameworkfwd.h"
7+
#include "FWCore/Framework/interface/global/EDAnalyzer.h"
8+
#include "FWCore/MessageLogger/interface/MessageLogger.h"
9+
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
10+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
11+
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
12+
#include "FWCore/Utilities/interface/EDGetToken.h"
13+
#include "FWCore/Utilities/interface/InputTag.h"
14+
15+
class TestAlpakaObjectAnalyzer : public edm::global::EDAnalyzer<> {
16+
public:
17+
TestAlpakaObjectAnalyzer(edm::ParameterSet const& config)
18+
: source_{config.getParameter<edm::InputTag>("source")}, token_{consumes(source_)} {
19+
if (std::string const& eb = config.getParameter<std::string>("expectBackend"); not eb.empty()) {
20+
expectBackend_ = cms::alpakatools::toBackend(eb);
21+
backendToken_ = consumes(edm::InputTag(source_.label(), "backend", source_.process()));
22+
}
23+
}
24+
25+
void analyze(edm::StreamID sid, edm::Event const& event, edm::EventSetup const&) const override {
26+
portabletest::TestHostObject const& product = event.get(token_);
27+
28+
auto const& value = product.value();
29+
{
30+
edm::LogInfo msg("TestAlpakaObjectAnalyzer");
31+
msg << source_.encode() << ".data() at " << product.data() << '\n';
32+
msg << source_.encode() << ".buffer().data() at " << product.buffer().data() << '\n';
33+
msg << source_.encode() << ".value() = {\n";
34+
msg << " .x: " << value.x << '\n';
35+
msg << " .y: " << value.y << '\n';
36+
msg << " .z: " << value.z << '\n';
37+
msg << " .id: " << value.id << '\n';
38+
msg << "}\n";
39+
}
40+
41+
// check that the product data is held in the product buffer
42+
assert(product.buffer().data() == product.data());
43+
44+
// check that the product content is as expected
45+
assert(value.x == 5.);
46+
assert(value.y == 12.);
47+
assert(value.z == 13.);
48+
assert(value.id == 42);
49+
50+
// check that the backend is as expected
51+
if (expectBackend_) {
52+
auto backend = static_cast<cms::alpakatools::Backend>(event.get(backendToken_));
53+
if (expectBackend_ != backend) {
54+
throw cms::Exception("Assert") << "Expected input backend " << cms::alpakatools::toString(*expectBackend_)
55+
<< ", got " << cms::alpakatools::toString(backend);
56+
}
57+
}
58+
}
59+
60+
static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
61+
edm::ParameterSetDescription desc;
62+
desc.add<edm::InputTag>("source");
63+
desc.add<std::string>("expectBackend", "")
64+
->setComment(
65+
"Expected backend of the input collection. Empty value means to not perform the check. Default: empty "
66+
"string");
67+
descriptions.addWithDefaultLabel(desc);
68+
}
69+
70+
private:
71+
const edm::InputTag source_;
72+
const edm::EDGetTokenT<portabletest::TestHostObject> token_;
73+
edm::EDGetTokenT<unsigned short> backendToken_;
74+
std::optional<cms::alpakatools::Backend> expectBackend_;
75+
};
76+
77+
#include "FWCore/Framework/interface/MakerMacros.h"
78+
DEFINE_FWK_MODULE(TestAlpakaObjectAnalyzer);

HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.dev.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,31 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE {
5555
alpaka::exec<Acc1D>(queue, workDiv, TestAlgoKernel{}, collection.view(), collection->metadata().size(), xvalue);
5656
}
5757

58+
class TestAlgoStructKernel {
59+
public:
60+
template <typename TAcc, typename = std::enable_if_t<alpaka::isAccelerator<TAcc>>>
61+
ALPAKA_FN_ACC void operator()(TAcc const& acc,
62+
portabletest::TestDeviceObject::Product* data,
63+
double x,
64+
double y,
65+
double z,
66+
int32_t id) const {
67+
// run on a single thread
68+
if (once_per_grid(acc)) {
69+
data->x = x;
70+
data->y = y;
71+
data->z = z;
72+
data->id = id;
73+
}
74+
}
75+
};
76+
77+
void TestAlgo::fillObject(
78+
Queue& queue, portabletest::TestDeviceObject& object, double x, double y, double z, int32_t id) const {
79+
// run on a single thread
80+
auto workDiv = make_workdiv<Acc1D>(1, 1);
81+
82+
alpaka::exec<Acc1D>(queue, workDiv, TestAlgoStructKernel{}, object.data(), x, y, z, id);
83+
}
84+
5885
} // namespace ALPAKA_ACCELERATOR_NAMESPACE

HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlgo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
#define HeterogeneousCore_AlpakaTest_plugins_alpaka_TestAlgo_h
33

44
#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceCollection.h"
5+
#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h"
56
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
67

78
namespace ALPAKA_ACCELERATOR_NAMESPACE {
89

910
class TestAlgo {
1011
public:
1112
void fill(Queue& queue, portabletest::TestDeviceCollection& collection, double xvalue = 0.) const;
13+
void fillObject(
14+
Queue& queue, portabletest::TestDeviceObject& object, double x, double y, double z, int32_t id) const;
1215
};
1316

1417
} // namespace ALPAKA_ACCELERATOR_NAMESPACE

HeterogeneousCore/AlpakaTest/plugins/alpaka/TestAlpakaProducer.cc

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceCollection.h"
2+
#include "DataFormats/PortableTestObjects/interface/alpaka/TestDeviceObject.h"
23
#include "FWCore/Framework/interface/Frameworkfwd.h"
34
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
45
#include "FWCore/ParameterSet/interface/ParameterSet.h"
@@ -18,15 +19,19 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE {
1819
class TestAlpakaProducer : public global::EDProducer<> {
1920
public:
2021
TestAlpakaProducer(edm::ParameterSet const& config)
21-
: deviceToken_{produces()}, size_{config.getParameter<int32_t>("size")} {}
22+
: objectToken_{produces()}, collectionToken_{produces()}, size_{config.getParameter<int32_t>("size")} {}
2223

2324
void produce(edm::StreamID sid, device::Event& event, device::EventSetup const&) const override {
2425
// run the algorithm, potentially asynchronously
25-
portabletest::TestDeviceCollection deviceProduct{size_, event.queue()};
26-
algo_.fill(event.queue(), deviceProduct);
26+
portabletest::TestDeviceCollection deviceCollection{size_, event.queue()};
27+
algo_.fill(event.queue(), deviceCollection);
2728

28-
// put the asynchronous product into the event without waiting
29-
event.emplace(deviceToken_, std::move(deviceProduct));
29+
portabletest::TestDeviceObject deviceObject{event.queue()};
30+
algo_.fillObject(event.queue(), deviceObject, 5., 12., 13., 42);
31+
32+
// put the asynchronous products into the event without waiting
33+
event.emplace(objectToken_, std::move(deviceObject));
34+
event.emplace(collectionToken_, std::move(deviceCollection));
3035
}
3136

3237
static void fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
@@ -36,7 +41,8 @@ namespace ALPAKA_ACCELERATOR_NAMESPACE {
3641
}
3742

3843
private:
39-
const device::EDPutToken<portabletest::TestDeviceCollection> deviceToken_;
44+
const device::EDPutToken<portabletest::TestDeviceObject> objectToken_;
45+
const device::EDPutToken<portabletest::TestDeviceCollection> collectionToken_;
4046
const int32_t size_;
4147

4248
// implementation of the algorithm

HeterogeneousCore/AlpakaTest/test/reader.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,32 @@
77
fileNames = cms.untracked.vstring('file:test.root')
88
)
99

10-
# enable logging for the TestAlpakaAnalyzer
10+
# enable logging for the analysers
1111
process.MessageLogger.TestAlpakaAnalyzer = cms.untracked.PSet()
12+
process.MessageLogger.TestAlpakaObjectAnalyzer = cms.untracked.PSet()
1213

13-
# analyse the first product
14+
# analyse the first set of products
1415
process.testAnalyzer = cms.EDAnalyzer('TestAlpakaAnalyzer',
1516
source = cms.InputTag('testProducer')
1617
)
1718

19+
process.testObjectAnalyzer = cms.EDAnalyzer('TestAlpakaObjectAnalyzer',
20+
source = cms.InputTag('testProducer')
21+
)
22+
1823
# analyse the second product
1924
process.testAnalyzerSerial = cms.EDAnalyzer('TestAlpakaAnalyzer',
2025
source = cms.InputTag('testProducerSerial'),
2126
expectBackend = cms.string('SerialSync')
2227
)
2328

24-
process.cuda_path = cms.Path(process.testAnalyzer)
29+
process.testObjectAnalyzerSerial = cms.EDAnalyzer('TestAlpakaObjectAnalyzer',
30+
source = cms.InputTag('testProducerSerial'),
31+
expectBackend = cms.string('SerialSync')
32+
)
33+
34+
process.device_path = cms.Path(process.testAnalyzer + process.testObjectAnalyzer)
2535

26-
process.serial_path = cms.Path(process.testAnalyzerSerial)
36+
process.serial_path = cms.Path(process.testAnalyzerSerial + process.testObjectAnalyzerSerial)
2737

2838
process.maxEvents.input = 10

HeterogeneousCore/AlpakaTest/test/writer.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
process.load('Configuration.StandardSequences.Accelerators_cff')
88
process.load('HeterogeneousCore.AlpakaCore.ProcessAcceleratorAlpaka_cfi')
99

10-
# enable logging for the AlpakaService and TestAlpakaAnalyzer
10+
# enable logging for the analysers
1111
process.MessageLogger.TestAlpakaAnalyzer = cms.untracked.PSet()
12+
process.MessageLogger.TestAlpakaObjectAnalyzer = cms.untracked.PSet()
1213

1314
# either run the producer on a gpu (if available) and copy the product to the cpu, or run the producer directly on the cpu
1415
process.testProducer = cms.EDProducer('TestAlpakaProducer@alpaka',
@@ -20,11 +21,15 @@
2021
#)
2122
)
2223

23-
# analyse the product
24+
# analyse the first set of products
2425
process.testAnalyzer = cms.EDAnalyzer('TestAlpakaAnalyzer',
2526
source = cms.InputTag('testProducer')
2627
)
2728

29+
process.testObjectAnalyzer = cms.EDAnalyzer('TestAlpakaObjectAnalyzer',
30+
source = cms.InputTag('testProducer')
31+
)
32+
2833
# run a second producer explicitly on the cpu
2934
process.testProducerSerial = cms.EDProducer('alpaka_serial_sync::TestAlpakaProducer',
3035
size = cms.int32(99)
@@ -37,28 +42,32 @@
3742
# )
3843
#)
3944

40-
# analyse the second product
45+
# analyse the second set of products
4146
process.testAnalyzerSerial = cms.EDAnalyzer('TestAlpakaAnalyzer',
42-
source = cms.InputTag('testProducerSerial')
47+
source = cms.InputTag('testProducerSerial'),
48+
expectBackend = cms.string('SerialSync')
49+
)
50+
51+
process.testObjectAnalyzerSerial = cms.EDAnalyzer('TestAlpakaObjectAnalyzer',
52+
source = cms.InputTag('testProducerSerial'),
53+
expectBackend = cms.string('SerialSync')
4354
)
4455

45-
# write the two products to a 'test.root' file
56+
# write all products to a 'test.root' file
4657
process.output = cms.OutputModule('PoolOutputModule',
4758
fileName = cms.untracked.string('test.root'),
48-
outputCommands = cms.untracked.vstring(
49-
'drop *',
50-
'keep *_testProducer_*_*',
51-
'keep *_testProducerSerial_*_*',
52-
)
59+
outputCommands = cms.untracked.vstring('keep *')
5360
)
5461

5562
process.process_path = cms.Path(
5663
process.testProducer +
57-
process.testAnalyzer)
64+
process.testAnalyzer +
65+
process.testObjectAnalyzer)
5866

5967
process.serial_path = cms.Path(
6068
process.testProducerSerial +
61-
process.testAnalyzerSerial)
69+
process.testAnalyzerSerial +
70+
process.testObjectAnalyzerSerial)
6271

6372
process.output_path = cms.EndPath(process.output)
6473

0 commit comments

Comments
 (0)