45 #include <boost/program_options.hpp> 46 #include <boost/bind.hpp> 47 #include <boost/foreach.hpp> 48 #include <boost/mem_fn.hpp> 55 namespace po = boost::program_options;
66 m_testName (
"BandwidthRx" ),
67 m_iterations ( 1000 ),
68 m_baseAddrStr (
"0x0" ),
70 m_bandwidthTestDepth ( 0 ),
72 m_perIterationDispatch ( false ),
73 m_includeConnect ( false )
78 m_testDescMap[
"BandwidthRx"] =
"Block read test (default depth = 340) to find the receive bandwidth.";
81 m_testDescMap[
"BandwidthTx"] =
"Block write test (default depth = 340) to find the transmit bandwidth.";
84 m_testDescMap[
"Validation"] =
"For validating downstream subsystems, such as the Control Hub or the IPbus firmware.";
87 m_testDescMap[
"Sandbox"] =
"A user-definable test - modify the sandbox() function to whatever you wish.";
90 srand ( time ( NULL ) );
99 po::options_description argDescriptions (
"Allowed options" );
100 argDescriptions.add_options()
101 (
"help,h",
"Produce help message" )
102 (
"list,l",
"List the names of the different tests that can be performed." )
103 (
"verbose,v",
"Make the output more verbose." )
104 (
"test,t", po::value<string> ( &
m_testName )->default_value (
"BandwidthRx" ),
"Name of the test to be performed." )
105 (
"iterations,i", po::value<uint64_t> ( &
m_iterations )->default_value ( 1000 ),
"Number of test iterations to run." )
106 (
"devices,d", po::value<StringVec> ( &
m_deviceURIs )->multitoken(),
"List of device connection URIs, e.g. chtcp-1.3://..., etc" )
107 (
"baseAddr,b", po::value<string> ( &
m_baseAddrStr )->default_value (
"0x0" ),
"Base address (in hex) of the test location on the target device(s)." )
108 (
"bandwidthTestDepth,w", po::value<boost::uint32_t> ( &
m_bandwidthTestDepth )->default_value ( 340 ),
"Depth of read/write used in bandwidth tests." )
109 (
"perIterationDispatch,p",
"Force a network dispatch every test iteration instead of the default single dispatch call at the end." )
110 (
"includeConnect,c",
"Include connect time in reported bandwidths and latencies" );
111 po::variables_map argMap;
112 po::store ( po::parse_command_line ( argc, argv, argDescriptions ), argMap );
113 po::notify ( argMap );
119 if ( convert.fail() )
121 cerr <<
"The specified base address was not valid hexadecimal!" << endl;
126 if ( argc < 2 || argMap.count (
"help" ) )
129 oss << argDescriptions;
134 if ( argMap.count (
"list" ) )
140 if ( argMap.count (
"verbose" ) )
145 if ( argMap.count (
"perIterationDispatch" ) )
150 if ( argMap.count (
"includeConnect" ) )
164 catch ( std::exception& e )
166 cerr <<
"Error - exception thrown ..." << endl << e.what() << endl;
171 cerr <<
"Caught exception of unknown type!" << endl;
183 cout <<
"\n -----------------------------------------\n" 184 " PerfTester.exe - IPbus Performance Tester\n" 185 " -----------------------------------------\n\n" 186 " Generate custom IPbus/uHAL tests from the command line\n\n" 188 <<
"Usage examples:\n\n" 189 " PerfTester.exe -t BandwidthTx -b 0xf0 -d ipbusudp-1.3://localhost:50001 ipbusudp-1.3://localhost:50002\n" 190 " PerfTester.exe -t BandwidthTx -w 5 -i 100 chtcp-1.3://localhost:10203?target=127.0.0.1:50001" << endl;
197 cout <<
"\nNames and descriptions of available tests:\n" << endl;
198 cout <<
" " << setw ( 16 ) << left <<
"Name" <<
" " <<
"Description" << endl;
199 cout <<
" " << setw ( 16 ) << left <<
"----" <<
" " <<
"-----------" << endl;
202 for ( ; iTest != iTestEnd ; ++iTest )
204 cout <<
" " << setw ( 16 ) << left << iTest->first <<
" " << iTest->second << endl;
215 cerr <<
"You must specify at least one device connection URI by using the -d option!" << endl;
222 <<
"' is not one of the available tests!\nDo 'PerfTester -l' to see names of available tests!" << endl;
232 cout <<
"Test settings:\n" << endl
233 <<
" Test Name --------------> " <<
m_testName << endl
235 <<
" Test iterations --------> " <<
m_iterations << endl
237 <<
" Device URIs:" << endl;
240 for ( ; iDevice != iDeviceEnd ; ++iDevice )
242 cout <<
" " << *iDevice << endl;
245 cout <<
"\nRunning test now...\n" << endl;
253 setLogLevelTo (
Debug() );
254 cout <<
"Building device clients..." << endl;
263 for (
unsigned int iURI = 0 ; iURI <
m_deviceURIs.size() ; ++iURI )
270 cout <<
"Device clients built successfully!" << endl;
278 underline.assign (
m_testName.size() + 14,
'-' );
280 << underline <<
"\n\n" 281 <<
"Number of IPbus hosts in test = " <<
m_deviceURIs.size() <<
"\n" 283 <<
"Total time taken = " << totalSeconds <<
" s\n" 284 <<
"Test iteration frequency = " <<
m_iterations/totalSeconds <<
" Hz" << endl;
290 return std::equal ( readBuffer.
begin(), readBuffer.
end(), writeBuffer.begin() );
307 std::vector<ClientInterface*> lClients;
310 lClients.push_back( &*iClient );
315 double dataRateKB_s = totalPayloadKB/totalSeconds;
318 <<
"Total IPbus payload received = " << totalPayloadKB <<
" KB\n" 319 <<
"Average read bandwidth = " << dataRateKB_s <<
" KB/s" << endl;
334 std::vector<ClientInterface*> lClients;
337 lClients.push_back( &*iClient );
342 double dataRateKB_s = totalPayloadKB/totalSeconds;
345 <<
"Total IPbus payload sent = " << totalPayloadKB <<
" KB\n" 346 <<
"Average write bandwidth = " << dataRateKB_s <<
" KB/s" << endl;
352 std::vector<ClientInterface*> lClients;
354 lClients.push_back(&**lIt);
361 bool 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)
363 unsigned nrTestsFailed = 0;
364 unsigned nrTestsTotal = 0;
368 typedef std::vector<ClientInterface*>::const_iterator ClientIt_t;
369 for ( ClientIt_t clientIt = aClients.begin(); clientIt != aClients.end(); clientIt++ )
372 cout <<
"\n\nWRITE READ-BACK TESTS for device at '" << client->
uri() <<
"'" << endl;
373 vector<uint32_t> addr_vec;
374 addr_vec.push_back ( aBaseAddr );
375 addr_vec.push_back ( aBaseAddr + aDepth - 1 );
377 for (
unsigned i = 0; i < 2498; i++ )
379 addr_vec.push_back ( aBaseAddr + ( rand() % aDepth ) );
382 cout <<
"\n 1. Single-register write/read (" << addr_vec.size() * 2 <<
" tests)" << endl;
384 for (
unsigned i = 0; i < addr_vec.size(); i++ )
401 cout <<
"\n 2. Block write/read (" << addr_vec.size() * 2 <<
" tests)" << endl;
403 for (
unsigned i = 0; i < addr_vec.size(); i++ )
405 uint32_t
addr = addr_vec.at ( i );
406 uint32_t max_depth = aBaseAddr + aDepth -
addr;
407 uint32_t depth = rand() % ( max_depth + 1 );
424 cout <<
"\n 3. Testing RMW-bits (write, RMWbits, read; " << addr_vec.size() * 2 <<
" tests)" << endl;
426 for ( std::vector<uint32_t>::const_iterator it = addr_vec.begin(); it != addr_vec.end(); it++ )
443 cout <<
"\n 4. Testing RMW-sum (write, RMW-sum, read; " << addr_vec.size() * 2 <<
" tests)" << endl;
445 for ( std::vector<uint32_t>::const_iterator it = addr_vec.begin(); it != addr_vec.end(); it++ )
463 if ( nrTestsFailed == 0 )
465 cout <<
"\n\nBASIC TESTS SUMMARY: All " << nrTestsTotal <<
" tests passed!" << endl << endl << endl;
469 cout <<
"\n\nBASIC TESTS SUMMARY: Total of " << nrTestsTotal <<
" tests run -- " << nrTestsFailed <<
" tests FAILED , " << ( nrTestsTotal - nrTestsFailed ) <<
" tests PASSED" << endl;
475 for ( ClientIt_t clientIt = aClients.begin(); clientIt != aClients.end(); clientIt++ )
478 cout <<
"\nSOAK TEST to device '" << client->
uri() <<
"'\n Random sequence of " << aNrIterations <<
" transactions will be sent to hardware" << endl << endl;
481 size_t found = client->
uri().find (
"-1.3" );
483 if ( found!=std::string::npos )
489 found = client->
uri().find (
"-2.0" );
491 if ( found!=std::string::npos )
497 log (
Error() ,
"Cannot deduce protocol from URI " ,
Quote ( client->
uri() ),
" Exiting before performing soak test." );
503 std::vector< uint32_t > registers ( aDepth , 0x00000000 );
507 uint32_t type,
addr, blockSize;
508 uint32_t tempUInt1, tempUInt2;
509 vector< boost::shared_ptr<QueuedTransaction> > queuedTransactions;
510 uint32_t nrQueuedWords = 0;
512 for (
unsigned i = 1; i <= aNrIterations; i++ )
514 type = ( rand() % 4 );
515 addr = aBaseAddr + ( rand() % aDepth );
526 nrQueuedWords += blockSize;
536 std::copy ( randomData.begin(), randomData.end(), registers.begin() + ( addr - aBaseAddr ) );
538 nrQueuedWords += blockSize;
546 vector<uint32_t>::iterator regIt = registers.begin() + ( addr - aBaseAddr );
548 if ( ipbus_vsn == 1 )
558 if ( ipbus_vsn == 2 )
570 vector<uint32_t>::iterator regIt = registers.begin() + ( addr - aBaseAddr );
572 if ( ipbus_vsn == 1 )
581 if ( ipbus_vsn == 2 )
590 if ( aDispatchEachIteration || ( nrQueuedWords > 20000000 ) || ( i == aNrIterations ) )
592 log (
Notice(),
"Soak test - issuing dispatch" );
594 log (
Notice(),
"Soak test - issuing empty dispatch" );
599 if ( ! ( *it )->check_values() )
601 cout <<
"ERROR OCCURED IN SOAK TEST to '" << client->
uri() <<
"' - after " << i <<
" successful transactions" << endl;
606 queuedTransactions.clear();
611 std::cout <<
"No errors after " << i <<
" transactions -- " << setiosflags (
ios::fixed ) << setprecision ( 1 ) << ( 100.0 * i ) / aNrIterations <<
"% done\r";
618 cout << endl <<
"Reached end of soak testing successfully!" << endl;
636 catch (
const std::exception& e )
638 cout << e.what() << endl;
647 int main (
int argc,
char* argv[] )
650 return perfTester.
run ( argc, argv );
void outputHelpText(const std::string &argDescriptions) const
Outputs the standard help text to screen.
void dispatch()
Method to dispatch all IPbus packets which are in the queue of IPbusPacketInfo's and wait until all q...
std::string m_testName
Holds the test name.
T value() const
Return the value of the validated memory with check on validity.
A class which wraps a block of data and marks whether or not it is valid.
double measureReadLatency(ClientInterface &aClient, uint32_t aBaseAddr, uint32_t aDepth, size_t aNrIterations, bool aDispatchEachIteration, bool aVerbose)
std::string m_baseAddrStr
Base addr of reg/ram the test will use. Use a string as workaround for hex input via boost::program_o...
static ClientFactory & getInstance()
Static method to retrieve the single instance of the class.
ClientVec m_clients
Vector of low-level uHAL clients.
bool m_perIterationDispatch
Perform a network dispatch every iteration flag.
TestDescMap m_testDescMap
Maps test name to test description.
void validationTest()
Historic basic firmware/software validation test.
int main(int argc, char *argv[])
bool badInput() const
Returns true if the user has entered bad command line arguments.
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...
std::vector< U32 > U32Vec
A vector of unsigned 32-bit words.
double measureWriteLatency(ClientInterface &aClient, uint32_t aBaseAddr, uint32_t aDepth, size_t aNrIterations, bool aDispatchEachIteration, bool aVerbose)
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)
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.
std::string uri() const
Ping the target for this client.
void push_back(const T &aValue)
If the memory has not previously been marked as valid, add an entry to the end of it...
PerfTester()
Constructor - takes no arguments, does nothing.
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.
const_iterator end() const
If the memory has previously been marked as valid, return a const iterator to the end (one past last ...
Empty struct which acts as a dummy variable for passing the formatting information around...
_Quote< T > Quote(const T &aT)
uint64_t m_iterations
Number of test iterations.
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=...
void outputTestDescriptionsList() const
Outputs the test names and descriptions to screen.
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.
void sandbox()
An area for a user-definable test.
const_iterator begin() const
If the memory has previously been marked as valid, return a const iterator to the beginning of the un...
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.
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.
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 bandwidthTxTest()
Write bandwidth test.
int run(int argc, char *argv[])
Pass in the two command-line parameter variables, this will define the test that then gets run...
An abstract base class for defining the interface to the various IPbus clients as well as providing t...
TestFuncMap m_testFuncMap
Maps test name to test function.
bool m_includeConnect
Include (e.g. TCP) connect time in reported bandwidth/latency.
bool m_verbose
Verbosity true/false flag.
void buildClients()
Constructs and sets up the appropriate IPbusClient for use in the test.
void outputUserChoices() const
Outputs the user's choices to screen.
void bandwidthRxTest()
Read bandwidth test.
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...
boost::uint32_t m_baseAddr
The m_baseAddrStr as converted into an actual unsigned value.
boost::uint32_t m_bandwidthTestDepth
The depth of read/write used in bandwidth tests.
bool buffersEqual(const U32Vec &writeBuffer, const U32ValVec &readBuffer) const
Compares a write buffer with one or more ValVec read responses.
void outputStandardResults(double totalSeconds) const
Outputs a standard result set to screen - provide it with the number of seconds the test took...
static U32Vec getRandomBuffer(unsigned size)
Returns a buffer of random numbers.
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
StringVec m_deviceURIs
Vector of individual connection URI strings.