PODIO v00-16-03
An Event-Data-Model Toolkit for High Energy Physics Experiments
Loading...
Searching...
No Matches
frame.cpp File Reference
#include "podio/Frame.h"
#include "catch2/catch_test_macros.hpp"
#include "datamodel/ExampleClusterCollection.h"
#include "datamodel/ExampleHitCollection.h"
#include <string>
#include <thread>
#include <vector>

Go to the source code of this file.

Functions

 TEST_CASE ("Frame collections", "[frame][basics]")
 
 TEST_CASE ("Frame parameters", "[frame][basics]")
 
 TEST_CASE ("Frame collections multithreaded insert", "[frame][basics][multithread]")
 
auto createFrame ()
 
std::string makeName (const std::string &prefix, int index)
 
void CHECK_INCREASE (const bool condition, int &counter)
 
 TEST_CASE ("Frame collections multithreaded insert and read", "[frame][basics][multithread]")
 
void checkFrame (const podio::Frame &frame)
 
 TEST_CASE ("Frame movability", "[frame][move-semantics]")
 
 TEST_CASE ("Frame parameters multithread insert", "[frame][basics][multithread]")
 
 TEST_CASE ("Frame parameters multithread insert and read", "[frame][basics][multithread]")
 

Function Documentation

◆ CHECK_INCREASE()

void CHECK_INCREASE ( const bool  condition,
int &  counter 
)

Definition at line 140 of file frame.cpp.

140 {
141 if (condition) {
142 counter++;
143 }
144}

Referenced by TEST_CASE().

◆ checkFrame()

void checkFrame ( const podio::Frame frame)

Definition at line 215 of file frame.cpp.

215 {
216 auto& hits = frame.get<ExampleHitCollection>("hits");
217 REQUIRE(hits.size() == 2);
218 REQUIRE(hits[0].energy() == 0);
219 REQUIRE(hits[0].cellID() == 0x42ULL);
220 REQUIRE(hits[1].energy() == 1);
221 REQUIRE(hits[1].cellID() == 0x123ULL);
222
223 REQUIRE(frame.get<ExampleClusterCollection>("emptyClusters").size() == 0);
224
225 auto& clusters = frame.get<ExampleClusterCollection>("clusters");
226 REQUIRE(clusters.size() == 2);
227 REQUIRE(clusters[0].energy() == 3.14f);
228 REQUIRE(clusters[0].Hits().size() == 1);
229 REQUIRE(clusters[0].Hits()[0] == hits[0]);
230 REQUIRE(clusters[0].Clusters().empty());
231
232 REQUIRE(clusters[1].energy() == 42.f);
233 REQUIRE(clusters[1].Hits().size() == 1);
234 REQUIRE(clusters[1].Hits()[0] == hits[1]);
235 REQUIRE(clusters[1].Clusters()[0] == clusters[0]);
236
237 REQUIRE(frame.getParameter<int>("anInt") == 42);
238 auto& floats = frame.getParameter<std::vector<float>>("someFloats");
239 REQUIRE(floats.size() == 3);
240 REQUIRE(floats[0] == 1.23f);
241 REQUIRE(floats[1] == 2.34f);
242 REQUIRE(floats[2] == 3.45f);
243}
const CollT & get(const std::string &name) const
Definition: Frame.h:297
podio::GenericDataReturnType< T > getParameter(const std::string &key) const
Definition: Frame.h:232

Referenced by TEST_CASE().

◆ createFrame()

auto createFrame ( )

Definition at line 100 of file frame.cpp.

100 {
101 auto frame = podio::Frame();
102
103 frame.put(ExampleClusterCollection(), "emptyClusters");
104
105 // Create a few hits inline (to avoid having to have two identifiers)
106 auto& hits = frame.put(
107 []() {
108 auto coll = ExampleHitCollection();
109 auto hit = coll.create(0x42ULL, 0., 0., 0., 0.);
110 auto hit2 = coll.create(0x123ULL, 1., 1., 1., 1.);
111 return coll;
112 }(),
113 "hits");
114
115 auto clusters = ExampleClusterCollection();
116 auto cluster = clusters.create(3.14f);
117 cluster.addHits(hits[0]);
118 auto cluster2 = clusters.create(42.0f);
119 cluster2.addHits(hits[1]);
120 cluster2.addClusters(cluster);
121
122 // Create a few clustes inline and relate them to the hits from above
123 frame.put(std::move(clusters), "clusters");
124
125 frame.putParameter("anInt", 42);
126 frame.putParameter("someFloats", {1.23f, 2.34f, 3.45f});
127
128 return frame;
129}

