Back to index

nordugrid-arc-nox  1.1.0~rc6
Functions | Variables
perftest.cpp File Reference
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <glibmm/thread.h>
#include <glibmm/timer.h>
#include <arc/ArcConfig.h>
#include <arc/message/MCCLoader.h>
#include <arc/message/SOAPEnvelope.h>
#include <arc/message/PayloadSOAP.h>
#include <arc/message/MCC.h>
#include <arc/StringConv.h>
#include <arc/Logger.h>

Go to the source code of this file.

Functions

void replace (std::string &str, const std::string &out, const std::string &in)
int Round (double x)
void sendRequests ()
int main (int argc, char *argv[])

Variables

Glib::Mutex * mutex
bool run
int finishedThreads
unsigned long completedRequests
unsigned long failedRequests
unsigned long totalRequests
Glib::TimeVal completedTime
Glib::TimeVal failedTime
Glib::TimeVal totalTime
std::string confString

Function Documentation

int main ( int  argc,
char *  argv[] 
)

Definition at line 171 of file perftest.cpp.

                                {
  // Some variables...
  std::string serviceHost;
  std::string portNumber;
  std::string httpPath("/Echo");
  int numberOfThreads;
  int duration;
  int i;
  Glib::Thread** threads;
  const char* config_file = NULL;
  int debug_level = -1;
  Arc::LogStream logcerr(std::cerr);

  // Process options - quick hack, must use Glib options later
  while(argc >= 3) {
    if(strcmp(argv[1],"-c") == 0) {
      config_file = argv[2];
      argv[2]=argv[0]; argv+=2; argc-=2;
    } else if(strcmp(argv[1],"-d") == 0) {
      debug_level=Arc::string_to_level(argv[2]);
      argv[2]=argv[0]; argv+=2; argc-=2;
    } else {
      break;
    };
  } 
  if(config_file) {
    std::ifstream f(config_file);
    if(!f) {
      std::cerr << "File "<<config_file<<" can't be open for reading!" << std::endl;
      exit(EXIT_FAILURE);
    }
    std::getline<char>(f, confString, 0);
  }
  if(debug_level >= 0) {
    Arc::Logger::getRootLogger().setThreshold((Arc::LogLevel)debug_level);
    Arc::Logger::getRootLogger().addDestination(logcerr);
  }
  // Extract command line arguments.
  if (argc!=5){
    std::cerr << "Wrong number of arguments!" << std::endl
             << std::endl
             << "Usage:" << std::endl
             << "perftest [-c config] [-d debug] host port threads duration" << std::endl
             << std::endl
             << "Arguments:" << std::endl
             << "host     The name of the host of the service." << std::endl
             << "port     The port to use on the host." << std::endl
             << "threads  The number of concurrent requests." << std::endl
             << "duration The duration of the test in seconds." << std::endl
             << "config   The file containing client chain XML configuration with " << std::endl
              << "         'soap' entry point and HOSTNAME, PORTNUMBER and PATH " << std::endl
              << "         keyword for hostname, port and HTTP path of 'echo' service." << std::endl
             << "debug    The textual representation of desired debug level. Available " << std::endl
              << "         levels: DEBUG, VERBOSE, INFO, WARNING, ERROR, FATAL." << std::endl;
    exit(EXIT_FAILURE);
  }
  serviceHost = std::string(argv[1]);
  portNumber = std::string(argv[2]);
  numberOfThreads = atoi(argv[3]);
  duration = atoi(argv[4]);
  
  // Insert host name and port number into the configuration string.
  replace(confString, "HOSTNAME", serviceHost);
  replace(confString, "PORTNUMBER", portNumber);
  replace(confString, "HTTPPATH", httpPath);

  // Start threads.
  run=true;
  finishedThreads=0;
  //Glib::thread_init();
  mutex=new Glib::Mutex;
  threads = new Glib::Thread*[numberOfThreads];
  for (i=0; i<numberOfThreads; i++)
    threads[i]=Glib::Thread::create(sigc::ptr_fun(sendRequests),true);

  // Sleep while the threads are working.
  Glib::usleep(duration*1000000);

  // Stop the threads
  run=false;
  while(finishedThreads<numberOfThreads)
    Glib::usleep(100000);

  // Print the result of the test.
  Glib::Mutex::Lock lock(*mutex);
  totalRequests = completedRequests+failedRequests;
  totalTime = completedTime+failedTime;
  std::cout << "========================================" << std::endl;
  std::cout << "Host: "
           << serviceHost << std::endl;
  std::cout << "Port: "
           << portNumber << std::endl;
  std::cout << "Number of threads: "
           << numberOfThreads << std::endl;
  std::cout << "Duration: "
           << duration << " s" << std::endl;
  std::cout << "Number of requests: "
           << totalRequests << std::endl;
  std::cout << "Completed requests: "
           << completedRequests << " ("
           << Round(completedRequests*100.0/totalRequests)
           << "%)" << std::endl;
  std::cout << "Failed requests: "
           << failedRequests << " ("
           << Round(failedRequests*100.0/totalRequests)
           << "%)" << std::endl;
  std::cout << "Average response time for all requests: "
           << Round(1000*totalTime.as_double()/totalRequests)
           << " ms" << std::endl;
  if (completedRequests!=0)
    std::cout << "Average response time for completed requests: "
             << Round(1000*completedTime.as_double()/completedRequests)
             << " ms" << std::endl;
  if (failedRequests!=0)
    std::cout << "Average response time for failed requests: "
             << Round(1000*failedTime.as_double()/failedRequests)
             << " ms" << std::endl;
  std::cout << "========================================" << std::endl;

  return 0;
}

Here is the call graph for this function:

