diff mbox

[PATCHv2] validation: pktio: test batch receive

Message ID 1449853851-10152-1-git-send-email-stuart.haslam@linaro.org
State New
Headers show

Commit Message

Stuart Haslam Dec. 11, 2015, 5:10 p.m. UTC
Modify the tests that currently transmit packets in batches to also
receive packets in batches. This adds coverage of odp_queue_deq_multi()
and odp_schedule_multi() specifically against a packet input queue,
as this doesn't get tested anywhere else in the validation suite.

Signed-off-by: Stuart Haslam <stuart.haslam@linaro.org>
---
Changes in v2 - rebased and picked up new time API

 test/validation/pktio/pktio.c | 139 +++++++++++++++++++++---------------------
 1 file changed, 68 insertions(+), 71 deletions(-)

Comments

Stuart Haslam Dec. 17, 2015, 4:58 p.m. UTC | #1
On Fri, Dec 11, 2015 at 05:10:51PM +0000, Stuart Haslam wrote:
> Modify the tests that currently transmit packets in batches to also
> receive packets in batches. This adds coverage of odp_queue_deq_multi()
> and odp_schedule_multi() specifically against a packet input queue,
> as this doesn't get tested anywhere else in the validation suite.
> 
> Signed-off-by: Stuart Haslam <stuart.haslam@linaro.org>

ping - review needed

