From patchwork Mon Apr 1 21:14:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Eads, Gage" X-Patchwork-Id: 52007 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D85BC559A; Mon, 1 Apr 2019 23:15:19 +0200 (CEST) Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by dpdk.org (Postfix) with ESMTP id 3F9B24C9C for ; Mon, 1 Apr 2019 23:15:13 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 01 Apr 2019 14:15:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,298,1549958400"; d="scan'208";a="312277346" Received: from txasoft-yocto.an.intel.com ([10.123.72.192]) by orsmga005.jf.intel.com with ESMTP; 01 Apr 2019 14:15:11 -0700 From: Gage Eads To: dev@dpdk.org Cc: olivier.matz@6wind.com, arybchenko@solarflare.com, bruce.richardson@intel.com, konstantin.ananyev@intel.com, gavin.hu@arm.com, Honnappa.Nagarahalli@arm.com, nd@arm.com, thomas@monjalon.net Date: Mon, 1 Apr 2019 16:14:24 -0500 Message-Id: <20190401211429.20282-4-gage.eads@intel.com> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20190401211429.20282-1-gage.eads@intel.com> References: <20190401001238.17625-1-gage.eads@intel.com> <20190401211429.20282-1-gage.eads@intel.com> Subject: [dpdk-dev] [PATCH v6 3/8] test/stack: add stack test X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" stack_autotest performs positive and negative testing of the stack API, and exercises the push and pop datapath functions with all available lcores. Signed-off-by: Gage Eads Reviewed-by: Olivier Matz --- MAINTAINERS | 1 + app/test/Makefile | 2 + app/test/meson.build | 3 + app/test/test_stack.c | 410 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 416 insertions(+) create mode 100644 app/test/test_stack.c diff --git a/MAINTAINERS b/MAINTAINERS index 13fe49e2b..2842f07ab 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -421,6 +421,7 @@ M: Olivier Matz F: lib/librte_stack/ F: doc/guides/prog_guide/stack_lib.rst F: drivers/mempool/stack/ +F: test/test/*stack* Memory Pool Drivers diff --git a/app/test/Makefile b/app/test/Makefile index d6aa28bad..e5bde81af 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -90,6 +90,8 @@ endif SRCS-y += test_rwlock.c +SRCS-$(CONFIG_RTE_LIBRTE_STACK) += test_stack.c + SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer.c SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_perf.c SRCS-$(CONFIG_RTE_LIBRTE_TIMER) += test_timer_racecond.c diff --git a/app/test/meson.build b/app/test/meson.build index c5e65fe66..56ea13f53 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -95,6 +95,7 @@ test_sources = files('commands.c', 'test_sched.c', 'test_service_cores.c', 'test_spinlock.c', + 'test_stack.c', 'test_string_fns.c', 'test_table.c', 'test_table_acl.c', @@ -133,6 +134,7 @@ test_deps = ['acl', 'port', 'reorder', 'ring', + 'stack', 'timer' ] @@ -174,6 +176,7 @@ fast_parallel_test_names = [ 'rwlock_autotest', 'sched_autotest', 'spinlock_autotest', + 'stack_autotest', 'string_autotest', 'table_autotest', 'tailq_autotest', diff --git a/app/test/test_stack.c b/app/test/test_stack.c new file mode 100644 index 000000000..8392e4e4d --- /dev/null +++ b/app/test/test_stack.c @@ -0,0 +1,410 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Intel Corporation + */ + +#include + +#include +#include +#include +#include + +#include "test.h" + +#define STACK_SIZE 4096 +#define MAX_BULK 32 + +static int +test_stack_push_pop(struct rte_stack *s, void **obj_table, unsigned int bulk_sz) +{ + unsigned int i, ret; + void **popped_objs; + + popped_objs = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0); + if (popped_objs == NULL) { + printf("[%s():%u] failed to calloc %zu bytes\n", + __func__, __LINE__, STACK_SIZE * sizeof(void *)); + return -1; + } + + for (i = 0; i < STACK_SIZE; i += bulk_sz) { + ret = rte_stack_push(s, &obj_table[i], bulk_sz); + + if (ret != bulk_sz) { + printf("[%s():%u] push returned: %d (expected %u)\n", + __func__, __LINE__, ret, bulk_sz); + rte_free(popped_objs); + return -1; + } + + if (rte_stack_count(s) != i + bulk_sz) { + printf("[%s():%u] stack count: %u (expected %u)\n", + __func__, __LINE__, rte_stack_count(s), + i + bulk_sz); + rte_free(popped_objs); + return -1; + } + + if (rte_stack_free_count(s) != STACK_SIZE - i - bulk_sz) { + printf("[%s():%u] stack free count: %u (expected %u)\n", + __func__, __LINE__, rte_stack_count(s), + STACK_SIZE - i - bulk_sz); + rte_free(popped_objs); + return -1; + } + } + + for (i = 0; i < STACK_SIZE; i += bulk_sz) { + ret = rte_stack_pop(s, &popped_objs[i], bulk_sz); + + if (ret != bulk_sz) { + printf("[%s():%u] pop returned: %d (expected %u)\n", + __func__, __LINE__, ret, bulk_sz); + rte_free(popped_objs); + return -1; + } + + if (rte_stack_count(s) != STACK_SIZE - i - bulk_sz) { + printf("[%s():%u] stack count: %u (expected %u)\n", + __func__, __LINE__, rte_stack_count(s), + STACK_SIZE - i - bulk_sz); + rte_free(popped_objs); + return -1; + } + + if (rte_stack_free_count(s) != i + bulk_sz) { + printf("[%s():%u] stack free count: %u (expected %u)\n", + __func__, __LINE__, rte_stack_count(s), + i + bulk_sz); + rte_free(popped_objs); + return -1; + } + } + + for (i = 0; i < STACK_SIZE; i++) { + if (obj_table[i] != popped_objs[STACK_SIZE - i - 1]) { + printf("[%s():%u] Incorrect value %p at index 0x%x\n", + __func__, __LINE__, + popped_objs[STACK_SIZE - i - 1], i); + rte_free(popped_objs); + return -1; + } + } + + rte_free(popped_objs); + + return 0; +} + +static int +test_stack_basic(void) +{ + struct rte_stack *s = NULL; + void **obj_table = NULL; + int i, ret = -1; + + obj_table = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0); + if (obj_table == NULL) { + printf("[%s():%u] failed to calloc %zu bytes\n", + __func__, __LINE__, STACK_SIZE * sizeof(void *)); + goto fail_test; + } + + for (i = 0; i < STACK_SIZE; i++) + obj_table[i] = (void *)(uintptr_t)i; + + s = rte_stack_create(__func__, STACK_SIZE, rte_socket_id(), 0); + if (s == NULL) { + printf("[%s():%u] failed to create a stack\n", + __func__, __LINE__); + goto fail_test; + } + + if (rte_stack_lookup(__func__) != s) { + printf("[%s():%u] failed to lookup a stack\n", + __func__, __LINE__); + goto fail_test; + } + + if (rte_stack_count(s) != 0) { + printf("[%s():%u] stack count: %u (expected 0)\n", + __func__, __LINE__, rte_stack_count(s)); + goto fail_test; + } + + if (rte_stack_free_count(s) != STACK_SIZE) { + printf("[%s():%u] stack free count: %u (expected %u)\n", + __func__, __LINE__, rte_stack_count(s), STACK_SIZE); + goto fail_test; + } + + ret = test_stack_push_pop(s, obj_table, 1); + if (ret) { + printf("[%s():%u] Single object push/pop failed\n", + __func__, __LINE__); + goto fail_test; + } + + ret = test_stack_push_pop(s, obj_table, MAX_BULK); + if (ret) { + printf("[%s():%u] Bulk object push/pop failed\n", + __func__, __LINE__); + goto fail_test; + } + + ret = rte_stack_push(s, obj_table, 2 * STACK_SIZE); + if (ret != 0) { + printf("[%s():%u] Excess objects push succeeded\n", + __func__, __LINE__); + goto fail_test; + } + + ret = rte_stack_pop(s, obj_table, 1); + if (ret != 0) { + printf("[%s():%u] Empty stack pop succeeded\n", + __func__, __LINE__); + goto fail_test; + } + + ret = 0; + +fail_test: + rte_stack_free(s); + + rte_free(obj_table); + + return ret; +} + +static int +test_stack_name_reuse(void) +{ + struct rte_stack *s[2]; + + s[0] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), 0); + if (s[0] == NULL) { + printf("[%s():%u] Failed to create a stack\n", + __func__, __LINE__); + return -1; + } + + s[1] = rte_stack_create("test", STACK_SIZE, rte_socket_id(), 0); + if (s[1] != NULL) { + printf("[%s():%u] Failed to detect re-used name\n", + __func__, __LINE__); + return -1; + } + + rte_stack_free(s[0]); + + return 0; +} + +static int +test_stack_name_length(void) +{ + char name[RTE_STACK_NAMESIZE + 1]; + struct rte_stack *s; + + memset(name, 's', sizeof(name)); + name[RTE_STACK_NAMESIZE] = '\0'; + + s = rte_stack_create(name, STACK_SIZE, rte_socket_id(), 0); + if (s != NULL) { + printf("[%s():%u] Failed to prevent long name\n", + __func__, __LINE__); + return -1; + } + + if (rte_errno != ENAMETOOLONG) { + printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n", + __func__, __LINE__); + return -1; + } + + return 0; +} + +static int +test_lookup_null(void) +{ + struct rte_stack *s = rte_stack_lookup("stack_not_found"); + + if (s != NULL) { + printf("[%s():%u] rte_stack found a non-existent stack\n", + __func__, __LINE__); + return -1; + } + + if (rte_errno != ENOENT) { + printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n", + __func__, __LINE__); + return -1; + } + + s = rte_stack_lookup(NULL); + + if (s != NULL) { + printf("[%s():%u] rte_stack found a non-existent stack\n", + __func__, __LINE__); + return -1; + } + + if (rte_errno != EINVAL) { + printf("[%s():%u] rte_stack failed to set correct errno on failed lookup\n", + __func__, __LINE__); + return -1; + } + + return 0; +} + +static int +test_free_null(void) +{ + /* Check whether the library proper handles a NULL pointer */ + rte_stack_free(NULL); + + return 0; +} + +#define NUM_ITERS_PER_THREAD 100000 + +struct test_args { + struct rte_stack *s; + rte_atomic64_t *sz; +}; + +static int +stack_thread_push_pop(void *args) +{ + struct test_args *t = args; + void **obj_table; + int i; + + obj_table = rte_calloc(NULL, STACK_SIZE, sizeof(void *), 0); + if (obj_table == NULL) { + printf("[%s():%u] failed to calloc %zu bytes\n", + __func__, __LINE__, STACK_SIZE * sizeof(void *)); + return -1; + } + + for (i = 0; i < NUM_ITERS_PER_THREAD; i++) { + unsigned int success, num; + + /* Reserve up to min(MAX_BULK, available slots) stack entries, + * then push and pop those stack entries. + */ + do { + uint64_t sz = rte_atomic64_read(t->sz); + volatile uint64_t *sz_addr; + + sz_addr = (volatile uint64_t *)t->sz; + + num = RTE_MIN(rte_rand() % MAX_BULK, STACK_SIZE - sz); + + success = rte_atomic64_cmpset(sz_addr, sz, sz + num); + } while (success == 0); + + if (rte_stack_push(t->s, obj_table, num) != num) { + printf("[%s():%u] Failed to push %u pointers\n", + __func__, __LINE__, num); + rte_free(obj_table); + return -1; + } + + if (rte_stack_pop(t->s, obj_table, num) != num) { + printf("[%s():%u] Failed to pop %u pointers\n", + __func__, __LINE__, num); + rte_free(obj_table); + return -1; + } + + rte_atomic64_sub(t->sz, num); + } + + rte_free(obj_table); + return 0; +} + +static int +test_stack_multithreaded(void) +{ + struct test_args *args; + unsigned int lcore_id; + struct rte_stack *s; + rte_atomic64_t size; + + printf("[%s():%u] Running with %u lcores\n", + __func__, __LINE__, rte_lcore_count()); + + if (rte_lcore_count() < 2) + return 0; + + args = rte_malloc(NULL, sizeof(struct test_args) * RTE_MAX_LCORE, 0); + if (args == NULL) { + printf("[%s():%u] failed to malloc %zu bytes\n", + __func__, __LINE__, + sizeof(struct test_args) * RTE_MAX_LCORE); + return -1; + } + + s = rte_stack_create("test", STACK_SIZE, rte_socket_id(), 0); + if (s == NULL) { + printf("[%s():%u] Failed to create a stack\n", + __func__, __LINE__); + rte_free(args); + return -1; + } + + rte_atomic64_init(&size); + + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + args[lcore_id].s = s; + args[lcore_id].sz = &size; + + if (rte_eal_remote_launch(stack_thread_push_pop, + &args[lcore_id], lcore_id)) + rte_panic("Failed to launch lcore %d\n", lcore_id); + } + + lcore_id = rte_lcore_id(); + + args[lcore_id].s = s; + args[lcore_id].sz = &size; + + stack_thread_push_pop(&args[lcore_id]); + + rte_eal_mp_wait_lcore(); + + rte_stack_free(s); + rte_free(args); + + return 0; +} + +static int +test_stack(void) +{ + if (test_stack_basic() < 0) + return -1; + + if (test_lookup_null() < 0) + return -1; + + if (test_free_null() < 0) + return -1; + + if (test_stack_name_reuse() < 0) + return -1; + + if (test_stack_name_length() < 0) + return -1; + + if (test_stack_multithreaded() < 0) + return -1; + + return 0; +} + +REGISTER_TEST_COMMAND(stack_autotest, test_stack);