diff --git a/tools/Makefile b/tools/Makefile index 15abde6..410b52c 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -5,11 +5,14 @@ CPPFLAGS = -Wall -I../src/server -I../src/common -I../src/proxy \ CFLAGS = $(CPPFLAGS) -g -O3 -std=gnu99 -all: holemap +all: holemap semtest # holemap requires libmhash-dev for md5 calculation holemap: holemap.c ../src/server/*.h $(CC) $(CFLAGS) -o $@ $^ ${shell pkg-config mhash --cflags --libs} +semtest: semtest.c + $(CC) $(CFLAGS) -o $@ $^ -lpthread + clean: - rm -f holemap + rm -f holemap semtest diff --git a/tools/semtest.c b/tools/semtest.c new file mode 100644 index 0000000..fd1c80e --- /dev/null +++ b/tools/semtest.c @@ -0,0 +1,122 @@ +/* + * Latency test for pthread 'conditions' vs using a good ol' + * pair of linked sockets. + * gcc -o semtest -O2 -g --std=c99 semtest.c -lpthread + * + */ +#include +#include +#include +#include +#include +#include + +#define TESTCOUNT 10000000 + +pthread_mutex_t mutex; +pthread_cond_t kidwake, dadwake; +int flag_passed = 0; + +static void *thread_semaphore(void * param) +{ + printf("kid started\n"); + pthread_mutex_lock(&mutex); + pthread_cond_signal( &dadwake ); + pthread_mutex_unlock(&mutex); + do { + pthread_mutex_lock(&mutex); + while (flag_passed == 0) + pthread_cond_wait( &kidwake, &mutex ); + flag_passed = 0; + pthread_cond_signal( &dadwake ); + pthread_mutex_unlock(&mutex); + } while (1); + return NULL; +} + +int sock[2]; + +static void * thread_socket(void * param) +{ + printf("kid started\n"); + do { + char b = 0; + int r = read(sock[1], &b, 1); + if (r != 1) + perror("read"); + b = 0; + write(sock[1], &b, 1); // tell the kid + } while (1); + + return NULL; +} + + +int main(int argc, char ** argv) +{ + int test = 0; + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "socket")) + test = 1; + else if (!strcmp(argv[i], "semaphore")) + test = 2; + else + goto usage; + } + if (!test) + goto usage; + + if (test == 1) { + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock)) { + perror("socketpair"); + exit(1); + } + printf("Socket test start:\n"); + pthread_t t; + pthread_create(&t, NULL, thread_socket, NULL); + + for (int ti = 0; ti < TESTCOUNT; ti++) { + char b = 1; + write(sock[0], &b, 1); // tell the kid + int r = read(sock[0], &b, 1); + if (r != 1) + perror("read"); + + if (!(ti % 100000)) { + printf("."); fflush(stdout); + } + } + } else { + pthread_mutex_init(&mutex, NULL); + pthread_cond_init( &kidwake, NULL ); + pthread_cond_init( &dadwake, NULL ); + + printf("Semaphore test start:\n"); + pthread_t t; + pthread_create(&t, NULL, thread_semaphore, NULL); + + pthread_mutex_lock(&mutex); + printf("dad wait for kid\n"); + pthread_cond_wait( &dadwake, &mutex ); + pthread_mutex_unlock(&mutex); + printf("dad has kid ready\n"); + + for (int ti = 0; ti < TESTCOUNT; ti++) { + pthread_mutex_lock(&mutex); + flag_passed = 1; + pthread_cond_signal( &kidwake ); + while (flag_passed == 1) + pthread_cond_wait( &dadwake, &mutex ); + pthread_mutex_unlock(&mutex); + if (!(ti % 100000)) { + printf("."); fflush(stdout); + } + } + } + printf("\nDone\n"); + exit(0); +usage: + fprintf(stderr, "%s socket -- run semaphore latency test with sockets\n", argv[0]); + fprintf(stderr, "%s semaphore -- run semaphore latency test with sockets\n", argv[0]); + exit(1); +}