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 );
116 istringstream convert ( m_baseAddrStr );
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;
130 outputHelpText ( oss.str() );
134 if ( argMap.count (
"list" ) )
136 outputTestDescriptionsList();
140 if ( argMap.count (
"verbose" ) )
145 if ( argMap.count (
"perIterationDispatch" ) )
147 m_perIterationDispatch =
true;
150 if ( argMap.count (
"includeConnect" ) )
152 m_includeConnect =
true;
162 ( this->*m_testFuncMap.find ( m_testName )->second ) ();
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;
191 outputTestDescriptionsList();
197 cout <<
"\nNames and descriptions of available tests:\n" << endl;
198 cout <<
" " << setw ( 16 ) << left <<
"Name" <<
" " <<
"Description" << endl;
199 cout <<
" " << setw ( 16 ) << left <<
"----" <<
" " <<
"-----------" << endl;
200 TestDescMap::const_iterator iTest = m_testDescMap.begin(), iTestEnd = m_testDescMap.end();
202 for ( ; iTest != iTestEnd ; ++iTest )
204 cout <<
" " << setw ( 16 ) << left << iTest->first <<
" " << iTest->second << endl;
213 if ( m_deviceURIs.empty() )
215 cerr <<
"You must specify at least one device connection URI by using the -d option!" << endl;
219 if ( m_testFuncMap.find ( m_testName ) == m_testFuncMap.end() )
221 cerr <<
"The test name '" << m_testName
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
234 <<
" Test register addr -----> " <<
std::hex << showbase << m_baseAddr << noshowbase <<
std::dec << endl
235 <<
" Test iterations --------> " << m_iterations << endl
236 <<
" Per-iteration dispatch --> " << ( m_perIterationDispatch?
"Yes":
"No" ) << endl
237 <<
" Device URIs:" << endl;
238 StringVec::const_iterator iDevice = m_deviceURIs.begin(), iDeviceEnd = m_deviceURIs.end();
240 for ( ; iDevice != iDeviceEnd ; ++iDevice )
242 cout <<
" " << *iDevice << endl;
245 cout <<
"\nRunning test now...\n" << endl;
254 cout <<
"Building device clients..." << endl;
261 m_clients.reserve ( m_deviceURIs.size() );
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,
'-' );
279 cout << m_testName <<
" Test Results:\n"
280 << underline <<
"\n\n"
281 <<
"Number of IPbus hosts in test = " << m_deviceURIs.size() <<
"\n"
282 <<
"Total test iterations = " << m_iterations <<
"\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() );
298 if ( ! m_includeConnect )
300 BOOST_FOREACH (
ClientPtr& iClient, m_clients )
307 std::vector<ClientInterface*> lClients;
308 BOOST_FOREACH (
ClientPtr& iClient, m_clients )
310 lClients.push_back( &*iClient );
313 double totalSeconds =
measureReadLatency(lClients, m_baseAddr, m_bandwidthTestDepth, m_iterations, m_perIterationDispatch, m_verbose);
314 double totalPayloadKB = m_deviceURIs.size() * m_iterations * m_bandwidthTestDepth * 4. / 1024.;
315 double dataRateKB_s = totalPayloadKB/totalSeconds;
316 outputStandardResults ( totalSeconds );
317 cout <<
"Read depth used each iteration = " << m_bandwidthTestDepth <<
" 32-bit words\n"
318 <<
"Total IPbus payload received = " << totalPayloadKB <<
" KB\n"
319 <<
"Average read bandwidth = " << dataRateKB_s <<
" KB/s" << endl;
325 if ( ! m_includeConnect )
327 BOOST_FOREACH (
ClientPtr& iClient, m_clients )
334 std::vector<ClientInterface*> lClients;
335 BOOST_FOREACH (
ClientPtr& iClient, m_clients )
337 lClients.push_back( &*iClient );
340 double totalSeconds =
measureWriteLatency(lClients, m_baseAddr, m_bandwidthTestDepth, m_iterations, m_perIterationDispatch, m_verbose);
341 double totalPayloadKB = m_deviceURIs.size() * m_iterations * m_bandwidthTestDepth * 4. / 1024.;
342 double dataRateKB_s = totalPayloadKB/totalSeconds;
343 outputStandardResults ( totalSeconds );
344 cout <<
"Write depth used each iteration = " << m_bandwidthTestDepth <<
" 32-bit words\n"
345 <<
"Total IPbus payload sent = " << totalPayloadKB <<
" KB\n"
346 <<
"Average write bandwidth = " << dataRateKB_s <<
" KB/s" << endl;
352 std::vector<ClientInterface*> lClients;
353 for(ClientVec::iterator lIt = m_clients.begin(); lIt != m_clients.end(); lIt++)
354 lClients.push_back(&**lIt);
356 if (! runValidationTest(lClients, m_baseAddr, m_bandwidthTestDepth, m_iterations, m_perIterationDispatch, m_verbose) )
365 BOOST_FOREACH (
ClientPtr& iClient, m_clients )
371 cout <<
"Read: " <<
std::hex << result.
value() <<
" from address: " << m_baseAddr <<
std::dec << endl;
374 catch (
const std::exception& e )
376 cout << e.what() << endl;
385 int main (
int argc,
char* argv[] )
388 return perfTester.
run ( argc, argv );