Refactor struct bench and appropriate code paths
authorAlex Pyrgiotis <apyrgio@grnet.gr>
Tue, 12 Mar 2013 16:16:50 +0000 (18:16 +0200)
committerAlex Pyrgiotis <apyrgio@grnet.gr>
Tue, 12 Mar 2013 16:53:03 +0000 (18:53 +0200)
Changes:

1. Move flag values (such as pattern, insanity, verify) in a specific
   bit-field.
2. Create a struct req_status where the status of requests will be
   stored.
3. Tidy up code.

Rationale:

1. For parameters that can have only a few different values, it's an
   overkill to use a specific field in struct bench to store them, when
   we can just as well store them in a flag. This reduces the size of
   struct bench and makes the code easier to grasp.
2. Previously, the requests' statuses would be scattered amongst
   different timers, which is counter-intuitive at best. By placing them
   in a specific struct, we make the code more intuitive and readable.

xseg/peers/user/bench-timer.c
xseg/peers/user/bench-utils.c
xseg/peers/user/bench-xseg.c
xseg/peers/user/bench-xseg.h

index 157394b..edb47fa 100644 (file)
@@ -67,7 +67,7 @@ void timer_start(struct bench *prefs, struct timer *timer)
        //We need a low-latency way to get current time in nanoseconds.
        //QUESTION: Is this way the best way?
        //RAW means that we trust the system's oscilator isn't screwed up
-       if (prefs->insanity < timer->insanity)
+       if (GET_FLAG(INSANITY, prefs->flags) < timer->insanity)
                return;
 
        clock_gettime(CLOCK_MONOTONIC_RAW, &timer->start_time);
@@ -80,8 +80,8 @@ void timer_stop(struct bench *prefs, struct timer *timer,
        volatile struct timespec elapsed_time;
        struct timespec start_time;
 
-       if (prefs->insanity < timer->insanity)
-               goto inc_completed;
+       if (GET_FLAG(INSANITY, prefs->flags)< timer->insanity)
+               return;
 
        /*
         * There are timers such as rec_tm whose start_time cannot be trusted and
@@ -134,7 +134,6 @@ void timer_stop(struct bench *prefs, struct timer *timer,
                timer->sum_sq.tv_sec2 += elapsed_time_sq.tv_sec2;
        }
 #endif
-inc_completed:
        //TODO: check if we need to make it volatile
        timer->completed++;
 
index fd3160f..cd64730 100644 (file)
@@ -49,6 +49,9 @@
 #include <math.h>
 #include <string.h>
 
+/******************************\
+ * Static miscellaneous tools *
+\******************************/
 struct timespec delay = {0, 4000000};
 
 static inline uint64_t _get_id()
@@ -56,11 +59,46 @@ static inline uint64_t _get_id()
        return atol(global_id + 6); /* cut the "bench-" part*/
 }
 
+static inline uint64_t _get_object_from_name(char *name)
+{
+       return atol(name + IDLEN); /* cut the "bench-908135-" part*/
+}
+
 static inline uint64_t _get_object(struct bench *prefs, uint64_t new)
 {
        return new / (prefs->os / prefs->bs);
 }
 
+static inline double timespec2double(struct timespec num)
+{
+       return (double) (num.tv_sec * pow(10, 9) + num.tv_nsec);
+}
+
+/*
+ * Seperates a double number in seconds, msec, usec, nsec
+ * Expects a number in nanoseconds (e.g. a number from timespec2double)
+ */
+static struct tm_result separate_by_order(double num)
+{
+       struct tm_result res;
+
+       //The format we expect is the following:
+       //
+       //              |-s-|-ms-|-us-|-ns|
+       //num =  123 456  789  012 . 000000000000
+       res.s = num / pow(10,9);
+       num = fmod(num, pow(10,9));
+       res.ms = num / pow(10,6);
+       num = fmod(num, pow(10,6));
+       res.us = num / 1000;
+       res.ns = fmod(num, 1000);
+
+       return res;
+}
+
+/******************************\
+ * Argument-parsing functions *
+\******************************/
 
 /*
  * Convert string to size in bytes.
@@ -98,21 +136,16 @@ uint64_t str2num(char *str)
 /*
  * Converts struct timespec to double (units in nanoseconds)
  */