Referenced by TEST_CASE().

◆ makeName()

std::string makeName ( const std::string &  prefix,
int  index 
)

Definition at line 132 of file frame.cpp.

132 {
133 return prefix + "_" + std::to_string(index);
134}

Referenced by TEST_CASE().

◆ TEST_CASE() [1/7]

TEST_CASE ( "Frame collections multithreaded insert and read"  ,
""  [frame][basics][multithread] 
)

Definition at line 146 of file frame.cpp.

146 {
147 constexpr int nThreads = 10;
148 std::vector<std::thread> threads;
149 threads.reserve(10);
150
151 // create a pre-populated frame
152 auto frame = createFrame();
153
154 // The Catch2 assertions are not threadsafe:
155 // https://github.com/catchorg/Catch2/blob/devel/docs/limitations.md#thread-safe-assertions
156 // Count the successes in this array here and check them outside
157 // Once the Catch2 deficiencies are resolved, this can be changed again
158 std::array<int, nThreads> successes{};
159
160 // Fill collections from different threads
161 for (int i = 0; i < nThreads; ++i) {
162 threads.emplace_back([&frame, i, &successes]() {
163 auto clusters = ExampleClusterCollection();
164 clusters.create(i * 3.14);
165 clusters.create(i * 3.14);
166 frame.put(std::move(clusters), makeName("clusters", i));
167
168 // Retrieve a few collections in between and do iust a very basic testing
169 auto& existingClu = frame.get<ExampleClusterCollection>("clusters");
170 CHECK_INCREASE(existingClu.size() == 2, successes[i]);
171 auto& existingHits = frame.get<ExampleHitCollection>("hits");
172 CHECK_INCREASE(existingHits.size() == 2, successes[i]);
173
174 auto hits = ExampleHitCollection();
175 hits.create(i * 100ULL);
176 hits.create(i * 100ULL);
177 hits.create(i * 100ULL);
178 frame.put(std::move(hits), makeName("hits", i));
179
180 // Fill in a lot of new collections to trigger a rehashing of the
181 // internal map, which invalidates iterators
182 constexpr int nColls = 100;
183 for (int k = 0; k < nColls; ++k) {
184 frame.put(ExampleHitCollection(), "h_" + std::to_string(i) + "_" + std::to_string(k));
185 }
186 });
187 }
188
189 for (auto& t : threads) {
190 t.join();
191 }
192
193 // Check the frame contents after all threads have finished
194 for (int i = 0; i < nThreads; ++i) {
195 // Check whether the insertsions are as expected
196 REQUIRE(successes[i] == 2);
197
198 auto& hits = frame.get<ExampleHitCollection>(makeName("hits", i));
199 REQUIRE(hits.size() == 3);
200 for (const auto h : hits) {
201 REQUIRE(h.cellID() == i * 100ULL);
202 }
203
204 auto& clusters = frame.get<ExampleClusterCollection>(makeName("clusters", i));
205 REQUIRE(clusters.size() == 2);
206 for (const auto c : clusters) {
207 REQUIRE(c.energy() == i * 3.14);
208 }
209 }
210}
auto createFrame()
Definition: frame.cpp:100
void CHECK_INCREASE(const bool condition, int &counter)
Definition: frame.cpp:140
std::string makeName(const std::string &prefix, int index)
Definition: frame.cpp:132

◆ TEST_CASE() [2/7]

TEST_CASE ( "Frame collections multithreaded insert"  ,
""  [frame][basics][multithread] 
)

Definition at line 56 of file frame.cpp.

