1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
#ifndef HeterogeneousCore_AlpakaCore_interface_alpaka_Event_h
#define HeterogeneousCore_AlpakaCore_interface_alpaka_Event_h
#include "DataFormats/Common/interface/Handle.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Utilities/interface/EDGetToken.h"
#include "FWCore/Utilities/interface/EDPutToken.h"
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/DeviceProductType.h"
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/EDGetToken.h"
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/EDMetadata.h"
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/EDPutToken.h"
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
namespace ALPAKA_ACCELERATOR_NAMESPACE::device {
/**
* The device::Event mimics edm::Event, and provides access to
* EDProducts in the host memory space, and in the device memory
* space defined by the backend (i.e. ALPAKA_ACCELERATOR_NAMESPACE).
* The device::Event also gives access to the Queue object the
* EDModule code should use to queue all the device operations.
*
* Access to device memory space products is synchronized properly.
* For backends with synchronous Queue this is trivial. For
* asynchronous Queue, either the Queue of the EDModule is taken
* from the first data product, or a wait is inserted into the
* EDModule's Queue to wait for the product's asynchronous
* production to finish.
*
* Note that not full interface of edm::Event is replicated here. If
* something important is missing, that can be added.
*/
class Event {
public:
// To be called in produce()
explicit Event(edm::Event& ev, std::shared_ptr<EDMetadata> metadata)
: constEvent_(ev), event_(&ev), metadata_(std::move(metadata)) {}
// To be called in acquire()
explicit Event(edm::Event const& ev, std::shared_ptr<EDMetadata> metadata)
: constEvent_(ev), metadata_(std::move(metadata)) {}
Event(Event const&) = delete;
Event& operator=(Event const&) = delete;
Event(Event&&) = delete;
Event& operator=(Event&&) = delete;
auto streamID() const { return constEvent_.streamID(); }
auto id() const { return constEvent_.id(); }
// To be able to interact with non-Alpaka helper code that needs
// to access edm::Event
operator edm::Event const&() const { return constEvent_; }
Device device() const { return metadata_->device(); }
// Alpaka operations do not accept a temporary as an argument
// TODO: Returning non-const reference here is BAD
Queue& queue() const {
queueUsed_ = true;
return metadata_->queue();
}
// get()
template <typename T>
T const& get(edm::EDGetTokenT<T> const& token) const {
return constEvent_.get(token);
}
template <typename T>
T const& get(device::EDGetToken<T> const& token) const {
auto const& deviceProduct = constEvent_.get(token.underlyingToken());
if constexpr (detail::useProductDirectly) {
return deviceProduct;
} else {
// try to re-use queue from deviceProduct if our queue has not yet been used
T const& product = deviceProduct.template getSynchronized<EDMetadata>(*metadata_, not queueUsed_);
queueUsed_ = true;
return product;
}
}
// getHandle()
template <typename T>
edm::Handle<T> getHandle(edm::EDGetTokenT<T> const& token) const {
return constEvent_.getHandle(token);
}
template <typename T>
edm::Handle<T> getHandle(device::EDGetToken<T> const& token) const {
auto deviceProductHandle = constEvent_.getHandle(token.underlyingToken());
if constexpr (detail::useProductDirectly) {
return deviceProductHandle;
} else {
if (not deviceProductHandle) {
return edm::Handle<T>(deviceProductHandle.whyFailedFactory());
}
// try to re-use queue from deviceProduct if our queue has not yet been used
T const& product = deviceProductHandle->getSynchronized(*metadata_, not queueUsed_);
queueUsed_ = true;
return edm::Handle<T>(&product, deviceProductHandle.provenance());
}
}
// emplace()
template <typename T, typename... Args>
edm::OrphanHandle<T> emplace(edm::EDPutTokenT<T> const& token, Args&&... args) {
return event_->emplace(token, std::forward<Args>(args)...);
}
// TODO: what to do about the returned OrphanHandle object?
// The idea for Ref-like things in this domain differs from earlier Refs anyway
template <typename T, typename... Args>
void emplace(device::EDPutToken<T> const& token, Args&&... args) {
if constexpr (detail::useProductDirectly) {
event_->emplace(token.underlyingToken(), std::forward<Args>(args)...);
} else {
event_->emplace(token.underlyingToken(), metadata_, std::forward<Args>(args)...);
}
}
// put()
template <typename T>
edm::OrphanHandle<T> put(edm::EDPutTokenT<T> const& token, std::unique_ptr<T> product) {
return event_->put(token, std::move(product));
}
template <typename T>
void put(device::EDPutToken<T> const& token, std::unique_ptr<T> product) {
if constexpr (detail::useProductDirectly) {
event_->emplace(token.underlyingToken(), std::move(*product));
} else {
event_->emplace(token.underlyingToken(), metadata_, std::move(*product));
}
}
// implementation details
bool wasQueueUsed() const { return queueUsed_; }
private:
// Having both const and non-const here in order to serve the
// clients with one device::Event class
edm::Event const& constEvent_;
edm::Event* event_ = nullptr;
std::shared_ptr<EDMetadata> metadata_;
// device::Event is not supposed to be const-thread-safe, so no
// additional protection is needed.
mutable bool queueUsed_ = false;
};
} // namespace ALPAKA_ACCELERATOR_NAMESPACE::device
#endif
|