-static double timespec2double(struct timespec num)
-{
-       return (double) (num.tv_sec * pow(10, 9) + num.tv_nsec);
-}
-
 int read_insanity(char *insanity)
 {
        if (strncmp(insanity, "sane", MAX_ARG_LEN + 1) == 0)
-               return TM_SANE;
+               return INSANITY_SANE;
        if (strncmp(insanity, "eccentric", MAX_ARG_LEN + 1) == 0)
-               return TM_ECCENTRIC;
+               return INSANITY_ECCENTRIC;
        if (strncmp(insanity, "manic", MAX_ARG_LEN + 1) == 0)
-               return TM_MANIC;
+               return INSANITY_MANIC;
        if (strncmp(insanity, "paranoid", MAX_ARG_LEN + 1) == 0)
-               return TM_PARANOID;
+               return INSANITY_PARANOID;
        return -1;
 }
 
@@ -135,51 +168,38 @@ int read_verify(char *verify)
                return VERIFY_NO;
        if (strncmp(verify, "meta", MAX_ARG_LEN + 1) == 0)
                return VERIFY_META;
+       if (strncmp(verify, "full", MAX_ARG_LEN + 1) == 0)
+               return VERIFY_FULL;
        return -1;
 }
 
 int read_pattern(char *pattern)
 {
        if (strncmp(pattern, "seq", MAX_ARG_LEN + 1) == 0)
-               return IO_SEQ;
+               return PATTERN_SEQ;
        if (strncmp(pattern, "rand", MAX_ARG_LEN + 1) == 0)
-               return IO_RAND;
+               return PATTERN_RAND;
        return -1;
 }
 
-/*
- * Seperates a double number in seconds, msec, usec, nsec
- * Expects a number in nanoseconds (e.g. a number from timespec2double)
- */
-static struct tm_result separate_by_order(double num)
-{
-       struct tm_result res;
-
-       //The format we expect is the following:
-       //
-       //              |-s-|-ms-|-us-|-ns|
-       //num =  123 456  789  012 . 000000000000
-       res.s = num / pow(10,9);
-       num = fmod(num, pow(10,9));
-       res.ms = num / pow(10,6);
-       num = fmod(num, pow(10,6));
-       res.us = num / 1000;
-       res.ns = fmod(num, 1000);
-
-       return res;
-}
+/*******************\
+ * Print functions *
+\*******************/
 
 void print_stats(struct bench *prefs)
 {
        uint64_t remaining;
 
        printf("\n");
-       printf("Requests total:     %10lu\n", prefs->max_requests);
-       printf("Requests submitted: %10lu\n", prefs->sub_tm->completed);
-       printf("Requests received:  %10lu\n", prefs->rec_tm->completed);
+       printf("Requests total:     %10lu\n", prefs->status->max);
+       printf("Requests submitted: %10lu\n", prefs->status->submitted);
+       printf("Requests received:  %10lu\n", prefs->status->received);
+       printf("Requests failed:    %10lu\n", prefs->status->failed);
+       if ((prefs->op == X_READ) && (GET_FLAG(VERIFY, prefs->flags) != VERIFY_NO))
+               printf("Requests corrupted: %10lu\n", prefs->status->corrupted);
        printf("\n");
 
-       remaining = prefs->max_requests - prefs->rec_tm->completed;
+       remaining = prefs->status->max - prefs->status->received;
        if (remaining)
                printf("Requests remaining: %10lu\n", remaining);
        else
@@ -201,10 +221,10 @@ void print_res(struct bench *prefs, struct timer *tm, char *type)
        printf("Total time:   %3u. %03u  %03u  %03u\n",
                        res.s, res.ms, res.us, res.ns);
 
-       if (!prefs->rec_tm->completed)
+       if (!prefs->status->received)
                return;
 
-       res = separate_by_order(sum / prefs->rec_tm->completed);
+       res = separate_by_order(sum / prefs->status->received);
 
        printf("Mean Time:    %3u. %03u  %03u  %03u\n",
                        res.s, res.ms, res.us, res.ns);
@@ -212,6 +232,10 @@ void print_res(struct bench *prefs, struct timer *tm, char *type)
        //TODO: Add std
 }
 
