loadtest.c: multiple threadds
authorArt Cancro <ajc@citadel.org>
Tue, 29 Aug 2023 02:02:51 +0000 (22:02 -0400)
committerArt Cancro <ajc@citadel.org>
Tue, 29 Aug 2023 02:02:51 +0000 (22:02 -0400)
citadel/server/citadel_defs.h
citadel/utils/loadtest.c

index 04ab4e7cb4ac2162bcc5f2b5b47f486535ed85db..2e306a20e371bedaa9465dedbfb337464411ef70 100644 (file)
@@ -11,8 +11,8 @@
 
 // Suppress these compiler warnings
 #pragma GCC diagnostic ignored "-Wcast-qual"
-// #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"     // this doesn't work on FreeBSD
-// #pragma GCC diagnostic ignored "-Wformat-truncation"                // nor does this
+#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"                // this doesn't work on FreeBSD
+#pragma GCC diagnostic ignored "-Wformat-truncation"           // nor does this
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 
 #include "sysdep.h"
index 0e6356a82e6cf76c0569e0bae25d06e84df8679e..25dfd9e90b7b7aafd02afd35d93c72604a534a8c 100644 (file)
 #include <limits.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <pthread.h>
 #include "../server/citadel_defs.h"
 #include "../server/server.h"
 #include "../server/citadel_dirs.h"
 #include <libcitadel.h>
 
