diff options
Diffstat (limited to 'ACE/performance-tests/SCTP/SOCK_SEQPACK_clt.cpp')
-rw-r--r-- | ACE/performance-tests/SCTP/SOCK_SEQPACK_clt.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/ACE/performance-tests/SCTP/SOCK_SEQPACK_clt.cpp b/ACE/performance-tests/SCTP/SOCK_SEQPACK_clt.cpp new file mode 100644 index 00000000000..fc41f2c7d3a --- /dev/null +++ b/ACE/performance-tests/SCTP/SOCK_SEQPACK_clt.cpp @@ -0,0 +1,309 @@ +// $Id$ + +#include "ace/OS_Memory.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_SEQPACK_Association.h" +#include "ace/SOCK_SEQPACK_Connector.h" +#include "ace/Log_Msg.h" +#include "ace/CDR_Stream.h" +#include "ace/High_Res_Timer.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/os_include/arpa/os_inet.h" + +// make sure that the code compiles cleanly even if SCTP is not +// available. If SCTP is not installed, program will exit early in +// main() with an error message +#ifdef ACE_HAS_SCTP +extern "C" { +#include <netinet/sctp.h> +}; +#else +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif // !IPPROTO_SCTP +#define SCTP_NODELAY 1 +#endif // ACE_HAS_SCTP + +// class that manages setting of options +#include "Options_Manager.h" + +// histogram code +#include "hist.h" + +// global constants +ACE_CDR::UShort const primerIterations = 100; +// ace/High_Res_Timer.h describes the need for the following. +ACE_UINT32 const microsec_clock_scale_factor = ACE_High_Res_Timer::global_scale_factor(); + +// forward declations of functions. Bodies follow main() to improve +// file readability. +ACE_SCTP::HIST runTest(ACE_SOCK_SEQPACK_Association &); + +int ACE_TMAIN (int argc, ACE_TCHAR **argv){ + + // Initialize the options manager + Options_Manager optsMgr(argc, argv, ACE_TEXT ("client-opts")); + + // show usage is requested + if (optsMgr._usage) { + optsMgr._show_usage(stderr, ACE_TEXT ("client-opts")); + return 1; + } + +#ifndef ACE_HAS_SCTP + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("SCTP was NOT installed/accessible when this binary was compiled.\n")), + 1); +#else + + // check that valid options were specified + if (optsMgr._error) { + ACE_OS::fprintf (stderr, "ERROR: %s\n", ACE_TEXT_ALWAYS_CHAR (optsMgr._error_message)); + return 1; + } + + + // Create the address that we want the client to connect to + ACE_INET_Addr serverAddr(Options_Manager::server_port, + Options_Manager::server_host); + + // Create the address that we want the client to connect FROM + ACE_Multihomed_INET_Addr clientAddr; + clientAddr.set(optsMgr.client_port, + optsMgr.client_connect_addr, + 1, + optsMgr.secondary_connect_addrs, + optsMgr.num_secondary_connect_addrs); + + // object that manages the connection to the server + ACE_SOCK_SEQPACK_Connector connector; + + // object that manages the data xfer between the client and server + ACE_SOCK_SEQPACK_Association dataStream; + + // connect to the server + if (connector.connect (dataStream, + serverAddr, + 0,clientAddr, 0, 0, 0, optsMgr.test_transport_protocol) == -1) /*, // ALL DEFAULT ARGUMENTS + Options_Manager::test_transport_protocol) == -1) */ + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("connection failed")), + 1); + + // run the test + ACE_SCTP::HIST testResultsHistogram = 0; + // connection is closed by runTest* functions + testResultsHistogram = runTest(dataStream); + + // report out the test statistics IF NO EXECPTIONS have been thrown + // all histograms created are placed onto a linked list that report() + // can access. So the histogram created in one of the *_test() functions + // will be reported out by the report() call + if (testResultsHistogram) + ACE_SCTP::report(); + + return 0; +#endif /* ACE_HAS_SCTP */ +} + +// create a histogram to store test results +ACE_SCTP::HIST createHistogram(ACE_CDR::ULong messageSize){ + // The histogram created below lives beyond the scope of this + // function. So the memory allocated here cannot be cleaned up when + // this function goes out of scope. Unfortunately the histogram + // implementation does not clean it up either. So it is a small + // memory leak. + char * histName = (char *) malloc(200); + + ACE_OS::sprintf(histName, "%s Unmarshalled Msg Synchronous Latency Test\n\t\t\t\t\t(Message Size %u, Message Type octet)", + "ACE", messageSize); + + // actually create the histogram + ACE_SCTP::HIST createdHist = ACE_SCTP::histogram(histName, + Options_Manager::histogram_bin_count, + Options_Manager::histogram_min_bin, + Options_Manager::histogram_max_bin); + + // set the maximum number of outliers to maintain in the histogram + ACE_SCTP::set_outer(Options_Manager::histogram_num_outliers, createdHist); + + return (createdHist); +} + +// send the test header (only contains number of iterations) +int sendHeader(ACE_SOCK_SEQPACK_Association & stream) { + + // create an ACE CDR output stream and place the header information + // into it + ACE_OutputCDR hdrCDR; + hdrCDR << ACE_OutputCDR::from_boolean (ACE_CDR_BYTE_ORDER); + hdrCDR << ACE_CDR::ULong(Options_Manager::test_iterations+primerIterations); + if (!hdrCDR.good_bit()) + return (0); + + // send the header to the server (HEADER is 8 BYTES LONG) + size_t bt; + if (stream.send_n(hdrCDR.begin(), 0, &bt) == -1) + return 0; + + return 1; +} + +// conduct the UnMarshalled Octet performance test using separate +// send_n calls with Nagle's algorithm disabled +ACE_SCTP::HIST runUnmarshalledOctetTest(ACE_CDR::Octet *buf, size_t seqLen, ACE_SOCK_SEQPACK_Association & stream){ + + ACE_CDR::ULong const testIterations = Options_Manager::test_iterations; + + size_t bt; + ACE_CDR::ULong cnt = 0; + // variables for the timing measurements + ACE_hrtime_t startTime, endTime; + ACE_CDR::Double messageLatency_usec = 0.0; + ACE_CDR::ULong msgLen = seqLen*ACE_CDR::OCTET_SIZE; + + // explicity configure Nagling. Default is + // Options_Manager::test_enable_nagle=0 so default configurations is + // NO NAGLING + ACE_CDR::Long nagle; + if (Options_Manager::test_enable_nagle) + nagle=0; + else + nagle=1; + if (-1 == stream.set_option(IPPROTO_SCTP, SCTP_NODELAY, &nagle, sizeof nagle)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("set_option")), + 0); + + // prime the client and server before starting the test + for(cnt=0;cnt<primerIterations;++cnt){ + + // send message size + // TODO : The message length should be CDR encoded + ACE_CDR::ULong msgLenExpressed = ACE_HTONL(msgLen); + if (-1 == stream.send_n (&msgLenExpressed, ACE_CDR::LONG_SIZE, 0, &bt)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n")), + 0); + + // send a message + if (-1 == stream.send_n (buf, msgLen, 0, &bt)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n")), + 0); + + // block for a Short reply + ACE_CDR::Short reply; + if ((stream.recv_n(&reply, ACE_CDR::SHORT_SIZE, 0, &bt)) == -1) + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv_n")), + 0); + } + + // AFTER PRIMING THE PUMP CREATE THE HISTOGRAM + ACE_SCTP::HIST aceStream_hist = 0; + aceStream_hist = createHistogram(msgLen); + if (0 == aceStream_hist) + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("histogram create failed")), + 0); + + iovec iov[2]; + // PERFORMANCE TEST LOOP + for (cnt = 0; cnt < testIterations; ++cnt){ + + // get the start time + startTime = ACE_OS::gethrtime(); + if (!startTime) + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_OS::gethrtime()")), + 0); + + ACE_CDR::ULong msgLenExpressed = ACE_HTONL(msgLen); + iov[0].iov_base = reinterpret_cast<char *> (&msgLenExpressed); + iov[0].iov_len = ACE_CDR::LONG_SIZE; + iov[1].iov_base = reinterpret_cast<char *> (buf); + iov[1].iov_len = msgLen; + + if (-1 == stream.sendv_n (iov, 2)) + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n")), + 0); + + // block for a Short reply + ACE_CDR::Short reply; + if ((stream.recv_n(&reply, ACE_CDR::SHORT_SIZE, 0, &bt)) == -1) + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv_n")), + 0); + + // get the end time + endTime = ACE_OS::gethrtime(); + if (!endTime) + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_OS::gethrtime()")), + 0); + + // compute the message latency in micro-seconds + messageLatency_usec = + + (static_cast<double> (ACE_UINT64_DBLCAST_ADAPTER(endTime)) - + static_cast<double> (ACE_UINT64_DBLCAST_ADAPTER(startTime))) + + / microsec_clock_scale_factor; + + + // record the message latency in the histogram + ACE_SCTP::record(messageLatency_usec, aceStream_hist); + } + + // THE HEADER MESSAGE SENT TO THE SERVER CONTAINED THE NUMBER OF + // PRIMER AND TEST MESSAGES TO BE SENT AFTER WHICH THE SERVER WILL + // CLOSE THE STREAM SO ONCE WE REACH THIS POINT THE STREAM IS NO + // LONGER VALID AND WE CLOSE IT. + stream.close(); + + // allocated by runTest + delete[] buf; + return aceStream_hist; +} + +// sends the test information to the server and calls the correct test +// function. +ACE_SCTP::HIST runTest(ACE_SOCK_SEQPACK_Association & stream) +{ + size_t msgLen = 1; + for (int i=1; i <= Options_Manager::payload_size_power_of_2; i++) + msgLen *= 2; + + + + // send a header to the server that contains test parameters + if (sendHeader(stream) < 0) + ACE_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("Could NOT Send CDR Encoded Header")), + 0); + + // create the forward message buffer + + ACE_CDR::Octet *o_arr; + ACE_CDR::ULong seqLen = msgLen/ACE_CDR::OCTET_SIZE; + ACE_NEW_RETURN(o_arr, + ACE_CDR::Octet[seqLen], + 0); + // o_arr is deleted in run_octet_test + return(runUnmarshalledOctetTest(o_arr, seqLen, stream)); +} |