From patchwork Mon Apr 1 01:37:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aditya Ambadipudi X-Patchwork-Id: 139013 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8198243D9B; Mon, 1 Apr 2024 03:37:59 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 96FBB402E2; Mon, 1 Apr 2024 03:37:45 +0200 (CEST) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mails.dpdk.org (Postfix) with ESMTP id 3A2FA402D1 for ; Mon, 1 Apr 2024 03:37:43 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1B2351474; Sun, 31 Mar 2024 18:38:15 -0700 (PDT) Received: from 2u-thunderx2.usa.Arm.com (unknown [10.118.12.78]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 3D68E3F64C; Sun, 31 Mar 2024 18:37:42 -0700 (PDT) From: Aditya Ambadipudi To: dev@dpdk.org, jackmin@nvidia.com, stephen@networkplumber.org, matan@nvidia.com, viacheslavo@nvidia.com, roretzla@linux.microsoft.com, konstantin.v.ananyev@yandex.ru, konstantin.ananyev@huawei.com, mb@smartsharesystems.com, hofors@lysator.liu.se Cc: Honnappa.Nagarahalli@arm.com, Dhruv.Tripathi@arm.com, wathsala.vithanage@arm.com, aditya.ambadipudi@arm.com, ganeshaditya1@gmail.com, nd@arm.com, Honnappa Nagarahalli Subject: [PATCH v1 2/2] deque: add unit tests for the deque library Date: Sun, 31 Mar 2024 20:37:29 -0500 Message-Id: <20240401013729.1466298-3-aditya.ambadipudi@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240401013729.1466298-1-aditya.ambadipudi@arm.com> References: <20230821060420.3509667-1-honnappa.nagarahalli@arm.com> <20240401013729.1466298-1-aditya.ambadipudi@arm.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Add unit test cases that test all of the enqueue/dequeue functions. Both normal enqueue/dequeue functions and the zerocopy API functions. Signed-off-by: Aditya Ambadipudi Reviewed-by: Honnappa Nagarahalli --- app/test/meson.build | 2 + app/test/test_deque_enqueue_dequeue.c | 1231 ++++++++++++++++++++++++ app/test/test_deque_helper_functions.c | 170 ++++ 3 files changed, 1403 insertions(+) create mode 100644 app/test/test_deque_enqueue_dequeue.c create mode 100644 app/test/test_deque_helper_functions.c diff --git a/app/test/meson.build b/app/test/meson.build index 7d909039ae..8913050c9b 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -60,6 +60,8 @@ source_file_deps = { 'test_cryptodev_security_tls_record.c': ['cryptodev', 'security'], 'test_cycles.c': [], 'test_debug.c': [], + 'test_deque_enqueue_dequeue.c': ['deque'], + 'test_deque_helper_functions.c': ['deque'], 'test_devargs.c': ['kvargs'], 'test_dispatcher.c': ['dispatcher'], 'test_distributor.c': ['distributor'], diff --git a/app/test/test_deque_enqueue_dequeue.c b/app/test/test_deque_enqueue_dequeue.c new file mode 100644 index 0000000000..35f2dd4451 --- /dev/null +++ b/app/test/test_deque_enqueue_dequeue.c @@ -0,0 +1,1231 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Arm Limited + */ + + +#include "test.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct rte_deque *deque; + +static const int esize[] = {4, 8, 16, 20}; +#define DEQUE_SIZE 4096 +#define MAX_BULK 32 +#define TEST_DEQUE_FULL_EMPTY_ITER 8 + +/* + * Validate the return value of test cases and print details of the + * deque if validation fails + * + * @param exp + * Expression to validate return value. + * @param r + * A pointer to the deque structure. + */ +#define TEST_DEQUE_VERIFY(exp, d, errst) do { \ + if (!(exp)) { \ + printf("error at %s:%d\tcondition " #exp " failed\n", \ + __func__, __LINE__); \ + rte_deque_dump(stdout, (d)); \ + errst; \ + } \ +} while (0) + +static int +test_deque_mem_cmp(void *src, void *dst, unsigned int size) +{ + int ret; + + ret = memcmp(src, dst, size); + if (ret) { + rte_hexdump(stdout, "src", src, size); + rte_hexdump(stdout, "dst", dst, size); + printf("data after dequeue is not the same\n"); + } + + return ret; +} + +static int +test_deque_mem_cmp_rvs(void *src, void *dst, + unsigned int count, unsigned int esize) +{ + int ret = 0; + uint32_t *src32 = ((uint32_t *)src), *dst32 = ((uint32_t *)dst); + uint32_t scale = esize/(sizeof(uint32_t)); + + /* Start at the end of the dst and compare from there.*/ + dst32 += (count - 1) * scale; + for (unsigned int i = 0; i < count; i++) { + for (unsigned int j = 0; j < scale; j++) { + if (src32[j] != dst32[j]) { + ret = -1; + break; + } + } + if (ret) + break; + dst32 -= scale; + src32 += scale; + } + if (ret) { + rte_hexdump(stdout, "src", src, count * esize); + rte_hexdump(stdout, "dst", dst, count * esize); + printf("data after dequeue is not the same\n"); + } + + return ret; +} + +static inline void * +test_deque_calloc(unsigned int dsize, int esize) +{ + void *p; + + p = rte_zmalloc(NULL, dsize * esize, RTE_CACHE_LINE_SIZE); + if (p == NULL) + printf("Failed to allocate memory\n"); + + return p; +} + +static void +test_deque_mem_init(void *obj, unsigned int count, int esize) +{ + for (unsigned int i = 0; i < (count * esize / sizeof(uint32_t)); i++) + ((uint32_t *)obj)[i] = i; +} + +static inline void * +test_deque_inc_ptr(void *obj, int esize, unsigned int n) +{ + return (void *)((uint32_t *)obj + (n * esize / sizeof(uint32_t))); +} + +/* Copy to the deque memory */ +static inline void +test_deque_zc_copy_to_deque(struct rte_deque_zc_data *zcd, const void *src, int esize, + unsigned int num) +{ + memcpy(zcd->ptr1, src, esize * zcd->n1); + if (zcd->n1 != num) { + const void *inc_src = (const void *)((const char *)src + + (zcd->n1 * esize)); + memcpy(zcd->ptr2, inc_src, esize * (num - zcd->n1)); + } +} + +static inline void +test_deque_zc_copy_to_deque_rev(struct rte_deque_zc_data *zcd, const void *src, + int esize, unsigned int num) +{ + void *ptr1 = zcd->ptr1; + for (unsigned int i = 0; i < zcd->n1; i++) { + memcpy(ptr1, src, esize); + src = (const void *)((const char *)src + esize); + ptr1 = (void *)((char *)ptr1 - esize); + } + if (zcd->n1 != num) { + void *ptr2 = zcd->ptr2; + for (unsigned int i = 0; i < (num - zcd->n1); i++) { + memcpy(ptr2, src, esize); + src = (const void *)((const char *)src + esize); + ptr2 = (void *)((char *)ptr2 - esize); + } + } +} + +/* Copy from the deque memory */ +static inline void +test_deque_zc_copy_from_deque(struct rte_deque_zc_data *zcd, void *dst, int esize, + unsigned int num) +{ + memcpy(dst, zcd->ptr1, esize * zcd->n1); + + if (zcd->n1 != num) { + dst = test_deque_inc_ptr(dst, esize, zcd->n1); + memcpy(dst, zcd->ptr2, esize * (num - zcd->n1)); + } +} + +static inline void +test_deque_zc_copy_from_deque_rev(struct rte_deque_zc_data *zcd, void *dst, int esize, + unsigned int num) +{ + void *ptr1 = zcd->ptr1; + for (unsigned int i = 0; i < zcd->n1; i++) { + memcpy(dst, ptr1, esize); + dst = (void *)((char *)dst + esize); + ptr1 = (void *)((char *)ptr1 - esize); + } + if (zcd->n1 != num) { + void *ptr2 = zcd->ptr2; + for (unsigned int i = 0; i < (num - zcd->n1); i++) { + memcpy(dst, ptr2, esize); + dst = (void *)((char *)dst + esize); + ptr2 = (void *)((char *)ptr2 - esize); + } + } +} + +/* Wrappers around the zero-copy APIs. The wrappers match + * the normal enqueue/dequeue API declarations. + */ +static unsigned int +test_deque_enqueue_zc_bulk_elem(struct rte_deque *d, const void *obj_table, + unsigned int esize, unsigned int n, unsigned int *free_space) +{ + uint32_t ret; + struct rte_deque_zc_data zcd; + + ret = rte_deque_enqueue_zc_bulk_elem_start(d, esize, n, + &zcd, free_space); + if (ret != 0) { + /* Copy the data to the deque */ + test_deque_zc_copy_to_deque(&zcd, obj_table, esize, ret); + rte_deque_enqueue_zc_elem_finish(d, ret); + } + + return ret; +} + +static unsigned int +test_deque_dequeue_zc_bulk_elem(struct rte_deque *d, void *obj_table, + unsigned int esize, unsigned int n, unsigned int *available) +{ + unsigned int ret; + struct rte_deque_zc_data zcd; + + ret = rte_deque_dequeue_zc_bulk_elem_start(d, esize, n, + &zcd, available); + if (ret != 0) { + /* Copy the data from the deque */ + test_deque_zc_copy_from_deque(&zcd, obj_table, esize, ret); + rte_deque_dequeue_zc_elem_finish(d, ret); + } + + return ret; +} + +static unsigned int +test_deque_enqueue_zc_burst_elem(struct rte_deque *d, const void *obj_table, + unsigned int esize, unsigned int n, unsigned int *free_space) +{ + uint32_t ret; + struct rte_deque_zc_data zcd; + + ret = rte_deque_enqueue_zc_burst_elem_start(d, esize, n, + &zcd, free_space); + if (ret != 0) { + /* Copy the data to the deque */ + test_deque_zc_copy_to_deque(&zcd, obj_table, esize, ret); + rte_deque_enqueue_zc_elem_finish(d, ret); + } + + return ret; +} + +static unsigned int +test_deque_dequeue_zc_burst_elem(struct rte_deque *d, void *obj_table, + unsigned int esize, unsigned int n, unsigned int *available) +{ + unsigned int ret; + struct rte_deque_zc_data zcd; + + ret = rte_deque_dequeue_zc_burst_elem_start(d, esize, n, + &zcd, available); + if (ret != 0) { + /* Copy the data from the deque */ + test_deque_zc_copy_from_deque(&zcd, obj_table, esize, ret); + rte_deque_dequeue_zc_elem_finish(d, ret); + } + return ret; +} + +static unsigned int +test_deque_enqueue_zc_bulk_elem_tail(struct rte_deque *d, const void *obj_table, + unsigned int esize, unsigned int n, unsigned int *free_space) +{ + uint32_t ret; + struct rte_deque_zc_data zcd; + + ret = rte_deque_enqueue_zc_bulk_elem_tail_start(d, esize, n, + &zcd, free_space); + if (ret != 0) { + /* Copy the data to the deque */ + test_deque_zc_copy_to_deque_rev(&zcd, obj_table, esize, ret); + rte_deque_enqueue_zc_elem_tail_finish(d, ret); + } + + return ret; +} + +static unsigned int +test_deque_dequeue_zc_bulk_elem_head(struct rte_deque *d, void *obj_table, + unsigned int esize, unsigned int n, unsigned int *available) +{ + unsigned int ret; + struct rte_deque_zc_data zcd; + + ret = rte_deque_dequeue_zc_bulk_elem_head_start(d, esize, n, + &zcd, available); + if (ret != 0) { + /* Copy the data from the deque */ + test_deque_zc_copy_from_deque_rev(&zcd, obj_table, esize, ret); + rte_deque_dequeue_zc_elem_head_finish(d, ret); + } + return ret; +} + +static unsigned int +test_deque_enqueue_zc_burst_elem_tail(struct rte_deque *d, + const void *obj_table, unsigned int esize, unsigned int n, + unsigned int *free_space) +{ + uint32_t ret; + struct rte_deque_zc_data zcd; + + ret = rte_deque_enqueue_zc_burst_elem_tail_start(d, esize, n, + &zcd, free_space); + if (ret != 0) { + /* Copy the data to the deque */ + test_deque_zc_copy_to_deque_rev(&zcd, obj_table, esize, ret); + rte_deque_enqueue_zc_elem_tail_finish(d, ret); + } + + return ret; +} + +static unsigned int +test_deque_dequeue_zc_burst_elem_head(struct rte_deque *d, void *obj_table, + unsigned int esize, unsigned int n, unsigned int *available) +{ + unsigned int ret; + struct rte_deque_zc_data zcd; + + ret = rte_deque_dequeue_zc_burst_elem_head_start(d, esize, n, + &zcd, available); + if (ret != 0) { + /* Copy the data from the deque */ + test_deque_zc_copy_from_deque_rev(&zcd, obj_table, esize, ret); + rte_deque_dequeue_zc_elem_head_finish(d, ret); + } + return ret; +} + +#define TEST_DEQUE_ELEM_BULK 8 +#define TEST_DEQUE_ELEM_BURST 16 +static const struct { + const char *desc; + const int api_flags; + unsigned int (*enq)(struct rte_deque *d, const void *obj_table, + unsigned int esize, unsigned int n, + unsigned int *free_space); + unsigned int (*deq)(struct rte_deque *d, void *obj_table, + unsigned int esize, unsigned int n, + unsigned int *available); + /* This dequeues in the opposite direction of enqueue. + * This is used for testing stack behavior + */ + unsigned int (*deq_opp)(struct rte_deque *d, void *obj_table, + unsigned int esize, unsigned int n, + unsigned int *available); +} test_enqdeq_impl[] = { + { + .desc = "Deque forward direction bulkmode", + .api_flags = TEST_DEQUE_ELEM_BULK, + .enq = rte_deque_enqueue_bulk_elem, + .deq = rte_deque_dequeue_bulk_elem, + .deq_opp = rte_deque_dequeue_at_head_bulk_elem, + }, + { + .desc = "Deque forward direction burstmode", + .api_flags = TEST_DEQUE_ELEM_BURST, + .enq = rte_deque_enqueue_burst_elem, + .deq = rte_deque_dequeue_burst_elem, + .deq_opp = rte_deque_dequeue_at_head_burst_elem, + }, + { + .desc = "Deque reverse direction bulkmode", + .api_flags = TEST_DEQUE_ELEM_BULK, + .enq = rte_deque_enqueue_at_tail_bulk_elem, + .deq = rte_deque_dequeue_at_head_bulk_elem, + .deq_opp = rte_deque_dequeue_bulk_elem, + }, + { + .desc = "Deque reverse direction burstmode", + .api_flags = TEST_DEQUE_ELEM_BURST, + .enq = rte_deque_enqueue_at_tail_burst_elem, + .deq = rte_deque_dequeue_at_head_burst_elem, + .deq_opp = rte_deque_dequeue_burst_elem, + }, + { + .desc = "Deque forward direction bulkmode zero copy", + .api_flags = TEST_DEQUE_ELEM_BULK, + .enq = test_deque_enqueue_zc_bulk_elem, + .deq = test_deque_dequeue_zc_bulk_elem, + .deq_opp = test_deque_dequeue_zc_bulk_elem_head, + }, + { + .desc = "Deque forward direction burstmode zero copy", + .api_flags = TEST_DEQUE_ELEM_BURST, + .enq = test_deque_enqueue_zc_burst_elem, + .deq = test_deque_dequeue_zc_burst_elem, + .deq_opp = test_deque_dequeue_zc_burst_elem_head, + }, + { + .desc = "Deque reverse direction bulkmode zero copy", + .api_flags = TEST_DEQUE_ELEM_BULK, + .enq = test_deque_enqueue_zc_bulk_elem_tail, + .deq = test_deque_dequeue_zc_bulk_elem_head, + .deq_opp = test_deque_dequeue_zc_bulk_elem, + }, + { + .desc = "Deque reverse direction burstmode zero copy", + .api_flags = TEST_DEQUE_ELEM_BURST, + .enq = test_deque_enqueue_zc_burst_elem_tail, + .deq = test_deque_dequeue_zc_burst_elem_head, + .deq_opp = test_deque_dequeue_zc_burst_elem, + }, +}; + +/* + * Burst and bulk operations in regular mode and zero copy mode. + * Random number of elements are enqueued and dequeued. + */ +static int +test_deque_burst_bulk_tests1(unsigned int test_idx) +{ + struct rte_deque *d; + void *src = NULL, *cur_src = NULL, *dst = NULL, *cur_dst = NULL; + unsigned int ret; + unsigned int i, j, temp_sz, free_space, available; + const unsigned int dsz = DEQUE_SIZE - 1; + + for (i = 0; i < RTE_DIM(esize); i++) { + printf("\n%s, esize: %d\n", test_enqdeq_impl[test_idx].desc, + esize[i]); + + /* Create the deque */ + static const char *DEQUE_NAME = "Over the boundary deque."; + d = rte_deque_create(DEQUE_NAME, esize[i], DEQUE_SIZE, 0, 0); + + /* alloc dummy object pointers */ + src = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (src == NULL) + goto fail; + + test_deque_mem_init(src, DEQUE_SIZE * 2, esize[i]); + cur_src = src; + + /* alloc some room for copied objects */ + dst = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (dst == NULL) + goto fail; + cur_dst = dst; + + printf("Random full/empty test\n"); + + for (j = 0; j != TEST_DEQUE_FULL_EMPTY_ITER; j++) { + /* random shift in the deque */ + int rand = RTE_MAX(rte_rand() % DEQUE_SIZE, 1UL); + printf("%s: iteration %u, random shift: %u;\n", + __func__, i, rand); + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + rand, &free_space); + TEST_DEQUE_VERIFY(ret == (unsigned int)rand, d, goto fail); + + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, esize[i], + rand, &available); + TEST_DEQUE_VERIFY(ret == (unsigned int)rand, d, goto fail); + + /* fill the deque */ + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, + esize[i], dsz, + &free_space); + TEST_DEQUE_VERIFY(ret == (int)dsz, d, goto fail); + + TEST_DEQUE_VERIFY(rte_deque_free_count(d) == 0, d, + goto fail); + TEST_DEQUE_VERIFY(dsz == rte_deque_count(d), d, + goto fail); + TEST_DEQUE_VERIFY(rte_deque_full(d), d, goto fail); + TEST_DEQUE_VERIFY(rte_deque_empty(d) == 0, d, goto fail); + + /* empty the deque */ + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, + esize[i], dsz, + &available); + TEST_DEQUE_VERIFY(ret == (int)dsz, d, goto fail); + + TEST_DEQUE_VERIFY(dsz == rte_deque_free_count(d), d, + goto fail); + TEST_DEQUE_VERIFY(rte_deque_count(d) == 0, d, goto fail); + TEST_DEQUE_VERIFY(rte_deque_full(d) == 0, d, goto fail); + TEST_DEQUE_VERIFY(rte_deque_empty(d), d, goto fail); + + /* check data */ + temp_sz = dsz * esize[i]; + TEST_DEQUE_VERIFY(test_deque_mem_cmp(src, dst, temp_sz) == 0, + d, goto fail); + } + + /* Free memory before test completed */ + rte_deque_free(d); + rte_free(src); + rte_free(dst); + d = NULL; + src = NULL; + dst = NULL; + } + + return 0; +fail: + rte_deque_free(d); + rte_free(src); + rte_free(dst); + return -1; +} + +/* + * Burst and bulk operations with regular & zero copy mode. + * Sequence of simple enqueues/dequeues and validate the enqueued and + * dequeued data. + */ +static int +test_deque_burst_bulk_tests2(unsigned int test_idx) +{ + struct rte_deque *d; + void *src = NULL, *cur_src = NULL, *dst = NULL, *cur_dst = NULL; + int ret; + unsigned int i, free_space, available; + + for (i = 0; i < RTE_DIM(esize); i++) { + printf("\n%s, esize: %d\n", test_enqdeq_impl[test_idx].desc, + esize[i]); + + + /* Create the deque */ + static const char *DEQUE_NAME = "Multiple enqs, deqs."; + d = rte_deque_create(DEQUE_NAME, esize[i], DEQUE_SIZE, 0, 0); + + /* alloc dummy object pointers */ + src = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (src == NULL) + goto fail; + + test_deque_mem_init(src, DEQUE_SIZE * 2, esize[i]); + cur_src = src; + + /* alloc some room for copied objects */ + dst = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (dst == NULL) + goto fail; + cur_dst = dst; + + printf("enqueue 1 obj\n"); + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + 1, &free_space); + TEST_DEQUE_VERIFY(ret == 1, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], 1); + + printf("enqueue 2 objs\n"); + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + 2, &free_space); + TEST_DEQUE_VERIFY(ret == 2, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], 2); + + printf("enqueue MAX_BULK objs\n"); + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + MAX_BULK, &free_space); + TEST_DEQUE_VERIFY(ret == MAX_BULK, d, goto fail); + + printf("dequeue 1 obj\n"); + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, esize[i], + 1, &available); + TEST_DEQUE_VERIFY(ret == 1, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], 1); + + printf("dequeue 2 objs\n"); + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, esize[i], + 2, &available); + TEST_DEQUE_VERIFY(ret == 2, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], 2); + + printf("dequeue MAX_BULK objs\n"); + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, esize[i], + MAX_BULK, &available); + TEST_DEQUE_VERIFY(ret == MAX_BULK, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], MAX_BULK); + + /* check data */ + TEST_DEQUE_VERIFY(test_deque_mem_cmp(src, dst, + RTE_PTR_DIFF(cur_dst, dst)) == 0, + d, goto fail); + + /* Free memory before test completed */ + rte_deque_free(d); + rte_free(src); + rte_free(dst); + d = NULL; + src = NULL; + dst = NULL; + } + + return 0; +fail: + rte_deque_free(d); + rte_free(src); + rte_free(dst); + return -1; +} + +/* + * Burst and bulk operations with normal mode & zero copy mode. + * Enqueue and dequeue to cover the entire deque length. + */ +static int +test_deque_burst_bulk_tests3(unsigned int test_idx) +{ + struct rte_deque *d; + void *src = NULL, *cur_src = NULL, *dst = NULL, *cur_dst = NULL; + int ret; + unsigned int i, j, free_space, available; + + for (i = 0; i < RTE_DIM(esize); i++) { + printf("\n%s, esize: %d\n", test_enqdeq_impl[test_idx].desc, + esize[i]); + + /* Create the deque */ + static const char *DEQUE_NAME = "Full deque length test"; + d = rte_deque_create(DEQUE_NAME, esize[i], DEQUE_SIZE, 0, 0); + + /* alloc dummy object pointers */ + src = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (src == NULL) + goto fail; + test_deque_mem_init(src, DEQUE_SIZE * 2, esize[i]); + cur_src = src; + + /* alloc some room for copied objects */ + dst = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (dst == NULL) + goto fail; + cur_dst = dst; + + printf("fill and empty the deque\n"); + for (j = 0; j < DEQUE_SIZE / MAX_BULK; j++) { + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, + esize[i], MAX_BULK, + &free_space); + TEST_DEQUE_VERIFY(ret == MAX_BULK, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], + MAX_BULK); + + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, + esize[i], MAX_BULK, + &available); + TEST_DEQUE_VERIFY(ret == MAX_BULK, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], + MAX_BULK); + } + + /* check data */ + TEST_DEQUE_VERIFY(test_deque_mem_cmp(src, dst, + RTE_PTR_DIFF(cur_dst, dst)) == 0, + d, goto fail); + + /* Free memory before test completed */ + rte_deque_free(d); + rte_free(src); + rte_free(dst); + d = NULL; + src = NULL; + dst = NULL; + } + + return 0; +fail: + rte_deque_free(d); + rte_free(src); + rte_free(dst); + return -1; +} + +/* + * Burst and bulk operations with normal mode & zero copy mode. + * Enqueue till the deque is full and dequeue till the deque becomes empty. + */ +static int +test_deque_burst_bulk_tests4(unsigned int test_idx) +{ + struct rte_deque *d; + void *src = NULL, *cur_src = NULL, *dst = NULL, *cur_dst = NULL; + int ret; + unsigned int i, j, available, free_space; + unsigned int num_elems, api_type; + api_type = test_enqdeq_impl[test_idx].api_flags; + + for (i = 0; i < RTE_DIM(esize); i++) { + printf("\n%s, esize: %d\n", test_enqdeq_impl[test_idx].desc, + esize[i]); + + /* Create the deque */ + static const char *DEQUE_NAME = "Full deque length test"; + d = rte_deque_create(DEQUE_NAME, esize[i], DEQUE_SIZE, 0, 0); + + /* alloc dummy object pointers */ + src = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (src == NULL) + goto fail; + test_deque_mem_init(src, DEQUE_SIZE * 2, esize[i]); + cur_src = src; + + /* alloc some room for copied objects */ + dst = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (dst == NULL) + goto fail; + cur_dst = dst; + + printf("Test enqueue without enough memory space\n"); + for (j = 0; j < (DEQUE_SIZE/MAX_BULK - 1); j++) { + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, + esize[i], MAX_BULK, + &free_space); + TEST_DEQUE_VERIFY(ret == MAX_BULK, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], + MAX_BULK); + } + + printf("Enqueue 2 objects, free entries = MAX_BULK - 2\n"); + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + 2, &free_space); + TEST_DEQUE_VERIFY(ret == 2, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], 2); + + printf("Enqueue the remaining entries = MAX_BULK - 3\n"); + /* Bulk APIs enqueue exact number of elements */ + if ((api_type & TEST_DEQUE_ELEM_BULK)) + num_elems = MAX_BULK - 3; + else + num_elems = MAX_BULK; + /* Always one free entry left */ + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + num_elems, &free_space); + TEST_DEQUE_VERIFY(ret == (MAX_BULK - 3), d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], + (MAX_BULK - 3)); + + printf("Test if deque is full\n"); + TEST_DEQUE_VERIFY(rte_deque_full(d) == 1, d, goto fail); + + printf("Test enqueue for a full entry\n"); + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + 1, &free_space); + TEST_DEQUE_VERIFY(ret == 0, d, goto fail); + + printf("Test dequeue without enough objects\n"); + for (j = 0; j < DEQUE_SIZE / MAX_BULK - 1; j++) { + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, esize[i], + MAX_BULK, &available); + TEST_DEQUE_VERIFY(ret == MAX_BULK, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], + MAX_BULK); + } + + /* Available memory space for the exact MAX_BULK entries */ + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, esize[i], + 2, &available); + TEST_DEQUE_VERIFY(ret == 2, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], 2); + + /* Bulk APIs enqueue exact number of elements */ + if ((api_type & TEST_DEQUE_ELEM_BULK)) + num_elems = MAX_BULK - 3; + else + num_elems = MAX_BULK; + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, esize[i], + num_elems, &available); + TEST_DEQUE_VERIFY(ret == MAX_BULK - 3, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], MAX_BULK - 3); + + printf("Test if deque is empty\n"); + /* Check if deque is empty */ + TEST_DEQUE_VERIFY(rte_deque_empty(d) == 1, d, goto fail); + + /* check data */ + TEST_DEQUE_VERIFY(test_deque_mem_cmp(src, dst, + RTE_PTR_DIFF(cur_dst, dst)) == 0, + d, goto fail); + + /* Free memory before test completed */ + rte_deque_free(d); + rte_free(src); + rte_free(dst); + d = NULL; + src = NULL; + dst = NULL; + } + + return 0; +fail: + rte_deque_free(d); + rte_free(src); + rte_free(dst); + return -1; +} + +/* + * Basic test cases with exact size deque. + */ +static int +test_deque_with_exact_size(void) +{ + struct rte_deque *std_d = NULL, *exact_sz_d = NULL; + void *src_orig = NULL, *dst_orig = NULL; + void *src = NULL, *cur_src = NULL, *dst = NULL, *cur_dst = NULL; + const unsigned int deque_sz = 16; + unsigned int i, j, free_space, available; + int ret = -1; + + for (i = 0; i < RTE_DIM(esize); i++) { + printf("\nTest exact size deque. Esize: %d\n", esize[i]); + + /* Create the deque */ + static const char *DEQUE_NAME = "std sized deque"; + std_d = rte_deque_create(DEQUE_NAME, esize[i], deque_sz, 0, 0); + + if (std_d == NULL) { + printf("%s: error, can't create std deque\n", __func__); + goto test_fail; + } + static const char *DEQUE_NAME2 = "Exact sized deque"; + exact_sz_d = rte_deque_create(DEQUE_NAME2, esize[i], deque_sz, + 0, RTE_DEQUE_F_EXACT_SZ); + if (exact_sz_d == NULL) { + printf("%s: error, can't create exact size deque\n", + __func__); + goto test_fail; + } + + /* alloc object pointers. Allocate one extra object + * and create an unaligned address. + */ + src_orig = test_deque_calloc(17, esize[i]); + if (src_orig == NULL) + goto test_fail; + test_deque_mem_init(src_orig, 17, esize[i]); + src = (void *)((uintptr_t)src_orig + 1); + cur_src = src; + + dst_orig = test_deque_calloc(17, esize[i]); + if (dst_orig == NULL) + goto test_fail; + dst = (void *)((uintptr_t)dst_orig + 1); + cur_dst = dst; + + /* + * Check that the exact size deque is bigger than the + * standard deque + */ + TEST_DEQUE_VERIFY(rte_deque_get_size(std_d) <= + rte_deque_get_size(exact_sz_d), + std_d, goto test_fail); + + /* + * check that the exact_sz_deque can hold one more element + * than the standard deque. (16 vs 15 elements) + */ + for (j = 0; j < deque_sz - 1; j++) { + ret = test_enqdeq_impl[0].enq(std_d, cur_src, esize[i], + 1, &free_space); + TEST_DEQUE_VERIFY(ret == 1, std_d, goto test_fail); + ret = test_enqdeq_impl[0].enq(exact_sz_d, cur_src, + esize[i], 1, &free_space); + TEST_DEQUE_VERIFY(ret == 1, exact_sz_d, goto test_fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], 1); + } + ret = test_enqdeq_impl[0].enq(std_d, cur_src, esize[i], 1, + &free_space); + TEST_DEQUE_VERIFY(ret == 0, std_d, goto test_fail); + ret = test_enqdeq_impl[0].enq(exact_sz_d, cur_src, esize[i], 1, + &free_space); + TEST_DEQUE_VERIFY(ret == 1, exact_sz_d, goto test_fail); + + /* check that dequeue returns the expected number of elements */ + ret = test_enqdeq_impl[0].deq(exact_sz_d, cur_dst, esize[i], + deque_sz, &available); + TEST_DEQUE_VERIFY(ret == (int)deque_sz, exact_sz_d, + goto test_fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], deque_sz); + + /* check that the capacity function returns expected value */ + TEST_DEQUE_VERIFY(rte_deque_get_capacity(exact_sz_d) == deque_sz, + exact_sz_d, goto test_fail); + + /* check data */ + TEST_DEQUE_VERIFY(test_deque_mem_cmp(src, dst, + RTE_PTR_DIFF(cur_dst, dst)) == 0, + exact_sz_d, goto test_fail); + + rte_free(src_orig); + rte_free(dst_orig); + rte_deque_free(std_d); + rte_deque_free(exact_sz_d); + src_orig = NULL; + dst_orig = NULL; + std_d = NULL; + exact_sz_d = NULL; + } + + return 0; + +test_fail: + rte_free(src_orig); + rte_free(dst_orig); + rte_deque_free(std_d); + rte_deque_free(exact_sz_d); + return -1; +} + +/* + * Burst and bulk operations in regular mode and zero copy mode. + * Random number of elements are enqueued and dequeued first. + * Which would bring both head and tail to somewhere in the middle of + * the deque. From that point, stack behavior of the deque is tested. + */ +static int +test_deque_stack_random_tests1(unsigned int test_idx) +{ + struct rte_deque *d; + void *src = NULL, *cur_src = NULL, *dst = NULL, *cur_dst = NULL; + unsigned int ret; + unsigned int i, j, free_space, available; + const unsigned int dsz = DEQUE_SIZE - 1; + + for (i = 0; i < RTE_DIM(esize); i++) { + printf("Stackmode tests1.\n"); + printf("\n%s, esize: %d\n", test_enqdeq_impl[test_idx].desc, + esize[i]); + + /* Create the deque */ + static const char *DEQUE_NAME = "Over the boundary deque."; + d = rte_deque_create(DEQUE_NAME, esize[i], DEQUE_SIZE, 0, 0); + + /* alloc dummy object pointers */ + src = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (src == NULL) + goto fail; + + test_deque_mem_init(src, DEQUE_SIZE * 2, esize[i]); + cur_src = src; + + /* alloc some room for copied objects */ + dst = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (dst == NULL) + goto fail; + cur_dst = dst; + + printf("Random starting point stack test\n"); + + for (j = 0; j != TEST_DEQUE_FULL_EMPTY_ITER; j++) { + /* random shift in the deque */ + int rand = RTE_MAX(rte_rand() % DEQUE_SIZE, 1UL); + printf("%s: iteration %u, random shift: %u;\n", + __func__, i, rand); + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, + esize[i], rand, + &free_space); + TEST_DEQUE_VERIFY(ret != 0, d, goto fail); + + ret = test_enqdeq_impl[test_idx].deq(d, cur_dst, + esize[i], rand, + &available); + TEST_DEQUE_VERIFY(ret == (unsigned int)rand, d, + goto fail); + + /* fill the deque */ + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + dsz, &free_space); + TEST_DEQUE_VERIFY(ret != 0, d, goto fail); + + TEST_DEQUE_VERIFY(rte_deque_free_count(d) == 0, d, + goto fail); + TEST_DEQUE_VERIFY(dsz == rte_deque_count(d), d, + goto fail); + TEST_DEQUE_VERIFY(rte_deque_full(d), d, + goto fail); + TEST_DEQUE_VERIFY(rte_deque_empty(d) == 0, d, + goto fail); + + /* empty the deque */ + ret = test_enqdeq_impl[test_idx].deq_opp(d, cur_dst, + esize[i], dsz, + &available); + TEST_DEQUE_VERIFY(ret == (int)dsz, d, goto fail); + + TEST_DEQUE_VERIFY(dsz == rte_deque_free_count(d), d, + goto fail); + TEST_DEQUE_VERIFY(rte_deque_count(d) == 0, d, + goto fail); + TEST_DEQUE_VERIFY(rte_deque_full(d) == 0, d, + goto fail); + TEST_DEQUE_VERIFY(rte_deque_empty(d), d, goto fail); + + /* check data */ + TEST_DEQUE_VERIFY(test_deque_mem_cmp_rvs(src, dst, + dsz, esize[i]) == 0, d, goto fail); + } + + /* Free memory before test completed */ + rte_deque_free(d); + rte_free(src); + rte_free(dst); + d = NULL; + src = NULL; + dst = NULL; + } + + return 0; +fail: + rte_deque_free(d); + rte_free(src); + rte_free(dst); + return -1; +} + +/* Tests both standard mode and zero-copy mode. + * Keep enqueuing 1, 2, MAX_BULK elements till the deque is full. + * Then deque them all and make sure the data is opposite of what + * was enqued. + */ +static int +test_deque_stack_random_tests2(unsigned int test_idx) +{ + struct rte_deque *d; + void *src = NULL, *cur_src = NULL, *dst = NULL, *cur_dst = NULL; + unsigned int ret; + unsigned int i, free_space, available; + const unsigned int dsz = DEQUE_SIZE - 1; + + for (i = 0; i < RTE_DIM(esize); i++) { + printf("Stackmode tests2.\n"); + printf("\n%s, esize: %d\n", test_enqdeq_impl[test_idx].desc, + esize[i]); + + /* Create the deque */ + static const char *DEQUE_NAME = "Multiple enqs, deqs."; + d = rte_deque_create(DEQUE_NAME, esize[i], DEQUE_SIZE, 0, 0); + + /* alloc dummy object pointers */ + src = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (src == NULL) + goto fail; + + test_deque_mem_init(src, DEQUE_SIZE * 2, esize[i]); + cur_src = src; + + /* alloc some room for copied objects */ + dst = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (dst == NULL) + goto fail; + cur_dst = dst; + + + printf("Enqueue objs till the deque is full.\n"); + unsigned int count = 0; + const unsigned int perIterCount = 1 + 2 + MAX_BULK; + while (count + perIterCount < DEQUE_SIZE - 1) { + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + 1, &free_space); + TEST_DEQUE_VERIFY(ret == 1, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], 1); + + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + 2, &free_space); + TEST_DEQUE_VERIFY(ret == 2, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], 2); + + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + MAX_BULK, &free_space); + TEST_DEQUE_VERIFY(ret == MAX_BULK, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], MAX_BULK); + count += perIterCount; + } + unsigned int leftOver = DEQUE_SIZE - 1 - count; + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + leftOver, &free_space); + TEST_DEQUE_VERIFY(ret == leftOver, d, goto fail); + cur_src = test_deque_inc_ptr(cur_src, esize[i], leftOver); + + printf("Deque all the enqued objs.\n"); + count = 0; + while (count + perIterCount < DEQUE_SIZE - 1) { + ret = test_enqdeq_impl[test_idx].deq_opp(d, cur_dst, + esize[i], 1, &available); + TEST_DEQUE_VERIFY(ret == 1, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], 1); + + ret = test_enqdeq_impl[test_idx].deq_opp(d, cur_dst, + esize[i], 2, + &available); + TEST_DEQUE_VERIFY(ret == 2, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], 2); + + ret = test_enqdeq_impl[test_idx].deq_opp(d, cur_dst, + esize[i], + MAX_BULK, + &available); + TEST_DEQUE_VERIFY(ret == MAX_BULK, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], MAX_BULK); + count += perIterCount; + } + leftOver = DEQUE_SIZE - 1 - count; + ret = test_enqdeq_impl[test_idx].deq_opp(d, cur_dst, esize[i], + leftOver, &available); + TEST_DEQUE_VERIFY(ret == leftOver, d, goto fail); + cur_dst = test_deque_inc_ptr(cur_dst, esize[i], leftOver); + + /* check data */ + TEST_DEQUE_VERIFY(test_deque_mem_cmp_rvs(src, dst, + dsz, esize[i]) == 0, d, + goto fail); + + /* Free memory before test completed */ + rte_deque_free(d); + rte_free(src); + rte_free(dst); + d = NULL; + src = NULL; + dst = NULL; + } + + return 0; +fail: + rte_deque_free(d); + rte_free(src); + rte_free(dst); + return -1; +} + +/* + * Tests both normal mode and zero-copy mode. + * Fill up the whole deque, and drain the deque. + * Make sure the data matches in reverse order. + */ +static int +test_deque_stack_random_tests3(unsigned int test_idx) +{ + struct rte_deque *d; + void *src = NULL, *cur_src = NULL, *dst = NULL, *cur_dst = NULL; + int ret; + unsigned int i, available, free_space; + const unsigned int dsz = DEQUE_SIZE - 1; + + for (i = 0; i < RTE_DIM(esize); i++) { + printf("Stackmode tests3.\n"); + printf("\n%s, esize: %d\n", test_enqdeq_impl[test_idx].desc, + esize[i]); + + /* Create the deque */ + static const char *DEQUE_NAME = "Full deque length test"; + d = rte_deque_create(DEQUE_NAME, esize[i], DEQUE_SIZE, 0, 0); + + /* alloc dummy object pointers */ + src = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (src == NULL) + goto fail; + test_deque_mem_init(src, DEQUE_SIZE * 2, esize[i]); + cur_src = src; + + /* alloc some room for copied objects */ + dst = test_deque_calloc(DEQUE_SIZE * 2, esize[i]); + if (dst == NULL) + goto fail; + cur_dst = dst; + + /* fill the deque */ + printf("Fill the whole deque using 1 " + "single enqueue operation.\n"); + ret = test_enqdeq_impl[test_idx].enq(d, cur_src, esize[i], + dsz, &free_space); + TEST_DEQUE_VERIFY(ret == (int)dsz, d, goto fail); + + TEST_DEQUE_VERIFY(rte_deque_free_count(d) == 0, d, goto fail); + TEST_DEQUE_VERIFY(dsz == rte_deque_count(d), d, goto fail); + TEST_DEQUE_VERIFY(rte_deque_full(d), d, goto fail); + TEST_DEQUE_VERIFY(rte_deque_empty(d) == 0, d, goto fail); + + /* empty the deque */ + printf("Empty the whole deque.\n"); + ret = test_enqdeq_impl[test_idx].deq_opp(d, cur_dst, esize[i], + dsz, &available); + TEST_DEQUE_VERIFY(ret == (int)dsz, d, goto fail); + + TEST_DEQUE_VERIFY(dsz == rte_deque_free_count(d), d, goto fail); + TEST_DEQUE_VERIFY(rte_deque_count(d) == 0, d, goto fail); + TEST_DEQUE_VERIFY(rte_deque_full(d) == 0, d, goto fail); + TEST_DEQUE_VERIFY(rte_deque_empty(d), d, goto fail); + + /* check data */ + TEST_DEQUE_VERIFY(test_deque_mem_cmp_rvs(src, dst, + dsz, esize[i]) == 0, d, goto fail); + + /* Free memory before test completed */ + rte_deque_free(d); + rte_free(src); + rte_free(dst); + d = NULL; + src = NULL; + dst = NULL; + } + + return 0; +fail: + rte_deque_free(d); + rte_free(src); + rte_free(dst); + return -1; +} + +static int +deque_enqueue_dequeue_autotest_fn(void) +{ + if (test_deque_with_exact_size() != 0) + goto fail; + int (*test_fns[])(unsigned int test_fn_idx) = { + test_deque_burst_bulk_tests1, + test_deque_burst_bulk_tests2, + test_deque_burst_bulk_tests3, + test_deque_burst_bulk_tests4, + test_deque_stack_random_tests1, + test_deque_stack_random_tests2, + test_deque_stack_random_tests3 + }; + for (unsigned int test_impl_idx = 0; + test_impl_idx < RTE_DIM(test_enqdeq_impl); test_impl_idx++) { + for (unsigned int test_fn_idx = 0; + test_fn_idx < RTE_DIM(test_fns); test_fn_idx++) { + if (test_fns[test_fn_idx](test_impl_idx) != 0) + goto fail; + } + } + return 0; +fail: + return -1; +} + +REGISTER_FAST_TEST(deque_enqueue_dequeue_autotest, true, true, + deque_enqueue_dequeue_autotest_fn); diff --git a/app/test/test_deque_helper_functions.c b/app/test/test_deque_helper_functions.c new file mode 100644 index 0000000000..78f3185c1b --- /dev/null +++ b/app/test/test_deque_helper_functions.c @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2024 Arm Limited + */ + +#include "test.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int +test_deque_get_memsize(void) +{ + const ssize_t RTE_DEQUE_SZ = sizeof(struct rte_deque); + /* (1) Should return EINVAL when the supplied size of deque is not a + * power of 2. + */ + TEST_ASSERT_EQUAL(rte_deque_get_memsize_elem(4, 9), -EINVAL, + "Get memsize function failed."); + + /* (2) Should return EINVAL when the supplied size of deque is not a + * multiple of 4. + */ + TEST_ASSERT_EQUAL(rte_deque_get_memsize_elem(5, 8), -EINVAL, + "Get memsize function failed."); + + /* (3) Requested size of the deque should be less than or equal to + * RTE_DEQUEUE_SZ_MASK + */ + TEST_ASSERT_EQUAL(rte_deque_get_memsize_elem(4, RTE_DEQUE_SZ_MASK), -EINVAL, + "Get memsize function failed."); + + /* (4) A deque of count 1, where the element size is 0, should not allocate + * any more memory than necessary to hold the dequeu structure. + */ + TEST_ASSERT_EQUAL(rte_deque_get_memsize_elem(0, 1), RTE_DEQUE_SZ, + "Get memsize function failed."); + + /* (5) Make sure the function is calculating the size correctly. + * size of deque: 128. Size for two elements each of size esize: 8 + * total: 128 + 8 = 132 + * Cache align'd size = 192. + */ + const ssize_t calculated_sz = RTE_ALIGN(RTE_DEQUE_SZ + 8, RTE_CACHE_LINE_SIZE); + TEST_ASSERT_EQUAL(rte_deque_get_memsize_elem(4, 2), calculated_sz, + "Get memsize function failed."); + return 0; +} + +/* Define a Test macro that will allow us to correctly free all the rte_deque + * objects that were created as a part of the test in case of a failure. + */ + +#define TEST_DEQUE_MEMSAFE(exp, msg, stmt) do { \ + if (!(exp)) { \ + printf("error at %s:%d\tcondition " #exp " failed. Msg: %s\n", \ + __func__, __LINE__, msg); \ + stmt; \ + } \ +} while (0) + +static int +test_deque_init(void) +{ + { + /* (1) Make sure init fails when the flags are not correctly passed in. */ + struct rte_deque deque; + + /* Calling init with undefined flags should fail. */ + TEST_ASSERT_EQUAL(rte_deque_init(&deque, "Deque", 10, 0x8), + -EINVAL, "Init failed."); + + /* Calling init with a count that is not a power of 2 + * And also not the setting the RTE_DEQUE_F_EXACT_SZ + * flag should fail. + */ + TEST_ASSERT_EQUAL(rte_deque_init(&deque, "Deque", 10, 0), + -EINVAL, "Init failed."); + + /* Calling init with a count that is not a power of 2 + * Should succeed only if the RTE_DEQUE_F_EXACT_SZ flag is set. + */ + TEST_ASSERT_EQUAL(rte_deque_init(&deque, "Deque", 10, RTE_DEQUE_F_EXACT_SZ), + 0, "Init failed."); + } + + { + /* Make sure all the fields are being correctly set when creating a + * Deque of a size that is not a power of 2. + */ + struct rte_deque deque; + static const char NAME[] = "Deque"; + + /* Calling init with a count that is not a power of 2 + * But with RTE_DEQUE_F_EXACT_SZ should succeed. + */ + TEST_ASSERT_EQUAL(rte_deque_init(&deque, NAME, 10, RTE_DEQUE_F_EXACT_SZ), + 0, "Init failed."); + + TEST_ASSERT_BUFFERS_ARE_EQUAL(deque.name, NAME, sizeof(NAME), "Init failed."); + TEST_ASSERT_EQUAL(deque.flags, RTE_DEQUE_F_EXACT_SZ, "Init failed."); + TEST_ASSERT_EQUAL(deque.size, 16, "Init failed."); + TEST_ASSERT_EQUAL(deque.mask, 15, "Init failed."); + TEST_ASSERT_EQUAL(deque.capacity, 10, "Init failed."); + } + + { + /* Make sure all the fields are being correctly set when creating a + * Deque of a size that is a power of 2. + */ + struct rte_deque deque; + static const char NAME[] = "Deque"; + + /* Calling init with a count that is not a power of 2 + * But with RTE_DEQUE_F_EXACT_SZ should succeed. + */ + TEST_ASSERT_EQUAL(rte_deque_init(&deque, NAME, 16, 0), 0, "Init failed."); + + TEST_ASSERT_EQUAL(deque.size, 16, "Init failed."); + TEST_ASSERT_EQUAL(deque.mask, 15, "Init failed."); + TEST_ASSERT_EQUAL(deque.capacity, 15, "Init failed."); + } + return 0; +} + +static int +test_deque_create(void) +{ + struct rte_deque *deque; + const char *NAME = "Deque"; + deque = rte_deque_create(NAME, 4, 16, 0, 0); + + /* Make sure the deque creation is successful. */ + TEST_DEQUE_MEMSAFE(deque != NULL, "Deque creation failed.", goto fail); + TEST_DEQUE_MEMSAFE(deque->memzone != NULL, "Deque creation failed.", goto fail); + return 0; +fail: + rte_free(deque); + return -1; +} + +#undef TEST_DEQUE_MEMSAFE + +static struct unit_test_suite deque_helper_functions_testsuite = { + .suite_name = "Deque library helper functions test suite", + .unit_test_cases = { + TEST_CASE(test_deque_get_memsize), + TEST_CASE(test_deque_init), + TEST_CASE(test_deque_create), + TEST_CASES_END(), /**< NULL terminate unit test array */ + }, +}; + +static int +deque_helper_functions_autotest_fn(void) +{ + return unit_test_suite_runner(&deque_helper_functions_testsuite); +} + +REGISTER_FAST_TEST(deque_helper_functions_autotest, true, true, + deque_helper_functions_autotest_fn);