From: Michael Tremer Date: Mon, 1 Feb 2021 17:19:38 +0000 (+0000) Subject: client: Create random pool to send data faster X-Git-Tag: 0.1.0~26 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=0b59cb819fb328146f3896b60cf5c60e7f28c5b2;p=fireperf.git client: Create random pool to send data faster This creates a pool of one thousand times the send buffer size which will be used to send random data. This data might repeat itself, but that is not a problem here because we only need to have more data than the window of any compression algorithm. Signed-off-by: Michael Tremer --- diff --git a/src/client.c b/src/client.c index 678502e..3de8a5d 100644 --- a/src/client.c +++ b/src/client.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,58 @@ static void handle_SIGALRM(int signal) { } } +const char ZERO[SOCKET_SEND_BUFFER_SIZE] = { 0 }; + +struct fireperf_random_pool { + char* data; + size_t size; +}; + +static void fireperf_random_pool_free(struct fireperf_random_pool* pool) { + if (pool->data) + free(pool->data); + + free(pool); +} + +static struct fireperf_random_pool* fireperf_random_pool_create(struct fireperf_config* conf, size_t size) { + struct fireperf_random_pool* pool = calloc(1, sizeof(*pool)); + if (!pool) + return NULL; + + pool->size = size; + + // Allocate the data array + pool->data = malloc(pool->size); + if (!pool->data) + goto ERROR; + + size_t offset = 0; + while (offset < pool->size) { + offset += getrandom(pool->data + offset, pool->size - offset, 0); + } + + DEBUG(conf, "Allocated random pool of %zu bytes(s)\n", pool->size); + + return pool; + +ERROR: + fireperf_random_pool_free(pool); + + return NULL; +} + +static const char* fireperf_random_pool_get_slice(struct fireperf_random_pool* pool, size_t size) { + if (size > pool->size) + return NULL; + + // Find a random value between the start and end of + // the data region that is at least size bytes long. + off_t offset = random() % (pool->size - size); + + return pool->data + offset; +} + static int connect_socket(struct fireperf_config* conf, int fd) { DEBUG(conf, "(Re-)connecting socket %d...\n", fd); @@ -117,42 +170,17 @@ static int connect_socket(struct fireperf_config* conf, int fd) { return 0; } -/* - This is just an example implementation because getrandom() is too slow for - this purpose. I would need a really fast pseudo-RNG. -*/ -static int randomize_buffer(char* buffer, size_t s) { - ssize_t r = getrandom(buffer, s, 0); - - // Error - if (r < 0) - return 1; - - // We received less data than we wanted - else if (r > 0 && (size_t)r < s) - return 1; - - return 0; -} - -static int send_data_to_server(struct fireperf_config* conf, int fd) { - char buffer[SOCKET_SEND_BUFFER_SIZE] = { 0 }; +static int send_data_to_server(struct fireperf_config* conf, int fd, + struct fireperf_random_pool* pool) { + const char* buffer = ZERO; ssize_t bytes_sent; - DEBUG(conf, "Sending %zu bytes of data to server\n", sizeof(buffer)); - - // Randomize the buffer if requested, otherwise just send an empty buffer - if (!conf->zero) { - int r = randomize_buffer(buffer, sizeof(buffer)); - if (r) { - ERROR(conf, "Could not generate a random block of data: %s\n", - strerror(errno)); - return 1; - } + if (pool) { + buffer = fireperf_random_pool_get_slice(pool, SOCKET_SEND_BUFFER_SIZE); } do { - bytes_sent = send(fd, buffer, sizeof(buffer), 0); + bytes_sent = send(fd, buffer, SOCKET_SEND_BUFFER_SIZE, 0); } while (bytes_sent < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)); DEBUG(conf, "bytes_sent = %zu\n", bytes_sent); @@ -161,8 +189,19 @@ static int send_data_to_server(struct fireperf_config* conf, int fd) { } int fireperf_client(struct fireperf_config* conf) { + struct fireperf_random_pool* pool = NULL; + DEBUG(conf, "Launching " PACKAGE_NAME " in client mode\n"); + // Initialize random pool + if (!conf->zero) { + pool = fireperf_random_pool_create(conf, CLIENT_RANDOM_POOL_SIZE); + if (!pool) { + ERROR(conf, "Could not allocate random data\n"); + return 1; + } + } + int r = 1; int epollfd = -1; @@ -235,7 +274,7 @@ int fireperf_client(struct fireperf_config* conf) { goto ERROR; } else if (events[i].events & EPOLLOUT) { - r = send_data_to_server(conf, fd); + r = send_data_to_server(conf, fd, pool); if (r) goto ERROR; } @@ -249,5 +288,8 @@ ERROR: if (epollfd > 0) close(epollfd); + if (pool) + fireperf_random_pool_free(pool); + return r; } diff --git a/src/main.c b/src/main.c index 9712d15..26b1b8a 100644 --- a/src/main.c +++ b/src/main.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "client.h" #include "main.h" @@ -196,6 +197,9 @@ int main(int argc, char* argv[]) { if (r) return r; + // Initialise random number generator + srandom(time(NULL)); + // Set limits r = set_limits(&conf); if (r) diff --git a/src/main.h b/src/main.h index 50dd3ca..5171e8a 100644 --- a/src/main.h +++ b/src/main.h @@ -37,6 +37,9 @@ #define SOCKET_RECV_BUFFER_SIZE SOCKET_BUFFER_SIZE #define SOCKET_SEND_BUFFER_SIZE SOCKET_BUFFER_SIZE +// Random pool size +#define CLIENT_RANDOM_POOL_SIZE (SOCKET_SEND_BUFFER_SIZE * 1000) + #define EPOLL_MAX_EVENTS 128 struct fireperf_config {