DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
dunedaq::datahandlinglibs::test Namespace Reference

Classes

class  TestDefaultRequestHandlerModel

Functions

template<template< class > class BufferType, class TypeAdapter>
void fill_buffer (std::shared_ptr< BufferType< TypeAdapter > > &buffer, uint64_t const init_timestamp=0, size_t const n_obj=10, std::set< size_t > const obj_to_skip={})
template<template< class > class BufferType, class TypeAdapter>
void print_buffer (std::shared_ptr< BufferType< TypeAdapter > > &buffer, std::string desc="")
template<template< class > class BufferType, class TypeAdapter>
void test_queue_model ()
template<template< class > class BufferType, class TypeAdapter>
void test_request_model ()

Function Documentation

◆ fill_buffer()

template<template< class > class BufferType, class TypeAdapter>
void dunedaq::datahandlinglibs::test::fill_buffer ( std::shared_ptr< BufferType< TypeAdapter > > & buffer,
uint64_t const init_timestamp = 0,
size_t const n_obj = 10,
std::set< size_t > const obj_to_skip = {} )

Definition at line 27 of file TestUtilities.hpp.

30 {})
31{
32
33 // allocate mem in buffer
34 buffer->allocate_memory(n_obj);
35
36 // some accounting
37 size_t i = 0, i_obj = 0;
38 uint64_t next_timestamp = init_timestamp;
39
40 // while we want to add to the buffer
41 while (i_obj < n_obj) {
42
43 // create a frame with appropriate timestamp
44 TypeAdapter frame;
45 frame.fake_timestamps(next_timestamp);
46
47 // increment to the next timestamp
48 next_timestamp += uint64_t(frame.get_num_frames() * TypeAdapter::expected_tick_difference);
49
50 // only write in buffer if not in the skip list
51 if (obj_to_skip.count(i) == 0) {
52 buffer->write(std::move(frame));
53 ++i_obj;
54 }
55 ++i;
56 } // end while(obj_in_buffer<n_obj)
57} // end fill_buffer

◆ print_buffer()

template<template< class > class BufferType, class TypeAdapter>
void dunedaq::datahandlinglibs::test::print_buffer ( std::shared_ptr< BufferType< TypeAdapter > > & buffer,
std::string desc = "" )

Definition at line 61 of file TestUtilities.hpp.

62{
63 std::stringstream ss;
64 ss << "Buffer (" << desc << "): ";
65 typename BufferType<TypeAdapter>::Iterator iter = buffer->begin();
66 while (iter != buffer->end()) {
67 ss << iter->get_timestamp() << " ";
68 ++iter;
69 }
70 BOOST_TEST_MESSAGE(ss.str());
71} // end print_buffer

◆ test_queue_model()

template<template< class > class BufferType, class TypeAdapter>
void dunedaq::datahandlinglibs::test::test_queue_model ( )

Definition at line 75 of file TestUtilities.hpp.

