[dpdk-dev,v1,5/5] L3fwd-power: enable one-shot rx interrupt and polling/interrupt mode switch

Message ID 1422438631-7853-6-git-send-email-danny.zhou@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Zhou, Danny Jan. 28, 2015, 9:50 a.m. UTC
  Signed-off-by: Danny Zhou <danny.zhou@intel.com>
---
 examples/l3fwd-power/main.c | 170 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 129 insertions(+), 41 deletions(-)
  

Comments

Cunming Liang Jan. 28, 2015, 6:34 p.m. UTC | #1
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Danny Zhou
> Sent: Wednesday, January 28, 2015 2:51 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v1 5/5] L3fwd-power: enable one-shot rx interrupt
> and polling/interrupt mode switch
> 
> Signed-off-by: Danny Zhou <danny.zhou@intel.com>
> ---
>  examples/l3fwd-power/main.c | 170
> +++++++++++++++++++++++++++++++++-----------
>  1 file changed, 129 insertions(+), 41 deletions(-)
> 
> diff --git a/examples/l3fwd-power/main.c b/examples/l3fwd-power/main.c
> index f6b55b9..e6e4f55 100644
> --- a/examples/l3fwd-power/main.c
> +++ b/examples/l3fwd-power/main.c
> @@ -75,12 +75,13 @@
>  #include <rte_string_fns.h>
>  #include <rte_timer.h>
>  #include <rte_power.h>
> +#include <rte_eal.h>
> 
>  #define RTE_LOGTYPE_L3FWD_POWER RTE_LOGTYPE_USER1
> 
>  #define MAX_PKT_BURST 32
> 
> -#define MIN_ZERO_POLL_COUNT 5
> +#define MIN_ZERO_POLL_COUNT 10
> 
>  /* around 100ms at 2 Ghz */
>  #define TIMER_RESOLUTION_CYCLES           200000000ULL
> @@ -188,6 +189,9 @@ struct lcore_rx_queue {
>  #define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS
>  #define MAX_RX_QUEUE_PER_PORT 128
> 
> +#define MAX_RX_QUEUE_INTERRUPT_PER_PORT 16
> +
> +
>  #define MAX_LCORE_PARAMS 1024
>  struct lcore_params {
>  	uint8_t port_id;
> @@ -214,7 +218,7 @@ static uint16_t nb_lcore_params =
> sizeof(lcore_params_array_default) /
> 
>  static struct rte_eth_conf port_conf = {
>  	.rxmode = {
> -		.mq_mode	= ETH_MQ_RX_RSS,
> +		.mq_mode = ETH_MQ_RX_RSS,
>  		.max_rx_pkt_len = ETHER_MAX_LEN,
>  		.split_hdr_size = 0,
>  		.header_split   = 0, /**< Header Split disabled */
> @@ -226,11 +230,14 @@ static struct rte_eth_conf port_conf = {
>  	.rx_adv_conf = {
>  		.rss_conf = {
>  			.rss_key = NULL,
> -			.rss_hf = ETH_RSS_IP,
> +			.rss_hf = ETH_RSS_UDP,
>  		},
>  	},
>  	.txmode = {
> -		.mq_mode = ETH_DCB_NONE,
> +		.mq_mode = ETH_MQ_TX_NONE,
> +	},
> +	.intr_conf = {
> +		.rxq = 1, /**< rxq interrupt feature enabled */
>  	},
>  };
> 
> @@ -402,19 +409,22 @@ power_timer_cb(__attribute__((unused)) struct
> rte_timer *tim,
>  	/* accumulate total execution time in us when callback is invoked */
>  	sleep_time_ratio = (float)(stats[lcore_id].sleep_time) /
>  					(float)SCALING_PERIOD;
> -
>  	/**
>  	 * check whether need to scale down frequency a step if it sleep a lot.
>  	 */
> -	if (sleep_time_ratio >= SCALING_DOWN_TIME_RATIO_THRESHOLD)
> -		rte_power_freq_down(lcore_id);
> +	if (sleep_time_ratio >= SCALING_DOWN_TIME_RATIO_THRESHOLD) {
> +		if (rte_power_freq_down)
> +			rte_power_freq_down(lcore_id);
> +	}
>  	else if ( (unsigned)(stats[lcore_id].nb_rx_processed /
> -		stats[lcore_id].nb_iteration_looped) < MAX_PKT_BURST)
> +		stats[lcore_id].nb_iteration_looped) < MAX_PKT_BURST) {
>  		/**
>  		 * scale down a step if average packet per iteration less
>  		 * than expectation.
>  		 */
> -		rte_power_freq_down(lcore_id);
> +		if (rte_power_freq_down)
> +			rte_power_freq_down(lcore_id);
> +	}
> 
>  	/**
>  	 * initialize another timer according to current frequency to ensure
> @@ -707,22 +717,20 @@ l3fwd_simple_forward(struct rte_mbuf *m, uint8_t
> portid,
> 
>  }
> 
> -#define SLEEP_GEAR1_THRESHOLD            100
> -#define SLEEP_GEAR2_THRESHOLD            1000
> +#define MINIMUM_SLEEP_TIME         1
> +#define SUSPEND_THRESHOLD          300
> 
>  static inline uint32_t
>  power_idle_heuristic(uint32_t zero_rx_packet_count)
>  {
> -	/* If zero count is less than 100, use it as the sleep time in us */
> -	if (zero_rx_packet_count < SLEEP_GEAR1_THRESHOLD)
> -		return zero_rx_packet_count;
> -	/* If zero count is less than 1000, sleep time should be 100 us */
> -	else if ((zero_rx_packet_count >= SLEEP_GEAR1_THRESHOLD) &&
> -			(zero_rx_packet_count < SLEEP_GEAR2_THRESHOLD))
> -		return SLEEP_GEAR1_THRESHOLD;
> -	/* If zero count is greater than 1000, sleep time should be 1000 us */
> -	else if (zero_rx_packet_count >= SLEEP_GEAR2_THRESHOLD)
> -		return SLEEP_GEAR2_THRESHOLD;
> +	/* If zero count is less than 100,  sleep 1us */
> +	if (zero_rx_packet_count < SUSPEND_THRESHOLD)
> +		return MINIMUM_SLEEP_TIME;
> +	/* If zero count is less than 1000, sleep 100 us which is the minimum
> latency
> +	    switching from C3/C6 to C0
> +	*/
> +	else
> +		return SUSPEND_THRESHOLD;
> 
>  	return 0;
>  }
> @@ -762,6 +770,35 @@ power_freq_scaleup_heuristic(unsigned lcore_id,
>  	return FREQ_CURRENT;
>  }
> 
> +/**
> + * force polling thread sleep until one-shot rx interrupt triggers
> + * @param port_id
> + *  Port id.
> + * @param queue_id
> + *  Rx queue id.
> + * @return
> + *  0 on success
> + */
> +static int
> +sleep_until_rx_interrupt(uint8_t port_id, uint8_t queue_id)
> +{
> +	/* Enable one-shot rx interrupt */
> +	rte_eth_dev_rx_queue_intr_enable(port_id, queue_id);
> +
> +	RTE_LOG(INFO, L3FWD_POWER,
> +		"lcore %u sleeps until interrupt on port%d,rxq%d triggers\n",
> +		rte_lcore_id(), port_id, queue_id);
> +	rte_eal_wait_rx_intr(port_id, queue_id);
> +	RTE_LOG(INFO, L3FWD_POWER,
> +		"lcore %u is waked up from rx interrupt on port%d,rxq%d\n",
> +		rte_lcore_id(), port_id, queue_id);
> +
> +	/* Disable one-shot rx interrupt */
> +	rte_eth_dev_rx_queue_intr_disable(port_id, queue_id);
> +
> +	return 0;
> +}
> +
>  /* main processing loop */
>  static int
>  main_loop(__attribute__((unused)) void *dummy)
> @@ -775,7 +812,6 @@ main_loop(__attribute__((unused)) void *dummy)
>  	struct lcore_conf *qconf;
>  	struct lcore_rx_queue *rx_queue;
>  	enum freq_scale_hint_t lcore_scaleup_hint;
> -
>  	uint32_t lcore_rx_idle_count = 0;
>  	uint32_t lcore_idle_hint = 0;
> 
> @@ -835,6 +871,8 @@ main_loop(__attribute__((unused)) void *dummy)
>  			prev_tsc_power = cur_tsc_power;
>  		}
> 
> +
> +start_rx:
>  		/*
>  		 * Read packet from RX queues
>  		 */
> @@ -848,6 +886,7 @@ main_loop(__attribute__((unused)) void *dummy)
> 
>  			nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
>  								MAX_PKT_BURST);
> +
>  			stats[lcore_id].nb_rx_processed += nb_rx;
>  			if (unlikely(nb_rx == 0)) {
>  				/**
> @@ -910,10 +949,13 @@ main_loop(__attribute__((unused)) void *dummy)
>  						rx_queue->freq_up_hint;
>  			}
> 
> -			if (lcore_scaleup_hint == FREQ_HIGHEST)
> -				rte_power_freq_max(lcore_id);
> -			else if (lcore_scaleup_hint == FREQ_HIGHER)
> -				rte_power_freq_up(lcore_id);
> +			if (lcore_scaleup_hint == FREQ_HIGHEST) {
> +				if (rte_power_freq_max)
> +					rte_power_freq_max(lcore_id);
> +			} else if (lcore_scaleup_hint == FREQ_HIGHER) {
> +				if (rte_power_freq_up)
> +					rte_power_freq_up(lcore_id);
> +			}
>  		} else {
>  			/**
>  			 * All Rx queues empty in recent consecutive polls,
> @@ -928,21 +970,55 @@ main_loop(__attribute__((unused)) void *dummy)
>  					lcore_idle_hint = rx_queue->idle_hint;
>  			}
> 
> -			if ( lcore_idle_hint < SLEEP_GEAR1_THRESHOLD)
> +			if (lcore_idle_hint < SUSPEND_THRESHOLD)
>  				/**
> -				 * execute "pause" instruction to avoid context
> -				 * switch for short sleep.
> - 				 */
> +				* execute "pause" instruction to avoid context
> +				* switch which generally take hundres of microsecond
> +				* for short sleep.
> +				*/
>  				rte_delay_us(lcore_idle_hint);
> -			else
> -				/* long sleep force runing thread to suspend */
> -				usleep(lcore_idle_hint);
> -
> +			else {
> +				/* suspend untill rx interrupt trigges */
> +				sleep_until_rx_interrupt(
> +					qconf->rx_queue_list[0].port_id,
> +					qconf->rx_queue_list[0].queue_id);
> +				/* start receiving packets immediately */
> +				goto start_rx;
> +			}
>  			stats[lcore_id].sleep_time += lcore_idle_hint;
>  		}
>  	}
>  }
> 
> +/**
> + * It will be called as the callback for specified port after a LSI interrupt
> + * has been fully handled. This callback needs to be implemented carefully as
> + * it will be called in the interrupt host thread which is different from the
> + * application main thread.
> + *
> + * @param port_id
> + *  Port id.
> + * @param type
> + *  event type.
> + * @param param
> + *  Pointer to(address of) the parameters.
> + *
> + * @return
> + *  void.
> + */
> +
> +/*
> +static void
> +rx_interrupt_event_callback(uint8_t port_id, enum rte_eth_event_type type,
> void *param)
> +{
> +	uint64_t rx_queues = *((uint64_t *)param);
> +
> +	port_id = port_id + 1;
> +	if(type == RTE_ETH_EVENT_INTR_RX)
> +		port_id = rx_queues;
[LCM] What's bunch of things for ?

> +}
> +*/
> +
>  static int
>  check_lcore_params(void)
>  {
> @@ -1270,7 +1346,7 @@ setup_hash(int socketid)
>  	char s[64];
> 
>  	/* create ipv4 hash */
> -	snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
> +	rte_snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
>  	ipv4_l3fwd_hash_params.name = s;
>  	ipv4_l3fwd_hash_params.socket_id = socketid;
>  	ipv4_l3fwd_lookup_struct[socketid] =
> @@ -1280,7 +1356,7 @@ setup_hash(int socketid)
>  				"socket %d\n", socketid);
> 
>  	/* create ipv6 hash */
> -	snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
> +	rte_snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
>  	ipv6_l3fwd_hash_params.name = s;
>  	ipv6_l3fwd_hash_params.socket_id = socketid;
>  	ipv6_l3fwd_lookup_struct[socketid] =
> @@ -1476,6 +1552,7 @@ main(int argc, char **argv)
>  	unsigned lcore_id;
>  	uint64_t hz;
>  	uint32_t n_tx_queue, nb_lcores;
> +	uint32_t dev_rxq_num, dev_txq_num;
>  	uint8_t portid, nb_rx_queue, queue, socketid;
> 
>  	/* catch SIGINT and restore cpufreq governor to ondemand */
> @@ -1525,10 +1602,18 @@ main(int argc, char **argv)
>  		printf("Initializing port %d ... ", portid );
>  		fflush(stdout);
> 
> +		rte_eth_dev_info_get(portid, &dev_info);
> +		dev_rxq_num = dev_info.max_rx_queues;
> +		dev_txq_num = dev_info.max_tx_queues;
> +
>  		nb_rx_queue = get_port_n_rx_queues(portid);
> +		if (nb_rx_queue > dev_rxq_num)
> +			rte_exit(EXIT_FAILURE, "Cannot configure not existed rxq: "
> +					"port=%d\n", portid);
> +
>  		n_tx_queue = nb_lcores;
> -		if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
> -			n_tx_queue = MAX_TX_QUEUE_PER_PORT;
> +		if (n_tx_queue > dev_txq_num)
> +			n_tx_queue = dev_txq_num;
>  		printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
>  			nb_rx_queue, (unsigned)n_tx_queue );
>  		ret = rte_eth_dev_configure(portid, nb_rx_queue,
> @@ -1552,6 +1637,9 @@ main(int argc, char **argv)
>  			if (rte_lcore_is_enabled(lcore_id) == 0)
>  				continue;
> 
> +			if (queueid >= dev_txq_num)
> +				continue;
> +
>  			if (numa_on)
>  				socketid = \
>  				(uint8_t)rte_lcore_to_socket_id(lcore_id);
> @@ -1586,8 +1674,9 @@ main(int argc, char **argv)
>  		/* init power management library */
>  		ret = rte_power_init(lcore_id);
>  		if (ret)
> -			rte_exit(EXIT_FAILURE, "Power management library "
> -				"initialization failed on core%u\n", lcore_id);
> +			rte_log(RTE_LOG_ERR, RTE_LOGTYPE_POWER,
> +				"Power management library initialization "
> +				"failed on core%u", lcore_id);
> 
>  		/* init timer structures for each enabled lcore */
>  		rte_timer_init(&power_timers[lcore_id]);
> @@ -1635,7 +1724,6 @@ main(int argc, char **argv)
>  		if (ret < 0)
>  			rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, "
>  						"port=%d\n", ret, portid);
> -
>  		/*
>  		 * If enabled, put device in promiscuous mode.
>  		 * This allows IO forwarding mode to forward packets
> --
> 1.8.1.4
  
Zhou, Danny Jan. 29, 2015, 4:07 a.m. UTC | #2
> -----Original Message-----
> From: Liang, Cunming
> Sent: Thursday, January 29, 2015 2:34 AM
> To: Zhou, Danny; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v1 5/5] L3fwd-power: enable one-shot rx interrupt and polling/interrupt mode switch
> 
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Danny Zhou
> > Sent: Wednesday, January 28, 2015 2:51 AM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH v1 5/5] L3fwd-power: enable one-shot rx interrupt
> > and polling/interrupt mode switch
> >
> > Signed-off-by: Danny Zhou <danny.zhou@intel.com>
> > ---
> >  examples/l3fwd-power/main.c | 170
> > +++++++++++++++++++++++++++++++++-----------
> >  1 file changed, 129 insertions(+), 41 deletions(-)
> >
> > diff --git a/examples/l3fwd-power/main.c b/examples/l3fwd-power/main.c
> > index f6b55b9..e6e4f55 100644
> > --- a/examples/l3fwd-power/main.c
> > +++ b/examples/l3fwd-power/main.c
> > @@ -75,12 +75,13 @@
> >  #include <rte_string_fns.h>
> >  #include <rte_timer.h>
> >  #include <rte_power.h>
> > +#include <rte_eal.h>
> >
> >  #define RTE_LOGTYPE_L3FWD_POWER RTE_LOGTYPE_USER1
> >
> >  #define MAX_PKT_BURST 32
> >
> > -#define MIN_ZERO_POLL_COUNT 5
> > +#define MIN_ZERO_POLL_COUNT 10
> >
> >  /* around 100ms at 2 Ghz */
> >  #define TIMER_RESOLUTION_CYCLES           200000000ULL
> > @@ -188,6 +189,9 @@ struct lcore_rx_queue {
> >  #define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS
> >  #define MAX_RX_QUEUE_PER_PORT 128
> >
> > +#define MAX_RX_QUEUE_INTERRUPT_PER_PORT 16
> > +
> > +
> >  #define MAX_LCORE_PARAMS 1024
> >  struct lcore_params {
> >  	uint8_t port_id;
> > @@ -214,7 +218,7 @@ static uint16_t nb_lcore_params =
> > sizeof(lcore_params_array_default) /
> >
> >  static struct rte_eth_conf port_conf = {
> >  	.rxmode = {
> > -		.mq_mode	= ETH_MQ_RX_RSS,
> > +		.mq_mode = ETH_MQ_RX_RSS,
> >  		.max_rx_pkt_len = ETHER_MAX_LEN,
> >  		.split_hdr_size = 0,
> >  		.header_split   = 0, /**< Header Split disabled */
> > @@ -226,11 +230,14 @@ static struct rte_eth_conf port_conf = {
> >  	.rx_adv_conf = {
> >  		.rss_conf = {
> >  			.rss_key = NULL,
> > -			.rss_hf = ETH_RSS_IP,
> > +			.rss_hf = ETH_RSS_UDP,
> >  		},
> >  	},
> >  	.txmode = {
> > -		.mq_mode = ETH_DCB_NONE,
> > +		.mq_mode = ETH_MQ_TX_NONE,
> > +	},
> > +	.intr_conf = {
> > +		.rxq = 1, /**< rxq interrupt feature enabled */
> >  	},
> >  };
> >
> > @@ -402,19 +409,22 @@ power_timer_cb(__attribute__((unused)) struct
> > rte_timer *tim,
> >  	/* accumulate total execution time in us when callback is invoked */
> >  	sleep_time_ratio = (float)(stats[lcore_id].sleep_time) /
> >  					(float)SCALING_PERIOD;
> > -
> >  	/**
> >  	 * check whether need to scale down frequency a step if it sleep a lot.
> >  	 */
> > -	if (sleep_time_ratio >= SCALING_DOWN_TIME_RATIO_THRESHOLD)
> > -		rte_power_freq_down(lcore_id);
> > +	if (sleep_time_ratio >= SCALING_DOWN_TIME_RATIO_THRESHOLD) {
> > +		if (rte_power_freq_down)
> > +			rte_power_freq_down(lcore_id);
> > +	}
> >  	else if ( (unsigned)(stats[lcore_id].nb_rx_processed /
> > -		stats[lcore_id].nb_iteration_looped) < MAX_PKT_BURST)
> > +		stats[lcore_id].nb_iteration_looped) < MAX_PKT_BURST) {
> >  		/**
> >  		 * scale down a step if average packet per iteration less
> >  		 * than expectation.
> >  		 */
> > -		rte_power_freq_down(lcore_id);
> > +		if (rte_power_freq_down)
> > +			rte_power_freq_down(lcore_id);
> > +	}
> >
> >  	/**
> >  	 * initialize another timer according to current frequency to ensure
> > @@ -707,22 +717,20 @@ l3fwd_simple_forward(struct rte_mbuf *m, uint8_t
> > portid,
> >
> >  }
> >
> > -#define SLEEP_GEAR1_THRESHOLD            100
> > -#define SLEEP_GEAR2_THRESHOLD            1000
> > +#define MINIMUM_SLEEP_TIME         1
> > +#define SUSPEND_THRESHOLD          300
> >
> >  static inline uint32_t
> >  power_idle_heuristic(uint32_t zero_rx_packet_count)
> >  {
> > -	/* If zero count is less than 100, use it as the sleep time in us */
> > -	if (zero_rx_packet_count < SLEEP_GEAR1_THRESHOLD)
> > -		return zero_rx_packet_count;
> > -	/* If zero count is less than 1000, sleep time should be 100 us */
> > -	else if ((zero_rx_packet_count >= SLEEP_GEAR1_THRESHOLD) &&
> > -			(zero_rx_packet_count < SLEEP_GEAR2_THRESHOLD))
> > -		return SLEEP_GEAR1_THRESHOLD;
> > -	/* If zero count is greater than 1000, sleep time should be 1000 us */
> > -	else if (zero_rx_packet_count >= SLEEP_GEAR2_THRESHOLD)
> > -		return SLEEP_GEAR2_THRESHOLD;
> > +	/* If zero count is less than 100,  sleep 1us */
> > +	if (zero_rx_packet_count < SUSPEND_THRESHOLD)
> > +		return MINIMUM_SLEEP_TIME;
> > +	/* If zero count is less than 1000, sleep 100 us which is the minimum
> > latency
> > +	    switching from C3/C6 to C0
> > +	*/
> > +	else
> > +		return SUSPEND_THRESHOLD;
> >
> >  	return 0;
> >  }
> > @@ -762,6 +770,35 @@ power_freq_scaleup_heuristic(unsigned lcore_id,
> >  	return FREQ_CURRENT;
> >  }
> >
> > +/**
> > + * force polling thread sleep until one-shot rx interrupt triggers
> > + * @param port_id
> > + *  Port id.
> > + * @param queue_id
> > + *  Rx queue id.
> > + * @return
> > + *  0 on success
> > + */
> > +static int
> > +sleep_until_rx_interrupt(uint8_t port_id, uint8_t queue_id)
> > +{
> > +	/* Enable one-shot rx interrupt */
> > +	rte_eth_dev_rx_queue_intr_enable(port_id, queue_id);
> > +
> > +	RTE_LOG(INFO, L3FWD_POWER,
> > +		"lcore %u sleeps until interrupt on port%d,rxq%d triggers\n",
> > +		rte_lcore_id(), port_id, queue_id);
> > +	rte_eal_wait_rx_intr(port_id, queue_id);
> > +	RTE_LOG(INFO, L3FWD_POWER,
> > +		"lcore %u is waked up from rx interrupt on port%d,rxq%d\n",
> > +		rte_lcore_id(), port_id, queue_id);
> > +
> > +	/* Disable one-shot rx interrupt */
> > +	rte_eth_dev_rx_queue_intr_disable(port_id, queue_id);
> > +
> > +	return 0;
> > +}
> > +
> >  /* main processing loop */
> >  static int
> >  main_loop(__attribute__((unused)) void *dummy)
> > @@ -775,7 +812,6 @@ main_loop(__attribute__((unused)) void *dummy)
> >  	struct lcore_conf *qconf;
> >  	struct lcore_rx_queue *rx_queue;
> >  	enum freq_scale_hint_t lcore_scaleup_hint;
> > -
> >  	uint32_t lcore_rx_idle_count = 0;
> >  	uint32_t lcore_idle_hint = 0;
> >
> > @@ -835,6 +871,8 @@ main_loop(__attribute__((unused)) void *dummy)
> >  			prev_tsc_power = cur_tsc_power;
> >  		}
> >
> > +
> > +start_rx:
> >  		/*
> >  		 * Read packet from RX queues
> >  		 */
> > @@ -848,6 +886,7 @@ main_loop(__attribute__((unused)) void *dummy)
> >
> >  			nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
> >  								MAX_PKT_BURST);
> > +
> >  			stats[lcore_id].nb_rx_processed += nb_rx;
> >  			if (unlikely(nb_rx == 0)) {
> >  				/**
> > @@ -910,10 +949,13 @@ main_loop(__attribute__((unused)) void *dummy)
> >  						rx_queue->freq_up_hint;
> >  			}
> >
> > -			if (lcore_scaleup_hint == FREQ_HIGHEST)
> > -				rte_power_freq_max(lcore_id);
> > -			else if (lcore_scaleup_hint == FREQ_HIGHER)
> > -				rte_power_freq_up(lcore_id);
> > +			if (lcore_scaleup_hint == FREQ_HIGHEST) {
> > +				if (rte_power_freq_max)
> > +					rte_power_freq_max(lcore_id);
> > +			} else if (lcore_scaleup_hint == FREQ_HIGHER) {
> > +				if (rte_power_freq_up)
> > +					rte_power_freq_up(lcore_id);
> > +			}
> >  		} else {
> >  			/**
> >  			 * All Rx queues empty in recent consecutive polls,
> > @@ -928,21 +970,55 @@ main_loop(__attribute__((unused)) void *dummy)
> >  					lcore_idle_hint = rx_queue->idle_hint;
> >  			}
> >
> > -			if ( lcore_idle_hint < SLEEP_GEAR1_THRESHOLD)
> > +			if (lcore_idle_hint < SUSPEND_THRESHOLD)
> >  				/**
> > -				 * execute "pause" instruction to avoid context
> > -				 * switch for short sleep.
> > - 				 */
> > +				* execute "pause" instruction to avoid context
> > +				* switch which generally take hundres of microsecond
> > +				* for short sleep.
> > +				*/
> >  				rte_delay_us(lcore_idle_hint);
> > -			else
> > -				/* long sleep force runing thread to suspend */
> > -				usleep(lcore_idle_hint);
> > -
> > +			else {
> > +				/* suspend untill rx interrupt trigges */
> > +				sleep_until_rx_interrupt(
> > +					qconf->rx_queue_list[0].port_id,
> > +					qconf->rx_queue_list[0].queue_id);
> > +				/* start receiving packets immediately */
> > +				goto start_rx;
> > +			}
> >  			stats[lcore_id].sleep_time += lcore_idle_hint;
> >  		}
> >  	}
> >  }
> >
> > +/**
> > + * It will be called as the callback for specified port after a LSI interrupt
> > + * has been fully handled. This callback needs to be implemented carefully as
> > + * it will be called in the interrupt host thread which is different from the
> > + * application main thread.
> > + *
> > + * @param port_id
> > + *  Port id.
> > + * @param type
> > + *  event type.
> > + * @param param
> > + *  Pointer to(address of) the parameters.
> > + *
> > + * @return
> > + *  void.
> > + */
> > +
> > +/*
> > +static void
> > +rx_interrupt_event_callback(uint8_t port_id, enum rte_eth_event_type type,
> > void *param)
> > +{
> > +	uint64_t rx_queues = *((uint64_t *)param);
> > +
> > +	port_id = port_id + 1;
> > +	if(type == RTE_ETH_EVENT_INTR_RX)
> > +		port_id = rx_queues;
> [LCM] What's bunch of things for ?

Debug related code which will be removed in V2 patch.

> 
> > +}
> > +*/
> > +
> >  static int
> >  check_lcore_params(void)
> >  {
> > @@ -1270,7 +1346,7 @@ setup_hash(int socketid)
> >  	char s[64];
> >
> >  	/* create ipv4 hash */
> > -	snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
> > +	rte_snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
> >  	ipv4_l3fwd_hash_params.name = s;
> >  	ipv4_l3fwd_hash_params.socket_id = socketid;
> >  	ipv4_l3fwd_lookup_struct[socketid] =
> > @@ -1280,7 +1356,7 @@ setup_hash(int socketid)
> >  				"socket %d\n", socketid);
> >
> >  	/* create ipv6 hash */
> > -	snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
> > +	rte_snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
> >  	ipv6_l3fwd_hash_params.name = s;
> >  	ipv6_l3fwd_hash_params.socket_id = socketid;
> >  	ipv6_l3fwd_lookup_struct[socketid] =
> > @@ -1476,6 +1552,7 @@ main(int argc, char **argv)
> >  	unsigned lcore_id;
> >  	uint64_t hz;
> >  	uint32_t n_tx_queue, nb_lcores;
> > +	uint32_t dev_rxq_num, dev_txq_num;
> >  	uint8_t portid, nb_rx_queue, queue, socketid;
> >
> >  	/* catch SIGINT and restore cpufreq governor to ondemand */
> > @@ -1525,10 +1602,18 @@ main(int argc, char **argv)
> >  		printf("Initializing port %d ... ", portid );
> >  		fflush(stdout);
> >
> > +		rte_eth_dev_info_get(portid, &dev_info);
> > +		dev_rxq_num = dev_info.max_rx_queues;
> > +		dev_txq_num = dev_info.max_tx_queues;
> > +
> >  		nb_rx_queue = get_port_n_rx_queues(portid);
> > +		if (nb_rx_queue > dev_rxq_num)
> > +			rte_exit(EXIT_FAILURE, "Cannot configure not existed rxq: "
> > +					"port=%d\n", portid);
> > +
> >  		n_tx_queue = nb_lcores;
> > -		if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
> > -			n_tx_queue = MAX_TX_QUEUE_PER_PORT;
> > +		if (n_tx_queue > dev_txq_num)
> > +			n_tx_queue = dev_txq_num;
> >  		printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
> >  			nb_rx_queue, (unsigned)n_tx_queue );
> >  		ret = rte_eth_dev_configure(portid, nb_rx_queue,
> > @@ -1552,6 +1637,9 @@ main(int argc, char **argv)
> >  			if (rte_lcore_is_enabled(lcore_id) == 0)
> >  				continue;
> >
> > +			if (queueid >= dev_txq_num)
> > +				continue;
> > +
> >  			if (numa_on)
> >  				socketid = \
> >  				(uint8_t)rte_lcore_to_socket_id(lcore_id);
> > @@ -1586,8 +1674,9 @@ main(int argc, char **argv)
> >  		/* init power management library */
> >  		ret = rte_power_init(lcore_id);
> >  		if (ret)
> > -			rte_exit(EXIT_FAILURE, "Power management library "
> > -				"initialization failed on core%u\n", lcore_id);
> > +			rte_log(RTE_LOG_ERR, RTE_LOGTYPE_POWER,
> > +				"Power management library initialization "
> > +				"failed on core%u", lcore_id);
> >
> >  		/* init timer structures for each enabled lcore */
> >  		rte_timer_init(&power_timers[lcore_id]);
> > @@ -1635,7 +1724,6 @@ main(int argc, char **argv)
> >  		if (ret < 0)
> >  			rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, "
> >  						"port=%d\n", ret, portid);
> > -
> >  		/*
> >  		 * If enabled, put device in promiscuous mode.
> >  		 * This allows IO forwarding mode to forward packets
> > --
> > 1.8.1.4
  

Patch

diff --git a/examples/l3fwd-power/main.c b/examples/l3fwd-power/main.c
index f6b55b9..e6e4f55 100644
--- a/examples/l3fwd-power/main.c
+++ b/examples/l3fwd-power/main.c
@@ -75,12 +75,13 @@ 
 #include <rte_string_fns.h>
 #include <rte_timer.h>
 #include <rte_power.h>
+#include <rte_eal.h>
 
 #define RTE_LOGTYPE_L3FWD_POWER RTE_LOGTYPE_USER1
 
 #define MAX_PKT_BURST 32
 
-#define MIN_ZERO_POLL_COUNT 5
+#define MIN_ZERO_POLL_COUNT 10
 
 /* around 100ms at 2 Ghz */
 #define TIMER_RESOLUTION_CYCLES           200000000ULL
