From: Luca Boccassi <bluca@debian.org>
To: alangordondewar@gmail.com, cristian.dumitrescu@intel.com
Cc: dev@dpdk.org, chas3@att.com, luca.boccassi@att.com,
alan.robertson@att.com, Alan Dewar <alan.dewar@att.com>
Subject: Re: [PATCH] test: new sched WRR unit-test
Date: Thu, 16 Nov 2017 18:12:26 +0000 [thread overview]
Message-ID: <1510855946.11864.5.camel@debian.org> (raw)
In-Reply-To: <1510852731-27555-1-git-send-email-alan.dewar@att.com>
On Thu, 2017-11-16 at 17:18 +0000, alangordondewar@gmail.com wrote:
> From: Alan Dewar <alan.dewar@att.com>
>
> New unit-test for the librte_sched WRR weighting code.
>
> With the standard 17.11 code, the first three sub-tests pass, but
> the last two fail due to bugs in the WRR weighting code.
>
> With the "sched: fix overflow errors in WRR weighting code" patch
> all five sub-tests pass.
>
> Signed-off-by: Alan Dewar <alan.dewar@att.com>
> ---
> test/test/Makefile | 1 +
> test/test/test_sched_wrr.c | 434
> +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 435 insertions(+)
> create mode 100644 test/test/test_sched_wrr.c
>
> diff --git a/test/test/Makefile b/test/test/Makefile
> index bb54c98..0ab0ed3 100644
> --- a/test/test/Makefile
> +++ b/test/test/Makefile
> @@ -173,6 +173,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_NET) += test_crc.c
> ifeq ($(CONFIG_RTE_LIBRTE_SCHED),y)
> SRCS-y += test_red.c
> SRCS-y += test_sched.c
> +SRCS-y += test_sched_wrr.c
> endif
>
> SRCS-$(CONFIG_RTE_LIBRTE_METER) += test_meter.c
> diff --git a/test/test/test_sched_wrr.c b/test/test/test_sched_wrr.c
> new file mode 100644
> index 0000000..3214091
> --- /dev/null
> +++ b/test/test/test_sched_wrr.c
> @@ -0,0 +1,434 @@
> +/*-
> + * BSD LICENSE
> + *
> + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> + * Copyright(c) 2017 ATT Intellectual Property. All rights
> reserved.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or
> without
> + * modification, are permitted provided that the following
> conditions
> + * are met:
> + *
> + * * Redistributions of source code must retain the above
> copyright
> + * notice, this list of conditions and the following
> disclaimer.
> + * * Redistributions in binary form must reproduce the above
> copyright
> + * notice, this list of conditions and the following
> disclaimer in
> + * the documentation and/or other materials provided with the
> + * distribution.
> + * * Neither the name of Intel Corporation nor the names of its
> + * contributors may be used to endorse or promote products
> derived
> + * from this software without specific prior written
> permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> + *
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdint.h>
> +#include <unistd.h>
> +
> +#include "test.h"
> +
> +#include <rte_cycles.h>
> +#include <rte_ether.h>
> +#include <rte_ip.h>
> +#include <rte_byteorder.h>
> +#include <rte_sched.h>
> +
> +
> +#define SUBPORT 0
> +#define PIPE 1
> +#define TC 0 // 2
> +#define QUEUE 3
> +
> +static struct rte_sched_subport_params subport_param[] = {
> + {
> + .tb_rate = 1250000000,
> + .tb_size = 1000000,
> +
> + .tc_rate = {1250000000, 1250000000, 1250000000,
> 1250000000},
> + .tc_period = 10,
> + },
> +};
> +
> +static struct rte_sched_pipe_params pipe_profile[] = {
> + { /* Profile #0 */
> + .tb_rate = 305175,
> + .tb_size = 1000000,
> +
> + .tc_rate = {305175, 305175, 305175, 305175},
> + .tc_period = 160,
> +
> + .wrr_weights = {1, 1, 1, 1,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1},
> + },
> +};
> +
> +static struct rte_sched_port_params port_param = {
> + .socket = 0, /* computed */
> + .rate = 0, /* computed */
> + .mtu = 1522,
> + .frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
> + .n_subports_per_port = 1,
> + .n_pipes_per_subport = 1024,
> + .qsize = {32, 32, 32, 32},
> + .pipe_profiles = pipe_profile,
> + .n_pipe_profiles = 1,
> +};
> +
> +#define NB_MBUF (4 * 32)
> +#define MBUF_DATA_SZ (2048 + RTE_PKTMBUF_HEADROOM)
> +#define MEMPOOL_CACHE_SZ 0
> +#define SOCKET 0
> +
> +
> +static struct rte_mempool *
> +create_mempool(uint32_t total_packets)
> +{
> + struct rte_mempool *mp;
> +
> + mp = rte_mempool_lookup("test_sched wrr");
> + if (!mp)
> + mp = rte_pktmbuf_pool_create("test_sched wrr",
> total_packets,
> + MEMPOOL_CACHE_SZ, 0, MBUF_DATA_SZ, SOCKET);
> +
> + return mp;
> +}
> +
> +static void
> +delete_mempool(struct rte_mempool *mp)
> +{
> + rte_mempool_free(mp);
> +}
> +
> +static void
> +prepare_pkt(struct rte_mbuf *mbuf, uint32_t tc, uint32_t queue)
> +{
> + struct ether_hdr *eth_hdr;
> + struct vlan_hdr *vlan1, *vlan2;
> + struct ipv4_hdr *ip_hdr;
> +
> + /* Simulate a classifier */
> + eth_hdr = rte_pktmbuf_mtod(mbuf, struct ether_hdr *);
> + vlan1 = (struct vlan_hdr *)(ð_hdr->ether_type);
> + vlan2 = (struct vlan_hdr *)((uintptr_t)ð_hdr->ether_type
> +
> + sizeof(struct vlan_hdr));
> + eth_hdr = (struct ether_hdr *)((uintptr_t)ð_hdr-
> >ether_type +
> + 2 * sizeof(struct vlan_hdr));
> + ip_hdr = (struct ipv4_hdr *)((uintptr_t)eth_hdr +
> + sizeof(eth_hdr->ether_type));
> +
> + vlan1->vlan_tci = rte_cpu_to_be_16(SUBPORT);
> + vlan2->vlan_tci = rte_cpu_to_be_16(PIPE);
> + eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
> + ip_hdr->dst_addr = IPv4(0, 0, TC, QUEUE);
> +
> +
> + rte_sched_port_pkt_write(mbuf, SUBPORT, PIPE, tc, queue,
> + e_RTE_METER_YELLOW);
> +
> + /* 64 byte packet */
> + mbuf->pkt_len = 60;
> + mbuf->data_len = 60;
> +}
> +
> +/*
> + * This function carries out the core of the enqueue/dequeue
> testing.
> + * This is where we should detect failures if the WRR code is
> broken.
> + */
> +static int
> +test_sched_wrr_enqueue_dequeue(const char *subtest_name,
> + struct rte_mempool *mp,
> + struct rte_sched_port *port,
> + struct rte_mbuf **in_mbufs,
> + struct rte_mbuf **out_mbufs,
> + int32_t enqueue_packets,
> + int32_t dequeue_packets,
> + uint32_t *expected_counts)
> +{
> + uint32_t wrr_counts[RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS] = {
> 0 };
> + uint32_t pipe;
> + int32_t i;
> + int err;
> +
> + /*
> + * Create the packets to be enqueued, spread them evenly
> across
> + * each of the four WRR queues of the test-TC
> + */
> + for (i = 0; i < enqueue_packets; i++) {
> + in_mbufs[i] = rte_pktmbuf_alloc(mp);
> + TEST_ASSERT_NOT_NULL(in_mbufs[i],
> + "%s: Packet allocation failed
> on packet "
> + "%d\n", subtest_name, i);
> + prepare_pkt(in_mbufs[i], TC, (i & 0x3));
> + }
> +
> + /*
> + * Queue all the enqueue packets, none should be dropped as
> the
> + * four queues should be long enough.
> + */
> + err = rte_sched_port_enqueue(port, in_mbufs,
> enqueue_packets);
> + TEST_ASSERT_EQUAL(err, enqueue_packets,
> + "%s: Enqueue failed, err: %d != %d\n",
> + subtest_name, err, enqueue_packets);
> +
> + /*
> + * Dequeue the required number of packets.
> + */
> + err = rte_sched_port_dequeue(port, out_mbufs,
> dequeue_packets);
> + TEST_ASSERT_EQUAL(err, dequeue_packets,
> + "%s: Dequeue failed, err: %d != %d\n",
> + subtest_name, err, dequeue_packets);
> +
> + /*
> + * Check each packet and count which WRR queue it came from.
> + */
> + for (i = 0; i < dequeue_packets; i++) {
> + enum rte_meter_color color;
> + uint32_t subport, traffic_class, queue;
> +
> + color = rte_sched_port_pkt_read_color(out_mbufs[i]);
> + TEST_ASSERT_EQUAL(color, e_RTE_METER_YELLOW,
> + "%s: Wrong color\n",
> subtest_name);
> +
> + rte_sched_port_pkt_read_tree_path(out_mbufs[i],
> + &subport, &pipe, &traffic_class,
> &queue);
> +
> + TEST_ASSERT_EQUAL(subport, SUBPORT, "%s: Wrong
> subport\n",
> + subtest_name);
> + TEST_ASSERT_EQUAL(pipe, PIPE, "%s: Wrong pipe\n",
> subtest_name);
> + TEST_ASSERT_EQUAL(traffic_class, TC,
> + "%s: Wrong traffic-class\n",
> subtest_name);
> + wrr_counts[queue]++;
> + rte_pktmbuf_free(out_mbufs[i]);
> + }
> +
> + /*
> + * Check the number of packets dequeued from each WRR queue
> + * against the expected counts.
> + */
> + err = 0;
> + for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
> + printf("%s - WRR queue %d, dequeued: %u, expected:
> %u\n",
> + subtest_name, i, wrr_counts[i],
> expected_counts[i]);
> + if (wrr_counts[i] != expected_counts[i])
> + err = -1;
> + }
> + return err;
> +}
> +
> +/*
> + * This function does the test config set-up and tear-down.
> + * If we see failures in here it is probably due to the test
> configuration.
> + */
> +static int
> +test_sched_wrr_test(const char *subtest_name, uint16_t *tc_qlengths,
> + uint8_t *wrr_weights, int32_t enqueue_packets,
> + int32_t dequeue_packets, uint32_t
> *expected_counts)
> +{
> + struct rte_mbuf **in_mbufs;
> + struct rte_mbuf **out_mbufs;
> + struct rte_mempool *mp = NULL;
> + struct rte_sched_port *port = NULL;
> + int32_t total_expected = 0;
> + uint32_t pipe;
> + int32_t i;
> + int err;
> +
> + /*
> + * Some inbound argument checking
> + */
> + TEST_ASSERT_EQUAL((tc_qlengths[TC] * 4), enqueue_packets,
> + "%s: Queue length/Enqueue packet
> mismatch\n",
> + subtest_name);
> + TEST_ASSERT((dequeue_packets <= enqueue_packets),
> + "%s: Dequeue packets %d > Enqueue packets %d\n",
> + subtest_name, dequeue_packets, enqueue_packets);
> +
> + for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++)
> + total_expected += expected_counts[i];
> +
> + TEST_ASSERT((dequeue_packets == total_expected),
> + "%s: Dequeue packets %d != Total expected %u\n",
> + subtest_name, dequeue_packets, total_expected);
> +
> + /*
> + * Create the mempool and allocate arrays to hold the
> rte_mbuf pointers
> + */
> + mp = create_mempool(enqueue_packets);
> + TEST_ASSERT_NOT_NULL(mp, "%s: Error creating mempool\n",
> subtest_name);
> +
> + in_mbufs = malloc(sizeof(struct rte_mbuf *) *
> enqueue_packets);
> + TEST_ASSERT_NOT_NULL(in_mbufs, "%s: Error creating in_mbuf
> array\n",
> + subtest_name);
> +
> + out_mbufs = malloc(sizeof(struct rte_mbuf *) *
> dequeue_packets);
> + TEST_ASSERT_NOT_NULL(out_mbufs, "%s: Error creating out_mbuf
> array\n",
> + subtest_name);
> +
> + /*
> + * Set up the port and pipe profiles with the TC's queue
> lengths
> + * and the WRR queue weightings
> + */
> + port_param.socket = 0;
> + port_param.rate = (uint64_t) 10000 * 1000 * 1000 / 8;
> + for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> + port_param.qsize[i] = tc_qlengths[i];
> +
> + for (i = 0; i < RTE_SCHED_QUEUES_PER_PIPE; i++)
> + pipe_profile[0].wrr_weights[i] = wrr_weights[i];
> +
> + port = rte_sched_port_config(&port_param);
> + TEST_ASSERT_NOT_NULL(port, "%s: Error config sched port\n",
> + subtest_name);
> +
> + err = rte_sched_subport_config(port, SUBPORT,
> subport_param);
> + TEST_ASSERT_SUCCESS(err, "%s: Error config sched, err=%d\n",
> + subtest_name, err);
> +
> + for (pipe = 0; pipe < port_param.n_pipes_per_subport;
> pipe++) {
> + err = rte_sched_pipe_config(port, SUBPORT, pipe, 0);
> + TEST_ASSERT_SUCCESS(err,
> + "%s: Error config sched pipe %u,
> err=%d\n",
> + subtest_name, pipe, err);
> + }
> +
> + /*
> + * Enqueue and dequeue packets checking that each WRR queue
> dequeued
> + * the correct number of packets.
> + */
> + err = test_sched_wrr_enqueue_dequeue(subtest_name, mp, port,
> in_mbufs,
> + out_mbufs,
> enqueue_packets,
> + dequeue_packets,
> + expected_counts);
> +
> + /*
> + * Free up allocated resources
> + */
> + free(in_mbufs);
> + free(out_mbufs);
> + rte_sched_port_free(port);
> + delete_mempool(mp);
> +
> + return err;
> +}
> +
> +static int
> +test_sched_wrr_even_weights(void)
> +{
> + uint16_t tc_qlengths[] = { 64, 64, 64, 64 };
> + uint8_t wrr_weights[] = { 1, 1, 1, 1, // TC-0
> + 1, 1, 1, 1, // TC-1
> + 1, 1, 1, 1, // TC-2
> + 1, 1, 1, 1 }; // TC-3
> + int32_t enqueue_packets = 64 * 4;
> + int32_t dequeue_packets = 32;
> + uint32_t expected_counts[] = { 8, 8, 8, 8 };
> +
> + return test_sched_wrr_test("wrr-even-weights", tc_qlengths,
> wrr_weights,
> + enqueue_packets, dequeue_packets,
> + expected_counts);
> +}
> +
> +static int
> +test_sched_wrr_8_4_2_1_weights(void)
> +{
> + uint16_t tc_qlengths[] = { 64, 64, 64, 64 };
> + uint8_t wrr_weights[] = { 8, 4, 2, 1, // TC-0
> + 1, 1, 1, 1,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1 };
> + int32_t enqueue_packets = 64 * 4;
> + int32_t dequeue_packets = 15;
> + uint32_t expected_counts[] = { 8, 4, 2, 1 };
> +
> + return test_sched_wrr_test("wrr-8-4-2-1-weights",
> tc_qlengths,
> + wrr_weights, enqueue_packets,
> + dequeue_packets,
> expected_counts);
> +}
> +
> +static int
> +test_sched_wrr_1_2_3_4_weights(void)
> +{
> + uint16_t tc_qlengths[] = { 64, 64, 64, 64 };
> + uint8_t wrr_weights[] = { 1, 2, 3, 4,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1 };
> + int32_t enqueue_packets = 64 * 4;
> + int32_t dequeue_packets = 40;
> + uint32_t expected_counts[] = { 4, 8, 12, 16 };
> +
> + return test_sched_wrr_test("wrr-1-2-3-4-weights",
> tc_qlengths,
> + wrr_weights, enqueue_packets,
> + dequeue_packets,
> expected_counts);
> +}
> +
> +static int
> +test_sched_wrr_11_7_5_3_weights(void)
> +{
> + uint16_t tc_qlengths[] = { 64, 64, 64, 64 };
> + uint8_t wrr_weights[] = { 11, 7, 5, 3,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1 };
> + int32_t enqueue_packets = 64 * 4;
> + int32_t dequeue_packets = 26;
> + uint32_t expected_counts[] = { 11, 7, 5, 3 };
> +
> + return test_sched_wrr_test("wrr-11-7-5-3-weights",
> tc_qlengths,
> + wrr_weights, enqueue_packets,
> + dequeue_packets,
> expected_counts);
> +}
> +
> +static int
> +test_sched_wrr_100_to_97_weights(void)
> +{
> + uint16_t tc_qlengths[] = { 128, 1, 1, 1 };
> + uint8_t wrr_weights[] = { 100, 99, 98, 97,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1,
> + 1, 1, 1, 1 };
> + int32_t enqueue_packets = 128 * 4;
> + int32_t dequeue_packets = 394;
> + uint32_t expected_counts[] = { 100, 99, 98, 97 };
> +
> + return test_sched_wrr_test("wrr-100-to-97-weights",
> tc_qlengths,
> + wrr_weights, enqueue_packets,
> + dequeue_packets,
> expected_counts);
> +}
> +
> +/**
> + * WRR test main entrance for library sched
> + */
> +static int
> +test_sched_wrr(void)
> +{
> + TEST_ASSERT_SUCCESS(test_sched_wrr_even_weights(),
> + "even-weight test failed\n");
> + TEST_ASSERT_SUCCESS(test_sched_wrr_8_4_2_1_weights(),
> + "8-4-2-1-weight test failed\n");
> + TEST_ASSERT_SUCCESS(test_sched_wrr_1_2_3_4_weights(),
> + "1-2-3-4-weight test failed\n");
> + TEST_ASSERT_SUCCESS(test_sched_wrr_11_7_5_3_weights(),
> + "11-7-5-3-weight test failed\n");
> + TEST_ASSERT_SUCCESS(test_sched_wrr_100_to_97_weights(),
> + "100-to-97-weight test failed\n");
> + return 0;
> +}
> +
> +REGISTER_TEST_COMMAND(sched_wrr_test, test_sched_wrr);
Reviewed-by: Luca Boccassi <bluca@debian.org>
LGTM
--
Kind regards,
Luca Boccassi
prev parent reply other threads:[~2017-11-16 18:12 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-16 17:18 [PATCH] test: new sched WRR unit-test alangordondewar
2017-11-16 18:12 ` Luca Boccassi [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1510855946.11864.5.camel@debian.org \
--to=bluca@debian.org \
--cc=alan.dewar@att.com \
--cc=alan.robertson@att.com \
--cc=alangordondewar@gmail.com \
--cc=chas3@att.com \
--cc=cristian.dumitrescu@intel.com \
--cc=dev@dpdk.org \
--cc=luca.boccassi@att.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.