76{
77 // some testing vars
78 TypeAdapter test_element;
79 uint64_t ticks_between = TypeAdapter::expected_tick_difference * test_element.get_num_frames();
80
81 auto test_lower_bound = [&](std::shared_ptr<BufferType<TypeAdapter>> buffer,
82 uint64_t test_ts,
83 uint32_t expected_idx,
84 bool with_errors = false) {
85 BOOST_TEST_MESSAGE("\ttesting ts=" << test_ts);
86
87 TypeAdapter test_element;
88 test_element.set_timestamp(test_ts);
89 typename BufferType<TypeAdapter>::Iterator expected_el = buffer->begin();
90 for (size_t i = 0; i < expected_idx; ++i) {
91 ++expected_el;
92 }
93
94 // get our lower_bound call
95 auto return_el = buffer->lower_bound(test_element, with_errors);
96
97 // loop through to get the previous element to return_el
98 typename BufferType<TypeAdapter>::Iterator scan_el = buffer->begin();
99 typename BufferType<TypeAdapter>::Iterator prev_el = buffer->begin();
100 while (scan_el != return_el) {
101 ++scan_el;
102 if (scan_el == return_el)
103 break;
104 ++prev_el;
105 }
106
107 // check that expected and return timestamps agree
108 BOOST_CHECK_MESSAGE(expected_el->get_timestamp() == return_el->get_timestamp(),
109 "Expected ts{" << expected_el->get_timestamp() << "} == return ts{"
110 << return_el->get_timestamp() << "} for test_ts=" << test_ts);
111
112 // check that we satisfy the lower bound condition
113 BOOST_CHECK_MESSAGE(return_el->get_timestamp() >= test_ts,
114 "Returned ts{" << return_el->get_timestamp() << "} is >= test_ts{" << test_ts << "}");
115 BOOST_CHECK_MESSAGE((prev_el->get_timestamp() < test_ts || return_el == buffer->begin()),
116 "Prev ts{" << prev_el->get_timestamp() << "} is < test_ts{" << test_ts
117 << "} (or lower bound is begin of buffer)");
118 }; // end test_lower_bounds
119
120 /*
121 * Unskipped buffer should have elements with index [0, 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]
122 * and timestamps [0,1*T,2*T,3*T,4*T,5*T,6*T,7*T,8*T,9*T]
123 * where T = DTS ticks between successive elements (tick_diff_per_frame * n_frames_per_obj_in_buffer)
124 */
125 BOOST_TEST_MESSAGE("Testing buffer without skips...");
126 auto buffer_noskip = std::make_shared<BufferType<TypeAdapter>>();
127 fill_buffer<BufferType, TypeAdapter>(buffer_noskip, 0, 10);
128 print_buffer<BufferType, TypeAdapter>(buffer_noskip, "noskip");
129
130 // get lower bound on aligned element
131 // should return the exact value
132 test_lower_bound(buffer_noskip, ticks_between * 2, 2);
133
134 if (ticks_between > 1) // unaligned tests don't make sense if ticks_between < 1
135 {
136 // get lower bound when maximally unaligned
137 // should get the next element up
138 test_lower_bound(buffer_noskip, ticks_between * 5 / 2, 3);
139
140 // get lower bound when minimally unaligned, next instance
141 test_lower_bound(buffer_noskip, ticks_between + 1, 2);
142 }
143
144 /*
145 * Skipped buffer should have elements with index [0, 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]
146 * and timestamps [0,1*T,4*T,5*T,6*T,7*T,8*T,9*T,10*T,11*T]
147 * where T = DTS ticks between successive elements (tick_diff_per_frame * n_frames_per_obj_in_buffer)
148 */
149 BOOST_TEST_MESSAGE("Testing buffer with skips...");
150 std::set<size_t> obj_to_skip = { 2, 3 };
151 auto buffer_skip = std::make_shared<BufferType<TypeAdapter>>();
152 fill_buffer<BufferType, TypeAdapter>(buffer_skip, 0, 10, obj_to_skip);
153 print_buffer<BufferType, TypeAdapter>(buffer_skip, "skip");
154
155 // get lower bound on aligned but skipped element
156 // should return next available
157 test_lower_bound(buffer_skip, ticks_between * 2, 2, true);
158 test_lower_bound(buffer_skip, ticks_between * 3, 2, true);
159 // should be unaffected
160 test_lower_bound(buffer_skip, ticks_between, 1, true);
161 test_lower_bound(buffer_skip, ticks_between * 4, 2, true);
162
163 if (ticks_between > 1) // unaligned tests don't make sense if ticks_between < 1
164 {
165 // get lower bound when maximally unaligned
166 test_lower_bound(buffer_skip, ticks_between * 3 / 2, 2, true);
167 test_lower_bound(buffer_skip, ticks_between * 5 / 2, 2, true);
168 test_lower_bound(buffer_skip, ticks_between * 7 / 2, 2, true);
169 // should be unaffected
170 test_lower_bound(buffer_skip, ticks_between * 1 / 2, 1, true);
171 test_lower_bound(buffer_skip, ticks_between * 9 / 2, 3, true);
172 test_lower_bound(buffer_skip, ticks_between * 11 / 2, 4, true);
173
174 // get lower bound when minimally unaligned, next instance
175 test_lower_bound(buffer_skip, ticks_between + 1, 2, true);
176 test_lower_bound(buffer_skip, ticks_between * 2 + 1, 2, true);
177 // should be unaffected
178 test_lower_bound(buffer_skip, 1, 1, true);
179 }
180
181} // end test_queue_model
void print_buffer(std::shared_ptr< BufferType< TypeAdapter > > &buffer, std::string desc="")
void fill_buffer(std::shared_ptr< BufferType< TypeAdapter > > &buffer, uint64_t const init_timestamp=0, size_t const n_obj=10, std::set< size_t > const obj_to_skip={})