@@ -188,6 +189,9 @@  struct lcore_rx_queue {
 #define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS
 #define MAX_RX_QUEUE_PER_PORT 128
 
+#define MAX_RX_QUEUE_INTERRUPT_PER_PORT 16
+
+
 #define MAX_LCORE_PARAMS 1024
 struct lcore_params {
 	uint8_t port_id;
@@ -214,7 +218,7 @@  static uint16_t nb_lcore_params = sizeof(lcore_params_array_default) /
 
 static struct rte_eth_conf port_conf = {
 	.rxmode = {
-		.mq_mode	= ETH_MQ_RX_RSS,
+		.mq_mode = ETH_MQ_RX_RSS,
 		.max_rx_pkt_len = ETHER_MAX_LEN,
 		.split_hdr_size = 0,
 		.header_split   = 0, /**< Header Split disabled */
@@ -226,11 +230,14 @@  static struct rte_eth_conf port_conf = {
 	.rx_adv_conf = {
 		.rss_conf = {
 			.rss_key = NULL,
-			.rss_hf = ETH_RSS_IP,
+			.rss_hf = ETH_RSS_UDP,
 		},
 	},
 	.txmode = {
-		.mq_mode = ETH_DCB_NONE,
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.intr_conf = {
+		.rxq = 1, /**< rxq interrupt feature enabled */
 	},
 };
 
@@ -402,19 +409,22 @@  power_timer_cb(__attribute__((unused)) struct rte_timer *tim,
 	/* accumulate total execution time in us when callback is invoked */
 	sleep_time_ratio = (float)(stats[lcore_id].sleep_time) /
 					(float)SCALING_PERIOD;
-
 	/**
 	 * check whether need to scale down frequency a step if it sleep a lot.
 	 */
-	if (sleep_time_ratio >= SCALING_DOWN_TIME_RATIO_THRESHOLD)
-		rte_power_freq_down(lcore_id);
+	if (sleep_time_ratio >= SCALING_DOWN_TIME_RATIO_THRESHOLD) {
+		if (rte_power_freq_down)
+			rte_power_freq_down(lcore_id);
+	}
 	else if ( (unsigned)(stats[lcore_id].nb_rx_processed /
-		stats[lcore_id].nb_iteration_looped) < MAX_PKT_BURST)
+		stats[lcore_id].nb_iteration_looped) < MAX_PKT_BURST) {
 		/**
 		 * scale down a step if average packet per iteration less
 		 * than expectation.
 		 */
-		rte_power_freq_down(lcore_id);
+		if (rte_power_freq_down)
+			rte_power_freq_down(lcore_id);
+	}
 
 	/**
 	 * initialize another timer according to current frequency to ensure
@@ -707,22 +717,20 @@  l3fwd_simple_forward(struct rte_mbuf *m, uint8_t portid,
 
 }
 
-#define SLEEP_GEAR1_THRESHOLD            100
-#define SLEEP_GEAR2_THRESHOLD            1000
+#define MINIMUM_SLEEP_TIME         1
+#define SUSPEND_THRESHOLD          300
 
 static inline uint32_t
 power_idle_heuristic(uint32_t zero_rx_packet_count)
 {
-	/* If zero count is less than 100, use it as the sleep time in us */
-	if (zero_rx_packet_count < SLEEP_GEAR1_THRESHOLD)
-		return zero_rx_packet_count;
-	/* If zero count is less than 1000, sleep time should be 100 us */
-	else if ((zero_rx_packet_count >= SLEEP_GEAR1_THRESHOLD) &&
-			(zero_rx_packet_count < SLEEP_GEAR2_THRESHOLD))
-		return SLEEP_GEAR1_THRESHOLD;
-	/* If zero count is greater than 1000, sleep time should be 1000 us */
-	else if (zero_rx_packet_count >= SLEEP_GEAR2_THRESHOLD)
-		return SLEEP_GEAR2_THRESHOLD;
+	/* If zero count is less than 100,  sleep 1us */
+	if (zero_rx_packet_count < SUSPEND_THRESHOLD)
+		return MINIMUM_SLEEP_TIME;
+	/* If zero count is less than 1000, sleep 100 us which is the minimum latency
+	    switching from C3/C6 to C0
+	*/
+	else
+		return SUSPEND_THRESHOLD;
 
 	return 0;
 }
@@ -762,6 +770,35 @@  power_freq_scaleup_heuristic(unsigned lcore_id,
 	return FREQ_CURRENT;
 }
 
+/**
+ * force polling thread sleep until one-shot rx interrupt triggers
+ * @param port_id
+ *  Port id.
+ * @param queue_id
+ *  Rx queue id.
+ * @return
+ *  0 on success
+ */
+static int
+sleep_until_rx_interrupt(uint8_t port_id, uint8_t queue_id)
+{
+	/* Enable one-shot rx interrupt */
+	rte_eth_dev_rx_queue_intr_enable(port_id, queue_id);
+
+	RTE_LOG(INFO, L3FWD_POWER,
+		"lcore %u sleeps until interrupt on port%d,rxq%d triggers\n",
+		rte_lcore_id(), port_id, queue_id);
+	rte_eal_wait_rx_intr(port_id, queue_id);
+	RTE_LOG(INFO, L3FWD_POWER,
+		"lcore %u is waked up from rx interrupt on port%d,rxq%d\n",
+		rte_lcore_id(), port_id, queue_id);
+
+	/* Disable one-shot rx interrupt */
+	rte_eth_dev_rx_queue_intr_disable(port_id, queue_id);
+
+	return 0;
+}
+
 /* main processing loop */
 static int
 main_loop(__attribute__((unused)) void *dummy)
@@ -775,7 +812,6 @@  main_loop(__attribute__((unused)) void *dummy)
 	struct lcore_conf *qconf;
 	struct lcore_rx_queue *rx_queue;
 	enum freq_scale_hint_t lcore_scaleup_hint;
-
 	uint32_t lcore_rx_idle_count = 0;
 	uint32_t lcore_idle_hint = 0;
 
@@ -835,6 +871,8 @@  main_loop(__attribute__((unused)) void *dummy)
 			prev_tsc_power = cur_tsc_power;
 		}
 
+
+start_rx:
 		/*
 		 * Read packet from RX queues
 		 */
@@ -848,6 +886,7 @@  main_loop(__attribute__((unused)) void *dummy)
 
 			nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
 								MAX_PKT_BURST);
+
 			stats[lcore_id].nb_rx_processed += nb_rx;
 			if (unlikely(nb_rx == 0)) {
 				/**
@@ -910,10 +949,13 @@  main_loop(__attribute__((unused)) void *dummy)
 						rx_queue->freq_up_hint;
 			}
 
-			if (lcore_scaleup_hint == FREQ_HIGHEST)
-				rte_power_freq_max(lcore_id);
-			else if (lcore_scaleup_hint == FREQ_HIGHER)
-				rte_power_freq_up(lcore_id);
+			if (lcore_scaleup_hint == FREQ_HIGHEST) {
+				if (rte_power_freq_max)
+					rte_power_freq_max(lcore_id);
+			} else if (lcore_scaleup_hint == FREQ_HIGHER) {
+				if (rte_power_freq_up)
+					rte_power_freq_up(lcore_id);
+			}
 		} else {
 			/**
 			 * All Rx queues empty in recent consecutive polls,
@@ -928,21 +970,55 @@  main_loop(__attribute__((unused)) void *dummy)
 					lcore_idle_hint = rx_queue->idle_hint;
 			}
 
-			if ( lcore_idle_hint < SLEEP_GEAR1_THRESHOLD)
+			if (lcore_idle_hint < SUSPEND_THRESHOLD)
 				/**
-				 * execute "pause" instruction to avoid context
-				 * switch for short sleep.
- 				 */
+				* execute "pause" instruction to avoid context
+				* switch which generally take hundres of microsecond
+				* for short sleep.
+				*/
 				rte_delay_us(lcore_idle_hint);
-			else
-				/* long sleep force runing thread to suspend */
-				usleep(lcore_idle_hint);
-
+			else {
+				/* suspend untill rx interrupt trigges */
+				sleep_until_rx_interrupt(
+					qconf->rx_queue_list[0].port_id,
+					qconf->rx_queue_list[0].queue_id);
+				/* start receiving packets immediately */
+				goto start_rx;
+			}
 			stats[lcore_id].sleep_time += lcore_idle_hint;
 		}
 	}
 }
 