56 {
57 constexpr int nThreads = 10;
58 std::vector<std::thread> threads;
59 threads.reserve(10);
60
61 auto frame = podio::Frame();
62
63 // Fill collections from different threads
64 for (int i = 0; i < nThreads; ++i) {
65 threads.emplace_back([&frame, i]() {
66 auto clusters = ExampleClusterCollection();
67 clusters.create(i * 3.14);
68 clusters.create(i * 3.14);
69 frame.put(std::move(clusters), "clusters_" + std::to_string(i));
70
71 auto hits = ExampleHitCollection();
72 hits.create(i * 100ULL);
73 hits.create(i * 100ULL);
74 hits.create(i * 100ULL);
75 frame.put(std::move(hits), "hits_" + std::to_string(i));
76 });
77 }
78
79 for (auto& t : threads) {
80 t.join();
81 }
82
83 // Check the frame contents after all threads have finished
84 for (int i = 0; i < nThreads; ++i) {
85 auto& hits = frame.get<ExampleHitCollection>("hits_" + std::to_string(i));
86 REQUIRE(hits.size() == 3);
87 for (const auto h : hits) {
88 REQUIRE(h.cellID() == i * 100ULL);
89 }
90
91 auto& clusters = frame.get<ExampleClusterCollection>("clusters_" + std::to_string(i));
92 REQUIRE(clusters.size() == 2);
93 for (const auto c : clusters) {
94 REQUIRE(c.energy() == i * 3.14);
95 }
96 }
97}

◆ TEST_CASE() [3/7]

TEST_CASE ( "Frame collections"  ,
""  [frame][basics] 
)

Definition at line 12 of file frame.cpp.

12 {
13 auto event = podio::Frame();
14 auto clusters = ExampleClusterCollection();
15 clusters.create(3.14f);
16 clusters.create(42.0f);
17
18 event.put(std::move(clusters), "clusters");
19
20 auto& coll = event.get<ExampleClusterCollection>("clusters");
21 REQUIRE(coll[0].energy() == 3.14f);
22 REQUIRE(coll[1].energy() == 42.0f);
23}

◆ TEST_CASE() [4/7]

TEST_CASE ( "Frame movability"  ,
""  [frame][move-semantics] 
)

Definition at line 245 of file frame.cpp.

245 {
246 auto frame = createFrame();
247 checkFrame(frame); // just to ensure that the setup is as expected
248
249 SECTION("Move constructor") {
250 auto otherFrame = std::move(frame);
251 checkFrame(otherFrame);
252 }
253
254 SECTION("Move assignment operator") {
255 auto otherFrame = podio::Frame();
256 otherFrame = std::move(frame);
257 checkFrame(otherFrame);
258 }
259
260 SECTION("Use after move construction") {
261 auto otherFrame = std::move(frame); // NOLINT(clang-analyzer-cplusplus.Move) clang-tidy and the Catch2 sections
262 // setup do not go along here
263 otherFrame.putParameter("aString", "Can add strings after move-constructing");
264 REQUIRE(otherFrame.getParameter<std::string>("aString") == "Can add strings after move-constructing");
265
266 otherFrame.put(
267 []() {
268 auto coll = ExampleHitCollection();
269 coll.create();
270 coll.create();
271 coll.create();
272 return coll;
273 }(),
274 "moreHits");
275
276 auto& hits = otherFrame.get<ExampleHitCollection>("moreHits");
277 REQUIRE(hits.size() == 3);
278 checkFrame(otherFrame);
279 }
280}
void checkFrame(const podio::Frame &frame)
Definition: frame.cpp:215

◆ TEST_CASE() [5/7]

TEST_CASE ( "Frame parameters multithread insert and read"  ,
""  [frame][basics][multithread] 
)

Definition at line 311 of file frame.cpp.

