...
 
Commits (24)
......@@ -13,7 +13,13 @@ CLEANFILES = $(bin_SCRIPTS)
MAINTAINERCLEANFILES =
EXTRA_DIST =
BUILT_SOURCES =
include_HEADERS = include/bake.h include/bake-client.h include/bake-server.h
include_HEADERS = include/bake.h\
include/bake-client.h\
include/bake-server.h\
include/bake.hpp\
include/bake-client.hpp\
include/bake-server.hpp
TESTS_ENVIRONMENT =
EXTRA_DIST += \
......
......@@ -98,9 +98,6 @@ int main(int argc, char **argv)
bake_write(bph, rid, 0, buf, size);
/* Make all modifications persistent */
bake_persist(bph, rid);
/* Get size of region */
size_t check_size;
bake_get_size(bph, rid, &check_size);
/* Release provider handle */
bake_provider_handle_release(bph);
/* Release BAKE client */
......@@ -146,7 +143,7 @@ This makes the provider manage the given storage target.
Other functions are available to remove a storage target (or all storage
targets) from a provider.
## Benchmark execution example
## Latency benchmark execution example
* `./bake-latency-bench sm:///tmp/cci/sm/carns-x1/1/1 100000 4 8`
......@@ -164,6 +161,57 @@ The second argument is the number of benchmark iterations.
The third and fourth arguments specify the range of sizes to use for read and
write operations in the benchmark.
## Generic Bake benchmark
By using `--enable-benchmark` when compiling Bake (or `+benchmark` when using Spack),
you will build a `bake-benchmark` program that can be used as a configurable benchmark.
This benchmark requires an MPI compiler, hence you may need to configure Bake with
`CC=mpicc` and `CXX=mpicxx`.
The benchmark is an MPI program that can be run on 2 or more ranks. Rank 0 will act
as a server, while non-zero ranks act as clients. The server will not create
a Bake target. The Bake target needs to be created (with `bake-makepool`) beforehand.
The program takes as parameter the path to a JSON file containing the sequence
of benchmarks to execute. An example of such a file is located in `src/benchmark.json`.
Each entry in the `benchmarks` array corresponds to a benchmark. The `type` field indicates
the type of benchmark to execute. The `repetitions` field indicates how many times the
benchmark should be repeated.
The following table describes each type of benchmark and their parameters.
| type | parameter | default | description |
|----------------------|-------------------|---------|-------------------------------------------------------------------|
| | | | |
| create | num-entries | 1 | Number of regions to create |
| | region-sizes | - | Size of the regions, or range (e.g. [12, 24]) |
| | erase-on-teardown | true | Whether to erase the created regions after the benchmark executed |
| | | | |
| write | num-entries | 1 | Number of regions to write |
| | region-sizes | - | Size of the regions, or range (e.g. [12, 24]) |
| | reuse-buffer | false | Whether to reuse the input buffer for each write |
| | reuse-region | false | Whether to write to the same region |
| | preregister-bulk | false | Whether to preregister the input buffer for RDMA |
| | erase-on-teardown | true | Whether to erase the created regions after the benchmark executed |
| | | | |
| persist | num-entries | 1 | Number of region to persist |
| | region-sizes | - | Size of the regions, or range (e.g. [12, 24]) |
| | erase-on-teardown | true | Whether to erase the created regions after the benchmark executed |
| | | | |
| read | num-entries | 1 | Number of region to read |
| | region-sizes | - | Size of the regions, or range (e.g. [12, 24]) |
| | reuse-buffer | false | Whether to reuse the same buffer for each read |
| | reuse-region | false | Whether to access the same region for each read |
| | preregister-bulk | false | Whether to preregister the client's buffer for RDMA |
| | erase-on-teardown | true | Whether to remove the regions after the benchmark |
| | | | |
| create-write-persist | num-entries | 1 | Number of regions to create/write/persist |
| | region-sizes | - | Size of the regions, or range (e.g. [12, 24]) |
| | reuse-buffer | false | Whether to reuse the same buffer on clients for each operation |
| | preregister-bulk | false | Whether to preregister the client's buffer for RDMA |
| | erase-on-teardown | true | Whether to remove the regions after the benchmark |
## Misc tips
Memory allocation seems to account for a significant portion of
......
......@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
AC_INIT([bake], [0.1], [],[],[])
AC_INIT([bake], [0.3.4], [],[],[])
AC_CONFIG_MACRO_DIR([m4])
LT_INIT
......@@ -80,11 +80,48 @@ LIBS="$UUID_LIBS $LIBS"
CPPFLAGS="$UUID_CFLAGS $CPPFLAGS"
CFLAGS="$UUID_CFLAGS $CFLAGS"
PKG_CHECK_MODULES([REMI],[remi],[],
[AC_MSG_ERROR([Could not find working remi installation!])])
LIBS="$REMI_LIBS $LIBS"
CPPFLAGS="$REMI_CFLAGS $CPPFLAGS"
CFLAGS="$REMI_CFLAGS $CFLAGS"
AC_ARG_ENABLE(remi,
[AS_HELP_STRING([--enable-remi],[Enable REMI (migration) support @<:@default=no@:>@])],
[case "${enableval}" in
yes) enable_remi="yes" ;;
no) enable_remi="no" ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-remi) ;;
esac],
[enable_remi="no"]
)
AM_CONDITIONAL(ENABLE_REMI, test x$enable_remi = xyes)
if test "$enable_remi" = "yes"; then
PKG_CHECK_MODULES(REMI, remi)
AC_DEFINE(USE_REMI, 1, [REMI support enabled.])
USE_REMI=1
LIBS="$REMI_LIBS $LIBS"
CPPFLAGS="$REMI_CFLAGS $CPPFLAGS"
CFLAGS="$REMI_CFLAGS $CFLAGS"
REMI_PKG="remi"
else
USE_REMI=0
REMI_PKG=""
fi
AC_SUBST(USE_REMI)
AC_SUBST(REMI_PKG)
AC_ARG_ENABLE(benchmark,
[AS_HELP_STRING([--enable-benchmark],[Build Bake benchmark @<:@default=no@:>@])],
[case "${enableval}" in
yes) enable_benchmark="yes" ;;
no) enable_benchmark="no" ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-benchmark) ;;
esac],
[enable_benchmark="no"]
)
AM_CONDITIONAL(BUILD_BENCHMARK, test x$enable_benchmark = xyes)
if [test "$enable_benchmark" = "yes"]; then
PKG_CHECK_MODULES(JSONCPP, jsoncpp)
LIBS="$JSONCPP_LIBS $LIBS"
CPPFLAGS="$JSONCPP_CFLAGS $CPPFLAGS"
CFLAGS="$JSONCPP_CFLAGS $CFLAGS"
fi
AC_ARG_ENABLE([sizecheck],
AS_HELP_STRING([--enable-sizecheck], [Adds a header in regions to keep track of region sizes (may degrade performance) @<:@default=no@:>@]),
......
This diff is collapsed.
......@@ -53,6 +53,16 @@ int bake_provider_register(
ABT_pool pool,
bake_provider_t* provider);
/**
* @brief Deregisters and destroys the provider.
*
* @param provider Provider to deregister and destroy.
*
* @return 0 on success, -1 otherwise.
*/
int bake_provider_destroy(
bake_provider_t provider);
/**
* Makes the provider start managing a target.
* The target must have been previously created with bake_makepool,
......@@ -119,39 +129,24 @@ int bake_provider_list_storage_targets(
bake_provider_t provider,
bake_target_id_t* targets);
/**
* @brief Sets the size and number of intermediate buffers used for transfering data.
* The size is set to 0 by default. A size of 0 indicates that RDMA will be
* done all at once and target the backend device directly without using an
* intermediate buffer.
*
* @param provider Bake provider
* @param target_id Target for which to change the buffer size.
* @param count Number of buffers to initialize.
* @param size Size of the buffer.
*
* @return 0 on success, -1 on failure
/* TODO: the following configuration management functions would ideally be
* split off into a dedicated component. Treating this as a prototype for
* now.
*/
int bake_provider_set_target_xfer_buffer(
bake_provider_t provider,
bake_target_id_t target_id,
size_t count,
size_t size);
/**
* @brief Sets the maximum number of ULTs that will be used to concurrently
* transfer data.
* @brief Set configuration parameters as string key/value pairs
*
* @param provider Bake provider
* @param target_id Target for which to change the number of ULTs
* @param num_threads Number of ULTs
* @param key Configuration key
* @param value Configuratiion value
*
* @return 0 on success, -1 on failure
*/
int bake_provider_set_target_xfer_concurrency(
int bake_provider_set_conf(
bake_provider_t provider,
bake_target_id_t target_id,
uint32_t num_threads);
const char *key,
const char *value);
#ifdef __cplusplus
}
......
/*
* (C) 2019 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#ifndef __BAKE_SERVER_HPP
#define __BAKE_SERVER_HPP
#include <string>
#include <vector>
#include <bake.hpp>
#include <bake-server.h>
#define _CHECK_RET(__ret) \
if(__ret != BAKE_SUCCESS) throw exception(__ret)
namespace bake {
/**
* @brief Creates a pool at a given path, with a given size and mode.
*
* @param pool_name Pool name.
* @param pool_size Pool size.
* @param pool_mode Mode.
*/
inline void makepool(
const std::string& pool_name,
size_t pool_size,
mode_t pool_mode) {
int ret = bake_makepool(pool_name.c_str(), pool_size, pool_mode);
_CHECK_RET(ret);
}
/**
* @brief The provider class is the C++ equivalent to a bake_provider_t.
*/
class provider {
margo_instance_id m_mid = MARGO_INSTANCE_NULL;
bake_provider_t m_provider = NULL;
provider(
margo_instance_id mid,
uint16_t provider_id = 0,
ABT_pool pool = ABT_POOL_NULL)
: m_mid(mid) {
int ret = bake_provider_register(mid, provider_id, pool, &m_provider);
_CHECK_RET(ret);
}
static void finalize_callback(void* args) {
auto* p = static_cast<provider*>(args);
delete p;
}
public:
/**
* @brief Factory method to create an instance of provider.
*
* @param mid Margo instance id.
* @param provider_id Provider id.
* @param pool Argobots pool.
*
* @return Pointer to newly created provider.
*/
static provider* create(margo_instance_id mid,
uint16_t provider_id = 0,
ABT_pool pool = BAKE_ABT_POOL_DEFAULT) {
auto p = new provider(mid, provider_id, pool);
margo_provider_push_finalize_callback(mid, p, &finalize_callback, p);
return p;
}
/**
* @brief Deleted copy constructor.
*/
provider(const provider&) = delete;
/**
* @brief Deleted move constructor.
*/
provider(provider&& other) = delete;
/**
* @brief Deleted copy-assignment operator.
*/
provider& operator=(const provider&) = delete;
/**
* @brief Deleted move-assignment operator.
*/
provider& operator=(provider&& other) = delete;
/**
* @brief Destructor.
*/
~provider() {
margo_provider_pop_finalize_callback(m_mid, this);
bake_provider_destroy(m_provider);
}
/**
* @brief Adds a storage target to the provider.
* The target must have been created beforehand.
*
* @param target_name Path to the target.
*
* @return a target object.
*/
target add_storage_target(const std::string& target_name) {
target t;
int ret = bake_provider_add_storage_target(
m_provider,
target_name.c_str(),
&(t.m_tid));
_CHECK_RET(ret);
return t;
}
/**
* @brief Removes the storage target from the provider.
* This does not removes the storage target from the device, it
* simply makes it unaccessible through this provider.
*
* @param t target to remove.
*/
void remove_storage_target(const target& t) {
int ret = bake_provider_remove_storage_target(m_provider, t.m_tid);
_CHECK_RET(ret);
}
/**
* @brief Removes all the storage targets managed by the provider.
*/
void remove_all_storage_targets() {
int ret = bake_provider_remove_all_storage_targets(m_provider);
_CHECK_RET(ret);
}
/**
* @brief Count the number of storage targets managed by the provider.
*
* @return number of storage targets.
*/
uint64_t count_storage_targets() const {
uint64_t count;
int ret = bake_provider_count_storage_targets(m_provider, &count);
_CHECK_RET(ret);
return count;
}
/**
* @brief Lists all the storage targets managed by the provider.
*
* @return Vector of targets.
*/
std::vector<target> list_storage_targets() const {
uint64_t count = count_storage_targets();
std::vector<target> result(count);
std::vector<bake_target_id_t> tgts(count);
int ret = bake_provider_list_storage_targets(m_provider, tgts.data());
_CHECK_RET(ret);
for(unsigned i=0; i < count; i++) {
result[i].m_tid = tgts[i];
}
return result;
}
void set_config(const std::string& key, const std::string& value) {
int ret = bake_provider_set_conf(m_provider, key.c_str(), value.c_str());
_CHECK_RET(ret);
}
};
}
#undef _CHECK_RET
#endif
......@@ -38,6 +38,70 @@ typedef struct {
#define BAKE_ERR_OUT_OF_BOUNDS (-9) /* Attempting an out of bound access */
#define BAKE_ERR_REMI (-10) /* Error related to REMI */
#define BAKE_ERR_OP_UNSUPPORTED (-11) /* Operation not supported */
#define BAKE_ERR_FORBIDDEN (-12) /* Forbidden operation */
#define BAKE_ERR_END (-13) /* End of valid bake error codes */
/**
* Print bake errors in human-friendly form
*
* @param a string to print out before the error
* @param ret error code from a bake routine
*/
void bake_perror(char *s, int ret);
/**
* @brief Converts a target id into an ASCII readable string.
*
* @param tid Target id to convert into a string.
* @param str Resulting string (must be allocated to at least 37 bytes)
* @param size size of the allocated string.
*
* @return error code.
*/
int bake_target_id_to_string(bake_target_id_t tid, char* str, size_t size);
/**
* @brief Converts an ASCI readable representation of the target id into
* and actual target id.
*
* @param str Null-terminated string to read from.
* @param tid Resulting target id.
*
* @return error code.
*/
int bake_target_id_from_string(const char* str, bake_target_id_t* tid);
/**
* @brief Converts the region id into an ASCII readable representation.
*
* @param rid Region id.
* @param str Resulting string, should be preallocated wirg sufficient size.
* @param size size of the preallocated string.
*
* @return error code.
*/
int bake_region_id_to_string(bake_region_id_t rid, char* str, size_t size);
/**
* @brief Converts a string back into a region id.
*
* @param str String to convert.
* @param rid Resulting region id.
*
* @return error code.
*/
int bake_region_id_from_string(const char* str, bake_region_id_t* rid);
/**
* Convert region id into printable string for debugging purposes
*
* @param[in] str string to fill in
* @param[in] size length of string, not including terminator. If rid
* string is longer than this it will be truncated.
* @param[in] rid region_id
*/
void bake_print_dbg_region_id_t(char *str, size_t size, bake_region_id_t rid)
__attribute__((deprecated("use bake_region_id_to_string instead")));
#ifdef __cplusplus
}
......
/*
* (C) 2019 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#ifndef __BAKE_HPP
#define __BAKE_HPP
#include <exception>
#include <string>
#include <bake.h>
namespace bake {
/**
* @brief Array of error messages for bake::exception.
*/
const char* const bake_error_messages[] = {
"",
"Allocation error",
"Invalid argument",
"Mercury error",
"Argobots error",
"PMEM error",
"Unknown target",
"Unknown provider",
"Unknown region",
"Access out of bound",
"REMI error",
"Operation not supported",
"Forbidden operation"
};
class client;
class provider;
/**
* @brief target instances are equivalent to bake_target_id_t.
*/
class target {
friend class client;
friend class provider;
bake_target_id_t m_tid;
public:
/**
* @brief Constructor.
*/
target() = default;
/**
* @brief Constructor from a human-readable string.
* The string must have been obtained using target's
* std::string cast operator.
*
* @param str String representation of the target.
*/
target(const std::string& str) {
bake_target_id_from_string(str.c_str(), &m_tid);
}
/**
* @brief Copy constructor.
*/
target(const target&) = default;
/**
* @brief Move constructor.
*/
target(target&&) = default;
/**
* @brief Copy-assignment operator.
*/
target& operator=(const target&) = default;
/**
* @brief Move-assignment operator.
*/
target& operator=(target&&) = default;
/**
* @brief Destructor.
*/
~target() = default;
/**
* @brief Converts the target to a human-readable string.
*/
operator std::string() const {
char str[37];
bake_target_id_to_string(m_tid, str, 37);
return std::string(str);
}
/**
* @brief Serialization function (useful when using Thallium).
*
* @tparam A Archive type.
* @param ar Archive object.
*/
template<typename A>
void save(A& ar) const {
ar.write(&m_tid);
}
/**
* @brief Deserialization function (useful when using Thallium).
*
* @tparam A Archive type.
* @param ar Archive object.
*/
template<typename A>
void load(A& ar) {
ar.read(&m_tid);
}
};
/**
* @brief The region class is the C++ equivalent to bake_region_id_t.
*/
class region {
friend class client;
bake_region_id_t m_rid;
public:
/**
* @brief Default constructor.
*/
region() = default;
/**
* @brief Builds a region from a human-readable string representation.
*
* @param str String representation of the region.
*/
region(const std::string& str) {
bake_region_id_from_string(str.c_str(), &m_rid);
}
/**
* @brief Copy constructor.
*/
region(const region&) = default;
/**
* @brief Move constructor.
*/
region(region&&) = default;
/**
* @brief Copy-assignment operator.
*/
region& operator=(const region&) = default;
/**
* @brief Move-assignment operator.
*/
region& operator=(region&&) = default;
/**
* @brief Destructor.
*/
~region() = default;
/**
* @brief Converts the region into a human-readable string.
*
* @return Human-readable representation of the region.
*/
operator std::string() const {
char str[128];
bake_region_id_to_string(m_rid, str, 128);
return std::string(str);
}
/**
* @brief Serialization function (useful when using Thallium).
*
* @tparam A Archive type.
* @param ar Archive object.
*/
template<typename A>
void save(A& ar) const {
ar.write(&m_rid);
}
/**
* @brief Deserialization function (useful when using Thallium).
*
* @tparam A Archive type.
* @param ar Archive object.
*/
template<typename A>
void load(A& ar) {
ar.read(&m_rid);
}
};
/**
* @brief Exception thrown by Bake methods.
*/
class exception : public std::exception {
int m_error;
std::string m_msg;
public:
exception(int error)
: m_error(error) {
if(error < 0 && error > BAKE_ERR_END) {
m_msg = std::string("[BAKE] ") + bake_error_messages[-error];
} else {
m_msg = std::string("[BAKE] Unknown error code "+std::to_string(error));
}
}
const char* what() const noexcept override {
return m_msg.c_str();
}
int error() const {
return m_error;
}
};
}
#endif
......@@ -5,7 +5,7 @@ includedir=@includedir@
Name: bake-client
Description: bulk data access service, client side
Version: 0.1
Version: 0.3.4
URL: https://xgitlab.cels.anl.gov/sds/bake
Requires: margo
Libs: -L${libdir} -lbake-client
......
......@@ -5,8 +5,8 @@ includedir=@includedir@
Name: bake-server
Description: bulk data access service, server side
Version: 0.1
Version: 0.3.4
URL: https://xgitlab.cels.anl.gov/sds/bake
Requires: margo uuid libpmemobj remi
Requires: margo uuid libpmemobj @REMI_PKG@
Libs: -L${libdir} -lbake-server
Cflags: -I${includedir}
#!/bin/bash
CLIENT=(include/bake-client.h include/bake.h src/bake-client.c src/bake-mkpool.c src/util.c)
SERVER=(include/bake-server.h src/bake-rpc.h src/bake-server.c src/bake-timing.h)
echo "************** CLIENT ***************"
sloccount "${CLIENT[@]}"
echo "************** SERVER ***************"
sloccount "${SERVER[@]}"
noinst_LTLIBRARIES = \
src/libutil.la
src_libutil_la_SOURCES = \
src/util.c \
src/base64/encode.c \
src/base64/decode.c
src_libbake_client_la_SOURCES += \
src/bake-client.c
src_libbake_client_la_LIBADD = src/libutil.la
src_libbake_server_la_SOURCES += \
src/bake-server.c
src_libbake_server_la_LIBADD = src/libutil.la
src_bake_server_daemon_LDADD = src/libbake-server.la
src_bake_mkpool_LDADD = src/libbake-server.la
......@@ -12,5 +24,13 @@ bin_PROGRAMS += \
src/bake-mkpool \
src/bake-shutdown \
src/bake-copy-to \
src/bake-copy-from \
src/bake-latency-bench
src/bake-copy-from
if BUILD_BENCHMARK
src_bake_benchmark_SOURCES = src/bake-benchmark.cc
src_bake_benchmark_LDADD = src/libbake-server.la src/libbake-client.la
bin_PROGRAMS += src/bake-benchmark
#src_bake_benchmark_LDADD = ${LIBS} -lbake-client -lbake-server
endif
This diff is collapsed.
......@@ -147,8 +147,8 @@ int bake_client_finalize(bake_client_t client)
{
if(client->num_provider_handles != 0) {
fprintf(stderr,
"[BAKE] Warning: %d provider handles not released before bake_client_finalize was called\n",
client->num_provider_handles);
"[BAKE] Warning: %llu provider handles not released before bake_client_finalize was called\n",
(long long unsigned int)client->num_provider_handles);
}
free(client);
return BAKE_SUCCESS;
......
......@@ -36,6 +36,7 @@ int main(int argc, char **argv)
char* local_region;
int region_fd;
uint64_t size;
char region_str[128];
if(argc != 6)
{
......@@ -63,7 +64,7 @@ int main(int argc, char **argv)
ret = bake_client_init(mid, &bcl);
if(ret != 0)
{
fprintf(stderr, "Error: bake_client_init()\n");
bake_perror( "Error: bake_client_init()", ret);
margo_finalize(mid);
return -1;
}
......@@ -80,7 +81,7 @@ int main(int argc, char **argv)
ret = bake_provider_handle_create(bcl, svr_addr, mplex_id, &bph);
if(ret < 0)
{
fprintf(stderr, "Error: bake_provider_handle_create()\n");
bake_perror("Error: bake_provider_handle_create()", ret);
margo_addr_free(mid, svr_addr);
bake_client_finalize(bcl);
margo_finalize(mid);
......@@ -111,12 +112,15 @@ int main(int argc, char **argv)
}
close(region_fd);
bake_print_dbg_region_id_t(region_str, 127, rid);
printf("# will read bake region %s\n", region_str);
#ifdef USE_SIZECHECK_HEADERS
uint64_t check_size;
ret = bake_get_size(bph, rid, &check_size);
if(ret != 0)
{
fprintf(stderr, "Error: bake_get_size()\n");
bake_perror("Error: bake_get_size()", ret);
bake_provider_handle_release(bph);
margo_addr_free(mid, svr_addr);
bake_client_finalize(bcl);
......@@ -185,7 +189,7 @@ int main(int argc, char **argv)
margo_addr_free(mid, svr_addr);
bake_client_finalize(bcl);
margo_finalize(mid);
fprintf(stderr, "Error: bake_read()\n");
bake_perror("Error: bake_read()", ret);
return(-1);
}
......
......@@ -38,7 +38,10 @@ int main(int argc, char **argv)
char* local_region;
int region_fd;
char region_file[128];
char region_str[128];
#ifdef USE_SIZECHECK_HEADERS
uint64_t check_size;
#endif
if(argc != 5)
{
......@@ -93,7 +96,7 @@ int main(int argc, char **argv)
ret = bake_client_init(mid, &bcl);
if(ret != 0)
{
fprintf(stderr, "Error: bake_client_init()\n");
bake_perror("Error: bake_client_init()", ret);
margo_finalize(mid);
munmap(local_region, statbuf.st_size);
close(fd);
......@@ -119,7 +122,7 @@ int main(int argc, char **argv)
margo_finalize(mid);
munmap(local_region, statbuf.st_size);
close(fd);
fprintf(stderr, "Error: bake_provider_handle_create()\n");
bake_perror("Error: bake_provider_handle_create()", ret);
return(-1);
}
......@@ -132,12 +135,12 @@ int main(int argc, char **argv)
margo_finalize(mid);
munmap(local_region, statbuf.st_size);
close(fd);
fprintf(stderr, "Error: bake_probe()\n");
bake_perror( "Error: bake_probe()", ret);
return(-1);
}
if(num_targets < target_number) {
fprintf(stderr, "Error: provider has only %d storage targets\n", num_targets);
fprintf(stderr, "Error: provider has only %llu storage targets\n", (long long unsigned int)num_targets);
margo_addr_free(mid, svr_addr);
bake_client_finalize(bcl);
margo_finalize(mid);
......@@ -156,10 +159,13 @@ int main(int argc, char **argv)
margo_finalize(mid);
munmap(local_region, statbuf.st_size);
close(fd);
fprintf(stderr, "Error: bake_create()\n");
bake_perror("Error: bake_create()", ret);
return(-1);
}
bake_print_dbg_region_id_t(region_str, 127, rid);
printf("# created bake region %s\n", region_str);
/* transfer data */
ret = bake_write(
bph,
......@@ -175,7 +181,7 @@ int main(int argc, char **argv)
margo_finalize(mid);
munmap(local_region, statbuf.st_size);
close(fd);
fprintf(stderr, "Error: bake_write()\n");
bake_perror("bake_write():", ret);
return(-1);
}
......@@ -189,7 +195,7 @@ int main(int argc, char **argv)
margo_addr_free(mid, svr_addr);
bake_client_finalize(bcl);
margo_finalize(mid);
fprintf(stderr, "Error: bake_persist()\n");
bake_perror("Error: bake_persist()", ret);
return(-1);
}
......@@ -202,7 +208,7 @@ int main(int argc, char **argv)
margo_addr_free(mid, svr_addr);
bake_client_finalize(bcl);
margo_finalize(mid);
fprintf(stderr, "Error: bake_get_size()\n");
bake_perror("Error: bake_get_size()", ret);
return(-1);
}
......
/*
* (C) 2015 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#include "bake-config.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "bake-client.h"
static void bench_routine_write(bake_provider_handle_t bph, bake_target_id_t bti, int iterations, double* measurement_array, int size);
static void bench_routine_read(bake_provider_handle_t bph, int iterations, double* measurement_array, int size);
static void bench_routine_noop(bake_provider_handle_t bph, int iterations, double* measurement_array);
static void bench_routine_print(const char* op, int size, int iterations, double* measurement_array);
static int measurement_cmp(const void* a, const void *b);
static double *measurement_array = NULL;
static bake_region_id_t rid;
int main(int argc, char **argv)
{
int i;
char cli_addr_prefix[64] = {0};
char *svr_addr_str;
hg_addr_t svr_addr;
margo_instance_id mid;
bake_client_t bcl;
bake_provider_handle_t bph;
uint64_t num_targets;
bake_target_id_t bti;
uint8_t mplex_id;
hg_return_t hret;
int ret;
int min_size, max_size, iterations, cur_size;
if(argc != 6)
{
fprintf(stderr, "Usage: bake-latency-bench <server addr> <mplex id> <iterations> <min_sz> <max_sz>\n");
fprintf(stderr, " Example: ./bake-latency-bench tcp://localhost:1234 3 1000 4 32\n");
return(-1);
}
svr_addr_str = argv[1];
mplex_id = atoi(argv[2]);
ret = sscanf(argv[3], "%d", &iterations);
assert(ret == 1);
ret = sscanf(argv[4], "%d", &min_size);
assert(ret == 1);
ret = sscanf(argv[5], "%d", &max_size);
assert(ret == 1);
measurement_array = malloc(sizeof(*measurement_array)*iterations);
assert(measurement_array);
/* initialize Margo using the transport portion of the server
* address (i.e., the part before the first : character if present)
*/
for(i=0; (i<63 && svr_addr_str[i] != '\0' && svr_addr_str[i] != ':'); i++)
cli_addr_prefix[i] = svr_addr_str[i];
mid = margo_init(cli_addr_prefix, MARGO_CLIENT_MODE, 0, -1);
if(mid == MARGO_INSTANCE_NULL)
{
fprintf(stderr, "Error: margo_init()\n");
return -1;
}
ret = bake_client_init(mid, &bcl);
if(ret != 0)
{
fprintf(stderr, "Error: bake_client_init()\n");
margo_finalize(mid);
return -1;
}
hret = margo_addr_lookup(mid, svr_addr_str, &svr_addr);
if(hret != HG_SUCCESS)
{
fprintf(stderr, "Error: margo_addr_lookup()\n");
bake_client_finalize(bcl);
margo_finalize(mid);
return(-1);
}
ret = bake_probe(bph, 1, &bti, &num_targets);
if(ret < 0)
{
fprintf(stderr, "Error: bake_probe()\n");
bake_provider_handle_release(bph);
margo_addr_free(mid, svr_addr);
bake_client_finalize(bcl);
margo_finalize(mid);
return(-1);
}
printf("# <op> <iterations> <size> <min> <q1> <med> <avg> <q3> <max>\n");
bench_routine_noop(bph, iterations, measurement_array);
bench_routine_print("noop", 0, iterations, measurement_array);
for(cur_size=min_size; cur_size <= max_size; cur_size *= 2)
{
bench_routine_write(bph, bti, iterations, measurement_array, cur_size);
bench_routine_print("write", cur_size, iterations, measurement_array);
bench_routine_read(bph, iterations, measurement_array, cur_size);
bench_routine_print("read", cur_size, iterations, measurement_array);
}
bake_provider_handle_release(bph);
margo_addr_free(mid, svr_addr);
bake_client_finalize(bcl);
margo_finalize(mid);
free(measurement_array);
return(0);
}
static double Wtime(void)
{
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
return((double)tp.tv_sec + (double)(tp.tv_nsec) / (double)1000000000.0);
}
static void bench_routine_write(bake_provider_handle_t bph, bake_target_id_t bti, int iterations, double *measurement_array, int size)
{
int ret;
double tm1, tm2;
char *buffer;
uint64_t region_offset = 0;
int i;
buffer = calloc(1, size);
assert(buffer);
/* create region */
ret = bake_create(bph, bti, size*iterations, &rid);
assert(ret == 0);
sleep(1);
for(i=0; i<iterations; i++)
{
tm1 = Wtime();
/* transfer data (writes) */
ret = bake_write(
bph,
rid,
region_offset,
buffer,
size);
tm2 = Wtime();
assert(ret == 0);
region_offset += size;
measurement_array[i] = tm2-tm1;
}
/* persist */
ret = bake_persist(bph, rid, 0, size*iterations);
assert(ret == 0);
free(buffer);
return;
}
static void bench_routine_read(bake_provider_handle_t bph, int iterations, double *measurement_array, int size)
{
int ret;
double tm1, tm2;
char *buffer;
uint64_t region_offset = 0;
int i;
buffer = calloc(1, size);
assert(buffer);
sleep(1);
for(i=0; i<iterations; i++)
{
tm1 = Wtime();
/* transfer data (reads) */
uint64_t bytes_read;
ret = bake_read(
bph,
rid,
region_offset,
buffer,
size,
&bytes_read);
tm2 = Wtime();
assert(ret == 0);
region_offset += size;
measurement_array[i] = tm2-tm1;
}
free(buffer);
return;
}
static void bench_routine_noop(bake_provider_handle_t bph, int iterations, double *measurement_array)
{
int ret;
double tm1, tm2;
int i;
sleep(1);
for(i=0; i<iterations; i++)
{
tm1 = Wtime();
/* noop */
ret = bake_noop(bph);
tm2 = Wtime();
assert(ret == 0);
measurement_array[i] = tm2-tm1;
}
return;
}
static int measurement_cmp(const void* a, const void *b)
{
const double *d_a = a;
const double *d_b = b;
if(*d_a < *d_b)
return(-1);
else if(*d_a > *d_b)
return(1);
else
return(0);
}
static void bench_routine_print(const char* op, int size, int iterations, double* measurement_array)
{
double min, max, q1, q3, med, avg, sum;
int bracket1, bracket2;
int i;
qsort(measurement_array, iterations, sizeof(double), measurement_cmp);
min = measurement_array[0];
max = measurement_array[iterations-1];
sum = 0;
for(i=0; i<iterations; i++)
{
sum += measurement_array[i];
}
avg = sum/(double)iterations;
bracket1 = iterations/2;
if(iterations%2)
bracket2 = bracket1 + 1;
else
bracket2 = bracket1;
med = (measurement_array[bracket1] + measurement_array[bracket2])/(double)2;
bracket1 = iterations/4;
if(iterations%4)
bracket2 = bracket1 + 1;
else
bracket2 = bracket1;
q1 = (measurement_array[bracket1] + measurement_array[bracket2])/(double)2;
bracket1 *= 3;
if(iterations%4)
bracket2 = bracket1 + 1;
else
bracket2 = bracket1;
q3 = (measurement_array[bracket1] + measurement_array[bracket2])/(double)2;
printf("%s\t%d\t%d\t%.9f\t%.9f\t%.9f\t%.9f\t%.9f\t%.9f", op, iterations, size, min, q1, med, avg, q3, max);
for(i=0; i<iterations; i++)
{
printf("\t%.9f", measurement_array[i]);
}
printf("\n");
fflush(NULL);
return;
}
......@@ -24,8 +24,9 @@ void usage(int argc, char *argv[])
{
fprintf(stderr, "Usage: bake-mkpool [OPTIONS] <pmem_pool>\n");
fprintf(stderr, " pmem_pool is the path to the pmemobj pool to create\n");
fprintf(stderr, " [-s size] is the desired size of the pool (K, M, G, etc. suffixes allowed) (%lu is default)\n", PMEMOBJ_MIN_POOL);
fprintf(stderr, " [-s size] create pool file named <pmem_pool> with specified size (K, M, G, etc. suffixes allowed)\n");
fprintf(stderr, "Example: ./bake-mkpool -s 16M /dev/shm/foo.dat\n");
fprintf(stderr, "Note: if -s is not specified, then target file must already exist with desired size.\n");
return;
}
......@@ -65,7 +66,6 @@ void parse_args(int argc, char *argv[], struct options *opts)
/* set default options */
memset(opts, 0, sizeof(*opts));
opts->pool_size = PMEMOBJ_MIN_POOL;
opts->pool_mode = 0664;
/* get options */
......
......@@ -60,7 +60,6 @@ MERCURY_GEN_PROC(bake_persist_out_t,
MERCURY_GEN_PROC(bake_create_write_persist_in_t,
((bake_target_id_t)(bti))\
((uint64_t)(region_size))\
((uint64_t)(region_offset))\
((hg_bulk_t)(bulk_handle))\
((uint64_t)(bulk_offset))\
((uint64_t)(bulk_size))\
......
......@@ -24,9 +24,7 @@ struct options
unsigned num_pools;
char **bake_pools;
char *host_file;
size_t buf_size;
size_t buf_count;
uint32_t num_threads;
int pipeline_enabled;
mplex_mode_t mplex_mode;
};
......@@ -37,9 +35,7 @@ static void usage(int argc, char **argv)
fprintf(stderr, " bake_pool is the path to the BAKE pool\n");
fprintf(stderr, " [-f filename] to write the server address to a file\n");
fprintf(stderr, " [-m mode] multiplexing mode (providers or targets) for managing multiple pools (default is targets)\n");
fprintf(stderr, " [-b size] buffer size for writes on provider\n");
fprintf(stderr, " [-c count] count of buffers used for accesses on provider\n");
fprintf(stderr, " [-t threads] number of threads used for concurrency\n");
fprintf(stderr, " [-p] enable pipelining\n");
fprintf(stderr, "Example: ./bake-server-daemon tcp://localhost:1234 /dev/shm/foo.dat /dev/shm/bar.dat\n");
return;
}
......@@ -51,7 +47,7 @@ static void parse_args(int argc, char **argv, struct options *opts)
memset(opts, 0, sizeof(*opts));
/* get options */
while((opt = getopt(argc, argv, "f:m:b:t:c:")) != -1)
while((opt = getopt(argc, argv, "f:m:p")) != -1)
{
switch(opt)
{
......@@ -68,14 +64,8 @@ static void parse_args(int argc, char **argv, struct options *opts)
exit(EXIT_FAILURE);
}
break;
case 'b':
opts->buf_size = atol(optarg);
break;
case 'c':
opts->buf_count = atol(optarg);
break;
case 't':
opts->num_threads = atol(optarg);
case 'p':
opts->pipeline_enabled = 1;
break;
default:
usage(argc, argv);
......@@ -170,7 +160,7 @@ int main(int argc, char **argv)
if(ret != 0)
{
fprintf(stderr, "Error: bake_provider_register()\n");
bake_perror( "Error: bake_provider_register()", ret);
margo_finalize(mid);
return(-1);
}
......@@ -179,14 +169,13 @@ int main(int argc, char **argv)
if(ret != 0)
{
fprintf(stderr, "Error: bake_provider_add_storage_target()\n");
bake_perror("Error: bake_provider_add_storage_target()", ret);
margo_finalize(mid);
return(-1);
}
bake_provider_set_target_xfer_buffer(provider, tid, opts.buf_count, opts.buf_size);
bake_provider_set_target_xfer_concurrency(provider, tid, opts.num_threads);
if(opts.pipeline_enabled)
bake_provider_set_conf(provider, "pipeline_enabled", "1");
printf("Provider %d managing new target at multiplex id %d\n", i, i+1);
}
......@@ -200,7 +189,7 @@ int main(int argc, char **argv)
if(ret != 0)
{
fprintf(stderr, "Error: bake_provider_register()\n");
bake_perror("Error: bake_provider_register()", ret);
margo_finalize(mid);
return(-1);
}
......@@ -211,14 +200,13 @@ int main(int argc, char **argv)
if(ret != 0)
{
fprintf(stderr, "Error: bake_provider_add_storage_target()\n");
bake_perror("Error: bake_provider_add_storage_target()", ret);
margo_finalize(mid);
return(-1);
}
bake_provider_set_target_xfer_buffer(provider, tid, opts.buf_count, opts.buf_size);
bake_provider_set_target_xfer_concurrency(provider, tid, opts.num_threads);
if(opts.pipeline_enabled)
bake_provider_set_conf(provider, "pipeline_enabled", "1");
printf("Provider 0 managing new target at multiplex id %d\n", 1);
}
}
......
This diff is collapsed.
......@@ -21,7 +21,6 @@ int main(int argc, char **argv)
char *svr_addr_str;
hg_addr_t svr_addr;
margo_instance_id mid;
bake_target_id_t bti;
hg_return_t hret;
int ret;
......@@ -59,7 +58,7 @@ int main(int argc, char **argv)
if(ret < 0)
{
fprintf(stderr, "Error: bake_probe_instance()\n");
bake_perror("Error: bake_probe_instance()", ret);
margo_addr_free(mid, svr_addr);
margo_finalize(mid);
return(-1);
......
The MIT License (MIT)
Copyright (c) 2014 Little Star Media, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The code in this directory was taken from https://github.com/littlstar/b64.c
and modified by Matthieu Dorier.
/**
* `b64.h' - b64
*
* copyright (c) 2014 joseph werle
*/
#ifndef B64_H
#define B64_H
char* bake_b64_encode(const unsigned char* data, size_t data_size);
unsigned char* bake_b64_decode(const char* str, size_t);
#endif
/**
* `decode.c' - b64
*
* copyright (c) 2014 joseph werle
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "b64.h"
/**
* Base64 index table.
*/
static const char b64_table[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
static unsigned char *
b64_decode_ex (const char *src, size_t len, size_t *decsize) {
int i = 0;
int j = 0;
int l = 0;
size_t size = 0;
unsigned char *dec = NULL;
unsigned char buf[3];
unsigned char tmp[4];
// alloc
dec = (unsigned char *) malloc(1);
if (NULL == dec) { return NULL; }
// parse until end of source
while (len--) {
// break if char is `=' or not base64 char
if ('=' == src[j]) { break; }
if (!(isalnum(src[j]) || '+' == src[j] || '/' == src[j])) { break; }
// read up to 4 bytes at a time into `tmp'
tmp[i++] = src[j++];
// if 4 bytes read then decode into `buf'
if (4 == i) {
// translate values in `tmp' from table
for (i = 0; i < 4; ++i) {
// find translation char in `b64_table'
for (l = 0; l < 64; ++l) {
if (tmp[i] == b64_table[l]) {
tmp[i] = l;
break;
}
}
}
// decode
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
// write decoded buffer to `dec'
dec = (unsigned char *) realloc(dec, size + 3);
if (dec != NULL){
for (i = 0; i < 3; ++i) {
dec[size++] = buf[i];
}
} else {
return NULL;
}
// reset
i = 0;
}
}
// remainder
if (i > 0) {
// fill `tmp' with `\0' at most 4 times
for (j = i; j < 4; ++j) {
tmp[j] = '\0';
}
// translate remainder
for (j = 0; j < 4; ++j) {
// find translation char in `b64_table'
for (l = 0; l < 64; ++l) {
if (tmp[j] == b64_table[l]) {
tmp[j] = l;
break;
}
}
}
// decode remainder
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
// write remainer decoded buffer to `dec'
dec = (unsigned char *) realloc(dec, size + (i - 1));
if (dec != NULL){
for (j = 0; (j < i - 1); ++j) {
dec[size++] = buf[j];
}
} else {
return NULL;
}
}
// Make sure we have enough space to add '\0' character at end.
dec = (unsigned char *) realloc(dec, size + 1);
if (dec != NULL){
dec[size] = '\0';
} else {
return NULL;
}