Added context state to output of RWHO command.
[citadel.git] / citadel / utils / loadtest.c
index 5d0e15062a3b510b81c5c62025afdcf490e761b6..8d4e41b2f6e26708edabeffa7a3c4f65bf6055ae 100644 (file)
@@ -1,6 +1,6 @@
 // Load testing utility for Citadel Server
 //
-// Copyright (c) 1987-2023 by the citadel.org team
+// Copyright (c) 1987-2024 by the citadel.org team
 //
 // This program is open source software.  Use, duplication, or disclosure
 // is subject to the terms of the GNU General Public License, version 3.
@@ -208,6 +208,8 @@ char *random_rooms[] = {
 int nrooms = sizeof(random_rooms) / sizeof(char *);
 char *test_user = "Load Test User";
 char test_pass[16];
+time_t time_started;
+volatile int ops_completed;
 
 
 // These are our randomized load test operations: an even mix of changing rooms, posting messages, and deleting messages.
@@ -270,23 +272,16 @@ void perform_random_thing(int serv_sock) {
                        serv_gets(serv_sock, buf);
                } while ( (buf[0] != '2') && (total_msgs > 0));
        }
-
 }
 
+#define ROW_OFFSET 8
 
 // This is the main loop.  We log in as the load test user, and then perform random operations until stopped.
-void *loadtest(void *ptr) {
+void *loadtest(void *pointer_to_thread_id) {
        char buf[SIZ];
        int serv_sock;
 
-       // Find a nice spot on the screen to show the operation count for this thread.
-       int threadnum;
-       threadnum = (ptr ? (*(int *)ptr) : 0);
-       int row = 10 + (threadnum % 20);
-       int col = (threadnum / 20) * 10;
-       long ops = 0;
-       printf("\033[%d;%dH\033[33m       0\033[0m", row, col);
-       fflush(stdout);
+       int thread_id = *(int *)pointer_to_thread_id;
 
        serv_sock = uds_connectsock(file_citadel_socket);
 
@@ -307,9 +302,20 @@ void *loadtest(void *ptr) {
        serv_puts(serv_sock, buf);
        serv_gets(serv_sock, buf);
 
+       // Find a nice spot on the screen to show the operation count for this thread.
+       int row = ROW_OFFSET + (thread_id % 20);
+       int col = (thread_id / 20) * 10;
+       long ops = 0;
+       printf("\033[%d;%dH\033[33m       0\033[0m", row, col);
+       fflush(stdout);
+
        while(1) {
                perform_random_thing(serv_sock);
                printf("\033[%d;%dH\033[32m%8ld\033[0m", row, col, ++ops);
+               ++ops_completed;                // this is declared "volatile" so we don't need to lock it
+               if (thread_id == 0) {
+                       printf("\033[2;55H\033[44m\033[33m\033[1m%ld ops/sec \033[0m", (ops_completed / (time(NULL) - time_started)));
+               }
                fflush(stdout);
        }
 }
@@ -344,15 +350,17 @@ void setup_accounts(int serv_sock) {
 // Main loop.  Do things and have fun.
 int main(int argc, char **argv) {
        int i;
-       int nthreads = 3;
-
-       fprintf(stderr, "\033[2J\033[H"
-                       "\033[44m\033[33m\033[1m                                                                        \033[K\033[0m\n"
-                       "\033[44m\033[33m\033[1m Load testing utility for Citadel                                       \033[K\033[0m\n"
-                       "\033[44m\033[33m\033[1m Copyright (c) 2023 by citadel.org et al.                               \033[K\033[0m\n"
-                       "\033[44m\033[33m\033[1m This program is open source software.  Use, duplication, or disclosure \033[K\033[0m\n"
-                       "\033[44m\033[33m\033[1m is subject to the terms of the GNU General Public license v3.          \033[K\033[0m\n"
-                       "\033[44m\033[33m\033[1m                                                                        \033[K\033[0m\n");
+       int nthreads = 10;
+       int row, col;
+
+       fprintf(stderr, "\033[2J\033[H\033[44m\033[1m"
+               "╔════════════════════════════════════════════════════════════════════════╗\n"
+               "║ Load testing utility for Citadel                                       ║\n"
+               "║ Copyright (c) 2023-2024 by citadel.org et al.                          ║\n"
+               "║ This program is open source software.  Use, duplication, or disclosure ║\n"
+               "║ is subject to the terms of the GNU General Public license v3.          ║\n"
+               "╚════════════════════════════════════════════════════════════════════════╝\033[0m\n"
+       );
 
        // Parse command line
        while ((i = getopt(argc, argv, "h:n:")) != EOF) {
@@ -374,14 +382,6 @@ int main(int argc, char **argv) {
                exit(errno);
        }
 
-       // set up the screen
-       for (i=0; i<nthreads; ++i) {
-               int row = 10 + (i % 20);
-               int col = (i / 20) * 10;
-               printf("\033[%d;%dH\033[31m--------\033[0m", row, col);
-       }
-       fflush(stdout);
-
        // Generate a random password for load test user.  No one needs this password except us.
        srand(time(NULL)+getpid());
        for (i=0; i<sizeof(test_pass)-1; ++i) {
@@ -389,6 +389,14 @@ int main(int argc, char **argv) {
        }
        test_pass[sizeof(test_pass)] = 0;
 
+       // paint the screen
+       for (i=0; i<nthreads; ++i) {
+               row = ROW_OFFSET + (i % 20);
+               col = (i / 20) * 10;
+               printf("\033[%d;%dH\033[31m       -\033[0m", row, col);
+               fflush(stdout);
+       }
+
        // start connecting
        int serv_sock = uds_connectsock(file_citadel_admin_socket);
        if (serv_sock < 0) {
@@ -401,25 +409,28 @@ int main(int argc, char **argv) {
        setup_accounts(serv_sock);
        close(serv_sock);
 
-       // start up load testing threads
-       for (i=0; i<(nthreads-1); ++i) {
+       size_t * threadId = calloc(nthreads, sizeof(size_t));
+       for (size_t i = 0; i < nthreads; ++i) {
+               threadId[i] = i;
+       }
+
+       time_started = time(NULL);
+       ops_completed = 0;
+
+       for (i=1; i<nthreads; ++i) {
+
                pthread_t thread;
                pthread_attr_t attr;
                int ret = 0;
 
                ret = pthread_attr_init(&attr);
                ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE);
-               ret = pthread_create(&thread, &attr, loadtest, &i);
+               ret = pthread_create(&thread, &attr, loadtest, &threadId[i]);
                if (ret != 0) {
                        exit(ret);
                }
 
        }
-
-       // now the original thread becomes load testing thread 0
-       loadtest(NULL);
-
-       // should never get here
+       loadtest(&threadId[0]);
        return(0);
 }
-