diff options
Diffstat (limited to 'host/lib/transport/uhd-dpdk/test')
| -rw-r--r-- | host/lib/transport/uhd-dpdk/test/Makefile | 53 | ||||
| -rw-r--r-- | host/lib/transport/uhd-dpdk/test/test.c | 303 | 
2 files changed, 356 insertions, 0 deletions
| diff --git a/host/lib/transport/uhd-dpdk/test/Makefile b/host/lib/transport/uhd-dpdk/test/Makefile new file mode 100644 index 000000000..9d6e60372 --- /dev/null +++ b/host/lib/transport/uhd-dpdk/test/Makefile @@ -0,0 +1,53 @@ +#   BSD LICENSE +# +#   Copyright(c) 2010-2014 Intel Corporation. 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. + +ifeq ($(RTE_SDK),) +$(error "Please define RTE_SDK environment variable") +endif + +# Default target, can be overridden by command line or environment +RTE_TARGET ?= x86_64-native-linuxapp-gcc + +include $(RTE_SDK)/mk/rte.vars.mk + +# binary name +APP = test + +# all source are stored in SRCS-y +SRCS-y := test.c + +CFLAGS += -O0 -g +CFLAGS += $(WERROR_FLAGS) + +EXTRA_CFLAGS=-I${S}/../include +EXTRA_LDFLAGS=-L${O}/lib -luhd-dpdk + +include $(RTE_SDK)/mk/rte.extapp.mk diff --git a/host/lib/transport/uhd-dpdk/test/test.c b/host/lib/transport/uhd-dpdk/test/test.c new file mode 100644 index 000000000..c324561de --- /dev/null +++ b/host/lib/transport/uhd-dpdk/test/test.c @@ -0,0 +1,303 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// +/** + * Benchmark program to check performance of 2 simultaneous links + */ + + +#include <uhd-dpdk.h> +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> +#include <errno.h> +#include <arpa/inet.h> + +#define NUM_MBUFS 4095 +#define MBUF_CACHE_SIZE 315 +#define BURST_SIZE 64 + +#define NUM_PORTS 2 +#define TX_CREDITS 28 +#define RX_CREDITS 64 +#define BENCH_SPP 700 +#define BENCH_IFG 220 + + +static uint32_t last_seqno[NUM_PORTS]; +static uint32_t dropped_packets[NUM_PORTS]; +static uint32_t lasts[NUM_PORTS][16], drops[NUM_PORTS][16]; +static uint32_t last_ackno[NUM_PORTS]; +static uint32_t tx_seqno[NUM_PORTS]; +static uint64_t tx_xfer[NUM_PORTS]; + +static void process_udp(int id, uint32_t *udp_data) +{ +	if (udp_data[0] != last_seqno[id] + 1) { +		lasts[id][dropped_packets[id] & 0xf] = last_seqno[id]; +		drops[id][dropped_packets[id] & 0xf] = udp_data[0]; +		dropped_packets[id]++; +	} + +	last_seqno[id] = udp_data[0]; +	last_ackno[id] = udp_data[1]; +} + +static void send_ctrl(struct uhd_dpdk_socket *sock, uint32_t run) +{ +	struct rte_mbuf *mbuf = NULL; +	uhd_dpdk_request_tx_bufs(sock, &mbuf, 1); +	if (unlikely(mbuf == NULL)) +		return; +	uint32_t *tx_data = uhd_dpdk_buf_to_data(sock, mbuf); +	tx_data[0] = (BENCH_SPP << 16) | (TX_CREDITS << 4) | run; // spp, tx_credits, run +	tx_data[1] = (RX_CREDITS << 16) | (BENCH_IFG); // credits, ifg +	mbuf->pkt_len = 8; +	mbuf->data_len = 8; +	uhd_dpdk_send(sock, &mbuf, 1); +} + +static void send_udp(struct uhd_dpdk_socket *sock, int id, bool fc_only) +{ +	struct rte_mbuf *mbuf = NULL; +	uhd_dpdk_request_tx_bufs(sock, &mbuf, 1); +	if (unlikely(mbuf == NULL)) +		return; +	uint32_t *tx_data = uhd_dpdk_buf_to_data(sock, mbuf); +	tx_data[0] = fc_only ? tx_seqno[id] - 1 : tx_seqno[id]; +	tx_data[1] = last_seqno[id]; +	if (!fc_only) { +		memset(&tx_data[2], last_seqno[id], 8*BENCH_SPP); +		tx_xfer[id] += 8*BENCH_SPP; +	} +	mbuf->pkt_len = 8 + (fc_only ? 0 : 8*BENCH_SPP); +	mbuf->data_len = 8 + (fc_only ? 0 : 8*BENCH_SPP); + +	uhd_dpdk_send(sock, &mbuf, 1); + +	if (!fc_only) { +		tx_seqno[id]++; +	} +} + +static void bench(struct uhd_dpdk_socket **tx, struct uhd_dpdk_socket **rx, struct uhd_dpdk_socket **ctrl, uint32_t nb_ports) +{ +	uint64_t total_xfer[NUM_PORTS]; +	uint32_t id; +	for (id = 0; id < nb_ports; id++) { +		tx_seqno[id] = 1; +		tx_xfer[id] = 0; +		last_ackno[id] = 0; +		last_seqno[id] = 0; +		dropped_packets[id] = 0; +		total_xfer[id] = 0; +	} +	sleep(1); +	struct timeval bench_start, bench_end; +	gettimeofday(&bench_start, NULL); +	for (id = 0; id < nb_ports; id++) { +		send_ctrl(ctrl[id], 0); +		for (int pktno = 0; (pktno < TX_CREDITS*3/4); pktno++) { +			send_udp(tx[id], id, false); +		} +	} +	for (id = 0; id < nb_ports; id++) { +		send_ctrl(ctrl[id], 1); +	} +	/* +	 * The test... +	 */ +	uint64_t total_received = 0; +	uint32_t consec_no_rx = 0; +	while (total_received < 1000000 ) { //&& consec_no_rx < 10000) { +		for (id = 0; id < nb_ports; id++) { + +			/* Get burst of RX packets, from first port of pair. */ +			struct rte_mbuf *bufs[BURST_SIZE]; +			const int64_t nb_rx = uhd_dpdk_recv(rx[id], bufs, BURST_SIZE); + +			if (unlikely(nb_rx <= 0)) { +				consec_no_rx++; +				if (consec_no_rx >= 100000) { +					uint32_t skt_drops = 0; +					uhd_dpdk_get_drop_count(rx[id], &skt_drops); +					printf("TX seq %d, TX ack %d, RX seq %d, %d, drops!\n", tx_seqno[id], last_ackno[id], last_seqno[id], skt_drops); +					consec_no_rx = 0; +					break; +				} +				continue; +			} else { +				consec_no_rx = 0; +			} + +			for (int buf = 0; buf < nb_rx; buf++) { +				total_xfer[id] += bufs[buf]->pkt_len; +				uint64_t ol_flags = bufs[buf]->ol_flags; +				uint32_t *data = (uint32_t *) uhd_dpdk_buf_to_data(rx[id], bufs[buf]); +				if (ol_flags == PKT_RX_IP_CKSUM_BAD) { /* FIXME: Deprecated/changed in later release */ +					printf("Buf %d: Bad IP cksum\n", buf); +				} else { +					process_udp(id, data); +				} +			} + +			/* Free buffers. */ +			for (int buf = 0; buf < nb_rx; buf++) +				uhd_dpdk_free_buf(bufs[buf]); +			total_received += nb_rx; +		} + +		for (id = 0; id < nb_ports; id++) { +			/* TX portion */ +			uint32_t window_end = last_ackno[id] + TX_CREDITS; +			//uint32_t window_end = last_seqno[port] + TX_CREDITS; +			if (window_end <= tx_seqno[id]) { +				if (consec_no_rx == 9999) { +					send_udp(tx[id], id, true); +				} +				//send_udp(tx[id], id, true); +				; +			} else { +				for (int pktno = 0; (pktno < BURST_SIZE) && (tx_seqno[id] < window_end); pktno++) { +					send_udp(tx[id], id, false); +				} +			} +		} +	} +	for (id = 0; id < nb_ports; id++) { +		send_ctrl(ctrl[id], 0); +	} +	gettimeofday(&bench_end, NULL); +	printf("Benchmark complete\n\n"); + +	for (id = 0; id < nb_ports; id++) { +		printf("\n"); +		printf("Bytes received = %ld\n", total_xfer[id]); +		printf("Bytes sent = %ld\n", tx_xfer[id]); +		printf("Time taken = %ld us\n", (bench_end.tv_sec - bench_start.tv_sec)*1000000 + (bench_end.tv_usec - bench_start.tv_usec)); +		double elapsed_time = (bench_end.tv_sec - bench_start.tv_sec)*1000000 + (bench_end.tv_usec - bench_start.tv_usec); +		elapsed_time *= 1.0e-6; +		double elapsed_bytes = total_xfer[id]; +		printf("RX Performance = %e Gbps\n", elapsed_bytes*8.0/1.0e9/elapsed_time); +		elapsed_bytes = tx_xfer[id]; +		printf("TX Performance = %e Gbps\n", elapsed_bytes*8.0/1.0e9/elapsed_time); +		uint32_t skt_drops = 0; +		uhd_dpdk_get_drop_count(rx[id], &skt_drops); +		printf("Dropped %d packets\n", dropped_packets[id]); +		printf("Socket reports dropped %d packets\n", skt_drops); +		for (unsigned int i = 0; i < 16; i++) { +			if (i >= dropped_packets[id]) +				break; +			printf("Last(%u), Recv(%u)\n", lasts[id][i], drops[id][i]); +		} +		//printf("%d missed/dropped packets\n", errors); +		printf("\n"); +	} + +} + +int main(int argc, char **argv) +{ +	int port_thread_mapping[2] = {1, 1}; +	int status = uhd_dpdk_init(argc, argv, 2, &port_thread_mapping[0], NUM_MBUFS, MBUF_CACHE_SIZE); +	if (status) { +		printf("%d: Something wrong?\n", status); +		return status; +	} + +	uint32_t eth_ip = htonl(0xc0a80008); +	uint32_t eth_mask = htonl(0xffffff00); +	status = uhd_dpdk_set_ipv4_addr(0, eth_ip, eth_mask); +	if (status) { +		printf("Error while setting IP0: %d\n", status); +		return status; +	} +	status = uhd_dpdk_set_ipv4_addr(1, eth_ip, eth_mask); +	if (status) { +		printf("Error while setting IP1: %d\n", status); +		return status; +	} + +	struct uhd_dpdk_socket *eth_rx[2]; +	struct uhd_dpdk_socket *eth_tx[2]; +	struct uhd_dpdk_socket *eth_ctrl[2]; +	struct uhd_dpdk_sockarg_udp sockarg = { +		.is_tx = false, +		.local_port = htons(0xBEE7), +		.remote_port = htons(0xBEE7), +		.dst_addr = htonl(0xc0a80004) +	}; +	eth_rx[0] = uhd_dpdk_sock_open(0, UHD_DPDK_SOCK_UDP, &sockarg); +	if (!eth_rx[0]) { +		printf("!eth0_rx\n"); +		return -ENODEV; +	} +	eth_rx[1] = uhd_dpdk_sock_open(1, UHD_DPDK_SOCK_UDP, &sockarg); +	if (!eth_rx[1]) { +		printf("!eth1_rx\n"); +		return -ENODEV; +	} + +	sockarg.is_tx = true; +	eth_tx[0] = uhd_dpdk_sock_open(0, UHD_DPDK_SOCK_UDP, &sockarg); +	if (!eth_tx[0]) { +		printf("!eth0_tx\n"); +		return -ENODEV; +	} +	eth_tx[1] = uhd_dpdk_sock_open(1, UHD_DPDK_SOCK_UDP, &sockarg); +	if (!eth_tx[1]) { +		printf("!eth1_tx\n"); +		return -ENODEV; +	} + +	sockarg.local_port = htons(0xB4D); +	sockarg.remote_port = htons(0xB4D); +	eth_ctrl[0] = uhd_dpdk_sock_open(0, UHD_DPDK_SOCK_UDP, &sockarg); +	if (!eth_ctrl[0]) { +		printf("!eth0_ctrl\n"); +		return -ENODEV; +	} +	eth_ctrl[1] = uhd_dpdk_sock_open(1, UHD_DPDK_SOCK_UDP, &sockarg); +	if (!eth_ctrl[1]) { +		printf("!eth1_ctrl\n"); +		return -ENODEV; +	} + +	bench(eth_tx, eth_rx, eth_ctrl, 2); + +	status = uhd_dpdk_sock_close(eth_rx[0]); +	if (status) { +		printf("Bad close RX0 %d\n", status); +		return status; +	} +	status = uhd_dpdk_sock_close(eth_rx[1]); +	if (status) { +		printf("Bad close RX1 %d\n", status); +		return status; +	} +	status = uhd_dpdk_sock_close(eth_tx[0]); +	if (status) { +		printf("Bad close TX0 %d\n", status); +		return status; +	} +	status = uhd_dpdk_sock_close(eth_tx[1]); +	if (status) { +		printf("Bad close TX1 %d\n", status); +		return status; +	} +	status = uhd_dpdk_sock_close(eth_ctrl[0]); +	if (status) { +		printf("Bad close Ctrl0 %d\n", status); +		return status; +	} +	status = uhd_dpdk_sock_close(eth_ctrl[1]); +	if (status) { +		printf("Bad close Ctrl1 %d\n", status); +		return status; +	} +	return status; +} | 