+/**************************\
+ * Benchmarking functions *
+\**************************/
+
 void create_id(unsigned long seed)
 {
        if (seed > pow(10, 9))
@@ -247,6 +271,13 @@ void create_chunk(struct bench *prefs, struct xseg_request *req, uint64_t new)
        struct bench_lfsr id_lfsr, obj_lfsr, off_lfsr;
        uint64_t i;
 
+uint64_t determine_next(struct bench *prefs)
+{
+       if (GET_FLAG(PATTERN, prefs->flags) == PATTERN_SEQ)
+               return prefs->status->submitted;
+       else
+               return lfsr_next(prefs->lfsr);
+}
 
        id = _get_id();
        object = _get_object(prefs, new);
@@ -282,7 +313,7 @@ void create_chunk(struct bench *prefs, struct xseg_request *req, uint64_t new)
        /* check for left-overs chunk */
 }
 
-uint64_t determine_next(struct bench *prefs)
+int read_chunk(struct bench *prefs, struct xseg_request *req)
 {
        if ((prefs->flags & (1 << PATTERN_FLAG)) == IO_SEQ)
                return prefs->sub_tm->completed;
index b1699e4..f5baa4e 100644 (file)
 #include <limits.h>
 
 char global_id[IDLEN];
-
 /*
  * This macro checks two things:
  * a) If in-flight requests are less than given iodepth
  * b) If we have submitted all of the requests
  */
-#define CAN_SEND_REQUEST(prefs)        \
-       prefs->sub_tm->completed - prefs->rec_tm->completed < prefs->iodepth && \
-       prefs->sub_tm->completed < prefs->max_requests  \
+#define CAN_SEND_REQUEST(prefs)                                                                                                  \
+       ((prefs->status->submitted - prefs->status->received < prefs->iodepth) && \
+       (prefs->status->submitted < prefs->status->max))
+
+#define CAN_VERIFY(prefs)                                                                                                        \
+       ((GET_FLAG(VERIFY, prefs->flags) != VERIFY_NO) && prefs->op == X_READ)
 
 void custom_peer_usage()
 {
@@ -124,6 +126,13 @@ int custom_peer_init(struct peerd *peer, int argc, char *argv[])
        }
        prefs->flags = 0;
 
+       prefs->status = malloc(sizeof(struct req_status));
+       if (!prefs->status) {
+               perror("malloc");
+               return -1;
+       }
+       memset(prefs->status, 0, sizeof(struct req_status));
+
        //Begin reading the benchmark-specific arguments
        BEGIN_READ_ARGS(argc, argv);
        READ_ARG_STRING("-op", op, MAX_ARG_LEN);
@@ -166,7 +175,7 @@ int custom_peer_init(struct peerd *peer, int argc, char *argv[])
                XSEGLOG2(&lc, E, "Invalid syntax: --pattern %s\n", pattern);
                goto arg_fail;
        }
-       prefs->flags |= (uint8_t)r;
+       SET_FLAG(PATTERN, prefs->flags, r);
 
        if (!verify[0])
                strcpy(verify, "no");
@@ -175,6 +184,7 @@ int custom_peer_init(struct peerd *peer, int argc, char *argv[])
                XSEGLOG2(&lc, E, "Invalid syntax: --verify %s\n", verify);
                goto arg_fail;
        }
