bench: Break large source file into smaller files
authorAlex Pyrgiotis <apyrgio@grnet.gr>
Fri, 19 Jul 2013 07:12:47 +0000 (10:12 +0300)
committerFilippos Giannakos <philipgian@grnet.gr>
Fri, 19 Jul 2013 14:06:30 +0000 (17:06 +0300)
The bench-utils.c file started to have utilities that could stand
semantically under a separate category. Namely, verification is now at
bench-verify.c and progress report under bench-report.c.

xseg/peers/user/Makefile
xseg/peers/user/bench-report.c [new file with mode: 0644]
xseg/peers/user/bench-utils.c
xseg/peers/user/bench-verify.c [new file with mode: 0644]

index 528bbf4..01fe5dd 100644 (file)
@@ -83,6 +83,7 @@ archip-dummy: dummy.c peer.c peer.h
        $(CC) $(CFLAGS) -o $@ $< peer.c $(INC) -L$(LIB) -lxseg -lpthread -DMT
 
 BENCH_PREQ=bench-xseg.c peer.c bench-lfsr.c bench-timer.c bench-utils.c \
+          bench-report.c bench-verify.c                                \
           bench-xseg.h peer.h bench-lfsr.h $(BASE)/xseg/protocol.h
 
 archip-bench: $(BENCH_PREQ)
