#include <math.h>
#include <string.h>
-#define PRINT_SIG(__who, __sig) \
- printf("%s (%lu): id %lu, object %lu, offset %lu\n", \
- #__who, (uint64_t)(__sig), \
- ((struct signature *)__sig)->id, \
- ((struct signature *)__sig)->object, \
+#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);
-/******************************\
- * Static miscellaneous tools *
-\******************************/
struct timespec delay = {0, 4000000};
-static inline uint64_t _get_id()
+__attribute__ ((unused))
+void inspect_obv(struct object_vars *obv)
{
- return atol(global_id + 6); /* cut the "bench-" part*/
+ 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 inline uint64_t _get_object_from_name(char *name)
+uint64_t __get_object(struct bench *prefs, uint64_t new)
{
- return atol(name + IDLEN); /* cut the "bench-908135-" part*/
+ if (prefs->ts > 0)
+ new = new / (prefs->os / prefs->bs);
+ return new;
}
-static inline 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)
{
- if (prefs->to < 0)
- new = new / (prefs->os / prefs->bs);
- return new;
+ /* 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)
+static inline int __snap_to_bound8(uint64_t space)
{
return space > 8 ? 8 : space;
}
-static inline double timespec2double(struct timespec num)
+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,
+static inline void __write_sig(struct bench_lfsr *sg, uint64_t *d, uint64_t s,
int pos)
{
uint64_t i;
/* 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));
+ 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,
+static inline int __read_sig(struct bench_lfsr *sg, uint64_t *d, uint64_t s,
int pos)
{
uint64_t i;
/* 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)))
+ 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)
+static struct tm_result __separate_by_order(double num)
{
struct tm_result res;
return res;
}
+static void __calculate_bw(struct bench *prefs, double iops, struct bw *bw)
+{
+ bw->val = iops * prefs->bs;
+ strcpy(bw->unit, "B/s");
+
+ if (bw->val < 1024)
+ return;
+
+ bw->val = bw->val / 1024;
+ strcpy(bw->unit, "KB/s");
+
+ if (bw->val < 1024)
+ return;
+
+ bw->val = bw->val / 1024;
+ strcpy(bw->unit, "MB/s");
+
+ if (bw->val < 1024)
+ return;
+
+ bw->val = bw->val / 1024;
+ strcpy(bw->unit, "GB/s");
+}
+
+static double __calculate_iops(struct bench *prefs, double elapsed_ns)
+{
+ /* elapsed_ns is in nanoseconds, so we convert it to seconds */
+ double elapsed = elapsed_ns / pow(10,9);
+ return (prefs->status->received / elapsed);
+}
+
/******************************\
* Argument-parsing functions *
\******************************/
return -1;
}
+int read_progress(char *progress)
+{
+ if (strncmp(progress, "no", MAX_ARG_LEN + 1) == 0)
+ return PROGRESS_NO;
+ if (strncmp(progress, "yes", MAX_ARG_LEN + 1) == 0)
+ return PROGRESS_YES;
+ return -1;
+}
+
+int read_ping(char *ping)
+{
+ if (strncmp(ping, "no", MAX_ARG_LEN + 1) == 0)
+ return PING_MODE_OFF;
+ if (strncmp(ping, "yes", MAX_ARG_LEN + 1) == 0)
+ return PING_MODE_ON;
+ return -1;
+}
+
int read_pattern(char *pattern)
{
if (strncmp(pattern, "seq", MAX_ARG_LEN + 1) == 0)
return -1;
}
+int validate_seed(struct bench *prefs, unsigned long seed)
+{
+ if (seed < pow(10, prefs->objvars->seedlen))
+ return 0;
+ return -1;
+}
+
/*******************\
* Print functions *
\*******************/
-void print_stats(struct bench *prefs)
+void print_io_stats(struct bench *prefs, double elapsed)
{
- uint64_t remaining;
+ struct bw bw;
+ double iops;
+
+ /*
+ * We could malloc struct bw in __calculate_bw, but it's safer in cases when
+ * there is no memory left.
+ */
+ iops = __calculate_iops(prefs, elapsed);
+ __calculate_bw(prefs, iops, &bw);
+
+ fprintf(stdout, " ~~~~~~~~~~~~~~~~~~~~~~~~\n");
+ 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);
+}
- printf("\n");
- 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);
+void print_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))
- printf("Requests corrupted: %10lu\n", prefs->status->corrupted);
- printf("\n");
+ fprintf(stdout, "Requests corrupted: %10lu\n", prefs->status->corrupted);
+ fprintf(stdout, "\n");
+ fflush(stdout);
+}
+
+void print_remaining(struct bench *prefs)
+{
+ uint64_t remaining;
remaining = prefs->status->max - prefs->status->received;
if (remaining)
- printf("Requests remaining: %10lu\n", remaining);
+ fprintf(stdout, "Requests remaining: %10lu\n", remaining);
else
- printf("All requests have been served.\n");
+ fprintf(stdout, "All requests have been served.\n");
+ fflush(stdout);
}
-void print_res(struct bench *prefs, struct timer *tm, char *type)
+void print_res(struct bench *prefs)
{
- struct tm_result res;
- double sum;
-
- sum = timespec2double(tm->sum);
- res = separate_by_order(sum);
-
- printf("\n");
- printf(" %s\n", type);
- printf(" ========================\n");
- printf(" |-s-||-ms-|-us-|-ns-|\n");
- printf("Total time: %3u. %03u %03u %03u\n",
+ struct timer *tm;
+ struct tm_result res, res_rec;
+ double sum, sum_rec;
+
+ /* */
+ tm = prefs->total_tm;
+ 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);
- if (!prefs->status->received)
+ if (!prefs->status->received) {
+ fflush(stdout);
return;
+ }
- res = separate_by_order(sum / prefs->status->received);
+ tm = prefs->rec_tm;
+ if (GET_FLAG(INSANITY, prefs->flags) < tm->insanity)
+ goto flush;
- printf("Mean Time: %3u. %03u %03u %03u\n",
- res.s, res.ms, res.us, res.ns);
+ sum_rec = __timespec2double(tm->sum);
+ res_rec = __separate_by_order(sum_rec / prefs->status->received);
- //TODO: Add std
-}
+ fprintf(stdout, "Avg. latency: %3u. %03u %03u %03u\n",
+ res_rec.s, res_rec.ms, res_rec.us, res_rec.ns);
-/**************************\
- * Benchmarking functions *
-\**************************/
+flush:
+ print_io_stats(prefs, sum);
+ fflush(stdout);
+}
-void create_id(unsigned long seed)
+void print_progress(struct bench *prefs)
{
- if (seed > pow(10, 9))
- XSEGLOG2(&lc, W, "Seed larger than 10^9, only its first 9 digits will "
- "be used\n");
+ int lines = 6;
- //nanoseconds can't be more than 9 digits
- snprintf(global_id, IDLEN, "bench-%09lu", seed);
+ if ((prefs->op == X_READ) && (GET_FLAG(VERIFY, prefs->flags) != VERIFY_NO))
+ lines++;
+
+ fprintf(stdout, "\033[%dA\033[J", lines);
+ print_stats(prefs);
}
-void create_target(struct bench *prefs, struct xseg_request *req,
- uint64_t new)
+/**************************\
+ * Benchmarking functions *
+\**************************/
+
+void create_target(struct bench *prefs, struct xseg_request *req)
{
struct xseg *xseg = prefs->peer->xseg;
+ struct object_vars *obv = prefs->objvars;
char *req_target;
req_target = xseg_get_target(xseg, req);
- //For read/write, the target object may not correspond to `new`, which is
- //actually the chunk number.
- new = _get_object(prefs, new);
- snprintf(req_target, TARGETLEN, "%s-%016lu", global_id, new);
+ /*
+ * For read/write, the target object may not correspond to `new`, which
+ * is actually the chunk number.
+ * Also, we use one extra byte while writting the target's name to store
+ * the null character and not overflow, but this will not be part of the
+ * target's name
+ */
+ if (obv->prefix[0]) {
+ snprintf(req_target, obv->namelen + 1, "%s-%0*lu-%0*lu",
+ obv->prefix, obv->seedlen, obv->seed,
+ obv->objnumlen, obv->objnum);
+ } else {
+ strncpy(req_target, obv->name, obv->namelen);
+ }
XSEGLOG2(&lc, D, "Target name of request is %s\n", req_target);
}
-
uint64_t determine_next(struct bench *prefs)
{
if (GET_FLAG(PATTERN, prefs->flags) == PATTERN_SEQ)
uint64_t calculate_offset(struct bench *prefs, uint64_t new)
{
- if (prefs->to < 0)
+ if (prefs->ts > 0)
return (new * prefs->bs) % prefs->os;
else
return 0;
}
+uint64_t calculate_prog_quantum(struct bench *prefs)
+{
+ return round((double)prefs->status->max / 20.0);
+}
+
+
/*
* ***********************************************
* `create_chunk` handles 3 identifiers:
* 3. The chunk offset in the object
*
* ************************************************
- * `_create_chunk_full` takes the above 3 identifiers and feeds them as seeds
+ * `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:
*
* **************************************************
* 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 _create_chunk_meta, which expects to write in a memory at least this big.
+ * 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 xseg *xseg, struct xseg_request *req,
- uint64_t id, uint64_t object)
+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, 0x7FFFFFFF, id, 0);
- lfsr_init(&obj_lfsr, 0x7FFFFFFF, object, 0);
- lfsr_init(&off_lfsr, 0x7FFFFFFF, req->offset, 0);
+ 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);
*/
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);
+ __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))
+ if (__read_sig(&id_lfsr, d, s, 0))
return 1;
- if (read_sig(&obj_lfsr, d, s, 1))
+ if (__read_sig(&obj_lfsr, d, s, 1))
return 1;
- if(read_sig(&off_lfsr, d, s, 2))
+ if(__read_sig(&off_lfsr, d, s, 2))
return 1;
}
return 0;
}
-static int _readwrite_chunk_meta(struct xseg *xseg, struct xseg_request *req,
- uint64_t id, uint64_t object)
+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;
- struct signature sig;
int sig_s = sizeof(struct signature);
int r = 0;
sig.offset = req->offset;
if (s < sig_s) {
- XSEGLOG2(&lc, E, "Too small chunk size (%lu butes). Leaving.", s);
+ XSEGLOG2(&lc, E, "Too small chunk size (%lu butes). "
+ "Leaving.", s);
return 1;
}
/*
* We want these functions to be as fast as possible in case we haven't asked
* for verification
- * TODO: Make them prettier but keep the speed of this implementation
*/
void create_chunk(struct bench *prefs, struct xseg_request *req, uint64_t new)
{
- struct xseg *xseg = prefs->peer->xseg;
- uint64_t id;
- uint64_t object;
int verify;
verify = GET_FLAG(VERIFY, prefs->flags);
case VERIFY_NO:
break;
case VERIFY_META:
- id = _get_id();
- object = _get_object(prefs, new);
- _readwrite_chunk_meta(xseg, req, id, object);
+ inspect_obv(prefs->objvars);
+ readwrite_chunk_meta(prefs, req);
break;
case VERIFY_FULL:
- id = _get_id();
- object = _get_object(prefs, new);
- _readwrite_chunk_full(xseg, req, id, object);
+ inspect_obv(prefs->objvars);
+ readwrite_chunk_full(prefs, req);
break;
default:
- XSEGLOG2(&lc, W, "Unexpected verification mode: %d\n", verify);
+ 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;
- uint64_t id;
- uint64_t object;
+ struct object_vars *obv = prefs->objvars;
char *target;
int verify;
int r = 0;
case VERIFY_NO:
break;
case VERIFY_META:
- id = _get_id();
target = xseg_get_target(xseg, req);
- object = _get_object_from_name(target);
- r = _readwrite_chunk_meta(xseg, req, id, object);
+ obv->objnum = __get_object_from_name(obv, target);
+ inspect_obv(prefs->objvars);
+ r = readwrite_chunk_meta(prefs, req);
break;
case VERIFY_FULL:
- id = _get_id();
target = xseg_get_target(xseg, req);
- object = _get_object_from_name(target);
- r = _readwrite_chunk_full(xseg, req, id, object);
+ 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);
+ XSEGLOG2(&lc, W, "Unexpected verification mode: %d\n",
+ verify);
}
return r;
}
-
-