Back to index

citadel  8.12
Functions | Variables
stress.c File Reference
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <libcitadel.h>
#include "sysdep.h"
#include <time.h>
#include "citadel_ipc.h"

Go to the source code of this file.

Functions

void * worker (void *data)
int shift (int argc, char **argv, int start, int count)
int main (int argc, char **argv)

Variables

char *const message = "stress -n 500 -w 25 myserver > stress.csv\n"
static int w = 10
static int n = 100
static int m = 1000
static volatile int count = 0
static volatile int total = 0
static pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER
static pthread_mutex_t arg_mutex = PTHREAD_MUTEX_INITIALIZER
static pthread_mutex_t output_mutex = PTHREAD_MUTEX_INITIALIZER
static char username [12]
static char password [12]
static pthread_mutex_t rand_mutex = PTHREAD_MUTEX_INITIALIZER
static pthread_mutex_t start_mutex = PTHREAD_MUTEX_INITIALIZER
static pthread_cond_t start_cond = PTHREAD_COND_INITIALIZER

Function Documentation

int main ( int  argc,
char **  argv 
)

Definition at line 293 of file stress.c.

{
       void* data[2];              /* pass args to worker thread */
       pthread_t* threads;  /* A shitload of threads */
       pthread_attr_t attr; /* Thread attributes (we use defaults) */
       int i;               /* Counters */
       long runtime;        /* Run time for each thread */

       /* Read argument list */
       for (i = 0; i < argc; i++) {
              if (!strcmp(argv[i], "-n")) {
                     n = atoi(argv[i + 1]);
                     argc = shift(argc, argv, i, 2);
              }
              if (!strcmp(argv[i], "-w")) {
                     w = atoi(argv[i + 1]);
                     argc = shift(argc, argv, i, 2);
              }
              if (!strcmp(argv[i], "-m")) {
                     m = atoi(argv[i + 1]);
                     argc = shift(argc, argv, i, 2);
              }
              if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
                     fprintf(stderr, "Read stress.c for usage info\n");
                     return 1;
              }
       }

       data[0] = (void*)argc;      /* pass args to worker thread */
       data[1] = (void*)argv;      /* pass args to worker thread */

       /* This is how many total messages will be posted */
       total = n * m;

       /* Pick a randomized username */
       pthread_mutex_lock(&rand_mutex);
       /* See Numerical Recipes in C or Knuth vol. 2 ch. 3 */
       i = (int)(100.0*rand()/(RAND_MAX+1.0));   /* range 0-99 */
       pthread_mutex_unlock(&rand_mutex);
       sprintf(username, "testuser%d", i);
       strcpy(password, username);

       /* First, memory for our shitload of threads */
       threads = calloc(n, sizeof(pthread_t));
       if (!threads) {
              perror("Not enough memory");
              return 1;
       }

       /* Then thread attributes (all defaults for now) */
       pthread_attr_init(&attr);
       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

       /* Then, create some threads */
       fprintf(stderr, "Creating threads      \r");
       for (i = 0; i < n; ++i) {
              pthread_create(&threads[i], &attr, worker, (void*)data);
              
              /* Give thread #0 time to create the user account */
              if (i == 0) sleep(3);
       }

       //fprintf(stderr, "Starting in %d seconds\r", n);
       //sleep(n);
       fprintf(stderr, "                      \r");

       /* Then, signal the conditional they all are waiting on */
       pthread_mutex_lock(&start_mutex);
       pthread_cond_broadcast(&start_cond);
       pthread_mutex_unlock(&start_mutex);

       /* Then wait for them to exit */
       for (i = 0; i < n; i++) {
              pthread_join(threads[i], (void*)&runtime);
              /* We're ignoring this value for now... TODO */
       }
       fprintf(stderr, "\r                                                                               \r");
       return 0;
}

Here is the call graph for this function:

int shift ( int  argc,
char **  argv,
int  start,
int  count 
)

Definition at line 279 of file stress.c.

{
       int i;

       for (i = start; i < argc - count; ++i)
              argv[i] = argv[i + count];
       return argc - count;
}
void* worker ( void *  data)