diff --git a/xseg/peers/user/bench-report.c b/xseg/peers/user/bench-report.c
new file mode 100644 (file)
index 0000000..6648b8f
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2012 GRNET S.A. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and
+ * documentation are those of the authors and should not be
+ * interpreted as representing official policies, either expressed
+ * or implied, of GRNET S.A.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <xseg/xseg.h>
+#include <peer.h>
+#include <time.h>
+#include <sys/util.h>
+#include <signal.h>
+#include <bench-xseg.h>
+
+#include <math.h>
+#include <string.h>
+
+/******************************\
+ * Static miscellaneous tools *
+\******************************/
+
+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;
+}
+
+static void __calculate_bw(struct bench *prefs, double iops, struct bw *bw)
+{
+       bw->val = iops * prefs->bs;
+
+       if (bw->val < 1024) {
+               strcpy(bw->unit, "B/s");
+               return;
+       }
+
+       bw->val = bw->val / 1024;
+
+       if (bw->val < 1024) {
+               strcpy(bw->unit, "KB/s");
+               return;
+       }
+
+       bw->val = bw->val / 1024;
+
+       if (bw->val < 1024) {
+               strcpy(bw->unit, "MB/s");
+               return;
+       }
+
+       bw->val = bw->val / 1024;
+       strcpy(bw->unit, "GB/s");
+}
+
+static double __calculate_iops(uint64_t requests, double elapsed_ns)
+{
+       /* elapsed_ns is in nanoseconds, so we convert it to seconds */
+       double elapsed = elapsed_ns / pow(10,9);
+       return (requests / elapsed);
+}
+
+/*******************\
+ * Print functions *
+\*******************/
+
+int calculate_report_lines(struct bench *prefs)
+{
+       int progress = GET_FLAG(PROGRESS, prefs->flags);
+       int lines = 0;
+
+       if (progress == PROGRESS_REQ || progress == PROGRESS_BOTH) {
+               lines = 6;
+               if ((GET_FLAG(VERIFY, prefs->flags) != VERIFY_NO) &&
+                               (prefs->op == X_READ))
+                       lines++;
+       }
+       if (progress == PROGRESS_IO ||  progress == PROGRESS_BOTH) {
+               lines += 1;
+               if (prefs->op == X_READ || prefs->op == X_WRITE)
+                       lines++;
+       }
+
+       return lines;
+}
+
+void clear_report_lines(int lines)
+{
+       fprintf(stdout, "\033[%dA\033[J", lines);
+}
+
+void print_divider()
+{
+       fprintf(stdout, "           ~~~~~~~~~~~~~~~~~~~~~~~~\n");
+}
+
+void print_io_stats(struct bench *prefs)
+{
+       struct timer *tm = prefs->total_tm;
+       struct bw bw;
+       double elapsed;
+       double iops;
+
+       if (!prefs->status->received) {
+               if (prefs->op == X_READ || prefs->op == X_WRITE)
+                       fprintf(stdout, "Bandwidth:    NaN\n");
+               fprintf(stdout, "IOPS:         NaN\n");
+               return;
+       }
+
+       elapsed = __timespec2double(tm->elapsed_time);
+       iops = __calculate_iops(prefs->rep->interval, elapsed);
+       __calculate_bw(prefs, iops, &bw);
+
+       if (prefs->op == X_READ || prefs->op == X_WRITE)
+               fprintf(stdout, "Bandwidth:    %.3lf %s\n", bw.val, bw.unit);
+       fprintf(stdout, "IOPS:         %.3lf\n", iops);
+}
+
+void print_req_stats(struct bench *prefs)
+{
+       fprintf(stdout, "\n"
+                       "Requests total:     %10lu\n"
+                       "Requests submitted: %10lu\n"
+                       "Requests received:  %10lu\n"
+                       "Requests failed:    %10lu\n",
+                       prefs->status->max,
+                       prefs->status->submitted,
+                       prefs->status->received,
+                       prefs->status->failed);
+       if ((prefs->op == X_READ) &&
+                       (GET_FLAG(VERIFY, prefs->flags) != VERIFY_NO))
+               fprintf(stdout, "Requests corrupted: %10lu\n",
+                               prefs->status->corrupted);
+       fprintf(stdout, "\n");
+}
+
+void print_remaining(struct bench *prefs)
+{
+       uint64_t remaining;
+
+       remaining = prefs->status->max - prefs->status->received;
+       if (remaining)
+               fprintf(stdout, "Requests remaining: %10lu\n", remaining);
+       else
+               fprintf(stdout, "All requests have been served.\n");
+}
+
+void print_total_res(struct bench *prefs)
+{
+       struct timer *tm = prefs->total_tm;
+       struct tm_result res;
+       double sum;
+
+       sum = __timespec2double(tm->sum);
+       res = __separate_by_order(sum);
+
+       fprintf(stdout, "\n");
+       fprintf(stdout, "              Benchmark results\n");
+       fprintf(stdout, "           ========================\n");
+       fprintf(stdout, "             |-s-||-ms-|-us-|-ns-|\n");
+       fprintf(stdout, "Total time:   %3u. %03u  %03u  %03u\n",
+                       res.s, res.ms, res.us, res.ns);
+}
+
+void print_rec_res(struct bench *prefs)
+{
+       struct timer *tm = prefs->rec_tm;
+       struct tm_result res;
+       double sum;
+
+       if (!prefs->status->received) {
+               fprintf(stdout, "Avg. latency: NaN\n");
+               return;
+       }
+
+       sum = __timespec2double(tm->sum);
+       res = __separate_by_order(sum / prefs->status->received);
+
+       fprintf(stdout, "Avg. latency: %3u. %03u  %03u  %03u\n",
+                       res.s, res.ms, res.us, res.ns);
+}
+
+static void __print_progress(struct bench *prefs)
+{
+       int progress = GET_FLAG(PROGRESS, prefs->flags);
+
+       if (progress == PROGRESS_REQ || progress == PROGRESS_BOTH)
+                       print_req_stats(prefs);
+       if (progress == PROGRESS_IO ||  progress == PROGRESS_BOTH)
+                       print_io_stats(prefs);
+       fflush(stdout);
+}
+
+void print_dummy_progress(struct bench *prefs)
+{
+       __print_progress(prefs);
+}
+
+void print_progress(struct bench *prefs)
+{
+       timer_stop(prefs, prefs->total_tm, NULL);
+       clear_report_lines(prefs->rep->lines);
+       __print_progress(prefs);
+       timer_start(prefs, prefs->total_tm);
+}
+
+
index 584ad71..8213ed4 100644 (file)
 #include <math.h>
 #include <string.h>
 
-#define PRINT_SIG(__who, __sig)                                                \
-       fprintf(stdout, "%s (%lu): id %lu, object %lu, offset %lu\n",   \
-                       #__who, (uint64_t)(__sig),                      \
-                       ((struct signature *)__sig)->id,                \
-                       ((struct signature *)__sig)->object,            \
-                       ((struct signature *)__sig)->offset);
-
 struct timespec delay = {0, 4000000};
 
