diff options
author | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:21 +0000 |
---|---|---|
committer | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:21 +0000 |
commit | 3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c (patch) | |
tree | 197c810e5f5bce17b1233a7cb8d7b50c0bcd25e2 /TAO/performance-tests/Cubit/TAO/MT_Cubit | |
parent | 6b846cf03c0bcbd8c276cb0af61a181e5f98eaae (diff) | |
download | ATCD-3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c.tar.gz |
Repo restructuring
Diffstat (limited to 'TAO/performance-tests/Cubit/TAO/MT_Cubit')
27 files changed, 5106 insertions, 0 deletions
diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Cubit_Task.cpp b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Cubit_Task.cpp new file mode 100644 index 00000000000..2fb15abdc38 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Cubit_Task.cpp @@ -0,0 +1,259 @@ +// $Id$ + +#include "ace/Sched_Params.h" +#include "Globals.h" +#include "Cubit_Task.h" +#include "tao/TAO_Internal.h" +#include "ace/Barrier.h" + +Cubit_Task::Cubit_Task (void) +{ + // No-op. +} + +Cubit_Task::Cubit_Task (const char *args, + const char *orbname, + u_int num_of_objs, + ACE_Thread_Manager *thr_mgr, + u_int task_id) + : ACE_Task<ACE_SYNCH> (thr_mgr), + key_ ("Cubit"), + orbname_ ((char *) orbname), + orbargs_ ((char *) args), + num_of_objs_ (num_of_objs), + servants_ (0), + servants_iors_ (0), + task_id_ (task_id) +{ +} + +int +Cubit_Task::svc (void) +{ + ACE_hthread_t thr_handle; + ACE_Thread::self (thr_handle); + int prio; + + // thr_getprio () on the current thread should never fail. + + if (ACE_OS::thr_getprio (thr_handle, prio) == -1) + return -1; + + // char buffer[BUFSIZ]; + // sprintf (buffer, "server%d.log", this->task_id_); + // ACE_Log_Msg::instance()->clr_flags (ACE_Log_Msg::OSTREAM); + // ACE_Log_Msg::instance()->clr_flags (ACE_Log_Msg::STDERR); + // ACE_Log_Msg::instance()->clr_flags (ACE_Log_Msg::LOGGER); + // ofstream log (buffer); + // log.setf (ios::unitbuf); + // log.rdbuf()->unbuffered (1); + //ACE_Log_Msg::instance()->msg_ostream (&log); + + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) Beginning Cubit task with args = '%s' and priority %d\n", + orbargs_, + prio)); + int result = this->initialize_orb (); + + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "ORB initialization failed\n"), + -1); + result = this->create_servants (); + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "Create Servants failed.\n"), + -1); + + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + GLOBALS::instance ()->barrier_->wait (); + + // Handle requests for this object until we're killed, or one of + // the methods asks us to exit. + int r = this->orb_manager_.run (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + + if (r == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "run"), + -1); + ACE_TRY_CHECK; + + CORBA::ORB_var orb = + this->orb_manager_.orb (); + + orb->destroy (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "poa->destroy()"); + } + ACE_ENDTRY; + + // Need to clean up and do a CORBA::release on everything we've + // created! + + for (u_int i = 0; i < num_of_objs_; i++) + delete this->servants_[i]; + + return 0; +} + +int +Cubit_Task::initialize_orb (void) +{ + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + ACE_ARGV args (this->orbargs_); + + int argc = args.argc (); + char **argv = args.argv (); + + char orb_name[BUFSIZ]; + ACE_OS::sprintf (orb_name, + "ORB %d", + this->task_id_); + + int r = this->orb_manager_.init_child_poa (argc, + argv, + "persistent_poa", + orb_name + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + if (r == -1) + return -1; + + this->orb_ = this->orb_manager_.orb (); + + // Do the argument parsing. + if (this->task_id_ == 0) + { + if (GLOBALS::instance ()->parse_args (argc, + argv) == -1) + return -1; + ACE_NEW_RETURN (GLOBALS::instance ()->barrier_, + ACE_Barrier (GLOBALS::instance ()->num_of_objs + 1), + -1); + ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ready_mon, + GLOBALS::instance ()->ready_mtx_, 1)); + GLOBALS::instance ()->ready_ = 1; + GLOBALS::instance ()->ready_cnd_.broadcast (); + } + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "orb_init"); + return -1; + } + ACE_ENDTRY; + + return 0; +} + +char* +Cubit_Task::get_servant_ior (u_int index) +{ + if (index >= num_of_objs_) + return 0; + else + return ACE_OS::strdup (this->servants_iors_[index]); +} + +int +Cubit_Task::create_servants (void) +{ + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + CORBA::Object_var obj = + this->orb_->resolve_initial_references ("RootPOA" + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + PortableServer::POA_var poa = + PortableServer::POA::_narrow (obj.in () ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + PortableServer::POAManager_var manager = + poa->the_POAManager(ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + + manager->activate(ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + + // Create the array of cubit implementations. + ACE_NEW_RETURN (this->servants_, + Cubit_i *[this->num_of_objs_], + -1); + + // Create the array of strings. + ACE_NEW_RETURN (this->servants_iors_, + char* [this->num_of_objs_], + -1); + + char *buffer; + // Length of the string is the length of the key + 2 char id of + // the servant + null space. + int len = ACE_OS::strlen (this->key_) + 3; + + ACE_NEW_RETURN (buffer, + char[len], + -1); + + // This loop creates multiple servants, and prints out their + // IORs. + for (u_int i = 0; + i < this->num_of_objs_; + i++) + { + ACE_OS::sprintf (buffer, + "%s%02d", + this->key_, + this->task_id_); + + ACE_NEW_RETURN (this->servants_[i], + Cubit_i (this->orb_.in (), + poa.in ()), + -1); + + if (this->servants_[i] == 0) + ACE_ERROR_RETURN ((LM_ERROR, + " (%P|%t) Unable to create " + "implementation object #%d\n", + i), + 2); + + // Stringify the objref we'll be implementing, and print it + // to stdout. Someone will take that string and give it to + // some client. Then release the object. + + Cubit_var cubit = + this->servants_[i]->_this (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + + + CORBA::String_var str = + this->orb_->object_to_string (cubit.in () + ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + + this->servants_iors_[i] = + ACE_OS::strdup (str.in ()); + } + + delete [] buffer; + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, + "Cubit_Task::create_servants"); + return -1; + } + ACE_ENDTRY; + return 0; +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Cubit_Task.h b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Cubit_Task.h new file mode 100644 index 00000000000..b222ad4c0b2 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Cubit_Task.h @@ -0,0 +1,88 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// Cubit_Task.h +// +// = AUTHOR +// Andy Gokhale, Sumedh Mungee,Sergio Flores-Gaitan and Nagarajan Surendran. +// +// ============================================================================ + +#ifndef MT_CUBIT_TASK_H +#define MT_CUBIT_TASK_H + +#include "ace/Task.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/ARGV.h" +#include "tao/Utils/ORB_Manager.h" +#include "cubit_i.h" +#include "Globals.h" + +class Cubit_Task : public ACE_Task<ACE_SYNCH> +{ + // = TITLE + // Encapsulates an ORB for the Cubit application. +public: + Cubit_Task (const char *args, + const char* orbname, + u_int num_of_objs, + ACE_Thread_Manager *thr_mgr, + u_int task_id); + // Constructor. + + virtual int svc (void); + // Active Object entry point. + + char* get_servant_ior (u_int index); + // Gets the ior of the cubit servant in this task. + +protected: + Cubit_Task (void); + // No-op constructor. + +private: + int initialize_orb (void); + // Initialize the ORB, and POA. + + int create_servants (void); + // Create the servants. + + const char *key_; + // All cubit objects will have this as prefix to its key. + + char *orbname_; + // Name of the ORB. + + char *orbargs_; + // ORB arguments. + + u_int num_of_objs_; + // Number of objects we're managing. + + CORBA::ORB_var orb_; + // Pointer to the ORB + + Cubit_i **servants_; + // Array to hold the servants. + + char **servants_iors_; + // IOR strings of the servants. + + u_int task_id_; + // ID used for naming service object name. + + TAO_ORB_Manager orb_manager_; + // The TAO ORB Manager. +}; + +#endif /* MT_CUBIT_TASK_H */ diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Globals.cpp b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Globals.cpp new file mode 100644 index 00000000000..c8408545aac --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Globals.cpp @@ -0,0 +1,227 @@ +// $Id$ + +#include "Globals.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_errno.h" +#include "ace/Null_Mutex.h" + +Globals::Globals (void) + : thr_create_flags (0), + default_priority (0), + ior_file (0), + num_of_objs (2), + thread_per_rate (0), + use_multiple_priority (0), + ready_ (0), + ready_cnd_ (ready_mtx_), + barrier_ (0) +{ + const char default_endpoint[] = "iiop://"; + // Default to iiop + + ACE_OS::strcpy (endpoint, default_endpoint); +} + +int +Globals::parse_args (int argc, char *argv[]) +{ + ACE_Get_Opt opts (argc, argv, "e:t:f:rm"); + int c; + + while ((c = opts ()) != -1) + { + switch (c) + { + case 'm': + use_multiple_priority = 1; + break; + case 'r': + thread_per_rate = 1; + break; + case 'f': + ACE_NEW_RETURN (ior_file, + char[BUFSIZ], + -1); + ACE_OS::strcpy (ior_file, + opts.opt_arg ()); + break; + case 'e': + ACE_OS::strcpy (endpoint, + opts.opt_arg ()); + break; + case 't': + num_of_objs = ACE_OS::atoi (opts.opt_arg ()); + break; + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + "usage: %s \t" + "[-e <endpoint>] // starting endpoint \n\t\t\t" + "[-t <number_of_servants>] // # of servant threads to create \n\t\t\t" + "[-f <ior_file> ] // specify a file to output all ior's \n\t\t\t" + "[-m ] // Use multiple priorities for threads\n\t\t\t" + "[-r ] // Run the thread-per-rate test \n" + ,argv [0]), + -1); + } + } + + if (thread_per_rate == 1) + num_of_objs = THREAD_PER_RATE_OBJS; + + // Indicates successful parsing of the command-line. + return 0; +} + +int +Globals::sched_fifo_init (void) +{ +#if defined (ACE_HAS_THREADS) + // Enable FIFO scheduling, e.g., RT scheduling class on Solaris. +# if defined (_AIX) || defined (__APPLE__) + int scope = ACE_SCOPE_THREAD; +# else + int scope = ACE_SCOPE_PROCESS; +# endif /* _AIX */ + + if (ACE_OS::sched_params (ACE_Sched_Params (ACE_SCHED_FIFO, + SCHED_PRIORITY, + scope))) + { + if (ACE_OS::last_error () == EPERM) + { + ACE_DEBUG ((LM_MAX, + "User is not superuser, " + "so remain in time-sharing class\n")); + ACE_SET_BITS (GLOBALS::instance ()->thr_create_flags, THR_NEW_LWP); + GLOBALS::instance ()->default_priority = ACE_THR_PRI_OTHER_DEF; + return 1; + } + else + ACE_ERROR_RETURN ((LM_ERROR, + "%n: ACE_OS::sched_params failed\n%a"), + -1); + } + + ACE_SET_BITS (GLOBALS::instance ()->thr_create_flags, THR_BOUND); + ACE_SET_BITS (GLOBALS::instance ()->thr_create_flags, THR_SCHED_FIFO); + GLOBALS::instance ()->default_priority = ACE_THR_PRI_FIFO_DEF; + + return 0; +#else + + ACE_ERROR_RETURN ((LM_ERROR, + "Test will not run. This platform doesn't seem to have threads.\n"), + -1); +#endif /* ACE_HAS_THREADS */ +} + +MT_Priority::MT_Priority (void) + : num_priorities_ (0), + grain_ (0) +{ +} + +MT_Priority::~MT_Priority (void) +{ +} + +ACE_Sched_Priority +MT_Priority::get_high_priority (void) +{ + ACE_Sched_Priority high_priority; + +#if defined (VXWORKS) + high_priority = GLOBALS::instance ()->default_priority; +#elif defined (ACE_WIN32) + high_priority = + ACE_Sched_Params::priority_max (ACE_SCHED_FIFO, + ACE_SCOPE_THREAD); +#else + high_priority = GLOBALS::instance ()->default_priority; +#endif /* VXWORKS */ + return high_priority; +} + +ACE_Sched_Priority +MT_Priority::get_low_priority (u_int num_low_priority, + ACE_Sched_Priority prev_priority, + u_int use_multiple_priority) +{ +#if !defined (ACE_HAS_THREADS) + ACE_UNUSED_ARG (num_low_priority); + ACE_UNUSED_ARG (prev_priority); + ACE_UNUSED_ARG (use_multiple_priority); + return -1; +#else + ACE_Sched_Priority low_priority = ACE_THR_PRI_FIFO_DEF; + int policy = ACE_SCHED_FIFO; + + if (!ACE_BIT_ENABLED (GLOBALS::instance ()->thr_create_flags, + THR_SCHED_FIFO)) + { + low_priority = ACE_THR_PRI_OTHER_DEF; + policy = ACE_SCHED_OTHER; + } + + // Drop the priority. + if (use_multiple_priority) + { + this->num_priorities_ = 0; + + for (ACE_Sched_Priority_Iterator priority_iterator + (policy, ACE_SCOPE_THREAD); + priority_iterator.more (); + priority_iterator.next ()) + this->num_priorities_++; + + // 1 priority is exclusive for the high priority client. + this->num_priorities_--; + + // Drop the priority, so that the priority of clients will + // increase with increasing client number. + for (u_int j = 0; + j < num_low_priority; + j++) + { + low_priority = + ACE_Sched_Params::previous_priority (policy, + prev_priority, + ACE_SCOPE_THREAD); + prev_priority = low_priority; + } + // Granularity of the assignment of the priorities. Some OSs + // have fewer levels of priorities than we have threads in our + // test, so with this mechanism we assign priorities to groups + // of threads when there are more threads than priorities. + this->grain_ = num_low_priority / this->num_priorities_; + + if (this->grain_ <= 0) + this->grain_ = 1; + } + else + low_priority = + ACE_Sched_Params::previous_priority (policy, + prev_priority, + ACE_SCOPE_THREAD); + return low_priority; +#endif /* ACE_HAS_THREADS */ +} + +u_int +MT_Priority::number_of_priorities (void) +{ + return this->num_priorities_; +} + +u_int +MT_Priority::grain (void) +{ + return this->grain_; +} + + +#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION) +template ACE_Singleton<Globals, ACE_Null_Mutex> *ACE_Singleton<Globals, ACE_Null_Mutex>::singleton_; +#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */ diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Globals.h b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Globals.h new file mode 100644 index 00000000000..171458e98d7 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Globals.h @@ -0,0 +1,219 @@ +// -*- C++ -*- +// $Id$ + +#ifndef GLOBALS_H +#define GLOBALS_H + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// Globals.h +// +// = DESCRIPTION +// All the globally defined classes, functions, types, and #defines +// are centralized here. +// +// = AUTHOR +// Nagarajan Surendran <naga@cs.wustl.edu> +// +// ============================================================================ + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Get_Opt.h" +#include "ace/Sched_Params.h" +#include "ace/Singleton.h" +#include "ace/Condition_Thread_Mutex.h" + +#include "tao/orbconf.h" + +#if defined (VXWORKS) && defined (VME_DRIVER) +#define VX_VME_INIT \ +STATUS status = vmeDrv ();\ +if (status != OK)\ + ACE_DEBUG ((LM_DEBUG,\ + "ERROR on call to vmeDrv()\n"));\ + status = vmeDevCreate ("/vme");\ + if (status != OK)\ + ACE_DEBUG ((LM_DEBUG,\ + "ERROR on call to vmeDevCreate()\n")); +#else +#define VX_VME_INIT +#endif /* VXWORKS && VME_DRIVER */ + +#if defined (__Lynx__) +#define SCHED_PRIORITY 30 +#elif defined (VXWORKS) +#define SCHED_PRIORITY 6 +#elif defined (ACE_WIN32) || defined (__FreeBSD__) +#define SCHED_PRIORITY \ +ACE_Sched_Params::priority_max(ACE_SCHED_FIFO,ACE_SCOPE_THREAD) +#elif defined (HPUX) +#define SCHED_PRIORITY ACE_THR_PRI_FIFO_MAX +#else +#define SCHED_PRIORITY \ +ACE_THR_PRI_FIFO_DEF + 25 +#endif /* ! __Lynx__ */ + +#if defined (CHORUS_MVME) +#define PCCTIMER_INIT {int pTime;/*Initialize the PCC timer chip */pccTimerInit ();\ +if (pccTimer (PCC2_TIMER1_START, &pTime) != K_OK)\ +ACE_DEBUG ((LM_DEBUG,"pccTimer has a pending benchmark\n"));\ +} +#else /* !CHORUS_MVME */ +#define PCCTIMER_INIT +#endif /* !CHORUS_MVME */ + +#if defined (VXWORKS) && defined (FORCE_ARGS) +static char *force_argv[]= +{ + "server", + "-f", + "ior.txt" +}; +#endif /* defined (VXWORKS) && defined (FORCE_ARGS) */ + +#if defined (VXWORKS) && defined (FORCE_ARGS) +#define FORCE_ARGV(argc,argv) \ +argc = 4; +argv = force_argv; +#else /* !VXWORKS && !FORCE_ARGS */ +#define FORCE_ARGV(argc,argv) +#endif +// Number of utilisation computations to compute the duration of one +// util computation. +#define NUM_UTIL_COMPUTATIONS 10000 + +#define THREAD_PER_RATE_OBJS 4 +// Number of cubit objects in the thread per rate test. + +#define TASK_ID_LEN 32 +// length of the task id ,used in vxworks. + +#define TASKNAME_LEN 14 +// Length of the task name in the task control block for vxworks. + +#define UTIL_BOUND_CONSTANT 1000 +// A constant to avoid the utility thread blocking the machine and to +// bound its number of computations. + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +class ACE_Barrier; +ACE_END_VERSIONED_NAMESPACE_DECL + +class Globals +{ + // = TITLE + // Globals class to be used as a singleton. + // + // = DESCRIPTION + // This is used both by the server and client. +public: + Globals (void); + // default constructor. + + int parse_args (int argc, char **argv); + // parse the arguments. + + static int sched_fifo_init (void); + // Enables fifo scheduling eg., RT scheduling class on solaris. + // Returns 0 on success, 1 if insufficient permission, or -1 + // for other failure. As a side effect, sets thr_create_flags + // appropriately. + + long thr_create_flags; + // Thread creation flags. Must call sched_fifo_init () before + // accessing. + + int default_priority; + // Default thread priority, used for the high thread priority. + // Must call sched_fifo_init () before accessing. + + char endpoint[BUFSIZ]; + // endpoint to be used for ORB_init. + + char *ior_file; + // file name to read/write the iors of the servants. + + u_int num_of_objs; + // number of objects per servant thread. + + u_int thread_per_rate; + // thread_per_rate test flag. + + u_int use_multiple_priority; + // flag to use multiple priorities for the low priority servants + // instead of one priority. + + int ready_; + // ready flag used by the high priority thread to wake up the low + // priority threads after it's parsed the arguments. + + TAO_SYNCH_MUTEX ready_mtx_; + // mutex for the condition variable. + + TAO_SYNCH_CONDITION ready_cnd_; + // condition variable for the low priority threads to wait + //until the high priority thread is done with the arguments parsing. + + ACE_Barrier *barrier_; + // Barrier for the multiple servants to synchronize after binding to + // the orb. +}; + +// Make the globals a Singleton. +typedef ACE_Singleton<Globals,ACE_Null_Mutex> GLOBALS; + +class MT_Priority +{ + // = TITLE + // Helper class to find high and low priorities for the + // MT_Cubit application over multiple platforms. + // + // = DESCRIPTION + // This class has 2 methods, one for the high priority and the + // other for low priority.If the flag use_multiple_priority is + // passed then multiple priorities are used for the low priority + // threads. + +public: + MT_Priority (void); + // constructor. + + /// Destructor. + virtual ~MT_Priority (void); + + virtual ACE_Sched_Priority get_high_priority (void); + // Sets the priority of the high priority thread. + + virtual ACE_Sched_Priority get_low_priority + (u_int num_low_priority, + ACE_Sched_Priority prev_priority, + u_int use_multiple_priority); + // Sets the priority to be used for the low priority thread. + + u_int number_of_priorities (void); + // Accessor for num_priorities_. + + u_int grain (void); + // Accessor for grain_. + +protected: + u_int num_priorities_; + // Number of priorities used. + + u_int grain_; + // Granularity of the assignment of the priorities. Some OSs have + // fewer levels of priorities than we have threads in our test, so + // with this mechanism we assign priorities to groups of threads + // when there are more threads than priorities. +}; + +#endif /* GLOBALS_H */ diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/MT_Cubit.mpc b/TAO/performance-tests/Cubit/TAO/MT_Cubit/MT_Cubit.mpc new file mode 100644 index 00000000000..d5cc27cdc06 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/MT_Cubit.mpc @@ -0,0 +1,49 @@ +// -*- MPC -*- +// $Id$ + +project(*IDL): taoidldefaults, strategies { + IDL_Files { + cubit.idl + } + custom_only = 1 +} + +project(*server): taoexe, utils, portableserver, strategies { + after += *IDL + + Source_Files { + Timer.cpp + Cubit_Task.cpp + Globals.cpp + cubit_i.cpp + server.cpp + cubitS.cpp + cubitC.cpp + } + + IDL_Files { + } +} + +project(*client): taoexe, utils, portableserver, strategies { + after += *IDL + + Source_Files { + Timer.cpp + Globals.cpp + cubit_i.cpp + Cubit_Task.cpp + Util_Thread.cpp + Task_Client.cpp + client.cpp + cubitS.cpp + cubitC.cpp + } + + IDL_Files { + } + + verbatim(gnuace, local) { + LDLIBS += $(MATHLIB) + } +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/MT_Cubit_Test b/TAO/performance-tests/Cubit/TAO/MT_Cubit/MT_Cubit_Test new file mode 100755 index 00000000000..e52dd38cece --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/MT_Cubit_Test @@ -0,0 +1,102 @@ +#! /bin/sh +# $Id$ +# +# Spawns MT_Cubit server and client executables on a single host. + +usage="usage: $0 [-n <iterations>] [-r <host>] [-t] [-l] <# low priority threads>" +usage2=" [-l] suppresses use of -ORBgioplite, [-r runs client on <host>], [-t] uses /tmp" + +user=`whoami` +ior_file=/tmp/MT_Cubit-ior.${user} +iterations=1000 +client_exec_prefix=time +gioplite=-ORBgioplite +remote_host= + +if [ "$HOSTTYPE" = "lynxos" ]; then + server_exec_prefix='prio 30' + tmp='/tmp/' +else + server_exec_prefix= + tmp= +fi + +if [ ! "$PWD" ]; then + PWD=`pwd` +fi + +######## +######## Interpret command arguments. +######## +while getopts ?ln:r:t arg; do + case $arg in + l ) gioplite= ;; + n ) iterations=$OPTARG ;; + r ) remote_host=$OPTARG + ior_file=MT_Cubit-ior ;; + t ) tmp='/tmp/' ;; + '?' ) echo $usage; echo $usage2; exit 0 ;; + esac +done + +if [ "$OPTIND" ]; then + shift `expr $OPTIND - 1` + + if [ $# -ne 1 ]; then + echo $usage; echo $usage2 + exit 1 + fi +else + #### sh does not support $OPTIND. Arg error checking isn't as good. + if [ $# -lt 1 ]; then + echo $usage; echo $usage2 + exit 1 + fi + + shift `expr $# - 1` +fi + +threads=`expr $1 + 1` + + +######## +######## Make sure that the executables have been built. +######## +if [ ! -f ./server -o ! -f ./client ]; then + echo $0: 'server and/or client need to be built!' + exit -1 +fi + + +######## +######## Enable signal handler. +######## +trap 'kill -15 $server_pid; /bin/rm -f $ior_file; exit 0' 0 1 2 15 + + +######## +######## Start server and save its pid. +######## +/bin/rm -f $ior_file +$server_exec_prefix ./server -f $ior_file -t $threads $gioplite > \ + ${tmp}server.log 2>&1 & +server_pid=$! + +while [ ! -f $ior_file ]; do + sleep 2 +done + + +######## +######## Start client. +######## +if [ "$remote_host" ]; then + rsh $remote_host \ + "cd $PWD; LD_LIBRARY_PATH=$LD_LIBRARY_PATH $client_exec_prefix \ + ./client -f $ior_file -t $threads -n $iterations $gioplite" > \ + ${tmp}client-${threads}.log 2>&1 +else + $client_exec_prefix \ + ./client -f $ior_file -t $threads -n $iterations $gioplite > \ + ${tmp}client-${threads}.log 2>&1 +fi diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Makefile.am b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Makefile.am new file mode 100644 index 00000000000..bad37120f93 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Makefile.am @@ -0,0 +1,140 @@ +## Process this file with automake to create Makefile.in +## +## $Id$ +## +## This file was generated by MPC. Any changes made directly to +## this file will be lost the next time it is generated. +## +## MPC Command: +## ../bin/mwc.pl -type automake -noreldefs TAO.mwc + +ACE_BUILDDIR = $(top_builddir)/.. +ACE_ROOT = $(top_srcdir)/.. +TAO_BUILDDIR = $(top_builddir) +TAO_IDL = ACE_ROOT=$(ACE_ROOT) TAO_ROOT=$(TAO_ROOT) $(TAO_BUILDDIR)/TAO_IDL/tao_idl +TAO_IDL_DEP = $(TAO_BUILDDIR)/TAO_IDL/tao_idl +TAO_IDLFLAGS = -Ge 1 -Wb,pre_include=ace/pre.h -Wb,post_include=ace/post.h -I$(TAO_ROOT) -I$(srcdir) -g $(ACE_BUILDDIR)/apps/gperf/src/gperf +TAO_ROOT = $(top_srcdir) + +noinst_PROGRAMS = + +## Makefile.MT_Cubit_IDL.am + +if !BUILD_ACE_FOR_TAO + +BUILT_SOURCES = \ + cubitC.cpp \ + cubitC.h \ + cubitC.inl \ + cubitS.cpp \ + cubitS.h \ + cubitS.inl + +CLEANFILES = \ + cubit-stamp \ + cubitC.cpp \ + cubitC.h \ + cubitC.inl \ + cubitS.cpp \ + cubitS.h \ + cubitS.inl + +cubitC.cpp cubitC.h cubitC.inl cubitS.cpp cubitS.h cubitS.inl: cubit-stamp + +cubit-stamp: $(srcdir)/cubit.idl $(TAO_IDL_DEP) + $(TAO_IDL) $(TAO_IDLFLAGS) $(srcdir)/cubit.idl + @touch $@ + + +noinst_HEADERS = \ + cubit.idl + +endif !BUILD_ACE_FOR_TAO + +## Makefile.MT_Cubit_Client.am + +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS += client + +client_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -I$(TAO_ROOT) \ + -I$(TAO_BUILDDIR) + +client_SOURCES = \ + Cubit_Task.cpp \ + Globals.cpp \ + Task_Client.cpp \ + Timer.cpp \ + Util_Thread.cpp \ + client.cpp \ + cubitC.cpp \ + cubitS.cpp \ + cubit_i.cpp \ + Cubit_Task.h \ + Globals.h \ + Task_Client.h \ + Timer.h \ + Util_Thread.h \ + client.h \ + cubit_i.h + +client_LDADD = \ + $(TAO_BUILDDIR)/tao/libTAO_Strategies.la \ + $(TAO_BUILDDIR)/tao/libTAO_Utils.la \ + $(TAO_BUILDDIR)/tao/libTAO_PI.la \ + $(TAO_BUILDDIR)/tao/libTAO_CodecFactory.la \ + $(TAO_BUILDDIR)/tao/libTAO_PortableServer.la \ + $(TAO_BUILDDIR)/tao/libTAO_AnyTypeCode.la \ + $(TAO_BUILDDIR)/tao/libTAO.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Makefile.MT_Cubit_Server.am + +if !BUILD_ACE_FOR_TAO + +noinst_PROGRAMS += server + +server_CPPFLAGS = \ + -I$(ACE_ROOT) \ + -I$(ACE_BUILDDIR) \ + -I$(TAO_ROOT) \ + -I$(TAO_BUILDDIR) + +server_SOURCES = \ + Cubit_Task.cpp \ + Globals.cpp \ + Timer.cpp \ + cubitC.cpp \ + cubitS.cpp \ + cubit_i.cpp \ + server.cpp \ + Cubit_Task.h \ + Globals.h \ + Timer.h \ + cubit_i.h \ + server.h + +server_LDADD = \ + $(TAO_BUILDDIR)/tao/libTAO_Strategies.la \ + $(TAO_BUILDDIR)/tao/libTAO_Utils.la \ + $(TAO_BUILDDIR)/tao/libTAO_PI.la \ + $(TAO_BUILDDIR)/tao/libTAO_CodecFactory.la \ + $(TAO_BUILDDIR)/tao/libTAO_PortableServer.la \ + $(TAO_BUILDDIR)/tao/libTAO_AnyTypeCode.la \ + $(TAO_BUILDDIR)/tao/libTAO.la \ + $(ACE_BUILDDIR)/ace/libACE.la + +endif !BUILD_ACE_FOR_TAO + +## Clean up template repositories, etc. +clean-local: + -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.* + -rm -f gcctemp.c gcctemp so_locations *.ics + -rm -rf cxx_repository ptrepository ti_files + -rm -rf templateregistry ir.out + -rm -rf ptrepository SunWS_cache Templates.DB diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/README b/TAO/performance-tests/Cubit/TAO/MT_Cubit/README new file mode 100644 index 00000000000..6a9a0ff666c --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/README @@ -0,0 +1,215 @@ +// $Id$ + +THE MT_CUBIT EXAMPLE +-------------------- + +This directory contains the source code for the TAO "MT_Cubit" +benchmark, which enables us to measure the real-time performance of +TAO. MT_Cubit measures the latency, jitter, determinism, CPU +utilization, and degree of priority inversion incurred by TAO twoway +operations invoked under different workloads and priorities. For +more information and empirical results, please see + +http://www.cs.wustl.edu/~schmidt/PDF/RT-perf.pdf +http://www.cs.wustl.edu/~schmidt/PDF/RT-OS.pdf + +COMPILING +--------- + +Makefile is provided. Use make to compile. + +You can either run the server in the background in the same window as +the client or open a separate window for the client and server. + +OPTIONS +------- +Options are case sensitive, e.g., "-U" has a different meaning than "-u". + +(1) server: + +./server [-e <endpoint>] // Endpoint to use (URL style endpoint) + [-t <number_of_servants>] // # of servant threads to create + [-f <ior_file> ] // specify a file to output all ior's + [-m ] // Use multiple priorities for threads + [-r ] // Run the thread-per-rate test + +[-e <endpoint>] indicates the endpoint the ORB should bind to. + This is useful when a machine has more than one network interface. + + Default Value: Whatever the current active pluggable protocol + uses as its default endpoint. + +[-t <number_of_servants>] tells the server how many servants to create. + + Default Value: 2 + +[-f <ior_file> ] Use to specify a file to write all the iors from the + different servants out to disk. + + Default Value: nil, which means not to write the iors to disk. + +[-m ] For the 1 to n low priority servants, this parameter indicates + the use of a range of priorities for the threads. + + Default Value: Disabled. One priority will be used for the + low priority threads. + +[-r] turn on the thread-per-rate tests. (Priority inversion tests) + + Default Value: Disabled. + +The server will print the IOR of the servants, but it is not required +by the client. + +(2) client: + +./client [<ORB OPTIONS>] // ORB options, e.g., "-ORBObjRefStyle url" + [-d <datatype>] // what datatype to use for calls + [-n <num_calls>] // number of CORBA calls to make. + [-t <num_of_clients>] // number of client threads to create + [-f <ior_file>] // specify the file from which we read the object references (iors), if any. + [-r] // run thread-per-rate test. + [-o] // makes client use oneway calls. By default, twoway calls are used. + [-x] // makes a call to servant to shutdown + [-u <requests> ] // run the client utilization test for a number of <requests>. + [-1] // run the one-to-n test. + [-g <granularity>] // choose the granularity of the timing of CORBA calls + [-c] // run the number of context switches test. + [-m] // use multiple priorities for the low priority clients. + +[-d <datatype>] <datatype> is one of the following: + + 0 Octet + 1 Short + 2 Long + 3 Struct of the above 3 types + + Default Value: 0 + +[-n <num_calls>] is the number of CORBA twoway calls to be made + + Default Value: 1000 + +[-t <num_of_clients>] is the total number of concurrent clients to be + created. The clients will have successively decreasing + priorities if "-m" is specified. + + Default Value: 2 + +[-f <ior_file> ] Use to specify a file to read the object references (iors) of the + different servants from disk. + + Default Value: nil, which means not to read the iors from disk. + +[-r] run the thread-per-rate test. (Priority inversion tests) + + Default Value: Disabled. + +[-o] enables oneway calls instead of two-way calls. The oneway call + is a noop call (for now). + + Default Value: Disabled + +[-x] makes the client call the shutdown() method on the servant which in turn + invokes the shutdown() method on the ORB and causes it to exit gracefully. + + Default Value: Disabled + +[-u <seconds>] runs the client/server utilization test for a number of <requests>. + The output is the number of seconds for the test to make such number of requests. + Now run the same test but with the -l option to make the same number of requests, + this time not using CORBA, instead directly making function calls. The difference + in time for each test to make the same number of requests is the utilization of + the OS/ORB combined. + (Note: This option overrides any specified "-t" option) + + Default Value: Disabled + +[-1] runs one-to-n test. One servant services all low priority clients. + + Default Value: Disabled + +[-g <granularity>] choose the granularity of timing the CORBA calls. + This option should disappear sometime in the future, together with + all the modifications done to support this. + + What happens when this options is not used, is that (1) we start a + timer, (2) invoke the CORBA call, (3) stop the timer after call + returns. Some platforms have a very coarse grain timer (e.g. 10 + msec) and timing individual calls does not report very accurate + latency results. + + This option enables a way to (1) start the timer, (2) invoke + <granularity> calls, and (3) stop the timer. This way, we get a + better sense of the average latency of the CORBA calls. + + The downside is that the mechanism to enforce the frequency of calls + (i.e., 20 Hz, 10Hz, etc) is in conflict with this option. Such + mechanism depends on the individual time for each call to enforce + the calling frequency. + + Default Value: 1 (time each CORBA call) + +[-c] Obtain number of context switches. + + Default Value: Disabled + +[-m] Use multiple priorities for the low priority client + + Default Value: Disabled. Will use one priority for all low priority clients. + +Running on VxWorks +------------------ + +A typical run of the server and client on a single VxWorks target: + + -> iam "<your login>" + -> ld < server + -> ld < client + -> spa server, "-f", "ior.txt", "-t", "2" + -> spa client, "-f", "ior.txt", "-t", "2", "-n", "1000" + +RESULTS +------- + +The client prints the latency observed by the high priority client, +and the average latency observed by the low priority clients. Jitter +(standard deviation of the latency) is also printed by the client. + + +Running MT_Cubit on CHORUS: +-------------------------- + +1.You should make sure that you set the HOST environment variable on the +Chorus VME Board to the IP address of that Board before you run +MT_Cubit test. + +e.g +$rsh tambora1 setenv HOST 128.252.165.82 + +2. You should make sure that the path to IOR file has write permission +for ALL. + +server: +------ +$rsh host_name arun path_to_server -e iiop://DOTTED_DECIMAL_ADDRESS:0 + -f path_to_ior_file -ORBDottedDecimalAddresses 1 <server_options> + +Since Chorus doesn't support DNS, you should pass +dotted_decimal_address of the server machine to -e option. + +You DONT have to use -ORBDottedDecimalAddresses 1 if you have +TAO_USE_DOTTED_DECIMAL_ADDRESSES defined in your config.h file. + +e.g +$rsh tambora1 arun /MT_Cubit/server -e iiop://128.252.165.82:0 -f /ior +-ORBDottedDecimalAddresses 1 -t 10 -ORBObjRefStyle url + +client: +------- + +$rsh host_name arun path_to_client -f path_to_ior_file <client_options> + +e.g + +$rsh tambora2 arun /MT_Cubit/client -f /ior -t 10 -n 300 diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/README.tests b/TAO/performance-tests/Cubit/TAO/MT_Cubit/README.tests new file mode 100644 index 00000000000..c81387596f6 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/README.tests @@ -0,0 +1,44 @@ +// $Id$ + +Note: this file is in very rough version. Updates are coming soon. + +ORB/OS CPU processing Overhead Test +----------------------- +1. Execute the following command to obtain latency for CORBA requests: + + ./client -u 10000000 + +NOTE: This runs a copy of the server in the same process as the client +and executes 10,000,000 CORBA requests. Take a note of the total latency (L1). + +2. Execute the following command to obtain latency for collocated calls: + + ./client -u 10000000 -l + +NOTE: The total latency is L2. + +The percentage of overhead is calculated in the following way: + +% Overhead = ( (L1 - L2) / L1 ) * 100 + + +Latency Test +------------------------ +-- configuration: + (1) su to root when running Solaris or LynxOS. + (2) Make yourself an Administrator in Windows NT + +on the server side: + ./server -f ior -t 2 & +on the client side: + ./client -f ior -t 2 -n 4000 -x + +NOTE: run_same is a script that automates the running of the latency +tests. This script output everything to a file. + +Context Switch Test +------------------- +Use the same arguments as the latency test, and add "-c" + +NOTE: For Windows NT use a tool like Microsoft Spy that is installed with +MS Visual C++ to obtain the context switch data. diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Task_Client.cpp b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Task_Client.cpp new file mode 100644 index 00000000000..876035b66dc --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Task_Client.cpp @@ -0,0 +1,1147 @@ +// $Id$ + +#include "Task_Client.h" +#include "Timer.h" +#include "ace/Stats.h" +#include "tao/TAO_Internal.h" +#include "ace/Barrier.h" +#include "ace/Thread_Semaphore.h" +#include "ace/OS_NS_unistd.h" + +#if defined (ACE_HAS_QUANTIFY) +# include "quantify.h" +#endif /* ACE_HAS_QUANTIFY */ + +inline +ACE_UINT32 +ACE_round (ACE_timer_t t) +{ +#if defined (ACE_LACKS_FLOATING_POINT) + return t; +#else + return static_cast<ACE_UINT32> (t); +#endif +} + +ACE_RCSID(MT_Cubit, Task_Client, "$Id$") + +Task_State::Task_State (void) + : barrier_ (0), + key_ ("Cubit"), + loop_count_ (1000), + thread_count_ (2), + latency_ (0), + ave_latency_ (0), + datatype_ (CB_OCTET), + thread_per_rate_ (0), + global_jitter_array_ (0), + count_ (0), + shutdown_ (0), + oneway_ (0), + one_ior_ (0), + one_to_n_test_ (0), + context_switch_test_ (0), + iors_ (0), + iors_count_ (0), + ior_file_ (0), + granularity_ (1), + use_utilization_test_ (0), + high_priority_loop_count_ (0), + semaphore_ (0), + use_multiple_priority_ (0), + ready_ (0), + ready_cnd_ (ready_mtx_), + remote_invocations_ (1), + util_test_time_ (0) +{ +} + +int +Task_State::parse_args (int argc,char *argv[]) +{ + ACE_Get_Opt opts (argc, argv, "mu:n:t:d:rxof:g:1cl"); + int c; + + while ((c = opts ()) != -1) + switch (c) { + case 'g': + granularity_ = ACE_OS::atoi (opts.opt_arg ()); + if (granularity_ < 1) + granularity_ = 1; + break; + case 'l': + remote_invocations_ = 0; + break; + case 'c': + context_switch_test_ = 1; + break; + case 'm': + use_multiple_priority_ = 1; + break; + case '1': + one_to_n_test_ = 1; + break; + case 'u': + use_utilization_test_ = 1; + loop_count_ = ACE_OS::atoi (opts.opt_arg ()); + break; + case 'f': + ior_file_ = ACE_OS::strdup (opts.opt_arg ()); + break; + case 'o': + oneway_ = 1; + break; + case 'x': + shutdown_ = 1; + break; + case 'r': + thread_per_rate_ = 1; + break; + case 'd': + { + int datatype = ACE_OS::atoi (opts.opt_arg ()); + switch (datatype) + { + case CB_OCTET: + ACE_DEBUG ((LM_DEBUG, + "Testing Octets\n")); + datatype_ = CB_OCTET; + break; + case CB_LONG: + ACE_DEBUG ((LM_DEBUG, + "Testing Longs\n")); + datatype_ = CB_LONG; + break; + case CB_STRUCT: + ACE_DEBUG ((LM_DEBUG, + "Testing Structs\n")); + datatype_ = CB_STRUCT; + break; + case CB_SHORT: + default: + ACE_DEBUG ((LM_DEBUG, + "Testing Shorts\n")); + datatype_ = CB_SHORT; + break; + } + } + continue; + case 'n': // loop count + loop_count_ = (u_int) ACE_OS::atoi (opts.opt_arg ()); + continue; + case 't': + thread_count_ = (u_int) ACE_OS::atoi (opts.opt_arg ()); + continue; + case '?': + default: + ACE_DEBUG ((LM_DEBUG, "usage: %s\t" + "[<ORB OPTIONS>] // ORB options, e.g., \"-ORBobjrefstyle url\" \n\t\t\t" + "[-d <datatype>] // what datatype to use for calls: Octet=0, Short=1, Long=2, Struct=3 \n\t\t\t" + "[-n <num_calls>] // number of CORBA calls to make. \n\t\t\t" + "[-t <num_of_clients>] // number of client threads to create \n\t\t\t" + "[-f <ior_file>] // specify the file from which we read the object references (iors), if any.\n\t\t\t" + "[-r] // run thread-per-rate test. \n\t\t\t" + "[-o] // makes client use oneway calls. By default, twoway calls are used. \n\t\t\t" + "[-x] // makes a call to servant to shutdown \n\t\t\t" + "[-u <requests> ] // run the client utilization test for a number of <requests> \n\t\t\t" + "[-1] // run the one-to-n test. \n\t\t\t" + "[-g <granularity>] // choose the granularity of the timing of CORBA calls \n\t\t\t" + "[-c] // run the number of context switches test. \n\t\t\t" + "[-l] // use direct function calls, as opposed to CORBA requests. ONLY to be used with -u option.\n\t\t\t" + "[-m] // use multiple priorities for the low priority clients. \n" + ,argv [0])); + return -1; + } + + if (thread_per_rate_ == 1) + thread_count_ = THREAD_PER_RATE_OBJS; + + if (use_utilization_test_ == 1) + { + thread_count_ = 1; + shutdown_ = 1; + datatype_ = CB_OCTET; + } + + // Allocate the array of character pointers. + ACE_NEW_RETURN (iors_, + char *[thread_count_], + -1); + + if (ior_file_ != 0) + { + FILE *ior_file = + ACE_OS::fopen (ior_file_, "r"); + + if (ior_file == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Task_State::parse_args; " + "unable to open IOR file \"%s\"\n", + ior_file_), + -1); + char buf[BUFSIZ]; + u_int i; + + for (i = 0; + ACE_OS::fgets (buf, BUFSIZ, ior_file) != 0 + && i < thread_count_; + i++) + { + ACE_DEBUG ((LM_DEBUG, + buf)); + int j = ACE_OS::strlen (buf); + + // This overwrites the '\n' that was read from the file. + buf[j - 1] = 0; + iors_[i] = ACE_OS::strdup (buf); + } + + this->iors_count_ = i; + ACE_OS::fclose (ior_file); + } + + // thread_count_ + 2 because there is one utilization thread also + // wanting to begin at the same time the clients begin && the main + // thread wants to know when clients will start running to get + // accurate context switch numbers. + + if (thread_per_rate_ == 0) + { + if (use_utilization_test_ == 1) + // If we are to use the utilization test, include it in the + // barrier count. See description of this variable in header + // file. + ACE_NEW_RETURN (barrier_, + ACE_Barrier (thread_count_ + 2), + -1); + else + ACE_NEW_RETURN (barrier_, + ACE_Barrier (thread_count_ + 1), + -1); + } + else + ACE_NEW_RETURN (this->barrier_, + ACE_Barrier (thread_count_), + -1); + ACE_NEW_RETURN (this->semaphore_, + ACE_SYNCH_SEMAPHORE (0), + -1); + ACE_NEW_RETURN (this->latency_, + ACE_timer_t [thread_count_], + -1); + ACE_NEW_RETURN (this->global_jitter_array_, + JITTER_ARRAY *[this->thread_count_], + -1); + ACE_NEW_RETURN (this->count_, + u_int [thread_count_], + -1); + return 0; +} + +Task_State::~Task_State (void) +{ + int i; + + if (this->ior_file_ != 0) + ACE_OS::free (this->ior_file_); + + // Delete the strduped memory. + for (i = 0; i < this->iors_count_; i++) + ACE_OS::free (this->iors_ [i]); + + delete [] this->iors_; + // Delete the barrier. + + delete this->barrier_; + delete this->semaphore_; + delete [] this->latency_; + delete [] this->ave_latency_; + delete [] this->global_jitter_array_; + delete [] this->count_; +} + +Client::Client (ACE_Thread_Manager *thread_manager, + Task_State *ts, + int argc, + char **argv, + u_int id) + : ACE_Task<ACE_SYNCH> (thread_manager), + cubit_impl_ (CORBA::ORB::_nil (), + PortableServer::POA::_nil ()), + ts_ (ts), + num_ (0), + id_ (id), + call_count_ (0), + error_count_ (0), + my_jitter_array_ (0), + timer_ (0), + frequency_ (0), + latency_ (0), + argc_ (argc), + argv_ (argv) +{ +} + +Client::~Client (void) +{ + delete this->my_jitter_array_; + delete this->timer_; +} + +int +Client::func (u_int i) +{ + return i - 117; +} + +void +Client::put_latency (JITTER_ARRAY *jitter, + ACE_timer_t latency, + u_int thread_id, + u_int count) +{ + ACE_MT (ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->ts_->lock_)); + + this->ts_->latency_[thread_id] = latency; + this->ts_->global_jitter_array_[thread_id] = jitter; + this->ts_->count_[thread_id] = count; + + ACE_DEBUG ((LM_DEBUG, + "(%t) My latency was %A msec\n", + latency/ACE_ONE_SECOND_IN_MSECS)); +} + +// Returns the latency in usecs. +ACE_timer_t +Client::get_high_priority_latency (void) +{ + return (ACE_timer_t) this->ts_->latency_ [0]; +} + +// Returns the latency in usecs. +ACE_timer_t +Client::get_low_priority_latency (void) +{ + if (this->ts_->thread_count_ == 1) + return 0; + + ACE_timer_t l = 0; + + for (u_int i = 1; + i < this->ts_->thread_count_; + i++) + l += (ACE_timer_t) this->ts_->latency_[i]; + + // Return the average latency for the low priority threads. + return l / (ACE_timer_t) (this->ts_->thread_count_ - 1); +} + +ACE_timer_t +Client::get_latency (u_int thread_id) +{ + return static_cast<ACE_timer_t> (this->ts_->latency_ [thread_id]); +} + +// Returns the jitter in usecs. +ACE_timer_t +Client::get_high_priority_jitter (void) +{ + ACE_timer_t jitter = 0.0; + ACE_timer_t average = get_high_priority_latency (); + u_int number_of_samples = 0; + + // Compute the standard deviation, i.e., jitter, from the values + // stored in the global_jitter_array_. + + ACE_Stats stats; + + // We first compute the sum of the squares of the differences each + // latency has from the average. + + JITTER_ARRAY_ITERATOR iterator = + this->ts_->global_jitter_array_[0]->begin (); + + // latency in usecs. + ACE_timer_t *latency = 0; + + for (iterator.first (); + iterator.next (latency) == 1; + iterator.advance ()) + { + ++number_of_samples; + + ACE_timer_t difference = *latency - average; + jitter += difference * difference; + + if (stats.sample (ACE_round (*latency)) == -1) + ACE_DEBUG ((LM_DEBUG, "Error: stats.sample returned -1\n")); + + } + + // Return the square root of the sum of the differences computed + // above, i.e., jitter. + + ACE_DEBUG ((LM_DEBUG, + "high priority jitter (%u samples):\n", number_of_samples)); + + ACE_DEBUG ((LM_DEBUG,"Latency stats (time in usec)\n")); + stats.print_summary (1, 1, stderr); + + return sqrt (jitter / (number_of_samples - 1)); +} + +// Returns the jitter in usecs. + +ACE_timer_t +Client::get_low_priority_jitter (void) +{ + if (this->ts_->thread_count_ == 1) + return 0; + + ACE_timer_t jitter = 0.0; + ACE_timer_t average = get_low_priority_latency (); + u_int number_of_samples = 0; + + // Compute the standard deviation, i.e., jitter, from the values + // stored in the global_jitter_array_. + + ACE_Stats stats; + + // We first compute the sum of the squares of the differences each + // latency has from the average. + + for (u_int j = 1; + j < this->ts_->thread_count_; + j++) + { + ACE_DEBUG ((LM_DEBUG, "count: %u\n", ts_->count_[j])); + + JITTER_ARRAY_ITERATOR iterator = + this->ts_->global_jitter_array_ [j]->begin (); + + ACE_timer_t number_of_calls = + this->ts_->count_ [j] / this->ts_->granularity_; + + ACE_timer_t *latency = 0; + + u_int i = 0; + + for (iterator.first (); + i < number_of_calls && iterator.next (latency) == 1; + iterator.advance ()) + { + ++number_of_samples; + ACE_timer_t difference = *latency - average; + jitter += difference * difference; + stats.sample (ACE_round (*latency)); + } + } + + ACE_DEBUG ((LM_DEBUG, + "low priority jitter (%u samples):\n", number_of_samples)); + ACE_DEBUG ((LM_DEBUG,"Latency stats (time in usec)\n")); + stats.print_summary (1, 1, stderr); + + // Return the square root of the sum of the differences computed + // above, i.e. jitter. + return sqrt (jitter / (number_of_samples - 1)); +} + +ACE_timer_t +Client::get_jitter (u_int id) +{ + ACE_timer_t jitter = 0.0; + ACE_timer_t average = get_latency (id); + u_int number_of_samples = 0; + + // Compute the standard deviation, i.e., jitter, from the values + // stored in the global_jitter_array_. + + ACE_Stats stats; + + // We first compute the sum of the squares of the differences each + // latency has from the average. + + JITTER_ARRAY_ITERATOR iterator = + this->ts_->global_jitter_array_ [id]->begin (); + + ACE_timer_t number_of_calls = + this->ts_->count_[id] / this->ts_->granularity_; + + ACE_timer_t *latency = 0; + + u_int i = 0; + + for (iterator.first (); + i < number_of_calls && iterator.next (latency) == 1; + i ++,iterator.advance ()) + { + ++number_of_samples; + ACE_timer_t difference = *latency - average; + jitter += difference * difference; + stats.sample (ACE_round (*latency)); + } + + ACE_DEBUG ((LM_DEBUG, + "jitter for thread id %u:\n", id)); + ACE_DEBUG ((LM_DEBUG,"Latency stats (time in usec)\n")); + stats.print_summary (1, 1, stderr); + + // Return the square root of the sum of the differences computed + // above, i.e. jitter. + return sqrt (jitter / (number_of_samples - 1)); +} + +void +Client::find_frequency (void) +{ + if (this->ts_->thread_per_rate_ == 0) + { + if (this->id_ == 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) I'm the high priority client, my id is %d.\n", + this->id_)); + this->frequency_ = CB_HIGH_PRIORITY_RATE; + } + else + { + ACE_DEBUG ((LM_DEBUG, + "(%t) I'm a low priority client, my id is %d.\n", + this->id_)); + this->frequency_ = CB_LOW_PRIORITY_RATE; + } + } + else + switch (this->id_) + { + case CB_20HZ_CONSUMER: + this->frequency_ = CB_20HZ_CONSUMER_RATE; + ACE_DEBUG ((LM_DEBUG, + "(%t) I'm a %u Hz frequency client, " + "my id is %u.\n", + CB_20HZ_CONSUMER_RATE, + this->id_)); + break; + case CB_10HZ_CONSUMER: + this->frequency_ = CB_10HZ_CONSUMER_RATE; + ACE_DEBUG ((LM_DEBUG, + "(%t) I'm a %u Hz frequency client, " + "my id is %u.\n", + CB_10HZ_CONSUMER_RATE, + this->id_)); + break; + case CB_5HZ_CONSUMER: + this->frequency_ = CB_5HZ_CONSUMER_RATE; + ACE_DEBUG ((LM_DEBUG, + "(%t) I'm a %u Hz frequency client, " + "my id is %u.\n", + CB_5HZ_CONSUMER_RATE, + this->id_)); + break; + case CB_1HZ_CONSUMER: + this->frequency_ = CB_1HZ_CONSUMER_RATE; + ACE_DEBUG ((LM_DEBUG, + "(%t) I'm a %u Hz frequency client, " + "my id is %u.\n", + CB_1HZ_CONSUMER_RATE, + this->id_)); + break; + default: + ACE_DEBUG ((LM_DEBUG, + "(%t) Invalid Thread ID!!!!\n", + this->id_)); + } +} + +CORBA::ORB_ptr +Client::init_orb (ACE_ENV_SINGLE_ARG_DECL) +{ + ACE_DEBUG ((LM_DEBUG, + "I'm thread %t\n")); + + + // Convert the argv vector into a string. + ACE_ARGV tmp_args (this->argv_); + char tmp_buf[BUFSIZ]; + + ACE_OS::strcpy (tmp_buf, + tmp_args.buf ()); + // Add the argument. + ACE_OS::strcat (tmp_buf, + " -ORBRcvSock 32768 " + " -ORBSndSock 32768 "); + + ACE_DEBUG ((LM_DEBUG, + tmp_buf)); + + // Convert back to argv vector style. + ACE_ARGV tmp_args2 (tmp_buf); + int argc = tmp_args2.argc (); + char **argv = tmp_args2.argv (); + + char orbid[64]; + ACE_OS::sprintf (orbid, "orb:%d", this->id_); + CORBA::ORB_var orb = CORBA::ORB_init (argc, + argv, + orbid + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (CORBA::ORB::_nil ()); + + if (this->id_ == 0) + { + ACE_DEBUG ((LM_DEBUG, + "parsing the arguments\n")); + + int result = this->ts_->parse_args (argc, + argv); + if (result != 0) + return CORBA::ORB::_nil (); + + ACE_DEBUG ((LM_DEBUG, + "(%t)Arguments parsed successfully\n")); + + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ready_mon, + this->ts_->ready_mtx_, + CORBA::ORB::_nil ()); + this->ts_->ready_ = 1; + this->ts_->ready_cnd_.broadcast (); + ready_mon.release (); + } + + ACE_DEBUG ((LM_DEBUG, + "(%t) ORB_init success\n")); + return orb._retn (); +} + +int +Client::get_cubit (CORBA::ORB_ptr orb ACE_ENV_ARG_DECL) +{ + char *my_ior = + this->ts_->use_utilization_test_ == 1 + ? this->ts_->one_ior_ + : this->ts_->iors_[this->id_]; + + // If we are running the "1 to n" test make sure all low + // priority clients use only 1 low priority servant. + if (this->id_ > 0 + && this->ts_->one_to_n_test_ == 1) + my_ior = this->ts_->iors_[1]; + + if (my_ior == 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Must specify valid ior filename with -f option\n"), + -1); + + CORBA::Object_var objref = + orb->string_to_object (my_ior + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + if (CORBA::is_nil (objref.in ())) + ACE_ERROR_RETURN ((LM_ERROR, + " (%t) string_to_object Failed!\n"), + -1); + + // Narrow the CORBA::Object reference to the stub object, + // checking the type along the way using _is_a. + this->cubit_ = Cubit::_narrow (objref.in () + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + if (CORBA::is_nil (this->cubit_)) + ACE_ERROR_RETURN ((LM_ERROR, + "Create cubit failed\n"), + -1); + + ACE_DEBUG ((LM_DEBUG, + "(%t) Binding succeeded\n")); + + CORBA::String_var str = + orb->object_to_string (this->cubit_ + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (-1); + + ACE_DEBUG ((LM_DEBUG, + "(%t) CUBIT OBJECT connected to <%s>\n", + str.in ())); + + return 0; +} + +int +Client::svc (void) +{ + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + // Initialize the ORB. + CORBA::ORB_var orb = this->init_orb (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + + // Find the frequency of CORBA requests based on thread id. + this->find_frequency (); + + // Get the cubit object from the file. + int r = this->get_cubit (orb.in () ACE_ENV_ARG_PARAMETER); + ACE_TRY_CHECK; + if (r != 0) + return r; + + ACE_DEBUG ((LM_DEBUG, + "(%t) Waiting for other threads to " + "finish binding..\n")); + + // Wait for all the client threads to be initialized before going + // any further. + this->ts_->barrier_->wait (); + ACE_DEBUG ((LM_DEBUG, + "(%t; %D) Everyone's done, here I go!!\n")); + if (this->ts_->oneway_ == 1) + ACE_DEBUG ((LM_DEBUG, + "(%t) **** USING ONEWAY CALLS ****\n")); + + // Perform the tests. + int result = this->run_tests (); + if (result != 0) + return result; + + // release the semaphore + if (this->ts_->thread_per_rate_ == 1 + && this->id_ == this->ts_->thread_count_ - 1) + this->ts_->semaphore_->release (this->ts_->thread_count_ - 1); + else + this->ts_->semaphore_->release (); + + // shutdown the server if necessary. + if (this->ts_->shutdown_) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) CALLING SHUTDOWN() ON THE SERVANT\n")); + this->cubit_->shutdown (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + } + + CORBA::release (this->cubit_); + this->cubit_ = 0; + + orb->destroy (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "Task_Client::svc()"); + } + ACE_ENDTRY; + + // To avoid a memPartFree on VxWorks. It will leak memory, though. + ACE_THR_FUNC_RETURN status = 0; + + if (thr_mgr ()) + thr_mgr ()->exit (status, 1); + else + ACE_OS::thr_exit (status); + + return 0; +} + +int +Client::cube_octet (void) +{ + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + this->call_count_++; + // Cube an octet. + CORBA::Octet arg_octet = func (this->num_); + CORBA::Octet ret_octet = 0; + + START_QUANTIFY; + + if (this->ts_->use_utilization_test_ == 1 && this->ts_->remote_invocations_ == 0) + ret_octet = this->cubit_impl_.cube_octet (arg_octet + ACE_ENV_ARG_PARAMETER); + else + ret_octet = this->cubit_->cube_octet (arg_octet + ACE_ENV_ARG_PARAMETER); + + STOP_QUANTIFY; + ACE_TRY_CHECK; + + // Perform the cube operation. + arg_octet = arg_octet * arg_octet * arg_octet; + + if (arg_octet != ret_octet) + { + this->error_count_++; + ACE_ERROR_RETURN ((LM_ERROR, + "** cube_octet (%d) (--> %d)\n", + arg_octet, + ret_octet), + -1); + } + + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "call to cube_octet()\n"); + return -1; + } + ACE_ENDTRY; + return 0; +} + +int +Client::cube_short (void) +{ + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + this->call_count_++; + + CORBA::Short arg_short = func (this->num_); + CORBA::Short ret_short; + + START_QUANTIFY; + ret_short = this->cubit_->cube_short (arg_short + ACE_ENV_ARG_PARAMETER); + STOP_QUANTIFY; + ACE_TRY_CHECK; + arg_short = arg_short * arg_short * arg_short; + + if (arg_short != ret_short) + { + this->error_count_++; + ACE_ERROR_RETURN ((LM_ERROR, + "** cube_short (%d) (--> %d)\n", + arg_short , + ret_short), + -1); + } + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "call to cube_short\n"); + return -1; + } + ACE_ENDTRY; + return 0; +} + +int +Client::cube_long (void) +{ + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + this->call_count_++; + + CORBA::Long arg_long = func (this->num_); + CORBA::Long ret_long; + + START_QUANTIFY; + ret_long = this->cubit_->cube_long (arg_long + ACE_ENV_ARG_PARAMETER); + STOP_QUANTIFY; + ACE_TRY_CHECK; + + arg_long = arg_long * arg_long * arg_long; + + if (arg_long != ret_long) + { + this->error_count_++; + ACE_ERROR ((LM_ERROR, + "** cube_long (%d) (--> %d)\n", + arg_long, + ret_long)); + } + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "call to cube_long()\n"); + return -1; + } + ACE_ENDTRY; + return 0; +} + +int +Client::cube_struct (void) +{ + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + Cubit::Many arg_struct; + Cubit::Many ret_struct; + + this->call_count_++; + + arg_struct.l = func (this->num_); + arg_struct.s = func (this->num_); + arg_struct.o = func (this->num_); + + START_QUANTIFY; + ret_struct = this->cubit_->cube_struct (arg_struct + ACE_ENV_ARG_PARAMETER); + STOP_QUANTIFY; + ACE_TRY_CHECK; + + arg_struct.l = arg_struct.l * arg_struct.l * arg_struct.l ; + arg_struct.s = arg_struct.s * arg_struct.s * arg_struct.s ; + arg_struct.o = arg_struct.o * arg_struct.o * arg_struct.o ; + + if (arg_struct.l != ret_struct.l + || arg_struct.s != ret_struct.s + || arg_struct.o != ret_struct.o ) + { + this->error_count_++; + ACE_ERROR ((LM_ERROR, + "**cube_struct error!\n")); + } + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "call to cube_struct()\n"); + return -1; + } + ACE_ENDTRY; + return 0; +} + +int +Client::make_request (void) +{ + int result; + + if (this->ts_->oneway_ == 0) + { + switch (this->ts_->datatype_) + { + case CB_OCTET: + result = this->cube_octet (); + break; + // Cube a short. + case CB_SHORT: + result = this->cube_short (); + break; + // Cube a long. + case CB_LONG: + result = this->cube_long (); + break; + // Cube a "struct" ... + case CB_STRUCT: + result = this->cube_struct (); + break; + default: + ACE_ERROR_RETURN ((LM_ERROR, + "(%P|%t); %s:%d; unexpected datatype: %d\n", + this->ts_->datatype_), -1); + } + if (result != 0) + return result; + } + else + { + ACE_DECLARE_NEW_CORBA_ENV; + ACE_TRY + { + this->call_count_++; + START_QUANTIFY; + this->cubit_->noop (ACE_ENV_SINGLE_ARG_PARAMETER); + ACE_TRY_CHECK; + STOP_QUANTIFY; + } + ACE_CATCHANY + { + ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION, "oneway call noop()\n"); + return -1; + } + ACE_ENDTRY; + } + // return success. + return 0; +} + +void +Client::print_stats (void) +{ + // Perform latency stats only if we are not running the utilization + // tests. + if (this->call_count_ > 0 + && this->ts_->use_utilization_test_ == 0) + { + if (this->error_count_ == 0) + { + // Latency is in usecs. + ACE_timer_t calls_per_second = + (this->call_count_ * ACE_ONE_SECOND_IN_USECS) / this->latency_; + + // Calculate average (per-call) latency in usecs. + this->latency_ = this->latency_/this->call_count_; + + if (this->latency_ > 0) + { + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) cube average call ACE_OS::time\t= %A msec, \t" + "%A calls/second\n", + this->latency_ / ACE_ONE_SECOND_IN_MSECS, + calls_per_second)); + this->put_latency (this->my_jitter_array_, + this->latency_, + this->id_, + this->call_count_); + } + else + { + // Still we have to call this function to store a valid + // array pointer. + this->put_latency (this->my_jitter_array_, + 0, + this->id_, + this->call_count_); + + ACE_DEBUG ((LM_DEBUG, + "*** Warning: Latency, %f, is less than or equal to zero." + " Precision may have been lost.\n, this->latency_")); + } + } + ACE_DEBUG ((LM_DEBUG, + "%d calls, %d errors\n", + this->call_count_, + this->error_count_)); + } +} + +ACE_timer_t +Client::calc_delta (ACE_timer_t real_time, + ACE_timer_t delta) +{ + ACE_timer_t new_delta; +#if defined (ACE_LACKS_FLOATING_POINT) + new_delta = 40 * real_time / 100 + 60 * delta / 100; +#else /* !ACE_LACKS_FLOATING_POINT */ + new_delta = 0.4 * fabs (real_time) + 0.6 * delta; +#endif /* ACE_LACKS_FLOATING_POINT */ + return new_delta; +} + +int +Client::do_test (void) +{ + ACE_timer_t delta = 0; + u_int low_priority_client_count = this->ts_->thread_count_ - 1; + ACE_timer_t sleep_time = // usec + (ACE_ONE_SECOND_IN_USECS * this->ts_->granularity_)/this->frequency_; + u_int i; + int result = 0; + + for (i = 0; + // keep running for loop count, OR + i < this->ts_->loop_count_ + // keep running if we are the highest priority thread and at + // least another lower client thread is running, OR + || (id_ == 0 && this->ts_->thread_count_ > 1) + // keep running if test is thread_per_rate and we're not the + // lowest frequency thread. + || (this->ts_->thread_per_rate_ == 1 + && id_ < (this->ts_->thread_count_ - 1)); + i++) + { + // Start timing a call. + if ((i % this->ts_->granularity_) == 0 && + this->ts_->use_utilization_test_ == 0) + { + // Delay a sufficient amount of time to be able to enforce + // the calling frequency, e.g., 20Hz, 10Hz, 5Hz, 1Hz. + ACE_Time_Value tv (0, + (u_long) (sleep_time < delta + ? 0 + : sleep_time - delta)); + ACE_OS::sleep (tv); + this->timer_->start (); + } + this->num_ = i; + // make a request to the server object depending on the datatype. + result = this->make_request (); + if (result != 0) + return 2; + + // Stop the timer. + if (i % this->ts_->granularity_ == this->ts_->granularity_ - 1 + && this->ts_->use_utilization_test_ == 0) + { + this->timer_->stop (); + + // Calculate time elapsed. + ACE_timer_t real_time; + real_time = this->timer_->get_elapsed (); + // Recalculate delta = 0.4 * elapsed_time + 0.6 * + // delta. This is used to adjust the sleeping time so that + // we make calls at the required frequency. + delta = this->calc_delta (real_time,delta); + this->latency_ += real_time * this->ts_->granularity_; + + if ((result = this->my_jitter_array_->enqueue_tail (real_time)) != 0) + ACE_DEBUG ((LM_DEBUG, "(%t) Error: my_jitter_array->enqueue_tail() returned %d\n", result)); + } + if (this->ts_->thread_per_rate_ == 1 + && id_ < (this->ts_->thread_count_ - 1)) + { + if (this->ts_->semaphore_->tryacquire () != -1) + break; + } + else + // If we are the high priority client. If tryacquire() + // succeeded then a client must have done a release () on it, + // thus we decrement the client counter. + if (id_ == 0 + && this->ts_->thread_count_ > 1) + { + if (this->ts_->semaphore_->tryacquire () != -1) + { + low_priority_client_count --; + // If all clients are done then break out of loop. + if (low_priority_client_count <= 0) + break; + } + } + + } /* end of for () */ + ACE_DEBUG ((LM_DEBUG, "(%t; %D) do_test executed %u iterations\n", i)); + + return 0; +} + +int +Client::run_tests (void) +{ + int result; + ACE_NEW_RETURN (this->my_jitter_array_, + JITTER_ARRAY, + -1); + + ACE_NEW_RETURN (this->timer_, + MT_Cubit_Timer (this->ts_->granularity_), + -1); + if (this->ts_->use_utilization_test_ == 1) + this->timer_->start (); + + // Make the calls in a loop. + result = this->do_test (); + if (result != 0) + return result; + + if (id_ == 0) + this->ts_->high_priority_loop_count_ = + this->call_count_; + + if (this->ts_->use_utilization_test_ == 1) + { + this->timer_->stop (); + this->ts_->util_test_time_ = this->timer_->get_elapsed (); + } + + // Print the latency results. + this->print_stats (); + return 0; +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Task_Client.h b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Task_Client.h new file mode 100644 index 00000000000..98b43509b90 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Task_Client.h @@ -0,0 +1,372 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// Task_Client.h +// +// = AUTHOR +// Andy Gokhale, Sumedh Mungee, Sergio Flores-Gaitan, and +// Nagarajan Surendran. +// +// ============================================================================ + +#ifndef TASK_CLIENT_H +#define TASK_CLIENT_H + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Task.h" +#include "ace/Thread_Manager.h" +#include "ace/Get_Opt.h" +#include "ace/Profile_Timer.h" +#include "ace/ARGV.h" +#include "ace/Sched_Params.h" +#include "ace/High_Res_Timer.h" +#include "ace/Containers.h" + +#include "cubitC.h" +#include "cubit_i.h" +#include "Globals.h" +#include "Timer.h" + +#if defined (CHORUS_MVME) +# include "pccTimer.h" +#endif /* CHORUS_MVME */ + +// FUZZ: disable check_for_math_include +#if defined(ACE_HAS_EXCEPTIONS) && !defined (__KCC) && !defined (__xlC__) && \ + (!defined __GNUG__ || !defined (DIGITAL_UNIX)) + // Some plaforms define an exception structure in math.h... +# if defined (__GNUG__) + // And some compilers have this workaround. Disable it with this + // #define, to avoid warning about multiple #defines of exception. +# define _MATH_H_WRAPPER +# endif /* __GNUG__ */ +# define exception _math_exception +# include /**/ <math.h> +# undef exception +#else +# include /**/ <math.h> +#endif /* ACE_HAS_EXCEPTIONS */ + +#if defined (ACE_LACKS_FLOATING_POINT) +// The following is just temporary, until we finish the sqrt() +// implementation. +#define sqrt(X) (1) +#endif /* ACE_LACKS_FLOATING_POINT */ + +#if defined (ACE_HAS_QUANTIFY) +# define START_QUANTIFY quantify_start_recording_data (); +# define STOP_QUANTIFY quantify_stop_recording_data(); +# define CLEAR_QUANTIFY quantify_clear_data (); +#else /* ! ACE_HAS_QUANTIFY */ +# define START_QUANTIFY +# define STOP_QUANTIFY +# define CLEAR_QUANTIFY +#endif /* ! ACE_HAS_QUANTIFY */ + + +enum Cubit_Datatypes +{ + // = The various datatypes the client and the server can exchange. + CB_OCTET, + CB_SHORT, + CB_LONG, + CB_STRUCT, + + // = Rate constants. + CB_20HZ_CONSUMER = 0, + CB_10HZ_CONSUMER = 1, + CB_5HZ_CONSUMER = 2, + CB_1HZ_CONSUMER = 3, + + CB_20HZ_CONSUMER_RATE = 20, + CB_10HZ_CONSUMER_RATE = 10, + CB_5HZ_CONSUMER_RATE = 5, + CB_1HZ_CONSUMER_RATE = 1, + + CB_HIGH_PRIORITY_RATE = 20, + CB_LOW_PRIORITY_RATE = 10 +}; + +typedef ACE_Unbounded_Queue<ACE_timer_t> JITTER_ARRAY; +typedef ACE_Unbounded_Queue_Iterator<ACE_timer_t> JITTER_ARRAY_ITERATOR; + +class Task_State +{ + // = TITLE + // Maintains state common to multiple Cubit clients. + // + // = DESCRIPTION + // This class maintains state which is common to the potentially + // multiple concurrent clients. +public: + Task_State (void); + // Constructor. + + int parse_args (int argc,char **argv); + // parses the arguments with the provided argc and argv. + + ~Task_State (void); + // Destructor + + ACE_Barrier *barrier_; + // Barrier for the multiple clients to synchronize after binding to + // the servants. + + const char *key_; + // All cubit objects will have this as prefix to its key. + + u_int loop_count_; + // Number of times to loop, making calls. + + u_int thread_count_; + // Number of concurrent clients to create. + + ACE_timer_t *latency_; + // Array to store the latency for every client, indexed by + // thread-id. + + int *ave_latency_; + // Int array to store the latencies. + + Cubit_Datatypes datatype_; + // Which datatype to use to make the calls. + + TAO_SYNCH_MUTEX lock_; + // Lock to protect access to this object. + + u_int thread_per_rate_; + // Flag for the thread_per_rate test. + + JITTER_ARRAY **global_jitter_array_; + // This array stores the latency seen by each client for each + // request, to be used later to compute jitter. + + u_int *count_; + // This array stores the call count of each thread. They will not + // always have the same call count. + + u_int shutdown_; + // Flag that indicates if we are going to call the shutdown methos + // for the servant. + + u_int oneway_; + // Flag that indicates if we are going to use oneway calls instead + // of two-way. + + char *one_ior_; + // Ior array used if utilization test is run. + + u_int one_to_n_test_; + // indicates whether we are running the "1 to n" test, which has 1 + // low priority servant and n low priority clients. + + u_int context_switch_test_; + // flag to run context switch test + + char **iors_; + // Array of pointers used to hold the ior strings read from the ior file + // that the server created. + + int iors_count_; + // count on the number of iors + + char *ior_file_; + // Name of the filename that the server used to store the iors. + + u_int granularity_; + // this is the granularity of the timing of the CORBA requests. A + // value of 5 represents that we will take time every 5 requests, + // instead of the default of every request (1). + + u_int use_utilization_test_; + // flag to indicate we are to use the utilization test. By default + // we do not use it, because it can cause starvation with real-time + // threads + + u_int high_priority_loop_count_; + // Number of times the high priority looped. We are going to loop + // as long as there is low priority clients running, so as to + // maintain high priority traffic as long as low priority traffic is + // going through. + + ACE_SYNCH_SEMAPHORE *semaphore_; + // semaphore in order for the high priority client to keep running + // as long as the low priority clients are running. See explanation + // of "high_priority_loop_count_" member in this class. + + u_int use_multiple_priority_; + // flag to indicate we are to use multiple priorities for the low + // priority clients. By default we use only one priority for all + // client threads. + + ACE_High_Res_Timer timer_; + // global timer to be started by the utilization task. + + int ready_; + // ready flag used by the high priority thread to wake up the low + // priority threads after it's parsed the arguments. + + TAO_SYNCH_MUTEX ready_mtx_; + // mutex for the condition variable. + + TAO_SYNCH_CONDITION ready_cnd_; + // condition variable for the low priority threads to wait + //until the high priority thread is done with the arguments parsing. + + u_int remote_invocations_; + // flag to indicate whether we make remote versus local invocations + // to calculate accurately the ORB overhead. + + ACE_timer_t util_test_time_; + // holds the total time for the utilization test to complete. +}; + +class Client : public ACE_Task<ACE_SYNCH> +{ + // = TITLE + // The Cubit client. + // + // = DESCRIPTION + // This class implements the Cubit Client, which is an active object. + // `n' threads execute svc, and make 2way CORBA calls on the server +public: + Client (ACE_Thread_Manager *, + Task_State *ts, + int argc, + char **argv, + u_int id); + // Constructor, with a pointer to the common task state. + + ~Client (void); + // destructor. + + virtual int svc (void); + // The thread function. + + ACE_timer_t get_high_priority_latency (void); + // Returns the latency of the high priority thread in usecs. + + ACE_timer_t get_low_priority_latency (void); + // Returns the average latency found for the low + // priority threads in usecs. + + ACE_timer_t get_high_priority_jitter (void); + // Returns the high priority jitter in usecs. + + ACE_timer_t get_low_priority_jitter (void); + // Returns the jitter for all the low priority + // thread request in usecs. + + ACE_timer_t get_latency (u_int thread_id); + // gets the average latency for that thread. + + ACE_timer_t get_jitter (u_int id); + // gets the jitter for this thread. + + static int func (u_int i); + // Arbitrary generator used by the client to create the numbers to be + // cubed. + +private: + CORBA::ORB_ptr init_orb (ACE_ENV_SINGLE_ARG_DECL); + // initialize the ORB. + + void read_ior (void); + // reads the cubit ior from a file. + + int get_cubit (CORBA::ORB_ptr orb + ACE_ENV_ARG_DECL); + // gets the cubit object. + + int run_tests (void); + // Run the various tests. + + int make_request (void); + // make a CORBA request depending on the datatype. + + int do_test (void); + // makes the corba requests. + + int cube_octet (void); + // call cube_octet method on the cubit object. + + int cube_short (void); + // call cube short on the cubit object. + + int cube_long (void); + // call cube long on the cubit object. + + int cube_struct (void); + // call cube struct on the cubit object. + + void print_stats (void); + // prints the latency stats. + + void put_latency (JITTER_ARRAY *jitter, + ACE_timer_t latency, + u_int thread_id, + u_int count); + // Records the latencies in the <Task_State>. + + int parse_args (int, char **); + // Parses the arguments. + + void find_frequency (void); + // determines the frequency at which to make calls depending on the + // id of the thread. + + ACE_timer_t calc_delta (ACE_timer_t real_time, + ACE_timer_t delta); + // calculate the delta value. + + Cubit_ptr cubit_; + // pointer to the cubit object. + + Cubit_i cubit_impl_; + // cubit implementation object. + + Task_State *ts_; + // Pointer to shared state. + + u_int num_; + // number used for cubing. + + u_int id_; + // unique id of the task + + u_int call_count_; + // count of the number of calls made. + + u_int error_count_; + // number of calls that failed. + + JITTER_ARRAY *my_jitter_array_; + // ACE Unbounded set holding the latency values for all the + // requests of this thread. + + MT_Cubit_Timer *timer_; + // Timer using pccTimer for chorus and ACE_Timer for other platforms. + + ACE_timer_t frequency_; + // frequency of CORBA requests. + + ACE_timer_t latency_; + // aggregate latency of the requests. + + // command-line arguments. + int argc_; + char **argv_; +}; + +#endif /* !defined (TASK_CLIENT_H) */ diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Timer.cpp b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Timer.cpp new file mode 100644 index 00000000000..23cc89ffc17 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Timer.cpp @@ -0,0 +1,56 @@ +/* $Id$ */ + +#include "Timer.h" +#include "Task_Client.h" + +MT_Cubit_Timer::MT_Cubit_Timer (u_int granularity) + :granularity_ (granularity) +#if defined (CHORUS_MVME) + , pstartTime_ (0) + , pstopTime_ (0) +#endif /* CHORUS_MVME */ +{ +} + +void +MT_Cubit_Timer::start (void) +{ +#if defined (CHORUS_MVME) + this->pstartTime_ = pccTime1Get(); +#else /* CHORUS_MVME */ + this->timer_.start (); +#endif /* !CHORUS_MVME */ +} + +void +MT_Cubit_Timer::stop (void) +{ +#if defined (CHORUS_MVME) + this->pstopTime_ = pccTime1Get (); +#else /* CHORUS_MVME */ + // If CHORUS_MVME is not defined just use plain timer_.stop (). + this->timer_.stop (); + this->timer_.elapsed_time (this->delta_); +#endif /* !CHORUS_MVME */ +} + +ACE_timer_t +MT_Cubit_Timer::get_elapsed (void) +{ + ACE_timer_t real_time; +#if defined (ACE_LACKS_FLOATING_POINT) +# if defined (CHORUS_MVME) + real_time = (this->pstopTime_ - this->pstartTime_) / this->granularity_; +# else /* CHORUS_MVME */ + // Store the time in usecs. + real_time = (this->delta_.sec () * ACE_ONE_SECOND_IN_USECS + + this->delta_.usec ()) / this->granularity_; +# endif /* !CHORUS_MVME */ +#else /* !ACE_LACKS_FLOATING_POINT */ + // Store the time in usecs. + real_time = (ACE_timer_t) this->delta_.sec () * ACE_ONE_SECOND_IN_USECS + + (ACE_timer_t) this->delta_.usec (); + real_time = real_time/this->granularity_; +#endif /* !ACE_LACKS_FLOATING_POINT */ + return real_time; // in usecs. +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Timer.h b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Timer.h new file mode 100644 index 00000000000..45c22dbb567 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Timer.h @@ -0,0 +1,61 @@ +/* -*- C++ -*- */ +/* $Id$ */ + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// Timer.h +// +// = AUTHOR +// Andy Gokhale, Sumedh Mungee, Sergio Flores-Gaitan and Nagarajan +// Surendran. +// +// ============================================================================ + +#ifndef _MT_CUBIT_TIMER_H +#define _MT_CUBIT_TIMER_H + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/High_Res_Timer.h" + +class MT_Cubit_Timer +{ + // = TITLE + // A class that encapsulates the pccTimer for chorus and uses + // ACE Timer for other platforms. +public: + MT_Cubit_Timer (u_int granularity); + + void start (void); + void stop (void); + + ACE_timer_t get_elapsed (void); + +private: + ACE_High_Res_Timer timer_; + // timer. + + ACE_Time_Value delta_; + // Elapsed time in microseconds. + + u_int granularity_; + // This is the granularity of the timing of the CORBA requests. A + // value of 5 represents that we will take time every 5 requests, + // instead of the default of every request (1). + +#if defined (CHORUS_MVME) + // Variables for the pccTimer. + int pstartTime_; + int pstopTime_; +#endif /* CHORUS_MVME */ +}; + +#endif /* _MT_CUBIT_TIMER_H */ diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Util_Thread.cpp b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Util_Thread.cpp new file mode 100644 index 00000000000..98564ca9266 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Util_Thread.cpp @@ -0,0 +1,99 @@ +// $Id$ + +#include "Util_Thread.h" +#include "ace/ACE.h" +#include "ace/Barrier.h" + +ACE_RCSID(MT_Cubit, Util_Thread, "$Id$") + +Util_Thread::Util_Thread (Task_State *ts, + ACE_Thread_Manager *thr_mgr) + : ACE_Task<ACE_NULL_SYNCH> (thr_mgr), + done_ (0), + number_of_computations_ (0), + ts_ (ts) +{ +} + +int +Util_Thread::svc (void) +{ + ACE_hthread_t thr_handle; + ACE_Thread::self (thr_handle); + int prio; + + if (ACE_OS::thr_getprio (thr_handle, prio) == -1) + return -1; + + ACE_DEBUG ((LM_DEBUG, + "(%t) Utilization Thread created with priority %d, " + "waiting for threads to finish binding\n", + prio)); + + // This barrier synchronizes the utilization thread with the client + // threads i.e., the Util_thread should wait until all the clients + // have finished binding, and only then start measuring the + // utilization. + this->ts_->barrier_->wait (); + + ACE_DEBUG ((LM_DEBUG, + "(%t) )))))))) " + "utilization test STARTED at %D\n")); + + this->ts_->timer_.start (); + this->run_computations (); + this->ts_->timer_.stop (); + + ACE_DEBUG ((LM_DEBUG, + "(%t) (((((((( " + "utilization test ENDED at %D\n")); + return 0; +} + +u_long +Util_Thread::get_number_of_computations (void) +{ + return this->number_of_computations_; +} + +// Computation performed by the Utilization thread. We need this in a +// separate function to get it's execution time. + +void +Util_Thread::computation (void) +{ + // This is the number that the Util_Thread uses to check for + // primality. + const u_long CUBIT_PRIME_NUMBER = 509UL; + + // See if this number is prime. 2 and CUBIT_PRIME_NUMBER / 2 are + // the recommended values for min_factor and max_factor, as + // explained in ACE.h (is_prime). + ACE::is_prime (CUBIT_PRIME_NUMBER, + 2UL, + CUBIT_PRIME_NUMBER / 2); +} + +// Perform repeated prime factor computations on an arbitrary number. +// And you thought your life was boring... :-) + +int +Util_Thread::run_computations (void) +{ + while (this->done_ == 0) + { + // Bound the number of computations, since we can potentially + // block the machine if this thread never leaves the loop. + if (this->number_of_computations_ > (ts_->loop_count_ * UTIL_BOUND_CONSTANT)) + { + ACE_DEBUG ((LM_DEBUG, + "\t(%t) utilization test breaking loop so machine won't block.\n")); + break; + } + + this->computation (); + this->number_of_computations_++; + } + + return 0; +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/Util_Thread.h b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Util_Thread.h new file mode 100644 index 00000000000..cad2577da57 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/Util_Thread.h @@ -0,0 +1,57 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// Util_Thread.h +// +// = AUTHOR +// Andy Gokhale, Sumedh Mungee, Sergio Flores-Gaitan and Nagarajan +// Surendran. +// +// ============================================================================ + +#ifndef UTIL_THREAD_H +#define UTIL_THREAD_H + +#include "Task_Client.h" + +class Util_Thread : public ACE_Task<ACE_NULL_SYNCH> +{ + // = TITLE + // The thread that computes utilization. +public: + Util_Thread (Task_State *, + ACE_Thread_Manager *thr_mgr); + // Constructor. + + virtual int svc (void); + // The thread entry point function. + + u_long get_number_of_computations (void); + // Gets the number of computations the thread was able to perform. + + void computation (void); + // this is the actual "computation" being performed. + + int done_; + // Indicates whether we're done. + +private: + int run_computations (void); + // Run the computations. + + u_long number_of_computations_; + // This stores the number of computations performed + // by the Util_Thread so far + + Task_State *ts_; + // Pointer to the Task state. Stores the state + // common to the multiple client threads +}; + +#endif /* !defined (UTIL_THREAD_H) */ diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/client.cpp b/TAO/performance-tests/Cubit/TAO/MT_Cubit/client.cpp new file mode 100644 index 00000000000..e0d97da8166 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/client.cpp @@ -0,0 +1,865 @@ +// $Id$ + +#include "ace/config-all.h" + +#if defined (ACE_VXWORKS) && !defined (__RTP__) +# undef ACE_MAIN +# define ACE_MAIN client +#endif /* ACE_VXWORKS && !__RTP__ */ + +#include "ace/Sched_Params.h" +#include "tao/Strategies/advanced_resource.h" +#include "server.h" +#include "client.h" +#include "Globals.h" +#include "ace/Barrier.h" + +#if defined (ACE_HAS_QUANTIFY) +# include "quantify.h" +#endif /* ACE_HAS_QUANTIFY */ + +ACE_RCSID(MT_Cubit, client, "$Id$") + +#if defined (ACE_VXWORKS) && !defined (__RTP__) && !defined (ACE_HAS_PTHREADS) +u_int ctx = 0; +u_int ct = 0; + +typedef struct +{ + char name[15]; + WIND_TCB *tcb; +#if (CPU_FAMILY == PPC) + INSTR pc; +#else + INSTR *pc; +#endif +} task_info; + +const u_int SWITCHES = 25000; +task_info tInfo[SWITCHES]; + +extern "C" +int +switchHook (WIND_TCB *pOldTcb, // pointer to old task's WIND_TCB. + WIND_TCB *pNewTcb) // pointer to new task's WIND_TCB. +{ + ACE_UNUSED_ARG (pOldTcb); + + // We create the client threads with names starting with "@". + char* name = ::taskName (::taskIdSelf ()); + if (name[0] == '@') + ++ctx; + + if (ct < SWITCHES) + { + ACE_OS::strncpy (tInfo[ct].name, + name, + TASKNAME_LEN); + tInfo[ct].tcb = pNewTcb; + tInfo[ct].pc = pNewTcb->regs.pc; + ++ct; + } + + return 0; +} +#endif /* ACE_VXWORKS && !__RTP__ && !ACE_HAS_PTHREADS */ + +// Constructor. + +Client_i::Client_i (void) + : high_priority_client_ (0), + low_priority_client_ (0), + util_thread_ (0), + ts_ (0), + num_low_priority_ (0), + num_priorities_ (0), + grain_ (0), + counter_ (0), + task_id_ (0), + argc_ (0), + argv_ (0), + context_switch_ (0) +{ +} + +// Destructor. + +Client_i::~Client_i (void) +{ + delete this->high_priority_client_; + if (this->low_priority_client_ != 0) + // Delete the low priority task array. + for (u_int i = this->num_low_priority_; + i > 0; + i--) + delete this->low_priority_client_[i - 1]; + delete [] this->low_priority_client_; + delete this->util_thread_; + delete this->ts_; +} + +int +Client_i::init (int argc, char *argv[]) +{ + this->argc_ = argc; + this->argv_ = argv; + + int result; + result = GLOBALS::instance ()->sched_fifo_init (); + if (result == -1) + return result; + VX_VME_INIT; + FORCE_ARGV (this->argc_,this->argv_); + // Make sure we've got plenty of socket handles. This call will use + // the default maximum. + ACE::set_handle_limit (); + + ACE_NEW_RETURN (this->ts_, + Task_State, + -1); + + // Preliminary argument processing. + for (int i=0; + i< this->argc_; + ++i) + { + if (ACE_OS::strcmp (this->argv_[i],"-r") == 0) + this->ts_->thread_per_rate_ = 1; + else if (ACE_OS::strcmp (this->argv_[i],"-t") == 0 + && (i - 1 < this->argc_)) + this->ts_->thread_count_ = + ACE_OS::atoi (this->argv_[i+1]); + } + PCCTIMER_INIT; + return 0; +} + +void +Client_i::run (void) +{ + if (this->ts_->thread_per_rate_ == 0) + { + this->do_priority_inversion_test (); + + if (this->ts_->use_utilization_test_ == 1) + { + // Exit. Otherwise, the process just waits forever. + ACE_OS::exit (); + } + } + else + this->do_thread_per_rate_test (); +} + +#if defined (ACE_VXWORKS) && !defined (__RTP__) && !defined (ACE_HAS_PTHREADS) +void +Client_i::output_taskinfo (void) +{ + FILE *file_handle = ACE_OS::fopen ("taskinfo.txt", "w"); + + if (file_handle == 0) + ACE_ERROR ((LM_ERROR, + "%p\n", + "open")); + + ACE_DEBUG ((LM_DEBUG, + "--->Output file for taskinfo data is \"taskinfo.txt\"\n")); + + // This loop visits each client. thread_count_ is the number of + // clients. + + for (u_int j = 0; j < SWITCHES; ++j) + ACE_OS::fprintf(file_handle, + "\tname= %s\ttcb= %p\tpc= %p\n", + tInfo[j].name, + tInfo[j].tcb, + tInfo[j].pc); + + ACE_OS::fclose (file_handle); +} +#endif /* ACE_VXWORKS && !__RTP__ && !ACE_HAS_PTHREADS */ + +void +Client_i::get_context_switches (void) +{ +#if (defined (ACE_HAS_PRUSAGE_T) || defined (ACE_HAS_GETRUSAGE)) && !defined (ACE_WIN32) + + if (this->ts_->context_switch_test_ == 1) + { + this->timer_for_context_switch.start (); + this->timer_for_context_switch.get_rusage (this->usage); +# if defined (ACE_HAS_PRUSAGE_T) + this->context_switch_ = this->usage.pr_vctx + this->usage.pr_ictx; +# else /* ACE_HAS_PRUSAGE_T */ + this->context_switch_ = this->usage.ru_nvcsw + this->usage.ru_nivcsw; +# endif /* ACE_HAS_GETRUSAGE */ + } +#endif /* ACE_HAS_PRUSAGE_T || ACE_HAS_GETRUSAGE */ + +#if defined (ACE_VXWORKS) && !defined (__RTP__) && !defined (ACE_HAS_PTHREADS) + if (this->ts_->context_switch_test_ == 1) + { + ACE_DEBUG ((LM_DEBUG, + "Adding the context switch hook!\n")); + taskSwitchHookAdd ((FUNCPTR) &switchHook); + } +#endif /* ACE_VXWORKS && !__RTP__ */ +} + +void +Client_i::output_latency (void) +{ + FILE *latency_file_handle = 0; + char latency_file[BUFSIZ]; + char buffer[BUFSIZ]; + + ACE_OS::sprintf (latency_file, + "c%d", + this->ts_->thread_count_); + + ACE_DEBUG ((LM_DEBUG, + "--->Output file for latency data is \"%s\"\n", + latency_file)); + + latency_file_handle = ACE_OS::fopen (latency_file, "w"); + + // This loop visits each client. thread_count_ is the number of + // clients. + for (u_int j = 0; + j < this->ts_->thread_count_; + ++j) + { + ACE_OS::sprintf(buffer, + "%s #%d", + j == 0 + ? "High Priority" + : "Low Priority", + j); + // This loop visits each request latency from a client. + JITTER_ARRAY_ITERATOR iterator = + this->ts_->global_jitter_array_ [j]->begin (); + + u_int i = 0; + ACE_timer_t *latency = 0; + + for (iterator.first (); + (i < (j == 0 + ? this->ts_->high_priority_loop_count_ + : this->ts_->loop_count_) / this->ts_->granularity_) && + (iterator.next (latency)); + i++,iterator.advance ()) + { + ACE_OS::sprintf (buffer + ACE_OS::strlen (buffer), +#if defined (CHORUS_MVME) + "\t%u\n", +#else + "\t%f\n", +#endif /* !CHORUS_MVME */ + *latency); + ACE_OS::fputs (buffer, + latency_file_handle); + buffer[0] = 0; + } + } + + ACE_OS::fclose (latency_file_handle); +} + +// Mechanism to distribute the available priorities among the threads +// when there are not enough different priorities for all threads. + +void +Client_i::init_low_priority (void) +{ + ACE_Sched_Priority prev_priority = this->high_priority_; + if (this->ts_->use_multiple_priority_ == 1) + this->low_priority_ = + this->priority_.get_low_priority (this->num_low_priority_, + prev_priority, + 1); + else + this->low_priority_ = + this->priority_.get_low_priority (this->num_low_priority_, + prev_priority, + 0); + this->num_priorities_ = + this->priority_.number_of_priorities (); + this->grain_ = this->priority_.grain (); + this->counter_ = 0; +} + +void +Client_i::calc_util_time (void) +{ + MT_Cubit_Timer timer (ACE_ONE_SECOND_IN_MSECS); + // Time the utilization thread' "computation" to get % IdleCPU at the + // end of the test. + + // Execute one computation. + timer.start (); +#if defined (CHORUS_MVME) + this->util_thread_->computation (); + timer.stop (); + this->util_task_duration_ = timer.get_elapsed (); +#else + for (u_int i = 0; + i < NUM_UTIL_COMPUTATIONS; + ++i) + this->util_thread_->computation (); + + timer.stop (); + this->util_task_duration_ = timer.get_elapsed () / NUM_UTIL_COMPUTATIONS; +#endif /* !CHORUS_MVME */ +} + +int +Client_i::activate_high_client (void) +{ + ACE_NEW_RETURN (this->high_priority_client_, + Client (&this->client_thread_manager_, + this->ts_, + this->argc_, + this->argv_, + 0), + -1); + +#if defined (ACE_VXWORKS) + // Set a task_id string starting with "@", so we are able to + // accurately count the number of context switches. + ACE_OS::strcpy (this->task_id_, + "@High"); +#endif /* ACE_VXWORKS */ + + this->high_priority_ = + this->priority_.get_high_priority (); + + ACE_DEBUG ((LM_DEBUG, + "Creating 1 client with high priority of %d\n", + this->high_priority_)); + if (this->high_priority_client_->activate ( + GLOBALS::instance ()->thr_create_flags, + 1, + 0, + this->high_priority_, + -1, + 0, + 0, + 0, + 0, + (ACE_thread_t *) &this->task_id_) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p; priority is %d\n", + "activate failed", + this->high_priority_), + -1); + return 0; +} + +int +Client_i::activate_low_client (void) +{ + ACE_NEW_RETURN (this->low_priority_client_, + Client *[this->ts_->thread_count_], + -1); + + // Hack to make sure we have something in this pointer, when + // thread_count == 1. + this->low_priority_client_[0] = + this->high_priority_client_; + this->num_low_priority_ = + this->ts_->thread_count_ - 1; + + // Set the priority for the low priority threads. + this->init_low_priority (); + + ACE_DEBUG ((LM_DEBUG, + "Creating %d clients at priority %d\n", + this->ts_->thread_count_ - 1, + this->low_priority_)); + + for (u_int i = this->num_low_priority_; + i > 0; + i--) + { + ACE_NEW_RETURN (this->low_priority_client_ [i - 1], + Client (&this->client_thread_manager_, + this->ts_, + this->argc_, + this->argv_, + i), + -1); +#if defined (ACE_VXWORKS) + // Pace the connection establishment on VxWorks. + const ACE_Time_Value delay (0L, 500000L); + ACE_OS::sleep (delay); + + // Set a task_id string startiing with "@", so we are able to + // accurately count the number of context switches on VXWORKS + sprintf (this->task_id_, + "@Low%u", + i); +#endif /* ACE_VXWORKS */ + ACE_DEBUG ((LM_DEBUG, + "Creating client with thread ID %d and priority %d\n", + i, + this->low_priority_)); + // The first thread starts at the lowest priority of all the low + // priority clients. + if (this->low_priority_client_[i - 1]->activate ( + GLOBALS::instance ()->thr_create_flags, + 1, + 0, + this->low_priority_, // These are constructor defaults. + -1, // int grp_id = -1, + 0, // ACE_Task_Base *task = 0, + 0, // ACE_hthread_t thread_handles[] = 0, + 0, // void *stack[] = 0, + 0, // size_t stack_size[] = 0, + (ACE_thread_t *) &this->task_id_) == -1) + ACE_ERROR ((LM_ERROR, + "%p; priority is %d\n", + "activate failed", + this->low_priority_)); + + if (this->ts_->use_multiple_priority_ == 1) + { + this->counter_ = (this->counter_ + 1) % this->grain_; + + if (this->counter_ == 0 + // Just so when we distribute the priorities among the + // threads, we make sure we don't go overboard. + && this->num_priorities_ * this->grain_ > this->num_low_priority_ - (i - 1)) + // Get the next higher priority. + this->low_priority_ = ACE_Sched_Params::next_priority + (ACE_SCHED_FIFO, this->low_priority_, ACE_SCOPE_THREAD); + } + } /* end of for () */ + + return 0; +} + +int +Client_i::activate_util_thread (void) +{ + ACE_NEW_RETURN (this->util_thread_, + Util_Thread (this->ts_, + &this->util_thread_manager_), + -1); + + // Time the utilization thread' "computation" to get %IdleCPU at the + // end of the test. + this->calc_util_time (); + + if (this->ts_->use_utilization_test_ == 1) + // Activate the utilization thread only if specified. See + // description of this variable in header file. + { + this->low_priority_ = + ACE_Sched_Params::priority_min (ACE_SCHED_FIFO, + ACE_SCOPE_THREAD); + ACE_DEBUG ((LM_DEBUG, + "Creating utilization thread with priority of %d\n", + this->low_priority_)); + + // Activate the Utilization thread. It will wait until all + // threads have finished binding. + this->util_thread_->activate ( + GLOBALS::instance ()->thr_create_flags, + 1, + 0, + this->low_priority_); + } + else + this->util_thread_->close (); + return 0; +} + +void +Client_i:: print_context_stats (void) +{ + if (this->ts_->context_switch_test_ == 1) + { +#if defined (ACE_HAS_PRUSAGE_T) + this->timer_for_context_switch.stop (); + this->timer_for_context_switch.get_rusage (this->usage); + // Add up the voluntary context switches & involuntary context + // switches. + this->context_switch_ = + this->usage.pr_vctx + this->usage.pr_ictx - this->context_switch_; + ACE_DEBUG ((LM_DEBUG, + "Voluntary context switches = %d, Involuntary context switches = %d\n", + this->usage.pr_vctx, + this->usage.pr_ictx)); +#elif defined (ACE_HAS_GETRUSAGE) && !defined (ACE_WIN32) + this->timer_for_context_switch.stop (); + this->timer_for_context_switch.get_rusage (this->usage); + // Add up the voluntary context switches & involuntary context + // switches. + this->context_switch_ = + this->usage.ru_nvcsw + this->usage.ru_nivcsw - this->context_switch_; + ACE_DEBUG ((LM_DEBUG, + "Voluntary context switches=%d, Involuntary context switches=%d\n", + this->usage.ru_nvcsw, + this->usage.ru_nivcsw)); +#elif defined (ACE_VXWORKS) && !defined (__RTP__) && !defined (ACE_HAS_PTHREADS) + taskSwitchHookDelete ((FUNCPTR) &switchHook); + ACE_DEBUG ((LM_DEBUG, + "Context switches=%d\n", + ctx)); +#endif /* ACE_HAS_PRUSAGE_T */ + } +} + +void +Client_i::print_latency_stats (void) +{ + // If running the utilization test, don't report latency nor jitter. + if (this->ts_->use_utilization_test_ == 0) + { +#if defined (ACE_VXWORKS) + ACE_DEBUG ((LM_DEBUG, + "Test done.\n" + "High priority client latency : %f usec, jitter: %f usec\n" + "Low priority client latency : %f usec, jitter: %f usec\n", + this->high_priority_client_->get_high_priority_latency (), + this->high_priority_client_->get_high_priority_jitter (), + this->low_priority_client_[0]->get_low_priority_latency (), + this->low_priority_client_[0]->get_low_priority_jitter ())); + // Output the latency values to a file, tab separated, to import + // it to Excel to calculate jitter, in the mean time we come up + // with the sqrt() function. + output_latency (); +#elif defined (CHORUS_MVME) + ACE_DEBUG ((LM_DEBUG, + "Test done.\n" + "High priority client latency : %u usec\n" + "Low priority client latency : %u usec\n", + this->high_priority_client_->get_high_priority_latency (), + this->low_priority_client_[0]->get_low_priority_latency () )); + // Output the latency values to a file, tab separated, to import + // it to Excel to calculate jitter, in the mean time we come up + // with the sqrt() function. + output_latency (); +#else /* !CHORUS_MVME */ + ACE_DEBUG ((LM_DEBUG, "Test done.\n" + "High priority client latency : %f usec, jitter: %f usec\n" + "Low priority client latency : %f usec, jitter: %f usec\n", + this->high_priority_client_->get_high_priority_latency (), + this->high_priority_client_->get_high_priority_jitter (), + this->low_priority_client_[0]->get_low_priority_latency (), + this->low_priority_client_[0]->get_low_priority_jitter ())); + // output_latency (); +#endif /* !ACE_VXWORKS && !CHORUS_MVME */ + } +} + +void +Client_i::print_util_stats (void) +{ + if (this->ts_->use_utilization_test_ == 1) + { + ACE_DEBUG ((LM_DEBUG, + "(%t) Scavenger task performed \t%u computations\n" + "(%t) CLIENT task performed \t\t%u %s calls as requested\n\n" + "(%t) Utilization test time is \t\t%f microseconds\n\t%s\n", + this->util_thread_->get_number_of_computations (), + this->ts_->loop_count_, + this->ts_->remote_invocations_ == 1 ? "CORBA" : "local", + this->ts_->util_test_time_, + this->ts_->remote_invocations_ == 1 ? + "NOW run the same test again, adding the \"-l\" option. See README file for explanation." : + " " + )); + } +} + +void +Client_i::print_priority_inversion_stats (void) +{ + this->print_context_stats (); + this->print_latency_stats (); + this->print_util_stats (); +} + +int +Client_i::start_servant (void) +{ + char high_thread_args[BUFSIZ]; + + ACE_OS::sprintf (high_thread_args, + "-ORBSndSock 32768 " + "-ORBRcvSock 32768 "); + + Cubit_Task *high_priority_task; + + ACE_NEW_RETURN (high_priority_task, + Cubit_Task ((const char *) high_thread_args, + (const char *) "internet", + (u_int) 1, + &this->server_thread_manager_, + (u_int) 0), // task id 0. + -1); + + this->high_priority_ = + this->priority_.get_high_priority (); + + ACE_DEBUG ((LM_DEBUG, + "Creating servant 0 with high priority %d\n", + this->high_priority_)); + + // Make the high priority task an active object. + if (high_priority_task->activate ( + GLOBALS::instance ()->thr_create_flags, + 1, + 0, + this->high_priority_) == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) %p\n", + "\thigh_priority_task->activate failed")); + + ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ready_mon, GLOBALS::instance ()->ready_mtx_,-1)); + + // Wait on the condition variable till the high priority cubit_task + // has finished argument processing. + while (!GLOBALS::instance ()->ready_) + GLOBALS::instance ()->ready_cnd_.wait (); + // wait on the barrier till the servant writes its ior. + GLOBALS::instance ()->barrier_->wait (); + + this->ts_->one_ior_ = + high_priority_task->get_servant_ior (0); + + return 0; +} + +int +Client_i::do_priority_inversion_test (void) +{ + this->timer_.start (); +#if defined (ACE_VXWORKS) +# if !defined (__RTP__) && !defined (ACE_HAS_PTHREADS) + ctx = 0; +# endif + ACE_NEW_RETURN (this->task_id_, + char[TASK_ID_LEN], + -1); +#endif /* ACE_VXWORKS */ + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) <<<<<<< starting test on %D\n")); + GLOBALS::instance ()->num_of_objs = 1; + + for (int j = 0; j < this->argc_; j++) + if (ACE_OS::strcmp (this->argv_[j], "-u") == 0) + { + this->start_servant (); + break; + } + // Create and activate the high priority client. + int result = this->activate_high_client (); + if (result < 0) + return result; + + ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ready_mon, this->ts_->ready_mtx_,-1)); + + // Wait on the condition variable until the high priority thread + // wakes us up. + while (!this->ts_->ready_) + this->ts_->ready_cnd_.wait (); + + result = this->activate_low_client (); + + if (result < 0) + return result; + + // Activate the utilization thread if necessary. + result = this->activate_util_thread (); + if (result < 0) + return result; + + // Wait for all the client threads to be initialized before going + // any further. + this->ts_->barrier_->wait (); + + STOP_QUANTIFY; + CLEAR_QUANTIFY; + + // Collect the context switch data. + this->get_context_switches (); + + // Wait for all the client threads to exit (except the utilization + // thread). + this->client_thread_manager_.wait (); + + STOP_QUANTIFY; + ACE_DEBUG ((LM_DEBUG,"(%P|%t) >>>>>>> ending test on %D\n")); + + this->timer_.stop (); + this->timer_.elapsed_time (this->delta_); + + // Signal the utilization thread to finish with its work.. only if + // utilization test was specified. See description of this variable + // in header file. + if (this->ts_->use_utilization_test_ == 1) + { + this->util_thread_->done_ = 1; + + // This will wait for the utilization thread to finish. + this->util_thread_manager_.wait (); + } + + ACE_DEBUG ((LM_DEBUG, + "-------------------------- Stats -------------------------------\n")); + + this->print_priority_inversion_stats (); + + return 0; +} + +int +Client_i::do_thread_per_rate_test (void) +{ + Client CB_20Hz_client (&this->client_thread_manager_, + this->ts_, + this->argc_, + this->argv_, + CB_20HZ_CONSUMER); + Client CB_10Hz_client (&this->client_thread_manager_, + this->ts_, + this->argc_, + this->argv_, + CB_10HZ_CONSUMER); + Client CB_5Hz_client (&this->client_thread_manager_, + this->ts_, + this->argc_, + this->argv_, + CB_5HZ_CONSUMER); + Client CB_1Hz_client (&this->client_thread_manager_, + this->ts_, + this->argc_, + this->argv_, + CB_1HZ_CONSUMER); + ACE_Sched_Priority priority; + + priority = this->priority_.get_high_priority (); + ACE_DEBUG ((LM_DEBUG, + "Creating 20 Hz client with priority %d\n", + priority)); + + if (CB_20Hz_client.activate ( + GLOBALS::instance ()->thr_create_flags, + 1, + 1, + priority) == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) errno = %p: activate failed\n")); + // The high priority thread is parsing the arguments, so wait on the + // condition variable until it wakes us up. + + ACE_DEBUG ((LM_DEBUG, + "(%t) Waiting for argument parsing\n")); + + ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ready_mon, this->ts_->ready_mtx_,-1)); + + // Wait on the condition variable until the high priority thread + // wakes us up. + while (!this->ts_->ready_) + this->ts_->ready_cnd_.wait (); + + ACE_DEBUG ((LM_DEBUG, + "(%t) Argument parsing waiting done\n")); + + priority = ACE_Sched_Params::previous_priority (ACE_SCHED_FIFO, + priority, + ACE_SCOPE_THREAD); + ACE_DEBUG ((LM_DEBUG, + "Creating 10 Hz client with priority %d\n", + priority)); + + if (CB_10Hz_client.activate ( + GLOBALS::instance ()->thr_create_flags, + 1, + 1, + priority) == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) errno = %p: activate failed\n")); + + priority = ACE_Sched_Params::previous_priority (ACE_SCHED_FIFO, + priority, + ACE_SCOPE_THREAD); + ACE_DEBUG ((LM_DEBUG, + "Creating 5 Hz client with priority %d\n", + priority)); + + if (CB_5Hz_client.activate ( + GLOBALS::instance ()->thr_create_flags, + 1, + 1, + priority) == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) errno = %p: activate failed\n")); + + priority = ACE_Sched_Params::previous_priority (ACE_SCHED_FIFO, + priority, + ACE_SCOPE_THREAD); + ACE_DEBUG ((LM_DEBUG, + "Creating 1 Hz client with priority %d\n", + priority)); + + if (CB_1Hz_client.activate ( + GLOBALS::instance ()->thr_create_flags, + 1, + 1, + priority) == -1) + ACE_ERROR ((LM_ERROR, + "(%P|%t) errno = %p: activate failed\n")); + + // Wait for all the threads to exit. + this->client_thread_manager_.wait (); + + ACE_DEBUG ((LM_DEBUG, + "Test done.\n" + "20Hz client latency : %A usec, jitter: %A usec\n" + "10Hz client latency : %A usec, jitter: %A usec\n" + "5Hz client latency : %A usec, jitter: %A usec\n" + "1Hz client latency : %A usec, jitter: %A usec\n", + CB_20Hz_client.get_latency (0), + CB_20Hz_client.get_jitter (0), + CB_10Hz_client.get_latency (1), + CB_10Hz_client.get_jitter (1), + CB_5Hz_client.get_latency (2), + CB_5Hz_client.get_jitter (2), + CB_1Hz_client.get_latency (3), + CB_1Hz_client.get_jitter (3) )); + return 0; +} + +// This is the main routine of the client, where we create a high +// priority and a low priority client. we then activate the clients +// with the appropriate priority threads, and wait for them to +// finish. After they aer done, we compute the latency and jitter +// metrics and print them. + +int +main (int argc, char *argv[]) +{ + ACE_Log_Msg::instance()->clr_flags (ACE_Log_Msg::LOGGER); + + Client_i client; + + int result = client.init (argc,argv); + + if (result < 0) + return result; + + // Run the tests. + client.run (); + +#if defined (CHORUS_MVME) + int pTime; + if (pccTimer (PCC2_TIMER1_STOP, + &pTime) != K_OK) + ACE_DEBUG ((LM_DEBUG, + "pccTimer has a pending bench mark\n")); +#endif /* CHORUS_MVME */ + return 0; +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/client.h b/TAO/performance-tests/Cubit/TAO/MT_Cubit/client.h new file mode 100644 index 00000000000..263c3474e42 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/client.h @@ -0,0 +1,183 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// client.h +// +// = AUTHOR +// Andy Gokhale, Brian Mendel, Sumedh Mungee, Sergio Flores-Gaitan +// and Nagarajan Surendran. +// +// ============================================================================ + +#include "ace/Task.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Thread_Manager.h" +#include "ace/Get_Opt.h" +#include "ace/Sched_Params.h" + +#include "cubitC.h" +#include "Task_Client.h" +#include "Util_Thread.h" +#include "Timer.h" + +#if defined (CHORUS_MVME) +#include "pccTimer.h" +#endif /* CHORUS_MVME */ + +#if defined (VME_DRIVER) +#include <hostLib.h> +extern "C" STATUS vmeDrv (void); +extern "C" STATUS vmeDevCreate (char *); +#endif /* defined (VME_DRIVER) */ + +class Client_i : public virtual MT_Priority +{ + // = TITLE + // Helper class implementing the Multi-Threaded Cubit client. +public: + Client_i (void); + //constructor. + + virtual ~Client_i (void); + // destructor. + + int init (int argc, char *argv[]); + // Initialize the state of <Client_i>. + + void run (void); + // Run the tests. + + int do_priority_inversion_test (void); + // Performs the priority inversion test. + + int do_thread_per_rate_test (void); + // Performs the test with 4 threads each sending requests at rates + // of 20, 10, 5, and 1Hz. + + int start_servant (void); + // Starts the client utilization thread. + + void output_latency (void); + // output the latency results for the requests. + +#if defined (VXWORKS) + void output_taskinfo (void); + // Outputs the details of this task to a file taskinfo.txt. +#endif /* VXWORKS */ + +private: + void init_low_priority (void); + // Sets the priority to be used for the low priority clients. + + void calc_util_time (void); + // Calculate the time for one util computation. + + int activate_high_client (void); + // Activates the high priority client. + + int activate_low_client (void); + // Activates the low priority client. + + int activate_util_thread (void); + // Activates the utilization thread. + + void print_priority_inversion_stats (void); + // Prints the results of the tests. + + void print_context_stats (void); + // Prints the context switch results. + + void print_util_stats (void); + // Prints the utilization test results. + + void print_latency_stats (void); + // Prints the latency and jitter results. + + void get_context_switches (void); + // gets the number of context switches. + + Client *high_priority_client_; + // Pointer to the high priority client object. + + Client **low_priority_client_; + // Array to hold pointers to the low priority tasks. + + ACE_High_Res_Timer timer_; + // Timer for timing the tests. + + MT_Priority priority_; + // Priority helper object. + + Util_Thread *util_thread_; + // Utilization thread. + + ACE_Thread_Manager util_thread_manager_; + // Utilization thread manager. + + ACE_timer_t util_task_duration_; + // Time for one computation of utilization thread. + + Task_State *ts_; + // Pointer to task state. + + ACE_Sched_Priority high_priority_; + // Priority used for the high priority client. + + ACE_Sched_Priority low_priority_; + // Priority used by the low priority clients. + + u_int num_low_priority_; + // Number of low priority clients + + u_int num_priorities_; + // Number of priorities used. + + u_int grain_; + // Granularity of the assignment of the priorities. Some OSs have + // fewer levels of priorities than we have threads in our test, so + // with this mechanism we assign priorities to groups of threads + // when there are more threads than priorities. + + u_int counter_; + // counter of the number of priorities used within a grain. + + char *task_id_; + // Set a task_id string starting with "@", so we are able to + // accurately count the number of context switches. + + ACE_Time_Value delta_; + // elapsed time for the latency tests. + + int argc_; + // number of command line arguments. + + char **argv_; + // command line argument array. + + ACE_Thread_Manager client_thread_manager_; + // Create a separate manager for the client. This allows the use of + // its wait () method on VxWorks, without interfering with the + // server's (global) thread manager. + + u_int context_switch_; + // Stores the total number of context switches incurred by the + // program while making CORBA requests + + ACE_Thread_Manager server_thread_manager_; + // Thread manager for the servant used for utilization. + +#if (defined (ACE_HAS_PRUSAGE_T) || defined (ACE_HAS_GETRUSAGE)) && !defined (ACE_WIN32) + ACE_Profile_Timer timer_for_context_switch; + ACE_Profile_Timer::Rusage usage; +#endif /* (defined (ACE_HAS_PRUSAGE_T) || defined (ACE_HAS_GETRUSAGE)) && !defined (ACE_WIN32) */ +}; diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit.idl b/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit.idl new file mode 100644 index 00000000000..30285cd9d12 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit.idl @@ -0,0 +1,39 @@ +// $Id$ + +interface Cubit +{ + // = TITLE + // Defines an interface that encapsulates operations that cube + // numbers. + // + // = DESCRIPTION + // This interface encapsulates operations that cube + // octets, shorts, longs, structs and unions. + + struct Many + { + octet o; // + 3 bytes padding (normally) ... + long l; + short s; // + 2 bytes padding (normally) ... + }; + + octet cube_octet (in octet o); + // Cube an octet. + + short cube_short (in short s); + // Cube a short. + + long cube_long (in long l); + // Cube a long. + + Many cube_struct (in Many values); + // Cube each of the members of a struct. + + oneway void noop (); + // Null operation. + + oneway void shutdown (); + // shut down the application + +}; + diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit_i.cpp b/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit_i.cpp new file mode 100644 index 00000000000..cd3adaaf7ca --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit_i.cpp @@ -0,0 +1,77 @@ +// $Id$ + +#include "tao/ORB_Constants.h" +#include "cubit_i.h" +#include "Task_Client.h" + +ACE_RCSID(MT_Cubit, cubit_i, "$Id$") + +Cubit_i::Cubit_i (CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa) + : orb_ (CORBA::ORB::_duplicate (orb)), + poa_ (PortableServer::POA::_duplicate (poa)) +{ +} + +Cubit_i::~Cubit_i (void) +{ +} + +CORBA::Octet +Cubit_i::cube_octet (CORBA::Octet o + ACE_ENV_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return (CORBA::Octet) (o * o * o); +} + +CORBA::Short +Cubit_i::cube_short (CORBA::Short s + ACE_ENV_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return (CORBA::Short) (s * s * s); +} + +CORBA::Long +Cubit_i::cube_long (CORBA::Long l + ACE_ENV_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + return (CORBA::Long) (l * l * l); +} + +Cubit::Many +Cubit_i::cube_struct (const Cubit::Many &values + ACE_ENV_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + Cubit::Many out_values; + + out_values.o = values.o * values.o * values.o; + out_values.s = values.s * values.s * values.s; + out_values.l = values.l * values.l * values.l; + + return out_values; +} + +void +Cubit_i::noop (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + // does nothing. +} + +void Cubit_i::shutdown (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) Calling orb ()->shutdown ()\n")); + this->orb_->shutdown (); +} + +PortableServer::POA_ptr +Cubit_i::_default_POA (ACE_ENV_SINGLE_ARG_DECL_NOT_USED) +{ + return PortableServer::POA::_duplicate (this->poa_.in ()); +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit_i.h b/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit_i.h new file mode 100644 index 00000000000..eaa646cfb06 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/cubit_i.h @@ -0,0 +1,66 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// cubit_i.h +// +// = AUTHOR +// Andy Gokhale, Sumedh Mungee, Sergio Flores-Gaitan and Nagarajan Surendran. +// +// ============================================================================ + +#ifndef _CUBIT_I_H +#define _CUBIT_I_H + +#include "cubitS.h" + +class Cubit_i : public POA_Cubit +{ + // = TITLE + // Cubit implementation class. +public: + // = Initialization and termination methods. + Cubit_i (CORBA::ORB_ptr orb, + PortableServer::POA_ptr poa); + ~Cubit_i (void); + + virtual CORBA::Octet cube_octet (CORBA::Octet o + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual CORBA::Short cube_short (CORBA::Short s + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual CORBA::Long cube_long (CORBA::Long l + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual Cubit::Many cube_struct (const Cubit::Many &values + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual void noop (ACE_ENV_SINGLE_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual void shutdown (ACE_ENV_SINGLE_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)); + + virtual PortableServer::POA_ptr + _default_POA (ACE_ENV_SINGLE_ARG_DECL); + // The default POA + +protected: + CORBA::ORB_var orb_; + // Keep a pointer to the ORB so we can shut it down. + + PortableServer::POA_var poa_; + // The default POA.. +}; + +#endif /* _CUBIT_I_H */ diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/plot b/TAO/performance-tests/Cubit/TAO/MT_Cubit/plot new file mode 100755 index 00000000000..d83cc92e988 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/plot @@ -0,0 +1,50 @@ +eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}' + & eval 'exec perl -w -S $0 $argv:q' + if 0; + +# $Id$ +# +# Plots output from summarize. + +open (HIGH_LATENCY, "> h") || die "$0: unable to open \"h\""; +open (LOW_LATENCY, "> l") || die "$0: unable to open \"l\""; + +while (<>) { + if (/([\d\.]+) +([\d\.]+) +([\d\.]+) +([\d\.]+) +([\d\.]+)/) { + $low_priority_threads = $1; + $high_latency = $2; + $high_jitter = $3; + $low_latency = $4; + $low_jitter = $5; + print HIGH_LATENCY "$low_priority_threads $high_latency $high_jitter\n"; + if ($low_priority_threads > 0) { + print LOW_LATENCY "$low_priority_threads $low_latency $low_jitter\n"; + } + } +} + +close HIGH_LATENCY; +close LOW_LATENCY; + +open (GNUPLOT, "| gnuplot") || die "unable to open \"gnuplot\"\n"; + +print GNUPLOT + "set terminal postscript eps color\n" . + "set output \"/dev/null\"\n" . + "set yrange [0:]\n" . + "set grid ytics\n" . + "set xlabel \"Number of Low priority Clients\"\n" . + "set ylabel \"Latency per two-way request, microseconds\n" . + "set linestyle 1 linetype 2 pointtype 2\n" . + "set linestyle 2 linetype 1 pointtype 1\n" . + " plot 'l' title \"Low Priority Clients\" with linespoints ls 2\n" . + "replot 'h' title \"High Priority Client\" with linespoints ls 1\n" . + "set yrange [] writeback\n" . + "replot 'h' notitle with errorbars ls 1\n" . + "set output \"plot.eps\"\n" . + "set noautoscale y\n" . + "replot 'l' notitle with errorbars ls 2\n"; + +close GNUPLOT; + +unlink 'h', 'l'; diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/run_test.pl b/TAO/performance-tests/Cubit/TAO/MT_Cubit/run_test.pl new file mode 100755 index 00000000000..559bdaac458 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/run_test.pl @@ -0,0 +1,74 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +$usage = "run_tests.pl [-n iterations] [-r, for thread-per-rate] [-t low priority threads]\n"; + +use lib "../../../../../bin"; +use PerlACE::Run_Test; + +$iorfile = PerlACE::LocalFile ("mtcubit.ior"); +$iterations = 1000; +$low_priority_threads = 1; +$thread_per_rate = ''; + +#### +#### Process command line args. +#### +while ($#ARGV >= $[ && $ARGV[0] =~ /^-/) { + if ($ARGV[0] eq '-n') { + if ($ARGV[1] =~ /^[\da-zA-Z]+$/) { + $iterations = $ARGV[1]; shift; + } else { + print STDERR "$0: must provide argument for -n option\n"; + die $usage; + } + } elsif ($ARGV[0] eq '-r') { + $thread_per_rate = '-r'; + } elsif ($ARGV[0] eq '-t') { + if ($ARGV[1] =~ /^[\da-zA-Z]+$/) { + $low_priority_threads = $ARGV[1]; shift; + } else { + print STDERR "$0: must provide argument for -n option\n"; + die $usage; + } + } elsif ($ARGV[0] eq '-?') { + print "$usage"; + exit; + } else { + print STDERR "$0: unknown option $ARGV[0]\n"; + die $usage; + } + shift; +} + +$threads = $low_priority_threads + 1; + +# Make sure the file is gone, so we can wait on it. +unlink $iorfile; + +$SV = new PerlACE::Process ("server", "$thread_per_rate -f $iorfile -t $threads"); +$CL = new PerlACE::Process ("client", "$thread_per_rate -f $iorfile -t $threads -n $iterations"); + +$SV->Spawn (); + +if (PerlACE::waitforfile_timed ($iorfile, 10) == -1) { + print STDERR "ERROR: cannot find file <$iorfile>\n"; + $SV->Kill (); + exit 1; +} + +$client = $CL->SpawnWaitKill (180); +$SV->Kill (); + +unlink $iorfile; + +if ($client != 0) { + print STDERR "ERROR: client returned $client\n"; + exit 1; +} + +exit 0; diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/server.cpp b/TAO/performance-tests/Cubit/TAO/MT_Cubit/server.cpp new file mode 100644 index 00000000000..9235f275e82 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/server.cpp @@ -0,0 +1,394 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// server.cpp +// +// = AUTHOR +// Andy Gokhale, +// Sumedh Mungee, +// Sergio Flores-Gaitan, and +// Nagarajan Surendran +// +// ============================================================================ + +#include "ace/config-all.h" + +#if defined (ACE_VXWORKS) && !defined (__RTP__) +# undef ACE_MAIN +# define ACE_MAIN server +#endif /* ACE_VXWORKS && !__RTP__ */ + +#include "server.h" +#include "ace/Sched_Params.h" +#include "tao/Strategies/advanced_resource.h" + +// FUZZ: disable check_for_streams_include +#include "ace/streams.h" + +#include "ace/Barrier.h" + +#if defined (ACE_HAS_QUANTIFY) +# include "quantify.h" +#endif /* ACE_HAS_QUANTIFY */ + +ACE_RCSID(MT_Cubit, server, "$Id$") + +Server::Server (void) + :argc_ (0), + argv_ (0), + cubits_ (0), + high_priority_task_ (0), + low_priority_tasks_ (0), + high_argv_ (0), + low_argv_ (0) +{ +} + +int +Server::init (int argc, char **argv) +{ + int result; + + result = GLOBALS::instance ()->sched_fifo_init (); + if (result == -1) + return result; + + this->argc_ = argc; + this->argv_ = argv; + + VX_VME_INIT; + FORCE_ARGV (this->argc_,this->argv_); + // Make sure we've got plenty of socket handles. This call will use + // the default maximum. + ACE::set_handle_limit (); + return 0; +} + +int +Server::run (void) +{ + STOP_QUANTIFY; + CLEAR_QUANTIFY; + START_QUANTIFY; + + if (this->start_servants () != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Error creating the servants\n"), + -1); + ACE_DEBUG ((LM_DEBUG, + "Wait for all the threads to exit\n")); + // Wait for all the threads to exit. + this->servant_manager_.wait (); + STOP_QUANTIFY; + return 0; +} + +void +Server::prelim_args_process (void) +{ + int i; + + for (i = 0; i < this->argc_ ; i++) + { + if (ACE_OS::strcmp (this->argv_[i], "-e") == 0 && + i - 1 < this->argc_) + ACE_OS::strcpy (GLOBALS::instance ()->endpoint, + this->argv_[i+1]); + } +} + +void +Server::init_low_priority (void) +{ + ACE_Sched_Priority prev_priority = this->high_priority_; + + // Drop the priority. + if (GLOBALS::instance ()->thread_per_rate == 1 + || GLOBALS::instance ()->use_multiple_priority == 1) + this->low_priority_ = + this->priority_.get_low_priority (this->num_low_priority_, + prev_priority, + 1); + else + this->low_priority_ = + this->priority_.get_low_priority (this->num_low_priority_, + prev_priority, + 0); + + this->num_priorities_ = this->priority_.number_of_priorities (); + this->grain_ = this->priority_.grain (); + this->counter_ = 0; +} + +// Write the ior's to a file so the client can read them. + +int +Server::write_iors (void) +{ + u_int j; + + // By this time the num of objs should be set properly. + ACE_NEW_RETURN (this->cubits_, + char* [GLOBALS::instance ()->num_of_objs], + -1); + + this->cubits_[0] = ACE_OS::strdup (this->high_priority_task_->get_servant_ior (0)); + + for (j = 1; + j < GLOBALS::instance ()->num_of_objs; + ++j) + this->cubits_[j] = + ACE_OS::strdup (this->low_priority_tasks_[j-1]->get_servant_ior (0)); + + FILE *ior_f = 0; + + if (GLOBALS::instance ()->ior_file != 0) + ior_f = ACE_OS::fopen (GLOBALS::instance ()->ior_file, + "w"); + + for (j = 0; + j < GLOBALS::instance ()->num_of_objs; + ++j) + { + if (ior_f != 0) + { + ACE_OS::fprintf (ior_f, + "%s\n", + this->cubits_[j]); + ACE_DEBUG ((LM_DEBUG, + "this->cubits_[%d] ior = %s\n", + j, + this->cubits_[j])); + } + } + + if (ior_f != 0) + ACE_OS::fclose (ior_f); + + return 0; +} + +int +Server::activate_high_servant (void) +{ + char orbendpoint[BUFSIZ]; + + ACE_OS::sprintf (orbendpoint, + "-ORBEndpoint %s ", + GLOBALS::instance ()->endpoint); + + char *high_second_argv[] = + {orbendpoint, + const_cast<char *> ("-ORBSndSock 32768 "), + const_cast<char *> ("-ORBRcvSock 32768 "), + 0}; + ACE_NEW_RETURN (this->high_argv_, + ACE_ARGV (this->argv_, high_second_argv), + -1); + ACE_NEW_RETURN (this->high_priority_task_, + Cubit_Task (this->high_argv_->buf (), + "internet", + 1, + &this->servant_manager_, + 0), //task id 0. + -1); + + // Make the high priority task an active object. + if (this->high_priority_task_->activate + (GLOBALS::instance ()->thr_create_flags, + 1, + 0, + this->high_priority_) == -1) + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) task activation at priority %d ") + ACE_TEXT (" failed, exiting!\n%a"), + this->high_priority_, + -1)); + + ACE_MT (ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + ready_mon, + GLOBALS::instance ()->ready_mtx_, + -1)); + + // Wait on the condition variable for the high priority client to + // finish parsing the arguments. + + while (!GLOBALS::instance ()->ready_) + GLOBALS::instance ()->ready_cnd_.wait (); + + // Default return success. + return 0; +} + +int +Server::activate_low_servants (void) +{ + if (static_cast<int> (this->num_low_priority_) > 0) + { + ACE_DEBUG ((LM_DEBUG, + "Creating %d servants starting at priority %d\n", + this->num_low_priority_, + this->low_priority_)); + + // Create the low priority servants. + ACE_NEW_RETURN (this->low_priority_tasks_, + Cubit_Task *[GLOBALS::instance ()->num_of_objs], + -1); + } + + // Strip the provided addr from the endpoint and make the ORB + // choose the remaining endpoints based on the protocol used in + // the endpoint. + // + // e.g.: orignal endpoint: iiop://foobar:10001 + // random endpoint iiop:// + + const char protocol_delimiter[] = "://"; + + char *addr = ACE_OS::strstr (GLOBALS::instance ()->endpoint, + protocol_delimiter); + + size_t random_endpoint_length = + ACE_OS::strlen (GLOBALS::instance ()->endpoint) - + ACE_OS::strlen (addr) + + ACE_OS::strlen (protocol_delimiter); + + char random_endpoint[BUFSIZ]; + + ACE_OS::sprintf (random_endpoint, "-ORBEndpoint "); + + ACE_OS::strncat (random_endpoint, + GLOBALS::instance ()->endpoint, + random_endpoint_length); + + for (int i = this->num_low_priority_; + i > 0; + i--) + { + char *low_second_argv[] = + {random_endpoint, + const_cast<char *> ("-ORBSndSock 32768 "), + const_cast<char *> ("-ORBRcvSock 32768 "), + 0}; + ACE_NEW_RETURN (this->low_argv_, + ACE_ARGV (this->argv_, + low_second_argv), + -1); + + ACE_NEW_RETURN (this->low_priority_tasks_ [i - 1], + Cubit_Task (this->low_argv_->buf (), + "internet", + 1, + &this->servant_manager_, + i), + -1); + + // Make the low priority task an active object. + if (this->low_priority_tasks_[i - 1]->activate + (GLOBALS::instance ()->thr_create_flags, + 1, + 0, + this->low_priority_) == -1) + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) task activation at priority %d ") + ACE_TEXT (" failed, exiting!\n%a"), + this->low_priority_, + -1)); + + ACE_DEBUG ((LM_DEBUG, + "Created servant %d with priority %d\n", + i, + this->low_priority_)); + + // Use different priorities on thread per rate or multiple + // priority. + if (GLOBALS::instance ()->use_multiple_priority == 1 + || GLOBALS::instance ()->thread_per_rate == 1) + { + this->counter_ = (this->counter_ + 1) % this->grain_; + + if (this->counter_ == 0 + //Just so when we distribute the priorities among the + //threads, we make sure we don't go overboard. + && this->num_priorities_ * this->grain_ > this->num_low_priority_ - (i - 1)) + // Get the next higher priority. + this->low_priority_ = ACE_Sched_Params::next_priority + (ACE_SCHED_FIFO, + this->low_priority_, + ACE_SCOPE_THREAD); + } + } /* end of for() */ + + // default return success. + return 0; +} + +int +Server::start_servants (void) +{ + // Do the preliminary argument processing for options -p and -h. + this->prelim_args_process (); + + // Find the priority for the high priority servant. + this->high_priority_ = this->priority_.get_high_priority (); + + ACE_DEBUG ((LM_DEBUG, + "Creating servant 0 with high priority %d\n", + this->high_priority_)); + + // Activate the high priority servant task + if (this->activate_high_servant () < 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Failure in activating high priority servant\n"), + -1); + + this->num_low_priority_ = + GLOBALS::instance ()->num_of_objs - 1; + + // Initialize the priority of the low priority servants. + this->init_low_priority (); + + // Activate the low priority servants. + if (this->activate_low_servants () < 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Failure in activating low priority servant\n"), + -1); + + // Wait in the barrier. + GLOBALS::instance ()->barrier_->wait (); + + int result = this->write_iors (); + if (result != 0) + return result; + return 0; +} + + +int +main (int argc, char *argv[]) +{ + int result; + + Server server; + + result = server.init (argc, argv); + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Error in Initialization\n"), + 1); + + // run the server. + result = server.run (); + ACE_DEBUG ((LM_DEBUG, + "%s:%d\n", __FILE__, __LINE__)); + if (result != 0) + ACE_ERROR_RETURN ((LM_ERROR, + "Error while running the servants\n"), + 2); + return 0; +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/server.h b/TAO/performance-tests/Cubit/TAO/MT_Cubit/server.h new file mode 100644 index 00000000000..1cfd32f967e --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/server.h @@ -0,0 +1,141 @@ +/* -*- C++ -*- */ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO/tests +// +// = FILENAME +// server.h +// +// = AUTHOR +// Andy Gokhale, Sumedh Mungee,Sergio Flores-Gaitan and Nagarajan +// Surendran. +// +// ============================================================================ + +#ifndef SERVER_H +#define SERVER_H + +// ACE includes. + +#if defined (TAO_PLATFORM_SVC_CONF_FILE_NOTSUP) +#define TAO_DEFAULT_SERVER_STRATEGY_FACTORY_ARGS \ +{ "-ORBconcurrency", "thread-per-connection", \ + "-ORBdemuxstrategy", "dynamic", \ + "-ORBtablesize", "128" } +#endif /* TAO_PLATFORM_SVC_CONF_FILE_NOTSUP */ + +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Get_Opt.h" +#include "ace/Log_Msg.h" +#include "ace/ARGV.h" +#include "ace/Sched_Params.h" + +// MT Cubit application includes. +#include "cubit_i.h" +#include "Task_Client.h" +#include "Util_Thread.h" +#include "Globals.h" +#include "Cubit_Task.h" + +#if defined (VME_DRIVER) +#include <hostLib.h> +extern "C" STATUS vmeDrv (void); +extern "C" STATUS vmeDevCreate (char *); +#endif /* VME_DRIVER */ + +class Server +{ + // = TITLE + // A multithreaded cubit server class. + // + // = DESCRIPTION + // This class encapsulates the functionality of a multi-threaded + // cubit server. To use this, call initialize and then + // start_servants method. +public: + Server (void); + // Default constructor. + + int init (int argc, char **argv); + // Initialize the server state. + + int run (void); + // Run method. + +private: + int start_servants (void); + // Start the high and low priority servants. + + void prelim_args_process (void); + // Preliminary argument processing code. + + void init_low_priority (void); + // sets the priority to be used for the low priority servants. + + int write_iors (void); + // Writes the iors of the servants to a file + + int activate_high_servant (void); + // Activates the high priority servant. + + int activate_low_servants (void); + // Activates the low priority servants. + + int argc_; + // Number of arguments for the servant. + + char **argv_; + // Arguments for the ORB. + + char * *cubits_; + // Array to hold pointers to the Cubit objects. + + Cubit_Task *high_priority_task_; + // Pointer to the high priority task + + Cubit_Task **low_priority_tasks_; + // Array to hold pointers to the low priority tasks. + + ACE_Sched_Priority high_priority_; + // Priority used for the high priority servant. + + ACE_Sched_Priority low_priority_; + // Priority used by the low priority servants. + + u_int num_low_priority_; + // Number of low priority servants + + u_int num_priorities_; + // Number of priorities used. + + u_int grain_; + // Granularity of the assignment of the priorities. Some OSs have + // fewer levels of priorities than we have threads in our test, so + // with this mechanism we assign priorities to groups of threads + // when there are more threads than priorities. + + u_int counter_; + // count of the number of priorities used within a grain. + + ACE_ARGV *high_argv_; + // argv passed to the high priority servant. + + ACE_ARGV *low_argv_; + // argv passed to the low priority servants. + + MT_Priority priority_; + // Priority helper object. + + ACE_Thread_Manager servant_manager_; + // Thread manager for the servant threads. +}; + +#endif /* SERVER_H */ diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/summarize b/TAO/performance-tests/Cubit/TAO/MT_Cubit/summarize new file mode 100755 index 00000000000..3fb8cf24cc8 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/summarize @@ -0,0 +1,63 @@ +eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}' + & eval 'exec perl -w -S $0 $argv:q' + if 0; + +# $Id$ +# +# Summarizes results from a series of runs of MT_Cubit_Test, with +# different numbers of clients. Example usage: +# +# $ for i in 0 1 2 5 10 15 20 25 30 35 40 45 50; do ./MT_Cubit_Test $i; done +# $ ./summarize +# +# The first three lines above let this script run without specifying the +# full path to perl, as long as it is in the user's PATH. +# Taken from perlrun man page. + +@files = glob 'client-*.log'; +@total_threads = (); + +foreach $file (@files) { + my ($i); + ($i = $file) =~ s/client-(\d+).log/$1/; + push @total_threads, $i; +} + +print " Round-trip, usec\n"; +print "Low-priority High-priority Low-priority\n"; +print " threads Latency Jitter Latency Jitter\n"; + +foreach $total_threads (sort {$a <=> $b} @total_threads) { + undef $high_latency; + undef $high_jitter; + undef $low_latency; + undef $low_jitter; + + open (FILE, "client-${total_threads}.log") || + die "$0: unable to open \"client-${total_threads}.log\"\n"; + while (<FILE>) { + #### Add 0.5 to round instead of truncate. + + if (/^High priority client latency : ([\d\.]+) msec, jitter: ([\d\.]+)/) { + #### For old versions of client.cpp that printed out in msec. + $high_latency = ($1 + 0.5) * 1000; + $high_jitter = ($2 + 0.5) * 1000; + } elsif (/^High priority client latency : ([\d\.]+) usec, jitter: ([\d\.]+)/) { + $high_latency = $1 + 0.5; + $high_jitter = $2 + 0.5; + } elsif (/^Low priority client latency : ([\d\.]+) msec, jitter: ([\d\.]+)/) { + #### For old versions of client.cpp that printed out in msec. + $low_latency = ($1 + 0.5) * 1000; + $low_jitter = ($2 + 0.5) * 1000; + last; + } elsif (/^Low priority client latency : ([\d\.]+) usec, jitter: ([\d\.]+)/) { + $low_latency = $1 + 0.5;; + $low_jitter = $2 + 0.5;; + last; + } + } + close FILE; + + printf " %3d %8d %8d %8d %8d\n", + $total_threads - 1, $high_latency, $high_jitter, $low_latency, $low_jitter; +} diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/svc.conf b/TAO/performance-tests/Cubit/TAO/MT_Cubit/svc.conf new file mode 100644 index 00000000000..bb4034051b9 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/svc.conf @@ -0,0 +1,8 @@ +# $Id$ +# +# Please see $TAO_ROOT/docs/Options.html for details on these options. +# + +static Advanced_Resource_Factory "-ORBInputCDRAllocator null -ORBConnectionCacheLock null" +static Client_Strategy_Factory "-ORBProfileLock null -ORBClientConnectionHandler RW" +static Server_Strategy_Factory "-ORBConcurrency thread-per-connection -ORBPOALock null -ORBAllowReactivationOfSystemids 0" diff --git a/TAO/performance-tests/Cubit/TAO/MT_Cubit/svc.conf.xml b/TAO/performance-tests/Cubit/TAO/MT_Cubit/svc.conf.xml new file mode 100644 index 00000000000..3d76eda6597 --- /dev/null +++ b/TAO/performance-tests/Cubit/TAO/MT_Cubit/svc.conf.xml @@ -0,0 +1,11 @@ +<?xml version='1.0'?> +<!-- Converted from ./performance-tests/Cubit/TAO/MT_Cubit/svc.conf by svcconf-convert.pl --> +<ACE_Svc_Conf> + <!-- $Id$ --> + <!-- --> + <!-- Please see $TAO_ROOT/docs/Options.html for details on these options. --> + <!-- --> + <static id="Advanced_Resource_Factory" params="-ORBInputCDRAllocator null -ORBConnectionCacheLock null"/> + <static id="Client_Strategy_Factory" params="-ORBProfileLock null -ORBClientConnectionHandler RW"/> + <static id="Server_Strategy_Factory" params="-ORBConcurrency thread-per-connection -ORBPOALock null -ORBAllowReactivationOfSystemids 0"/> +</ACE_Svc_Conf> |