+/**
+ * It will be called as the callback for specified port after a LSI interrupt
+ * has been fully handled. This callback needs to be implemented carefully as
+ * it will be called in the interrupt host thread which is different from the
+ * application main thread.
+ *
+ * @param port_id
+ *  Port id.
+ * @param type
+ *  event type.
+ * @param param
+ *  Pointer to(address of) the parameters.
+ *
+ * @return
+ *  void.
+ */
+
+/*
+static void
+rx_interrupt_event_callback(uint8_t port_id, enum rte_eth_event_type type, void *param)
+{
+	uint64_t rx_queues = *((uint64_t *)param);
+
+	port_id = port_id + 1;
+	if(type == RTE_ETH_EVENT_INTR_RX)
+		port_id = rx_queues;
+}
+*/
+
 static int
 check_lcore_params(void)
 {
@@ -1270,7 +1346,7 @@  setup_hash(int socketid)
 	char s[64];
 
 	/* create ipv4 hash */
-	snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
+	rte_snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
 	ipv4_l3fwd_hash_params.name = s;
 	ipv4_l3fwd_hash_params.socket_id = socketid;
 	ipv4_l3fwd_lookup_struct[socketid] =
@@ -1280,7 +1356,7 @@  setup_hash(int socketid)
 				"socket %d\n", socketid);
 
 	/* create ipv6 hash */