-__attribute__ ((unused))
-void inspect_obv(struct object_vars *obv)
-{
-       XSEGLOG2(&lc, D, "Struct object vars:\n"
-                       "\tname: %s (%d),\n"
-                       "\tprefix: %s (%d),\n"
-                       "\tseed: %lu (%d),\n"
-                       "\tobjnum: %lu (%d)",
-                       obv->name, obv->namelen, obv->prefix, obv->prefixlen,
-                       obv->seed, obv->seedlen,
-                       obv->objnum, obv->objnumlen);
-}
-
 uint64_t __get_object(struct bench *prefs, uint64_t new)
 {
        if (prefs->ts > 0)
@@ -79,125 +59,6 @@ uint64_t __get_object(struct bench *prefs, uint64_t new)
 }
 
 /******************************\
- * Static miscellaneous tools *
-\******************************/
-static inline uint64_t __get_object_from_name(struct object_vars *obv,
-               char *name)
-{
-       /* In case of --objname switch */
-       if (obv->name[0])
-               return 0;
-
-       /* Keep only the object number */
-       return atol(name + obv->namelen - obv->objnumlen);
-}
-
-static inline int __snap_to_bound8(uint64_t space)
-{
-       return space > 8 ? 8 : space;
-}
-
-static inline double __timespec2double(struct timespec num)
-{
-       return (double) (num.tv_sec * pow(10, 9) + num.tv_nsec);
-}
-
-static inline void __write_sig(struct bench_lfsr *sg, uint64_t *d, uint64_t s,
-               int pos)
-{
-       uint64_t i;
-       uint64_t last_val;
-       uint64_t space_left;
-
-       /* Write random numbers (based on global_id) every 24 bytes */
-       /* TODO: Should we use memcpy? */
-       for (i = pos; i < (s / 8) - (3 - pos); i += 3)
-               *(d + i) = lfsr_next(sg);
-
-       /* special care for last chunk */
-       last_val = lfsr_next(sg);
-       space_left = s - (i * 8);
-       memcpy(d + i, &last_val, __snap_to_bound8(space_left));
-}
-
-static inline int __read_sig(struct bench_lfsr *sg, uint64_t *d, uint64_t s,
-               int pos)
-{
-       uint64_t i;
-       uint64_t last_val;
-       uint64_t space_left;
-
-       /* TODO: Should we use memcmp? */
-       for (i = pos; i < (s / 8) - (3 - pos); i += 3) {
-               if (*(d + i) != lfsr_next(sg))
-                       return 1;
-       }
-       /* special care for last chunk */
-       last_val = lfsr_next(sg);
-       space_left = s - (i * 8);
-       if (memcmp(d + i, &last_val, __snap_to_bound8(space_left)))
-               return 1;
-
-       return 0;
-}
-
-/*
- * 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;
-}
-
-static void __calculate_bw(struct bench *prefs, double iops, struct bw *bw)
-{
-       bw->val = iops * prefs->bs;
-
-       if (bw->val < 1024) {
-               strcpy(bw->unit, "B/s");
-               return;
-       }
-
-       bw->val = bw->val / 1024;
-
-       if (bw->val < 1024) {
-               strcpy(bw->unit, "KB/s");
-               return;
-       }
-
-       bw->val = bw->val / 1024;
-
-       if (bw->val < 1024) {
-               strcpy(bw->unit, "MB/s");
-               return;
-       }
-
-       bw->val = bw->val / 1024;
-       strcpy(bw->unit, "GB/s");
-}
-
-static double __calculate_iops(uint64_t requests, double elapsed_ns)
-{
-       /* elapsed_ns is in nanoseconds, so we convert it to seconds */
-       double elapsed = elapsed_ns / pow(10,9);
-       return (requests / elapsed);
-}
-
-/******************************\
  * Argument-parsing functions *
 \******************************/
 
@@ -335,10 +196,6 @@ int validate_seed(struct bench *prefs, unsigned long seed)
        return -1;
 }
 
