diff options
Diffstat (limited to 'test/validation/api/pool/pool.c')
-rw-r--r-- | test/validation/api/pool/pool.c | 2440 |
1 files changed, 2440 insertions, 0 deletions
diff --git a/test/validation/api/pool/pool.c b/test/validation/api/pool/pool.c new file mode 100644 index 000000000..95d9ef14e --- /dev/null +++ b/test/validation/api/pool/pool.c @@ -0,0 +1,2440 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2014-2018 Linaro Limited + * Copyright (c) 2020 Marvell + * Copyright (c) 2020-2023 Nokia + */ + +#include <odp_api.h> +#include "odp_cunit_common.h" +#include "test_common_macros.h" +#include <odp/helper/odph_api.h> + +#define MAX_WORKERS 32 + +#define BUF_SIZE 1500 +#define BUF_NUM 1000 +#define TMO_NUM 1000 +#define VEC_NUM 1000 +#define VEC_LEN 32 +#define PKT_LEN 400 +#define PKT_NUM 500 +#define ELEM_NUM 10u +#define ELEM_SIZE 128u +#define CACHE_SIZE 32 +#define MAX_NUM_DEFAULT (10 * 1024 * 1024) +#define UAREA 0xaa + +#define EXT_NUM_BUF 10 +#define EXT_BUF_SIZE 2048 +#define EXT_BUF_ALIGN 64 +#define EXT_APP_HDR_SIZE 128 +#define EXT_UAREA_SIZE 32 +#define EXT_HEADROOM 16 +#define MAGIC_U8 0x7a + +typedef struct { + odp_barrier_t init_barrier; + odp_atomic_u32_t index; + uint32_t nb_threads; + odp_pool_t pool; +} global_shared_mem_t; + +typedef struct { + uint32_t count; + uint8_t mark[ELEM_NUM]; +} uarea_init_t; + +static global_shared_mem_t *global_mem; + +static odp_pool_capability_t global_pool_capa; +static odp_pool_param_t default_pool_param; +static odp_pool_ext_capability_t global_pool_ext_capa; + +static void test_param_init(uint8_t fill) +{ + odp_pool_param_t param; + + memset(¶m, fill, sizeof(param)); + odp_pool_param_init(¶m); + + CU_ASSERT(param.uarea_init.init_fn == NULL); + CU_ASSERT(param.uarea_init.args == NULL); + + CU_ASSERT(param.buf.uarea_size == 0); + CU_ASSERT(param.buf.cache_size >= global_pool_capa.buf.min_cache_size && + param.buf.cache_size <= global_pool_capa.buf.max_cache_size); + + CU_ASSERT(param.pkt.max_num == 0); + CU_ASSERT(param.pkt.num_subparam == 0); + CU_ASSERT(param.pkt.uarea_size == 0); + CU_ASSERT(param.pkt.cache_size >= global_pool_capa.pkt.min_cache_size && + param.pkt.cache_size <= global_pool_capa.pkt.max_cache_size); + + CU_ASSERT(param.tmo.uarea_size == 0); + CU_ASSERT(param.tmo.cache_size >= global_pool_capa.tmo.min_cache_size && + param.tmo.cache_size <= global_pool_capa.tmo.max_cache_size); + + CU_ASSERT(param.vector.uarea_size == 0); + CU_ASSERT(param.vector.cache_size >= global_pool_capa.vector.min_cache_size && + param.vector.cache_size <= global_pool_capa.vector.max_cache_size); +} + +static void pool_test_param_init(void) +{ + test_param_init(0); + test_param_init(0xff); +} + +static void pool_create_destroy(odp_pool_param_t *param) +{ + odp_pool_t pool; + + pool = odp_pool_create(NULL, param); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + CU_ASSERT(odp_pool_to_u64(pool) != + odp_pool_to_u64(ODP_POOL_INVALID)); + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_create_destroy_buffer(void) +{ + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_BUFFER; + param.buf.size = BUF_SIZE; + param.buf.num = BUF_NUM; + + pool_create_destroy(¶m); +} + +static void pool_test_create_destroy_packet(void) +{ + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_PACKET; + param.pkt.len = PKT_LEN; + param.pkt.num = PKT_NUM; + + pool_create_destroy(¶m); +} + +static void pool_test_create_destroy_timeout(void) +{ + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_TIMEOUT; + param.tmo.num = TMO_NUM; + + pool_create_destroy(¶m); +} + +static void pool_test_create_destroy_vector(void) +{ + odp_pool_param_t param; + odp_pool_capability_t capa; + uint32_t max_num = VEC_NUM; + + CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0); + + CU_ASSERT_FATAL(capa.vector.max_pools > 0); + + if (capa.vector.max_num && capa.vector.max_num < max_num) + max_num = capa.vector.max_num; + + odp_pool_param_init(¶m); + param.type = ODP_POOL_VECTOR; + param.vector.num = max_num; + param.vector.max_size = capa.vector.max_size < VEC_LEN ? capa.vector.max_size : VEC_LEN; + + pool_create_destroy(¶m); +} + +static int pool_check_buffer_uarea_init(void) +{ + if (global_pool_capa.buf.max_uarea_size == 0 || !global_pool_capa.buf.uarea_persistence) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int pool_check_packet_uarea_init(void) +{ + if (global_pool_capa.pkt.max_uarea_size == 0 || !global_pool_capa.pkt.uarea_persistence) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int pool_check_vector_uarea_init(void) +{ + if (global_pool_capa.vector.max_uarea_size == 0 || + !global_pool_capa.vector.uarea_persistence) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int pool_check_timeout_uarea_init(void) +{ + if (global_pool_capa.tmo.max_uarea_size == 0 || !global_pool_capa.tmo.uarea_persistence) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static void init_event_uarea(void *uarea, uint32_t size, void *args, uint32_t index) +{ + uarea_init_t *data = args; + + data->count++; + data->mark[index] = 1; + memset(uarea, UAREA, size); +} + +static void pool_test_buffer_uarea_init(void) +{ + odp_pool_param_t param; + uint32_t num = ODPH_MIN(global_pool_capa.buf.max_num, ELEM_NUM), + size = ODPH_MIN(global_pool_capa.buf.max_size, ELEM_SIZE), i; + odp_pool_t pool; + uarea_init_t data; + odp_buffer_t bufs[num]; + uint8_t *uarea; + + memset(&data, 0, sizeof(uarea_init_t)); + odp_pool_param_init(¶m); + param.type = ODP_POOL_BUFFER; + param.uarea_init.init_fn = init_event_uarea; + param.uarea_init.args = &data; + param.buf.num = num; + param.buf.size = size; + param.buf.uarea_size = 1; + pool = odp_pool_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + CU_ASSERT(data.count == num); + + for (i = 0; i < num; i++) { + CU_ASSERT(data.mark[i] == 1); + + bufs[i] = odp_buffer_alloc(pool); + + CU_ASSERT(bufs[i] != ODP_BUFFER_INVALID); + + if (bufs[i] == ODP_BUFFER_INVALID) + break; + + uarea = odp_buffer_user_area(bufs[i]); + + CU_ASSERT(*uarea == UAREA); + } + + odp_buffer_free_multi(bufs, i); + odp_pool_destroy(pool); +} + +static void pool_test_packet_uarea_init(void) +{ + odp_pool_param_t param; + uint32_t num = ODPH_MIN(global_pool_capa.pkt.max_num, ELEM_NUM), + size = ODPH_MIN(global_pool_capa.pkt.max_len, ELEM_SIZE), i; + odp_pool_t pool; + uarea_init_t data; + odp_packet_t pkts[num]; + uint8_t *uarea; + + memset(&data, 0, sizeof(uarea_init_t)); + odp_pool_param_init(¶m); + param.type = ODP_POOL_PACKET; + param.uarea_init.init_fn = init_event_uarea; + param.uarea_init.args = &data; + param.pkt.num = num; + param.pkt.len = size; + param.pkt.uarea_size = 1; + pool = odp_pool_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + CU_ASSERT(data.count == num); + + for (i = 0; i < num; i++) { + CU_ASSERT(data.mark[i] == 1); + + pkts[i] = odp_packet_alloc(pool, ELEM_SIZE); + + CU_ASSERT(pkts[i] != ODP_PACKET_INVALID); + + if (pkts[i] == ODP_PACKET_INVALID) + break; + + uarea = odp_packet_user_area(pkts[i]); + + CU_ASSERT(*uarea == UAREA); + } + + odp_packet_free_multi(pkts, i); + odp_pool_destroy(pool); +} + +static void pool_test_vector_uarea_init(void) +{ + odp_pool_param_t param; + uint32_t num = ODPH_MIN(global_pool_capa.vector.max_num, ELEM_NUM), + size = ODPH_MIN(global_pool_capa.vector.max_size, ELEM_NUM), i; + odp_pool_t pool; + uarea_init_t data; + odp_packet_vector_t vecs[num]; + uint8_t *uarea; + + memset(&data, 0, sizeof(uarea_init_t)); + odp_pool_param_init(¶m); + param.type = ODP_POOL_VECTOR; + param.uarea_init.init_fn = init_event_uarea; + param.uarea_init.args = &data; + param.vector.num = num; + param.vector.max_size = size; + param.vector.uarea_size = 1; + pool = odp_pool_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + CU_ASSERT(data.count == num); + + for (i = 0; i < num; i++) { + CU_ASSERT(data.mark[i] == 1); + + vecs[i] = odp_packet_vector_alloc(pool); + + CU_ASSERT(vecs[i] != ODP_PACKET_VECTOR_INVALID); + + if (vecs[i] == ODP_PACKET_VECTOR_INVALID) + break; + + uarea = odp_packet_vector_user_area(vecs[i]); + + CU_ASSERT(*uarea == UAREA); + } + + for (uint32_t j = 0; j < i; j++) + odp_packet_vector_free(vecs[j]); + + odp_pool_destroy(pool); +} + +static void pool_test_timeout_uarea_init(void) +{ + odp_pool_param_t param; + uint32_t num = ODPH_MIN(global_pool_capa.tmo.max_num, ELEM_NUM), i; + odp_pool_t pool; + uarea_init_t data; + odp_timeout_t tmos[num]; + uint8_t *uarea; + + memset(&data, 0, sizeof(uarea_init_t)); + odp_pool_param_init(¶m); + param.type = ODP_POOL_TIMEOUT; + param.uarea_init.init_fn = init_event_uarea; + param.uarea_init.args = &data; + param.tmo.num = num; + param.tmo.uarea_size = 1; + pool = odp_pool_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + CU_ASSERT(data.count == num); + + for (i = 0; i < num; i++) { + CU_ASSERT(data.mark[i] == 1); + + tmos[i] = odp_timeout_alloc(pool); + + CU_ASSERT(tmos[i] != ODP_TIMEOUT_INVALID); + + if (tmos[i] == ODP_TIMEOUT_INVALID) + break; + + uarea = odp_timeout_user_area(tmos[i]); + + CU_ASSERT(*uarea == UAREA); + } + + for (uint32_t j = 0; j < i; j++) + odp_timeout_free(tmos[j]); + + odp_pool_destroy(pool); +} + +static void pool_test_lookup_info_print(void) +{ + odp_pool_t pool; + const char pool_name[] = "pool_for_lookup_test"; + odp_pool_info_t info; + odp_pool_param_t param; + + memset(&info, 0, sizeof(info)); + odp_pool_param_init(¶m); + + param.type = ODP_POOL_BUFFER; + param.buf.size = BUF_SIZE; + param.buf.num = BUF_NUM; + + pool = odp_pool_create(pool_name, ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + pool = odp_pool_lookup(pool_name); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + CU_ASSERT_FATAL(odp_pool_info(pool, &info) == 0); + CU_ASSERT(strncmp(pool_name, info.name, sizeof(pool_name)) == 0); + CU_ASSERT(param.buf.size <= info.params.buf.size); + CU_ASSERT(param.buf.align <= info.params.buf.align); + CU_ASSERT(param.buf.num <= info.params.buf.num); + CU_ASSERT(param.type == info.params.type); + + odp_pool_print(pool); + odp_pool_print_all(); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_long_name(void) +{ + odp_pool_t pool; + odp_pool_info_t info; + odp_pool_param_t param; + char name[ODP_POOL_NAME_LEN]; + + memset(name, 'a', sizeof(name)); + name[sizeof(name) - 1] = 0; + + memset(&info, 0, sizeof(info)); + odp_pool_param_init(¶m); + + param.type = ODP_POOL_BUFFER; + param.buf.size = BUF_SIZE; + param.buf.num = BUF_NUM; + param.buf.uarea_size = 64; + + pool = odp_pool_create(name, ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + pool = odp_pool_lookup(name); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + CU_ASSERT_FATAL(odp_pool_info(pool, &info) == 0); + CU_ASSERT(strncmp(name, info.name, sizeof(name)) == 0); + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_same_name(const odp_pool_param_t *param) +{ + odp_pool_t pool, pool_a, pool_b; + const char *name = "same_name"; + + pool_a = odp_pool_create(name, param); + CU_ASSERT_FATAL(pool_a != ODP_POOL_INVALID); + + pool = odp_pool_lookup(name); + CU_ASSERT(pool == pool_a); + + /* Second pool with the same name */ + pool_b = odp_pool_create(name, param); + CU_ASSERT_FATAL(pool_b != ODP_POOL_INVALID); + + pool = odp_pool_lookup(name); + CU_ASSERT(pool == pool_a || pool == pool_b); + + CU_ASSERT(odp_pool_destroy(pool_a) == 0); + CU_ASSERT(odp_pool_destroy(pool_b) == 0); +} + +static void pool_test_same_name_buf(void) +{ + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_BUFFER; + param.buf.size = BUF_SIZE; + param.buf.num = BUF_NUM; + + pool_test_same_name(¶m); +} + +static void pool_test_same_name_pkt(void) +{ + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_PACKET; + param.pkt.len = PKT_LEN; + param.pkt.num = PKT_NUM; + + pool_test_same_name(¶m); +} + +static void pool_test_same_name_tmo(void) +{ + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_TIMEOUT; + param.tmo.num = TMO_NUM; + + pool_test_same_name(¶m); +} + +static void pool_test_same_name_vec(void) +{ + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_VECTOR; + param.vector.num = 10; + param.vector.max_size = 2; + + pool_test_same_name(¶m); +} + +static void alloc_buffer(uint32_t cache_size) +{ + odp_pool_t pool; + odp_pool_param_t param; + uint32_t i, num; + odp_buffer_t buf[BUF_NUM]; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_BUFFER; + param.buf.num = BUF_NUM; + param.buf.size = BUF_SIZE; + param.pkt.cache_size = cache_size; + + pool = odp_pool_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + num = 0; + + for (i = 0; i < PKT_NUM; i++) { + buf[num] = odp_buffer_alloc(pool); + CU_ASSERT(buf[num] != ODP_BUFFER_INVALID); + + if (buf[num] != ODP_BUFFER_INVALID) + num++; + } + + for (i = 0; i < num; i++) + odp_buffer_free(buf[i]); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_alloc_buffer(void) +{ + alloc_buffer(default_pool_param.buf.cache_size); +} + +static void pool_test_alloc_buffer_min_cache(void) +{ + alloc_buffer(global_pool_capa.buf.min_cache_size); +} + +static void pool_test_alloc_buffer_max_cache(void) +{ + alloc_buffer(global_pool_capa.buf.max_cache_size); +} + +static void alloc_packet_vector(uint32_t cache_size) +{ + odp_pool_t pool; + odp_pool_param_t param; + odp_pool_capability_t capa; + uint32_t i, num; + odp_packet_vector_t pkt_vec[VEC_NUM]; + uint32_t max_num = VEC_NUM; + + CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0); + + if (capa.vector.max_num && capa.vector.max_num < max_num) + max_num = capa.vector.max_num; + + odp_pool_param_init(¶m); + param.type = ODP_POOL_VECTOR; + param.vector.num = max_num; + param.vector.max_size = capa.vector.max_size < VEC_LEN ? capa.vector.max_size : VEC_LEN; + param.vector.cache_size = cache_size; + + pool = odp_pool_create(NULL, ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + num = 0; + for (i = 0; i < max_num; i++) { + odp_packet_vector_t pktv = odp_packet_vector_alloc(pool); + + CU_ASSERT(pktv != ODP_PACKET_VECTOR_INVALID); + + if (pktv == ODP_PACKET_VECTOR_INVALID) + continue; + + CU_ASSERT(odp_packet_vector_valid(pktv) == 1); + CU_ASSERT(odp_event_is_valid(odp_packet_vector_to_event(pktv)) == 1); + CU_ASSERT(odp_packet_vector_size(pktv) == 0); + + pkt_vec[num] = pktv; + num++; + } + + for (i = 0; i < num; i++) + odp_packet_vector_free(pkt_vec[i]); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_alloc_packet_vector(void) +{ + alloc_packet_vector(default_pool_param.vector.cache_size); +} + +static void pool_test_alloc_packet_vector_min_cache(void) +{ + alloc_packet_vector(global_pool_capa.vector.min_cache_size); +} + +static void pool_test_alloc_packet_vector_max_cache(void) +{ + alloc_packet_vector(global_pool_capa.vector.max_cache_size); +} + +static void alloc_packet(uint32_t cache_size) +{ + odp_pool_t pool; + odp_pool_param_t param; + uint32_t i, num; + odp_packet_t pkt[PKT_NUM]; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_PACKET; + param.pkt.num = PKT_NUM; + param.pkt.len = PKT_LEN; + param.pkt.cache_size = cache_size; + + pool = odp_pool_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + num = 0; + + for (i = 0; i < PKT_NUM; i++) { + pkt[num] = odp_packet_alloc(pool, PKT_LEN); + CU_ASSERT(pkt[num] != ODP_PACKET_INVALID); + + if (pkt[num] != ODP_PACKET_INVALID) + num++; + } + + for (i = 0; i < num; i++) + odp_packet_free(pkt[i]); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_alloc_packet(void) +{ + alloc_packet(default_pool_param.pkt.cache_size); +} + +static void pool_test_alloc_packet_min_cache(void) +{ + alloc_packet(global_pool_capa.pkt.min_cache_size); +} + +static void pool_test_alloc_packet_max_cache(void) +{ + alloc_packet(global_pool_capa.pkt.max_cache_size); +} + +static void pool_test_alloc_packet_subparam(void) +{ + odp_pool_t pool; + odp_pool_capability_t capa; + odp_pool_param_t param; + uint32_t i, j, num, num_sub; + odp_packet_t pkt[PKT_NUM]; + + CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0); + num_sub = capa.pkt.max_num_subparam; + + CU_ASSERT_FATAL(num_sub <= ODP_POOL_MAX_SUBPARAMS); + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_PACKET; + param.pkt.num = PKT_NUM; + param.pkt.len = PKT_LEN; + param.pkt.num_subparam = num_sub; + + for (i = 0; i < num_sub; i++) { + param.pkt.sub[i].num = PKT_NUM; + param.pkt.sub[i].len = PKT_LEN + (i * 100); + } + + pool = odp_pool_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + num = 0; + + for (i = 0; i < PKT_NUM; i++) { + pkt[num] = odp_packet_alloc(pool, PKT_LEN); + CU_ASSERT(pkt[num] != ODP_PACKET_INVALID); + + if (pkt[num] != ODP_PACKET_INVALID) + num++; + } + + for (i = 0; i < num; i++) + odp_packet_free(pkt[i]); + + for (j = 0; j < num_sub; j++) { + num = 0; + + for (i = 0; i < param.pkt.sub[j].num; i++) { + pkt[num] = odp_packet_alloc(pool, param.pkt.sub[j].len); + CU_ASSERT(pkt[num] != ODP_PACKET_INVALID); + + if (pkt[num] != ODP_PACKET_INVALID) + num++; + } + + for (i = 0; i < num; i++) + odp_packet_free(pkt[i]); + } + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void alloc_timeout(uint32_t cache_size) +{ + odp_pool_t pool; + odp_pool_param_t param; + uint32_t i, num; + odp_timeout_t tmo[TMO_NUM]; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_TIMEOUT; + param.tmo.num = TMO_NUM; + param.tmo.cache_size = cache_size; + + pool = odp_pool_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + num = 0; + + for (i = 0; i < PKT_NUM; i++) { + tmo[num] = odp_timeout_alloc(pool); + CU_ASSERT(tmo[num] != ODP_TIMEOUT_INVALID); + + if (tmo[num] != ODP_TIMEOUT_INVALID) + num++; + } + + for (i = 0; i < num; i++) + odp_timeout_free(tmo[i]); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_alloc_timeout(void) +{ + alloc_timeout(default_pool_param.tmo.cache_size); +} + +static void pool_test_alloc_timeout_min_cache(void) +{ + alloc_timeout(global_pool_capa.tmo.min_cache_size); +} + +static void pool_test_alloc_timeout_max_cache(void) +{ + alloc_timeout(global_pool_capa.tmo.max_cache_size); +} + +static void pool_test_info_packet(void) +{ + odp_pool_t pool; + odp_pool_info_t info; + odp_pool_param_t param; + const char pool_name[] = "test_pool_name"; + + memset(&info, 0, sizeof(info)); + odp_pool_param_init(¶m); + + param.type = ODP_POOL_PACKET; + param.pkt.num = PKT_NUM; + param.pkt.len = PKT_LEN; + + pool = odp_pool_create(pool_name, ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + memset(&info, 0, sizeof(odp_pool_info_t)); + CU_ASSERT_FATAL(odp_pool_info(pool, &info) == 0); + + CU_ASSERT(strncmp(pool_name, info.name, sizeof(pool_name)) == 0); + CU_ASSERT(info.params.type == ODP_POOL_PACKET); + CU_ASSERT(info.params.pkt.num == param.pkt.num); + CU_ASSERT(info.params.pkt.len == param.pkt.len); + CU_ASSERT(info.pkt.max_num >= param.pkt.num); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_info_data_range(void) +{ + odp_pool_t pool; + odp_pool_info_t info; + odp_pool_param_t param; + odp_packet_t pkt[PKT_NUM]; + uint32_t i, num; + uintptr_t pool_len; + + memset(&info, 0, sizeof(info)); + odp_pool_param_init(¶m); + + param.type = ODP_POOL_PACKET; + param.pkt.num = PKT_NUM; + param.pkt.len = PKT_LEN; + + pool = odp_pool_create(NULL, ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + CU_ASSERT_FATAL(odp_pool_info(pool, &info) == 0); + + pool_len = info.max_data_addr - info.min_data_addr + 1; + CU_ASSERT(pool_len >= PKT_NUM * PKT_LEN); + + num = 0; + + for (i = 0; i < PKT_NUM; i++) { + pkt[num] = odp_packet_alloc(pool, PKT_LEN); + CU_ASSERT(pkt[num] != ODP_PACKET_INVALID); + + if (pkt[num] != ODP_PACKET_INVALID) + num++; + } + + for (i = 0; i < num; i++) { + uintptr_t pkt_data, pkt_data_end; + uint32_t offset = 0; + uint32_t seg_len = 0; + uint32_t pkt_len = odp_packet_len(pkt[i]); + + while (offset < pkt_len) { + pkt_data = (uintptr_t)odp_packet_offset(pkt[i], offset, + &seg_len, NULL); + pkt_data_end = pkt_data + seg_len - 1; + CU_ASSERT((pkt_data >= info.min_data_addr) && + (pkt_data_end <= info.max_data_addr)); + offset += seg_len; + } + + odp_packet_free(pkt[i]); + } + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_buf_max_num(void) +{ + odp_pool_t pool; + odp_pool_param_t param; + odp_pool_capability_t capa; + uint32_t max_num, num, i; + odp_shm_t shm; + odp_buffer_t *buf; + + CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0); + + max_num = MAX_NUM_DEFAULT; + if (capa.buf.max_num) + max_num = capa.buf.max_num; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_BUFFER; + param.buf.num = max_num; + param.buf.size = 10; + + pool = odp_pool_create("test_buf_max_num", ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + shm = odp_shm_reserve("test_max_num_shm", + max_num * sizeof(odp_buffer_t), + sizeof(odp_buffer_t), 0); + + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + + buf = odp_shm_addr(shm); + + num = 0; + for (i = 0; i < max_num; i++) { + buf[num] = odp_buffer_alloc(pool); + + if (buf[num] != ODP_BUFFER_INVALID) { + CU_ASSERT(odp_buffer_is_valid(buf[num]) == 1); + CU_ASSERT(odp_event_is_valid(odp_buffer_to_event(buf[num])) == 1); + num++; + } + } + + CU_ASSERT(num == max_num); + + for (i = 0; i < num; i++) + odp_buffer_free(buf[i]); + + CU_ASSERT(odp_shm_free(shm) == 0); + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_pkt_max_num(void) +{ + odp_pool_t pool; + odp_pool_param_t param; + odp_pool_capability_t capa; + uint32_t max_num, num, i; + odp_shm_t shm; + odp_packet_t *pkt; + uint32_t len = 10; + + CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0); + + max_num = MAX_NUM_DEFAULT; + if (capa.pkt.max_num) + max_num = capa.pkt.max_num; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_PACKET; + param.pkt.num = max_num; + param.pkt.max_num = max_num; + param.pkt.len = len; + param.pkt.max_len = len; + param.pkt.headroom = 0; + + pool = odp_pool_create("test_packet_max_num", ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + shm = odp_shm_reserve("test_max_num_shm", + max_num * sizeof(odp_packet_t), + sizeof(odp_packet_t), 0); + + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + + pkt = odp_shm_addr(shm); + + num = 0; + for (i = 0; i < max_num; i++) { + pkt[num] = odp_packet_alloc(pool, len); + + if (pkt[num] != ODP_PACKET_INVALID) { + CU_ASSERT(odp_packet_is_valid(pkt[num]) == 1); + CU_ASSERT(odp_event_is_valid(odp_packet_to_event(pkt[num])) == 1); + num++; + } + } + + CU_ASSERT(num == max_num); + + for (i = 0; i < num; i++) + odp_packet_free(pkt[i]); + + CU_ASSERT(odp_shm_free(shm) == 0); + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_packet_vector_max_num(void) +{ + odp_pool_t pool; + odp_pool_param_t param; + odp_pool_capability_t capa; + uint32_t num, i; + odp_shm_t shm; + odp_packet_vector_t *pktv; + uint32_t max_num = VEC_NUM; + + CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0); + + if (capa.vector.max_num) + max_num = capa.vector.max_num; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_VECTOR; + param.vector.num = max_num; + param.vector.max_size = 1; + + pool = odp_pool_create("test_packet_vector_max_num", ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + shm = odp_shm_reserve("test_max_num_shm", max_num * sizeof(odp_packet_vector_t), + sizeof(odp_packet_vector_t), 0); + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + + pktv = odp_shm_addr(shm); + CU_ASSERT_FATAL(pktv != NULL); + + num = 0; + for (i = 0; i < max_num; i++) { + pktv[num] = odp_packet_vector_alloc(pool); + + if (pktv[num] != ODP_PACKET_VECTOR_INVALID) + num++; + } + + CU_ASSERT(num == max_num); + + for (i = 0; i < num; i++) + odp_packet_vector_free(pktv[i]); + + CU_ASSERT(odp_shm_free(shm) == 0); + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_pkt_seg_len(void) +{ + uint32_t len = 1500; + uint32_t min_seg_len = 42; + uint32_t max_num = 10; + uint32_t num = 0; + uint32_t i; + odp_packet_t pkt_tbl[max_num]; + odp_pool_t pool; + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_PACKET; + param.pkt.num = max_num; + param.pkt.len = len; + param.pkt.max_len = len; + param.pkt.seg_len = min_seg_len; + + pool = odp_pool_create("test_packet_seg_len", ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + for (i = 0; i < max_num; i++) { + pkt_tbl[i] = odp_packet_alloc(pool, len); + + if (pkt_tbl[i] != ODP_PACKET_INVALID) + num++; + } + + CU_ASSERT(num == max_num); + + for (i = 0; i < num; i++) { + CU_ASSERT(odp_packet_seg_len(pkt_tbl[i]) >= min_seg_len); + odp_packet_free(pkt_tbl[i]); + } + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void pool_test_tmo_max_num(void) +{ + odp_pool_t pool; + odp_pool_param_t param; + odp_pool_capability_t capa; + uint32_t max_num, num, i; + odp_shm_t shm; + odp_timeout_t *tmo; + + CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0); + + max_num = MAX_NUM_DEFAULT; + if (capa.tmo.max_num) + max_num = capa.tmo.max_num; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_TIMEOUT; + param.tmo.num = max_num; + + pool = odp_pool_create("test_tmo_max_num", ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + shm = odp_shm_reserve("test_max_num_shm", + max_num * sizeof(odp_packet_t), + sizeof(odp_packet_t), 0); + + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + + tmo = odp_shm_addr(shm); + + num = 0; + for (i = 0; i < max_num; i++) { + tmo[num] = odp_timeout_alloc(pool); + + if (tmo[num] != ODP_TIMEOUT_INVALID) { + CU_ASSERT(odp_event_is_valid(odp_timeout_to_event(tmo[num])) == 1); + num++; + } + } + + CU_ASSERT(num == max_num); + + for (i = 0; i < num; i++) + odp_timeout_free(tmo[i]); + + CU_ASSERT(odp_shm_free(shm) == 0); + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void buffer_alloc_loop(odp_pool_t pool, int num, int buffer_size) +{ + int allocs; + + /* Allocate, modify, and free buffers */ + for (allocs = 0; allocs < num;) { + odp_buffer_t buf; + uint8_t *data; + int i; + + buf = odp_buffer_alloc(pool); + if (buf == ODP_BUFFER_INVALID) + continue; + + data = odp_buffer_addr(buf); + + for (i = 0; i < buffer_size; i++) + data[i] = i; + + odp_buffer_free(buf); + allocs++; + } +} + +static int run_pool_test_create_after_fork(void *arg ODP_UNUSED) +{ + int thr_index; + + thr_index = odp_atomic_fetch_inc_u32(&global_mem->index); + + /* Thread 0 allocates the shared pool */ + if (thr_index == 0) { + odp_pool_t pool; + odp_pool_param_t param; + + odp_pool_param_init(¶m); + + param.type = ODP_POOL_BUFFER; + param.buf.size = BUF_SIZE; + param.buf.num = BUF_NUM; + + pool = odp_pool_create(NULL, ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + global_mem->pool = pool; + } + + odp_barrier_wait(&global_mem->init_barrier); + + buffer_alloc_loop(global_mem->pool, BUF_NUM, BUF_SIZE); + + return CU_get_number_of_failures(); +} + +static void pool_test_create_after_fork(void) +{ + odp_shm_t shm; + int num; + + /* No single VA required since reserve is done before fork */ + shm = odp_shm_reserve(NULL, sizeof(global_shared_mem_t), 0, 0); + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + global_mem = odp_shm_addr(shm); + CU_ASSERT_FATAL(global_mem != NULL); + + num = odp_cpumask_default_worker(NULL, 0); + if (num > MAX_WORKERS) + num = MAX_WORKERS; + + global_mem->nb_threads = num; + global_mem->pool = ODP_POOL_INVALID; + odp_barrier_init(&global_mem->init_barrier, num + 1); + odp_atomic_init_u32(&global_mem->index, 0); + + /* Fork here */ + odp_cunit_thread_create(num, run_pool_test_create_after_fork, NULL, 0, 0); + + /* Wait until thread 0 has created the test pool */ + odp_barrier_wait(&global_mem->init_barrier); + + buffer_alloc_loop(global_mem->pool, BUF_NUM, BUF_SIZE); + + /* Wait for all thread endings */ + CU_ASSERT(odp_cunit_thread_join(num) >= 0); + + CU_ASSERT(!odp_pool_destroy(global_mem->pool)); + + CU_ASSERT(!odp_shm_free(shm)); +} + +static void pool_test_pool_index(void) +{ + uint32_t max_pools = global_pool_capa.pkt.max_pools; + uint32_t i, num_pools; + unsigned int max_index = odp_pool_max_index(); + odp_packet_t pool_lookup[max_index + 1]; + odp_packet_t pkt; + odp_pool_t pool[max_pools]; + odp_pool_param_t param; + int pool_index; + + CU_ASSERT_FATAL(max_pools > 0); + + /* Pool max index should match to pool capability */ + CU_ASSERT_FATAL(max_index >= global_pool_capa.max_pools - 1); + CU_ASSERT_FATAL(max_index >= global_pool_capa.pkt.max_pools - 1); + + odp_pool_param_init(¶m); + param.type = ODP_POOL_PACKET; + param.pkt.len = PKT_LEN; + param.pkt.num = 1; + param.pkt.max_num = 1; + + for (i = 0; i < max_pools; i++) { + pool[i] = odp_pool_create(NULL, ¶m); + + if (pool[i] == ODP_POOL_INVALID) + break; + } + + /* Ensuring max possible pools are created */ + num_pools = i; + CU_ASSERT(num_pools == max_pools); + + for (i = 0; i < num_pools; i++) { + pkt = odp_packet_alloc(pool[i], PKT_LEN); + CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID); + + /* Only one packet should be possible from each pool */ + CU_ASSERT_FATAL(odp_packet_alloc(pool[i], PKT_LEN) == ODP_PACKET_INVALID); + + /* Check pool index validity */ + pool_index = odp_pool_index(pool[i]); + CU_ASSERT_FATAL(pool_index >= 0); + CU_ASSERT_FATAL((unsigned int)pool_index <= odp_pool_max_index()); + + /* Store packet handle in pool lookup table */ + pool_lookup[pool_index] = pkt; + } + + for (i = 0; i < num_pools; i++) { + pool_index = odp_pool_index(pool[i]); + + /* Free the packet using pool lookup */ + odp_packet_free(pool_lookup[pool_index]); + + /* Now packet allocation from the pool should be possible */ + pkt = odp_packet_alloc(pool[i], PKT_LEN); + CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID); + odp_packet_free(pkt); + + /* Destroy the pool */ + CU_ASSERT(odp_pool_destroy(pool[i]) == 0); + } +} + +static void pool_test_create_max_pkt_pools(void) +{ + uint32_t max_pools = global_pool_capa.pkt.max_pools; + uint32_t i, num_pools, num_shm; + odp_pool_t pool[max_pools]; + odp_pool_param_t param; + odp_shm_capability_t shm_capa; + uint32_t shm_size = 32; + uint32_t uarea_size = 32; + + CU_ASSERT_FATAL(max_pools > 0); + + /* Reserve maximum number of SHM blocks */ + CU_ASSERT_FATAL(odp_shm_capability(&shm_capa) == 0); + CU_ASSERT_FATAL(shm_capa.max_blocks > 0); + + odp_shm_t shm[shm_capa.max_blocks]; + + if (shm_capa.max_size && shm_capa.max_size < shm_size) + shm_size = shm_capa.max_size; + + for (i = 0; i < shm_capa.max_blocks; i++) { + shm[i] = odp_shm_reserve(NULL, shm_size, 0, 0); + + if (shm[i] == ODP_SHM_INVALID) + break; + } + num_shm = i; + CU_ASSERT(num_shm == shm_capa.max_blocks); + + /* Create maximum number of packet pools */ + if (uarea_size > global_pool_capa.pkt.max_uarea_size) + uarea_size = global_pool_capa.pkt.max_uarea_size; + + odp_pool_param_init(¶m); + param.type = ODP_POOL_PACKET; + param.pkt.len = PKT_LEN; + param.pkt.num = 1; + param.pkt.max_num = 1; + param.pkt.uarea_size = uarea_size; + + for (i = 0; i < max_pools; i++) { + pool[i] = odp_pool_create(NULL, ¶m); + + if (pool[i] == ODP_POOL_INVALID) + break; + } + num_pools = i; + CU_ASSERT(num_pools == max_pools); + + for (i = 0; i < num_pools; i++) + CU_ASSERT(odp_pool_destroy(pool[i]) == 0); + + for (i = 0; i < num_shm; i++) + CU_ASSERT(odp_shm_free(shm[i]) == 0); +} + +static int pool_check_buffer_pool_statistics(void) +{ + if (global_pool_capa.buf.stats.all == 0) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int pool_check_packet_pool_statistics(void) +{ + if (global_pool_capa.pkt.stats.all == 0) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int pool_check_packet_vector_pool_statistics(void) +{ + if (global_pool_capa.vector.stats.all == 0) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int pool_check_timeout_pool_statistics(void) +{ + if (global_pool_capa.tmo.stats.all == 0) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static void pool_test_pool_statistics(odp_pool_type_t pool_type) +{ + odp_pool_stats_t stats; + odp_pool_stats_selected_t selected; + odp_pool_param_t param; + odp_pool_stats_opt_t supported; + uint32_t i, j, num_pool, num_obj, cache_size, num_thr; + uint32_t max_pools = 2; + uint16_t first = 0; + uint16_t last = ODP_POOL_MAX_THREAD_STATS - 1; + + if (last > odp_thread_count_max() - 1) + last = odp_thread_count_max() - 1; + + odp_pool_param_init(¶m); + + if (pool_type == ODP_POOL_BUFFER) { + max_pools = global_pool_capa.buf.max_pools < max_pools ? + global_pool_capa.buf.max_pools : max_pools; + num_obj = BUF_NUM; + supported.all = global_pool_capa.buf.stats.all; + param.type = ODP_POOL_BUFFER; + cache_size = CACHE_SIZE > global_pool_capa.buf.max_cache_size ? + global_pool_capa.buf.max_cache_size : CACHE_SIZE; + param.buf.cache_size = cache_size; + param.buf.size = BUF_SIZE; + param.buf.num = num_obj; + } else if (pool_type == ODP_POOL_PACKET) { + max_pools = global_pool_capa.pkt.max_pools < max_pools ? + global_pool_capa.pkt.max_pools : max_pools; + num_obj = PKT_NUM; + supported.all = global_pool_capa.pkt.stats.all; + param.type = ODP_POOL_PACKET; + cache_size = CACHE_SIZE > global_pool_capa.pkt.max_cache_size ? + global_pool_capa.pkt.max_cache_size : CACHE_SIZE; + param.pkt.cache_size = cache_size; + param.pkt.len = PKT_LEN; + param.pkt.num = num_obj; + param.pkt.max_num = num_obj; + } else if (pool_type == ODP_POOL_VECTOR) { + max_pools = global_pool_capa.vector.max_pools < max_pools ? + global_pool_capa.vector.max_pools : max_pools; + num_obj = VEC_NUM; + if (global_pool_capa.vector.max_num && global_pool_capa.vector.max_num < num_obj) + num_obj = global_pool_capa.vector.max_num; + supported.all = global_pool_capa.vector.stats.all; + param.type = ODP_POOL_VECTOR; + cache_size = CACHE_SIZE > global_pool_capa.vector.max_cache_size ? + global_pool_capa.vector.max_cache_size : CACHE_SIZE; + param.vector.cache_size = cache_size; + param.vector.num = num_obj; + param.vector.max_size = global_pool_capa.vector.max_size < VEC_LEN ? + global_pool_capa.vector.max_size : VEC_LEN; + } else { + max_pools = global_pool_capa.tmo.max_pools < max_pools ? + global_pool_capa.tmo.max_pools : max_pools; + num_obj = TMO_NUM; + supported.all = global_pool_capa.tmo.stats.all; + param.type = ODP_POOL_TIMEOUT; + cache_size = CACHE_SIZE > global_pool_capa.tmo.max_cache_size ? + global_pool_capa.tmo.max_cache_size : CACHE_SIZE; + param.tmo.cache_size = cache_size; + param.tmo.num = num_obj; + } + + param.stats.all = supported.all; + + CU_ASSERT_FATAL(max_pools != 0); + + /* Extra alloc rounds for testing odp_pool_stats_t.alloc_fails */ + uint32_t num_allocs = num_obj + 100; + odp_event_t event[max_pools][num_allocs]; + uint32_t num_event[max_pools]; + odp_pool_t pool[max_pools]; + + for (i = 0; i < max_pools; i++) { + pool[i] = odp_pool_create(NULL, ¶m); + + if (pool[i] == ODP_POOL_INVALID) + break; + } + + num_pool = i; + CU_ASSERT(num_pool == max_pools); + + for (i = 0; i < num_pool; i++) { + uint32_t num_events = 0; + uint32_t num_fails = 0; + + memset(&stats, 0xff, sizeof(odp_pool_stats_t)); + memset(&selected, 0xff, sizeof(odp_pool_stats_selected_t)); + + CU_ASSERT_FATAL(odp_pool_stats_reset(pool[i]) == 0); + + stats.thread.first = first; + stats.thread.last = last; + num_thr = last - first + 1; + CU_ASSERT_FATAL(odp_pool_stats(pool[i], &stats) == 0); + CU_ASSERT_FATAL(odp_pool_stats_selected(pool[i], &selected, &supported) == 0); + + CU_ASSERT(stats.available <= num_obj); + if (supported.bit.available) + CU_ASSERT(selected.available <= num_obj); + CU_ASSERT(stats.alloc_ops == 0); + if (supported.bit.alloc_ops) + CU_ASSERT(selected.alloc_ops == 0); + CU_ASSERT(stats.alloc_fails == 0); + if (supported.bit.alloc_fails) + CU_ASSERT(selected.alloc_fails == 0); + CU_ASSERT(stats.free_ops == 0); + if (supported.bit.free_ops) + CU_ASSERT(selected.free_ops == 0); + CU_ASSERT(stats.total_ops == 0); + if (supported.bit.total_ops) + CU_ASSERT(selected.total_ops == 0); + CU_ASSERT(stats.cache_available <= num_obj); + if (supported.bit.cache_available) + CU_ASSERT(selected.cache_available <= num_obj); + CU_ASSERT(stats.cache_alloc_ops == 0); + if (supported.bit.cache_alloc_ops) + CU_ASSERT(selected.cache_alloc_ops == 0); + CU_ASSERT(stats.cache_free_ops == 0); + if (supported.bit.cache_free_ops) + CU_ASSERT(selected.cache_free_ops == 0); + + CU_ASSERT(stats.thread.first == first); + CU_ASSERT(stats.thread.last == last); + + if (supported.bit.thread_cache_available) { + for (j = 0; j < num_thr; j++) + CU_ASSERT(stats.thread.cache_available[j] <= stats.cache_available); + } + + /* Allocate the events */ + for (j = 0; j < num_allocs; j++) { + odp_event_t new_event = ODP_EVENT_INVALID; + uint64_t total_cached = 0; + uint16_t first_id = 0; + uint16_t last_id = last; + + if (pool_type == ODP_POOL_BUFFER) { + odp_buffer_t buf = odp_buffer_alloc(pool[i]); + + if (buf != ODP_BUFFER_INVALID) + new_event = odp_buffer_to_event(buf); + } else if (pool_type == ODP_POOL_PACKET) { + odp_packet_t pkt = odp_packet_alloc(pool[i], PKT_LEN); + + if (pkt != ODP_PACKET_INVALID) + new_event = odp_packet_to_event(pkt); + } else if (pool_type == ODP_POOL_VECTOR) { + odp_packet_vector_t pktv = odp_packet_vector_alloc(pool[i]); + + if (pktv != ODP_PACKET_VECTOR_INVALID) + new_event = odp_packet_vector_to_event(pktv); + } else { + odp_timeout_t tmo = odp_timeout_alloc(pool[i]); + + if (tmo != ODP_TIMEOUT_INVALID) + new_event = odp_timeout_to_event(tmo); + } + + if (new_event != ODP_EVENT_INVALID) + event[i][num_events++] = new_event; + else + num_fails++; + + CU_ASSERT_FATAL(odp_pool_stats(pool[i], &stats) == 0); + CU_ASSERT_FATAL(odp_pool_stats_selected(pool[i], &selected, + &supported) == 0); + CU_ASSERT(stats.available <= num_obj - num_events); + if (supported.bit.available) + CU_ASSERT(selected.available <= num_obj - num_events); + CU_ASSERT(stats.cache_available <= num_obj - num_events); + if (supported.bit.cache_available) + CU_ASSERT(selected.cache_available <= num_obj - num_events); + + if (supported.bit.thread_cache_available) { + while (first_id < odp_thread_count_max()) { + memset(&stats, 0xff, sizeof(odp_pool_stats_t)); + + stats.thread.first = first_id; + stats.thread.last = last_id; + num_thr = last_id - first_id + 1; + CU_ASSERT_FATAL(odp_pool_stats(pool[i], &stats) == 0); + + for (uint32_t k = 0; k < num_thr; k++) { + uint64_t cached = stats.thread.cache_available[k]; + + CU_ASSERT(cached <= num_obj - num_events); + total_cached += cached; + } + first_id = last_id + 1; + last_id += ODP_POOL_MAX_THREAD_STATS; + if (last_id >= odp_thread_count_max()) + last_id = odp_thread_count_max() - 1; + }; + + if (supported.bit.cache_available && + ODP_POOL_MAX_THREAD_STATS >= odp_thread_count_max()) + CU_ASSERT(stats.cache_available == total_cached); + } + } + + CU_ASSERT(num_events == num_obj); + num_event[i] = num_events; + + /* Allow implementation some time to update counters */ + odp_time_wait_ns(ODP_TIME_MSEC_IN_NS); + + memset(&stats, 0xff, sizeof(odp_pool_stats_t)); + memset(&selected, 0xff, sizeof(odp_pool_stats_selected_t)); + + stats.thread.first = first; + stats.thread.last = last; + num_thr = last - first + 1; + CU_ASSERT_FATAL(odp_pool_stats(pool[i], &stats) == 0); + CU_ASSERT_FATAL(odp_pool_stats_selected(pool[i], &selected, &supported) == 0); + + /* All events are allocated, available count in pool and pool + * local caches should be zero. */ + CU_ASSERT(stats.available == 0); + if (supported.bit.available) + CU_ASSERT(selected.available == 0); + CU_ASSERT(stats.cache_available == 0); + if (supported.bit.cache_available) + CU_ASSERT(selected.cache_available == 0); + if (supported.bit.thread_cache_available) { + for (j = 0; j < num_thr; j++) + CU_ASSERT(stats.thread.cache_available[j] == 0); + } + if (supported.bit.alloc_ops) { + CU_ASSERT(stats.alloc_ops > 0 && stats.alloc_ops <= num_allocs); + CU_ASSERT(selected.alloc_ops > 0 && selected.alloc_ops <= num_allocs); + } + if (supported.bit.alloc_fails) { + CU_ASSERT(stats.alloc_fails == num_fails); + CU_ASSERT(selected.alloc_fails == num_fails); + } + if (supported.bit.total_ops) { + CU_ASSERT(stats.total_ops > 0 && stats.total_ops <= num_allocs); + CU_ASSERT(selected.total_ops > 0 && selected.total_ops <= num_allocs); + } + CU_ASSERT(stats.free_ops == 0); + if (supported.bit.free_ops) + CU_ASSERT(selected.free_ops == 0); + CU_ASSERT(stats.cache_alloc_ops <= num_allocs); + if (supported.bit.cache_alloc_ops) + CU_ASSERT(selected.cache_alloc_ops <= num_allocs); + CU_ASSERT(stats.cache_free_ops == 0); + if (supported.bit.cache_free_ops) + CU_ASSERT(selected.cache_free_ops == 0); + } + + for (i = 0; i < num_pool; i++) { + odp_event_free_multi(event[i], num_event[i]); + + /* Allow implementation some time to update counters */ + odp_time_wait_ns(ODP_TIME_MSEC_IN_NS); + + stats.thread.first = odp_thread_id(); + stats.thread.last = odp_thread_id(); + CU_ASSERT_FATAL(odp_pool_stats(pool[i], &stats) == 0); + CU_ASSERT_FATAL(odp_pool_stats_selected(pool[i], &selected, &supported) == 0); + + if (supported.bit.available && supported.bit.cache_available) { + CU_ASSERT(stats.available + stats.cache_available == num_obj); + CU_ASSERT(selected.available + selected.cache_available == num_obj); + } + if (supported.bit.free_ops) { + CU_ASSERT(stats.free_ops > 0); + CU_ASSERT(selected.free_ops > 0); + } + if (supported.bit.total_ops) { + CU_ASSERT(stats.total_ops > 0); + CU_ASSERT(selected.total_ops > 0); + } + + if (i == 0) { + printf("\nPool Statistics\n---------------\n"); + printf(" available: %" PRIu64 "\n", stats.available); + printf(" alloc_ops: %" PRIu64 "\n", stats.alloc_ops); + printf(" alloc_fails: %" PRIu64 "\n", stats.alloc_fails); + printf(" free_ops: %" PRIu64 "\n", stats.free_ops); + printf(" total_ops: %" PRIu64 "\n", stats.total_ops); + printf(" cache_available: %" PRIu64 "\n", stats.cache_available); + printf(" cache_alloc_ops: %" PRIu64 "\n", stats.cache_alloc_ops); + printf(" cache_free_ops: %" PRIu64 "\n", stats.cache_free_ops); + if (supported.bit.thread_cache_available) + printf(" thread.cache_available[0]: %" PRIu64 "\n", + stats.thread.cache_available[0]); + } + + CU_ASSERT_FATAL(odp_pool_stats_reset(pool[i]) == 0); + CU_ASSERT_FATAL(odp_pool_stats(pool[i], &stats) == 0); + CU_ASSERT_FATAL(odp_pool_stats_selected(pool[i], &selected, &supported) == 0); + + CU_ASSERT(stats.alloc_ops == 0); + if (supported.bit.alloc_ops) + CU_ASSERT(selected.alloc_ops == 0); + CU_ASSERT(stats.alloc_fails == 0); + if (supported.bit.alloc_fails) + CU_ASSERT(selected.alloc_fails == 0); + CU_ASSERT(stats.free_ops == 0); + if (supported.bit.free_ops) + CU_ASSERT(selected.free_ops == 0); + CU_ASSERT(stats.total_ops == 0); + if (supported.bit.total_ops) + CU_ASSERT(selected.total_ops == 0); + CU_ASSERT(stats.cache_alloc_ops == 0); + if (supported.bit.cache_alloc_ops) + CU_ASSERT(selected.cache_alloc_ops == 0); + CU_ASSERT(stats.cache_free_ops == 0); + if (supported.bit.cache_free_ops) + CU_ASSERT(selected.cache_free_ops == 0); + + CU_ASSERT(odp_pool_destroy(pool[i]) == 0); + } +} + +static void pool_test_buffer_pool_statistics(void) +{ + pool_test_pool_statistics(ODP_POOL_BUFFER); +} + +static void pool_test_packet_pool_statistics(void) +{ + pool_test_pool_statistics(ODP_POOL_PACKET); +} + +static void pool_test_packet_vector_pool_statistics(void) +{ + pool_test_pool_statistics(ODP_POOL_VECTOR); +} + +static void pool_test_timeout_pool_statistics(void) +{ + pool_test_pool_statistics(ODP_POOL_TIMEOUT); +} + +static void pool_ext_init_packet_pool_param(odp_pool_ext_param_t *param) +{ + odp_pool_ext_capability_t capa; + uint32_t head_offset, head_align, trailer_size; + odp_pool_type_t type = ODP_POOL_PACKET; + uint32_t num_buf = EXT_NUM_BUF; + uint32_t buf_size = EXT_BUF_SIZE; + uint32_t uarea_size = EXT_UAREA_SIZE; + uint32_t headroom = EXT_HEADROOM; + uint32_t app_hdr_size = EXT_APP_HDR_SIZE; + + CU_ASSERT_FATAL(odp_pool_ext_capability(type, &capa) == 0); + + odp_pool_ext_param_init(type, param); + + if (num_buf > capa.pkt.max_num_buf) + num_buf = capa.pkt.max_num_buf; + + if (buf_size > capa.pkt.max_buf_size) + buf_size = capa.pkt.max_buf_size; + + if (uarea_size > capa.pkt.max_uarea_size) + uarea_size = capa.pkt.max_uarea_size; + + if (headroom > capa.pkt.max_headroom) + headroom = capa.pkt.max_headroom; + + head_align = capa.pkt.min_head_align; + head_offset = capa.pkt.odp_header_size + app_hdr_size; + trailer_size = capa.pkt.odp_trailer_size; + + CU_ASSERT_FATAL(head_offset < buf_size); + CU_ASSERT_FATAL((head_offset + trailer_size) < buf_size); + + while (head_offset % head_align) { + app_hdr_size++; + head_offset = capa.pkt.odp_header_size + app_hdr_size; + + if (head_offset >= buf_size) { + ODPH_ERR("Head align too large (%u). No room for data.\n", head_align); + break; + } + } + + CU_ASSERT_FATAL(head_offset < buf_size); + CU_ASSERT_FATAL((head_offset + trailer_size) < buf_size); + CU_ASSERT_FATAL((head_offset % head_align) == 0); + + param->pkt.num_buf = num_buf; + param->pkt.buf_size = buf_size; + param->pkt.app_header_size = app_hdr_size; + param->pkt.uarea_size = uarea_size; + param->pkt.headroom = headroom; +} + +static void test_packet_pool_ext_capa(void) +{ + odp_pool_ext_capability_t capa; + odp_pool_type_t type; + const odp_pool_type_t unsupported_types[] = {ODP_POOL_BUFFER, ODP_POOL_TIMEOUT, + ODP_POOL_VECTOR, ODP_POOL_DMA_COMPL, + ODP_POOL_ML_COMPL}; + const int num_types = ODPH_ARRAY_SIZE(unsupported_types); + + /* Verify operation for unsupported pool types */ + for (int i = 0; i < num_types; i++) { + type = unsupported_types[i]; + CU_ASSERT_FATAL(odp_pool_ext_capability(type, &capa) == 0); + CU_ASSERT(capa.max_pools == 0); + } + + type = ODP_POOL_PACKET; + + CU_ASSERT_FATAL(odp_pool_ext_capability(type, &capa) == 0); + + CU_ASSERT(capa.type == type); + + /* External memory pools not supported */ + if (capa.max_pools == 0) + return; + + CU_ASSERT(capa.max_pools > 0); + CU_ASSERT(capa.min_cache_size <= capa.max_cache_size); + CU_ASSERT(capa.pkt.max_num_buf > 0); + CU_ASSERT(capa.pkt.max_buf_size > 0); + CU_ASSERT(capa.pkt.min_mem_align > 0); + CU_ASSERT(TEST_CHECK_POW2(capa.pkt.min_mem_align)); + CU_ASSERT(capa.pkt.min_buf_align > 0); + CU_ASSERT(capa.pkt.min_head_align > 0); + CU_ASSERT(capa.pkt.max_headroom > 0); + CU_ASSERT(capa.pkt.max_headroom_size > 0); + CU_ASSERT(capa.pkt.max_headroom_size >= capa.pkt.max_headroom); + CU_ASSERT(capa.pkt.max_segs_per_pkt > 0); +} + +static void test_ext_param_init(uint8_t fill) +{ + odp_pool_ext_param_t param; + + memset(¶m, fill, sizeof(param)); + odp_pool_ext_param_init(ODP_POOL_PACKET, ¶m); + + CU_ASSERT(param.type == ODP_POOL_PACKET); + CU_ASSERT(param.uarea_init.init_fn == NULL); + CU_ASSERT(param.uarea_init.args == NULL); + CU_ASSERT(param.cache_size >= global_pool_ext_capa.min_cache_size && + param.cache_size <= global_pool_ext_capa.max_cache_size); + CU_ASSERT(param.stats.all == 0); + CU_ASSERT(param.pkt.app_header_size == 0); + CU_ASSERT(param.pkt.uarea_size == 0); +} + +static void test_packet_pool_ext_param_init(void) +{ + test_ext_param_init(0); + test_ext_param_init(0xff); +} + +static void test_packet_pool_ext_create(void) +{ + odp_pool_t pool; + odp_pool_ext_param_t param; + + pool_ext_init_packet_pool_param(¶m); + + pool = odp_pool_ext_create("pool_ext_0", ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void test_packet_pool_ext_lookup(void) +{ + odp_pool_t pool, pool_1; + odp_pool_ext_param_t param; + const char *name = "pool_ext_0"; + + pool_ext_init_packet_pool_param(¶m); + + pool = odp_pool_ext_create(name, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + pool_1 = odp_pool_lookup(name); + + CU_ASSERT_FATAL(pool_1 != ODP_POOL_INVALID); + CU_ASSERT(pool == pool_1); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void test_packet_pool_ext_info(void) +{ + odp_pool_t pool; + odp_pool_ext_param_t param; + odp_pool_info_t info; + const char *name = "pool_ext_0"; + + pool_ext_init_packet_pool_param(¶m); + + pool = odp_pool_ext_create(name, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + memset(&info, 0, sizeof(odp_pool_info_t)); + CU_ASSERT_FATAL(odp_pool_info(pool, &info) == 0); + + CU_ASSERT(info.pool_ext); + CU_ASSERT(strncmp(name, info.name, strlen(name)) == 0); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static void test_packet_pool_ext_long_name(void) +{ + odp_pool_t pool; + odp_pool_ext_param_t param; + odp_pool_info_t info; + char name[ODP_POOL_NAME_LEN]; + + memset(name, 'a', sizeof(name)); + name[sizeof(name) - 1] = 0; + + pool_ext_init_packet_pool_param(¶m); + pool = odp_pool_ext_create(name, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + CU_ASSERT_FATAL(pool == odp_pool_lookup(name)); + + memset(&info, 0, sizeof(odp_pool_info_t)); + CU_ASSERT_FATAL(odp_pool_info(pool, &info) == 0); + + CU_ASSERT(info.pool_ext); + CU_ASSERT(strncmp(name, info.name, strlen(name)) == 0); + + CU_ASSERT(odp_pool_destroy(pool) == 0); +} + +static odp_shm_t populate_pool(odp_pool_t pool, odp_pool_ext_capability_t *capa, + void *buf[], uint32_t num, uint32_t buf_size) +{ + odp_shm_t shm; + uint8_t *buf_ptr; + uint32_t i; + uint32_t shm_size, mem_align; + uint32_t flags = 0; + uint32_t buf_align = EXT_BUF_ALIGN; + uint32_t min_align = capa->pkt.min_buf_align; + + CU_ASSERT_FATAL(min_align > 0); + + if (min_align > buf_align) + buf_align = min_align; + + if (capa->pkt.buf_size_aligned) { + buf_align = buf_size; + CU_ASSERT_FATAL((buf_size % min_align) == 0); + } + + mem_align = buf_align; + if (capa->pkt.min_mem_align > mem_align) + mem_align = capa->pkt.min_mem_align; + + /* Prepare to align every buffer */ + shm_size = (num + 1) * (buf_size + buf_align); + + shm = odp_shm_reserve("test_pool_ext_populate", shm_size, mem_align, 0); + if (shm == ODP_SHM_INVALID) + return ODP_SHM_INVALID; + + buf_ptr = odp_shm_addr(shm); + CU_ASSERT_FATAL((uintptr_t)buf_ptr % mem_align == 0); + + /* initialize entire pool memory with a pattern */ + memset(buf_ptr, MAGIC_U8, shm_size); + + /* Move from mem_align to buf_align */ + while ((uintptr_t)buf_ptr % buf_align) + buf_ptr++; + + for (i = 0; i < num; i++) { + if (i == num - 1) + flags = ODP_POOL_POPULATE_DONE; + + buf[i] = buf_ptr; + CU_ASSERT_FATAL(odp_pool_ext_populate(pool, &buf[i], buf_size, 1, flags) == 0); + + buf_ptr += buf_size; + while ((uintptr_t)buf_ptr % buf_align) + buf_ptr++; + } + + return shm; +} + +static void test_packet_pool_ext_populate(void) +{ + odp_shm_t shm; + odp_pool_t pool; + odp_pool_ext_param_t param; + odp_pool_ext_capability_t capa; + uint32_t buf_size, num_buf; + void *buf[EXT_NUM_BUF]; + + CU_ASSERT_FATAL(odp_pool_ext_capability(ODP_POOL_PACKET, &capa) == 0); + + pool_ext_init_packet_pool_param(¶m); + num_buf = param.pkt.num_buf; + buf_size = param.pkt.buf_size; + + CU_ASSERT_FATAL(capa.pkt.min_head_align > 0); + + pool = odp_pool_ext_create("pool_ext_0", ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + shm = populate_pool(pool, &capa, buf, num_buf, buf_size); + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + + CU_ASSERT(odp_pool_destroy(pool) == 0); + CU_ASSERT(odp_shm_free(shm) == 0); +} + +static uint32_t find_buf(odp_packet_t pkt, void *buf[], uint32_t num, uint32_t head_offset) +{ + uint32_t i; + uint8_t *ptr; + uint8_t *head = odp_packet_head(pkt); + + for (i = 0; i < num; i++) { + ptr = buf[i]; + ptr += head_offset; + + if (head == ptr) + break; + } + + return i; +} + +#define PKT_LEN_NORMAL 0 +#define PKT_LEN_MAX 1 +#define PKT_LEN_SEGMENTED 2 + +static void packet_pool_ext_alloc(int len_test) +{ + odp_shm_t shm; + odp_pool_t pool; + odp_pool_ext_param_t param; + odp_pool_ext_capability_t capa; + uint32_t i, j, buf_size, num_buf, num_pkt, num_alloc, buf_index; + uint32_t pkt_len, head_offset, trailer_size, headroom, max_headroom; + uint32_t hr, tr, uarea_size, max_payload, buf_data_size, app_hdr_size; + int num_seg; + uint8_t *app_hdr; + void *buf[EXT_NUM_BUF]; + odp_packet_t pkt[EXT_NUM_BUF]; + uint32_t seg_len = 0; + + CU_ASSERT_FATAL(odp_pool_ext_capability(ODP_POOL_PACKET, &capa) == 0); + + pool_ext_init_packet_pool_param(¶m); + num_buf = param.pkt.num_buf; + buf_size = param.pkt.buf_size; + uarea_size = param.pkt.uarea_size; + + pool = odp_pool_ext_create("pool_ext_0", ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + shm = populate_pool(pool, &capa, buf, num_buf, buf_size); + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + + app_hdr_size = param.pkt.app_header_size; + head_offset = capa.pkt.odp_header_size + app_hdr_size; + max_headroom = capa.pkt.max_headroom_size; + headroom = param.pkt.headroom; + trailer_size = capa.pkt.odp_trailer_size; + buf_data_size = buf_size - head_offset - trailer_size; + max_payload = buf_data_size - max_headroom; + num_pkt = num_buf; + num_seg = 1; + + if (len_test == PKT_LEN_NORMAL) { + pkt_len = (buf_data_size - headroom) / 2; + } else if (len_test == PKT_LEN_MAX) { + pkt_len = max_payload; + } else { + CU_ASSERT_FATAL(capa.pkt.max_segs_per_pkt > 1); + /* length that results 2 segments */ + pkt_len = max_payload + (buf_size / 2); + num_seg = 2; + num_pkt = num_buf / num_seg; + } + + for (i = 0; i < num_pkt; i++) { + pkt[i] = odp_packet_alloc(pool, pkt_len); + CU_ASSERT(pkt[i] != ODP_PACKET_INVALID); + if (pkt[i] == ODP_PACKET_INVALID) + break; + + CU_ASSERT(odp_packet_is_valid(pkt[i]) == 1); + CU_ASSERT(odp_event_is_valid(odp_packet_to_event(pkt[i])) == 1); + CU_ASSERT(odp_packet_len(pkt[i]) == pkt_len); + CU_ASSERT(odp_packet_headroom(pkt[i]) >= headroom); + buf_index = find_buf(pkt[i], buf, num_buf, head_offset); + CU_ASSERT(buf_index < num_buf); + hr = (uintptr_t)odp_packet_data(pkt[i]) - (uintptr_t)odp_packet_head(pkt[i]); + CU_ASSERT(hr == odp_packet_headroom(pkt[i])); + CU_ASSERT(num_seg == odp_packet_num_segs(pkt[i])); + CU_ASSERT(odp_packet_data(pkt[i]) == odp_packet_data_seg_len(pkt[i], &seg_len)); + CU_ASSERT(odp_packet_seg_len(pkt[i]) == seg_len); + + if (num_seg == 1) { + tr = buf_data_size - hr - pkt_len; + CU_ASSERT(tr == odp_packet_tailroom(pkt[i])); + CU_ASSERT(odp_packet_seg_len(pkt[i]) == pkt_len); + } else { + odp_packet_seg_t seg = odp_packet_last_seg(pkt[i]); + uint32_t last_seg_len = odp_packet_seg_data_len(pkt[i], seg); + uint32_t max_tr = buf_data_size - last_seg_len; + + CU_ASSERT(odp_packet_tailroom(pkt[i]) <= max_tr); + CU_ASSERT(pkt_len == (odp_packet_seg_len(pkt[i]) + last_seg_len)); + } + + CU_ASSERT(odp_packet_buf_len(pkt[i]) == num_seg * buf_data_size); + + if (uarea_size) { + CU_ASSERT(odp_packet_user_area(pkt[i]) != NULL); + CU_ASSERT(odp_packet_user_area_size(pkt[i]) >= uarea_size); + } + + /* Check that application header content has not changed */ + app_hdr = (uint8_t *)odp_packet_head(pkt[i]) - app_hdr_size; + for (j = 0; j < app_hdr_size; j++) + CU_ASSERT(app_hdr[j] == MAGIC_U8); + } + + num_alloc = i; + CU_ASSERT(num_alloc == num_pkt); + + /* Pool is now empty */ + CU_ASSERT(odp_packet_alloc(pool, pkt_len) == ODP_PACKET_INVALID); + + for (i = 0; i < num_alloc; i++) + odp_packet_free(pkt[i]); + + CU_ASSERT(odp_pool_destroy(pool) == 0); + CU_ASSERT(odp_shm_free(shm) == 0); +} + +static void test_packet_pool_ext_alloc(void) +{ + packet_pool_ext_alloc(PKT_LEN_NORMAL); +} + +static void test_packet_pool_ext_uarea_init(void) +{ + odp_pool_ext_capability_t capa; + odp_pool_ext_param_t param; + uint32_t num = ELEM_NUM, i; + uint32_t max_payload; + odp_pool_t pool; + uarea_init_t data; + odp_shm_t shm; + uint8_t *uarea; + + CU_ASSERT_FATAL(odp_pool_ext_capability(ODP_POOL_PACKET, &capa) == 0); + + memset(&data, 0, sizeof(uarea_init_t)); + pool_ext_init_packet_pool_param(¶m); + param.uarea_init.init_fn = init_event_uarea; + param.uarea_init.args = &data; + num = ODPH_MIN(num, param.pkt.num_buf); + param.pkt.num_buf = num; + param.pkt.uarea_size = 1; + pool = odp_pool_ext_create(NULL, ¶m); + + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + void *buf[num]; + odp_packet_t pkts[num]; + + shm = populate_pool(pool, &capa, buf, num, param.pkt.buf_size); + + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + CU_ASSERT(data.count == num); + + max_payload = param.pkt.buf_size; + max_payload -= capa.pkt.odp_header_size + param.pkt.app_header_size; + max_payload -= capa.pkt.max_headroom_size; + max_payload -= capa.pkt.odp_trailer_size; + for (i = 0; i < num; i++) { + CU_ASSERT(data.mark[i] == 1); + + pkts[i] = odp_packet_alloc(pool, max_payload); + + CU_ASSERT(pkts[i] != ODP_PACKET_INVALID); + + if (pkts[i] == ODP_PACKET_INVALID) + break; + + uarea = odp_packet_user_area(pkts[i]); + + CU_ASSERT(*uarea == UAREA); + } + + odp_packet_free_multi(pkts, i); + odp_pool_destroy(pool); + odp_shm_free(shm); +} + +static void test_packet_pool_ext_alloc_max(void) +{ + packet_pool_ext_alloc(PKT_LEN_MAX); +} + +static void test_packet_pool_ext_alloc_seg(void) +{ + packet_pool_ext_alloc(PKT_LEN_SEGMENTED); +} + +static void test_packet_pool_ext_disassemble(void) +{ + odp_shm_t shm; + odp_pool_t pool; + odp_pool_ext_param_t param; + odp_pool_ext_capability_t capa; + uint32_t i, j, buf_size, num_buf, num_pkt, num_alloc, buf_index; + uint32_t pkt_len, head_offset, trailer_size, headroom, max_headroom; + uint32_t hr, max_payload, buf_data_size; + uint32_t num_seg; + void *buf[EXT_NUM_BUF]; + odp_packet_t pkt_tbl[EXT_NUM_BUF]; + + CU_ASSERT_FATAL(odp_pool_ext_capability(ODP_POOL_PACKET, &capa) == 0); + CU_ASSERT_FATAL(capa.pkt.max_segs_per_pkt > 1); + + pool_ext_init_packet_pool_param(¶m); + num_buf = param.pkt.num_buf; + buf_size = param.pkt.buf_size; + + pool = odp_pool_ext_create("pool_ext_0", ¶m); + CU_ASSERT_FATAL(pool != ODP_POOL_INVALID); + + shm = populate_pool(pool, &capa, buf, num_buf, buf_size); + CU_ASSERT_FATAL(shm != ODP_SHM_INVALID); + + head_offset = capa.pkt.odp_header_size + param.pkt.app_header_size; + max_headroom = capa.pkt.max_headroom_size; + headroom = param.pkt.headroom; + trailer_size = capa.pkt.odp_trailer_size; + buf_data_size = buf_size - head_offset - trailer_size; + max_payload = buf_data_size - max_headroom; + + /* length that results 2 segments */ + pkt_len = max_payload + (buf_size / 2); + num_seg = 2; + num_pkt = num_buf / num_seg; + + for (i = 0; i < num_pkt; i++) { + odp_packet_t pkt; + odp_packet_seg_t seg; + uint32_t num_pkt_buf, data_offset, data_len; + void *head, *data, *pkt_head; + odp_packet_buf_t pkt_buf[num_seg]; + void *seg_data[num_seg]; + uint32_t seg_len[num_seg]; + + pkt = odp_packet_alloc(pool, pkt_len); + pkt_tbl[i] = pkt; + CU_ASSERT(pkt != ODP_PACKET_INVALID); + if (pkt == ODP_PACKET_INVALID) + break; + + CU_ASSERT(odp_packet_len(pkt) == pkt_len); + CU_ASSERT(odp_packet_headroom(pkt) >= headroom); + buf_index = find_buf(pkt, buf, num_buf, head_offset); + CU_ASSERT(buf_index < num_buf); + pkt_head = odp_packet_head(pkt); + hr = (uintptr_t)odp_packet_data(pkt) - (uintptr_t)pkt_head; + CU_ASSERT(hr == odp_packet_headroom(pkt)); + CU_ASSERT((int)num_seg == odp_packet_num_segs(pkt)); + + seg = odp_packet_first_seg(pkt); + for (j = 0; j < num_seg; j++) { + seg_data[j] = odp_packet_seg_data(pkt, seg); + seg_len[j] = odp_packet_seg_data_len(pkt, seg); + seg = odp_packet_next_seg(pkt, seg); + } + + CU_ASSERT(odp_packet_data(pkt) == seg_data[0]); + CU_ASSERT(odp_packet_seg_len(pkt) == seg_len[0]) + + /* Disassemble packet */ + num_pkt_buf = odp_packet_disassemble(pkt, pkt_buf, num_seg); + CU_ASSERT_FATAL(num_pkt_buf == num_seg); + + CU_ASSERT(odp_packet_buf_head(pkt_buf[0]) == pkt_head); + CU_ASSERT(odp_packet_buf_data_offset(pkt_buf[0]) == hr); + + for (j = 0; j < num_seg; j++) { + CU_ASSERT(odp_packet_buf_size(pkt_buf[j]) == buf_data_size); + + head = odp_packet_buf_head(pkt_buf[j]); + data_offset = odp_packet_buf_data_offset(pkt_buf[j]); + data = (uint8_t *)head + data_offset; + CU_ASSERT(seg_data[j] == data); + data_len = odp_packet_buf_data_len(pkt_buf[j]); + CU_ASSERT(seg_len[j] == data_len); + + CU_ASSERT(odp_packet_buf_from_head(pool, head) == pkt_buf[j]); + + /* Pull in head and tail by one byte */ + odp_packet_buf_data_set(pkt_buf[j], data_offset + 1, data_len - 2); + CU_ASSERT(odp_packet_buf_data_offset(pkt_buf[j]) == data_offset + 1); + CU_ASSERT(odp_packet_buf_data_len(pkt_buf[j]) == data_len - 2); + } + + /* Reassemble packet, each segment is now 2 bytes shorter */ + pkt = odp_packet_reassemble(pool, pkt_buf, num_seg); + + CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID); + CU_ASSERT(odp_packet_num_segs(pkt) == (int)num_seg); + pkt_tbl[i] = pkt; + + CU_ASSERT(odp_packet_len(pkt) == (pkt_len - (num_seg * 2))); + } + + num_alloc = i; + CU_ASSERT(num_alloc == num_pkt); + + /* Pool is now empty */ + CU_ASSERT(odp_packet_alloc(pool, pkt_len) == ODP_PACKET_INVALID); + + for (i = 0; i < num_alloc; i++) + odp_packet_free(pkt_tbl[i]); + + CU_ASSERT(odp_pool_destroy(pool) == 0); + CU_ASSERT(odp_shm_free(shm) == 0); +} + +static int pool_suite_init(void) +{ + memset(&global_pool_capa, 0, sizeof(odp_pool_capability_t)); + memset(&default_pool_param, 0, sizeof(odp_pool_param_t)); + + if (odp_pool_capability(&global_pool_capa) < 0) { + ODPH_ERR("odp_pool_capability() failed in suite init\n"); + return -1; + } + + odp_pool_param_init(&default_pool_param); + + return 0; +} + +static int pool_ext_suite_init(void) +{ + memset(&global_pool_ext_capa, 0, sizeof(odp_pool_ext_capability_t)); + + if (odp_pool_ext_capability(ODP_POOL_PACKET, &global_pool_ext_capa)) { + ODPH_ERR("Pool ext capa failed in suite init\n"); + return -1; + } + + if (global_pool_ext_capa.type != ODP_POOL_PACKET) { + ODPH_ERR("Bad type from pool ext capa in suite init\n"); + return -1; + } + + return 0; +} + +static int check_pool_ext_support(void) +{ + if (global_pool_ext_capa.max_pools == 0) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int check_pool_ext_uarea_init_support(void) +{ + if (global_pool_ext_capa.max_pools == 0 || !global_pool_ext_capa.pkt.uarea_persistence || + global_pool_ext_capa.pkt.max_uarea_size == 0) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +static int check_pool_ext_segment_support(void) +{ + if (global_pool_ext_capa.max_pools == 0 || global_pool_ext_capa.pkt.max_segs_per_pkt < 2) + return ODP_TEST_INACTIVE; + + return ODP_TEST_ACTIVE; +} + +odp_testinfo_t pool_suite[] = { + ODP_TEST_INFO(pool_test_param_init), + ODP_TEST_INFO(pool_test_create_destroy_buffer), + ODP_TEST_INFO(pool_test_create_destroy_packet), + ODP_TEST_INFO(pool_test_create_destroy_timeout), + ODP_TEST_INFO(pool_test_create_destroy_vector), + ODP_TEST_INFO_CONDITIONAL(pool_test_buffer_uarea_init, pool_check_buffer_uarea_init), + ODP_TEST_INFO_CONDITIONAL(pool_test_packet_uarea_init, pool_check_packet_uarea_init), + ODP_TEST_INFO_CONDITIONAL(pool_test_vector_uarea_init, pool_check_vector_uarea_init), + ODP_TEST_INFO_CONDITIONAL(pool_test_timeout_uarea_init, pool_check_timeout_uarea_init), + ODP_TEST_INFO(pool_test_lookup_info_print), + ODP_TEST_INFO(pool_test_long_name), + ODP_TEST_INFO(pool_test_same_name_buf), + ODP_TEST_INFO(pool_test_same_name_pkt), + ODP_TEST_INFO(pool_test_same_name_tmo), + ODP_TEST_INFO(pool_test_same_name_vec), + ODP_TEST_INFO(pool_test_alloc_buffer), + ODP_TEST_INFO(pool_test_alloc_buffer_min_cache), + ODP_TEST_INFO(pool_test_alloc_buffer_max_cache), + ODP_TEST_INFO(pool_test_alloc_packet_vector), + ODP_TEST_INFO(pool_test_alloc_packet_vector_min_cache), + ODP_TEST_INFO(pool_test_alloc_packet_vector_max_cache), + ODP_TEST_INFO(pool_test_alloc_packet), + ODP_TEST_INFO(pool_test_alloc_packet_min_cache), + ODP_TEST_INFO(pool_test_alloc_packet_max_cache), + ODP_TEST_INFO(pool_test_alloc_packet_subparam), + ODP_TEST_INFO(pool_test_alloc_timeout), + ODP_TEST_INFO(pool_test_alloc_timeout_min_cache), + ODP_TEST_INFO(pool_test_alloc_timeout_max_cache), + ODP_TEST_INFO(pool_test_info_packet), + ODP_TEST_INFO(pool_test_info_data_range), + ODP_TEST_INFO(pool_test_buf_max_num), + ODP_TEST_INFO(pool_test_pkt_max_num), + ODP_TEST_INFO(pool_test_packet_vector_max_num), + ODP_TEST_INFO(pool_test_pkt_seg_len), + ODP_TEST_INFO(pool_test_tmo_max_num), + ODP_TEST_INFO(pool_test_create_after_fork), + ODP_TEST_INFO(pool_test_pool_index), + ODP_TEST_INFO(pool_test_create_max_pkt_pools), + ODP_TEST_INFO_CONDITIONAL(pool_test_buffer_pool_statistics, + pool_check_buffer_pool_statistics), + ODP_TEST_INFO_CONDITIONAL(pool_test_packet_pool_statistics, + pool_check_packet_pool_statistics), + ODP_TEST_INFO_CONDITIONAL(pool_test_packet_vector_pool_statistics, + pool_check_packet_vector_pool_statistics), + ODP_TEST_INFO_CONDITIONAL(pool_test_timeout_pool_statistics, + pool_check_timeout_pool_statistics), + ODP_TEST_INFO_NULL, +}; + +odp_testinfo_t pool_ext_suite[] = { + ODP_TEST_INFO(test_packet_pool_ext_capa), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_param_init, check_pool_ext_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_create, check_pool_ext_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_lookup, check_pool_ext_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_info, check_pool_ext_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_long_name, check_pool_ext_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_populate, check_pool_ext_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_alloc, check_pool_ext_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_uarea_init, + check_pool_ext_uarea_init_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_alloc_max, check_pool_ext_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_alloc_seg, check_pool_ext_segment_support), + ODP_TEST_INFO_CONDITIONAL(test_packet_pool_ext_disassemble, check_pool_ext_segment_support), + ODP_TEST_INFO_NULL, +}; + +odp_suiteinfo_t pool_suites[] = { + { .name = "Pool tests", + .testinfo_tbl = pool_suite, + .init_func = pool_suite_init, + }, + { .name = "Ext mem pool tests", + .testinfo_tbl = pool_ext_suite, + .init_func = pool_ext_suite_init, + }, + ODP_SUITE_INFO_NULL, +}; + +int main(int argc, char *argv[]) +{ + int ret; + + /* parse common options: */ + if (odp_cunit_parse_options(&argc, argv)) + return -1; + + ret = odp_cunit_register(pool_suites); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} |