Definition at line 118 of file stress.c.

{
       CtdlIPC* ipc; /* My connection to the server */
       void** args;  /* Args sent in */
       int r;        /* IPC return code */
       char aaa[SIZ];       /* Generic buffer */
       int c;        /* Message count */
       time_t start, end;   /* Timestamps */
       struct ctdlipcmessage msg;  /* The message we will post */
       int argc_;
       char** argv_;
       long tmin = LONG_MAX, trun = 0, tmax = LONG_MIN;

       args = (void*)data;
       argc_ = (int)args[0];
       argv_ = (char**)args[1];

       /* Setup the message we will be posting */
       msg.text = message;
       msg.anonymous = 0;
       msg.type = 1;
       strcpy(msg.recipient, "");
       strcpy(msg.subject, "Test message; ignore");
       strcpy(msg.author, username);

       pthread_mutex_lock(&arg_mutex);
       ipc = CtdlIPC_new(argc_, argv_, NULL, NULL);
       pthread_mutex_unlock(&arg_mutex);
       if (!ipc)
              return NULL;  /* oops, something happened... */

       CtdlIPC_chat_recv(ipc, aaa);
       if (aaa[0] != '2') {
              fprintf(stderr, "Citadel refused me: %s\n", &aaa[4]);
              return NULL;  /* server ran out of connections maybe? */
       }

       CtdlIPCIdentifySoftware(ipc, 8, 8, REV_LEVEL, "Citadel stress tester",
              "localhost", aaa);   /* we're lying, the server knows */
       
       r = CtdlIPCQueryUsername(ipc, username, aaa);
       if (r / 100 == 2) {
              /* testuser already exists (from previous run?) */
              r = CtdlIPCTryLogin(ipc, username, aaa);
              if (r / 100 != 3) {
                     fprintf(stderr, "Citadel refused username: %s\n", aaa);
                     CtdlIPC_delete_ptr(&ipc);
                     return NULL;  /* Gawd only knows what went wrong */
              }
              r = CtdlIPCTryPassword(ipc, password, aaa);
              if (r / 100 != 2) {
                     fprintf(stderr, "Citadel refused password: %s\n", aaa);
                     CtdlIPC_delete_ptr(&ipc);
                     return NULL;  /* Gawd only knows what went wrong */
              }
       } else {
              /* testuser doesn't yet exist */
              r = CtdlIPCCreateUser(ipc, username, 1, aaa);
              if (r / 100 != 2) {
                     fprintf(stderr, "Citadel refused create user: %s\n", aaa);
                     CtdlIPC_delete_ptr(&ipc);
                     return NULL;  /* Gawd only knows what went wrong */
              }
              r = CtdlIPCChangePassword(ipc, password, aaa);
              if (r / 100 != 2) {
                     fprintf(stderr, "Citadel refused change password: %s\n", aaa);
                     CtdlIPC_delete_ptr(&ipc);
                     return NULL;  /* Gawd only knows what went wrong */
              }
       }

       /* Wait for the rest of the threads */
       pthread_mutex_lock(&start_mutex);
       pthread_cond_wait(&start_cond, &start_mutex);
       pthread_mutex_unlock(&start_mutex);

       /* And now the fun begins!  Send out a whole shitload of messages */
       start = time(NULL);
       for (c = 0; c < m; c++) {
              int rm;
              char room[7];
              struct ctdlipcroom *rret;
              struct timeval tv;
              long tstart, tend;
              int wait;

              /* Wait for a while */
              pthread_mutex_lock(&rand_mutex);
              /* See Numerical Recipes in C or Knuth vol. 2 ch. 3 */
              /* Randomize between w/3 to w*3 (yes, it's complicated) */
              wait = (int)((1.0+2.7*(float)w)*rand()/(RAND_MAX+(float)w/3.0)); /* range 0-99 */
              pthread_mutex_unlock(&rand_mutex);
              sleep(wait);

              /* Select the room to goto */
              pthread_mutex_lock(&rand_mutex);
              /* See Numerical Recipes in C or Knuth vol. 2 ch. 3 */
              rm = (int)(100.0*rand()/(RAND_MAX+1.0)); /* range 0-99 */
              pthread_mutex_unlock(&rand_mutex);

              /* Goto the selected room */
              sprintf(room, "test%d", rm);
              /* Create the room if not existing. Ignore the return */
              r = CtdlIPCCreateRoom(ipc, 1, room, 0, NULL, 0, aaa);
              if (r / 100 != 2 && r != 574) {    /* Already exists */
                     fprintf(stderr, "Citadel refused room create: %s\n", aaa);
                     pthread_mutex_lock(&count_mutex);
                     total -= m - c;
                     pthread_mutex_unlock(&count_mutex);
                     CtdlIPC_delete_ptr(&ipc);
                     return NULL;
              }
              gettimeofday(&tv, NULL);
              tstart = tv.tv_sec * 1000 + tv.tv_usec / 1000; /* cvt to msec */
              r = CtdlIPCGotoRoom(ipc, room, "", &rret, aaa);
              if (r / 100 != 2) {
                     fprintf(stderr, "Citadel refused room change: %s\n", aaa);
                     pthread_mutex_lock(&count_mutex);
                     total -= m - c;
                     pthread_mutex_unlock(&count_mutex);
                     CtdlIPC_delete_ptr(&ipc);
                     return NULL;
              }

              /* Post the message */
              r = CtdlIPCPostMessage(ipc, 1, NULL, &msg, aaa);
              if (r / 100 != 4) {
                     fprintf(stderr, "Citadel refused message entry: %s\n", aaa);
                     pthread_mutex_lock(&count_mutex);
                     total -= m - c;
                     pthread_mutex_unlock(&count_mutex);
                     CtdlIPC_delete_ptr(&ipc);
                     return NULL;
              }

              /* Do a status update */
              pthread_mutex_lock(&count_mutex);
              count++;
              pthread_mutex_unlock(&count_mutex);
              fprintf(stderr, " %d/%d=%d%%             \r",
                     count, total,
                     (int)(100 * count / total));
              gettimeofday(&tv, NULL);
              tend = tv.tv_sec * 1000 + tv.tv_usec / 1000; /* cvt to msec */
              tend -= tstart;
              if (tend < tmin) tmin = tend;
              if (tend > tmax) tmax = tend;
              trun += tend;
       }
       end = time(NULL);
       pthread_mutex_lock(&output_mutex);
       fprintf(stderr, "               \r");
       printf("%ld %ld %ld %ld\n", end - start, tmin, trun / c, tmax);
       pthread_mutex_unlock(&output_mutex);
       return (void*)(end - start);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

pthread_mutex_t arg_mutex = PTHREAD_MUTEX_INITIALIZER [static]

Definition at line 93 of file stress.c.

volatile int count = 0 [static]

Definition at line 90 of file stress.c.

pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER [static]

Definition at line 92 of file stress.c.

int m = 1000 [static]

Definition at line 89 of file stress.c.

char* const message = "stress -n 500 -w 25 myserver > stress.csv\n"

Definition at line 3 of file stress.c.

int n = 100 [static]

Definition at line 88 of file stress.c.

pthread_mutex_t output_mutex = PTHREAD_MUTEX_INITIALIZER [static]

Definition at line 94 of file stress.c.

char password[12] [static]

Definition at line 97 of file stress.c.

pthread_mutex_t rand_mutex = PTHREAD_MUTEX_INITIALIZER [static]

Definition at line 104 of file stress.c.

pthread_cond_t start_cond = PTHREAD_COND_INITIALIZER [static]

Definition at line 111 of file stress.c.

pthread_mutex_t start_mutex = PTHREAD_MUTEX_INITIALIZER [static]

Definition at line 110 of file stress.c.

volatile int total = 0 [static]

Definition at line 91 of file stress.c.

char username[12] [static]

Definition at line 96 of file stress.c.

int w = 10 [static]

Definition at line 87 of file stress.c.