diff --git a/test/Makefile b/test/Makefile index 135435a2..49420478 100644 --- a/test/Makefile +++ b/test/Makefile @@ -6,7 +6,7 @@ TEST_DEPS := dev_null # Tests: need to be compiled and run by test-% target TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server server_epoll unix_socket # Benchmarks: need to be compiled and run by bench-% target -BENCHES := spawn_and_exit_latency pipe_throughput +BENCHES := spawn_and_exit_latency pipe_throughput unix_socket_throughput # Top-level Makefile targets BUILD_TARGETS := $(TEST_DEPS) $(TESTS) $(BENCHES) diff --git a/test/unix_socket/main.c b/test/unix_socket/main.c index a00c2eb4..4f9af75a 100644 --- a/test/unix_socket/main.c +++ b/test/unix_socket/main.c @@ -54,10 +54,6 @@ int create_client_socket() { } int main(int argc, const char* argv[]) { - // XXX: this is a hack! remove this in the future - void* ptr = malloc(64); - free(ptr); - int listen_fd = create_server_socket(); if (listen_fd == -1) { printf("ERROR: failed to create server socket"); diff --git a/test/unix_socket_throughput/Makefile b/test/unix_socket_throughput/Makefile new file mode 100644 index 00000000..8c5a2fb4 --- /dev/null +++ b/test/unix_socket_throughput/Makefile @@ -0,0 +1,5 @@ +include ../test_common.mk + +EXTRA_C_FLAGS := -Wno-incompatible-pointer-types-discards-qualifiers +EXTRA_LINK_FLAGS := +BIN_ARGS := diff --git a/test/unix_socket_throughput/main.c b/test/unix_socket_throughput/main.c new file mode 100644 index 00000000..f8bed173 --- /dev/null +++ b/test/unix_socket_throughput/main.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KB (1024UL) +#define MB (1024UL * 1024UL) +#define GB (1024UL * 1024UL * 1024UL) + +#define TOTAL_BYTES (2 * GB) +#define BUF_SIZE (128 * KB) + +#define MIN(x, y) ((x) <= (y) ? (x) : (y)) + +const char SOCK_PATH[] = "echo_socket"; + +int create_server_socket() { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + printf("ERROR: failed to create a unix socket"); + return -1; + } + + struct sockaddr_un local; + local.sun_family = AF_UNIX; + strcpy(local.sun_path, SOCK_PATH); + socklen_t len = strlen(local.sun_path) + sizeof(local.sun_family); + + if (bind(fd, (struct sockaddr *)&local, len) == -1) { + printf("ERROR: failed to bind\n"); + return -1; + } + + if (listen(fd, 5) == -1) { + printf("ERROR: failed to listen\n"); + return -1; + } + return fd; +} + +int create_client_socket() { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + printf("ERROR: failed to create a unix socket"); + return -1; + } + + struct sockaddr_un remote; + remote.sun_family = AF_UNIX; + strcpy(remote.sun_path, SOCK_PATH); + socklen_t len = strlen(remote.sun_path) + sizeof(remote.sun_family); + + if (connect(fd, (struct sockaddr *)&remote, len) == -1) { + printf("ERROR: failed to connect\n"); + return -1; + } + return fd; +} + +int main(int argc, const char* argv[]) { + int listen_fd = create_server_socket(); + if (listen_fd == -1) { + printf("ERROR: failed to create server socket"); + return -1; + } + + int socket_rd_fd = create_client_socket(); + if (socket_rd_fd == -1) { + printf("ERROR: failed to create client socket"); + return -1; + } + + struct sockaddr_un remote; + socklen_t len = sizeof(remote); + int socket_wr_fd = accept(listen_fd, (struct sockaddr *)&remote, &len); + if (socket_wr_fd == -1) { + printf("ERROR: failed to accept socket"); + return -1; + } + + // The following is same as 'pipe_throughput' + + // Spawn a child process that reads from the pipe + posix_spawn_file_actions_t file_actions; + posix_spawn_file_actions_init(&file_actions); + posix_spawn_file_actions_adddup2(&file_actions, socket_rd_fd, STDIN_FILENO); + posix_spawn_file_actions_addclose(&file_actions, socket_wr_fd); + + int child_pid; + if (posix_spawn(&child_pid, "dev_null", &file_actions, + NULL, NULL, NULL) < 0) { + printf("ERROR: failed to spawn a child process\n"); + return -1; + } + close(socket_rd_fd); + + // Start the timer + struct timeval tv_start, tv_end; + gettimeofday(&tv_start, NULL); + + // Tell the reader how many data are to be transfered + size_t remain_bytes = TOTAL_BYTES; + if (write(socket_wr_fd, &remain_bytes, sizeof(remain_bytes)) != sizeof(remain_bytes)) { + printf("ERROR: failed to write to pipe\n"); + return -1; + } + + // Tell the reader the buffer size that it should use + size_t buf_size = BUF_SIZE; + if (write(socket_wr_fd, &buf_size, sizeof(buf_size)) != sizeof(buf_size)) { + printf("ERROR: failed to write to pipe\n"); + return -1; + } + + // Write a specified amount of data in a buffer of specified size + char buf[BUF_SIZE] = {0}; + while (remain_bytes > 0) { + size_t len = MIN(buf_size, remain_bytes); + if ((len = write(socket_wr_fd, &buf, len)) < 0) { + printf("ERROR: failed to write to pipe\n"); + return -1; + } + remain_bytes -= len; + } + + // Wait for the child process to read all data and exit + int status = 0; + if (wait4(child_pid, &status, 0, NULL) < 0) { + printf("ERROR: failed to wait4 the child process\n"); + return -1; + } + + // Stop the timer + gettimeofday(&tv_end, NULL); + + // Calculate the throughput + double total_s = (tv_end.tv_sec - tv_start.tv_sec) + + (double)(tv_end.tv_usec - tv_start.tv_usec) / 1000000; + if (total_s < 1.0) { + printf("WARNING: run long enough to get meaningful results\n"); + if (total_s == 0) { return 0; } + } + double total_mb = (double)TOTAL_BYTES / MB; + double throughput = total_mb / total_s; + printf("Throughput of unix socket is %.2f MB/s\n", throughput); + return 0; +}