311 {
312 constexpr int nThreads = 10;
313 std::vector<std::thread> threads;
314 threads.reserve(nThreads);
315
316 auto frame = podio::Frame();
317 frame.putParameter("int_par", 42);
318 frame.putParameter("string_par", "some string");
319 frame.putParameter("float_pars", {1.23f, 4.56f, 7.89f});
320
321 // The Catch2 assertions are not threadsafe:
322 // https://github.com/catchorg/Catch2/blob/devel/docs/limitations.md#thread-safe-assertions
323 // Count the successes in this array here and check them outside
324 // Once the Catch2 deficiencies are resolved, this can be changed again
325 std::array<int, nThreads> successes{};
326
327 for (int i = 0; i < nThreads; ++i) {
328 threads.emplace_back([&frame, i, &successes]() {
329 frame.putParameter(makeName("int", i), i);
330 frame.putParameter(makeName("float", i), (float)i);
331
332 CHECK_INCREASE(frame.getParameter<int>("int_par") == 42, successes[i]);
333 CHECK_INCREASE(frame.getParameter<float>(makeName("float", i)) == (float)i, successes[i]);
334
335 frame.putParameter(makeName("string", i), std::to_string(i));
336 CHECK_INCREASE(frame.getParameter<std::string>("string_par") == "some string", successes[i]);
337
338 const auto& floatPars = frame.getParameter<std::vector<float>>("float_pars");
339 CHECK_INCREASE(floatPars.size() == 3, successes[i]);
340 CHECK_INCREASE(floatPars[0] == 1.23f, successes[i]);
341 CHECK_INCREASE(floatPars[1] == 4.56f, successes[i]);
342 CHECK_INCREASE(floatPars[2] == 7.89f, successes[i]);
343
344 // Fill in a lot of new parameters to trigger rehashing of the internal
345 // map, which invalidates iterators
346 constexpr int nParams = 100;
347 for (int k = 0; k < nParams; ++k) {
348 frame.putParameter(makeName("intPar", i) + std::to_string(k), i * k);
349 frame.putParameter(makeName("floatPar", i) + std::to_string(k), (float)i * k);
350 frame.putParameter(makeName("stringPar", i) + std::to_string(k), std::to_string(i * k));
351 }
352 });
353 }
354
355 for (auto& t : threads) {
356 t.join();
357 }
358
359 for (int i = 0; i < nThreads; ++i) {
360 // Check the insertion successes
361 REQUIRE(successes[i] == 7);
362
363 REQUIRE(frame.getParameter<int>(makeName("int", i)) == i);
364 REQUIRE(frame.getParameter<float>(makeName("float", i)) == (float)i);
365 REQUIRE(frame.getParameter<std::string>(makeName("string", i)) == std::to_string(i));
366 }
367}

◆ TEST_CASE() [6/7]

TEST_CASE ( "Frame parameters multithread insert"  ,
""  [frame][basics][multithread] 
)

Definition at line 282 of file frame.cpp.

282 {
283 // Test that parameter access is thread safe
284 constexpr int nThreads = 10;
285 std::vector<std::thread> threads;
286 threads.reserve(nThreads);
287
288 auto frame = podio::Frame();
289
290 for (int i = 0; i < nThreads; ++i) {
291 threads.emplace_back([&frame, i]() {
292 frame.putParameter(makeName("int_par", i), i);
293
294 frame.putParameter(makeName("float_par", i), (float)i);
295
296 frame.putParameter(makeName("string_par", i), std::to_string(i));
297 });
298 }
299
300 for (auto& t : threads) {
301 t.join();
302 }
303
304 for (int i = 0; i < nThreads; ++i) {
305 REQUIRE(frame.getParameter<int>(makeName("int_par", i)) == i);
306 REQUIRE(frame.getParameter<float>(makeName("float_par", i)) == (float)i);
307 REQUIRE(frame.getParameter<std::string>(makeName("string_par", i)) == std::to_string(i));
308 }
309}

◆ TEST_CASE() [7/7]

TEST_CASE ( "Frame parameters"  ,
""  [frame][basics] 
)

Definition at line 25 of file frame.cpp.

25 {
26 auto event = podio::Frame();
27
28 event.putParameter("aString", "from a string literal");
29 REQUIRE(event.getParameter<std::string>("aString") == "from a string literal");
30
31 event.putParameter("someInts", {42, 123});
32 const auto& ints = event.getParameter<std::vector<int>>("someInts");
33 REQUIRE(ints.size() == 2);
34 REQUIRE(ints[0] == 42);
35 REQUIRE(ints[1] == 123);
36
37 event.putParameter("someStrings", {"one", "two", "three"});
38 const auto& strings = event.getParameter<std::vector<std::string>>("someStrings");
39 REQUIRE(strings.size() == 3);
40 REQUIRE(strings[0] == "one");
41 REQUIRE(strings[1] == "two");
42 REQUIRE(strings[2] == "three");
43
44 const auto stringKeys = event.getParameterKeys<std::string>();
45 REQUIRE(stringKeys.size() == 2);
46 // Can't rely on an insertion order here
47 REQUIRE(std::find(stringKeys.begin(), stringKeys.end(), "aString") != stringKeys.end());
48 REQUIRE(std::find(stringKeys.begin(), stringKeys.end(), "someStrings") != stringKeys.end());
49}