+       SET_FLAG(VERIFY, prefs->flags, r);
 
        //Default iodepth value is 1
        if (iodepth < 0)
@@ -193,11 +203,12 @@ int custom_peer_init(struct peerd *peer, int argc, char *argv[])
        if (!insanity[0])
                strcpy(insanity, "sane");
 
-       prefs->insanity = read_insanity(insanity);
-       if (prefs->insanity < 0) {
+       r = read_insanity(insanity);
+       if (r < 0) {
                XSEGLOG2(&lc, E, "Invalid syntax: --insanity %s\n", insanity);
                goto arg_fail;
        }
+       SET_FLAG(INSANITY, prefs->flags, r);
 
        /*
         * If we have a request other than read/write, we don't need to check
@@ -222,7 +233,7 @@ int custom_peer_init(struct peerd *peer, int argc, char *argv[])
 
                //In this case, the maximum number of requests is the total number of
                //objects we will handle
-               prefs->max_requests = prefs->to;
+               prefs->status->max = prefs->to;
        } else {
 
                /*************************\
@@ -284,7 +295,7 @@ int custom_peer_init(struct peerd *peer, int argc, char *argv[])
 
                //In this case, the maximum number of requests is the number of blocks
                //we need to cover the total I/O size
-               prefs->max_requests = prefs->ts / prefs->bs;
+               prefs->status->max = prefs->ts / prefs->bs;
        }
 
        /*************************\
@@ -303,13 +314,13 @@ int custom_peer_init(struct peerd *peer, int argc, char *argv[])
         * Create timers for all metrics *
        \*********************************/
 
-       if (init_timer(&prefs->total_tm, TM_SANE))
+       if (init_timer(&prefs->total_tm, INSANITY_SANE))
                goto tm_fail;
-       if (init_timer(&prefs->sub_tm, TM_MANIC))
+       if (init_timer(&prefs->sub_tm, INSANITY_MANIC))
                goto tm_fail;
-       if (init_timer(&prefs->get_tm, TM_PARANOID))
+       if (init_timer(&prefs->get_tm, INSANITY_PARANOID))
                goto tm_fail;
-       if (init_timer(&prefs->rec_tm, TM_ECCENTRIC))
+       if (init_timer(&prefs->rec_tm, INSANITY_ECCENTRIC))
                goto tm_fail;
 
        /********************************\
@@ -328,14 +339,14 @@ reseed:
        }
        create_id(seed);
 
-       if ((prefs->flags & (1 << PATTERN_FLAG)) == IO_RAND) {
+       if (GET_FLAG(PATTERN, prefs->flags) == PATTERN_RAND) {
                prefs->lfsr = malloc(sizeof(struct bench_lfsr));
                if (!prefs->lfsr) {
                        perror("malloc");
                        goto lfsr_fail;
                }
 
-               r = lfsr_init(prefs->lfsr, prefs->max_requests, seed, seed & 0xF);
+               r = lfsr_init(prefs->lfsr, prefs->status->max, seed, seed & 0xF);
                if (r && set_by_hand) {
                        XSEGLOG2(&lc, E, "LFSR could not be initialized\n");
                        goto lfsr_fail;
@@ -346,7 +357,7 @@ reseed:
        }
        XSEGLOG2(&lc, I, "Global ID is %s\n", global_id);
 
-       peer->peerd_loop = custom_peerd_loop;
+       peer->peerd_loop = bench_peerd_loop;
        peer->priv = (void *) prefs;
        return 0;
 
@@ -399,6 +410,7 @@ static int send_request(struct peerd *peer, struct bench *prefs)
 
        //Determine what the next target/chunk will be, based on I/O pattern
        new = determine_next(prefs);
+       req->op = prefs->op;
        XSEGLOG2(&lc, I, "Our new request is %lu\n", new);
        //Create a target of this format: "bench-<global_id>-<obj_no>"
        create_target(prefs, req, new);
@@ -413,7 +425,6 @@ static int send_request(struct peerd *peer, struct bench *prefs)
                        create_chunk(prefs, req, new);
        }
 
-       req->op = prefs->op;
 
        //Measure this?
        XSEGLOG2(&lc, D, "Allocate peer request\n");
@@ -446,7 +457,7 @@ static int send_request(struct peerd *peer, struct bench *prefs)
         * QUESTION: Is this the fastest way?
         */
        timer_start(prefs, prefs->rec_tm);
-       if (prefs->rec_tm->insanity <= prefs->insanity)
+       if (prefs->rec_tm->insanity <= GET_FLAG(INSANITY, prefs->flags))
                memcpy(pr->priv, &prefs->rec_tm->start_time, sizeof(struct timespec));
 
        //Submit the request from the source port to the target port
@@ -457,6 +468,7 @@ static int send_request(struct peerd *peer, struct bench *prefs)
                XSEGLOG2(&lc, W, "Cannot submit request\n");
                goto put_peer_request;
        }