-/*******************\
- * Print functions *
-\*******************/
-
 uint64_t calculate_interval(struct bench *prefs, uint64_t percentage)
 {
        uint64_t interval = round((double)prefs->status->max *
@@ -350,147 +207,6 @@ uint64_t calculate_interval(struct bench *prefs, uint64_t percentage)
        return interval;
 }
 
-int calculate_report_lines(struct bench *prefs)
-{
-       int progress = GET_FLAG(PROGRESS, prefs->flags);
-       int lines = 0;
-
-       if (progress == PROGRESS_REQ || progress == PROGRESS_BOTH) {
-               lines = 6;
-               if ((GET_FLAG(VERIFY, prefs->flags) != VERIFY_NO) &&
-                               (prefs->op == X_READ))
-                       lines++;
-       }
-       if (progress == PROGRESS_IO ||  progress == PROGRESS_BOTH) {
-               lines += 1;
-               if (prefs->op == X_READ || prefs->op == X_WRITE)
-                       lines++;
-       }
-
-       return lines;
-}
-
-void clear_report_lines(int lines)
-{
-       fprintf(stdout, "\033[%dA\033[J", lines);
-}
-
-void print_divider()
-{
-       fprintf(stdout, "           ~~~~~~~~~~~~~~~~~~~~~~~~\n");
-}
-
-void print_io_stats(struct bench *prefs)
-{
-       struct timer *tm = prefs->total_tm;
-       struct bw bw;
-       double elapsed;
-       double iops;
-
-       if (!prefs->status->received) {
-               if (prefs->op == X_READ || prefs->op == X_WRITE)
-                       fprintf(stdout, "Bandwidth:    NaN\n");
-               fprintf(stdout, "IOPS:         NaN\n");
-               return;
-       }
-
-       elapsed = __timespec2double(tm->elapsed_time);
-       iops = __calculate_iops(prefs->rep->interval, elapsed);
-       __calculate_bw(prefs, iops, &bw);
-
-       if (prefs->op == X_READ || prefs->op == X_WRITE)
-               fprintf(stdout, "Bandwidth:    %.3lf %s\n", bw.val, bw.unit);
-       fprintf(stdout, "IOPS:         %.3lf\n", iops);
-}
-
-void print_req_stats(struct bench *prefs)
-{
-       fprintf(stdout, "\n"
-                       "Requests total:     %10lu\n"
-                       "Requests submitted: %10lu\n"
-                       "Requests received:  %10lu\n"
-                       "Requests failed:    %10lu\n",
-                       prefs->status->max,
-                       prefs->status->submitted,
-                       prefs->status->received,
-                       prefs->status->failed);
-       if ((prefs->op == X_READ) &&
-                       (GET_FLAG(VERIFY, prefs->flags) != VERIFY_NO))
-               fprintf(stdout, "Requests corrupted: %10lu\n",
-                               prefs->status->corrupted);
-       fprintf(stdout, "\n");
-}
-
-void print_remaining(struct bench *prefs)
-{
-       uint64_t remaining;
-
-       remaining = prefs->status->max - prefs->status->received;
-       if (remaining)
-               fprintf(stdout, "Requests remaining: %10lu\n", remaining);
-       else
-               fprintf(stdout, "All requests have been served.\n");
-}
-
-void print_total_res(struct bench *prefs)
-{
-       struct timer *tm = prefs->total_tm;
-       struct tm_result res;
-       double sum;
-
-       sum = __timespec2double(tm->sum);
-       res = __separate_by_order(sum);
-
-       fprintf(stdout, "\n");
-       fprintf(stdout, "              Benchmark results\n");
-       fprintf(stdout, "           ========================\n");
-       fprintf(stdout, "             |-s-||-ms-|-us-|-ns-|\n");
-       fprintf(stdout, "Total time:   %3u. %03u  %03u  %03u\n",
-                       res.s, res.ms, res.us, res.ns);
-}
-
-void print_rec_res(struct bench *prefs)
-{
-       struct timer *tm = prefs->rec_tm;
-       struct tm_result res;
-       double sum;
-
-       if (!prefs->status->received) {
-               fprintf(stdout, "Avg. latency: NaN\n");
-               return;
-       }
-
-       sum = __timespec2double(tm->sum);
-       res = __separate_by_order(sum / prefs->status->received);
-
-       fprintf(stdout, "Avg. latency: %3u. %03u  %03u  %03u\n",
-                       res.s, res.ms, res.us, res.ns);
-}
-
-static void __print_progress(struct bench *prefs)
-{
-       int progress = GET_FLAG(PROGRESS, prefs->flags);
-
-       if (progress == PROGRESS_REQ || progress == PROGRESS_BOTH)
-                       print_req_stats(prefs);
-       if (progress == PROGRESS_IO ||  progress == PROGRESS_BOTH)
-                       print_io_stats(prefs);
-       fflush(stdout);
-}
-
-void print_dummy_progress(struct bench *prefs)
-{
-       __print_progress(prefs);
-}
-
-void print_progress(struct bench *prefs)
-{
-       timer_stop(prefs, prefs->total_tm, NULL);
-       clear_report_lines(prefs->rep->lines);
-       __print_progress(prefs);
-       timer_start(prefs, prefs->total_tm);
-}
-
 /**************************\
  * Benchmarking functions *
 \**************************/
@@ -536,173 +252,3 @@ uint64_t calculate_offset(struct bench *prefs, uint64_t new)
                return 0;
 }
 
