]> git.ipfire.org Git - fireperf.git/commitdiff
client: Create random pool to send data faster
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 1 Feb 2021 17:19:38 +0000 (17:19 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 1 Feb 2021 17:19:38 +0000 (17:19 +0000)
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 <michael.tremer@ipfire.org>
src/client.c
src/main.c
src/main.h

index 678502e391445e0060f50845dabced4b1f809d41..3de8a5de9f2ff313b7a71efa1d6e7b3db9a8bb94 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <netinet/tcp.h>
+#include <stdlib.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/epoll.h>
@@ -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;
 }
index 9712d15a1a0a83164ed5a3c2dedefaabf7b3c2c8..26b1b8a0cd152dcb59a10c33965569b48d87e922 100644 (file)
@@ -29,6 +29,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/resource.h>
+#include <time.h>
 
 #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)
index 50dd3ca5b7123d0004d6b5397ee64fec9bc5feb3..5171e8a031c5952b454f9ff8767f61ae83e82ace 100644 (file)
@@ -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 {