From 43e57ce5e11e9052f5a7db66f2e8613f1784f919 Mon Sep 17 00:00:00 2001 From: Frederic Robra Date: Tue, 25 Jun 2019 17:03:28 +0200 Subject: first version of dnbd3-ng --- src/bench/connection.c | 133 ++++++++++++++++++++++++++++++++++++++++++ src/bench/connection.h | 26 +++++++++ src/bench/helper.c | 37 ++++++++++++ src/bench/helper.h | 38 ++++++++++++ src/bench/main.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++ src/bench/serialize.c | 5 ++ 6 files changed, 393 insertions(+) create mode 100644 src/bench/connection.c create mode 100644 src/bench/connection.h create mode 100644 src/bench/helper.c create mode 100644 src/bench/helper.h create mode 100644 src/bench/main.c create mode 100644 src/bench/serialize.c (limited to 'src/bench') diff --git a/src/bench/connection.c b/src/bench/connection.c new file mode 100644 index 0000000..129ae3c --- /dev/null +++ b/src/bench/connection.c @@ -0,0 +1,133 @@ +#include "connection.h" +#include "helper.h" +#include "../config.h" +#include "../shared/protocol.h" +#include "../shared/fdsignal.h" +#include "../shared/sockhelper.h" +#include "../shared/log.h" + +#include +#include +#include +#include +#include +#include + +/* Constants */ +static const size_t SHORTBUF = 100; +#define SOCKET_KEEPALIVE_TIMEOUT (3) +#define MAX_ALTS (8) +#define MAX_HOSTS_PER_ADDRESS (2) +// If a server wasn't reachable this many times, we slowly start skipping it on measurements +static const int FAIL_BACKOFF_START_COUNT = 8; +#define RTT_COUNT (4) + +/* Module variables */ + +// Init guard +static bool connectionInitDone = false; +static bool keepRunning = true; + +static struct { + int sockFd; + pthread_mutex_t sendMutex; + dnbd3_signal_t* panicSignal; + dnbd3_host_t currentServer; + uint64_t startupTime; +} connection; + +// Known alt servers +typedef struct _alt_server { + dnbd3_host_t host; + int consecutiveFails; + int rtt; + int rtts[RTT_COUNT]; + int rttIndex; + int bestCount; +} alt_server_t; +alt_server_t altservers[MAX_ALTS]; +dnbd3_server_entry_t newservers[MAX_ALTS]; +pthread_spinlock_t altLock; + +bool connection_init_n_times( + const char *hosts, + const char *lowerImage, + const uint16_t rid, + int ntimes, + BenchCounters* counters, + bool closeSockets + ) { + for (int run_i = 0; run_i < ntimes; ++run_i) { + counters->attempts++; + + printf("."); + int sock = -1; + char host[SHORTBUF]; + serialized_buffer_t buffer; + uint16_t remoteVersion, remoteRid; + char *remoteName; + uint64_t remoteSize; + + if ( !connectionInitDone && keepRunning ) { + dnbd3_host_t tempHosts[MAX_HOSTS_PER_ADDRESS]; + const char *current, *end; + int altIndex = 0; + memset( altservers, 0, sizeof altservers ); + connection.sockFd = -1; + current = hosts; + do { + // Get next host from string + while ( *current == ' ' ) current++; + end = strchr( current, ' ' ); + size_t len = (end == NULL ? SHORTBUF : (size_t)( end - current ) + 1); + if ( len > SHORTBUF ) len = SHORTBUF; + snprintf( host, len, "%s", current ); + int newHosts = sock_resolveToDnbd3Host( host, tempHosts, MAX_HOSTS_PER_ADDRESS ); + for ( int i = 0; i < newHosts; ++i ) { + if ( altIndex >= MAX_ALTS ) + break; + altservers[altIndex].host = tempHosts[i]; + altIndex += 1; + } + current = end + 1; + } while ( end != NULL && altIndex < MAX_ALTS ); + logadd( LOG_INFO, "Got %d servers from init call", altIndex ); + // Connect + for ( int i = 0; i < altIndex; ++i ) { + if ( altservers[i].host.type == 0 ) + continue; + // Try to connect + sock = sock_connect( &altservers[i].host, 500, SOCKET_KEEPALIVE_TIMEOUT * 1000 ); + if ( sock == -1 ) { + counters->fails++; + logadd( LOG_ERROR, "Could not connect to host" ); + } else if ( !dnbd3_select_image( sock, lowerImage, rid, 0 ) ) { + counters->fails++; + logadd( LOG_ERROR, "Could not send select image" ); + } else if ( !dnbd3_select_image_reply( &buffer, sock, &remoteVersion, &remoteName, &remoteRid, &remoteSize ) ) { + counters->fails++; + logadd( LOG_ERROR, "Could not read select image reply (%d)", errno ); + } else if ( rid != 0 && rid != remoteRid ) { + counters->fails++; + logadd( LOG_ERROR, "rid mismatch" ); + } else { + counters->success++; + break; + } + // Failed + logadd( LOG_DEBUG1, "Server does not offer requested image... " ); + if ( sock != -1 ) { + close( sock ); + sock = -1; + } + } + if ( sock != -1 ) { + // connectionInitDone = true; + if (closeSockets) { + close( sock ); + } + } + } + } + return true; +} diff --git a/src/bench/connection.h b/src/bench/connection.h new file mode 100644 index 0000000..9cb59ef --- /dev/null +++ b/src/bench/connection.h @@ -0,0 +1,26 @@ +#ifndef _CONNECTION_H_ +#define _CONNECTION_H_ + +#include "../shared/fdsignal.h" +#include +#include +#include "helper.h" + +struct _dnbd3_async; + +typedef struct _dnbd3_async { + struct _dnbd3_async *next; // Next in this linked list (provate field, not set by caller) + char* buffer; // Caller-provided buffer to be filled + uint64_t offset; + uint32_t length; + dnbd3_signal_t* signal; // Used to signal the caller + bool finished; // Will be set to true if the request has been handled + bool success; // Will be set to true if the request succeeded +} dnbd3_async_t; + + +bool connection_init_n_times(const char *hosts, const char *image, const uint16_t rid, int ntimes, BenchCounters* counters, bool closeSockets); + +bool connection_init(const char *hosts, const char *image, const uint16_t rid); + +#endif /* CONNECTION_H_ */ diff --git a/src/bench/helper.c b/src/bench/helper.c new file mode 100644 index 0000000..c89b614 --- /dev/null +++ b/src/bench/helper.c @@ -0,0 +1,37 @@ +#include "helper.h" + +#include +#include +#include + +//BenchCounters benchC = { .attempts = 0, .success = 0, .fails = 0}; + +void printLog( log_info *info ) +{ + FILE *logFile; + + // Create logfile + + logFile = fopen( "log.txt", "w" ); + if ( logFile == NULL ) { + printf( "Error creating/opening log.txt\n" ); + return; + } + + //rewind(file); + fprintf( logFile, "ImageSize: %"PRIu64" MiB\n", ( uint64_t )( info->imageSize/ ( 1024ll*1024ll ) ) ); + fprintf( logFile, "ReceivedMiB: %"PRIu64" MiB\n", ( uint64_t )( info->receivedBytes/ ( 1024ll*1024ll ) ) ); + fprintf( logFile, "imageBlockCount: %"PRIu64"\n", info->imageBlockCount ); + fprintf( logFile, "Blocksize: 4KiB\n\n" ); + fprintf( logFile, "Block access count:\n" ); + + uint64_t i = 0; + for ( ; i < info->imageBlockCount; i++ ) { + if ( i % 50 == 0 ) { + fprintf( logFile, "\n" ); + } + fprintf( logFile, "%i ", ( int ) info->blockRequestCount[i] ); + } + fprintf( logFile, "\n" ); + fclose( logFile ); +} diff --git a/src/bench/helper.h b/src/bench/helper.h new file mode 100644 index 0000000..8342a79 --- /dev/null +++ b/src/bench/helper.h @@ -0,0 +1,38 @@ +#ifndef IMAGEHELPER_H +#define IMAGEHELPER_H + +#include "../types.h" + +#include +#include +#include +#include +#include + +typedef struct log_info { + uint64_t imageSize; + uint64_t receivedBytes; + uint64_t imageBlockCount; + uint8_t *blockRequestCount; +} log_info; + + +typedef struct BenchCounters { + int attempts; + int success; + int fails; +} BenchCounters; + + +typedef struct BenchThreadData { + BenchCounters* counter; + char* server_address; + char * image_name; + int runs; + int threadNumber; + bool closeSockets; +} BenchThreadData; + + + +#endif diff --git a/src/bench/main.c b/src/bench/main.c new file mode 100644 index 0000000..2f32dbf --- /dev/null +++ b/src/bench/main.c @@ -0,0 +1,154 @@ +/* +* Butchered from the dnbd3-fuse by C.K. +**/ + +#include "connection.h" +#include "helper.h" +#include "../shared/protocol.h" +#include "../shared/log.h" + +#include +#include +#include +#include +#include +#include + +#define debugf(...) do { logadd( LOG_DEBUG1, __VA_ARGS__ ); } while (0) + + +/* Debug/Benchmark variables */ +static bool useDebug = false; + + +static void printUsage(char *argv0, int exitCode) +{ + printf( "Usage: %s [--debug] --host --image [--rid revision]\n", argv0 ); + printf( "Or: %s [-d] -h -i [-r revision]\n", argv0 ); + printf( " -h --host List of space separated hosts to use\n" ); + printf( " -i --image Remote image name to request\n" ); + printf( " -r --rid Revision to use (omit or pass 0 for latest)\n" ); + printf( " -n --runs Number of connection attempts per thread\n" ); + printf( " -t --threads number of threads\n" ); + printf( " -l --log Write log to given location\n" ); + printf( " -d --debug Don't fork and print debug output (fuse > stderr, dnbd3 > stdout)\n" ); + // // fuse_main( 2, arg, &dnbd3_fuse_no_operations, NULL ); + exit( exitCode ); +} + +static const char *optString = "h:i:n:t:HvVd"; +static const struct option longOpts[] = { + { "host", required_argument, NULL, 'h' }, + { "image", required_argument, NULL, 'i' }, + { "nruns", optional_argument, NULL, 'n' }, + { "threads", optional_argument, NULL, 't' }, + { "help", optional_argument, NULL, 'H' }, + { "version", no_argument, NULL, 'v' }, + { 0, 0, 0, 0 } +}; + + +static void printBenchCounters(BenchCounters* c) { + printf ("Attempts:\t%d\n", c->attempts); + printf ("Success :\t%d\n", c->success); + printf ("Fails :\t%d\n", c->fails); +} + + +void* runBenchThread(void* t) { + BenchThreadData* data = t; + connection_init_n_times( + data->server_address, + data->server_address, + 0, + data->runs, + data->counter, + data->closeSockets); + printf("Thread #%d finished\n", data->threadNumber); + return NULL; +} + +int main(int argc, char *argv[]) +{ + char *server_address = NULL; + char *image_Name = NULL; + int opt, lidx; + + bool closeSockets = false; + int n_runs = 100; + int n_threads = 1; + + if ( argc <= 1 || strcmp( argv[1], "--help" ) == 0 || strcmp( argv[1], "--usage" ) == 0 ) { + printUsage( argv[0], 0 ); + } + + while ( ( opt = getopt_long( argc, argv, optString, longOpts, &lidx ) ) != -1 ) { + switch ( opt ) { + case 'h': + server_address = optarg; + break; + case 'i': + image_Name = optarg; + break; + case 'n': + n_runs = atoi(optarg); + break; + case 't': + n_threads = atoi(optarg); + break; + case 'c': + closeSockets = true; + break; + case 'H': + printUsage( argv[0], 0 ); + break; + case 'd': + useDebug = true; + break; + default: + printUsage( argv[0], EXIT_FAILURE ); + } + } + + printf("Welcome to dnbd3 benchmark tool\n"); + + /* all counters */ + BenchCounters counters[n_threads]; + BenchThreadData threadData[n_threads]; + pthread_t threads[n_threads]; + + /* create all threads */ + for (int i = 0; i < n_threads; i++) { + BenchCounters tmp1 = {0,0,0}; + counters[i] = tmp1; + BenchThreadData tmp2 = { + &(counters[i]), + server_address, + image_Name, + n_runs, + i, + closeSockets}; + threadData[i] = tmp2; + pthread_create(&(threads[i]), NULL, runBenchThread, &(threadData[i])); + } + + + /* join all threads*/ + for (int i = 0; i < n_threads; ++i) { + pthread_join(threads[i], NULL); + } + + /* print out all counters & sum up */ + BenchCounters total = {0,0,0}; + for (int i = 0; i < n_threads; ++i) { + printf("#### Thread %d\n", i); + printBenchCounters(&counters[i]); + total.attempts += counters[i].attempts; + total.success += counters[i].success; + total.fails += counters[i].fails; + } + /* print out summary */ + printf("\n\n#### SUMMARY\n"); + printBenchCounters(&total); + printf("\n-- End of program"); +} diff --git a/src/bench/serialize.c b/src/bench/serialize.c new file mode 100644 index 0000000..4934132 --- /dev/null +++ b/src/bench/serialize.c @@ -0,0 +1,5 @@ +#include +#include +#include + +#include "../serialize.c" -- cgit v1.2.3-55-g7522