◆ test_request_model()

template<template< class > class BufferType, class TypeAdapter>
void dunedaq::datahandlinglibs::test::test_request_model ( )

Definition at line 199 of file TestUtilities.hpp.

200{
201
203
204 // some testing vars
205 TypeAdapter test_element;
206 uint64_t n_frames = test_element.get_num_frames();
207 uint64_t ticks_per_frame = TypeAdapter::expected_tick_difference;
208 uint64_t ticks_between = ticks_per_frame * n_frames;
209
210 // function for testing get_fragment_pieces in cases where there are no skips in the buffer
211 auto test_req_bounds = [&](std::shared_ptr<BufferType<TypeAdapter>> buffer,
212 uint64_t start_win,
213 uint64_t end_win,
214 std::set<size_t> objects_skipped = {}) {
215 BOOST_TEST_MESSAGE("\ttesting [start_win{" << start_win << "}, end_win{" << end_win << "})");
216
217 // make the error registry we need
218 auto errorRegistry = std::make_unique<dunedaq::datahandlinglibs::FrameErrorRegistry>();
219
220 // create the request handler
221 DefaultRequestHandler requestHandler(buffer, errorRegistry);
222
223 // call the get_fragment_pieces
224 auto dfmessage = dunedaq::dfmessages::DataRequest();
225 auto req_res =
226 typename DefaultRequestHandler::RequestResult(DefaultRequestHandler::ResultCode::kUnknown, dfmessage);
227 auto ret = requestHandler.get_fragment_pieces(start_win, end_win, req_res);
228
229 // check that the return code is correct.
230 BOOST_CHECK_EQUAL(req_res.result_code, DefaultRequestHandler::ResultCode::kFound);
231
232 // check that the first and last returned blocks are not empty
233 BOOST_REQUIRE_GT(ret.front().second, 0);
234 BOOST_REQUIRE_GT(ret.back().second, 0);
235
236 // grab the (first) timestamps of the first and last frames
237 uint64_t first_ts = reinterpret_cast<const TypeAdapter::FrameType*>(ret.front().first)->get_timestamp();
238
239 // if n_frames is 1, then all payloads are just one frame, and we can grab the timestamp directly
240 // this is particularly useful for not having to deal with wrapper objects, as those complicate things a bunch
241 // if not, then we really hope that sizeof(TypeAdapter::FrameType) is what we want ...
242 uint64_t last_ts = 0;
243 if (n_frames == 1)
244 last_ts = reinterpret_cast<const TypeAdapter::FrameType*>(ret.back().first)->get_timestamp();
245 else
246 last_ts = reinterpret_cast<const TypeAdapter::FrameType*>((char*)(ret.back().first) + (ret.back().second) -
247 sizeof(typename TypeAdapter::FrameType))
248 ->get_timestamp();
249
250 // general check:
251 // first_ts <= start_win < first_ts + ticks_per_frame
252 // last_ts < end_win <= last_ts + ticks_per_frame
253 if (objects_skipped.size() == 0)
254 BOOST_CHECK_MESSAGE(first_ts <= start_win,
255 "first_frame_ts{" << first_ts << "} <= start_win{" << start_win << "}");
256 BOOST_CHECK_MESSAGE(start_win < first_ts + ticks_per_frame,
257 "start_win{" << start_win << "} < first_frame_ts+ticks_per_frame{" << first_ts + ticks_per_frame
258 << "}");
259 BOOST_CHECK_MESSAGE(last_ts < end_win, "Check last_frame_ts{" << last_ts << "} < end_win{" << end_win << "}");
260 if (objects_skipped.size() == 0)
261 BOOST_CHECK_MESSAGE(end_win <= last_ts + ticks_per_frame,
262 "end_win{" << end_win << "} <= last_frame_ts+ticks_per_frame{" << last_ts + ticks_per_frame
263 << "}");
264
265 // expected timestamps for begin of fragment and 'end' of fragment, assuming no skipping
266 auto expected_start =
267 TypeAdapter::expected_tick_difference * (uint64_t)std::floor((float)(start_win) / (float)(ticks_per_frame));
268 auto expected_end =
269 TypeAdapter::expected_tick_difference * (uint64_t)std::ceil((float)(end_win) / (float)(ticks_per_frame));
270
271 // correct for the cases there that object has been skipped
272 auto expected_start_obj = expected_start - expected_start % ticks_between;
273 while (objects_skipped.count(expected_start_obj / ticks_between) > 0 && expected_start < expected_end) {
274 expected_start += ticks_per_frame;
275 expected_start_obj = expected_start - expected_start % ticks_between;
276 }
277
278 auto expected_end_obj = expected_end - ticks_per_frame - (expected_end - ticks_per_frame) % ticks_between;
279 while (objects_skipped.count(expected_end_obj / ticks_between) > 0 &&
280 expected_end > (expected_start + ticks_per_frame)) {
281 expected_end -= ticks_per_frame;
282 expected_start_obj = expected_end - ticks_per_frame - (expected_end - ticks_per_frame) % ticks_between;
283 }
284
285 // specfic check: are values for this request what we expect
286 BOOST_CHECK_MESSAGE(first_ts == expected_start,
287 "Fragment start ts {" << first_ts << "} is expected value {" << expected_start << "}");
288 BOOST_CHECK_MESSAGE((last_ts + TypeAdapter::expected_tick_difference) == expected_end,
289 "Fragment 'end' ts {" << last_ts + TypeAdapter::expected_tick_difference
290 << "} is expected value {" << expected_end << "}");
291 }; // end test_req_bounds
292
293 /*
294 * Unskipped buffer should have elements with index [0, 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]
295 * and timestamps [0,1*T,2*T,3*T,4*T,5*T,6*T,7*T,8*T,9*T]
296 * where T = DTS ticks between successive elements (tick_diff_per_frame * n_frames_per_obj_in_buffer)
297 */
298 BOOST_TEST_MESSAGE("Testing buffer without skips...");
299 auto buffer_noskip = std::make_shared<BufferType<TypeAdapter>>();
300 fill_buffer<BufferType, TypeAdapter>(buffer_noskip, 0, 10);
301 print_buffer<BufferType, TypeAdapter>(buffer_noskip, "noskip");
302
303 test_req_bounds(buffer_noskip, ticks_between * 2, ticks_between * 5);
304 test_req_bounds(buffer_noskip, ticks_between * 3 / 2, ticks_between * 9 / 2);
305 test_req_bounds(buffer_noskip, ticks_between * 11 / 5, ticks_between * 21 / 5);
306 test_req_bounds(buffer_noskip, ticks_between * 2 + 1, ticks_between * 5 + 1);
307
308 /*
309 * Skipped buffer should have elements with index [0, 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]
310 * and timestamps [0,1*T,4*T,5*T,6*T,7*T,8*T,9*T,10*T,11*T]
311 * where T = DTS ticks between successive elements (tick_diff_per_frame * n_frames_per_obj_in_buffer)
312 */
313 BOOST_TEST_MESSAGE("Testing buffer with skips...");
314 std::set<size_t> obj_to_skip = { 2, 3 };
315 auto buffer_skip = std::make_shared<BufferType<TypeAdapter>>();
316 fill_buffer<BufferType, TypeAdapter>(buffer_skip, 0, 10, obj_to_skip);
317 print_buffer<BufferType, TypeAdapter>(buffer_skip, "skip");
318
319 test_req_bounds(buffer_skip, ticks_between * 2, ticks_between * 5, obj_to_skip);
320 test_req_bounds(buffer_skip, ticks_between * 3 / 2, ticks_between * 9 / 2, obj_to_skip);
321 if ((ticks_between * 21 / 5) > 4 * ticks_between) // protect in cases where ticks_between is very small (e.g. 1)
322 test_req_bounds(buffer_skip, ticks_between * 11 / 5, ticks_between * 21 / 5, obj_to_skip);
323 test_req_bounds(buffer_skip, ticks_between * 2 + 1, ticks_between * 5 + 1, obj_to_skip);
324
325} // end test_request_model
This message represents a request for data sent to a single component of the DAQ.