> ---
> Changes in v2 - rebased and picked up new time API
> 
>  test/validation/pktio/pktio.c | 139 +++++++++++++++++++++---------------------
>  1 file changed, 68 insertions(+), 71 deletions(-)
> 
> diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c
> index 52e5414..1eca694 100644
> --- a/test/validation/pktio/pktio.c
> +++ b/test/validation/pktio/pktio.c
> @@ -137,7 +137,7 @@ static uint32_t pktio_pkt_seq(odp_packet_t pkt)
>  	pkt_tail_t tail;
>  
>  	if (pkt == ODP_PACKET_INVALID)
> -		return -1;
> +		return TEST_SEQ_INVALID;
>  
>  	off = odp_packet_l4_offset(pkt);
>  	if (off ==  ODP_PACKET_OFFSET_INVALID)
> @@ -332,68 +332,76 @@ static int destroy_inq(odp_pktio_t pktio)
>  	return odp_queue_destroy(inq);
>  }
>  
> -static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns)
> +static int get_packets(pktio_info_t *pktio_rx, odp_packet_t pkt_tbl[], int num)
>  {
> -	odp_time_t start, now, diff;
> -	odp_event_t ev;
> +	odp_event_t evt_tbl[num];
> +	int num_evts = 0;
> +	int num_pkts = 0;
> +	int i;
>  
> -	start = odp_time_local();
> +	if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV)
> +		return odp_pktio_recv(pktio_rx->id, pkt_tbl, num);
>  
> -	do {
> -		ev = odp_queue_deq(queue);
> -		if (ev != ODP_EVENT_INVALID)
> -			return ev;
> -		now = odp_time_local();
> -		diff = odp_time_diff(now, start);
> -	} while (odp_time_to_ns(diff) < ns);
> +	if (num > 1) {
> +		if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
> +			num_evts = odp_queue_deq_multi(pktio_rx->inq, evt_tbl,
> +						       num);
> +		else
> +			num_evts = odp_schedule_multi(NULL, ODP_SCHED_NO_WAIT,
> +						      evt_tbl, num);
> +	} else {
> +		odp_event_t evt_tmp;
> +
> +		if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
> +			evt_tmp = odp_queue_deq(pktio_rx->inq);
> +		else
> +			evt_tmp = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
> +
> +		if (evt_tmp != ODP_EVENT_INVALID)
> +			evt_tbl[num_evts++] = evt_tmp;
> +	}
> +
> +	/* convert events to packets, discarding any non-packet events */
> +	for (i = 0; i < num_evts; ++i) {
> +		if (odp_event_type(evt_tbl[i]) == ODP_EVENT_PACKET)
> +			pkt_tbl[num_pkts++] = odp_packet_from_event(evt_tbl[i]);
> +		else
> +			odp_event_free(evt_tbl[i]);
> +	}
>  
> -	return ODP_EVENT_INVALID;
> +	return num_pkts;
>  }
>  
> -static odp_packet_t wait_for_packet(pktio_info_t *pktio_rx,
> -				    uint32_t seq, uint64_t ns)
> +static int wait_for_packets(pktio_info_t *pktio_rx, odp_packet_t pkt_tbl[],
> +			    uint32_t seq_tbl[], int num, uint64_t ns)
>  {
>  	odp_time_t start, now, diff;
> -	odp_event_t ev;
> -	odp_packet_t pkt;
> -	uint64_t wait;
> +	int num_rx = 0;
> +	int i;
> +	odp_packet_t pkt_tmp[num];
>  
>  	start = odp_time_local();
> -	wait = odp_schedule_wait_time(ns);
>  
>  	do {
> -		pkt = ODP_PACKET_INVALID;
> -
> -		if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV) {
> -			odp_pktio_recv(pktio_rx->id, &pkt, 1);
> -		} else {
> -			if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
> -				ev = queue_deq_wait_time(pktio_rx->inq, ns);
> -			else
> -				ev = odp_schedule(NULL, wait);
> -
> -			if (ev != ODP_EVENT_INVALID) {
> -				if (odp_event_type(ev) == ODP_EVENT_PACKET)
> -					pkt = odp_packet_from_event(ev);
> -				else
> -					odp_event_free(ev);
> -			}
> -		}
> +		int n = get_packets(pktio_rx, pkt_tmp, num);
>  
> -		if (pkt != ODP_PACKET_INVALID) {
> -			if (pktio_pkt_seq(pkt) == seq)
> -				return pkt;
> +		if (n < 0)
> +			break;
>  
> -			odp_packet_free(pkt);
> +		for (i = 0; i < n; ++i) {
> +			if (pktio_pkt_seq(pkt_tmp[i]) == seq_tbl[num_rx]) {
> +				pkt_tbl[num_rx++] = pkt_tmp[i];
> +				num--;
> +			} else {
> +				odp_packet_free(pkt_tmp[i]);
> +			}
>  		}
>  
>  		now = odp_time_local();
>  		diff = odp_time_diff(now, start);
> -	} while (odp_time_to_ns(diff) < ns);
> +	} while (num_rx < num && odp_time_to_ns(diff) < ns);
>  
> -	CU_FAIL("failed to receive transmitted packet");
> -
> -	return ODP_PACKET_INVALID;
> +	return num_rx;
>  }
>  
>  static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
> @@ -401,9 +409,9 @@ static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
>  {
>  	odp_packet_t tx_pkt[num_pkts];
>  	odp_event_t tx_ev[num_pkts];
> -	odp_packet_t rx_pkt;
> +	odp_packet_t rx_pkt[num_pkts];
>  	uint32_t tx_seq[num_pkts];
> -	int i, ret;
> +	int i, ret, num_rx;
>  
>  	/* generate test packets to send */
>  	for (i = 0; i < num_pkts; ++i) {
> @@ -447,18 +455,16 @@ static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
>  	}
>  
>  	/* and wait for them to arrive back */
> -	for (i = 0; i < num_pkts; ++i) {
> -		rx_pkt = wait_for_packet(pktio_b, tx_seq[i],
> -					 ODP_TIME_SEC_IN_NS);
> -
> -		if (rx_pkt == ODP_PACKET_INVALID)
> -			break;
> -		CU_ASSERT(odp_packet_input(rx_pkt) == pktio_b->id);
> -		CU_ASSERT(odp_packet_has_error(rx_pkt) == 0);
> -		odp_packet_free(rx_pkt);
> +	num_rx = wait_for_packets(pktio_b, rx_pkt, tx_seq,
> +				  num_pkts, ODP_TIME_SEC_IN_NS);
> +	CU_ASSERT(num_rx == num_pkts);
> +
> +	for (i = 0; i < num_rx; ++i) {
> +		CU_ASSERT_FATAL(rx_pkt[i] != ODP_PACKET_INVALID);
> +		CU_ASSERT(odp_packet_input(rx_pkt[i]) == pktio_b->id);
> +		CU_ASSERT(odp_packet_has_error(rx_pkt[i]) == 0);
> +		odp_packet_free(rx_pkt[i]);
>  	}
> -
> -	CU_ASSERT(i == num_pkts);
>  }
>  
>  static void test_txrx(odp_pktio_input_mode_t in_mode, int num_pkts)
> @@ -929,12 +935,8 @@ static void pktio_test_send_failure(void)
>  		info_rx.inq  = ODP_QUEUE_INVALID;
>  		info_rx.in_mode = ODP_PKTIN_MODE_RECV;
>  
> -		for (i = 0; i < ret; ++i) {
> -			pkt_tbl[i] = wait_for_packet(&info_rx, pkt_seq[i],
> -						     ODP_TIME_SEC_IN_NS);
> -			if (pkt_tbl[i] == ODP_PACKET_INVALID)
> -				break;
> -		}
> +		i = wait_for_packets(&info_rx, pkt_tbl, pkt_seq,
> +				     ret, ODP_TIME_SEC_IN_NS);
>  
>  		if (i == ret) {
>  			/* now try to send starting with the too-long packet
> @@ -960,14 +962,9 @@ static void pktio_test_send_failure(void)
>  		ret = odp_pktio_send(pktio_tx, &pkt_tbl[i], TX_BATCH_LEN - i);
>  		CU_ASSERT_FATAL(ret == (TX_BATCH_LEN - i));
>  
> -		for (; i < TX_BATCH_LEN; ++i) {
> -			pkt_tbl[i] = wait_for_packet(&info_rx,
> -						     pkt_seq[i],
> -						     ODP_TIME_SEC_IN_NS);
> -			if (pkt_tbl[i] == ODP_PACKET_INVALID)
> -				break;
> -		}
> -		CU_ASSERT(i == TX_BATCH_LEN);
> +		i = wait_for_packets(&info_rx, &pkt_tbl[i], &pkt_seq[i],
> +				     ret, ODP_TIME_SEC_IN_NS);
> +		CU_ASSERT(i == ret);
>  	} else {
>  		CU_FAIL("failed to generate test packets\n");
>  	}
> -- 
> 2.1.1
>
Maxim Uvarov Dec. 18, 2015, 10:43 a.m. UTC | #2
One comment bellow, other things look good.

Maxim.

On 12/11/2015 20:10, Stuart Haslam wrote:
> Modify the tests that currently transmit packets in batches to also
> receive packets in batches. This adds coverage of odp_queue_deq_multi()
> and odp_schedule_multi() specifically against a packet input queue,
> as this doesn't get tested anywhere else in the validation suite.
>
> Signed-off-by: Stuart Haslam <stuart.haslam@linaro.org>
> ---
> Changes in v2 - rebased and picked up new time API
>
>   test/validation/pktio/pktio.c | 139 +++++++++++++++++++++---------------------
>   1 file changed, 68 insertions(+), 71 deletions(-)
>
> diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c
> index 52e5414..1eca694 100644
> --- a/test/validation/pktio/pktio.c
> +++ b/test/validation/pktio/pktio.c
> @@ -137,7 +137,7 @@ static uint32_t pktio_pkt_seq(odp_packet_t pkt)
>   	pkt_tail_t tail;
>   
>   	if (pkt == ODP_PACKET_INVALID)
> -		return -1;
> +		return TEST_SEQ_INVALID;
>   
>   	off = odp_packet_l4_offset(pkt);
>   	if (off ==  ODP_PACKET_OFFSET_INVALID)
> @@ -332,68 +332,76 @@ static int destroy_inq(odp_pktio_t pktio)
>   	return odp_queue_destroy(inq);
>   }
>   
> -static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns)
> +static int get_packets(pktio_info_t *pktio_rx, odp_packet_t pkt_tbl[], int num)
>   {
> -	odp_time_t start, now, diff;
> -	odp_event_t ev;
> +	odp_event_t evt_tbl[num];
> +	int num_evts = 0;
> +	int num_pkts = 0;
> +	int i;
>   
> -	start = odp_time_local();
> +	if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV)
> +		return odp_pktio_recv(pktio_rx->id, pkt_tbl, num);
>   
> -	do {
> -		ev = odp_queue_deq(queue);
> -		if (ev != ODP_EVENT_INVALID)
> -			return ev;
> -		now = odp_time_local();
> -		diff = odp_time_diff(now, start);
> -	} while (odp_time_to_ns(diff) < ns);
> +	if (num > 1) {
that means that you never test odp_queue_deq_multi and 
odp_schedule_multi for num = 1.
But validation tests should do it' It's not performance tests so I think 
simple it can be separate test case.


> +		if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
> +			num_evts = odp_queue_deq_multi(pktio_rx->inq, evt_tbl,
> +						       num);
> +		else
> +			num_evts = odp_schedule_multi(NULL, ODP_SCHED_NO_WAIT,
> +						      evt_tbl, num);
> +	} else {
> +		odp_event_t evt_tmp;
> +
> +		if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
> +			evt_tmp = odp_queue_deq(pktio_rx->inq);
> +		else
> +			evt_tmp = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
> +
> +		if (evt_tmp != ODP_EVENT_INVALID)
> +			evt_tbl[num_evts++] = evt_tmp;
> +	}
> +
> +	/* convert events to packets, discarding any non-packet events */
> +	for (i = 0; i < num_evts; ++i) {
> +		if (odp_event_type(evt_tbl[i]) == ODP_EVENT_PACKET)
> +			pkt_tbl[num_pkts++] = odp_packet_from_event(evt_tbl[i]);
> +		else
> +			odp_event_free(evt_tbl[i]);
> +	}
>   
> -	return ODP_EVENT_INVALID;
> +	return num_pkts;
>   }
>   
> -static odp_packet_t wait_for_packet(pktio_info_t *pktio_rx,
> -				    uint32_t seq, uint64_t ns)
> +static int wait_for_packets(pktio_info_t *pktio_rx, odp_packet_t pkt_tbl[],
> +			    uint32_t seq_tbl[], int num, uint64_t ns)
>   {
>   	odp_time_t start, now, diff;
> -	odp_event_t ev;
> -	odp_packet_t pkt;
> -	uint64_t wait;
> +	int num_rx = 0;
> +	int i;
> +	odp_packet_t pkt_tmp[num];
>   
>   	start = odp_time_local();
> -	wait = odp_schedule_wait_time(ns);
>   
>   	do {
> -		pkt = ODP_PACKET_INVALID;
> -
> -		if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV) {
> -			odp_pktio_recv(pktio_rx->id, &pkt, 1);
> -		} else {
> -			if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
> -				ev = queue_deq_wait_time(pktio_rx->inq, ns);
> -			else
> -				ev = odp_schedule(NULL, wait);
> -
> -			if (ev != ODP_EVENT_INVALID) {
> -				if (odp_event_type(ev) == ODP_EVENT_PACKET)
> -					pkt = odp_packet_from_event(ev);
> -				else
> -					odp_event_free(ev);
> -			}
> -		}
> +		int n = get_packets(pktio_rx, pkt_tmp, num);
>   
> -		if (pkt != ODP_PACKET_INVALID) {
> -			if (pktio_pkt_seq(pkt) == seq)
> -				return pkt;
> +		if (n < 0)
> +			break;
>   
> -			odp_packet_free(pkt);
> +		for (i = 0; i < n; ++i) {
> +			if (pktio_pkt_seq(pkt_tmp[i]) == seq_tbl[num_rx]) {
> +				pkt_tbl[num_rx++] = pkt_tmp[i];
> +				num--;
> +			} else {
> +				odp_packet_free(pkt_tmp[i]);
> +			}
>   		}
>   
>   		now = odp_time_local();
>   		diff = odp_time_diff(now, start);
> -	} while (odp_time_to_ns(diff) < ns);
> +	} while (num_rx < num && odp_time_to_ns(diff) < ns);
>   
> -	CU_FAIL("failed to receive transmitted packet");
> -
> -	return ODP_PACKET_INVALID;
> +	return num_rx;
>   }
>   
>   static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
> @@ -401,9 +409,9 @@ static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
>   {
>   	odp_packet_t tx_pkt[num_pkts];
>   	odp_event_t tx_ev[num_pkts];
> -	odp_packet_t rx_pkt;
> +	odp_packet_t rx_pkt[num_pkts];
>   	uint32_t tx_seq[num_pkts];
> -	int i, ret;
> +	int i, ret, num_rx;
>   
>   	/* generate test packets to send */
>   	for (i = 0; i < num_pkts; ++i) {
> @@ -447,18 +455,16 @@ static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
>   	}
>   
>   	/* and wait for them to arrive back */
> -	for (i = 0; i < num_pkts; ++i) {
> -		rx_pkt = wait_for_packet(pktio_b, tx_seq[i],
> -					 ODP_TIME_SEC_IN_NS);
> -
> -		if (rx_pkt == ODP_PACKET_INVALID)
> -			break;
> -		CU_ASSERT(odp_packet_input(rx_pkt) == pktio_b->id);
> -		CU_ASSERT(odp_packet_has_error(rx_pkt) == 0);
> -		odp_packet_free(rx_pkt);
> +	num_rx = wait_for_packets(pktio_b, rx_pkt, tx_seq,
> +				  num_pkts, ODP_TIME_SEC_IN_NS);
> +	CU_ASSERT(num_rx == num_pkts);
> +
> +	for (i = 0; i < num_rx; ++i) {
> +		CU_ASSERT_FATAL(rx_pkt[i] != ODP_PACKET_INVALID);
> +		CU_ASSERT(odp_packet_input(rx_pkt[i]) == pktio_b->id);
> +		CU_ASSERT(odp_packet_has_error(rx_pkt[i]) == 0);
> +		odp_packet_free(rx_pkt[i]);
>   	}
> -
> -	CU_ASSERT(i == num_pkts);
>   }
>   
>   static void test_txrx(odp_pktio_input_mode_t in_mode, int num_pkts)
> @@ -929,12 +935,8 @@ static void pktio_test_send_failure(void)
>   		info_rx.inq  = ODP_QUEUE_INVALID;
>   		info_rx.in_mode = ODP_PKTIN_MODE_RECV;
>   
> -		for (i = 0; i < ret; ++i) {
> -			pkt_tbl[i] = wait_for_packet(&info_rx, pkt_seq[i],
> -						     ODP_TIME_SEC_IN_NS);
> -			if (pkt_tbl[i] == ODP_PACKET_INVALID)
> -				break;
> -		}
> +		i = wait_for_packets(&info_rx, pkt_tbl, pkt_seq,
> +				     ret, ODP_TIME_SEC_IN_NS);
>   
>   		if (i == ret) {
>   			/* now try to send starting with the too-long packet
> @@ -960,14 +962,9 @@ static void pktio_test_send_failure(void)
>   		ret = odp_pktio_send(pktio_tx, &pkt_tbl[i], TX_BATCH_LEN - i);
>   		CU_ASSERT_FATAL(ret == (TX_BATCH_LEN - i));
>   
> -		for (; i < TX_BATCH_LEN; ++i) {
> -			pkt_tbl[i] = wait_for_packet(&info_rx,
> -						     pkt_seq[i],
> -						     ODP_TIME_SEC_IN_NS);
> -			if (pkt_tbl[i] == ODP_PACKET_INVALID)
> -				break;
> -		}
> -		CU_ASSERT(i == TX_BATCH_LEN);
> +		i = wait_for_packets(&info_rx, &pkt_tbl[i], &pkt_seq[i],
> +				     ret, ODP_TIME_SEC_IN_NS);
> +		CU_ASSERT(i == ret);
>   	} else {
>   		CU_FAIL("failed to generate test packets\n");
>   	}
Stuart Haslam Dec. 18, 2015, noon UTC | #3
On Fri, Dec 18, 2015 at 01:43:18PM +0300, Maxim Uvarov wrote:
> One comment bellow, other things look good.
> 
> Maxim.
> 
> On 12/11/2015 20:10, Stuart Haslam wrote:
> >Modify the tests that currently transmit packets in batches to also
> >receive packets in batches. This adds coverage of odp_queue_deq_multi()
> >and odp_schedule_multi() specifically against a packet input queue,
> >as this doesn't get tested anywhere else in the validation suite.
> >
> >Signed-off-by: Stuart Haslam <stuart.haslam@linaro.org>
> >---
> >Changes in v2 - rebased and picked up new time API
> >
> >  test/validation/pktio/pktio.c | 139 +++++++++++++++++++++---------------------
> >  1 file changed, 68 insertions(+), 71 deletions(-)
> >
> >diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c
> >index 52e5414..1eca694 100644
> >--- a/test/validation/pktio/pktio.c
> >+++ b/test/validation/pktio/pktio.c
> >@@ -137,7 +137,7 @@ static uint32_t pktio_pkt_seq(odp_packet_t pkt)
> >  	pkt_tail_t tail;
> >  	if (pkt == ODP_PACKET_INVALID)
> >-		return -1;
> >+		return TEST_SEQ_INVALID;
> >  	off = odp_packet_l4_offset(pkt);
> >  	if (off ==  ODP_PACKET_OFFSET_INVALID)
> >@@ -332,68 +332,76 @@ static int destroy_inq(odp_pktio_t pktio)
> >  	return odp_queue_destroy(inq);
> >  }
> >-static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns)
> >+static int get_packets(pktio_info_t *pktio_rx, odp_packet_t pkt_tbl[], int num)
> >  {
> >-	odp_time_t start, now, diff;
> >-	odp_event_t ev;
> >+	odp_event_t evt_tbl[num];
> >+	int num_evts = 0;
> >+	int num_pkts = 0;
> >+	int i;
> >-	start = odp_time_local();
> >+	if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV)
> >+		return odp_pktio_recv(pktio_rx->id, pkt_tbl, num);
> >-	do {
> >-		ev = odp_queue_deq(queue);
> >-		if (ev != ODP_EVENT_INVALID)
> >-			return ev;
> >-		now = odp_time_local();
> >-		diff = odp_time_diff(now, start);
> >-	} while (odp_time_to_ns(diff) < ns);
> >+	if (num > 1) {
> that means that you never test odp_queue_deq_multi and
> odp_schedule_multi for num = 1.
> But validation tests should do it' It's not performance tests so I
> think simple it can be separate test case.
> 

OK, although there are plenty of other batch lengths that we don't test,
it's easy enough to add a special case for 1.
diff mbox

Patch

diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c
index 52e5414..1eca694 100644
--- a/test/validation/pktio/pktio.c
+++ b/test/validation/pktio/pktio.c
@@ -137,7 +137,7 @@  static uint32_t pktio_pkt_seq(odp_packet_t pkt)
 	pkt_tail_t tail;
 
 	if (pkt == ODP_PACKET_INVALID)
-		return -1;
+		return TEST_SEQ_INVALID;
 
 	off = odp_packet_l4_offset(pkt);
 	if (off ==  ODP_PACKET_OFFSET_INVALID)
@@ -332,68 +332,76 @@  static int destroy_inq(odp_pktio_t pktio)
 	return odp_queue_destroy(inq);
 }
 
-static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns)
+static int get_packets(pktio_info_t *pktio_rx, odp_packet_t pkt_tbl[], int num)
 {
-	odp_time_t start, now, diff;
-	odp_event_t ev;
+	odp_event_t evt_tbl[num];
+	int num_evts = 0;
+	int num_pkts = 0;
+	int i;
 
-	start = odp_time_local();
+	if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV)
+		return odp_pktio_recv(pktio_rx->id, pkt_tbl, num);
 
-	do {
-		ev = odp_queue_deq(queue);
-		if (ev != ODP_EVENT_INVALID)
-			return ev;
-		now = odp_time_local();
-		diff = odp_time_diff(now, start);
-	} while (odp_time_to_ns(diff) < ns);
+	if (num > 1) {
+		if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
+			num_evts = odp_queue_deq_multi(pktio_rx->inq, evt_tbl,
+						       num);
+		else
+			num_evts = odp_schedule_multi(NULL, ODP_SCHED_NO_WAIT,
+						      evt_tbl, num);
+	} else {
+		odp_event_t evt_tmp;
+
+		if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
+			evt_tmp = odp_queue_deq(pktio_rx->inq);
+		else
+			evt_tmp = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
+
+		if (evt_tmp != ODP_EVENT_INVALID)
+			evt_tbl[num_evts++] = evt_tmp;
+	}
+
+	/* convert events to packets, discarding any non-packet events */
+	for (i = 0; i < num_evts; ++i) {
+		if (odp_event_type(evt_tbl[i]) == ODP_EVENT_PACKET)
+			pkt_tbl[num_pkts++] = odp_packet_from_event(evt_tbl[i]);
+		else
+			odp_event_free(evt_tbl[i]);
+	}
 
-	return ODP_EVENT_INVALID;
+	return num_pkts;
 }
 
-static odp_packet_t wait_for_packet(pktio_info_t *pktio_rx,
-				    uint32_t seq, uint64_t ns)
+static int wait_for_packets(pktio_info_t *pktio_rx, odp_packet_t pkt_tbl[],
+			    uint32_t seq_tbl[], int num, uint64_t ns)
 {
 	odp_time_t start, now, diff;
-	odp_event_t ev;
-	odp_packet_t pkt;
-	uint64_t wait;
+	int num_rx = 0;
+	int i;
+	odp_packet_t pkt_tmp[num];
 
 	start = odp_time_local();
-	wait = odp_schedule_wait_time(ns);
 
 	do {
-		pkt = ODP_PACKET_INVALID;
-
-		if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV) {
-			odp_pktio_recv(pktio_rx->id, &pkt, 1);
-		} else {
-			if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
-				ev = queue_deq_wait_time(pktio_rx->inq, ns);
-			else
-				ev = odp_schedule(NULL, wait);
-
-			if (ev != ODP_EVENT_INVALID) {
-				if (odp_event_type(ev) == ODP_EVENT_PACKET)
-					pkt = odp_packet_from_event(ev);
-				else
-					odp_event_free(ev);
-			}
-		}
+		int n = get_packets(pktio_rx, pkt_tmp, num);
 
-		if (pkt != ODP_PACKET_INVALID) {
-			if (pktio_pkt_seq(pkt) == seq)
-				return pkt;
+		if (n < 0)
+			break;
 
-			odp_packet_free(pkt);
+		for (i = 0; i < n; ++i) {
+			if (pktio_pkt_seq(pkt_tmp[i]) == seq_tbl[num_rx]) {
+				pkt_tbl[num_rx++] = pkt_tmp[i];
+				num--;
+			} else {
+				odp_packet_free(pkt_tmp[i]);
+			}
 		}
 
 		now = odp_time_local();
 		diff = odp_time_diff(now, start);
-	} while (odp_time_to_ns(diff) < ns);
+	} while (num_rx < num && odp_time_to_ns(diff) < ns);
 
-	CU_FAIL("failed to receive transmitted packet");
-
-	return ODP_PACKET_INVALID;
+	return num_rx;
 }
 
 static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