void replace ( std::string &  str,
const std::string &  out,
const std::string &  in 
)

Definition at line 59 of file perftest.cpp.

{
  std::string::size_type index = str.find(out);
  if (index!=std::string::npos)
    str.replace(index, out.size(), in);
}

Here is the caller graph for this function:

int Round ( double  x)

Definition at line 69 of file perftest.cpp.

                   {
  return int(x+0.5);
}

Here is the caller graph for this function:

void sendRequests ( )

Definition at line 74 of file perftest.cpp.

                   {
  // Some variables...
  unsigned long completedRequests = 0;
  unsigned long failedRequests = 0;
  Glib::TimeVal completedTime(0,0);
  Glib::TimeVal failedTime(0,0);
  Glib::TimeVal tBefore;
  Glib::TimeVal tAfter;
  bool connected;
      
  while(run){
    
    // Create a client chain.
    Arc::Config client_config(confString);
    if(!client_config) {
      std::cerr << "Failed to load client configuration." << std::endl;
      return;
    }
    Arc::MCCLoader client_loader(client_config);
    Arc::MCC* client_entry = client_loader["soap"];
    if(!client_entry) {
      std::cerr << "Client chain have no entry point." << std::endl;
      return;
    }
    connected=true;

    Arc::MessageContext context;
    while(run and connected){
      // Prepare the request.
      Arc::NS echo_ns;
      echo_ns["echo"]="http://www.nordugrid.org/schemas/echo";
      Arc::PayloadSOAP req(echo_ns);
      req.NewChild("echo").NewChild("say")="HELLO";
      Arc::Message reqmsg;
      Arc::Message repmsg;
      Arc::MessageAttributes attributes_req;
      Arc::MessageAttributes attributes_rep;
      reqmsg.Attributes(&attributes_req);
      reqmsg.Context(&context);
      reqmsg.Payload(&req);
      repmsg.Attributes(&attributes_rep);
      repmsg.Context(&context);
      
      // Send the request and time it.
      tBefore.assign_current_time();
      Arc::MCC_Status status = client_entry->process(reqmsg,repmsg);
      tAfter.assign_current_time();
      
      if(!status) {
        // Request failed.
        failedRequests++;
        failedTime+=tAfter-tBefore;
           connected=false;
      } else {
        Arc::PayloadSOAP* resp = NULL;
        if(repmsg.Payload() != NULL) {
          // There is response.
          try{
            resp = dynamic_cast<Arc::PayloadSOAP*>(repmsg.Payload());
          }
          catch(std::exception&){ };
        }
        if(resp == NULL) {
          // Response was not SOAP or no response at all.
          failedRequests++;
          failedTime+=tAfter-tBefore;
          connected=false;
        } else {
          std::string xml;
          resp->GetXML(xml);
          if (std::string((*resp)["echoResponse"]["hear"]).size()==0){
            // The response was not what it should be.
            failedRequests++;
            failedTime+=tAfter-tBefore;
            connected=false;
          }
          else{
            // Everything worked just fine!
            completedRequests++;
            completedTime+=tAfter-tBefore;
          }
        }
      }
      if(repmsg.Payload()) delete repmsg.Payload();
    }
  }

  // Update global variables.
  Glib::Mutex::Lock lock(*mutex);
  ::completedRequests+=completedRequests;
  ::failedRequests+=failedRequests;
  ::completedTime+=completedTime;
  ::failedTime+=failedTime;
  finishedThreads++;
  std::cout << "Number of finished threads: " << finishedThreads << std::endl;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

unsigned long completedRequests

Definition at line 26 of file perftest.cpp.

Glib::TimeVal completedTime

Definition at line 29 of file perftest.cpp.

std::string confString
Initial value:
"\
    <ArcConfig\
      xmlns=\"http://www.nordugrid.org/schemas/ArcConfig/2007\"\
      xmlns:tcp=\"http://www.nordugrid.org/schemas/ArcMCCTCP/2007\">\
     <ModuleManager>\
        <Path>.libs/</Path>\
        <Path>../../hed/mcc/http/.libs/</Path>\
        <Path>../../hed/mcc/soap/.libs/</Path>\
        <Path>../../hed/mcc/tls/.libs/</Path>\
        <Path>../../hed/mcc/tcp/.libs/</Path>\
        <Path>../../lib/arc/</Path>\
     </ModuleManager>\
     <Plugins><Name>mcctcp</Name></Plugins>\
     <Plugins><Name>mcctls</Name></Plugins>\
     <Plugins><Name>mcchttp</Name></Plugins>\
     <Plugins><Name>mccsoap</Name></Plugins>\
     <Chain>\
      <Component name='tcp.client' id='tcp'><tcp:Connect><tcp:Host>HOSTNAME</tcp:Host><tcp:Port>PORTNUMBER</tcp:Port></tcp:Connect></Component>\
      <Component name='tls.client' id='tls'><next id='tcp'/></Component> \
      <Component name='http.client' id='http'><next id='tls'/><Method>POST</Method><Endpoint>HTTPPATH</Endpoint></Component>\
      <Component name='soap.client' id='soap' entry='soap'><next id='http'/></Component>\
     </Chain>\
    </ArcConfig>"

Definition at line 34 of file perftest.cpp.

unsigned long failedRequests

Definition at line 27 of file perftest.cpp.

Glib::TimeVal failedTime

Definition at line 30 of file perftest.cpp.

Definition at line 25 of file perftest.cpp.

Glib::Mutex* mutex

Definition at line 23 of file perftest.cpp.

bool run

Definition at line 24 of file perftest.cpp.

unsigned long totalRequests

Definition at line 28 of file perftest.cpp.

Glib::TimeVal totalTime

Definition at line 31 of file perftest.cpp.