Line data Source code
1 : /**
2 : * @file ProcessorInternalStateBufferManager_test.cxx
3 : *
4 : * @copyright This is part of the DUNE DAQ Software Suite, copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 :
9 : #define BOOST_TEST_MODULE ProcessorInternalStateBufferManager_tests
10 : #define FMT_HEADER_ONLY
11 :
12 : #include "tpglibs/ProcessorInternalStateBufferManager.hpp"
13 : #include "tpglibs/ProcessorInternalStateNameRegistry.hpp"
14 :
15 : #include <boost/test/unit_test.hpp>
16 : #include <immintrin.h>
17 : #include <thread>
18 : #include <atomic>
19 : #include <vector>
20 : #include <chrono>
21 :
22 : namespace tpglibs {
23 :
24 : // =============================================================================
25 : // LIFECYCLE TESTS
26 : // =============================================================================
27 :
28 : BOOST_AUTO_TEST_SUITE(lifecycle_tests)
29 :
30 2 : BOOST_AUTO_TEST_CASE(test_construction_and_destruction)
31 : {
32 : // Test that we can construct and destroy without crashing
33 1 : ProcessorInternalStateBufferManager<__m256i> manager;
34 1 : BOOST_TEST(true); // If we reach here, construction succeeded
35 1 : }
36 :
37 2 : BOOST_AUTO_TEST_CASE(test_configure_single_item)
38 : {
39 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
40 1 : __m256i a = _mm256_set1_epi16(42);
41 1 : auto a_ptr = std::make_shared<__m256i>(a);
42 :
43 1 : registry.register_internal_state("state_a", a_ptr);
44 1 : registry.parse_requested_internal_state_items("state_a");
45 :
46 1 : ProcessorInternalStateBufferManager<__m256i> manager;
47 1 : manager.configure_from_registry(®istry);
48 :
49 : // Configuration should succeed without crash
50 1 : BOOST_TEST(true);
51 1 : }
52 :
53 2 : BOOST_AUTO_TEST_CASE(test_configure_multiple_items)
54 : {
55 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
56 :
57 1 : __m256i a = _mm256_set1_epi16(1);
58 1 : __m256i b = _mm256_set1_epi16(2);
59 1 : __m256i c = _mm256_set1_epi16(3);
60 :
61 1 : auto a_ptr = std::make_shared<__m256i>(a);
62 1 : auto b_ptr = std::make_shared<__m256i>(b);
63 1 : auto c_ptr = std::make_shared<__m256i>(c);
64 :
65 1 : registry.register_internal_state("a", a_ptr);
66 1 : registry.register_internal_state("b", b_ptr);
67 1 : registry.register_internal_state("c", c_ptr);
68 1 : registry.parse_requested_internal_state_items("a,b,c");
69 :
70 1 : ProcessorInternalStateBufferManager<__m256i> manager;
71 1 : manager.configure_from_registry(®istry);
72 :
73 1 : BOOST_TEST(true);
74 1 : }
75 :
76 2 : BOOST_AUTO_TEST_CASE(test_configure_empty_registry)
77 : {
78 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
79 : // Don't register or request any items
80 1 : registry.parse_requested_internal_state_items("");
81 :
82 1 : ProcessorInternalStateBufferManager<__m256i> manager;
83 1 : manager.configure_from_registry(®istry);
84 :
85 : // Should handle empty configuration gracefully
86 1 : BOOST_TEST(true);
87 1 : }
88 :
89 : BOOST_AUTO_TEST_SUITE_END()
90 :
91 : // =============================================================================
92 : // READ AND WRITE BEHAVIOR TESTS
93 : // =============================================================================
94 :
95 : BOOST_AUTO_TEST_SUITE(read_write_behavior_tests)
96 :
97 2 : BOOST_AUTO_TEST_CASE(test_basic_write_and_read)
98 : {
99 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
100 1 : __m256i a = _mm256_set1_epi16(100);
101 1 : auto a_ptr = std::make_shared<__m256i>(a);
102 :
103 1 : registry.register_internal_state("a", a_ptr);
104 1 : registry.parse_requested_internal_state_items("a");
105 :
106 1 : ProcessorInternalStateBufferManager<__m256i> manager;
107 1 : manager.configure_from_registry(®istry);
108 1 : manager.write_to_active_buffer();
109 :
110 1 : auto result = manager.switch_buffer_and_read();
111 :
112 1 : BOOST_TEST(result.m_size == 1);
113 1 : BOOST_REQUIRE(result.m_data != nullptr);
114 :
115 1 : int16_t out[16];
116 1 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out), result.m_data[0]);
117 :
118 17 : for (int i = 0; i < 16; i++) {
119 16 : BOOST_TEST(out[i] == 100);
120 : }
121 1 : }
122 :
123 2 : BOOST_AUTO_TEST_CASE(test_multiple_items_write_and_read)
124 : {
125 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
126 :
127 1 : __m256i a = _mm256_set1_epi16(10);
128 1 : __m256i b = _mm256_set1_epi16(20);
129 1 : __m256i c = _mm256_set1_epi16(30);
130 :
131 1 : auto a_ptr = std::make_shared<__m256i>(a);
132 1 : auto b_ptr = std::make_shared<__m256i>(b);
133 1 : auto c_ptr = std::make_shared<__m256i>(c);
134 :
135 1 : registry.register_internal_state("a", a_ptr);
136 1 : registry.register_internal_state("b", b_ptr);
137 1 : registry.register_internal_state("c", c_ptr);
138 1 : registry.parse_requested_internal_state_items("a,b,c");
139 :
140 1 : ProcessorInternalStateBufferManager<__m256i> manager;
141 1 : manager.configure_from_registry(®istry);
142 1 : manager.write_to_active_buffer();
143 :
144 1 : auto result = manager.switch_buffer_and_read();
145 :
146 1 : BOOST_TEST(result.m_size == 3);
147 1 : BOOST_REQUIRE(result.m_data != nullptr);
148 :
149 : // Check each item
150 1 : int16_t expected_values[3] = {10, 20, 30};
151 4 : for (size_t item = 0; item < 3; ++item) {
152 3 : int16_t out[16];
153 3 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out), result.m_data[item]);
154 :
155 51 : for (int i = 0; i < 16; i++) {
156 48 : BOOST_TEST(out[i] == expected_values[item]);
157 : }
158 : }
159 1 : }
160 :
161 2 : BOOST_AUTO_TEST_CASE(test_data_update_between_writes)
162 : {
163 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
164 1 : __m256i state = _mm256_set1_epi16(100);
165 1 : auto state_ptr = std::make_shared<__m256i>(state);
166 :
167 1 : registry.register_internal_state("state", state_ptr);
168 1 : registry.parse_requested_internal_state_items("state");
169 :
170 1 : ProcessorInternalStateBufferManager<__m256i> manager;
171 1 : manager.configure_from_registry(®istry);
172 :
173 : // First write
174 1 : manager.write_to_active_buffer();
175 1 : auto result1 = manager.switch_buffer_and_read();
176 :
177 1 : int16_t out1[16];
178 1 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out1), result1.m_data[0]);
179 1 : BOOST_TEST(out1[0] == 100);
180 :
181 : // Modify the state
182 1 : *state_ptr = _mm256_set1_epi16(200);
183 :
184 : // Second write
185 1 : manager.write_to_active_buffer();
186 1 : auto result2 = manager.switch_buffer_and_read();
187 :
188 1 : int16_t out2[16];
189 1 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out2), result2.m_data[0]);
190 1 : BOOST_TEST(out2[0] == 200);
191 1 : }
192 :
193 2 : BOOST_AUTO_TEST_CASE(test_multiple_consecutive_writes)
194 : {
195 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
196 1 : __m256i state = _mm256_set1_epi16(1);
197 1 : auto state_ptr = std::make_shared<__m256i>(state);
198 :
199 1 : registry.register_internal_state("state", state_ptr);
200 1 : registry.parse_requested_internal_state_items("state");
201 :
202 1 : ProcessorInternalStateBufferManager<__m256i> manager;
203 1 : manager.configure_from_registry(®istry);
204 :
205 : // Multiple writes without reads
206 6 : for (int i = 1; i <= 5; ++i) {
207 5 : *state_ptr = _mm256_set1_epi16(i * 10);
208 5 : manager.write_to_active_buffer();
209 : }
210 :
211 : // Read should get the last written value
212 1 : auto result = manager.switch_buffer_and_read();
213 :
214 1 : int16_t out[16];
215 1 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out), result.m_data[0]);
216 1 : BOOST_TEST(out[0] == 50); // Last value (5 * 10)
217 1 : }
218 :
219 2 : BOOST_AUTO_TEST_CASE(test_casted_read)
220 : {
221 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
222 1 : __m256i a = _mm256_set1_epi16(123);
223 1 : auto a_ptr = std::make_shared<__m256i>(a);
224 :
225 1 : registry.register_internal_state("a", a_ptr);
226 1 : registry.parse_requested_internal_state_items("a");
227 :
228 1 : ProcessorInternalStateBufferManager<__m256i> manager;
229 1 : manager.configure_from_registry(®istry);
230 1 : manager.write_to_active_buffer();
231 :
232 1 : auto result = manager.switch_buffer_and_read_casted();
233 :
234 1 : BOOST_TEST(result.m_size == 1);
235 1 : BOOST_REQUIRE(result.m_data != nullptr);
236 :
237 : // Check all 16 values in the array
238 17 : for (int i = 0; i < 16; i++) {
239 16 : BOOST_TEST(result.m_data[0][i] == 123);
240 : }
241 1 : }
242 :
243 2 : BOOST_AUTO_TEST_CASE(test_multiple_reads_without_write)
244 : {
245 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
246 1 : __m256i state = _mm256_set1_epi16(777);
247 1 : auto state_ptr = std::make_shared<__m256i>(state);
248 :
249 1 : registry.register_internal_state("state", state_ptr);
250 1 : registry.parse_requested_internal_state_items("state");
251 :
252 1 : ProcessorInternalStateBufferManager<__m256i> manager;
253 1 : manager.configure_from_registry(®istry);
254 1 : manager.write_to_active_buffer();
255 :
256 : // Multiple reads
257 4 : for (int i = 0; i < 3; ++i) {
258 3 : auto result = manager.switch_buffer_and_read();
259 3 : int16_t out[16];
260 3 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out), result.m_data[0]);
261 3 : BOOST_TEST(out[0] == 777);
262 : }
263 1 : }
264 :
265 : BOOST_AUTO_TEST_SUITE_END()
266 :
267 : // =============================================================================
268 : // THREAD SAFETY TESTS
269 : // =============================================================================
270 :
271 : BOOST_AUTO_TEST_SUITE(thread_safety_tests)
272 :
273 2 : BOOST_AUTO_TEST_CASE(test_concurrent_single_writer_single_reader)
274 : {
275 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
276 1 : __m256i state = _mm256_set1_epi16(0);
277 1 : auto state_ptr = std::make_shared<__m256i>(state);
278 :
279 1 : registry.register_internal_state("state", state_ptr);
280 1 : registry.parse_requested_internal_state_items("state");
281 :
282 1 : ProcessorInternalStateBufferManager<__m256i> manager;
283 1 : manager.configure_from_registry(®istry);
284 :
285 1 : std::atomic<bool> done{false};
286 1 : std::atomic<int> write_count{0};
287 1 : std::atomic<int> read_count{0};
288 :
289 : // Writer thread
290 3 : std::thread writer([&]() {
291 1001 : for (int i = 0; i < 1000; ++i) {
292 1000 : *state_ptr = _mm256_set1_epi16(i);
293 1000 : manager.write_to_active_buffer();
294 1000 : write_count++;
295 1000 : std::this_thread::sleep_for(std::chrono::microseconds(10));
296 : }
297 1 : done.store(true, std::memory_order_release);
298 2 : });
299 :
300 : // Reader thread
301 3 : std::thread reader([&]() {
302 935 : while (!done.load(std::memory_order_acquire)) {
303 934 : auto result = manager.switch_buffer_and_read();
304 934 : if (result.m_data != nullptr) {
305 934 : read_count++;
306 : }
307 934 : std::this_thread::sleep_for(std::chrono::microseconds(15));
308 : }
309 2 : });
310 :
311 1 : writer.join();
312 1 : reader.join();
313 :
314 1 : BOOST_TEST(write_count == 1000);
315 1 : BOOST_TEST(read_count > 0);
316 1 : }
317 :
318 2 : BOOST_AUTO_TEST_CASE(test_concurrent_single_writer_multiple_readers)
319 : {
320 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
321 1 : __m256i state = _mm256_set1_epi16(0);
322 1 : auto state_ptr = std::make_shared<__m256i>(state);
323 :
324 1 : registry.register_internal_state("state", state_ptr);
325 1 : registry.parse_requested_internal_state_items("state");
326 :
327 1 : ProcessorInternalStateBufferManager<__m256i> manager;
328 1 : manager.configure_from_registry(®istry);
329 :
330 1 : std::atomic<bool> done{false};
331 1 : std::atomic<int> total_reads{0};
332 1 : const int num_readers = 3;
333 :
334 : // Writer thread
335 3 : std::thread writer([&]() {
336 501 : for (int i = 0; i < 500; ++i) {
337 500 : *state_ptr = _mm256_set1_epi16(i);
338 500 : manager.write_to_active_buffer();
339 500 : std::this_thread::sleep_for(std::chrono::microseconds(20));
340 : }
341 1 : done.store(true, std::memory_order_release);
342 2 : });
343 :
344 : // Multiple reader threads
345 1 : std::vector<std::thread> readers;
346 4 : for (int r = 0; r < num_readers; ++r) {
347 6 : readers.emplace_back([&]() {
348 3 : int local_reads = 0;
349 1381 : while (!done.load(std::memory_order_acquire)) {
350 1375 : auto result = manager.switch_buffer_and_read();
351 1373 : if (result.m_data != nullptr) {
352 1373 : local_reads++;
353 : }
354 1373 : std::this_thread::sleep_for(std::chrono::microseconds(30));
355 : }
356 3 : total_reads.fetch_add(local_reads);
357 3 : });
358 : }
359 :
360 1 : writer.join();
361 4 : for (auto& reader : readers) {
362 3 : reader.join();
363 : }
364 :
365 1 : BOOST_TEST(total_reads > 0);
366 1 : }
367 :
368 2 : BOOST_AUTO_TEST_CASE(test_stress_many_operations)
369 : {
370 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
371 1 : __m256i a = _mm256_set1_epi16(0);
372 1 : __m256i b = _mm256_set1_epi16(0);
373 :
374 1 : auto a_ptr = std::make_shared<__m256i>(a);
375 1 : auto b_ptr = std::make_shared<__m256i>(b);
376 :
377 1 : registry.register_internal_state("a", a_ptr);
378 1 : registry.register_internal_state("b", b_ptr);
379 1 : registry.parse_requested_internal_state_items("a,b");
380 :
381 1 : ProcessorInternalStateBufferManager<__m256i> manager;
382 1 : manager.configure_from_registry(®istry);
383 :
384 1 : std::atomic<bool> done{false};
385 :
386 : // High-frequency writer
387 3 : std::thread writer([&]() {
388 10001 : for (int i = 0; i < 10000; ++i) {
389 10000 : *a_ptr = _mm256_set1_epi16(i % 1000);
390 10000 : *b_ptr = _mm256_set1_epi16((i * 2) % 1000);
391 10000 : manager.write_to_active_buffer();
392 : }
393 1 : done.store(true, std::memory_order_release);
394 2 : });
395 :
396 : // High-frequency reader
397 3 : std::thread reader([&]() {
398 1 : int successful_reads = 0;
399 3215 : while (!done.load(std::memory_order_acquire)) {
400 3214 : auto result = manager.switch_buffer_and_read();
401 3214 : if (result.m_data != nullptr && result.m_size == 2) {
402 3214 : successful_reads++;
403 : }
404 : }
405 1 : BOOST_TEST(successful_reads > 0);
406 2 : });
407 :
408 1 : writer.join();
409 1 : reader.join();
410 :
411 1 : BOOST_TEST(true); // Test passes if no crashes
412 1 : }
413 :
414 2 : BOOST_AUTO_TEST_CASE(test_casted_read_thread_safety)
415 : {
416 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
417 1 : __m256i state = _mm256_set1_epi16(0);
418 1 : auto state_ptr = std::make_shared<__m256i>(state);
419 :
420 1 : registry.register_internal_state("state", state_ptr);
421 1 : registry.parse_requested_internal_state_items("state");
422 :
423 1 : ProcessorInternalStateBufferManager<__m256i> manager;
424 1 : manager.configure_from_registry(®istry);
425 :
426 1 : std::atomic<bool> done{false};
427 :
428 : // Writer thread
429 3 : std::thread writer([&]() {
430 1001 : for (int i = 0; i < 1000; ++i) {
431 1000 : *state_ptr = _mm256_set1_epi16(i);
432 1000 : manager.write_to_active_buffer();
433 1000 : std::this_thread::sleep_for(std::chrono::microseconds(10));
434 : }
435 1 : done.store(true, std::memory_order_release);
436 2 : });
437 :
438 : // Reader using casted read
439 3 : std::thread reader([&]() {
440 1 : int successful_reads = 0;
441 928 : while (!done.load(std::memory_order_acquire)) {
442 927 : auto result = manager.switch_buffer_and_read_casted();
443 927 : if (result.m_data != nullptr) {
444 927 : successful_reads++;
445 : }
446 927 : std::this_thread::sleep_for(std::chrono::microseconds(15));
447 : }
448 1 : BOOST_TEST(successful_reads > 0);
449 2 : });
450 :
451 1 : writer.join();
452 1 : reader.join();
453 :
454 1 : BOOST_TEST(true);
455 1 : }
456 :
457 : BOOST_AUTO_TEST_SUITE_END()
458 :
459 : // =============================================================================
460 : // EDGE CASE TESTS
461 : // =============================================================================
462 :
463 : BOOST_AUTO_TEST_SUITE(edge_case_tests)
464 :
465 2 : BOOST_AUTO_TEST_CASE(test_read_before_any_write)
466 : {
467 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
468 1 : __m256i state = _mm256_set1_epi16(555);
469 1 : auto state_ptr = std::make_shared<__m256i>(state);
470 :
471 1 : registry.register_internal_state("state", state_ptr);
472 1 : registry.parse_requested_internal_state_items("state");
473 :
474 1 : ProcessorInternalStateBufferManager<__m256i> manager;
475 1 : manager.configure_from_registry(®istry);
476 :
477 : // Read without writing first - should not crash
478 1 : auto result = manager.switch_buffer_and_read();
479 1 : BOOST_TEST(result.m_data != nullptr);
480 1 : }
481 :
482 2 : BOOST_AUTO_TEST_CASE(test_alternating_write_read_pattern)
483 : {
484 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
485 1 : __m256i state = _mm256_set1_epi16(0);
486 1 : auto state_ptr = std::make_shared<__m256i>(state);
487 :
488 1 : registry.register_internal_state("state", state_ptr);
489 1 : registry.parse_requested_internal_state_items("state");
490 :
491 1 : ProcessorInternalStateBufferManager<__m256i> manager;
492 1 : manager.configure_from_registry(®istry);
493 :
494 : // Alternating write-read pattern
495 11 : for (int i = 0; i < 10; ++i) {
496 10 : *state_ptr = _mm256_set1_epi16(i * 10);
497 10 : manager.write_to_active_buffer();
498 :
499 10 : auto result = manager.switch_buffer_and_read();
500 10 : int16_t out[16];
501 10 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out), result.m_data[0]);
502 10 : BOOST_TEST(out[0] == i * 10);
503 : }
504 1 : }
505 :
506 2 : BOOST_AUTO_TEST_CASE(test_rapid_buffer_switching)
507 : {
508 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
509 1 : __m256i state = _mm256_set1_epi16(999);
510 1 : auto state_ptr = std::make_shared<__m256i>(state);
511 :
512 1 : registry.register_internal_state("state", state_ptr);
513 1 : registry.parse_requested_internal_state_items("state");
514 :
515 1 : ProcessorInternalStateBufferManager<__m256i> manager;
516 1 : manager.configure_from_registry(®istry);
517 1 : manager.write_to_active_buffer();
518 :
519 : // Rapid consecutive reads (buffer switches)
520 101 : for (int i = 0; i < 100; ++i) {
521 100 : auto result = manager.switch_buffer_and_read();
522 100 : BOOST_TEST(result.m_data != nullptr);
523 100 : BOOST_TEST(result.m_size == 1);
524 : }
525 1 : }
526 :
527 2 : BOOST_AUTO_TEST_CASE(test_partial_item_selection)
528 : {
529 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
530 :
531 1 : __m256i a = _mm256_set1_epi16(10);
532 1 : __m256i b = _mm256_set1_epi16(20);
533 1 : __m256i c = _mm256_set1_epi16(30);
534 :
535 1 : auto a_ptr = std::make_shared<__m256i>(a);
536 1 : auto b_ptr = std::make_shared<__m256i>(b);
537 1 : auto c_ptr = std::make_shared<__m256i>(c);
538 :
539 1 : registry.register_internal_state("a", a_ptr);
540 1 : registry.register_internal_state("b", b_ptr);
541 1 : registry.register_internal_state("c", c_ptr);
542 :
543 : // Only request a subset of registered items
544 1 : registry.parse_requested_internal_state_items("a,c");
545 :
546 1 : ProcessorInternalStateBufferManager<__m256i> manager;
547 1 : manager.configure_from_registry(®istry);
548 1 : manager.write_to_active_buffer();
549 :
550 1 : auto result = manager.switch_buffer_and_read();
551 :
552 : // Should only have 2 items (a and c)
553 1 : BOOST_TEST(result.m_size == 2);
554 :
555 1 : int16_t out0[16], out1[16];
556 1 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out0), result.m_data[0]);
557 1 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out1), result.m_data[1]);
558 :
559 1 : BOOST_TEST(out0[0] == 10); // a
560 1 : BOOST_TEST(out1[0] == 30); // c
561 1 : }
562 :
563 2 : BOOST_AUTO_TEST_CASE(test_large_number_of_items)
564 : {
565 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
566 :
567 1 : const int num_items = 20;
568 1 : std::vector<std::shared_ptr<__m256i>> ptrs;
569 1 : std::string request_string;
570 :
571 21 : for (int i = 0; i < num_items; ++i) {
572 20 : __m256i val = _mm256_set1_epi16(i * 100);
573 20 : auto ptr = std::make_shared<__m256i>(val);
574 20 : ptrs.push_back(ptr);
575 :
576 20 : std::string name = "state_" + std::to_string(i);
577 20 : registry.register_internal_state(name, ptr);
578 :
579 20 : if (i > 0) request_string += ",";
580 20 : request_string += name;
581 20 : }
582 :
583 1 : registry.parse_requested_internal_state_items(request_string);
584 :
585 1 : ProcessorInternalStateBufferManager<__m256i> manager;
586 1 : manager.configure_from_registry(®istry);
587 1 : manager.write_to_active_buffer();
588 :
589 1 : auto result = manager.switch_buffer_and_read();
590 :
591 1 : BOOST_TEST(result.m_size == num_items);
592 :
593 : // Verify each item
594 21 : for (int i = 0; i < num_items; ++i) {
595 20 : int16_t out[16];
596 20 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out), result.m_data[i]);
597 20 : BOOST_TEST(out[0] == i * 100);
598 : }
599 1 : }
600 :
601 2 : BOOST_AUTO_TEST_CASE(test_data_consistency_after_multiple_switches)
602 : {
603 1 : ProcessorInternalStateNameRegistry<__m256i> registry;
604 1 : __m256i state = _mm256_set1_epi16(12345);
605 1 : auto state_ptr = std::make_shared<__m256i>(state);
606 :
607 1 : registry.register_internal_state("state", state_ptr);
608 1 : registry.parse_requested_internal_state_items("state");
609 :
610 1 : ProcessorInternalStateBufferManager<__m256i> manager;
611 1 : manager.configure_from_registry(®istry);
612 :
613 : // Write once
614 1 : manager.write_to_active_buffer();
615 :
616 : // Multiple reads - data should remain consistent
617 6 : for (int i = 0; i < 5; ++i) {
618 5 : auto result = manager.switch_buffer_and_read();
619 5 : int16_t out[16];
620 5 : _mm256_storeu_si256(reinterpret_cast<__m256i*>(&out), result.m_data[0]);
621 5 : BOOST_TEST(out[0] == 12345);
622 : }
623 1 : }
624 :
625 : BOOST_AUTO_TEST_SUITE_END()
626 :
627 : } // namespace tpglibs
628 :
|