μHAL (v2.8.17)
Part of the IPbus software repository
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
PerfTester_static.cpp
Go to the documentation of this file.
1/*
2---------------------------------------------------------------------------
3
4 This file is part of uHAL.
5
6 uHAL is a hardware access library and programming framework
7 originally developed for upgrades of the Level-1 trigger of the CMS
8 experiment at CERN.
9
10 uHAL is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 uHAL is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with uHAL. If not, see <http://www.gnu.org/licenses/>.
22
23 Marc Magrans de Abril, CERN
24 email: marc.magrans.de.abril <AT> cern.ch
25
26 Andrew Rose, Imperial College, London
27 email: awr01 <AT> imperial.ac.uk
28
29 Tom Williams, Rutherford Appleton Laboratory, Oxfordshire
30 email: tom.williams <AT> cern.ch
31
32---------------------------------------------------------------------------
33*/
34
36
37// C++ headers
38#include <iostream>
39#include <iomanip>
40#include <sstream>
41#include <cstdlib>
42#include <unistd.h>
43
44// Boost headers
45#include <boost/program_options.hpp>
46#include <boost/mem_fn.hpp>
47
48// uHAL headers
50#include "uhal/tests/tools.hpp"
51
52// Namespace resolution
53using namespace std;
54
55
56
57
58uint32_t uhal::tests::PerfTester::getRandomBlockSize ( const uint32_t maxSize )
59{
60 // Generate uniformly-distributed random float in range: 0 <= x < 1
61 const double uniformRandom = static_cast<double> ( rand() ) / RAND_MAX; //TODO -- replace with boost::random random-double-generating function
62 // Transform to 1/x distributed random float in range: 0.5 <= x < maxSize+1
63 const double inverseRandom = 0.5 * pow ( static_cast<double> ( ( maxSize+1 ) / 0.5 ) , uniformRandom );
64 uint32_t retVal = static_cast<uint32_t>( floor(inverseRandom) );
65
66 if ( retVal > maxSize )
67 {
68 log ( Warning(), "Random block size (", Integer(retVal), ") is larger than maxSize (" , Integer(retVal) , ") ...\n",
69 " * uniformRandom=", uniformRandom, "\n",
70 " * inverseRandom=", inverseRandom, "\n",
71 "Correcting block size as temporary fix." );
72 retVal = maxSize;
73 }
74
75 // Floor the float to get integer with desired distribution
76 return retVal;
77}
78
79
81{
83 buffer.reserve ( size );
84
85 // Never said anything about it being a flat random distribution... ;-)
86 for ( unsigned i = 0 ; i < size ; ++i )
87 {
88 buffer.push_back ( rand() + rand() );
89 }
90
91 return buffer;
92}
93
94
95// Validation test -- single-register write/read-back
96bool uhal::tests::PerfTester::validation_test_single_write_read ( ClientInterface& c, const uint32_t addr, const bool perTransactionDispatch, const bool aVerbose )
97{
98 std::ostringstream oss_details;
99 oss_details << "Single-register write-read @ 0x" << std::hex << addr << ( perTransactionDispatch ? " (multiple dispatches)" : " (single dispatch)" );
100
101 if ( aVerbose )
102 {
103 cout << oss_details.str() << endl;
104 }
105
106 const uint32_t x = rand();
107
108 try
109 {
110 c.write ( addr, x );
111
112 if ( perTransactionDispatch )
113 {
114 c.dispatch();
115 }
116
118 c.dispatch();
119
120 if ( x != reg.value() )
121 {
122 cout << "TEST FAILED: " << oss_details.str() << ". Wrote value 0x" << std::hex << x << " but read-back 0x" << reg.value() << std::dec << endl;
123 return false;
124 }
125 }
126 catch ( const std::exception& e )
127 {
128 cout << "TEST FAILED: " << oss_details.str() << ". Exception of type '" << typeid ( e ).name() << "' thrown ..." << endl << e.what() << endl;
129 return false;
130 }
131
132 return true;
133}
134
135
136// Validation test -- block write/read-back
137bool uhal::tests::PerfTester::validation_test_block_write_read ( ClientInterface& c, const uint32_t addr, const uint32_t depth, const bool perTransactionDispatch, const bool aVerbose )
138{
139 std::ostringstream oss_details;
140 oss_details << depth << "-word write-read @ 0x" << std::hex << addr;
141
142 if ( depth>1 )
143 {
144 oss_details << " to 0x" << addr+depth-1 << std::dec;
145 }
146
147 oss_details << ( perTransactionDispatch ? " (multiple dispatches)" : " (single dispatch)" );
148
149 if ( aVerbose )
150 {
151 cout << "Running test: " << oss_details.str() << endl;
152 }
153
154 const U32Vec xx = getRandomBuffer ( depth );
155
156 try
157 {
158 c.writeBlock ( addr, xx );
159
160 if ( perTransactionDispatch )
161 {
162 c.dispatch();
163 }
164
165 U32ValVec ram = c.readBlock ( addr, depth );
166 c.dispatch();
167 std::vector<uint32_t>::const_iterator valVecIt = ram.begin();
168 std::vector<uint32_t>::const_iterator xxIt = xx.begin();
169
170 for ( ; valVecIt != ram.end(); valVecIt++, xxIt++ )
171 {
172 if ( ( *valVecIt ) != ( *xxIt ) )
173 {
174 uint32_t reg_addr = addr + ( valVecIt - ram.begin() );
175 cout << "TEST FAILED: " << oss_details.str() << ". Wrote value Ox" << std::hex << *xxIt << " to register 0x" << reg_addr << " but read-back 0x" << *valVecIt << std::dec << std::endl;
176 return false;
177 }
178 }
179
180 log ( Notice(), "TEST PASSED: ", oss_details.str() );
181 }
182 catch ( const std::exception& e )
183 {
184 cout << "TEST FAILED: " << oss_details.str() << "! EXCEPTION of type '" << typeid ( e ).name() << "' thrown ..." << endl << e.what() << endl;
185 return false;
186 }
187
188 return true;
189}
190
191
192// Validation test -- write, RMW bits, read
193bool uhal::tests::PerfTester::validation_test_write_rmwbits_read ( ClientInterface& c, const uint32_t addr, const bool perTransactionDispatch, const bool aVerbose )
194{
195 std::ostringstream oss_details;
196 oss_details << "RMW-bits @ 0x" << std::hex << addr << ( perTransactionDispatch ? " (multiple dispatches)" : " (single dispatch)" );
197
198 if ( aVerbose )
199 {
200 cout << "TESTING: " << oss_details.str() << endl;
201 }
202
203 const uint32_t x0 = rand();
204
205 const uint32_t a = rand();
206
207 const uint32_t b = rand();
208
209 const uint32_t x1 = ( x0 & a ) | b;
210
211 std::ostringstream oss_values;
212
213 oss_values << "Wrote value 0x" << std::hex << x0 << ", then did RMW-bits with AND-term 0x" << a << ", OR-term 0x" << b;
214
215 const bool ipbus2 = ( ( c.uri().find ( "ipbusudp-2.0" ) != string::npos ) || ( c.uri().find ( "ipbustcp-2.0" ) != string::npos ) || ( c.uri().find ( "chtcp-2.0" ) != string::npos ) || ( c.uri().find ( "ipbuspcie-2.0" ) != string::npos ) || ( c.uri().find ( "ipbusmmap-2.0" ) != string::npos ) );
216
217 try
218 {
219 c.write ( addr, x0 );
220
221 if ( perTransactionDispatch )
222 {
223 c.dispatch();
224 }
225
226 ValWord<uint32_t> reg_rmw = c.rmw_bits ( addr, a, b );
227 c.dispatch();
228
229 if ( ipbus2 ? ( x0 != reg_rmw.value() ) : ( x1 != reg_rmw.value() ) )
230 {
231 cout << "TEST FAILED: " << oss_details.str() << " ... RMW-bits returned value 0x" << std::hex << reg_rmw.value() << ", but expected 0x" << ( ipbus2 ? x0 : x1 ) << std::dec << endl << oss_values.str() << endl;
232 return false;
233 }
234
235 ValWord<uint32_t> reg_read = c.read ( addr );
236 c.dispatch();
237
238 if ( x1 != reg_read.value() )
239 {
240 cout << "TEST FAILED: " << oss_details.str() << " ... Read after RMW-bits returned value 0x" << std::hex << reg_read.value() << ", but expected 0x" << x1 << std::dec << endl << oss_values.str() << endl;
241 return false;
242 }
243 }
244 catch ( const std::exception& e )
245 {
246 cout << "TEST FAILED: " << oss_values.str() << ". Exception of type '" << typeid ( e ).name() << "' thrown ..." << endl << e.what() << endl;
247 return false;
248 }
249
250 return true;
251}
252
253// Validation test -- write, RMW sum, read
254bool uhal::tests::PerfTester::validation_test_write_rmwsum_read ( ClientInterface& c, const uint32_t addr, const bool perTransactionDispatch, const bool aVerbose )
255{
256 std::ostringstream oss_details;
257 oss_details << "RMW-sum @ 0x" << std::hex << addr << ( perTransactionDispatch ? " (multiple dispatches)" : " (single dispatch)" );
258
259 if ( aVerbose )
260 {
261 cout << "TESTING: " << oss_details.str() << endl;
262 }
263
264 const uint32_t x0 = rand();
265
266 const uint32_t a = rand();
267
268 const uint32_t x1 = x0 + a;
269
270 std::ostringstream oss_values;
271
272 oss_values << "Wrote value 0x" << std::hex << x0 << ", then did RMW-sum with ADDEND 0x" << a;
273
274 const bool ipbus2 = ( ( c.uri().find ( "ipbusudp-2.0" ) != string::npos ) || ( c.uri().find ( "ipbustcp-2.0" ) != string::npos ) || ( c.uri().find ( "chtcp-2.0" ) != string::npos ) || ( c.uri().find ( "ipbuspcie-2.0" ) != string::npos ) || ( c.uri().find ( "ipbusmmap-2.0" ) != string::npos ) );
275
276 try
277 {
278 c.write ( addr, x0 );
279
280 if ( perTransactionDispatch )
281 {
282 c.dispatch();
283 }
284
285 ValWord<uint32_t> reg_sum = c.rmw_sum ( addr, a );
286 c.dispatch();
287
288 if ( ipbus2 ? ( x0 != reg_sum.value() ) : ( x1 != reg_sum.value() ) )
289 {
290 cout << "TEST FAILED: " << oss_details.str() << " ... RMW-sum returned value 0x" << std::hex << reg_sum.value() << ", but expected 0x" << ( ipbus2 ? x0 : x1 ) << std::dec << endl << oss_values.str() << endl;
291 return false;
292 }
293
294 ValWord<uint32_t> reg_read = c.read ( addr );
295 c.dispatch();
296
297 if ( x1 != reg_read.value() )
298 {
299 cout << "TEST FAILED: " << oss_details.str() << " ... Read after RMW-sum returned value 0x" << std::hex << reg_read.value() << ", but expected 0x" << x1 << std::dec << endl << oss_values.str() << endl;
300 return false;
301 }
302 }
303 catch ( const std::exception& e )
304 {
305 cout << "TEST FAILED: " << oss_values.str() << ". Exception of type '" << typeid ( e ).name() << "' thrown ..." << endl << e.what() << endl;
306 return false;
307 }
308
309 return true;
310}
311
312
313bool uhal::tests::PerfTester::runValidationTest(const std::vector<ClientInterface*>& aClients, const uint32_t aBaseAddr, const uint32_t aDepth, const size_t aNrIterations, const bool aDispatchEachIteration, const bool aVerbose)
314{
315 unsigned nrTestsFailed = 0;
316 unsigned nrTestsTotal = 0;
317
318 // ---> A) Write read-back tests
319 //
320 typedef std::vector<ClientInterface*>::const_iterator ClientIt_t;
321 for ( ClientIt_t clientIt = aClients.begin(); clientIt != aClients.end(); clientIt++ )
322 {
323 ClientInterface* client = *clientIt;
324 cout << "\n\nWRITE READ-BACK TESTS for device at '" << client->uri() << "'" << endl;
325 vector<uint32_t> addr_vec;
326 addr_vec.push_back ( aBaseAddr );
327 addr_vec.push_back ( aBaseAddr + aDepth - 1 );
328
329 for ( unsigned i = 0; i < 2498; i++ )
330 {
331 addr_vec.push_back ( aBaseAddr + ( rand() % aDepth ) );
332 }
333
334 cout << "\n 1. Single-register write/read (" << addr_vec.size() * 2 << " tests)" << endl;
335
336 for ( unsigned i = 0; i < addr_vec.size(); i++ )
337 {
338 nrTestsTotal++;
339
340 if ( ! validation_test_single_write_read ( *client, addr_vec.at ( i ), true, aVerbose ) )
341 {
342 nrTestsFailed++;
343 std::exit(1);
344 }
345
346 nrTestsTotal++;
347
348 if ( ! validation_test_single_write_read ( *client, addr_vec.at ( i ), false || aDispatchEachIteration, aVerbose ) )
349 {
350 nrTestsFailed++;
351 std::exit(1);
352 }
353 }
354
355 cout << "\n 2. Block write/read (" << addr_vec.size() * 2 << " tests)" << endl;
356
357 for ( unsigned i = 0; i < addr_vec.size(); i++ )
358 {
359 uint32_t addr = addr_vec.at ( i );
360 uint32_t max_depth = aBaseAddr + aDepth - addr;
361 uint32_t depth = rand() % ( max_depth + 1 );
362
363 nrTestsTotal++;
364
365 if ( ! validation_test_block_write_read ( *client, addr, depth, true, aVerbose ) )
366 {
367 nrTestsFailed++;
368 std::exit(1);
369 }
370
371 nrTestsTotal++;
372
373 if ( ! validation_test_block_write_read ( *client, addr, depth, false || aDispatchEachIteration, aVerbose ) )
374 {
375 nrTestsFailed++;
376 std::exit(1);
377 }
378 }
379
380 cout << "\n 3. Testing RMW-bits (write, RMWbits, read; " << addr_vec.size() * 2 << " tests)" << endl;
381
382 for ( std::vector<uint32_t>::const_iterator it = addr_vec.begin(); it != addr_vec.end(); it++ )
383 {
384 nrTestsTotal++;
385
386 if ( ! validation_test_write_rmwbits_read ( *client, *it, true, aVerbose ) )
387 {
388 nrTestsFailed++;
389 std::exit(1);
390 }
391
392 nrTestsTotal++;
393
394 if ( ! validation_test_write_rmwbits_read ( *client, *it, false || aDispatchEachIteration, aVerbose ) )
395 {
396 nrTestsFailed++;
397 std::exit(1);
398 }
399 }
400
401 cout << "\n 4. Testing RMW-sum (write, RMW-sum, read; " << addr_vec.size() * 2 << " tests)" << endl;
402
403 for ( std::vector<uint32_t>::const_iterator it = addr_vec.begin(); it != addr_vec.end(); it++ )
404 {
405 nrTestsTotal++;
406
407 if ( ! validation_test_write_rmwsum_read ( *client, *it, true, aVerbose ) )
408 {
409 nrTestsFailed++;
410 std::exit(1);
411 }
412
413 nrTestsTotal++;
414
415 if ( ! validation_test_write_rmwsum_read ( *client, *it, false || aDispatchEachIteration, aVerbose ) )
416 {
417 nrTestsFailed++;
418 std::exit(1);
419 }
420 }
421 }//end: for, m_clients
422
423 if ( nrTestsFailed == 0 )
424 {
425 cout << "\n\nBASIC TESTS SUMMARY: All " << nrTestsTotal << " tests passed!" << endl << endl << endl;
426 }
427 else
428 {
429 cout << "\n\nBASIC TESTS SUMMARY: Total of " << nrTestsTotal << " tests run -- " << nrTestsFailed << " tests FAILED , " << ( nrTestsTotal - nrTestsFailed ) << " tests PASSED" << endl;
430 return false;
431 }
432
433 // ---> B) SOAK TESTs
434 //
435 for ( ClientIt_t clientIt = aClients.begin(); clientIt != aClients.end(); clientIt++ )
436 {
437 ClientInterface* client = *clientIt;
438 cout << "\nSOAK TEST to device '" << client->uri() << "'\n Random sequence of " << aNrIterations << " transactions will be sent to hardware" << endl << endl;
439 // Setup
440 uint32_t ipbus_vsn;
441 size_t found = client->uri().find ( "-1.3" );
442
443 if ( found!=std::string::npos )
444 {
445 ipbus_vsn = 1;
446 }
447 else
448 {
449 found = client->uri().find ( "-2.0" );
450
451 if ( found!=std::string::npos )
452 {
453 ipbus_vsn = 2;
454 }
455 else
456 {
457 log ( Error() , "Cannot deduce protocol from URI " , Quote ( client->uri() ), " Exiting before performing soak test." );
458 return false;
459 }
460 }
461
462 // Initialise registers to 0x0
463 std::vector< uint32_t > registers ( aDepth , 0x00000000 );
464 client->writeBlock ( aBaseAddr, registers );
465 client->dispatch();
466 // ACTUAL MEAT OF SOAK TEST
467 uint32_t type, addr, blockSize;
468 uint32_t tempUInt1, tempUInt2;
469 vector< std::shared_ptr<QueuedTransaction> > queuedTransactions;
470 uint32_t nrQueuedWords = 0;
471
472 for ( unsigned i = 1; i <= aNrIterations; i++ )
473 {
474 type = ( rand() % 4 );
475 addr = aBaseAddr + ( rand() % aDepth );
476
477 switch ( type )
478 {
479 case 0: // read
480 {
481 blockSize = getRandomBlockSize ( aBaseAddr + aDepth - addr );
482 log ( Notice(), "Soak test - queueing: ", Integer ( blockSize ), "-word read at ", Integer ( addr, IntFmt<hex,fixed>() ) );
483
485 queuedTransactions.push_back ( std::shared_ptr<QueuedTransaction> ( new QueuedBlockRead ( addr, result, registers.begin() + ( addr - aBaseAddr ) ) ) );
486 nrQueuedWords += blockSize;
487 break;
488 }
489 case 1: // write
490 {
491 blockSize = getRandomBlockSize ( aBaseAddr + aDepth - addr );
492 log ( Notice(), "Soak test - queueing: ", Integer ( blockSize ), "-word write at ", Integer ( addr, IntFmt<hex,fixed>() ) );
493
494 vector<uint32_t> randomData = getRandomBuffer ( blockSize );
495 ValHeader result = client->writeBlock ( addr, randomData, defs::INCREMENTAL );
496 std::copy ( randomData.begin(), randomData.end(), registers.begin() + ( addr - aBaseAddr ) );
497 queuedTransactions.push_back ( std::shared_ptr<QueuedTransaction> ( new QueuedBlockWrite ( addr, blockSize, result ) ) );
498 nrQueuedWords += blockSize;
499 break;
500 }
501 case 2: // RMW-bits
502 {
503 log ( Notice(), "Soak test - queueing: RMW-bits at ", Integer ( addr, IntFmt<hex,fixed>() ) );
504 tempUInt1 = rand();
505 tempUInt2 = rand();
506 vector<uint32_t>::iterator regIt = registers.begin() + ( addr - aBaseAddr );
507
508 if ( ipbus_vsn == 1 )
509 {
510 *regIt &= tempUInt1;
511 *regIt |= tempUInt2;
512 }
513
514 ValWord<uint32_t> result = client->rmw_bits ( addr, tempUInt1, tempUInt2 );
515 queuedTransactions.push_back ( std::shared_ptr<QueuedTransaction> ( new QueuedRmwBits ( addr, tempUInt1, tempUInt2, result, *regIt ) ) );
516 nrQueuedWords += 1;
517
518 if ( ipbus_vsn == 2 )
519 {
520 *regIt &= tempUInt1;
521 *regIt |= tempUInt2;
522 }
523
524 break;
525 }
526 case 3: // RMW-sum
527 {
528 log ( Notice(), "Soak test - queueing: RMW-sum at ", Integer ( addr, IntFmt<hex,fixed>() ) );
529 tempUInt1 = rand();
530 vector<uint32_t>::iterator regIt = registers.begin() + ( addr - aBaseAddr );
531
532 if ( ipbus_vsn == 1 )
533 {
534 *regIt += tempUInt1;
535 }
536
537 ValWord<uint32_t> result = client->rmw_sum ( addr, tempUInt1 );
538 queuedTransactions.push_back ( std::shared_ptr<QueuedTransaction> ( new QueuedRmwSum ( addr, tempUInt1, result, *regIt ) ) );
539 nrQueuedWords += 1;
540
541 if ( ipbus_vsn == 2 )
542 {
543 *regIt += tempUInt1;
544 }
545
546 break;
547 }
548 }
549
550 if ( aDispatchEachIteration || ( nrQueuedWords > 20000000 ) || ( i == aNrIterations ) )
551 {
552 log ( Notice(), "Soak test - issuing dispatch" );
553 client->dispatch();
554 log ( Notice(), "Soak test - issuing empty dispatch" );
555 client->dispatch();
556
557 for ( vector< std::shared_ptr<QueuedTransaction> >::const_iterator it = queuedTransactions.begin(); it != queuedTransactions.end(); it++ )
558 {
559 if ( ! ( *it )->check_values() )
560 {
561 cout << "ERROR OCCURED IN SOAK TEST to '" << client->uri() << "' - after " << i << " successful transactions" << endl;
562 return false;
563 }
564 }
565
566 queuedTransactions.clear();
567 nrQueuedWords = 0;
568
569 if ( ! aVerbose )
570 {
571 std::cout << "No errors after " << i << " transactions -- " << setiosflags ( ios::fixed ) << setprecision ( 1 ) << ( 100.0 * i ) / aNrIterations << "% done\r";
572 std::cout.flush();
573 }
574 }
575 }
576 }//end: for, aClients
577
578 cout << endl << "Reached end of soak testing successfully!" << endl;
579 return true;
580}
581
582
583// PerfTester::QueuedBlockRead MEMBER FUNCTIONS
584
585uhal::tests::PerfTester::QueuedBlockRead::QueuedBlockRead ( const uint32_t addr, const ValVector<uint32_t>& valVector, std::vector<uint32_t>::const_iterator expectedValuesIt ) :
586 m_depth ( valVector.size() ),
587 m_addr ( addr ),
588 m_valVector ( valVector )
589{
590 m_expected.assign ( expectedValuesIt, expectedValuesIt + m_depth );
591}
592
594{ }
595
597{
598 std::vector<uint32_t>::const_iterator valVecIt = m_valVector.begin();
599 std::vector<uint32_t>::const_iterator expdIt = m_expected.begin();
600
601 for ( ; valVecIt != m_valVector.end(); valVecIt++, expdIt++ )
602 {
603 if ( ( *valVecIt ) != ( *expdIt ) )
604 {
605 uint32_t addr = m_addr + ( valVecIt - m_valVector.begin() );
606 log ( Error(), "TEST FAILED: In ", Integer ( m_depth ), "-word read @ ", Integer ( m_addr, IntFmt<hex,fixed>() ), ", register ", Integer ( addr, IntFmt<hex,fixed>() ), " has value ", Integer ( *valVecIt, IntFmt<hex,fixed>() ), ", but expected value ", Integer ( *expdIt, IntFmt<hex,fixed>() ) );
607 return false;
608 }
609 }
610
611 log ( Notice(), "TEST PASSED: Incrementing ", Integer ( m_depth ), "-word read @ ", Integer ( m_addr, IntFmt<hex,fixed>() ), " --> ", Integer ( m_addr + m_depth - 1, IntFmt<hex,fixed>() ) );
612 return true;
613}
614
615
616// PerfTester::QueuedBlockWrite MEMBER FUNCTIONS
617
618uhal::tests::PerfTester::QueuedBlockWrite::QueuedBlockWrite ( const uint32_t addr, const uint32_t depth, const ValHeader& valHeader ) :
619 m_depth ( depth ),
620 m_addr ( addr ),
621 m_valHeader ( valHeader )
622{ }
623
625{ }
626
628{
629 if ( ! m_valHeader.valid() )
630 {
631 log ( Error(), "TEST FAILED: Incrementing ", Integer ( m_depth ), "-word write @ ", Integer ( m_addr, IntFmt<hex,fixed>() ), " unsuccessful." );
632 return false;
633 }
634
635 log ( Notice(), "TEST PASSED: Incrementing ", Integer ( m_depth ), "-word write @ ", Integer ( m_addr, IntFmt<hex,fixed>() ), " --> ", Integer ( m_addr + m_depth - 1, IntFmt<hex,fixed>() ) );
636 return true;
637}
638
639
640// PerfTester::QueuedRmwBits MEMBER FUNCTIONS
641
642uhal::tests::PerfTester::QueuedRmwBits::QueuedRmwBits ( const uint32_t addr, const uint32_t a, const uint32_t b, const ValWord<uint32_t>& valWord, const uint32_t expected ) :
643 m_addr ( addr ),
644 m_and ( a ),
645 m_or ( b ),
646 m_valWord ( valWord ),
647 m_expected ( expected )
648{ }
649
651{ }
652
654{
655 if ( m_valWord.value() != m_expected )
656 {
657 log ( Error(), "TEST FAILED: RMW-bits @ ", Integer ( m_addr, IntFmt<hex,fixed>() ), " (AND=", Integer ( m_and, IntFmt<hex,fixed>() ), ", OR=", Integer ( m_or, IntFmt<hex,fixed>() ), "). Transaction returned ", Integer ( m_valWord.value(), IntFmt<hex,fixed>() ), ", but expected ", Integer ( m_expected, IntFmt<hex,fixed>() ) );
658 return false;
659 }
660
661 log ( Notice(), "TEST PASSED: RMW-bits @ ", Integer ( m_addr, IntFmt<hex,fixed>() ) );
662 return true;
663}
664
665
666// PerfTester::QueuedRmwSum MEMBER FUNCTIONS
667
668uhal::tests::PerfTester::QueuedRmwSum::QueuedRmwSum ( const uint32_t addr, const uint32_t a, const ValWord<uint32_t>& valWord, const uint32_t expected ) :
669 m_addr ( addr ),
670 m_addend ( a ),
671 m_valWord ( valWord ),
672 m_expected ( expected )
673{ }
674
676{ }
677
679{
680 if ( m_valWord.value() != m_expected )
681 {
682 log ( Error(), "TEST FAILED: RMW-sum @ ", Integer ( m_addr, IntFmt<hex,fixed>() ), ", ADDEND=", Integer ( m_addend, IntFmt<hex,fixed>() ), ". Transaction returned ", Integer ( m_valWord.value(), IntFmt<hex,fixed>() ), ", but I expected ", Integer ( m_expected, IntFmt<>() ) );
683 return false;
684 }
685
686 log ( Notice(), "TEST PASSED: RMW-sum @ ", Integer ( m_addr, IntFmt<hex,fixed>() ) );
687 return true;
688}
Definition: pytypes.h:1167
An abstract base class for defining the interface to the various IPbus clients as well as providing t...
ValHeader write(const uint32_t &aAddr, const uint32_t &aValue)
Write a single, unmasked word to a register.
ValHeader writeBlock(const uint32_t &aAddr, const std::vector< uint32_t > &aValues, const defs::BlockReadWriteMode &aMode=defs::INCREMENTAL)
Write a block of data to a block of registers or a block-write port.
void dispatch()
Method to dispatch all queued transactions, and wait until all corresponding responses have been rece...
ValWord< uint32_t > rmw_bits(const uint32_t &aAddr, const uint32_t &aANDterm, const uint32_t &aORterm)
Read the value of a register, apply the AND-term, apply the OR-term, set the register to this new val...
ValWord< uint32_t > rmw_sum(const uint32_t &aAddr, const int32_t &aAddend)
Read the value of a register, add the addend, set the register to this new value and return a copy of...
ValVector< uint32_t > readBlock(const uint32_t &aAddr, const uint32_t &aSize, const defs::BlockReadWriteMode &aMode=defs::INCREMENTAL)
Read a block of unsigned data from a block of registers or a block-read port.
ValWord< uint32_t > read(const uint32_t &aAddr)
Read a single, unmasked, unsigned word.
const std::string & uri() const
Return the url of the target for this client.
A class which wraps a single word of data and marks whether or not it is valid.
Definition: ValMem.hpp:147
A class which wraps a block of data and marks whether or not it is valid.
Definition: ValMem.hpp:273
const_iterator begin() const
If the memory has previously been marked as valid, return a const iterator to the beginning of the un...
Definition: ValMem.cpp:311
void push_back(const T &aValue)
If the memory has not previously been marked as valid, add an entry to the end of it.
Definition: ValMem.cpp:232
const_iterator end() const
If the memory has previously been marked as valid, return a const iterator to the end (one past last ...
Definition: ValMem.cpp:327
A class which wraps a single word of data and marks whether or not it is valid.
Definition: ValMem.hpp:189
T value() const
Return the value of the validated memory with check on validity.
Definition: ValMem.cpp:141
QueuedBlockRead(const uint32_t addr, const ValVector< uint32_t > &valVector, std::vector< uint32_t >::const_iterator expectedValuesIt)
QueuedBlockWrite(const uint32_t addr, const uint32_t depth, const ValHeader &valHeader)
QueuedRmwBits(const uint32_t addr, const uint32_t a, const uint32_t b, const ValWord< uint32_t > &valWord, const uint32_t expected)
QueuedRmwSum(const uint32_t addr, const uint32_t a, const ValWord< uint32_t > &valWord, const uint32_t expected)
static bool validation_test_single_write_read(uhal::ClientInterface &c, const uint32_t addr, const bool perTransactionDispatch, const bool aVerbose)
Validation test – single-register write/read-back.
static bool validation_test_write_rmwbits_read(uhal::ClientInterface &c, const uint32_t addr, const bool perTransactionDispatch, const bool aVerbose)
Validation test – write, RMW bits, read.
std::vector< U32 > U32Vec
A vector of unsigned 32-bit words.
Definition: PerfTester.hxx:83
static bool validation_test_write_rmwsum_read(uhal::ClientInterface &c, const uint32_t addr, const bool perTransactionDispatch, const bool aVerbose)
Validation test – write, RMW sum, read.
static bool validation_test_block_write_read(uhal::ClientInterface &c, const uint32_t addr, const uint32_t depth, const bool perTransactionDispatch, const bool aVerbose)
Validation test – block write/read-back.
static U32Vec getRandomBuffer(unsigned size)
Returns a buffer of random numbers.
static uint32_t getRandomBlockSize(const uint32_t maxSize)
Returns a random uint32_t in the range [0,maxSize], with 1/x probability distribution – so that p(x=0...
static bool runValidationTest(const std::vector< ClientInterface * > &aClients, const uint32_t aBaseAddr, const uint32_t aDepth, const size_t aNrIterations, const bool aDispatchEachIteration, const bool aVerbose)
IPbusCore & client
ClientInterface * c
uint32_t x
Definition: test_single.cpp:93
std::vector< uint32_t > xx
Definition: test_block.cpp:249
ValWord< uint32_t > reg
_Quote< T > Quote(const T &aT)
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
ErrorLevel Error
Definition: LogLevels.cpp:61
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
Definition: log.hxx:18
WarningLevel Warning
Definition: LogLevels.cpp:79
NoticeLevel Notice
Definition: LogLevels.cpp:97
Annotation for function names.
Definition: attr.h:47
Empty struct which acts as a dummy variable for passing the formatting information around.