+       prefs->status->submitted++;
        timer_stop(prefs, prefs->sub_tm, NULL);
 
        //Send SIGIO to the process that has bound this port to inform that
@@ -480,7 +492,7 @@ put_xseg_request:
  * This function substitutes the default generic_peerd_loop of peer.c.
  * It's plugged to struct peerd at custom peer's initialisation
  */
-int custom_peerd_loop(void *arg)
+int bench_peerd_loop(void *arg)
 {
 #ifdef MT
        struct thread *t = (struct thread *) arg;
@@ -518,9 +530,9 @@ send_request:
                while (CAN_SEND_REQUEST(prefs)) {
                        xseg_cancel_wait(xseg, peer->portno_start);
                        XSEGLOG2(&lc, D, "...because %lu < %lu && %lu < %lu\n",
-                                       prefs->sub_tm->completed - prefs->rec_tm->completed,
-                                       prefs->iodepth, prefs->sub_tm->completed,
-                                       prefs->max_requests);
+                                       prefs->status->submitted - prefs->status->received,
+                                       prefs->iodepth, prefs->status->received,
+                                       prefs->status->max);
                        XSEGLOG2(&lc, D, "Start sending new request\n");
                        r = send_request(peer, prefs);
                        if (r < 0)
@@ -534,7 +546,7 @@ send_request:
                        if (check_ports(peer)) {
                                //If an old request has just been acked, the most sensible
                                //thing to do is to immediately send a new one
-                               if (prefs->rec_tm->completed < prefs->max_requests)
+                               if (prefs->status->received < prefs->status->max)
                                        goto send_request;
                                else
                                        return 0;
@@ -582,6 +594,7 @@ static void handle_received(struct peerd *peer, struct peer_req *pr)
        struct bench *prefs = peer->priv;
        struct timer *rec = prefs->rec_tm;
 
+       prefs->status->received++;
        if (!pr->req) {
                //This is a serious error, so we must stop
                XSEGLOG2(&lc, E, "Received peer request with no xseg request");
@@ -589,7 +602,7 @@ static void handle_received(struct peerd *peer, struct peer_req *pr)
                return;
        }
 
-       if (!pr->priv) {
+       if ((GET_FLAG(INSANITY, prefs->flags) < rec->insanity) && !pr->priv) {
                XSEGLOG2(&lc, W, "Cannot find submission time of request");
                return;
        }
index ddfefd7..f4a4053 100644 (file)
 
 #define MAX_ARG_LEN 10
 
-#define TM_SANE 0
-#define TM_ECCENTRIC 1
-#define TM_MANIC 2
-#define TM_PARANOID 3
+/*
+ * Pattern type occupies 1st flag bit.
+ * If 1, it's sequential, if 0, it's random.
+ */
+#define PATTERN_FLAG_POS 0
+#define PATTERN_BITMASK 1
+#define PATTERN_SEQ 0
+#define PATTERN_RAND 1
 
 /*
- * Pattern type occupies first flag bit.
- * If 1, it's synchronous, if 0, it's random.
+ * Verify mode occupies 2nd and 3rd flag bit.
+ * If 01, it uses metadata for verification, if 11 it writes pseudorandom nums
+ * in chunk's memory range and if 00, it's off.
  */
-#define PATTERN_FLAG 0
-#define IO_SEQ 0 << PATTERN_FLAG
-#define IO_RAND 1 << PATTERN_FLAG
+#define VERIFY_FLAG_POS 1
+#define VERIFY_BITMASK 3       /* i.e. "11" in binary form */
+#define VERIFY_NO 0
+#define        VERIFY_META 1
+#define        VERIFY_FULL 2
+
+/* Timer insanity occupies 4th and 5th flag bit */
+#define INSANITY_FLAG_POS 3
+#define INSANITY_BITMASK 3     /* i.e. "11" in binary form */
+#define INSANITY_SANE 0
+#define INSANITY_ECCENTRIC 1
+#define INSANITY_MANIC 2
+#define INSANITY_PARANOID 3
+
 
 /*
- * Verify mode occupies second flag bit.
- * If 1, it uses metadata for verification, if 0, it's off.
+ * Current bench flags representation:
+ * 64 7  6  5  4  3  2  1 : bits
+ * ...0  0  0  0  0  0  0
+ *         |____||____||_|
+ *                       ^         ^   ^
+ *                       |             |   |
+ *                insanity     | pattern
+ *                              verify
  */
-#define VERIFY_FLAG 1
-#define VERIFY_NO 0 << VERIFY_FLAG
-#define        VERIFY_META 1 << VERIFY_FLAG
+/* Add flag bit according to its position */
+#define SET_FLAG(__ftype, __flag, __val)       \
+       __flag |= __val << __ftype##_FLAG_POS;
 
+/* Apply bitmask to flags, shift result to the right to get correct value */
+#define GET_FLAG(__ftype, __flag)                      \
+       (__flag & (__ftype##_BITMASK << __ftype##_FLAG_POS)) >> __ftype##_FLAG_POS
 /*
  * The benchark ID (IDLEN) is global for the test, calculated once and is a
  * string of the following form: {"bench-" + 9-digit number + "\0"}.
@@ -72,14 +97,13 @@ struct bench {
        uint64_t ts; //Total I/O size
        uint64_t os; //Object size
        uint64_t bs; //Block size
-       uint64_t max_requests; //Max number of requests for a benchmark
        uint32_t iodepth; //Num of in-flight xseg reqs
-       int insanity;
        xport dst_port;
        xport src_port;
        uint32_t op;    //xseg operation
-       uint8_t flags;
+       uint64_t flags;
        struct peerd *peer;
+       struct req_status *status;
        struct bench_lfsr *lfsr;
        struct timer *total_tm; //Total time for benchmark
        struct timer *get_tm;   //Time for xseg_get_request
@@ -87,6 +111,14 @@ struct bench {
        struct timer *rec_tm;   //Time for xseg_receive_request
 };
 
+struct req_status {
+       uint64_t max;           /* Max requests for benchmark */
+       uint64_t submitted;
+       uint64_t received;
+       uint64_t corrupted;     /* Requests that did not pass verification */
+       uint64_t failed;
+};
+
 /*
  * Custom timespec. Made to calculate variance, where we need the square of a
  * timespec struct. This struct should be more than enough to hold the square
@@ -122,17 +154,14 @@ struct tm_result {
        unsigned int ns;
 };
 
-/* FILLME */
 struct signature {
-       char obj_name[TARGETLEN];
+       uint64_t id;
+       uint64_t object;
        uint64_t offset;
-       uint64_t size;
-
-       //hash of data (heavy)
 };
 
 
-int custom_peerd_loop(void *arg);
+int bench_peerd_loop(void *arg);
 
 void timer_start(struct bench *prefs, struct timer *sample_req);
 void timer_stop(struct bench *prefs, struct timer *sample_tm,