From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id C87EBA0C4B; Thu, 14 Oct 2021 17:36:40 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5C5B04129F; Thu, 14 Oct 2021 17:36:16 +0200 (CEST) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id D7A31412BF for ; Thu, 14 Oct 2021 17:36:13 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10137"; a="291188497" X-IronPort-AV: E=Sophos;i="5.85,372,1624345200"; d="scan'208";a="291188497" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Oct 2021 08:34:02 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.85,372,1624345200"; d="scan'208";a="442154413" Received: from silpixa00400629.ir.intel.com ([10.237.213.30]) by orsmga006.jf.intel.com with ESMTP; 14 Oct 2021 08:34:00 -0700 From: "Liguzinski, WojciechX" To: dev@dpdk.org, jasvinder.singh@intel.com, cristian.dumitrescu@intel.com Cc: megha.ajmera@intel.com Date: Thu, 14 Oct 2021 15:33:46 +0000 Message-Id: <20211014153346.2816600-6-wojciechx.liguzinski@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211014153346.2816600-1-wojciechx.liguzinski@intel.com> References: <20211014151111.2815099-1-wojciechx.liguzinski@intel.com> <20211014153346.2816600-1-wojciechx.liguzinski@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [dpdk-dev] [PATCH v13 5/5] app/test: add tests for PIE 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 Sender: "dev" Tests for PIE code added to test application. Signed-off-by: Liguzinski, WojciechX --- app/test/autotest_data.py | 18 + app/test/meson.build | 4 + app/test/test_pie.c | 1065 +++++++++++++++++++++++++++++++++++++ lib/sched/rte_pie.c | 6 +- lib/sched/rte_pie.h | 17 +- 5 files changed, 1103 insertions(+), 7 deletions(-) create mode 100644 app/test/test_pie.c diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py index 302d6374c1..1d4418b6a3 100644 --- a/app/test/autotest_data.py +++ b/app/test/autotest_data.py @@ -279,6 +279,12 @@ "Func": default_autotest, "Report": None, }, + { + "Name": "Pie autotest", + "Command": "pie_autotest", + "Func": default_autotest, + "Report": None, + }, { "Name": "PMD ring autotest", "Command": "ring_pmd_autotest", @@ -525,6 +531,12 @@ "Func": default_autotest, "Report": None, }, + { + "Name": "Pie all", + "Command": "red_all", + "Func": default_autotest, + "Report": None, + }, { "Name": "Fbarray autotest", "Command": "fbarray_autotest", @@ -731,6 +743,12 @@ "Func": default_autotest, "Report": None, }, + { + "Name": "Pie_perf", + "Command": "pie_perf", + "Func": default_autotest, + "Report": None, + }, { "Name": "Lpm6 perf autotest", "Command": "lpm6_perf_autotest", diff --git a/app/test/meson.build b/app/test/meson.build index a7611686ad..f224b0c17e 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -111,6 +111,7 @@ test_sources = files( 'test_reciprocal_division.c', 'test_reciprocal_division_perf.c', 'test_red.c', + 'test_pie.c', 'test_reorder.c', 'test_rib.c', 'test_rib6.c', @@ -241,6 +242,7 @@ fast_tests = [ ['prefetch_autotest', true], ['rcu_qsbr_autotest', true], ['red_autotest', true], + ['pie_autotest', true], ['rib_autotest', true], ['rib6_autotest', true], ['ring_autotest', true], @@ -292,6 +294,7 @@ perf_test_names = [ 'fib_slow_autotest', 'fib_perf_autotest', 'red_all', + 'pie_all', 'barrier_autotest', 'hash_multiwriter_autotest', 'timer_racecond_autotest', @@ -305,6 +308,7 @@ perf_test_names = [ 'fib6_perf_autotest', 'rcu_qsbr_perf_autotest', 'red_perf', + 'pie_perf', 'distributor_perf_autotest', 'pmd_perf_autotest', 'stack_perf_autotest', diff --git a/app/test/test_pie.c b/app/test/test_pie.c new file mode 100644 index 0000000000..dfa69d1c7e --- /dev/null +++ b/app/test/test_pie.c @@ -0,0 +1,1065 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" + +#include + +#ifdef __INTEL_COMPILER +#pragma warning(disable:2259) /* conversion may lose significant bits */ +#pragma warning(disable:181) /* Arg incompatible with format string */ +#endif + +/**< structures for testing rte_pie performance and function */ +struct test_rte_pie_config { /**< Test structure for RTE_PIE config */ + struct rte_pie_config *pconfig; /**< RTE_PIE configuration parameters */ + uint8_t num_cfg; /**< Number of RTE_PIE configs to test */ + uint16_t qdelay_ref; /**< Latency Target (milliseconds) */ + uint16_t *dp_update_interval; /**< Update interval for drop probability + * (milliseconds) + */ + uint16_t *max_burst; /**< Max Burst Allowance (milliseconds) */ + uint16_t tailq_th; /**< Tailq drop threshold (packet counts) */ +}; + +struct test_queue { /**< Test structure for RTE_PIE Queues */ + struct rte_pie *pdata_in; /**< RTE_PIE runtime data input */ + struct rte_pie *pdata_out; /**< RTE_PIE runtime data output*/ + uint32_t num_queues; /**< Number of RTE_PIE queues to test */ + uint32_t *qlen; /**< Queue size */ + uint32_t q_ramp_up; /**< Num of enqueues to ramp up the queue */ + double drop_tolerance; /**< Drop tolerance of packets not enqueued */ +}; + +struct test_var { /**< Test variables used for testing RTE_PIE */ + uint32_t num_iterations; /**< Number of test iterations */ + uint32_t num_ops; /**< Number of test operations */ + uint64_t clk_freq; /**< CPU clock frequency */ + uint32_t *dropped; /**< Test operations dropped */ + uint32_t *enqueued; /**< Test operations enqueued */ + uint32_t *dequeued; /**< Test operations dequeued */ +}; + +struct test_config { /**< Primary test structure for RTE_PIE */ + const char *ifname; /**< Interface name */ + const char *msg; /**< Test message for display */ + const char *htxt; /**< Header txt display for result output */ + struct test_rte_pie_config *tconfig; /**< Test structure for RTE_PIE config */ + struct test_queue *tqueue; /**< Test structure for RTE_PIE Queues */ + struct test_var *tvar; /**< Test variables used for testing RTE_PIE */ + uint32_t *tlevel; /**< Queue levels */ +}; + +enum test_result { + FAIL = 0, + PASS +}; + +/**< Test structure to define tests to run */ +struct tests { + struct test_config *testcfg; + enum test_result (*testfn)(struct test_config *cfg); +}; + +struct rdtsc_prof { + uint64_t clk_start; + uint64_t clk_min; /**< min clocks */ + uint64_t clk_max; /**< max clocks */ + uint64_t clk_avgc; /**< count to calc average */ + double clk_avg; /**< cumulative sum to calc average */ + const char *name; +}; + +static const uint64_t port_speed_bytes = (10ULL*1000ULL*1000ULL*1000ULL)/8ULL; +static double inv_cycles_per_byte; + +static void init_port_ts(uint64_t cpu_clock) +{ + double cycles_per_byte = (double)(cpu_clock) / (double)(port_speed_bytes); + inv_cycles_per_byte = 1.0 / cycles_per_byte; +} + +static uint64_t get_port_ts(void) +{ + return (uint64_t)((double)rte_rdtsc() * inv_cycles_per_byte); +} + +static void rdtsc_prof_init(struct rdtsc_prof *p, const char *name) +{ + p->clk_min = (uint64_t)(-1LL); + p->clk_max = 0; + p->clk_avg = 0; + p->clk_avgc = 0; + p->name = name; +} + +static inline void rdtsc_prof_start(struct rdtsc_prof *p) +{ + p->clk_start = rte_rdtsc_precise(); +} + +static inline void rdtsc_prof_end(struct rdtsc_prof *p) +{ + uint64_t clk_start = rte_rdtsc() - p->clk_start; + + p->clk_avgc++; + p->clk_avg += (double) clk_start; + + if (clk_start > p->clk_max) + p->clk_max = clk_start; + if (clk_start < p->clk_min) + p->clk_min = clk_start; +} + +static void rdtsc_prof_print(struct rdtsc_prof *p) +{ + if (p->clk_avgc > 0) { + printf("RDTSC stats for %s: n=%" PRIu64 ", min=%" PRIu64 + ",max=%" PRIu64 ", avg=%.1f\n", + p->name, + p->clk_avgc, + p->clk_min, + p->clk_max, + (p->clk_avg / ((double) p->clk_avgc))); + } +} + +static uint16_t rte_pie_get_active(const struct rte_pie_config *pie_cfg, + struct rte_pie *pie) +{ + /**< Flag for activating/deactivating pie */ + RTE_SET_USED(pie_cfg); + return pie->active; +} + +static void rte_pie_set_active(const struct rte_pie_config *pie_cfg, + struct rte_pie *pie, + uint16_t active) +{ + /**< Flag for activating/deactivating pie */ + RTE_SET_USED(pie_cfg); + pie->active = active; +} + +/** + * Read the drop probability + */ +static double rte_pie_get_drop_prob(const struct rte_pie_config *pie_cfg, + struct rte_pie *pie) +{ + /**< Current packet drop probability */ + RTE_SET_USED(pie_cfg); + return pie->drop_prob; +} + +static double rte_pie_get_avg_dq_time(const struct rte_pie_config *pie_cfg, + struct rte_pie *pie) +{ + /**< Current packet drop probability */ + RTE_SET_USED(pie_cfg); + return pie->avg_dq_time; +} + +static double calc_drop_rate(uint32_t enqueued, uint32_t dropped) +{ + return (double)dropped / ((double)enqueued + (double)dropped); +} + +/** + * check if drop rate matches drop probability within tolerance + */ +static int check_drop_rate(double *diff, double drop_rate, double drop_prob, + double tolerance) +{ + double abs_diff = 0.0; + int ret = 1; + + abs_diff = fabs(drop_rate - drop_prob); + if ((int)abs_diff == 0) { + *diff = 0.0; + } else { + *diff = (abs_diff / drop_prob) * 100.0; + if (*diff > tolerance) + ret = 0; + } + return ret; +} + +/** + * initialize the test rte_pie config + */ +static enum test_result +test_rte_pie_init(struct test_config *tcfg) +{ + unsigned int i = 0; + + tcfg->tvar->clk_freq = rte_get_timer_hz(); + init_port_ts(tcfg->tvar->clk_freq); + + for (i = 0; i < tcfg->tconfig->num_cfg; i++) { + if (rte_pie_config_init(&tcfg->tconfig->pconfig[i], + (uint16_t)tcfg->tconfig->qdelay_ref, + (uint16_t)tcfg->tconfig->dp_update_interval[i], + (uint16_t)tcfg->tconfig->max_burst[i], + (uint16_t)tcfg->tconfig->tailq_th) != 0) { + return FAIL; + } + } + + *tcfg->tqueue->qlen = 0; + *tcfg->tvar->dropped = 0; + *tcfg->tvar->enqueued = 0; + + return PASS; +} + +/** + * enqueue until actual queue size reaches target level + */ +static int +increase_qsize(struct rte_pie_config *pie_cfg, + struct rte_pie *pie, + uint32_t *qlen, + uint32_t pkt_len, + uint32_t attempts) +{ + uint32_t i = 0; + + for (i = 0; i < attempts; i++) { + int ret = 0; + + /** + * enqueue + */ + ret = rte_pie_enqueue(pie_cfg, pie, *qlen, pkt_len, get_port_ts()); + /** + * check if target actual queue size has been reached + */ + if (ret == 0) + return 0; + } + /** + * no success + */ + return -1; +} + +/** + * functional test enqueue/dequeue packets + */ +static void +enqueue_dequeue_func(struct rte_pie_config *pie_cfg, + struct rte_pie *pie, + uint32_t *qlen, + uint32_t num_ops, + uint32_t *enqueued, + uint32_t *dropped) +{ + uint32_t i = 0; + + for (i = 0; i < num_ops; i++) { + int ret = 0; + + /** + * enqueue + */ + ret = rte_pie_enqueue(pie_cfg, pie, *qlen, sizeof(uint32_t), + get_port_ts()); + if (ret == 0) + (*enqueued)++; + else + (*dropped)++; + } +} + +/** + * setup default values for the Functional test structures + */ +static struct rte_pie_config ft_wpconfig[1]; +static struct rte_pie ft_rtdata[1]; +static uint32_t ft_q[] = {0}; +static uint32_t ft_dropped[] = {0}; +static uint32_t ft_enqueued[] = {0}; +static uint16_t ft_max_burst[] = {64}; +static uint16_t ft_dp_update_interval[] = {150}; + +static struct test_rte_pie_config ft_tconfig = { + .pconfig = ft_wpconfig, + .num_cfg = RTE_DIM(ft_wpconfig), + .qdelay_ref = 15, + .dp_update_interval = ft_dp_update_interval, + .max_burst = ft_max_burst, + .tailq_th = 15, +}; + +static struct test_queue ft_tqueue = { + .pdata_in = ft_rtdata, + .num_queues = RTE_DIM(ft_rtdata), + .qlen = ft_q, + .q_ramp_up = 10, + .drop_tolerance = 0, +}; + +static struct test_var ft_tvar = { + .num_iterations = 0, + .num_ops = 10000, + .clk_freq = 0, + .dropped = ft_dropped, + .enqueued = ft_enqueued, +}; + +/** + * Test F1: functional test 1 + */ +static uint32_t ft_tlevels[] = {6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, + 72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 144}; + +static struct test_config func_test_config1 = { + .ifname = "functional test interface", + .msg = "functional test : use one pie configuration\n\n", + .htxt = " " + "drop probability " + "enqueued " + "dropped " + "drop prob % " + "drop rate % " + "diff % " + "tolerance % " + "active " + "\n", + .tconfig = &ft_tconfig, + .tqueue = &ft_tqueue, + .tvar = &ft_tvar, + .tlevel = ft_tlevels, +}; + +static enum test_result func_test1(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint32_t i = 0; + + printf("%s", tcfg->msg); + + if (test_rte_pie_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + printf("%s", tcfg->htxt); + + /** + * reset rte_pie run-time data + */ + rte_pie_rt_data_init(tcfg->tqueue->pdata_in); + rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); + *tcfg->tvar->enqueued = 0; + *tcfg->tvar->dropped = 0; + + if (increase_qsize(&tcfg->tconfig->pconfig[i], + tcfg->tqueue->pdata_in, + tcfg->tqueue->qlen, + tcfg->tlevel[i], + tcfg->tqueue->q_ramp_up) != 0) { + fprintf(stderr, "Fail: increase qsize\n"); + result = FAIL; + goto out; + } + + for (i = 0; i < RTE_DIM(ft_tlevels); i++) { + const char *label = NULL; + uint16_t prob = 0; + uint16_t active = 0; + double drop_rate = 1.0; + double drop_prob = 0.0; + double diff = 0.0; + + enqueue_dequeue_func(&tcfg->tconfig->pconfig[i], + tcfg->tqueue->pdata_in, + tcfg->tqueue->qlen, + tcfg->tvar->num_ops, + tcfg->tvar->enqueued, + tcfg->tvar->dropped); + + drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, + *tcfg->tvar->dropped); + drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in); + + if (drop_prob != 0) { + fprintf(stderr, "Fail: check drop prob\n"); + result = FAIL; + } + + if (drop_rate != 0) { + fprintf(stderr, "Fail: check drop rate\n"); + result = FAIL; + } + + label = "Summary "; + active = rte_pie_get_active(NULL, tcfg->tqueue->pdata_in); + printf("%s%-16u%-12u%-12u%-12.4lf%-12.4lf%-12.4lf%-12.4lf%-8i\n", + label, prob, *tcfg->tvar->enqueued, *tcfg->tvar->dropped, + drop_prob * 100.0, drop_rate * 100.0, diff, + (double)tcfg->tqueue->drop_tolerance, active); + } +out: + return result; +} + +/** + * Test F2: functional test 2 + */ +static uint32_t ft2_tlevel[] = {127}; +static uint16_t ft2_max_burst[] = {1, 2, 8, 16, 32, 64, 128, 256, 512, 1024}; +static uint16_t ft2_dp_update_interval[] = { + 10, 20, 50, 150, 300, 600, 900, 1200, 1500, 3000}; +static struct rte_pie_config ft2_pconfig[10]; + +static struct test_rte_pie_config ft2_tconfig = { + .pconfig = ft2_pconfig, + .num_cfg = RTE_DIM(ft2_pconfig), + .qdelay_ref = 15, + .dp_update_interval = ft2_dp_update_interval, + .max_burst = ft2_max_burst, + .tailq_th = 15, +}; + +static struct test_config func_test_config2 = { + .ifname = "functional test 2 interface", + .msg = "functional test 2 : use several PIE configurations,\n" + " compare drop rate to drop probability\n\n", + .htxt = "PIE config " + "avg queue size " + "enqueued " + "dropped " + "drop prob % " + "drop rate % " + "diff % " + "tolerance % " + "\n", + .tconfig = &ft2_tconfig, + .tqueue = &ft_tqueue, + .tvar = &ft_tvar, + .tlevel = ft2_tlevel, +}; + +static enum test_result func_test2(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint32_t i = 0; + + printf("%s", tcfg->msg); + + printf("%s", tcfg->htxt); + + for (i = 0; i < tcfg->tconfig->num_cfg; i++) { + uint32_t avg = 0; + double drop_rate = 0.0; + double drop_prob = 0.0; + double diff = 0.0; + + if (test_rte_pie_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + rte_pie_rt_data_init(tcfg->tqueue->pdata_in); + rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); + *tcfg->tvar->enqueued = 0; + *tcfg->tvar->dropped = 0; + + if (increase_qsize(&tcfg->tconfig->pconfig[i], + tcfg->tqueue->pdata_in, + tcfg->tqueue->qlen, + *tcfg->tlevel, + tcfg->tqueue->q_ramp_up) != 0) { + result = FAIL; + goto out; + } + + enqueue_dequeue_func(&tcfg->tconfig->pconfig[i], + tcfg->tqueue->pdata_in, + tcfg->tqueue->qlen, + tcfg->tvar->num_ops, + tcfg->tvar->enqueued, + tcfg->tvar->dropped); + + avg = rte_pie_get_avg_dq_time(NULL, tcfg->tqueue->pdata_in); + + drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, + *tcfg->tvar->dropped); + drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in); + + if (!check_drop_rate(&diff, drop_rate, drop_prob, + (double)tcfg->tqueue->drop_tolerance)) { + fprintf(stderr, "Fail: drop rate outside tolerance\n"); + result = FAIL; + } + + printf("%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n", + i, avg, *tcfg->tvar->enqueued, *tcfg->tvar->dropped, + drop_prob * 100.0, drop_rate * 100.0, diff, + (double)tcfg->tqueue->drop_tolerance); + } +out: + return result; +} + +static uint32_t ft3_qlen[] = {100}; + +static struct test_rte_pie_config ft3_tconfig = { + .pconfig = ft_wpconfig, + .num_cfg = RTE_DIM(ft_wpconfig), + .qdelay_ref = 15, + .dp_update_interval = ft_dp_update_interval, + .max_burst = ft_max_burst, + .tailq_th = 15, +}; + +static struct test_queue ft3_tqueue = { + .pdata_in = ft_rtdata, + .num_queues = RTE_DIM(ft_rtdata), + .qlen = ft3_qlen, + .q_ramp_up = 10, + .drop_tolerance = 0, +}; + +static struct test_var ft3_tvar = { + .num_iterations = 0, + .num_ops = 10000, + .clk_freq = 0, + .dropped = ft_dropped, + .enqueued = ft_enqueued, +}; + +/** + * Test F3: functional test 3 + */ +static uint32_t ft3_tlevels[] = {64, 127, 222}; + +static struct test_config func_test_config3 = { + .ifname = "functional test interface", + .msg = "functional test 2 : use one pie configuration\n" + "using non zero qlen\n\n", + .htxt = " " + "drop probability " + "enqueued " + "dropped " + "drop prob % " + "drop rate % " + "diff % " + "tolerance % " + "active " + "\n", + .tconfig = &ft3_tconfig, + .tqueue = &ft3_tqueue, + .tvar = &ft3_tvar, + .tlevel = ft3_tlevels, +}; + +static enum test_result func_test3(struct test_config *tcfg) +{ + enum test_result result = PASS; + uint32_t i = 0; + + printf("%s", tcfg->msg); + + if (test_rte_pie_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + printf("%s", tcfg->htxt); + + /** + * reset rte_pie run-time data + */ + rte_pie_rt_data_init(tcfg->tqueue->pdata_in); + rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); + *tcfg->tvar->enqueued = 0; + *tcfg->tvar->dropped = 0; + + if (increase_qsize(&tcfg->tconfig->pconfig[i], + tcfg->tqueue->pdata_in, + tcfg->tqueue->qlen, + tcfg->tlevel[i], + tcfg->tqueue->q_ramp_up) != 0) { + fprintf(stderr, "Fail: increase qsize\n"); + result = FAIL; + goto out; + } + + for (i = 0; i < RTE_DIM(ft_tlevels); i++) { + const char *label = NULL; + uint16_t prob = 0; + uint16_t active = 0; + double drop_rate = 1.0; + double drop_prob = 0.0; + double diff = 0.0; + + enqueue_dequeue_func(&tcfg->tconfig->pconfig[i], + tcfg->tqueue->pdata_in, + tcfg->tqueue->qlen, + tcfg->tvar->num_ops, + tcfg->tvar->enqueued, + tcfg->tvar->dropped); + + drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, + *tcfg->tvar->dropped); + drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in); + + if (drop_prob != 0) { + fprintf(stderr, "Fail: check drop prob\n"); + result = FAIL; + } + + if (drop_rate != 0) { + fprintf(stderr, "Fail: check drop rate\n"); + result = FAIL; + } + + label = "Summary "; + active = rte_pie_get_active(NULL, tcfg->tqueue->pdata_in); + printf("%s%-16u%-12u%-12u%-12.4lf%-12.4lf%-12.4lf%-12.4lf%-8i\n", + label, prob, *tcfg->tvar->enqueued, *tcfg->tvar->dropped, + drop_prob * 100.0, drop_rate * 100.0, diff, + (double)tcfg->tqueue->drop_tolerance, active); + } +out: + return result; +} + +/** + * setup default values for the Performance test structures + */ +static struct rte_pie_config pt_wrconfig[1]; +static struct rte_pie pt_rtdata[1]; +static struct rte_pie pt_wtdata[1]; +static uint32_t pt_q[] = {0}; +static uint32_t pt_dropped[] = {0}; +static uint32_t pt_enqueued[] = {0}; +static uint32_t pt_dequeued[] = {0}; +static uint16_t pt_max_burst[] = {64}; +static uint16_t pt_dp_update_interval[] = {150}; + +static struct test_rte_pie_config pt_tconfig = { + .pconfig = pt_wrconfig, + .num_cfg = RTE_DIM(pt_wrconfig), + .qdelay_ref = 15, + .dp_update_interval = pt_dp_update_interval, + .max_burst = pt_max_burst, + .tailq_th = 150, +}; + +static struct test_queue pt_tqueue = { + .pdata_in = pt_rtdata, + .num_queues = RTE_DIM(pt_rtdata), + .qlen = pt_q, + .q_ramp_up = 1000000, + .drop_tolerance = 0, /* 0 percent */ +}; + +static struct test_rte_pie_config pt_tconfig2 = { + .pconfig = pt_wrconfig, + .num_cfg = RTE_DIM(pt_wrconfig), + .qdelay_ref = 15, + .dp_update_interval = pt_dp_update_interval, + .max_burst = pt_max_burst, + .tailq_th = 150, +}; + +static struct test_queue pt_tqueue2 = { + .pdata_in = pt_rtdata, + .pdata_out = pt_wtdata, + .num_queues = RTE_DIM(pt_rtdata), + .qlen = pt_q, + .q_ramp_up = 1000000, + .drop_tolerance = 0, /* 0 percent */ +}; + +/** + * enqueue/dequeue packets + * aka + * rte_sched_port_enqueue(port, in_mbufs, 10); + * rte_sched_port_dequeue(port, out_mbufs, 10); + */ +static void enqueue_dequeue_perf(struct rte_pie_config *pie_cfg, + struct rte_pie *pie_in, + struct rte_pie *pie_out, + uint32_t *qlen, + uint32_t num_ops, + uint32_t *enqueued, + uint32_t *dropped, + uint32_t *dequeued, + struct rdtsc_prof *prof) +{ + uint32_t i = 0; + + if (pie_cfg == NULL) { + printf("%s: Error: PIE configuration cannot be empty.\n", __func__); + return; + } + + if (pie_in == NULL) { + printf("%s: Error: PIE enqueue data cannot be empty.\n", __func__); + return; + } + + for (i = 0; i < num_ops; i++) { + uint64_t ts = 0; + int ret = 0; + + /** + * enqueue + */ + ts = get_port_ts(); + rdtsc_prof_start(prof); + ret = rte_pie_enqueue(pie_cfg, pie_in, *qlen, + 1000*sizeof(uint32_t), ts); + rdtsc_prof_end(prof); + + if (ret == 0) + (*enqueued)++; + else + (*dropped)++; + + if (pie_out != NULL) { + ts = get_port_ts(); + rdtsc_prof_start(prof); + rte_pie_dequeue(pie_out, 1000*sizeof(uint32_t), ts); + rdtsc_prof_end(prof); + + (*dequeued)++; + } + } +} + +/** + * Setup test structures for tests P1 + * performance tests 1 + */ +static uint32_t pt1_tlevel[] = {80}; + +static struct test_var perf1_tvar = { + .num_iterations = 0, + .num_ops = 30000, + .clk_freq = 0, + .dropped = pt_dropped, + .enqueued = pt_enqueued +}; + +static struct test_config perf_test_config = { + .ifname = "performance test 1 interface", + .msg = "performance test 1 : use one PIE configuration,\n" + " measure enqueue performance\n\n", + .tconfig = &pt_tconfig, + .tqueue = &pt_tqueue, + .tvar = &perf1_tvar, + .tlevel = pt1_tlevel, +}; + +/** + * Performance test function to measure enqueue performance. + * + */ +static enum test_result perf_test(struct test_config *tcfg) +{ + enum test_result result = PASS; + struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL}; + uint32_t total = 0; + + printf("%s", tcfg->msg); + + rdtsc_prof_init(&prof, "enqueue"); + + if (test_rte_pie_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + /** + * initialize the rte_pie run time data structure + */ + rte_pie_rt_data_init(tcfg->tqueue->pdata_in); + rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); + *tcfg->tvar->enqueued = 0; + *tcfg->tvar->dropped = 0; + + enqueue_dequeue_perf(tcfg->tconfig->pconfig, + tcfg->tqueue->pdata_in, + NULL, + tcfg->tqueue->qlen, + tcfg->tvar->num_ops, + tcfg->tvar->enqueued, + tcfg->tvar->dropped, + tcfg->tvar->dequeued, + &prof); + + total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped; + + printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", + total, *tcfg->tvar->enqueued, + ((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0, + *tcfg->tvar->dropped, + ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0); + + rdtsc_prof_print(&prof); +out: + return result; +} + + + +/** + * Setup test structures for tests P2 + * performance tests 2 + */ +static uint32_t pt2_tlevel[] = {80}; + +static struct test_var perf2_tvar = { + .num_iterations = 0, + .num_ops = 30000, + .clk_freq = 0, + .dropped = pt_dropped, + .enqueued = pt_enqueued, + .dequeued = pt_dequeued +}; + +static struct test_config perf_test_config2 = { + .ifname = "performance test 2 interface", + .msg = "performance test 2 : use one PIE configuration,\n" + " measure enqueue & dequeue performance\n\n", + .tconfig = &pt_tconfig2, + .tqueue = &pt_tqueue2, + .tvar = &perf2_tvar, + .tlevel = pt2_tlevel, +}; + +/** + * Performance test function to measure enqueue & dequeue performance. + * + */ +static enum test_result perf_test2(struct test_config *tcfg) +{ + enum test_result result = PASS; + struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL}; + uint32_t total = 0; + + printf("%s", tcfg->msg); + + rdtsc_prof_init(&prof, "enqueue"); + + if (test_rte_pie_init(tcfg) != PASS) { + result = FAIL; + goto out; + } + + /** + * initialize the rte_pie run time data structure + */ + rte_pie_rt_data_init(tcfg->tqueue->pdata_in); + rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); + *tcfg->tvar->enqueued = 0; + *tcfg->tvar->dequeued = 0; + *tcfg->tvar->dropped = 0; + + enqueue_dequeue_perf(tcfg->tconfig->pconfig, + tcfg->tqueue->pdata_in, + tcfg->tqueue->pdata_out, + tcfg->tqueue->qlen, + tcfg->tvar->num_ops, + tcfg->tvar->enqueued, + tcfg->tvar->dropped, + tcfg->tvar->dequeued, + &prof); + + total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped; + + printf("\ntotal: %u, dequeued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", + total, *tcfg->tvar->dequeued, + ((double)(*tcfg->tvar->dequeued) / (double)total) * 100.0, + *tcfg->tvar->dropped, + ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0); + + rdtsc_prof_print(&prof); +out: + return result; +} + +/** + * define the functional tests to be executed fast + */ +struct tests func_pie_tests_quick[] = { + { &func_test_config1, func_test1 }, + { &func_test_config2, func_test2 }, +}; + +/** + * define the functional and performance tests to be executed + */ +struct tests func_pie_tests[] = { + { &func_test_config1, func_test1 }, + { &func_test_config2, func_test2 }, + { &func_test_config3, func_test3 }, +}; + +struct tests perf_pie_tests[] = { + { &perf_test_config, perf_test }, + { &perf_test_config2, perf_test2 }, +}; + +/** + * function to execute the required pie tests + */ +static void run_tests(struct tests *test_type, uint32_t test_count, + uint32_t *num_tests, uint32_t *num_pass) +{ + enum test_result result = PASS; + uint32_t i = 0; + static const char *bar_str = "-------------------------------------" + "-------------------------------------------"; + static const char *bar_pass_str = "-------------------------------------" + "-------------------------------------"; + static const char *bar_fail_str = "-------------------------------------" + "-------------------------------------"; + + for (i = 0; i < test_count; i++) { + printf("\n%s\n", bar_str); + result = test_type[i].testfn(test_type[i].testcfg); + (*num_tests)++; + if (result == PASS) { + (*num_pass)++; + printf("%s\n", bar_pass_str); + } else { + printf("%s\n", bar_fail_str); + } + } +} + +/** + * check if functions accept invalid parameters + * + * First, all functions will be called without initialized PIE + * Then, all of them will be called with NULL/invalid parameters + * + * Some functions are not tested as they are performance-critical and thus + * don't do any parameter checking. + */ +static int +test_invalid_parameters(void) +{ + struct rte_pie_config config; + static const char *shf_str = "rte_pie_config_init should have failed!"; + static const char *shf_rt_str = "rte_pie_rt_data_init should have failed!"; + + /* NULL config */ + if (rte_pie_rt_data_init(NULL) == 0) { + printf("%i: %s\n", __LINE__, shf_rt_str); + return -1; + } + + /* NULL config */ + if (rte_pie_config_init(NULL, 0, 0, 0, 0) == 0) { + printf("%i%s\n", __LINE__, shf_str); + return -1; + } + + /* qdelay_ref <= 0 */ + if (rte_pie_config_init(&config, 0, 1, 1, 1) == 0) { + printf("%i%s\n", __LINE__, shf_str); + return -1; + } + + /* dp_update_interval <= 0 */ + if (rte_pie_config_init(&config, 1, 0, 1, 1) == 0) { + printf("%i%s\n", __LINE__, shf_str); + return -1; + } + + /* max_burst <= 0 */ + if (rte_pie_config_init(&config, 1, 1, 0, 1) == 0) { + printf("%i%s\n", __LINE__, shf_str); + return -1; + } + + /* tailq_th <= 0 */ + if (rte_pie_config_init(&config, 1, 1, 1, 0) == 0) { + printf("%i%s\n", __LINE__, shf_str); + return -1; + } + + RTE_SET_USED(config); + + return 0; +} + +static void +show_stats(const uint32_t num_tests, const uint32_t num_pass) +{ + if (num_pass == num_tests) + printf("[total: %u, pass: %u]\n", num_tests, num_pass); + else + printf("[total: %u, pass: %u, fail: %u]\n", num_tests, num_pass, + num_tests - num_pass); +} + +static int +tell_the_result(const uint32_t num_tests, const uint32_t num_pass) +{ + return (num_pass == num_tests) ? 0 : 1; +} + +static int +test_pie(void) +{ + uint32_t num_tests = 0; + uint32_t num_pass = 0; + + if (test_invalid_parameters() < 0) + return -1; + + run_tests(func_pie_tests_quick, RTE_DIM(func_pie_tests_quick), + &num_tests, &num_pass); + show_stats(num_tests, num_pass); + return tell_the_result(num_tests, num_pass); +} + +static int +test_pie_perf(void) +{ + uint32_t num_tests = 0; + uint32_t num_pass = 0; + + run_tests(perf_pie_tests, RTE_DIM(perf_pie_tests), &num_tests, &num_pass); + show_stats(num_tests, num_pass); + return tell_the_result(num_tests, num_pass); +} + +static int +test_pie_all(void) +{ + uint32_t num_tests = 0; + uint32_t num_pass = 0; + + if (test_invalid_parameters() < 0) + return -1; + + run_tests(func_pie_tests, RTE_DIM(func_pie_tests), &num_tests, &num_pass); + run_tests(perf_pie_tests, RTE_DIM(perf_pie_tests), &num_tests, &num_pass); + show_stats(num_tests, num_pass); + return tell_the_result(num_tests, num_pass); +} + +REGISTER_TEST_COMMAND(pie_autotest, test_pie); +REGISTER_TEST_COMMAND(pie_perf, test_pie_perf); +REGISTER_TEST_COMMAND(pie_all, test_pie_all); diff --git a/lib/sched/rte_pie.c b/lib/sched/rte_pie.c index 2fcecb2db4..934e9aee50 100644 --- a/lib/sched/rte_pie.c +++ b/lib/sched/rte_pie.c @@ -13,7 +13,7 @@ #pragma warning(disable:2259) /* conversion may lose significant bits */ #endif -void +int rte_pie_rt_data_init(struct rte_pie *pie) { if (pie == NULL) { @@ -22,6 +22,8 @@ rte_pie_rt_data_init(struct rte_pie *pie) if (pie == NULL) RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__); + + return -1; } pie->active = 0; @@ -35,6 +37,8 @@ rte_pie_rt_data_init(struct rte_pie *pie) pie->qdelay_old = 0; pie->drop_prob = 0; pie->accu_prob = 0; + + return 0; } int diff --git a/lib/sched/rte_pie.h b/lib/sched/rte_pie.h index f83c95664f..68f1b96192 100644 --- a/lib/sched/rte_pie.h +++ b/lib/sched/rte_pie.h @@ -20,6 +20,7 @@ extern "C" { #include #include +#include #define RTE_DQ_THRESHOLD 16384 /**< Queue length threshold (2^14) * to start measurement cycle (bytes) @@ -53,7 +54,7 @@ struct rte_pie_config { }; /** - * RED run-time data + * PIE run-time data */ struct rte_pie { uint16_t active; /**< Flag for activating/deactivating pie */ @@ -74,8 +75,12 @@ struct rte_pie { * @brief Initialises run-time data * * @param pie [in,out] data pointer to PIE runtime data + * + * @return Operation status + * @retval 0 success + * @retval !0 error */ -void +int __rte_experimental rte_pie_rt_data_init(struct rte_pie *pie); @@ -113,7 +118,7 @@ rte_pie_config_init(struct rte_pie_config *pie_cfg, * @retval 0 enqueue the packet * @retval !0 drop the packet */ -static inline int +static int __rte_experimental rte_pie_enqueue_empty(const struct rte_pie_config *pie_cfg, struct rte_pie *pie, @@ -145,7 +150,7 @@ rte_pie_enqueue_empty(const struct rte_pie_config *pie_cfg, * @param pie [in, out] data pointer to PIE runtime data * @param time [in] current time (measured in cpu cycles) */ -static inline void +static void __rte_experimental _calc_drop_probability(const struct rte_pie_config *pie_cfg, struct rte_pie *pie, uint64_t time) @@ -155,7 +160,7 @@ _calc_drop_probability(const struct rte_pie_config *pie_cfg, /* Note: can be implemented using integer multiply. * DQ_THRESHOLD is power of 2 value. */ - double current_qdelay = pie->qlen * (pie->avg_dq_time / RTE_DQ_THRESHOLD); + uint64_t current_qdelay = pie->qlen * (pie->avg_dq_time >> 14); double p = RTE_ALPHA * (current_qdelay - qdelay_ref) + RTE_BETA * (current_qdelay - pie->qdelay_old); @@ -181,7 +186,7 @@ _calc_drop_probability(const struct rte_pie_config *pie_cfg, double qdelay = qdelay_ref * 0.5; /* Exponentially decay drop prob when congestion goes away */ - if (current_qdelay < qdelay && pie->qdelay_old < qdelay) + if ((double)current_qdelay < qdelay && pie->qdelay_old < qdelay) pie->drop_prob *= 0.98; /* 1 - 1/64 is sufficient */ /* Bound drop probability */ -- 2.25.1