When this is specified with a number greater than 0 the server will start
almost as normal except it will not start any workers or module related
threads.
Instead it will create the specified number of simulation threads and time
how long it takes for them to be created, create a context, delete the
context and get cleaned up. A message is written to the log stating how long
it took and then the server will exit normally.
This is to help tune the client connection code and thread creation stuff.
+ /* run a few stats if -s was specified */
+ else if (!strncmp(argv[a], "-s", 2)) {
+ statcount = atoi(&argv[a][2]);
+ }
+
/* -x specifies the desired logging level */
else if (!strncmp(argv[a], "-x", 2)) {
verbosity = atoi(&argv[a][2]);
/* -x specifies the desired logging level */
else if (!strncmp(argv[a], "-x", 2)) {
verbosity = atoi(&argv[a][2]);
CtdlLogPrintf(CTDL_EMERG, "citserver: usage: "
"citserver "
"[-lLogFacility] "
CtdlLogPrintf(CTDL_EMERG, "citserver: usage: "
"citserver "
"[-lLogFacility] "
" [-tTraceFile]"
" [-xLogLevel] [-hHomeDir]\n");
exit(1);
" [-tTraceFile]"
" [-xLogLevel] [-hHomeDir]\n");
exit(1);
static int num_threads = 0; /* Current number of threads */
static int num_workers = 0; /* Current number of worker threads */
static int num_threads = 0; /* Current number of threads */
static int num_workers = 0; /* Current number of worker threads */
+long statcount = 0; /* are we doing a stats check? */
+static long stats_done = 0;
CtdlThreadNode *CtdlThreadList = NULL;
CtdlThreadNode *CtdlThreadSchedList = NULL;
CtdlThreadNode *CtdlThreadList = NULL;
CtdlThreadNode *CtdlThreadSchedList = NULL;
extern void close_masters (void);
extern void close_masters (void);
+void *simulation_worker (void*arg) {
+ struct CitContext *this;
+
+ this = CreateNewContext();
+ this->kill_me = 1;
+ this->state = CON_IDLE;
+ dead_session_purge(1);
+ begin_critical_section(S_SESSION_TABLE);
+ stats_done++;
+ end_critical_section(S_SESSION_TABLE);
+ return NULL;
+}
+
+
+void *simulation_thread (void *arg)
+{
+ long stats = statcount;
+
+ while(stats) {
+ CtdlThreadCreate("Connection simulation worker", CTDLTHREAD_BIGSTACK, simulation_worker, NULL);
+ stats--;
+ }
+ CtdlThreadStopAll();
+ return NULL;
+}
void go_threading(void)
{
int i;
CtdlThreadNode *last_worker;
void go_threading(void)
{
int i;
CtdlThreadNode *last_worker;
+ struct timeval start, now, result;
+ double last_duration;
/*
* Initialise the thread system
/*
* Initialise the thread system
ctdl_thread_internal_init();
/* Second call to module init functions now that threading is up */
ctdl_thread_internal_init();
/* Second call to module init functions now that threading is up */
+ if (!statcount)
+ initialise_modules(1);
+ else {
+ CtdlLogPrintf(CTDL_EMERG, "Running connection simulation stats\n");
+ gettimeofday(&start, NULL);
+ CtdlThreadCreate("Connection simulation master", CTDLTHREAD_BIGSTACK, simulation_thread, NULL);
+ }
+
/*
* This thread is now used for garbage collection of other threads in the thread list
/*
* This thread is now used for garbage collection of other threads in the thread list
/* FIXME: come up with a better way to dynamically alter the number of threads
* based on the system load
*/
/* FIXME: come up with a better way to dynamically alter the number of threads
* based on the system load
*/
#ifdef NEW_WORKER
if ((((CtdlThreadGetWorkers() < config.c_max_workers) && (CtdlThreadGetWorkers() <= num_sessions) ) || CtdlThreadGetWorkers() < config.c_min_workers) && (CT->state > CTDL_THREAD_STOP_REQ))
#else
#ifdef NEW_WORKER
if ((((CtdlThreadGetWorkers() < config.c_max_workers) && (CtdlThreadGetWorkers() <= num_sessions) ) || CtdlThreadGetWorkers() < config.c_min_workers) && (CT->state > CTDL_THREAD_STOP_REQ))
#else
else
CtdlLogPrintf (CTDL_WARNING, "Server strangled due to machine load average too high.\n");
}
else
CtdlLogPrintf (CTDL_WARNING, "Server strangled due to machine load average too high.\n");
}
CtdlThreadGC();
if (CtdlThreadGetCount() <= 1) // Shutting down clean up the garbage collector
CtdlThreadGC();
if (CtdlThreadGetCount() <= 1) // Shutting down clean up the garbage collector
#ifdef THREADS_USESIGNALS
if (CtdlThreadGetCount() && CT->state > CTDL_THREAD_STOP_REQ)
#else
#ifdef THREADS_USESIGNALS
if (CtdlThreadGetCount() && CT->state > CTDL_THREAD_STOP_REQ)
#else
- if (CtdlThreadGetCount())
+ if (CtdlThreadGetCount() && !statcount)
#endif
CtdlThreadSleep(1);
}
#endif
CtdlThreadSleep(1);
}
* If the above loop exits we must be shutting down since we obviously have no threads
*/
ctdl_thread_internal_cleanup();
* If the above loop exits we must be shutting down since we obviously have no threads
*/
ctdl_thread_internal_cleanup();
+
+ if (statcount) {
+ gettimeofday(&now, NULL);
+ timersub(&now, &start, &result);
+ last_duration = (double)result.tv_sec + ((double)result.tv_usec / (double) 1000000);
+ CtdlLogPrintf(CTDL_EMERG, "Simulated %ld connections in %f seconds\n", stats_done, last_duration);
+ }
extern double CtdlThreadLoadAvg;
extern double CtdlThreadWorkerAvg;
extern double CtdlThreadLoadAvg;
extern double CtdlThreadWorkerAvg;
+extern long statcount; /* are we doing a stats check? */
extern citthread_key_t ThreadKey;
void ctdl_thread_internal_init_tsd(void);
extern citthread_key_t ThreadKey;
void ctdl_thread_internal_init_tsd(void);