/**
* Copyright (C) Mellanox Technologies Ltd. 2001-2014. ALL RIGHTS RESERVED.
*
* See file LICENSE for terms.
*/
#include <common/test.h>
extern "C" {
#include <ucs/datastruct/mpool.h>
}
#include <limits.h>
#include <vector>
#include <queue>
class test_mpool : public ucs::test {
protected:
static ucs_status_t test_alloc(ucs_mpool_t *mp, size_t *size_p, void **chunk_p) {
*chunk_p = malloc(*size_p);
return (*chunk_p == NULL) ? UCS_ERR_NO_MEMORY : UCS_OK;
}
static void test_free(ucs_mpool_t *mp, void *chunk) {
free(chunk);
}
static ucs_log_func_rc_t
mpool_log_handler(const char *file, unsigned line, const char *function,
ucs_log_level_t level, const char *message, va_list ap)
{
// Ignore errors that invalid input parameters as it is expected
if (level == UCS_LOG_LEVEL_ERROR) {
std::string err_str = format_message(message, ap);
std::string exp_str = "Invalid memory pool parameter(s)";
if (err_str == exp_str) {
UCS_TEST_MESSAGE << err_str;
return UCS_LOG_FUNC_RC_STOP;
}
}
return UCS_LOG_FUNC_RC_CONTINUE;
}
static const size_t header_size = 30;
static const size_t data_size = 152;
static const size_t align = 128;
};
UCS_TEST_F(test_mpool, no_allocs) {
ucs_mpool_t mp;
ucs_status_t status;
ucs_mpool_ops_t ops = {
ucs_mpool_chunk_malloc,
ucs_mpool_chunk_free,
NULL,
NULL
};
status = ucs_mpool_init(&mp, 0, header_size + data_size, header_size, align,
6, 18, &ops, "test");
ASSERT_UCS_OK(status);
ucs_mpool_cleanup(&mp, 1);
}
UCS_TEST_F(test_mpool, wrong_ops) {
ucs_mpool_t mp;
ucs_status_t status;
ucs_mpool_ops_t ops = { 0 };
scoped_log_handler log_handler(mpool_log_handler);
status = ucs_mpool_init(&mp, 0, header_size + data_size, header_size, align,
6, 18, &ops, "test");
EXPECT_TRUE(status == UCS_ERR_INVALID_PARAM);
}
UCS_TEST_F(test_mpool, basic) {
ucs_status_t status;
ucs_mpool_t mp;
ucs_mpool_ops_t ops = {
ucs_mpool_chunk_malloc,
ucs_mpool_chunk_free,
NULL,
NULL
};
push_config();
for (int mpool_fifo = 0; mpool_fifo <= 1; ++mpool_fifo) {
#if ENABLE_DEBUG_DATA
modify_config("MPOOL_FIFO", ucs::to_string(mpool_fifo).c_str());
#else
if (mpool_fifo == 1) {
continue;
}
#endif
status = ucs_mpool_init(&mp, 0, header_size + data_size, header_size, align,
6, 18, &ops, "test");
ASSERT_UCS_OK(status);
for (unsigned loop = 0; loop < 10; ++loop) {
std::vector<void*> objs;
for (unsigned i = 0; i < 18; ++i) {
void *ptr = ucs_mpool_get(&mp);
ASSERT_TRUE(ptr != NULL);
ASSERT_EQ(0ul, ((uintptr_t)ptr + header_size) % align) << ptr;
memset(ptr, 0xAA, header_size + data_size);
objs.push_back(ptr);
}
ASSERT_TRUE(NULL == ucs_mpool_get(&mp));
for (std::vector<void*>::iterator iter = objs.begin(); iter != objs.end(); ++iter) {
ucs_mpool_put(*iter);
}
}
ucs_mpool_cleanup(&mp, 1);
}
pop_config();
}
UCS_TEST_F(test_mpool, custom_alloc) {
ucs_status_t status;
ucs_mpool_t mp;
ucs_mpool_ops_t ops = {
test_alloc,
test_free,
NULL,
NULL
};
status = ucs_mpool_init(&mp, 0, header_size + data_size, header_size, align,
5, 18, &ops, "test");
ASSERT_UCS_OK(status);
void *obj = ucs_mpool_get(&mp);
EXPECT_TRUE(obj != NULL);
ucs_mpool_put(obj);
ucs_mpool_cleanup(&mp, 1);
}
UCS_TEST_F(test_mpool, grow) {
ucs_status_t status;
ucs_mpool_t mp;
ucs_mpool_ops_t ops = {
ucs_mpool_chunk_malloc,
ucs_mpool_chunk_free,
NULL,
NULL
};
status = ucs_mpool_init(&mp, 0, header_size + data_size, header_size, align,
1000, 2000, &ops, "test");
ASSERT_UCS_OK(status);
ucs_mpool_grow(&mp, 1);
void *obj = ucs_mpool_get(&mp);
EXPECT_TRUE(obj != NULL);
ucs_mpool_put(obj);
ucs_mpool_cleanup(&mp, 1);
}
UCS_TEST_F(test_mpool, infinite) {
const unsigned NUM_ELEMS = 1000000 / ucs::test_time_multiplier();
ucs_status_t status;
ucs_mpool_t mp;
ucs_mpool_ops_t ops = {
ucs_mpool_chunk_malloc,
ucs_mpool_chunk_free,
NULL,
NULL
};
status = ucs_mpool_init(&mp, 0, header_size + data_size, header_size, align,
10000, UINT_MAX, &ops, "test");
ASSERT_UCS_OK(status);
std::queue<void*> q;
for (unsigned i = 0; i < NUM_ELEMS; ++i) {
void *obj = ucs_mpool_get(&mp);
ASSERT_TRUE(obj != NULL);
q.push(obj);
}
while (!q.empty()) {
ucs_mpool_put(q.front());
q.pop();
}
ucs_mpool_cleanup(&mp, 1);
}