@@ -401,9 +409,9 @@  static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
 {
 	odp_packet_t tx_pkt[num_pkts];
 	odp_event_t tx_ev[num_pkts];
-	odp_packet_t rx_pkt;
+	odp_packet_t rx_pkt[num_pkts];
 	uint32_t tx_seq[num_pkts];
-	int i, ret;
+	int i, ret, num_rx;
 
 	/* generate test packets to send */
 	for (i = 0; i < num_pkts; ++i) {
@@ -447,18 +455,16 @@  static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
 	}
 
 	/* and wait for them to arrive back */
-	for (i = 0; i < num_pkts; ++i) {
-		rx_pkt = wait_for_packet(pktio_b, tx_seq[i],
-					 ODP_TIME_SEC_IN_NS);
-
-		if (rx_pkt == ODP_PACKET_INVALID)
-			break;
-		CU_ASSERT(odp_packet_input(rx_pkt) == pktio_b->id);
-		CU_ASSERT(odp_packet_has_error(rx_pkt) == 0);
-		odp_packet_free(rx_pkt);
+	num_rx = wait_for_packets(pktio_b, rx_pkt, tx_seq,
+				  num_pkts, ODP_TIME_SEC_IN_NS);
+	CU_ASSERT(num_rx == num_pkts);
+
+	for (i = 0; i < num_rx; ++i) {
+		CU_ASSERT_FATAL(rx_pkt[i] != ODP_PACKET_INVALID);
+		CU_ASSERT(odp_packet_input(rx_pkt[i]) == pktio_b->id);
+		CU_ASSERT(odp_packet_has_error(rx_pkt[i]) == 0);
+		odp_packet_free(rx_pkt[i]);
 	}
-
-	CU_ASSERT(i == num_pkts);
 }
 
 static void test_txrx(odp_pktio_input_mode_t in_mode, int num_pkts)
@@ -929,12 +935,8 @@  static void pktio_test_send_failure(void)
 		info_rx.inq  = ODP_QUEUE_INVALID;
 		info_rx.in_mode = ODP_PKTIN_MODE_RECV;
 
-		for (i = 0; i < ret; ++i) {
-			pkt_tbl[i] = wait_for_packet(&info_rx, pkt_seq[i],
-						     ODP_TIME_SEC_IN_NS);
-			if (pkt_tbl[i] == ODP_PACKET_INVALID)
-				break;
-		}
+		i = wait_for_packets(&info_rx, pkt_tbl, pkt_seq,
+				     ret, ODP_TIME_SEC_IN_NS);
 
 		if (i == ret) {
 			/* now try to send starting with the too-long packet
@@ -960,14 +962,9 @@  static void pktio_test_send_failure(void)
 		ret = odp_pktio_send(pktio_tx, &pkt_tbl[i], TX_BATCH_LEN - i);
 		CU_ASSERT_FATAL(ret == (TX_BATCH_LEN - i));
 
-		for (; i < TX_BATCH_LEN; ++i) {
-			pkt_tbl[i] = wait_for_packet(&info_rx,
-						     pkt_seq[i],
-						     ODP_TIME_SEC_IN_NS);
-			if (pkt_tbl[i] == ODP_PACKET_INVALID)
-				break;
-		}
-		CU_ASSERT(i == TX_BATCH_LEN);
+		i = wait_for_packets(&info_rx, &pkt_tbl[i], &pkt_seq[i],
+				     ret, ODP_TIME_SEC_IN_NS);
+		CU_ASSERT(i == ret);
 	} else {
 		CU_FAIL("failed to generate test packets\n");
 	}