struct timespec delay = {0, 4000000};
-/******************************\
- * Static miscellaneous tools *
-\******************************/
-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)
-{
- return atol(name + IDLEN + 1); /* cut the "bench-908135-" part*/
-}
-
-static inline uint64_t __get_object(struct bench *prefs, uint64_t new)
+uint64_t __get_object(struct bench *prefs, uint64_t new)
{
if (prefs->ts > 0)
new = new / (prefs->os / prefs->bs);
return 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;
return -1;
}
+int validate_seed(struct bench *prefs, unsigned long seed)
+{
+ if (seed < pow(10, prefs->objvars->seedlen))
+ return 0;
+ return -1;
+}
+
/*******************\
* Print functions *
\*******************/
* Benchmarking functions *
\**************************/
-void create_id(unsigned long seed)
-{
- if (seed >= pow(10, 9))
- XSEGLOG2(&lc, W, "Seed larger than 10^9, only its first 9 digits will "
- "be used\n");
-
- //nanoseconds can't be more than 9 digits
- snprintf(global_id, IDLEN + 1, "bench-%09lu", seed);
-}
-
-void create_target(struct bench *prefs, struct xseg_request *req,
- uint64_t new)
+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;
- char buf[TARGETLEN + 1];
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(buf, TARGETLEN + 1, "%s-%016lu", global_id, new);
- strncpy(req_target, buf, TARGETLEN);
- XSEGLOG2(&lc, D, "Target name of request is %s\n", buf);
+ /*
+ * 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)
* **************************************************
* 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 reeadwrite_chunk_meta, which expects to write in a memory at least this
+ * by readwrite_chunk_meta, which expects to write in a memory at least this
* big.
*
* **************************************************
* 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;
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;
}
*/
#define _GNU_SOURCE
+#include <xseg/xseg.h>
#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 <bench-xseg.h>
#include <bench-lfsr.h>
#include <limits.h>
+#include <math.h>
-char global_id[IDLEN + 1];
/*
* This macro checks two things:
* a) If in-flight requests are less than given iodepth
" --seed | None | Initialize LFSR and target names\n"
" --insanity| sane | Adjust insanity level of benchmark:\n"
" | | [sane|eccentric|manic|paranoid]\n"
- " --progress| yes | Show progress of requests\n"
+ " --progress| yes | Show progress of requests [yes|no]\n"
" --ping | yes | Ping target before starting benchmark\n"
+ " | | [yes|no]\n"
+ " --prefix | 'bench' | Add a common prefix to all object names\n"
+ " --objname | 'bench' | Use only one object with this name\n"
"\n"
"Additional information:\n"
" --------------------------------------------\n"
- " The -to and -ts options are mutually exclusive\n"
+ " * The -to and -ts options are mutually exclusive\n"
+ "\n"
+ " * The object name is always not null-terminated and\n"
+ " defaults to the following structure:\n"
+ " <prefix>-<seed>-<object number>\n"
+ "\n"
+ " where:\n"
+ " a. <prefix> is given by user or defaults to 'bench'\n"
+ " b. <seed> is given by user or defaults to a random value.\n"
+ " Its length will be 9 digits, with trailing zeros where\n"
+ " necessary\n"
+ " c. <object number> is out of the user's control. It is\n"
+ " calculated during the benchmark and is a 15-digit\n"
+ " number, allowing a maximum of 1 quadrillion objects\n"
+ "\n"
+ " So, if bench is called with the arguments:\n"
+ " --prefix obj --seed 999\n"
+ "\n"
+ " and <object number> is 9,the resulting object name will\n"
+ " be:\n"
+ " obj-000000999-000000000000009\n"
+ "\n"
+ " * The above object name structure can by bypassed with the\n"
+ " --objname <object name> argument. This implies the\n"
+ " following:\n"
+ "\n"
+ " a. --pattern argument defaults to 'seq'\n"
+ " b. --verify argument defaults to 'no'\n"
+ " c. -to argument defaults to 1\n"
+ " d. -ts argument defaults to (and can't be larger than)\n"
+ " the object size (-os argument)\n"
+ " e. --seed and --prefix arguments are not only unnecessary,\n"
+ " but will also produce an error to alert the user\n"
"\n");
}
char verify[MAX_ARG_LEN + 1];
char progress[MAX_ARG_LEN + 1];
char ping[MAX_ARG_LEN + 1];
+ char prefix[XSEG_MAX_TARGETLEN + 1];
+ char objname[XSEG_MAX_TARGETLEN + 1];
struct xseg *xseg = peer->xseg;
+ struct object_vars *obv;
unsigned int xseg_page_size = 1 << xseg->config.page_shift;
long iodepth = -1;
long dst_port = -1;
unsigned long seed = -1;
+ unsigned long seed_max;
uint64_t rc;
- struct timespec timer_seed;
struct timespec *ts;
- int set_by_hand = 0;
- int i, r;
+ int set_by_hand = 1;
+ int j, r;
op[0] = 0;
pattern[0] = 0;
request_cap[0] = 0;
progress[0] = 0;
ping[0] = 0;
+ prefix[0] = 0;
+ objname[0] = 0;
+ /* allocate struct bench */
prefs = malloc(sizeof(struct bench));
if (!prefs) {
perror("malloc");
}
memset(prefs, 0, sizeof(struct bench));
+ /* allocate struct req_status */
prefs->status = malloc(sizeof(struct req_status));
if (!prefs->status) {
perror("malloc");
}
memset(prefs->status, 0, sizeof(struct req_status));
- for (i = 0; i < peer->nr_ops; i++) {
+ /* allocate struct object_name */
+ prefs->objvars = malloc(sizeof(struct object_vars));
+ if (!prefs->objvars) {
+ perror("malloc");
+ goto object_name_fail;
+ }
+ memset(prefs->objvars, 0, sizeof(struct object_vars));
+
+ /* allocate a struct timespec for each peer request */
+ for (j = 0; j < peer->nr_ops; j++) {
ts = malloc(sizeof(struct timespec));
if (!ts) {
perror("malloc");
goto priv_fail;
}
- peer->peer_reqs[i].priv = ts;
+ peer->peer_reqs[j].priv = ts;
}
//Begin reading the benchmark-specific arguments
READ_ARG_STRING("--verify", verify, MAX_ARG_LEN);
READ_ARG_STRING("--progress", progress, MAX_ARG_LEN);
READ_ARG_STRING("--ping", ping, MAX_ARG_LEN);
+ READ_ARG_STRING("--prefix", prefix, XSEG_MAX_TARGETLEN);
+ READ_ARG_STRING("--objname", objname, XSEG_MAX_TARGETLEN);
END_READ_ARGS();
+ /********************************\
+ * Check object name parameters *
+ \********************************/
+ if (objname[0] && prefix[0]) {
+ XSEGLOG2(&lc, E, "--objname and --prefix options cannot be"
+ "used together.");
+ goto arg_fail;
+ }
+
+ obv = prefs->objvars;
+ obv->seedlen = SEEDLEN;
+ obv->objnumlen = OBJNUMLEN;
+ if (objname[0]) {
+ /* TODO: Fill restrictions here */
+ strncpy(obv->name, objname, XSEG_MAX_TARGETLEN);
+ obv->prefixlen = 0;
+ obv->namelen = strlen(objname);
+ } else {
+ if (!prefix[0]) /* In this case we use a default value */
+ strcpy(prefix, "bench");
+ strncpy(obv->prefix, prefix, XSEG_MAX_TARGETLEN);
+ obv->prefixlen = strlen(prefix);
+ /* We add 2 for the extra dashes */
+ obv->namelen = obv->prefixlen + obv->seedlen +
+ obv->objnumlen + 2;
+ }
+
+ /* Only --prefix can exceed bounds since --objname is bounded */
+ if (obv->namelen > XSEG_MAX_TARGETLEN) {
+ XSEGLOG2(&lc, E, "--prefix %s: Prefix is too long.", prefix);
+ goto arg_fail;
+ }
+
/*****************************\
* Check I/O type parameters *
\*****************************/
goto arg_fail;
}
+ if (prefs->status->max == 1)
+ SET_FLAG(PATTERN, prefs->flags, PATTERN_SEQ);
+
//Object size (os): Defaults to 4M.
//Must have the same format as "block size"
//Must be integer multiple of "block size"
if (init_timer(&prefs->rec_tm, INSANITY_ECCENTRIC))
goto tm_fail;
- /*************************************\
- * Initialize the LFSR and global_id *
- \*************************************/
-reseed:
- //We proceed to initialise the global_id, and seed variables.
+ /***********************\
+ * Initialize the LFSR *
+ \***********************/
+
+ seed_max = pow(10, obv->seedlen + 1) - 1;
if (seed == -1) {
- clock_gettime(CLOCK_BENCH, &timer_seed);
- seed = timer_seed.tv_nsec;
- } else {
- set_by_hand = 1;
+ srand(time(NULL));
+ set_by_hand = 0;
+ } else if (validate_seed(prefs, seed)) {
+ XSEGLOG2(&lc, E, "--seed %lu: Seed larger than %lu. Only its "
+ "first %d digits will be used",
+ seed, seed_max, obv->seedlen);
+ goto arg_fail;
}
- create_id(seed);
- if (prefs->status->max == 1)
- SET_FLAG(PATTERN, prefs->flags, PATTERN_SEQ);
+reseed:
+ if (!set_by_hand)
+ seed = rand() % seed_max + 1;
if (GET_FLAG(PATTERN, prefs->flags) == PATTERN_RAND) {
prefs->lfsr = malloc(sizeof(struct bench_lfsr));
goto lfsr_fail;
}
- r = lfsr_init(prefs->lfsr, prefs->status->max, seed, seed & 0xF);
- if (r && set_by_hand) {
+ r = lfsr_init(prefs->lfsr, prefs->status->max,
+ seed, seed & 0xF);
+ if (r) {
+ if (!set_by_hand) {
+ free(prefs->lfsr);
+ goto reseed;
+ }
XSEGLOG2(&lc, E, "LFSR could not be initialized.\n");
goto lfsr_fail;
- } else if (r) {
- seed = -1;
- goto reseed;
}
}
+ obv->seed = seed;
/*********************************\
* Miscellaneous initializations *
prefs->peer = peer;
peer->peerd_loop = bench_peerd_loop;
peer->priv = (void *) prefs;
- XSEGLOG2(&lc, I, "Global ID is %s\n", global_id);
+
+ if (obv->prefixlen)
+ XSEGLOG2(&lc, I, "Seed is %u, prefix is %s",
+ obv->seed, obv->prefix);
+ else
+ XSEGLOG2(&lc, I, "Seed is %u, object name is %s",
+ obv->seed, obv->name);
+
return 0;
arg_fail:
free(prefs->get_tm);
free(prefs->rec_tm);
priv_fail:
- for (; i >= 0; i--) {
- free(peer->peer_reqs[i].priv);
+ for (; j >= 0; j--) {
+ free(peer->peer_reqs[j].priv);
}
+object_name_fail:
+ free(prefs->objvars);
status_fail:
free(prefs->status);
prefs_fail:
struct xseg_request *req;
struct xseg *xseg = peer->xseg;
struct peer_req *pr;
+ struct object_vars *obv = prefs->objvars;
xport srcport = prefs->src_port;
xport dstport = prefs->dst_port;
xport p;
}
timer_stop(prefs, prefs->get_tm, NULL);
- //Allocate enough space for the data and the target's name
+ /*
+ * Allocate enough space for the data and the target's name.
+ * Also, allocate one extra byte to prevent buffer overflow due to the
+ * obligatory null termination of snprint(). This extra byte will not be
+ * counted as part of the target's name.
+ */
XSEGLOG2(&lc, D, "Prepare new request\n");
- r = xseg_prep_request(xseg, req, TARGETLEN, size);
+ r = xseg_prep_request(xseg, req, obv->namelen + 1, size);
if (r < 0) {
XSEGLOG2(&lc, W, "Cannot prepare request! (%lu, %llu)\n",
- TARGETLEN, (unsigned long long)size);
+ obv->namelen + 1, (unsigned long long)size);
goto put_xseg_request;
}
+ req->targetlen--;
//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);
+ obv->objnum = __get_object(prefs, new);
+ create_target(prefs, req);
if (prefs->op == X_WRITE || prefs->op == X_READ) {
req->size = size;
* or implied, of GRNET S.A.
*/
+#include <xseg/protocol.h>
#include <bench-lfsr.h>
-
#ifdef __GNUC__
#define LIKELY(x) __builtin_expect(!!(x),1)
#define UNLIKELY(x) __builtin_expect(!!(x),0)
(__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"}.
- * The target string (TARGETLEN) is per object, concatenated with the string
- * above and is of the following form: {"-" +16-digit number}.
+ * For now, the seed length is fixed to 9 digits whereas the object number
+ * length is fixed to fifteen digits.
*/
-#define IDLEN 15
-#define TARGETLEN (IDLEN + 1 + 16)
-extern char global_id[IDLEN + 1];
+#define SEEDLEN 9
+#define OBJNUMLEN 15
struct bench {
uint64_t to; //Total number of objects (not for read/write)
struct peerd *peer;
struct req_status *status;
struct bench_lfsr *lfsr;
+ struct object_vars *objvars;
struct timer *total_tm; //Total time for benchmark
struct timer *get_tm; //Time for xseg_get_request
struct timer *sub_tm; //Time for xseg_submit_request
struct timer *rec_tm; //Time for xseg_receive_request
};
+struct object_vars {
+ char name[XSEG_MAX_TARGETLEN];
+ int namelen;
+ char prefix[XSEG_MAX_TARGETLEN];
+ int prefixlen;
+ uint64_t seed;
+ int seedlen; /* seed length is hardcoded for now*/
+ uint64_t objnum;
+ int objnumlen; /* object number length is hardcoded for now*/
+};
+
struct req_status {
uint64_t max; /* Max requests for benchmark */
uint64_t submitted;
void print_stats(struct bench *prefs);
void print_progress(struct bench *prefs);
void print_remaining(struct bench *prefs);
-void create_target(struct bench *prefs, struct xseg_request *req,
- uint64_t new);
+void create_target(struct bench *prefs, struct xseg_request *req);
void create_chunk(struct bench *prefs, struct xseg_request *req, uint64_t new);
int read_chunk(struct bench *prefs, struct xseg_request *req);
uint64_t determine_next(struct bench *prefs);
uint64_t calculate_offset(struct bench *prefs, uint64_t new);
uint64_t calculate_prog_quantum(struct bench *prefs);
-void create_id(unsigned long seed);
+int validate_seed(struct bench *prefs, unsigned long seed);
+
+void inspect_obv(struct object_vars *obv);
+uint64_t __get_object(struct bench *prefs, uint64_t new);