-/*
- * ***********************************************
- * `create_chunk` handles 3 identifiers:
- * 1. The benchmark's global_id
- * 2. The object's number
- * 3. The chunk offset in the object
- *
- * ************************************************
- * `readwrite_chunk_full` takes the above 3 identifiers and feeds them as seeds
- * in 63-bit LFSRs. The numbers generated are written consecutively in chunk's
- * memory range. For example, for a 72-byte chunk:
- *
- * || 1 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 ||
- *  ^   8  16  24  32  40  48  56  64   ^
- *  |                                   |
- *  |                                   |
- * start                               end
- *
- * 1,2,3 differ between each iteration
- *
- * **************************************************
- * `_create_chunk_meta` simply writes the above 3 ids in the start and end of
- * the chunk's memory range, so it should be much faster (but less safe)
- *
- * **************************************************
- * In both cases, special care is taken not to exceed the chunk's memory range.
- * Also, the bare minimum chunk to verify should be 48 bytes. This limit is set
- * by readwrite_chunk_meta, which expects to write in a memory at least this
- * big.
- *
- * **************************************************
- * Note: The diagram above also represents the x86_64's endianness.
- * Endianness must be taken into careful consideration when examining a memory
- * chunk.
- */
-static int readwrite_chunk_full(struct bench *prefs, struct xseg_request *req)
-{
-       struct bench_lfsr id_lfsr;
-       struct bench_lfsr obj_lfsr;
-       struct bench_lfsr off_lfsr;
-       struct xseg *xseg = prefs->peer->xseg;
-       uint64_t id = prefs->objvars->seed;
-       uint64_t object = prefs->objvars->objnum;
-       uint64_t *d = (uint64_t *)xseg_get_data(xseg, req);
-       uint64_t s = req->size;
-
-       /* Create 63-bit LFSRs */
-       lfsr_init(&id_lfsr, 0x7FFFFFFFFFFFFFFF, id, 0);
-       lfsr_init(&obj_lfsr, 0x7FFFFFFFFFFFFFFF, object, 0);
-       lfsr_init(&off_lfsr, 0x7FFFFFFFFFFFFFFF, req->offset, 0);
-
-       if (s < sizeof(struct signature)) {
-               XSEGLOG2(&lc, E, "Too small chunk size (%lu butes). Leaving.", s);
-               return 1;
-       }
-
-       /*
-        * Every write operation has its read counterpart which, if it finds any
-        * corruption, returns 1
-        */
-
-       if (req->op == X_WRITE) {
-               __write_sig(&id_lfsr, d, s, 0);
-               __write_sig(&obj_lfsr, d, s, 1);
-               __write_sig(&off_lfsr, d, s, 2);
-       } else {
-               if (__read_sig(&id_lfsr, d, s, 0))
-                       return 1;
-               if (__read_sig(&obj_lfsr, d, s, 1))
-                       return 1;
-               if(__read_sig(&off_lfsr, d, s, 2))
-                       return 1;
-       }
-
-       return 0;
-}
-
-static int readwrite_chunk_meta(struct bench *prefs, struct xseg_request *req)
-{
-       struct xseg *xseg = prefs->peer->xseg;
-       struct signature sig;
-       uint64_t id = prefs->objvars->seed;
-       uint64_t object = prefs->objvars->objnum;
-       char *d = xseg_get_data(xseg, req);
-       uint64_t s = req->size;
-       int sig_s = sizeof(struct signature);
-       int r = 0;
-
-       sig.id = id;
-       sig.object = object;
-       sig.offset = req->offset;
-
-       if (s < sig_s) {
-               XSEGLOG2(&lc, E, "Too small chunk size (%lu butes). "
-                               "Leaving.", s);
-               return 1;
-       }
-
-       //PRINT_SIG(expected, (&sig));
-       /* Read/Write chunk signature both at its start and at its end */
-       if (req->op == X_WRITE) {
-               memcpy(d, &sig, sig_s);
-               memcpy(d + s - sig_s, &sig, sig_s);
-       } else {
-               if (memcmp(d, &sig, sig_s))
-                       r = 1;
-               else if (memcmp(d + s - sig_s, &sig, sig_s))
-                       r = 1;
-       }
-       //PRINT_SIG(start, d);
-       //PRINT_SIG(end, (d + s - sig_s));
-       return r;
-}
-
-/*
- * We want these functions to be as fast as possible in case we haven't asked
- * for verification
- */
-void create_chunk(struct bench *prefs, struct xseg_request *req, uint64_t new)
-{
-       int verify;
-
-       verify = GET_FLAG(VERIFY, prefs->flags);
-       switch (verify) {
-               case VERIFY_NO:
-                       break;
-               case VERIFY_META:
-                       inspect_obv(prefs->objvars);
-                       readwrite_chunk_meta(prefs, req);
-                       break;
-               case VERIFY_FULL:
-                       inspect_obv(prefs->objvars);
-                       readwrite_chunk_full(prefs, req);
-                       break;
-               default:
-                       XSEGLOG2(&lc, W, "Unexpected verification mode: %d\n",
-                                       verify);
-       }
-}
-
-int read_chunk(struct bench *prefs, struct xseg_request *req)
-{
-       struct xseg *xseg = prefs->peer->xseg;
-       struct object_vars *obv = prefs->objvars;
-       char *target;
-       int verify;
-       int r = 0;
-
-       verify = GET_FLAG(VERIFY, prefs->flags);
-       switch (verify) {
-               case VERIFY_NO:
-                       break;
-               case VERIFY_META:
-                       target = xseg_get_target(xseg, req);
-                       obv->objnum = __get_object_from_name(obv, target);
-                       inspect_obv(prefs->objvars);
-                       r = readwrite_chunk_meta(prefs, req);
-                       break;
-               case VERIFY_FULL:
-                       target = xseg_get_target(xseg, req);
-                       obv->objnum = __get_object_from_name(obv, target);
-                       inspect_obv(prefs->objvars);
-                       r = readwrite_chunk_full(prefs, req);
-                       break;
-               default:
-                       XSEGLOG2(&lc, W, "Unexpected verification mode: %d\n",
-                                       verify);
-       }
-       return r;
-}
diff --git a/xseg/peers/user/bench-verify.c b/xseg/peers/user/bench-verify.c
new file mode 100644 (file)
index 0000000..5a5fa03
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2012 GRNET S.A. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and
+ * documentation are those of the authors and should not be
+ * interpreted as representing official policies, either expressed
+ * or implied, of GRNET S.A.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <xseg/xseg.h>
+#include <peer.h>
+#include <time.h>
+#include <sys/util.h>
+#include <signal.h>
+#include <bench-xseg.h>
+
+#include <math.h>
+#include <string.h>
+
+/********************\
+ * Diagnostic tools *
+\********************/
+
+#define PRINT_SIG(__who, __sig)                                                \
+       fprintf(stdout, "%s (%lu): id %lu, object %lu, offset %lu\n",   \
+                       #__who, (uint64_t)(__sig),                      \
+                       ((struct signature *)__sig)->id,                \
+                       ((struct signature *)__sig)->object,            \
+                       ((struct signature *)__sig)->offset);
+
+__attribute__ ((unused))
+void inspect_obv(struct object_vars *obv)
+{
+       XSEGLOG2(&lc, D, "Struct object vars:\n"
+                       "\tname: %s (%d),\n"
+                       "\tprefix: %s (%d),\n"
+                       "\tseed: %lu (%d),\n"
+                       "\tobjnum: %lu (%d)",
+                       obv->name, obv->namelen, obv->prefix, obv->prefixlen,
+                       obv->seed, obv->seedlen,
+                       obv->objnum, obv->objnumlen);
+}
+
+/******************************\
+ * Static miscellaneous tools *
+\******************************/
+
+static inline uint64_t __get_object_from_name(struct object_vars *obv,
+               char *name)
+{
+       /* In case of --objname switch */
+       if (obv->name[0])
+               return 0;
+
+       /* Keep only the object number */
+       return atol(name + obv->namelen - obv->objnumlen);
+}
+
+static inline int __snap_to_bound8(uint64_t space)
+{
+       return space > 8 ? 8 : space;
+}
+
+static inline void __write_sig(struct bench_lfsr *sg, uint64_t *d, uint64_t s,
+               int pos)
+{
+       uint64_t i;
+       uint64_t last_val;
+       uint64_t space_left;
+
+       /* Write random numbers (based on global_id) every 24 bytes */
+       /* TODO: Should we use memcpy? */
+       for (i = pos; i < (s / 8) - (3 - pos); i += 3)
+               *(d + i) = lfsr_next(sg);
+
+       /* special care for last chunk */
+       last_val = lfsr_next(sg);
+       space_left = s - (i * 8);
+       memcpy(d + i, &last_val, __snap_to_bound8(space_left));
+}
+
+static inline int __read_sig(struct bench_lfsr *sg, uint64_t *d, uint64_t s,
+               int pos)
+{
+       uint64_t i;
+       uint64_t last_val;
+       uint64_t space_left;
+
+       /* TODO: Should we use memcmp? */
+       for (i = pos; i < (s / 8) - (3 - pos); i += 3) {
+               if (*(d + i) != lfsr_next(sg))
+                       return 1;
+       }
+       /* special care for last chunk */
+       last_val = lfsr_next(sg);
+       space_left = s - (i * 8);
+       if (memcmp(d + i, &last_val, __snap_to_bound8(space_left)))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * ***********************************************
+ * `create_chunk` handles 3 identifiers:
+ * 1. The benchmark's global_id
+ * 2. The object's number
+ * 3. The chunk offset in the object
+ *
+ * ************************************************
+ * `readwrite_chunk_full` takes the above 3 identifiers and feeds them as seeds
+ * in 63-bit LFSRs. The numbers generated are written consecutively in chunk's
+ * memory range. For example, for a 72-byte chunk:
+ *
+ * || 1 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 ||
+ *  ^   8  16  24  32  40  48  56  64   ^
+ *  |                                   |
+ *  |                                   |
+ * start                               end
+ *
+ * 1,2,3 differ between each iteration
+ *
+ * **************************************************
+ * `_create_chunk_meta` simply writes the above 3 ids in the start and end of
+ * the chunk's memory range, so it should be much faster (but less safe)
+ *
+ * **************************************************
+ * In both cases, special care is taken not to exceed the chunk's memory range.
+ * Also, the bare minimum chunk to verify should be 48 bytes. This limit is set
+ * by readwrite_chunk_meta, which expects to write in a memory at least this
+ * big.
+ *
+ * **************************************************
+ * Note: The diagram above also represents the x86_64's endianness.
+ * Endianness must be taken into careful consideration when examining a memory
+ * chunk.
+ */
+static int readwrite_chunk_full(struct bench *prefs, struct xseg_request *req)
+{
+       struct bench_lfsr id_lfsr;
+       struct bench_lfsr obj_lfsr;
+       struct bench_lfsr off_lfsr;
+       struct xseg *xseg = prefs->peer->xseg;
+       uint64_t id = prefs->objvars->seed;
+       uint64_t object = prefs->objvars->objnum;
+       uint64_t *d = (uint64_t *)xseg_get_data(xseg, req);
+       uint64_t s = req->size;
+
+       /* Create 63-bit LFSRs */
+       lfsr_init(&id_lfsr, 0x7FFFFFFFFFFFFFFF, id, 0);
+       lfsr_init(&obj_lfsr, 0x7FFFFFFFFFFFFFFF, object, 0);
+       lfsr_init(&off_lfsr, 0x7FFFFFFFFFFFFFFF, req->offset, 0);
+
+       if (s < sizeof(struct signature)) {
+               XSEGLOG2(&lc, E, "Too small chunk size (%lu butes). Leaving.", s);
+               return 1;
+       }
+
+       /*
+        * Every write operation has its read counterpart which, if it finds any
+        * corruption, returns 1
+        */
+
+       if (req->op == X_WRITE) {
+               __write_sig(&id_lfsr, d, s, 0);
+               __write_sig(&obj_lfsr, d, s, 1);
+               __write_sig(&off_lfsr, d, s, 2);
+       } else {
+               if (__read_sig(&id_lfsr, d, s, 0))
+                       return 1;
+               if (__read_sig(&obj_lfsr, d, s, 1))
+                       return 1;
+               if(__read_sig(&off_lfsr, d, s, 2))
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int readwrite_chunk_meta(struct bench *prefs, struct xseg_request *req)
+{
+       struct xseg *xseg = prefs->peer->xseg;
+       struct signature sig;
+       uint64_t id = prefs->objvars->seed;
+       uint64_t object = prefs->objvars->objnum;
+       char *d = xseg_get_data(xseg, req);
+       uint64_t s = req->size;
+       int sig_s = sizeof(struct signature);
+       int r = 0;
+
+       sig.id = id;
+       sig.object = object;
+       sig.offset = req->offset;
+
+       if (s < sig_s) {
+               XSEGLOG2(&lc, E, "Too small chunk size (%lu butes). "
+                               "Leaving.", s);
+               return 1;
+       }
+
+       //PRINT_SIG(expected, (&sig));
+       /* Read/Write chunk signature both at its start and at its end */
+       if (req->op == X_WRITE) {
+               memcpy(d, &sig, sig_s);
+               memcpy(d + s - sig_s, &sig, sig_s);
+       } else {
+               if (memcmp(d, &sig, sig_s))
+                       r = 1;
+               else if (memcmp(d + s - sig_s, &sig, sig_s))
+                       r = 1;
+       }
+       //PRINT_SIG(start, d);
+       //PRINT_SIG(end, (d + s - sig_s));
+       return r;
+}
+
+/*
+ * We want these functions to be as fast as possible in case we haven't asked
+ * for verification
+ */
+void create_chunk(struct bench *prefs, struct xseg_request *req, uint64_t new)
+{
+       int verify;
+
+       verify = GET_FLAG(VERIFY, prefs->flags);
+       switch (verify) {
+               case VERIFY_NO:
+                       break;
+               case VERIFY_META:
+                       readwrite_chunk_meta(prefs, req);
+                       break;
+               case VERIFY_FULL:
+                       readwrite_chunk_full(prefs, req);
+                       break;
+               default:
+                       XSEGLOG2(&lc, W, "Unexpected verification mode: %d\n",
+                                       verify);
+       }
+}
+
+int read_chunk(struct bench *prefs, struct xseg_request *req)
+{
+       struct xseg *xseg = prefs->peer->xseg;
+       struct object_vars *obv = prefs->objvars;
+       char *target;
+       int verify;
+       int r = 0;
+
+       verify = GET_FLAG(VERIFY, prefs->flags);
+       switch (verify) {
+               case VERIFY_NO:
+                       break;
+               case VERIFY_META:
+                       target = xseg_get_target(xseg, req);
+                       obv->objnum = __get_object_from_name(obv, target);
+                       r = readwrite_chunk_meta(prefs, req);
+                       break;
+               case VERIFY_FULL:
+                       target = xseg_get_target(xseg, req);
+                       obv->objnum = __get_object_from_name(obv, target);
+                       r = readwrite_chunk_full(prefs, req);
+                       break;
+               default:
+                       XSEGLOG2(&lc, W, "Unexpected verification mode: %d\n",
+                                       verify);
+       }
+       return r;
+}
+