-	snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
+	rte_snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
 	ipv6_l3fwd_hash_params.name = s;
 	ipv6_l3fwd_hash_params.socket_id = socketid;
 	ipv6_l3fwd_lookup_struct[socketid] =
@@ -1476,6 +1552,7 @@  main(int argc, char **argv)
 	unsigned lcore_id;
 	uint64_t hz;
 	uint32_t n_tx_queue, nb_lcores;
+	uint32_t dev_rxq_num, dev_txq_num;
 	uint8_t portid, nb_rx_queue, queue, socketid;
 
 	/* catch SIGINT and restore cpufreq governor to ondemand */
@@ -1525,10 +1602,18 @@  main(int argc, char **argv)
 		printf("Initializing port %d ... ", portid );
 		fflush(stdout);
 
+		rte_eth_dev_info_get(portid, &dev_info);
+		dev_rxq_num = dev_info.max_rx_queues;
+		dev_txq_num = dev_info.max_tx_queues;
+
 		nb_rx_queue = get_port_n_rx_queues(portid);
+		if (nb_rx_queue > dev_rxq_num)
+			rte_exit(EXIT_FAILURE, "Cannot configure not existed rxq: "
+					"port=%d\n", portid);
+
 		n_tx_queue = nb_lcores;
-		if (n_tx_queue > MAX_TX_QUEUE_PER_PORT)
-			n_tx_queue = MAX_TX_QUEUE_PER_PORT;
+		if (n_tx_queue > dev_txq_num)
+			n_tx_queue = dev_txq_num;
 		printf("Creating queues: nb_rxq=%d nb_txq=%u... ",
 			nb_rx_queue, (unsigned)n_tx_queue );
 		ret = rte_eth_dev_configure(portid, nb_rx_queue,
@@ -1552,6 +1637,9 @@  main(int argc, char **argv)
 			if (rte_lcore_is_enabled(lcore_id) == 0)
 				continue;
 
+			if (queueid >= dev_txq_num)
+				continue;
+
 			if (numa_on)
 				socketid = \
 				(uint8_t)rte_lcore_to_socket_id(lcore_id);
@@ -1586,8 +1674,9 @@  main(int argc, char **argv)
 		/* init power management library */
 		ret = rte_power_init(lcore_id);
 		if (ret)
-			rte_exit(EXIT_FAILURE, "Power management library "
-				"initialization failed on core%u\n", lcore_id);
+			rte_log(RTE_LOG_ERR, RTE_LOGTYPE_POWER,
+				"Power management library initialization "
+				"failed on core%u", lcore_id);
 
 		/* init timer structures for each enabled lcore */
 		rte_timer_init(&power_timers[lcore_id]);
@@ -1635,7 +1724,6 @@  main(int argc, char **argv)
 		if (ret < 0)
 			rte_exit(EXIT_FAILURE, "rte_eth_dev_start: err=%d, "
 						"port=%d\n", ret, portid);
-
 		/*
 		 * If enabled, put device in promiscuous mode.
 		 * This allows IO forwarding mode to forward packets