+char ctdldir[PATH_MAX]=CTDLDIR;
+
 char *words[] = {
        "lorem","ipsum","dolor","sit","amet","consectetuer","adipiscing","elit","integer","in","mi","a","mauris",
        "ornare","sagittis","suspendisse","potenti","suspendisse","dapibus","dignissim","dolor","nam",
@@ -113,7 +116,6 @@ char *words[] = {
 };
 int nwords = sizeof(words) / sizeof(char *);
 
-int serv_sock = (-1);
 
 int uds_connectsock(char *sockpath) {
        int s;
@@ -140,7 +142,7 @@ int uds_connectsock(char *sockpath) {
 
 
 // input binary data from socket
-void serv_read(char *buf, int bytes) {
+void serv_read(int serv_sock, char *buf, int bytes) {
        int len, rlen;
 
        len = 0;
@@ -155,7 +157,7 @@ void serv_read(char *buf, int bytes) {
 
 
 // send binary to server
-void serv_write(char *buf, int nbytes) {
+void serv_write(int serv_sock, char *buf, int nbytes) {
        int bytes_written = 0;
        int retval;
        while (bytes_written < nbytes) {
@@ -169,12 +171,12 @@ void serv_write(char *buf, int nbytes) {
 
 
 // input string from socket - implemented in terms of serv_read()
-void serv_gets(char *buf) {
+void serv_gets(int serv_sock, char *buf) {
        int i;
 
        // Read one character at a time.
        for (i = 0;; i++) {
-               serv_read(&buf[i], 1);
+               serv_read(serv_sock, &buf[i], 1);
                if (buf[i] == '\n' || i == (SIZ-1))
                        break;
        }
@@ -182,7 +184,7 @@ void serv_gets(char *buf) {
        // If we got a long line, discard characters until the newline.
        if (i == (SIZ-1)) {
                while (buf[i] != '\n') {
-                       serv_read(&buf[i], 1);
+                       serv_read(serv_sock, &buf[i], 1);
                }
        }
 
@@ -192,9 +194,9 @@ void serv_gets(char *buf) {
 
 
 // send line to server - implemented in terms of serv_write()
-void serv_puts(char *buf) {
-       serv_write(buf, strlen(buf));
-       serv_write("\n", 1);
+void serv_puts(int serv_sock, char *buf) {
+       serv_write(serv_sock, buf, strlen(buf));
+       serv_write(serv_sock, "\n", 1);
 }
 
 
@@ -210,7 +212,7 @@ int nrooms = sizeof(random_rooms) / sizeof(char *);
 
 char *test_user = "Load Test User";
 
-void perform_random_thing(void) {
+void perform_random_thing(int serv_sock) {
        int op = random() % 3;
        char buf[SIZ];
        int i;
@@ -219,14 +221,14 @@ void perform_random_thing(void) {
        // Random operation 0 : change rooms
        if (op == 0) {
                snprintf(buf, sizeof(buf), "GOTO %s", random_rooms[random() % nrooms]);
-               serv_puts(buf);
-               serv_gets(buf);
+               serv_puts(serv_sock, buf);
+               serv_gets(serv_sock, buf);
        }
 
        // Random operation 1 : post a message
        if (op == 1) {
-               serv_puts("ENT0 1");
-               serv_gets(buf);
+               serv_puts(serv_sock, "ENT0 1");
+               serv_gets(serv_sock, buf);
                if (buf[0] == '4') {
 
                        bigness = random() % 500;
@@ -234,15 +236,15 @@ void perform_random_thing(void) {
                        for (i=0; i<bigness; ++i) {
                                strcat(buf, words[random() % nwords]);
                                if ( (i != 0) && ((i % 10) == 0) ) {
-                                       serv_puts(buf);
+                                       serv_puts(serv_sock, buf);
                                        strcpy(buf, "");
                                }
                                else {
                                        strcat(buf, " ");
                                }
                        }
-                       serv_puts(buf);
-                       serv_puts("000");
+                       serv_puts(serv_sock, buf);
+                       serv_puts(serv_sock, "000");
                }
        }
 
@@ -254,10 +256,10 @@ void perform_random_thing(void) {
                selected_msg = 0;
 
                do {
-                       serv_puts("MSGS ALL");
-                       serv_gets(buf);
+                       serv_puts(serv_sock, "MSGS ALL");
+                       serv_gets(serv_sock, buf);
                        if (buf[0] == '1') {
-                               while (serv_gets(buf), strcmp(buf, "000")) {
+                               while (serv_gets(serv_sock, buf), strcmp(buf, "000")) {
                                        ++total_msgs;
                                        if ((random() % total_msgs) == 0) {
                                                selected_msg = atol(buf);
@@ -265,100 +267,112 @@ void perform_random_thing(void) {
                                }
                        }
                        snprintf(buf, sizeof buf, "DELE %ld", selected_msg);
-                       serv_puts(buf);
-                       serv_gets(buf);
+                       serv_puts(serv_sock, buf);
+                       serv_gets(serv_sock, buf);
                } while ( (buf[0] != '2') && (total_msgs > 0));
        }
 
 }
 
 
-void do_stuff(void) {
+void do_stuff(int serv_sock) {
        int i;
        char buf[SIZ];
 
        snprintf(buf, sizeof buf, "CREU %s", test_user);
-       printf("< %s\n", buf);
-       serv_puts(buf);
-       serv_gets(buf);
-       printf("> %s\n", buf);
+       serv_puts(serv_sock, buf);
+       serv_gets(serv_sock, buf);
        snprintf(buf, sizeof buf, "ASUP %s|640k_enough_ne1|0|||6|", test_user);
-       printf("< %s\n", buf);
-       serv_puts(buf);
-       serv_gets(buf);
-       printf("> %s\n", buf);
+       serv_puts(serv_sock, buf);
+       serv_gets(serv_sock, buf);
        snprintf(buf, sizeof buf, "USER %s", test_user);
-       printf("< %s\n", buf);
-       serv_puts(buf);
-       serv_gets(buf);
-       printf("> %s\n", buf);
+       serv_puts(serv_sock, buf);
+       serv_gets(serv_sock, buf);
        snprintf(buf, sizeof buf, "PASS 640k_enough_ne1");
-       printf("< %s\n", buf);
-       serv_puts(buf);
-       serv_gets(buf);
-       printf("> %s\n", buf);
+       serv_puts(serv_sock, buf);
+       serv_gets(serv_sock, buf);
 
        for (i=0; i<nrooms; ++i) {
                snprintf(buf, sizeof buf, "CRE8 1|%s|", random_rooms[i]);
-               printf("< %s\n", buf);
-               serv_puts(buf);
-               serv_gets(buf);
-               printf("> %s\n", buf);
+               serv_puts(serv_sock, buf);
+               serv_gets(serv_sock, buf);
        }
 
        snprintf(buf, sizeof(buf), "GOTO %s", random_rooms[0]);
-       printf("< %s\n", buf);
-       serv_puts(buf);
-       serv_gets(buf);
-       printf("> %s\n", buf);
+       serv_puts(serv_sock, buf);
+       serv_gets(serv_sock, buf);
+
+       printf("\033[%d;0H\033[33m%ld\033[0m", 7+serv_sock, serv_sock-3);
 
        long ops = 0;
        while(1) {
                alarm(30);
-               perform_random_thing();
-               printf("  \033[32mOperations completed: \033[33m%ld\033[0m\r", ++ops);
+               perform_random_thing(serv_sock);
+               printf("\033[%d;5H\033[33m%8ld\033[0m", 7+serv_sock, ++ops);
                fflush(stdout);
        }
 }
 
+void *loadtest(void *blah) {
+       char buf[SIZ];
+       int serv_sock;
+
+       serv_sock = uds_connectsock(file_citadel_admin_socket);
+       serv_gets(serv_sock, buf);
+
+       do_stuff(serv_sock);
+
+       close(serv_sock);
+}
 
 
 // Main loop.  Do things and have fun.
 int main(int argc, char **argv) {
        int a;
-       char buf[SIZ];
-       char ctdldir[PATH_MAX]=CTDLDIR;
+       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");
 
        // Parse command line
-       while ((a = getopt(argc, argv, "h:")) != EOF) {
+       while ((a = getopt(argc, argv, "h:n:")) != EOF) {
                switch (a) {
                case 'h':
                        strncpy(ctdldir, optarg, sizeof ctdldir);
                        break;
+               case 'n':
+                       nthreads = atoi(optarg);
+                       break;
                default:
-                       fprintf(stderr, "loadtest: usage: %s [-h server_dir]\n", argv[0]);
+                       fprintf(stderr, "loadtest: usage: %s [-h server_dir] [-n number_of_threads]\n", argv[0]);
                        return(1);
                }
        }
 
-       fprintf(stderr, "loadtest: started (pid=%d) connecting to Citadel server with data directory %s\n",
-               (int) getpid(),
-               ctdldir
-       );
-       fflush(stderr);
-
        if (chdir(ctdldir) != 0) {
                fprintf(stderr, "loadtest: %s: %s\n", ctdldir, strerror(errno));
                exit(errno);
        }
 
-       serv_sock = uds_connectsock(file_citadel_admin_socket);
-       serv_gets(buf);
-       printf("> %s\n", buf);
+       for (a=0; a<(nthreads-1); ++a) {
+               pthread_t thread;
+               pthread_attr_t attr;
+               int ret = 0;
 
-       do_stuff();
+               ret = pthread_attr_init(&attr);
+               ret = pthread_attr_setstacksize(&attr, THREADSTACKSIZE);
+               ret = pthread_create(&thread, &attr, loadtest, NULL);
+               if (ret != 0) {
+                       exit(ret);
+               }
 
-       close(serv_sock);
+       }
+       loadtest(NULL);
 
        return(0);
 }