#include <cassert>
#include <cerrno>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <unistd.h>
#include "benchmark.hpp"
#include "libpmemobj.h"
#include "util.h"
#define FACTOR 3
#define ALLOC_MIN_SIZE 64
#define OOB_HEADER_SIZE 64
#define CONST_B 0xFF
struct prog_args {
size_t minsize;
bool use_random_size;
bool no_warmup;
unsigned seed;
};
struct obj_bench {
PMEMobjpool *pop;
struct prog_args *pa;
PMEMoid *oids;
void **ptrs;
uint64_t nobjs;
size_t obj_size;
int const_b;
};
static int
init_objects(struct obj_bench *ob)
{
assert(ob->nobjs != 0);
ob->oids = (PMEMoid *)malloc(ob->nobjs * sizeof(*ob->oids));
if (!ob->oids) {
perror("malloc");
return -1;
}
ob->ptrs = (void **)malloc(ob->nobjs * sizeof(*ob->ptrs));
if (!ob->ptrs) {
perror("malloc");
goto err_malloc;
}
for (uint64_t i = 0; i < ob->nobjs; i++) {
PMEMoid oid;
void *ptr;
if (pmemobj_alloc(ob->pop, &oid, ob->obj_size, 0, NULL, NULL)) {
perror("pmemobj_alloc");
goto err_palloc;
}
ptr = pmemobj_direct(oid);
if (!ptr) {
perror("pmemobj_direct");
goto err_palloc;
}
ob->oids[i] = oid;
ob->ptrs[i] = ptr;
}
return 0;
err_palloc:
free(ob->ptrs);
err_malloc:
free(ob->oids);
return -1;
}
static void
do_warmup(struct obj_bench *ob)
{
for (uint64_t i = 0; i < ob->nobjs; ++i) {
memset(ob->ptrs[i], 0, ob->obj_size);
pmemobj_persist(ob->pop, ob->ptrs[i], ob->obj_size);
}
}
static int
obj_persist_op(struct benchmark *bench, struct operation_info *info)
{
struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench);
uint64_t idx = info->worker->index * info->args->n_ops_per_thread +
info->index;
assert(idx < ob->nobjs);
void *ptr = ob->ptrs[idx];
memset(ptr, ob->const_b, ob->obj_size);
pmemobj_persist(ob->pop, ptr, ob->obj_size);
return 0;
}
static int
obj_persist_init(struct benchmark *bench, struct benchmark_args *args)
{
assert(bench != NULL);
assert(args != NULL);
assert(args->opts != NULL);
struct prog_args *pa = (struct prog_args *)args->opts;
size_t poolsize;
if (pa->minsize >= args->dsize) {
fprintf(stderr, "Wrong params - allocation size\n");
return -1;
}
struct obj_bench *ob =
(struct obj_bench *)malloc(sizeof(struct obj_bench));
if (ob == NULL) {
perror("malloc");
return -1;
}
pmembench_set_priv(bench, ob);
ob->pa = pa;
ob->const_b = CONST_B;
ob->nobjs = args->n_ops_per_thread * args->n_threads;
ob->obj_size = args->dsize;
if (ob->obj_size < ALLOC_MIN_SIZE)
ob->obj_size = ALLOC_MIN_SIZE;
poolsize = ob->nobjs * (ob->obj_size + OOB_HEADER_SIZE);
poolsize = poolsize * FACTOR;
if (args->is_poolset) {
if (args->fsize < poolsize) {
fprintf(stderr, "insufficient size of poolset\n");
goto free_ob;
}
poolsize = 0;
} else {
if (poolsize < PMEMOBJ_MIN_POOL)
poolsize = PMEMOBJ_MIN_POOL;
}
poolsize = PAGE_ALIGNED_UP_SIZE(poolsize);
ob->pop = pmemobj_create(args->fname, NULL, poolsize, args->fmode);
if (ob->pop == NULL) {
fprintf(stderr, "%s\n", pmemobj_errormsg());
goto free_ob;
}
if (init_objects(ob)) {
goto free_pop;
}
if (!ob->pa->no_warmup) {
do_warmup(ob);
}
return 0;
free_pop:
pmemobj_close(ob->pop);
free_ob:
free(ob);
return -1;
}
static int
obj_persist_exit(struct benchmark *bench, struct benchmark_args *args)
{
struct obj_bench *ob = (struct obj_bench *)pmembench_get_priv(bench);
for (uint64_t i = 0; i < ob->nobjs; ++i) {
pmemobj_free(&ob->oids[i]);
}
pmemobj_close(ob->pop);
free(ob->oids);
free(ob->ptrs);
free(ob);
return 0;
}
static struct benchmark_clo obj_persist_clo[1];
static struct benchmark_info obj_persist_info;
CONSTRUCTOR(pmemobj_persist_costructor)
void
pmemobj_persist_costructor(void)
{
obj_persist_clo[0].opt_short = 'w';
obj_persist_clo[0].opt_long = "no-warmup";
obj_persist_clo[0].descr = "Don't do warmup";
obj_persist_clo[0].def = "false";
obj_persist_clo[0].type = CLO_TYPE_FLAG;
obj_persist_clo[0].off = clo_field_offset(struct prog_args, no_warmup);
obj_persist_info.name = "pmemobj_persist";
obj_persist_info.brief = "Benchmark for pmemobj_persist() "
"operation";
obj_persist_info.init = obj_persist_init;
obj_persist_info.exit = obj_persist_exit;
obj_persist_info.multithread = true;
obj_persist_info.multiops = true;
obj_persist_info.operation = obj_persist_op;
obj_persist_info.measure_time = true;
obj_persist_info.clos = obj_persist_clo;
obj_persist_info.nclos = ARRAY_SIZE(obj_persist_clo);
obj_persist_info.opts_size = sizeof(struct prog_args);
obj_persist_info.rm_file = true;
obj_persist_info.allow_poolset = true;
REGISTER_BENCHMARK(obj_persist_info);
};