45#include <boost/program_options.hpp>
46#include <boost/mem_fn.hpp>
53namespace po = boost::program_options;
64 m_testName (
"BandwidthRx" ),
65 m_iterations ( 1000 ),
66 m_baseAddrStr (
"0x0" ),
68 m_bandwidthTestDepth ( 0 ),
70 m_perIterationDispatch ( false ),
71 m_includeConnect ( false )
76 m_testDescMap[
"BandwidthRx"] =
"Block read test (default depth = 340) to find the receive bandwidth.";
79 m_testDescMap[
"BandwidthTx"] =
"Block write test (default depth = 340) to find the transmit bandwidth.";
82 m_testDescMap[
"Validation"] =
"For validating downstream subsystems, such as the Control Hub or the IPbus firmware.";
85 m_testDescMap[
"Sandbox"] =
"A user-definable test - modify the sandbox() function to whatever you wish.";
88 srand ( time ( NULL ) );
97 po::options_description argDescriptions (
"Allowed options" );
98 argDescriptions.add_options()
99 (
"help,h",
"Produce help message" )
100 (
"list,l",
"List the names of the different tests that can be performed." )
101 (
"verbose,v",
"Make the output more verbose." )
102 (
"test,t", po::value<string> ( &m_testName )->default_value (
"BandwidthRx" ),
"Name of the test to be performed." )
103 (
"iterations,i", po::value<uint64_t> ( &m_iterations )->default_value ( 1000 ),
"Number of test iterations to run." )
104 (
"devices,d", po::value<StringVec> ( &m_deviceURIs )->multitoken(),
"List of device connection URIs, e.g. chtcp-1.3://..., etc" )
105 (
"baseAddr,b", po::value<string> ( &m_baseAddrStr )->default_value (
"0x0" ),
"Base address (in hex) of the test location on the target device(s)." )
106 (
"bandwidthTestDepth,w", po::value<boost::uint32_t> ( &m_bandwidthTestDepth )->default_value ( 340 ),
"Depth of read/write used in bandwidth tests." )
107 (
"perIterationDispatch,p",
"Force a network dispatch every test iteration instead of the default single dispatch call at the end." )
108 (
"includeConnect,c",
"Include connect time in reported bandwidths and latencies" );
109 po::variables_map argMap;
110 po::store ( po::parse_command_line ( argc, argv, argDescriptions ), argMap );
111 po::notify ( argMap );
114 istringstream convert ( m_baseAddrStr );
115 convert >> std::hex >> m_baseAddr;
117 if ( convert.fail() )
119 cerr <<
"The specified base address was not valid hexadecimal!" << endl;
124 if ( argc < 2 || argMap.count (
"help" ) )
127 oss << argDescriptions;
128 outputHelpText ( oss.str() );
132 if ( argMap.count (
"list" ) )
134 outputTestDescriptionsList();
138 if ( argMap.count (
"verbose" ) )
143 if ( argMap.count (
"perIterationDispatch" ) )
145 m_perIterationDispatch =
true;
148 if ( argMap.count (
"includeConnect" ) )
150 m_includeConnect =
true;
160 ( this->*m_testFuncMap.find ( m_testName )->second ) ();
162 catch ( std::exception& e )
164 cerr <<
"Error - exception thrown ..." << endl << e.what() << endl;
169 cerr <<
"Caught exception of unknown type!" << endl;
181 cout <<
"\n -----------------------------------------\n"
182 " PerfTester.exe - IPbus Performance Tester\n"
183 " -----------------------------------------\n\n"
184 " Generate custom IPbus/uHAL tests from the command line\n\n"
186 <<
"Usage examples:\n\n"
187 " PerfTester.exe -t BandwidthTx -b 0xf0 -d ipbusudp-1.3://localhost:50001 ipbusudp-1.3://localhost:50002\n"
188 " PerfTester.exe -t BandwidthTx -w 5 -i 100 chtcp-1.3://localhost:10203?target=127.0.0.1:50001" << endl;
189 outputTestDescriptionsList();
195 cout <<
"\nNames and descriptions of available tests:\n" << endl;
196 cout <<
" " << setw ( 16 ) << left <<
"Name" <<
" " <<
"Description" << endl;
197 cout <<
" " << setw ( 16 ) << left <<
"----" <<
" " <<
"-----------" << endl;
198 TestDescMap::const_iterator iTest = m_testDescMap.begin(), iTestEnd = m_testDescMap.end();
200 for ( ; iTest != iTestEnd ; ++iTest )
202 cout <<
" " << setw ( 16 ) << left << iTest->first <<
" " << iTest->second << endl;
211 if ( m_deviceURIs.empty() )
213 cerr <<
"You must specify at least one device connection URI by using the -d option!" << endl;
217 if ( m_testFuncMap.find ( m_testName ) == m_testFuncMap.end() )
219 cerr <<
"The test name '" << m_testName
220 <<
"' is not one of the available tests!\nDo 'PerfTester -l' to see names of available tests!" << endl;
230 cout <<
"Test settings:\n" << endl
231 <<
" Test Name --------------> " << m_testName << endl
232 <<
" Test register addr -----> " << std::hex << showbase << m_baseAddr << noshowbase << std::dec << endl
233 <<
" Test iterations --------> " << m_iterations << endl
234 <<
" Per-iteration dispatch --> " << ( m_perIterationDispatch?
"Yes":
"No" ) << endl
235 <<
" Device URIs:" << endl;
236 StringVec::const_iterator iDevice = m_deviceURIs.begin(), iDeviceEnd = m_deviceURIs.end();
238 for ( ; iDevice != iDeviceEnd ; ++iDevice )
240 cout <<
" " << *iDevice << endl;
243 cout <<
"\nRunning test now...\n" << endl;
252 cout <<
"Building device clients..." << endl;
259 m_clients.reserve ( m_deviceURIs.size() );
261 for (
unsigned int iURI = 0 ; iURI < m_deviceURIs.size() ; ++iURI )
268 cout <<
"Device clients built successfully!" << endl;
276 underline.assign ( m_testName.size() + 14,
'-' );
277 cout << m_testName <<
" Test Results:\n"
278 << underline <<
"\n\n"
279 <<
"Number of IPbus hosts in test = " << m_deviceURIs.size() <<
"\n"
280 <<
"Total test iterations = " << m_iterations <<
"\n"
281 <<
"Total time taken = " << totalSeconds <<
" s\n"
282 <<
"Test iteration frequency = " << m_iterations/totalSeconds <<
" Hz" << endl;
288 return std::equal ( readBuffer.
begin(), readBuffer.
end(), writeBuffer.begin() );
296 if ( ! m_includeConnect )
305 std::vector<ClientInterface*> lClients;
308 lClients.push_back( &*iClient );
311 double totalSeconds =
measureReadLatency(lClients, m_baseAddr, m_bandwidthTestDepth, m_iterations, m_perIterationDispatch, m_verbose);
312 double totalPayloadKB = m_deviceURIs.size() * m_iterations * m_bandwidthTestDepth * 4. / 1024.;
313 double dataRateKB_s = totalPayloadKB/totalSeconds;
314 outputStandardResults ( totalSeconds );
315 cout <<
"Read depth used each iteration = " << m_bandwidthTestDepth <<
" 32-bit words\n"
316 <<
"Total IPbus payload received = " << totalPayloadKB <<
" KB\n"
317 <<
"Average read bandwidth = " << dataRateKB_s <<
" KB/s" << endl;
323 if ( ! m_includeConnect )
332 std::vector<ClientInterface*> lClients;
335 lClients.push_back( &*iClient );
338 double totalSeconds =
measureWriteLatency(lClients, m_baseAddr, m_bandwidthTestDepth, m_iterations, m_perIterationDispatch, m_verbose);
339 double totalPayloadKB = m_deviceURIs.size() * m_iterations * m_bandwidthTestDepth * 4. / 1024.;
340 double dataRateKB_s = totalPayloadKB/totalSeconds;
341 outputStandardResults ( totalSeconds );
342 cout <<
"Write depth used each iteration = " << m_bandwidthTestDepth <<
" 32-bit words\n"
343 <<
"Total IPbus payload sent = " << totalPayloadKB <<
" KB\n"
344 <<
"Average write bandwidth = " << dataRateKB_s <<
" KB/s" << endl;
350 std::vector<ClientInterface*> lClients;
351 for (
const auto&
c: m_clients)
352 lClients.push_back(&*
c);
354 if (not runValidationTest(lClients, m_baseAddr, m_bandwidthTestDepth, m_iterations, m_perIterationDispatch, m_verbose) )
369 cout <<
"Read: " << std::hex << result.value() <<
" from address: " << m_baseAddr << std::dec << endl;
372 catch (
const std::exception& e )
374 cout << e.what() << endl;
383int main (
int argc,
char* argv[] )
386 return perfTester.
run ( argc, argv );
static ClientFactory & getInstance()
Static method to retrieve the single instance of the class.
A class which wraps a block of data and marks whether or not it is valid.
const_iterator begin() const
If the memory has previously been marked as valid, return a const iterator to the beginning of the un...
const_iterator end() const
If the memory has previously been marked as valid, return a const iterator to the end (one past last ...
A class which wraps a single word of data and marks whether or not it is valid.
bool badInput() const
Returns true if the user has entered bad command line arguments.
void sandbox()
An area for a user-definable test.
void outputUserChoices() const
Outputs the user's choices to screen.
void bandwidthTxTest()
Write bandwidth test.
TestFuncMap m_testFuncMap
Maps test name to test function.
PerfTester()
Constructor - takes no arguments, does nothing.
void outputHelpText(const std::string &argDescriptions) const
Outputs the standard help text to screen.
void buildClients()
Constructs and sets up the appropriate IPbusClient for use in the test.
void bandwidthRxTest()
Read 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.
std::vector< U32 > U32Vec
A vector of unsigned 32-bit words.
TestDescMap m_testDescMap
Maps test name to test description.
bool buffersEqual(const U32Vec &writeBuffer, const U32ValVec &readBuffer) const
Compares a write buffer with one or more ValVec read responses.
void outputTestDescriptionsList() const
Outputs the test names and descriptions to screen.
void validationTest()
Historic basic firmware/software validation test.
void outputStandardResults(double totalSeconds) const
Outputs a standard result set to screen - provide it with the number of seconds the test took.
std::shared_ptr< uhal::ClientInterface > ClientPtr
Typedef for a ClientInterface shared_ptr.
int main(int argc, char *argv[])
double measureReadLatency(ClientInterface &aClient, uint32_t aBaseAddr, uint32_t aDepth, size_t aNrIterations, bool aDispatchEachIteration, bool aVerbose)
double measureWriteLatency(ClientInterface &aClient, uint32_t aBaseAddr, uint32_t aDepth, size_t aNrIterations, bool aDispatchEachIteration, bool aVerbose)
void setLogLevelTo(const FatalLevel &)
Function to specify, at runtime, that only messages with a severity level above Fatal should be logge...