Power-optimized RX for Ethernet devices
Subsystems (3)
cover Power-optimized RX for Ethernet devices
This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive, along with a set of (hopefully generic) intrinsics that facilitate that. This is achieved through cooperation with the NIC driver that will allow us to know address of the next NIC RX ring packet descriptor, and wait for writes on it.
On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.
To achieve power savings, there is a very simple mechanism
used: we're counting empty polls, and if a certain threshold is reached, we get the address of next RX ring descriptor from the NIC driver, arm the monitoring hardware, and enter a power-optimized state. We will then wake up when either a timeout happens, or a write happens (or generally whenever CPU feels like waking up - this is platform- specific), and proceed as normal. The empty poll counter is reset whenever we actually get packets, so we only go to sleep when we know nothing is going on.
Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it wit minimal changes to the application code. The current approach allows to just flip a switch and automagically have power savings.
There are certain limitations in this patchset right now:
- Currently, only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Currently, power management is enabled per-port, not per-queue
- There is potential to greatly increase TX latency if we are buffering things, and go to sleep before sending packets
- The API is not perfect and could use some improvement and discussion
- The API doesn't extend to other device types
- The intrinsics are platform-specific, so ethdev has some platform-specific code in it
- Support was only implemented for devices using net/ixgbe, net/i40e and net/ice drivers
Hopefully this would generate enough feedback to clear a path forward!
Anatoly Burakov (6):
eal: add power management intrinsics
ethdev: add simple power management API net/ixgbe: implement power management API net/i40e: implement power management API net/ice: implement power management API app/testpmd: add command for power management on a port
app/test-pmd/cmdline.c | 48 +++++++ drivers/net/i40e/i40e_ethdev.c | 1 + drivers/net/i40e/i40e_rxtx.c | 23 +++ drivers/net/i40e/i40e_rxtx.h | 2 + drivers/net/ice/ice_ethdev.c | 1 + drivers/net/ice/ice_rxtx.c | 23 +++ drivers/net/ice/ice_rxtx.h | 2 + drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 +++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 + .../include/generic/rte_power_intrinsics.h | 64 +++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + lib/librte_eal/x86/include/rte_cpuflags.h | 1 + .../x86/include/rte_power_intrinsics.h | 134 ++++++++++++++++++ lib/librte_eal/x86/rte_cpuflags.c | 2 + lib/librte_ethdev/rte_ethdev.c | 39 +++++ lib/librte_ethdev/rte_ethdev.h | 70 +++++++++ lib/librte_ethdev/rte_ethdev_core.h | 41 +++++- lib/librte_ethdev/rte_ethdev_version.map | 4 + 20 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
Signature · 1 line
2.17.1
RFC 1/6 eal: add power management intrinsics
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
--- .../include/generic/rte_power_intrinsics.h | 64 +++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + lib/librte_eal/x86/include/rte_cpuflags.h | 1 + .../x86/include/rte_power_intrinsics.h | 134 ++++++++++++++++++ lib/librte_eal/x86/rte_cpuflags.c | 2 + 6 files changed, 203 insertions(+) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
@@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_H_ +#define _RTE_POWER_INTRINSIC_H_ + +#include <inttypes.h> + +/** +* @file +* Advanced power management operations. +* +* This file define APIs for advanced power management, +* which are architecture-dependent. +*/ + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* @param p +* Address to monitor for changes. Must be aligned on an 8-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp); + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp); + +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
@@ -59,6 +59,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',
lib/librte_eal/x86/include/rte_cpuflags.h +1 -0
@@ -110,6 +110,7 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_RDTSCP ,/**< RDTSCP */ RTE_CPUFLAG_EM64T ,/**< EM64T */ +RTE_CPUFLAG_WAITPKG ,/**< UMINITOR/UMWAIT/TPAUSE */ /* (EAX 80000007h) EDX features */ RTE_CPUFLAG_INVTSC, /**< INVTSC */
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +134 -0
134 lines not on this page · raw message
lib/librte_eal/x86/rte_cpuflags.c +2 -0
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 )
Signature · 1 line
2.17.1
RFC 3/6 net/ixgbe: implement power management API
In reply to Anatoly BurakovImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 ++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 ++ 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
@@ -605,6 +605,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = { .udp_tunnel_port_del = ixgbe_dev_udp_tunnel_port_del, .tm_ops_get = ixgbe_tm_ops_get, .tx_done_cleanup = ixgbe_dev_tx_done_cleanup, + .next_rx_desc = ixgbe_next_rx_desc, };/*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
@@ -1366,6 +1366,28 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +int ixgbe_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ixgbe_adv_rx_desc *rxdp; +struct ixgbe_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.upper.status_error; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + *mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + +return 0 ; +} +/* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */ static inline uint32_t ixgbe_rxd_pkt_info_to_pkt_type (uint32_t pkt_info,uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_queue_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_port_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_tx_queue_offloads (struct rte_eth_dev *dev); +int ixgbe_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
RFC 2/6 ethdev: add simple power management API
In reply to Anatoly BurakovAdd a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API is limited to 1 core 1 queue use case as there is no coordination between queues/cores in ethdev.
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
--- lib/librte_ethdev/rte_ethdev.c | 39 +++++++++++++ lib/librte_ethdev/rte_ethdev.h | 70 ++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_core.h | 41 +++++++++++++- lib/librte_ethdev/rte_ethdev_version.map | 4 ++ 4 files changed, 152 insertions(+), 2 deletions(-)
lib/librte_ethdev/rte_ethdev.c +39 -0
@@ -16,6 +16,7 @@#include <netinet/in.h> #include <rte_byteorder.h> +#include <rte_cpuflags.h> #include <rte_log.h> #include <rte_debug.h> #include <rte_interrupts.h>
@@ -5053,6 +5054,44 @@ rte_eth_dev_pool_ops_supported(uint16_t port_id, const char *pool)return (*dev->dev_ops->pool_ops_supported)(dev, pool); } +int +rte_eth_dev_power_mgmt_enable (uint16_t port_id) +{ +struct rte_eth_dev *dev; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); + dev = &rte_eth_devices[port_id]; + +if (!rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) +return -ENOTSUP ; + +/* allocate memory for empty poll stats */ + dev->empty_poll_stats =rte_malloc_socket (NULL , +sizeof (struct rte_eth_ep_stat ) *RTE_MAX_QUEUES_PER_PORT , +0 , dev->data->numa_node); + +if (dev->empty_poll_stats ==NULL ) +return -ENOMEM ; + + dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_ENABLED ; +return 0 ; +} + +int +rte_eth_dev_power_mgmt_disable (uint16_t port_id) +{ +struct rte_eth_dev *dev; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); + dev = &rte_eth_devices[port_id]; + +/* rte_free ignores NULL so safe to call without checks */ +rte_free (dev->empty_poll_stats); + + dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_DISABLED ; +return 0 ; +} +/** * A set of values to describe the possible states of a switch domain. */
lib/librte_ethdev/rte_ethdev.h +70 -0
100 lines not on this page · raw message
lib/librte_ethdev/rte_ethdev_core.h +39 -2
65 lines not on this page · raw message
lib/librte_ethdev/rte_ethdev_version.map +4 -0
@@ -241,4 +241,8 @@ EXPERIMENTAL { __rte_ethdev_trace_rx_burst; __rte_ethdev_trace_tx_burst; rte_flow_get_aged_flows; + + # added in 20.08 + rte_eth_dev_power_mgmt_disable; + rte_eth_dev_power_mgmt_enable; };
Signature · 1 line
2.17.1
RFC 5/6 net/ice: implement power management API
In reply to Anatoly BurakovImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/ice/ice_ethdev.c | 1 + drivers/net/ice/ice_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/ice/ice_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
@@ -219,6 +219,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .udp_tunnel_port_add = ice_dev_udp_tunnel_port_add, .udp_tunnel_port_del = ice_dev_udp_tunnel_port_del, .tx_done_cleanup = ice_tx_done_cleanup, + .next_rx_desc = ice_next_rx_desc, };/* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
@@ -24,6 +24,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_mask;uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask; +int ice_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ice_rx_flex_desc *rxdp; +struct ice_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.status_error0; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + *mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + +return 0 ; +} + +static inline uint64_t ice_rxdid_to_proto_xtr_ol_flag (uint8_t rxdid) {
drivers/net/ice/ice_rxtx.h +2 -0
@@ -202,5 +202,7 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);int ice_fdir_programming (struct ice_pf *pf,struct ice_fltr_desc *fdir_desc);int ice_tx_done_cleanup (void *txq,uint32_t free_cnt); +int ice_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _ICE_RXTX_H_ */
Signature · 1 line
2.17.1
RFC 4/6 net/i40e: implement power management API
In reply to Anatoly BurakovImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/i40e/i40e_ethdev.c | 1 + drivers/net/i40e/i40e_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/i40e/i40e_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
@@ -526,6 +526,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = { .mtu_set = i40e_dev_mtu_set, .tm_ops_get = i40e_tm_ops_get, .tx_done_cleanup = i40e_tx_done_cleanup, + .next_rx_desc = i40e_next_rx_desc, };/* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
@@ -71,6 +71,29 @@#define I40E_TX_OFFLOAD_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK) +int +i40e_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +struct i40e_rx_queue *rxq = rx_queue; +volatile union i40e_rx_desc *rxdp; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.qword1.status_error_len; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + *mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + +return 0 ; +} +static inline void i40e_rxd_to_vlan_tci (struct rte_mbuf *mb,volatile union i40e_rx_desc *rxdp) {
drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -245,6 +245,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);uint16_t i40e_xmit_pkts_vec_avx2 (void *tx_queue,struct rte_mbuf **tx_pkts,uint16_t nb_pkts); +int i40e_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *value);/* For each value it means, datasheet of hardware can tell more details *
Signature · 1 line
2.17.1
RFC 6/6 app/testpmd: add command for power management on a port
In reply to Anatoly BurakovA quick-and-dirty testpmd command to enable power management on a specific port.
--- app/test-pmd/cmdline.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+)
app/test-pmd/cmdline.c +48 -0
@@ -1773,6 +1773,53 @@ cmdline_parse_inst_t cmd_config_speed_specific = { }, }; +/* *** enable power management for specific port *** */ +struct cmd_port_pmgmt { +cmdline_fixed_string_t port; +portid_t id; +cmdline_fixed_string_t pmgmt; +cmdline_fixed_string_t on; +}; + +static void +cmd_port_pmgmt_parsed (void *parsed_result, + __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ +struct cmd_port_pmgmt *res = parsed_result; + +if (port_id_is_invalid (res->id,ENABLED_WARN )) +return ; + +if (!strcmp (res->on,"on" )) +rte_eth_dev_power_mgmt_enable (res->id); +else if (!strcmp (res->on,"off" )) +rte_eth_dev_power_mgmt_disable (res->id); +} + + +cmdline_parse_token_string_t cmd_port_pmgmt_port = + TOKEN_STRING_INITIALIZER(struct cmd_port_pmgmt, port, "port"); +cmdline_parse_token_num_t cmd_port_pmgmt_id = + TOKEN_NUM_INITIALIZER(struct cmd_port_pmgmt, id, UINT16); +cmdline_parse_token_string_t cmd_port_pmgmt_item1 = + TOKEN_STRING_INITIALIZER(struct cmd_port_pmgmt, pmgmt, "power-mgmt"); +cmdline_parse_token_string_t cmd_port_pmgmt_value1 = + TOKEN_STRING_INITIALIZER(struct cmd_port_pmgmt, on, "on#off"); + +cmdline_parse_inst_t cmd_port_pmgmt = { + .f = cmd_port_pmgmt_parsed, + .data =NULL , + .help_str ="port <port_id> power-mgmt on|off" , + .tokens = { + (void *)&cmd_port_pmgmt_port, + (void *)&cmd_port_pmgmt_id, + (void *)&cmd_port_pmgmt_item1, + (void *)&cmd_port_pmgmt_value1, +NULL , + }, +}; +/* *** configure loopback for all ports *** */ struct cmd_config_loopback_all {cmdline_fixed_string_t port;
@@ -19692,6 +19739,7 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_show_set_raw, (cmdline_parse_inst_t *)&cmd_show_set_raw_all, (cmdline_parse_inst_t *)&cmd_config_tx_dynf_specific, + (cmdline_parse_inst_t *)&cmd_port_pmgmt, NULL, };
Signature · 1 line
2.17.1
Quoted 50 lines · Anatoly Burakov
This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive, along with a set of (hopefully generic) intrinsics that facilitate that. This is achieved through cooperation with the NIC driver that will allow us to know address of the next NIC RX ring packet descriptor, and wait for writes on it.
On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.
To achieve power savings, there is a very simple mechanism
used: we're counting empty polls, and if a certain threshold is reached, we get the address of next RX ring descriptor from the NIC driver, arm the monitoring hardware, and enter a power-optimized state. We will then wake up when either a timeout happens, or a write happens (or generally whenever CPU feels like waking up - this is platform- specific), and proceed as normal. The empty poll counter is reset whenever we actually get packets, so we only go to sleep when we know nothing is going on.Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it wit minimal changes to the application code. The current approach allows to just flip a switch and automagically have power savings.
There are certain limitations in this patchset right now:
- Currently, only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Currently, power management is enabled per-port, not per-queue
- There is potential to greatly increase TX latency if we are buffering things, and go to sleep before sending packets
- The API is not perfect and could use some improvement and discussion
- The API doesn't extend to other device types
- The intrinsics are platform-specific, so ethdev has some platform-specific code in it
- Support was only implemented for devices using net/ixgbe, net/i40e and net/ice drivers
Quoted 2 lines
Hopefully this would generate enough feedback to clear a path forward!
Just for my understanding:
How/Is this solution is superior than Rx queue interrupt based scheme that applied in l3fwd-power?
What I meant by superior here, as an example,
a)Is there any power savings in mill watt vs interrupt scheme?
b) Is there improvement on time reduction between switching from/to a different state
(i.e how fast it can move from low power state to full power state) vs interrupt scheme.
etc
or This just for just pushing all the logic to ethdev so that applications can be transparent?
Quoted 35 lines
Anatoly Burakov (6):
eal: add power management intrinsics
ethdev: add simple power management API net/ixgbe: implement power management API net/i40e: implement power management API net/ice: implement power management API app/testpmd: add command for power management on a portapp/test-pmd/cmdline.c | 48 +++++++ drivers/net/i40e/i40e_ethdev.c | 1 + drivers/net/i40e/i40e_rxtx.c | 23 +++ drivers/net/i40e/i40e_rxtx.h | 2 + drivers/net/ice/ice_ethdev.c | 1 + drivers/net/ice/ice_rxtx.c | 23 +++ drivers/net/ice/ice_rxtx.h | 2 + drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 +++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 + .../include/generic/rte_power_intrinsics.h | 64 +++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + lib/librte_eal/x86/include/rte_cpuflags.h | 1 + .../x86/include/rte_power_intrinsics.h | 134 ++++++++++++++++++ lib/librte_eal/x86/rte_cpuflags.c | 2 + lib/librte_ethdev/rte_ethdev.c | 39 +++++ lib/librte_ethdev/rte_ethdev.h | 70 +++++++++ lib/librte_ethdev/rte_ethdev_core.h | 41 +++++- lib/librte_ethdev/rte_ethdev_version.map | 4 + 20 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h--
2.17.1
Quoted 68 lines · On Wed, 27 May 2020 23:03:59 +0530 Jerin Jacob <[email protected]> wrote:
Quoted 50 lines · Anatoly Burakov
This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive, along with a set of (hopefully generic) intrinsics that facilitate that. This is achieved through cooperation with the NIC driver that will allow us to know address of the next NIC RX ring packet descriptor, and wait for writes on it.
On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.
To achieve power savings, there is a very simple mechanism
used: we're counting empty polls, and if a certain threshold is reached, we get the address of next RX ring descriptor from the NIC driver, arm the monitoring hardware, and enter a power-optimized state. We will then wake up when either a timeout happens, or a write happens (or generally whenever CPU feels like waking up - this is platform- specific), and proceed as normal. The empty poll counter is reset whenever we actually get packets, so we only go to sleep when we know nothing is going on.Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it wit minimal changes to the application code. The current approach allows to just flip a switch and automagically have power savings.
There are certain limitations in this patchset right now:
- Currently, only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Currently, power management is enabled per-port, not per-queue
- There is potential to greatly increase TX latency if we are buffering things, and go to sleep before sending packets
- The API is not perfect and could use some improvement and discussion
- The API doesn't extend to other device types
- The intrinsics are platform-specific, so ethdev has some platform-specific code in it
- Support was only implemented for devices using net/ixgbe, net/i40e and net/ice driversQuoted 2 lines
Hopefully this would generate enough feedback to clear a path forward!
Just for my understanding:
How/Is this solution is superior than Rx queue interrupt based scheme that applied in l3fwd-power?
What I meant by superior here, as an example,
a)Is there any power savings in mill watt vs interrupt scheme?
b) Is there improvement on time reduction between switching from/to a different state
(i.e how fast it can move from low power state to full power state) vs interrupt scheme.
etc
Quoted 3 lines
or This just for just pushing all the logic to ethdev so that applications can be transparent?
The interrupt scheme is going to get better power management since the core can go to WAIT. This scheme does look interesting in theory since it will be lower latency.
but has a number of issues:
* changing drivers
* can not multiplex multiple queues per core; you are assuming a certain threading model
* what if thread is preempted
* what about thread in a VM
* platform specific: ARM and x86 have different semantics here
Re: [dpdk-dev] [RFC 1/6] eal: add power management intrinsics
In reply to Anatoly BurakovHi Anatoly,
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Recently ARM guys introduced new generic API
for similar (as I understand) purposes: rte_wait_until_equal_(16|32|64). Probably would make sense to unite both APIs into something common and HW transparent.
Konstantin
Quoted 275 lines
Signed-off-by Liang J. Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- .../include/generic/rte_power_intrinsics.h | 64 +++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + lib/librte_eal/x86/include/rte_cpuflags.h | 1 + .../x86/include/rte_power_intrinsics.h | 134 ++++++++++++++++++ lib/librte_eal/x86/rte_cpuflags.c | 2 + 6 files changed, 203 insertions(+) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.hlib/librte_eal/include/generic/rte_power_intrinsics.h new file +64
-0@@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_H_ +#define _RTE_POWER_INTRINSIC_H_ + +#include <inttypes.h> + +/** +* @file +* Advanced power management operations. +* +* This file define APIs for advanced power management, +* which are architecture-dependent. +*/ + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* @param p +* Address to monitor for changes. Must be aligned on an 8-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp); + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp); + +#endif /* _RTE_POWER_INTRINSIC_H_ */ lib/librte_eal/include/meson.build +1
-0@@ -59,6 +59,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',lib/librte_eal/x86/include/meson.build +1
-0@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',lib/librte_eal/x86/include/rte_cpuflags.h +1
-0@@ -110,6 +110,7 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_RDTSCP ,/**< RDTSCP */ RTE_CPUFLAG_EM64T ,/**< EM64T */ +RTE_CPUFLAG_WAITPKG ,/**< UMINITOR/UMWAIT/TPAUSE */ /* (EAX 80000007h) EDX features */ RTE_CPUFLAG_INVTSC, /**< INVTSC */lib/librte_eal/x86/include/rte_power_intrinsics.h new file +134
-0@@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_X86_64_H_ +#define _RTE_POWER_INTRINSIC_X86_64_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_atomic.h> +#include <rte_common.h> + +#include "generic/rte_power_intrinsics.h" + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* This function uses UMONITOR/UMWAIT instructions. For more information about +* their usage, please refer to Intel(R) 64 and IA-32 Architectures Software +* Developer's Manual. +* +* @param p +* Address to monitor for changes. Must be aligned on an 8-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number. Can be 0 (C0.2) or +* 1 (C0.1). +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to memory write or other reasons. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp) +{ +const uint32_t tsc_l = (uint32_t )tsc_timestamp; +const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 ); +uint64_t rflags; + +/* +* we're using raw byte codes for now as only the newest compiler +* versions support this instruction natively. +*/ + +/* set address for UMONITOR */ + asmvolatile (".byte 0xf3, 0x0f, 0xae, 0xf7;" + : + :"D" (p)); +rte_mb (); +if (value_mask) { +const uint64_t cur_value = *(const volatile uint64_t *)p; +const uint64_t masked = cur_value & value_mask; +/* if the masked value is already matching, abort */ +if (masked == expected_value) +return 0 ; + } +/* execute UMWAIT */ + asmvolatile (".byte 0xf2, 0x0f, 0xae, 0xf7;\n" +/* +* UMWAIT sets CF flag in RFLAGS, so PUSHF to push them +* onto the stack, then pop them back into `rflags` so that +* we can read it. +*/ +"pushf;\n" +"pop %0;\n" + :"=r" (rflags) + :"D" (state),"a" (tsc_l),"d" (tsc_h)); + +/* we're interested in the first bit (the carry flag) */ +return rflags &0x1 ; +} + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* This function uses TPAUSE instruction. For more information about its usage, +* please refer to Intel(R) 64 and IA-32 Architectures Software Developer's +* Manual. +* +* @param state +* Architecture-dependent optimized power state number. Can be 0 (C0.2) or +* 1 (C0.1). +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to other reasons. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp) +{ +const uint32_t tsc_l = (uint32_t )tsc_timestamp; +const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 ); +uint64_t rflags; + +/* execute TPAUSE */ + asmvolatile (".byte 0x66, 0x0f, 0xae, 0xf7;\n" +/* +* TPAUSE sets CF flag in RFLAGS, so PUSHF to push them +* onto the stack, then pop them back into `rflags` so that +* we can read it. +*/ +"pushf;\n" +"pop %0;\n" + :"=r" (rflags) + :"D" (state),"a" (tsc_l),"d" (tsc_h)); + +/* we're interested in the first bit (the carry flag) */ +return rflags &0x1 ; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_POWER_INTRINSIC_X86_64_H_ */ lib/librte_eal/x86/rte_cpuflags.c +2
-1@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 ) --2.17.1
Re: [dpdk-dev] [RFC 2/6] ethdev: add simple power management API
In reply to Anatoly BurakovQuoted 168 lines
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API is limited to 1 core 1 queue use case as there is no coordination between queues/cores in ethdev.
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
Signed-off-by Liang J. Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_ethdev/rte_ethdev.c | 39 +++++++++++++ lib/librte_ethdev/rte_ethdev.h | 70 ++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_core.h | 41 +++++++++++++- lib/librte_ethdev/rte_ethdev_version.map | 4 ++ 4 files changed, 152 insertions(+), 2 deletions(-)lib/librte_ethdev/rte_ethdev.c +39
-0@@ -16,6 +16,7 @@#include <netinet/in.h> #include <rte_byteorder.h> +#include <rte_cpuflags.h> #include <rte_log.h> #include <rte_debug.h> #include <rte_interrupts.h> @@ -5053,6 +5054,44 @@ rte_eth_dev_pool_ops_supported(uint16_t port_id, const char *pool)return (*dev->dev_ops->pool_ops_supported)(dev, pool); } +int +rte_eth_dev_power_mgmt_enable (uint16_t port_id) +{ +struct rte_eth_dev *dev; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); + dev = &rte_eth_devices[port_id]; + +if (!rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) +return -ENOTSUP ; + +/* allocate memory for empty poll stats */ + dev->empty_poll_stats =rte_malloc_socket (NULL , +sizeof (struct rte_eth_ep_stat ) *RTE_MAX_QUEUES_PER_PORT , +0 , dev->data->numa_node); + +if (dev->empty_poll_stats ==NULL ) +return -ENOMEM ; + + dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_ENABLED ; +return 0 ; +} + +int +rte_eth_dev_power_mgmt_disable (uint16_t port_id) +{ +struct rte_eth_dev *dev; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); + dev = &rte_eth_devices[port_id]; + +/* rte_free ignores NULL so safe to call without checks */ +rte_free (dev->empty_poll_stats); + + dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_DISABLED ; +return 0 ; +} +/** * A set of values to describe the possible states of a switch domain. */ lib/librte_ethdev/rte_ethdev.h +51
-0@@ -157,6 +157,7 @@ extern "C" {#include <rte_common.h> #include <rte_config.h> #include <rte_ether.h> +#include <rte_power_intrinsics.h> #include "rte_ethdev_trace_fp.h" #include "rte_dev_info.h" @@ -666,6 +667,7 @@ rte_eth_rss_hf_refine(uint64_t rss_hf)/** Maximum nb. of vlan per mirror rule */ #define ETH_MIRROR_MAX_VLANS 64 +#define ETH_EMPTYPOLL_MAX 512/**< Empty poll number threshlold */ #define ETH_MIRROR_VIRTUAL_POOL_UP 0x01/**< Virtual Pool uplink Mirroring. */ #define ETH_MIRROR_UPLINK_PORT 0x02/**< Uplink Port Mirroring. */ #define ETH_MIRROR_DOWNLINK_PORT 0x04/**< Downlink Port Mirroring. */ @@ -1490,6 +1492,16 @@ enum rte_eth_dev_state { RTE_ETH_DEV_REMOVED, }; +/** +* Possible power managment states of an ethdev port. +*/ +enum rte_eth_dev_power_mgmt_state { +/** Device power management is disabled. */ +RTE_ETH_DEV_POWER_MGMT_DISABLED =0 , +/** Device power management is enabled. */ +RTE_ETH_DEV_POWER_MGMT_ENABLED +}; +struct rte_eth_dev_sriov {uint8_t active;/**< SRIOV is active with 16, 32 or 64 pools */ uint8_t nb_q_per_pool;/**< rx queue number per pool */ @@ -4302,6 +4314,38 @@ __rte_experimentalint rte_eth_dev_hairpin_capability_get (uint16_t port_id,struct rte_eth_hairpin_cap *cap); +/** +* @warning +* @b EXPERIMENTAL: this API may change, or be removed, without prior notice +* +* Enable device power management. +* +* @param port_id +* The port identifier of the Ethernet device. +* +* @return +* 0 on success +* <0 on error +*/ +__rte_experimental +int rte_eth_dev_power_mgmt_enable(uint16_t port_id); + +/** +* @warning +* @b EXPERIMENTAL: this API may change, or be removed, without prior notice +* +* Disable device power management. +* +* @param port_id +* The port identifier of the Ethernet device. +* +* @return +* 0 on success +* <0 on error +*/ +__rte_experimental +int rte_eth_dev_power_mgmt_disable(uint16_t port_id); +#include <rte_ethdev_core.h> /** @@ -4417,6 +4461,32 @@ rte_eth_rx_burst(uint16_t port_id, uint16_t queue_id, } while (cb != NULL); }#endif +if (dev->pwr_mgmt_state ==RTE_ETH_DEV_POWER_MGMT_ENABLED ) { +if (unlikely (nb_rx ==0 )) { + dev->empty_poll_stats[queue_id].num++; +if (unlikely (dev->empty_poll_stats[queue_id].num > +ETH_EMPTYPOLL_MAX )) { +volatile void *target_addr; +uint64_t expected, mask;
lib/librte_ethdev/rte_ethdev.h rte_eth_rx_burst(uint16_t port_id, uint16_t queue_id, · line 4480
Quoted 10 lines
lib/librte_ethdev/rte_ethdev.h +10
-0+int ret; + +/* +* get address of next descriptor in the RX +* ring for this queue, as well as expected +* value and a mask. +*/ + ret = (*dev->dev_ops->next_rx_desc) + (dev->data->rx_queues[queue_id], + &target_addr, &expected, &mask);
That makes every PMD that doesn't support next_rx_desc op to crash.
One simple way to avoid it - check in rte_eth_dev_power_mgmt_enable() that PMD does implement ops->next_rx_desc.
Though I don't think introducing such new op is a best approach, as it implies that PMD does have HW RX descriptor mapped into WB-type memory, and dictates
to PMD on what it should sleep on.
Though depending on HW/SW capabilities and implementation PMD might choose to sleep on different thing (HW doorbell, SW cond var, etc.).
Another thing - I doubt it is a good idea to pollute generic RX function with power specific code (again, as I said above it probably wouldn't be that generic for all possible PMDs). From my perspective we have 2 alternatives to implement such functionality:
1. Keep rte_eth_dev_power_mgmt_enable/disable(port, queue) and move actual *wait_on* code into the PMD RX implementations (we probably can still have some common. logic about allowed number of empty polls, max timeout to sleep, etc.).
2. Drop rte_eth_dev_power_mgmt_enable/disable and introduce explicit:
rte_eth_dev_wait_for_packet(port, queue, timeout) API function.
In both cases PMD will have a full freedom to implement *wait_on_packet* functionality in a most convenient way.
For 2) user would have to do some extra work himself
(count number of consecutive empty polls, call *wait_on_packet* function explicitly). Though I think it can be easily hidden inside some wrapper API on top
of rte_eth_rx_burst()/rte_eth-dev_wait_for_packet().
Something like rte_eth_rx_burst_wait() or so.
We can have logic about allowed number of empty polls,
might be some other conditions in that top level function.
In that case changes in the user app will still be minimal.
From other side 2) gives user explicit control on where and when to sleep, so from my perspective it seems more straightforward and flexible.
Quoted 100 lines
lib/librte_ethdev/rte_ethdev.h +9
-0+if (ret ==0 ) +/* -1ULL is maximum value for TSC */ +rte_power_monitor (target_addr, + expected, mask, +0 ,-1ULL ); + } + }else + dev->empty_poll_stats[queue_id].num =0 ; + }rte_ethdev_trace_rx_burst (port_id, queue_id, (void **)rx_pkts, nb_rx);return nb_rx;lib/librte_ethdev/rte_ethdev_core.h +39
-2@@ -603,6 +603,27 @@ typedef int (*eth_tx_hairpin_queue_setup_t)uint16_t nb_tx_desc, const struct rte_eth_hairpin_conf *hairpin_conf); +/** +* @internal +* Get the next RX ring descriptor address. +* +* @param rxq +* ethdev queue pointer. +* @param tail_desc_addr +* the pointer point to descriptor address var. +* +* @return +* Negative errno value on error, 0 on success. +* +* @retval 0 +* Success. +* @retval -EINVAL +* Failed to get descriptor address. +*/ +typedef int (*eth_next_rx_desc_t ) + (void *rxq,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask); +/** * @internal A structure containing the functions exported by an Ethernet driver. */ @@ -752,6 +773,8 @@ struct eth_dev_ops {/**< Set up device RX hairpin queue. */ eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;/**< Set up device TX hairpin queue. */ +eth_next_rx_desc_t next_rx_desc; +/**< Get next RX ring descriptor address. */ };/** @@ -768,6 +791,14 @@ struct rte_eth_rxtx_callback {void *param; }; +/** +* @internal +* Structure used to hold counters for empty poll +*/ +struct rte_eth_ep_stat { +uint64_t num; +} __rte_cache_aligned; +/** * @internal * The generic data structure associated with each ethernet device. @@ -807,8 +838,14 @@ struct rte_eth_dev {enum rte_eth_dev_state state;/**< Flag indicating the port state */ void *security_ctx;/**< Context for security ops */ -uint64_t reserved_64s[4 ];/**< Reserved for future fields */ -void *reserved_ptrs[4 ];/**< Reserved for future fields */ +/**< Empty poll number */ +enum rte_eth_dev_power_mgmt_state pwr_mgmt_state; +uint32_t reserved_32; +uint64_t reserved_64s[3 ];/**< Reserved for future fields */ + +/**< Flag indicating the port power state */ +struct rte_eth_ep_stat *empty_poll_stats; +void *reserved_ptrs[3 ];/**< Reserved for future fields */ } __rte_cache_aligned;struct rte_eth_dev_sriov ;lib/librte_ethdev/rte_ethdev_version.map +4
-1@@ -241,4 +241,8 @@ EXPERIMENTAL { __rte_ethdev_trace_rx_burst; __rte_ethdev_trace_tx_burst; rte_flow_get_aged_flows; + + # added in 20.08 + rte_eth_dev_power_mgmt_disable; + rte_eth_dev_power_mgmt_enable; }; --2.17.1
Re: [dpdk-dev] [RFC 1/6] eal: add power management intrinsics
In reply to Ananyev, KonstantinQuoted 15 lines · Konstantin
Hi Anatoly,
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 5 lines
Recently ARM guys introduced new generic API
for similar (as I understand) purposes:rte_wait_until_equal_(16|32|64). Probably would make sense to unite both APIs into something common and HW transparent.
Konstantin
Hi Konstantin,
That's not really similar purpose. This is monitoring a cacheline for writes, not waiting on a specific value. The "expected" value is there as basically a hack to get around the race condition due to the fact that by the time you enter monitoring state, the write you're waiting for may have already happened.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [RFC 1/6] eal: add power management intrinsics
Quoted 22 lines · Anatoly
Quoted 15 lines · Konstantin
Hi Anatoly,
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 5 lines
Recently ARM guys introduced new generic API
for similar (as I understand) purposes:rte_wait_until_equal_(16|32|64). Probably would make sense to unite both APIs into something common and HW transparent.
Konstantin
Quoted 8 lines
Hi Konstantin,
That's not really similar purpose. This is monitoring a cacheline for writes, not waiting on a specific value. The "expected" value is there as basically a hack to get around the race condition due to the fact that by the time you enter monitoring state, the write you're waiting for may have already happened.
Rather than the "expected" value, is it not more useful for a general API to check for the existing value? Since we are awaiting writes, we may not know what new value will be written, but we do know what the value is now, and can just check that it's not been changed.
Regards,
/Bruce
Re: [dpdk-dev] [RFC 1/6] eal: add power management intrinsics
In reply to Burakov, AnatolyQuoted 22 lines
Quoted 16 lines
Hi Anatoly,
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 5 lines
Recently ARM guys introduced new generic API
for similar (as I understand) purposes:rte_wait_until_equal_(16|32|64). Probably would make sense to unite both APIs into something common and HW transparent.
Konstantin
Quoted 4 lines
Hi Konstantin,
That's not really similar purpose. This is monitoring a cacheline for writes, not waiting on a specific value.
I understand that.
Quoted 4 lines
The "expected" value is there
as basically a hack to get around the race condition due to the fact that by the time you enter monitoring state, the write you're waiting for may have already happened.
AFAIK, current rte_wait_until_equal_* does pretty much the same thing:
LDXR memaddr, $reg // an address to monitor for
if ($reg != expected_value)
SEVL // arm monitor
do {
WFE // waits for write to that memory address
LDXR memaddr, $reg
} while ($reg != expected_value);
Looks pretty similar to what rte_power_monitor() does, except you don't have a loop for checking the new value. Plus rte_power_monitor() provides extra options to the user - timestamp and power save mode to enter.
Also I don't know what is the granularity of such events on ARM, is it a cache-line or more/less.
Might be ARM people can comment/correct me here. Konstantin
Re: [dpdk-dev] [RFC 1/6] eal: add power management intrinsics
Quoted 45 lines · Konstantin
Quoted 23 lines
Quoted 17 lines
Hi Anatoly,
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 5 lines
Recently ARM guys introduced new generic API
for similar (as I understand) purposes:rte_wait_until_equal_(16|32|64). Probably would make sense to unite both APIs into something common and HW transparent.
KonstantinQuoted 4 lines
Hi Konstantin,
That's not really similar purpose. This is monitoring a cacheline for writes, not waiting on a specific value.
I understand that.
Quoted 4 lines
The "expected" value is there
as basically a hack to get around the race condition due to the fact that by the time you enter monitoring state, the write you're waiting for may have already happened.AFAIK, current rte_wait_until_equal_* does pretty much the same thing:
LDXR memaddr, $reg // an address to monitor for
if ($reg !=expected_value)
SEVL // arm monitor
do {
WFE // waits for write to that memory address
LDXR memaddr, $reg
} while ($reg !=expected_value);
Quoted 6 lines
Looks pretty similar to what
rte_power_monitor()does, except you don't have a loop for checking the new value. Plusrte_power_monitor()provides extra options to the user - timestamp and power save mode to enter.
Also I don't know what is the granularity of such events on ARM, is it a cache-line or more/less.
As I understand it, Granularity is per the cache-line. ie. Load-exclusive(LDXR) followed by WFE will wait in a low-power state until the cache line is written.
But I see UMONITOR bit different, Where _without_ other core signaling to wakeup from wait state,
it can wake on TSC expiry. I think, that's is the main primitive on this feature. Right?
WFE can also wake based on Timer stream events(kind of TSC in x86 analogy) but it has a configuration
bit that needs to allow for this scheme in userspace(EL0) or not? defined by EL1(Linux kernel).
I am planning to spend time on this after understanding the value addition of the feature/usecase[1]
[1]
http://mails.dpdk.org/archives/dev/2020-May/168888.html
Quoted 2 lines
Might be ARM people can comment/correct me here.
Konstantin
Re: [dpdk-dev] [RFC 1/6] eal: add power management intrinsics
Quoted 65 lines
Quoted 45 lines · Konstantin
Quoted 23 lines
Quoted 17 lines
Hi Anatoly,
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 5 lines
Recently ARM guys introduced new generic API
for similar (as I understand) purposes:rte_wait_until_equal_(16|32|64). Probably would make sense to unite both APIs into something common and HW transparent.
KonstantinQuoted 4 lines
Hi Konstantin,
That's not really similar purpose. This is monitoring a cacheline for writes, not waiting on a specific value.
I understand that.
Quoted 4 lines
The "expected" value is there
as basically a hack to get around the race condition due to the fact that by the time you enter monitoring state, the write you're waiting for may have already happened.AFAIK, current rte_wait_until_equal_* does pretty much the same thing:
LDXR memaddr, $reg // an address to monitor for
if ($reg !=expected_value)
SEVL // arm monitor
do {
WFE // waits for write to that memory address
LDXR memaddr, $reg
} while ($reg !=expected_value);Quoted 6 lines
Looks pretty similar to what
rte_power_monitor()does, except you don't have a loop for checking the new value. Plusrte_power_monitor()provides extra options to the user - timestamp and power save mode to enter.
Also I don't know what is the granularity of such events on ARM, is it a cache-line or more/less.As I understand it, Granularity is per the cache-line. ie. Load-exclusive(LDXR) followed by WFE will wait in a low-power state until the cache line is written.
But I see UMONITOR bit different, Where _without_ other core signaling to wakeup from wait state,
it can wake on TSC expiry. I think, that's is the main primitive on this feature. Right?
Quoted 9 lines
WFE can also wake based on Timer stream events(kind of TSC in x86 analogy) but it has a configuration
bit that needs to allow for this scheme in userspace(EL0) or not? defined by EL1(Linux kernel).
I am planning to spend time on this after understanding the value addition of the feature/usecase[1]
[1]
http://mails.dpdk.org/archives/dev/2020-May/168888.html
Ok, if there is a consensus to keep these two APIs disjoint for now - I wouldn't insist.
Konstantin
Re: [dpdk-dev] [RFC 1/6] eal: add power management intrinsics
In reply to Jerin Jacob<snip>
Quoted 56 lines
Quoted 10 lines · Konstantin
Quoted 10 lines
Quoted 10 lines
Hi Anatoly,
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more
writes are expected.
Quoted 29 lines
Quoted 11 lines
Quoted 6 lines
Recently ARM guys introduced new generic API for similar (as I understand) purposes:
rte_wait_until_equal_(16|32|64). Probably would make sense to unite both APIs into something common and HW transparent.
KonstantinHi Konstantin,
That's not really similar purpose. This is monitoring a cacheline for writes, not waiting on a specific value.
I understand that.
Quoted 4 lines
The "expected" value is there
as basically a hack to get around the race condition due to the fact that by the time you enter monitoring state, the write you're waiting for may have already happened.AFAIK, current rte_wait_until_equal_* does pretty much the same thing:
LDXR memaddr, $reg // an address to monitor for if ($reg !=
expected_value)
SEVL // arm monitor
do {
WFE // waits for write to that memory address
LDXR memaddr, $reg
} while ($reg !=expected_value);Quoted 6 lines
Looks pretty similar to what
rte_power_monitor()does, except you don't have a loop for checking the new value.
Plusrte_power_monitor()provides extra options to the user - timestamp and power save mode to enter.
Also I don't know what is the granularity of such events on ARM, is it a cache-line or more/less.
Quoted 3 lines
As I understand it, Granularity is per the cache-line.
ie. Load-exclusive(LDXR) followed by WFE will wait in a low-power state until the cache line is written.
Architecture allows for 16B to 2048B space. Typically, implementations use cache-line granularity.
Quoted 9 lines
But I see UMONITOR bit different, Where _without_ other core signaling to wakeup from wait state, it can wake on TSC expiry. I think, that's is the main primitive on this feature. Right?
WFE can also wake based on Timer stream events(kind of TSC in x86 analogy) but it has a configuration
bit that needs to allow for this scheme in userspace(EL0) or not? defined by EL1(Linux kernel).
Timer stream events are not per CPU core. They are system wide streams.
Quoted 10 lines
I am planning to spend time on this after understanding the value addition of the feature/usecase[1] [1] http://mails.dpdk.org/archives/dev/2020-
May/168888.htmlQuoted 2 lines
Might be ARM people can comment/correct me here.
Konstantin
Re: [dpdk-dev] [RFC 1/6] eal: add power management intrinsics
Quoted 69 lines · Honnappa Nagarahalli
<snip>
Quoted 56 lines
Quoted 10 lines · Konstantin
Quoted 10 lines
Quoted 10 lines
Hi Anatoly,
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more
writes are expected.
Quoted 29 lines
Quoted 11 lines
Quoted 6 lines
Recently ARM guys introduced new generic API for similar (as I understand) purposes:
rte_wait_until_equal_(16|32|64). Probably would make sense to unite both APIs into something common and HW transparent.
KonstantinHi Konstantin,
That's not really similar purpose. This is monitoring a cacheline for writes, not waiting on a specific value.
I understand that.
Quoted 4 lines
The "expected" value is there
as basically a hack to get around the race condition due to the fact that by the time you enter monitoring state, the write you're waiting for may have already happened.AFAIK, current rte_wait_until_equal_* does pretty much the same thing:
LDXR memaddr, $reg // an address to monitor for if ($reg !=
expected_value)
SEVL // arm monitor
do {
WFE // waits for write to that memory address
LDXR memaddr, $reg
} while ($reg !=expected_value);Quoted 6 lines
Looks pretty similar to what
rte_power_monitor()does, except you don't have a loop for checking the new value.
Plusrte_power_monitor()provides extra options to the user - timestamp and power save mode to enter.
Also I don't know what is the granularity of such events on ARM, is it a cache-line or more/less.Quoted 3 lines
As I understand it, Granularity is per the cache-line.
ie. Load-exclusive(LDXR) followed by WFE will wait in a low-power state until the cache line is written.Architecture allows for 16B to 2048B space. Typically, implementations use cache-line granularity.
Quoted 5 lines
But I see UMONITOR bit different, Where _without_ other core signaling to wakeup from wait state, it can wake on TSC expiry. I think, that's is the main primitive on this feature. Right?
Quoted 5 lines
Quoted 4 lines
WFE can also wake based on Timer stream events(kind of TSC in x86 analogy) but it has a configuration
bit that needs to allow for this scheme in userspace(EL0) or not? defined by EL1(Linux kernel).Timer stream events are not per CPU core. They are system wide streams.
We may not need per core support to implement this use case.
I think, currently, kernel configured to have a WFE signal on every 100us.(System-wide).
do while{} loop can check if it is passing the requested timestamp after WFE. But minimum granularity will be 100us.(i.e 100us worth of ticks)
Quoted 11 lines
Quoted 11 lines
I am planning to spend time on this after understanding the value addition of the feature/usecase[1] [1] http://mails.dpdk.org/archives/dev/2020-
May/168888.htmlQuoted 2 lines
Might be ARM people can comment/correct me here.
Konstantin
RFC v2 1/5 eal: add power management intrinsics
In reply to Anatoly BurakovAdd two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
--- .../include/generic/rte_power_intrinsics.h | 64 ++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + lib/librte_eal/x86/include/rte_cpuflags.h | 1 + .../x86/include/rte_power_intrinsics.h | 138 ++++++++++++++++++ lib/librte_eal/x86/rte_cpuflags.c | 2 + 6 files changed, 207 insertions(+) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
@@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_H_ +#define _RTE_POWER_INTRINSIC_H_ + +#include <inttypes.h> + +/** +* @file +* Advanced power management operations. +* +* This file define APIs for advanced power management, +* which are architecture-dependent. +*/ + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* @param p +* Address to monitor for changes. Must be aligned on an 8-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp); + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp); + +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
@@ -60,6 +60,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',
lib/librte_eal/x86/include/rte_cpuflags.h +1 -0
@@ -110,6 +110,7 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_RDTSCP ,/**< RDTSCP */ RTE_CPUFLAG_EM64T ,/**< EM64T */ +RTE_CPUFLAG_WAITPKG ,/**< UMINITOR/UMWAIT/TPAUSE */ /* (EAX 80000007h) EDX features */ RTE_CPUFLAG_INVTSC, /**< INVTSC */
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +138 -0
138 lines not on this page · raw message
lib/librte_eal/x86/rte_cpuflags.c +2 -0
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 )
Signature · 1 line
2.17.1
RFC v2 2/5 ethdev: add simple power management API and callback
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API is limited to 1 core 1 queue use case as there is no coordination between queues/cores in ethdev.
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.
--- config/common_base | 4 +- lib/Makefile | 1 + lib/librte_ethdev/Makefile | 2 +- lib/librte_ethdev/meson.build | 2 +- lib/librte_ethdev/rte_ethdev.c | 198 +++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev.h | 59 +++++++ lib/librte_ethdev/rte_ethdev_core.h | 43 ++++- lib/librte_ethdev/rte_ethdev_version.map | 4 + lib/meson.build | 5 +- mk/rte.app.mk | 2 +- 10 files changed, 311 insertions(+), 9 deletions(-)
config/common_base +2 -2
@@ -155,7 +155,7 @@ CONFIG_RTE_MAX_ETHPORTS=32 CONFIG_RTE_MAX_QUEUES_PER_PORT=1024 CONFIG_RTE_LIBRTE_IEEE1588=n CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16 -CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y +CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=n CONFIG_RTE_ETHDEV_PROFILE_WITH_VTUNE=n #
@@ -978,7 +978,7 @@ CONFIG_RTE_LIBRTE_ACL_DEBUG=n # # Compile librte_power # -CONFIG_RTE_LIBRTE_POWER=n +CONFIG_RTE_LIBRTE_POWER=y CONFIG_RTE_LIBRTE_POWER_DEBUG=n CONFIG_RTE_MAX_LCORE_FREQS=64
lib/Makefile +1 -0
@@ -28,6 +28,7 @@ DEPDIRS-librte_ethdev := librte_net librte_eal librte_mempool librte_ring DEPDIRS-librte_ethdev += librte_mbuf DEPDIRS-librte_ethdev += librte_kvargs DEPDIRS-librte_ethdev += librte_meter +DEPDIRS-librte_ethdev += librte_power DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
lib/librte_ethdev/Makefile +1 -1
@@ -11,7 +11,7 @@ LIB = librte_ethdev.a CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf -lrte_kvargs -lrte_meter -lrte_telemetry +LDLIBS += -lrte_mbuf -lrte_kvargs -lrte_meter -lrte_telemetry -lrte_power EXPORT_MAP := rte_ethdev_version.map
lib/librte_ethdev/meson.build +1 -1
@@ -27,4 +27,4 @@ headers = files('rte_ethdev.h', 'rte_tm.h', 'rte_tm_driver.h') -deps += ['net', 'kvargs', 'meter', 'telemetry'] +deps += ['net', 'kvargs', 'meter', 'telemetry', 'power']
lib/librte_ethdev/rte_ethdev.c +198 -0
222 lines not on this page · raw message
lib/librte_ethdev/rte_ethdev.h +59 -0
95 lines not on this page · raw message
lib/librte_ethdev/rte_ethdev_core.h +41 -2
67 lines not on this page · raw message
lib/librte_ethdev/rte_ethdev_version.map +4 -0
@@ -241,6 +241,10 @@ EXPERIMENTAL { __rte_ethdev_trace_rx_burst; __rte_ethdev_trace_tx_burst; rte_flow_get_aged_flows; + + # added in 20.08 + rte_eth_dev_power_mgmt_disable; + rte_eth_dev_power_mgmt_enable; }; INTERNAL {
lib/meson.build +3 -2
@@ -14,17 +14,18 @@ libraries = [ 'eal', # everything depends on eal 'ring', 'rcu', # rcu depends on ring + 'timer', # eventdev depends on this + 'power', # eventdev depends on this 'mempool', 'mbuf', 'net', 'meter', 'ethdev', 'pci', # core 'cmdline', 'metrics', # bitrate/latency stats depends on this 'hash', # efd depends on this - 'timer', # eventdev depends on this 'acl', 'bbdev', 'bitratestats', 'cfgfile', 'compressdev', 'cryptodev', 'distributor', 'efd', 'eventdev', 'gro', 'gso', 'ip_frag', 'jobstats', 'kni', 'latencystats', 'lpm', 'member', - 'power', 'pdump', 'rawdev', 'regexdev', + 'pdump', 'rawdev', 'regexdev', 'rib', 'reorder', 'sched', 'security', 'stack', 'vhost', # ipsec lib depends on net, crypto and security 'ipsec',
mk/rte.app.mk +1 -1
@@ -58,7 +58,6 @@ endif _LDLIBS-$(CONFIG_RTE_LIBRTE_METRICS) += --no-whole-archive _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE) += -lrte_bitratestats _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS) += -lrte_latencystats -_LDLIBS-$(CONFIG_RTE_LIBRTE_POWER) += -lrte_power _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD) += -lrte_efd _LDLIBS-$(CONFIG_RTE_LIBRTE_BPF) += -lrte_bpf
@@ -80,6 +79,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS) += -lrte_kvargs _LDLIBS-y += -lrte_telemetry _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF) += -lrte_mbuf _LDLIBS-$(CONFIG_RTE_LIBRTE_NET) += -lrte_net +_LDLIBS-$(CONFIG_RTE_LIBRTE_POWER) += -lrte_power _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER) += -lrte_ethdev _LDLIBS-$(CONFIG_RTE_LIBRTE_BBDEV) += -lrte_bbdev _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += -lrte_cryptodev
Signature · 1 line
2.17.1
RFC v2 3/5 net/ixgbe: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 ++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 ++ 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
@@ -592,6 +592,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = { .udp_tunnel_port_del = ixgbe_dev_udp_tunnel_port_del, .tm_ops_get = ixgbe_tm_ops_get, .tx_done_cleanup = ixgbe_dev_tx_done_cleanup, + .next_rx_desc = ixgbe_next_rx_desc, };/*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
@@ -1366,6 +1366,28 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +int ixgbe_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ixgbe_adv_rx_desc *rxdp; +struct ixgbe_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.upper.status_error; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + *mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + +return 0 ; +} +/* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */ static inline uint32_t ixgbe_rxd_pkt_info_to_pkt_type (uint32_t pkt_info,uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_queue_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_port_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_tx_queue_offloads (struct rte_eth_dev *dev); +int ixgbe_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
RFC v2 4/5 net/i40e: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/i40e/i40e_ethdev.c | 1 + drivers/net/i40e/i40e_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/i40e/i40e_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
@@ -515,6 +515,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = { .mtu_set = i40e_dev_mtu_set, .tm_ops_get = i40e_tm_ops_get, .tx_done_cleanup = i40e_tx_done_cleanup, + .next_rx_desc = i40e_next_rx_desc, };/* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
@@ -71,6 +71,29 @@#define I40E_TX_OFFLOAD_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK) +int +i40e_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +struct i40e_rx_queue *rxq = rx_queue; +volatile union i40e_rx_desc *rxdp; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.qword1.status_error_len; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + *mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + +return 0 ; +} +static inline void i40e_rxd_to_vlan_tci (struct rte_mbuf *mb,volatile union i40e_rx_desc *rxdp) {
drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);uint16_t i40e_xmit_pkts_vec_avx2 (void *tx_queue,struct rte_mbuf **tx_pkts,uint16_t nb_pkts); +int i40e_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *value);/* For each value it means, datasheet of hardware can tell more details *
Signature · 1 line
2.17.1
RFC v2 5/5 net/ice: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/ice/ice_ethdev.c | 1 + drivers/net/ice/ice_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/ice/ice_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
@@ -212,6 +212,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .udp_tunnel_port_add = ice_dev_udp_tunnel_port_add, .udp_tunnel_port_del = ice_dev_udp_tunnel_port_del, .tx_done_cleanup = ice_tx_done_cleanup, + .next_rx_desc = ice_next_rx_desc, };/* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
@@ -24,6 +24,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_mask;uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask; +int ice_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ice_rx_flex_desc *rxdp; +struct ice_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.status_error0; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + *mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + +return 0 ; +} + +static inline uint64_t ice_rxdid_to_proto_xtr_ol_flag (uint8_t rxdid) {
drivers/net/ice/ice_rxtx.h +2 -0
@@ -202,5 +202,7 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);int ice_fdir_programming (struct ice_pf *pf,struct ice_fltr_desc *fdir_desc);int ice_tx_done_cleanup (void *txq,uint32_t free_cnt); +int ice_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _ICE_RXTX_H_ */
Signature · 1 line
2.17.1
Re: [dpdk-dev] [RFC v2 1/5] eal: add power management intrinsics
In reply to Liang MaQuoted 15 lines · Liang Ma
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
<snip>
lib/librte_eal/x86/include/rte_cpuflags.h enum rte_cpu_flag_t { · line 113
Quoted 9 lines
lib/librte_eal/x86/include/rte_cpuflags.h +1
-0@@ -110,6 +110,7 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_RDTSCP ,/**< RDTSCP */ RTE_CPUFLAG_EM64T ,/**< EM64T */ + RTE_CPUFLAG_WAITPKG, /**< UMINITOR/UMWAIT/TPAUSE */
need re-work the order to avoid breaking ABI
lib/librte_eal/x86/include/rte_cpuflags.h enum rte_cpu_flag_t { · line 116
Quoted 3 lines
lib/librte_eal/x86/include/rte_cpuflags.h +0
-0/* (EAX 80000007h) EDX features */ RTE_CPUFLAG_INVTSC, /**< INVTSC */
</snip>
Quoted 3 lines
Signature · 1 line
2.17.1
Re: [dpdk-dev] [RFC v2 2/5] ethdev: add simple power management API and callback
In reply to Liang MaOn 11 Aug 11:27, Liang Ma wrote:
<snip>
Quoted 26 lines
lib/librte_ethdev/rte_ethdev.c +26
-0+static uint16_t +rte_ethdev_pmgmt_umait (uint16_t port_id,uint16_t qidx, + struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ + +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +if (dev->pwr_mgmt_state ==RTE_ETH_DEV_POWER_MGMT_ENABLED ) { +if (unlikely (nb_rx ==0 )) { + dev->empty_poll_stats[qidx].num++; +if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) { +volatile void *target_addr; +uint64_t expected, mask; +uint16_t ret; + +/* +* get address of next descriptor in the RX +* ring for this queue, as well as expected +* value and a mask. +*/ + ret = (*dev->dev_ops->next_rx_desc) + (dev->data->rx_queues[qidx], + &target_addr, &expected, &mask); +if (ret ==0 )
lib/librte_ethdev/rte_ethdev.c enum { · line 226
Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10
-0+/* -1ULL is maximum value for TSC */ +rte_power_monitor (target_addr, + expected, mask, +0 ,-1ULL ); + } + }else + dev->empty_poll_stats[qidx].num =0 ; + } + +return 0 ;
should return nb_rx here. that's fixed in v3.
Quoted 18 lines
lib/librte_ethdev/rte_ethdev.c +18
-0+} + +static uint16_t +rte_ethdev_pmgmt_pause (uint16_t port_id,uint16_t qidx, + struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +int i; + +if (dev->pwr_mgmt_state ==RTE_ETH_DEV_POWER_MGMT_ENABLED ) { +if (unlikely (nb_rx ==0 )) { + + dev->empty_poll_stats[qidx].num++; + +if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) {
lib/librte_ethdev/rte_ethdev.c enum { · line 254
Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10
-0+ +for (i =0 ; i <RTE_ETH_PAUSE_NUM ; i++) +rte_pause (); + + } + }else + dev->empty_poll_stats[qidx].num =0 ; + } + +return 0 ;
should return nb_rx here. that's fixed in v3.
Quoted 17 lines
lib/librte_ethdev/rte_ethdev.c +17
-0+} + +static uint16_t +rte_ethdev_pmgmt_scalefreq (uint16_t port_id,uint16_t qidx, + struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +if (dev->pwr_mgmt_state ==RTE_ETH_DEV_POWER_MGMT_ENABLED ) { +if (unlikely (nb_rx ==0 )) { + dev->empty_poll_stats[qidx].num++; +if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) { + +/*scale down freq */ +rte_power_freq_min (rte_lcore_id ());
lib/librte_ethdev/rte_ethdev.c enum { · line 281
Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10
-0+ + } + }else { + dev->empty_poll_stats[qidx].num =0 ; +/* scal up freq */ +rte_power_freq_max (rte_lcore_id ()); + } + } + +return 0 ;
should return nb_rx here. that's fixed in v3.
Review
Quoted 2 lines
(quoted diff) +2
-0+} +
</snip>
--
Quoted 2 lines
2.17.1
RFC PATCH v3 1/6 eal: add power management intrinsics
In reply to Liang MaAdd two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
--- .../include/generic/rte_power_intrinsics.h | 64 ++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + lib/librte_eal/x86/include/rte_cpuflags.h | 2 + .../x86/include/rte_power_intrinsics.h | 143 ++++++++++++++++++ lib/librte_eal/x86/rte_cpuflags.c | 2 + 6 files changed, 213 insertions(+) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
@@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_H_ +#define _RTE_POWER_INTRINSIC_H_ + +#include <inttypes.h> + +/** +* @file +* Advanced power management operations. +* +* This file define APIs for advanced power management, +* which are architecture-dependent. +*/ + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp); + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp); + +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
@@ -60,6 +60,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_MOVDIR64B ,/**< Direct Store Instructions 64B */ RTE_CPUFLAG_AVX512VP2INTERSECT ,/**< AVX512 Two Register Intersection */ +/**< UMWAIT/TPAUSE Instructions */ +RTE_CPUFLAG_WAITPKG ,/**< UMINITOR/UMWAIT/TPAUSE */ /* The last item */ RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */ };
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +143 -0
143 lines not on this page · raw message
lib/librte_eal/x86/rte_cpuflags.c +2 -0
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 )
Signature · 1 line
2.17.1
RFC PATCH v3 2/6 ethdev: add simple power management API
Add a simple API allow ethdev get the last available queue descriptor address from PMD. Also include internal structure update.
--- lib/librte_ethdev/rte_ethdev.h | 22 ++++++++++++++ lib/librte_ethdev/rte_ethdev_core.h | 46 +++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-)
lib/librte_ethdev/rte_ethdev.h +22 -0
@@ -157,6 +157,7 @@ extern "C" {#include <rte_common.h> #include <rte_config.h> #include <rte_ether.h> +#include <rte_power_intrinsics.h> #include "rte_ethdev_trace_fp.h" #include "rte_dev_info.h"
@@ -775,6 +776,7 @@ rte_eth_rss_hf_refine(uint64_t rss_hf)/** Maximum nb. of vlan per mirror rule */ #define ETH_MIRROR_MAX_VLANS 64 +#define ETH_EMPTYPOLL_MAX 512/**< Empty poll number threshlold */ #define ETH_MIRROR_VIRTUAL_POOL_UP 0x01/**< Virtual Pool uplink Mirroring. */ #define ETH_MIRROR_UPLINK_PORT 0x02/**< Uplink Port Mirroring. */ #define ETH_MIRROR_DOWNLINK_PORT 0x04/**< Downlink Port Mirroring. */
@@ -1602,6 +1604,26 @@ enum rte_eth_dev_state { RTE_ETH_DEV_REMOVED, }; +#define RTE_ETH_PAUSE_NUM 64/* How many times to pause */ +/** +* Possible power management states of an ethdev port. +*/ +enum rte_eth_dev_power_mgmt_state { +/** Device power management is disabled. */ +RTE_ETH_DEV_POWER_MGMT_DISABLED =0 , +/** Device power management is enabled. */ +RTE_ETH_DEV_POWER_MGMT_ENABLED , +}; + +enum rte_eth_dev_power_mgmt_cb_mode { +/** WAIT callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_WAIT =1 , +/** PAUSE callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_PAUSE , +/** Freq Scaling callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_SCALE , +}; +struct rte_eth_dev_sriov {uint8_t active;/**< SRIOV is active with 16, 32 or 64 pools */ uint8_t nb_q_per_pool;/**< rx queue number per pool */
lib/librte_ethdev/rte_ethdev_core.h +44 -2
70 lines not on this page · raw message
Signature · 1 line
2.17.1
RFC PATCH v3 3/6 power: add simple power management API and callback
In reply to Liang MaAdd a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API is limited to 1 core 1 port 1 queue use case as there is no coordination between queues/cores in ethdev. 1 port map to multiple core will be supported in next version.
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.
--- lib/librte_power/meson.build | 3 +- lib/librte_power/rte_power.h | 38 +++++ lib/librte_power/rte_power_pmd_mgmt.c | 184 +++++++++++++++++++++++++ lib/librte_power/rte_power_version.map | 4 + 4 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
lib/librte_power/meson.build +2 -1
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c', 'power_kvm_vm.c', 'guest_channel.c', 'rte_power_empty_poll.c', 'power_pstate_cpufreq.c', + 'rte_power_pmd_mgmt.c', 'power_common.c') headers = files('rte_power.h','rte_power_empty_poll.h') -deps += ['timer'] +deps += ['timer' ,'ethdev']
lib/librte_power/rte_power.h +38 -0
@@ -14,6 +14,7 @@#include <rte_byteorder.h> #include <rte_log.h> #include <rte_string_fns.h> +#include <rte_ethdev.h> #ifdef __cplusplusextern "C" {
@@ -97,6 +98,43 @@ int rte_power_init(unsigned int lcore_id);*/ int rte_power_exit (unsigned int lcore_id); +/** +* @warning +* @b EXPERIMENTAL: this API may change, or be removed, without prior notice +* +* Enable device power management. +* @param lcore_id +* lcore id. +* @param port_id +* The port identifier of the Ethernet device. +* @param mode +* The power management callback function mode. +* @return +* 0 on success +* <0 on error +*/ +__rte_experimental +int rte_power_pmd_mgmt_enable(unsigned int lcore_id, +uint16_t port_id, +enum rte_eth_dev_power_mgmt_cb_mode mode); + +/** +* @warning +* @b EXPERIMENTAL: this API may change, or be removed, without prior notice +* +* Disable device power management. +* @param lcore_id +* lcore id. +* @param port_id +* The port identifier of the Ethernet device. +* +* @return +* 0 on success +* <0 on error +*/ +__rte_experimental +int rte_power_pmd_mgmt_disable(unsigned int lcore_id, uint16_t port_id); +/** * Get the available frequencies of a specific lcore. * Function pointer definition. Review each environments
lib/librte_power/rte_power_pmd_mgmt.c new file +184 -0
184 lines not on this page · raw message
lib/librte_power/rte_power_version.map +4 -0
@@ -34,4 +34,8 @@ EXPERIMENTAL { rte_power_guest_channel_receive_msg; rte_power_poll_stat_fetch; rte_power_poll_stat_update; + # added in 20.08 + rte_power_pmd_mgmt_disable; + rte_power_pmd_mgmt_enable; + };
Signature · 1 line
2.17.1
RFC PATCH v3 5/6 net/i40e: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/i40e/i40e_ethdev.c | 1 + drivers/net/i40e/i40e_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/i40e/i40e_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
@@ -517,6 +517,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = { .mtu_set = i40e_dev_mtu_set, .tm_ops_get = i40e_tm_ops_get, .tx_done_cleanup = i40e_tx_done_cleanup, + .next_rx_desc = i40e_next_rx_desc, };/* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
@@ -71,6 +71,29 @@#define I40E_TX_OFFLOAD_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK) +int +i40e_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +struct i40e_rx_queue *rxq = rx_queue; +volatile union i40e_rx_desc *rxdp; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.qword1.status_error_len; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + *mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + +return 0 ; +} +static inline void i40e_rxd_to_vlan_tci (struct rte_mbuf *mb,volatile union i40e_rx_desc *rxdp) {
drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);uint16_t i40e_xmit_pkts_vec_avx2 (void *tx_queue,struct rte_mbuf **tx_pkts,uint16_t nb_pkts); +int i40e_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *value);/* For each value it means, datasheet of hardware can tell more details *
Signature · 1 line
2.17.1
RFC PATCH v3 6/6 net/ice: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/ice/ice_ethdev.c | 1 + drivers/net/ice/ice_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/ice/ice_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
@@ -212,6 +212,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .udp_tunnel_port_add = ice_dev_udp_tunnel_port_add, .udp_tunnel_port_del = ice_dev_udp_tunnel_port_del, .tx_done_cleanup = ice_tx_done_cleanup, + .next_rx_desc = ice_next_rx_desc, };/* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
@@ -24,6 +24,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_mask;uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask; +int ice_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ice_rx_flex_desc *rxdp; +struct ice_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.status_error0; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + *mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + +return 0 ; +} + +static inline uint64_t ice_rxdid_to_proto_xtr_ol_flag (uint8_t rxdid) {
drivers/net/ice/ice_rxtx.h +2 -0
@@ -202,5 +202,7 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);int ice_fdir_programming (struct ice_pf *pf,struct ice_fltr_desc *fdir_desc);int ice_tx_done_cleanup (void *txq,uint32_t free_cnt); +int ice_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _ICE_RXTX_H_ */
Signature · 1 line
2.17.1
RFC PATCH v3 4/6 net/ixgbe: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 ++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 ++ 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
@@ -592,6 +592,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = { .udp_tunnel_port_del = ixgbe_dev_udp_tunnel_port_del, .tm_ops_get = ixgbe_tm_ops_get, .tx_done_cleanup = ixgbe_dev_tx_done_cleanup, + .next_rx_desc = ixgbe_next_rx_desc, };/*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
@@ -1366,6 +1366,28 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +int ixgbe_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ixgbe_adv_rx_desc *rxdp; +struct ixgbe_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.upper.status_error; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + *mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + +return 0 ; +} +/* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */ static inline uint32_t ixgbe_rxd_pkt_info_to_pkt_type (uint32_t pkt_info,uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_queue_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_port_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_tx_queue_offloads (struct rte_eth_dev *dev); +int ixgbe_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
PATCH v3 1/6 eal: add power management intrinsics
In reply to Liang MaAdd two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
--- .../include/generic/rte_power_intrinsics.h | 64 ++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + lib/librte_eal/x86/include/rte_cpuflags.h | 2 + .../x86/include/rte_power_intrinsics.h | 143 ++++++++++++++++++ lib/librte_eal/x86/rte_cpuflags.c | 2 + 6 files changed, 213 insertions(+) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
@@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_H_ +#define _RTE_POWER_INTRINSIC_H_ + +#include <inttypes.h> + +/** +* @file +* Advanced power management operations. +* +* This file define APIs for advanced power management, +* which are architecture-dependent. +*/ + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp); + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp); + +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
@@ -60,6 +60,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_MOVDIR64B ,/**< Direct Store Instructions 64B */ RTE_CPUFLAG_AVX512VP2INTERSECT ,/**< AVX512 Two Register Intersection */ +/**< UMWAIT/TPAUSE Instructions */ +RTE_CPUFLAG_WAITPKG ,/**< UMINITOR/UMWAIT/TPAUSE */ /* The last item */ RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */ };
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +143 -0
143 lines not on this page · raw message
lib/librte_eal/x86/rte_cpuflags.c +2 -0
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 )
Signature · 1 line
2.17.1
PATCH v3 2/6 ethdev: add simple power management API
Add a simple API allow ethdev get the last available queue descriptor address from PMD. Also include internal structure update.
--- lib/librte_ethdev/rte_ethdev.h | 22 ++++++++++++++ lib/librte_ethdev/rte_ethdev_core.h | 46 +++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-)
lib/librte_ethdev/rte_ethdev.h +22 -0
@@ -157,6 +157,7 @@ extern "C" {#include <rte_common.h> #include <rte_config.h> #include <rte_ether.h> +#include <rte_power_intrinsics.h> #include "rte_ethdev_trace_fp.h" #include "rte_dev_info.h"
@@ -775,6 +776,7 @@ rte_eth_rss_hf_refine(uint64_t rss_hf)/** Maximum nb. of vlan per mirror rule */ #define ETH_MIRROR_MAX_VLANS 64 +#define ETH_EMPTYPOLL_MAX 512/**< Empty poll number threshlold */ #define ETH_MIRROR_VIRTUAL_POOL_UP 0x01/**< Virtual Pool uplink Mirroring. */ #define ETH_MIRROR_UPLINK_PORT 0x02/**< Uplink Port Mirroring. */ #define ETH_MIRROR_DOWNLINK_PORT 0x04/**< Downlink Port Mirroring. */
@@ -1602,6 +1604,26 @@ enum rte_eth_dev_state { RTE_ETH_DEV_REMOVED, }; +#define RTE_ETH_PAUSE_NUM 64/* How many times to pause */ +/** +* Possible power management states of an ethdev port. +*/ +enum rte_eth_dev_power_mgmt_state { +/** Device power management is disabled. */ +RTE_ETH_DEV_POWER_MGMT_DISABLED =0 , +/** Device power management is enabled. */ +RTE_ETH_DEV_POWER_MGMT_ENABLED , +}; + +enum rte_eth_dev_power_mgmt_cb_mode { +/** WAIT callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_WAIT =1 , +/** PAUSE callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_PAUSE , +/** Freq Scaling callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_SCALE , +}; +struct rte_eth_dev_sriov {uint8_t active;/**< SRIOV is active with 16, 32 or 64 pools */ uint8_t nb_q_per_pool;/**< rx queue number per pool */
lib/librte_ethdev/rte_ethdev_core.h +44 -2
70 lines not on this page · raw message
Signature · 1 line
2.17.1
PATCH v3 3/6 power: add simple power management API and callback
In reply to Liang MaAdd a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API is limited to 1 core 1 port 1 queue use case as there is no coordination between queues/cores in ethdev. 1 port map to multiple core will be supported in next version.
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.
--- lib/librte_power/meson.build | 3 +- lib/librte_power/rte_power.h | 38 +++++ lib/librte_power/rte_power_pmd_mgmt.c | 184 +++++++++++++++++++++++++ lib/librte_power/rte_power_version.map | 4 + 4 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
lib/librte_power/meson.build +2 -1
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c', 'power_kvm_vm.c', 'guest_channel.c', 'rte_power_empty_poll.c', 'power_pstate_cpufreq.c', + 'rte_power_pmd_mgmt.c', 'power_common.c') headers = files('rte_power.h','rte_power_empty_poll.h') -deps += ['timer'] +deps += ['timer' ,'ethdev']
lib/librte_power/rte_power.h +38 -0
@@ -14,6 +14,7 @@#include <rte_byteorder.h> #include <rte_log.h> #include <rte_string_fns.h> +#include <rte_ethdev.h> #ifdef __cplusplusextern "C" {
@@ -97,6 +98,43 @@ int rte_power_init(unsigned int lcore_id);*/ int rte_power_exit (unsigned int lcore_id); +/** +* @warning +* @b EXPERIMENTAL: this API may change, or be removed, without prior notice +* +* Enable device power management. +* @param lcore_id +* lcore id. +* @param port_id +* The port identifier of the Ethernet device. +* @param mode +* The power management callback function mode. +* @return +* 0 on success +* <0 on error +*/ +__rte_experimental +int rte_power_pmd_mgmt_enable(unsigned int lcore_id, +uint16_t port_id, +enum rte_eth_dev_power_mgmt_cb_mode mode); + +/** +* @warning +* @b EXPERIMENTAL: this API may change, or be removed, without prior notice +* +* Disable device power management. +* @param lcore_id +* lcore id. +* @param port_id +* The port identifier of the Ethernet device. +* +* @return +* 0 on success +* <0 on error +*/ +__rte_experimental +int rte_power_pmd_mgmt_disable(unsigned int lcore_id, uint16_t port_id); +/** * Get the available frequencies of a specific lcore. * Function pointer definition. Review each environments
lib/librte_power/rte_power_pmd_mgmt.c new file +184 -0
184 lines not on this page · raw message
lib/librte_power/rte_power_version.map +4 -0
@@ -34,4 +34,8 @@ EXPERIMENTAL { rte_power_guest_channel_receive_msg; rte_power_poll_stat_fetch; rte_power_poll_stat_update; + # added in 20.08 + rte_power_pmd_mgmt_disable; + rte_power_pmd_mgmt_enable; + };
Signature · 1 line
2.17.1
PATCH v3 4/6 net/ixgbe: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 ++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 ++ 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
@@ -592,6 +592,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = { .udp_tunnel_port_del = ixgbe_dev_udp_tunnel_port_del, .tm_ops_get = ixgbe_tm_ops_get, .tx_done_cleanup = ixgbe_dev_tx_done_cleanup, + .next_rx_desc = ixgbe_next_rx_desc, };/*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
@@ -1366,6 +1366,28 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +int ixgbe_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ixgbe_adv_rx_desc *rxdp; +struct ixgbe_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.upper.status_error; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + *mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + +return 0 ; +} +/* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */ static inline uint32_t ixgbe_rxd_pkt_info_to_pkt_type (uint32_t pkt_info,uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_queue_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_port_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_tx_queue_offloads (struct rte_eth_dev *dev); +int ixgbe_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
PATCH v3 5/6 net/i40e: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/i40e/i40e_ethdev.c | 1 + drivers/net/i40e/i40e_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/i40e/i40e_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
@@ -517,6 +517,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = { .mtu_set = i40e_dev_mtu_set, .tm_ops_get = i40e_tm_ops_get, .tx_done_cleanup = i40e_tx_done_cleanup, + .next_rx_desc = i40e_next_rx_desc, };/* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
@@ -71,6 +71,29 @@#define I40E_TX_OFFLOAD_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK) +int +i40e_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +struct i40e_rx_queue *rxq = rx_queue; +volatile union i40e_rx_desc *rxdp; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.qword1.status_error_len; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + *mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + +return 0 ; +} +static inline void i40e_rxd_to_vlan_tci (struct rte_mbuf *mb,volatile union i40e_rx_desc *rxdp) {
drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);uint16_t i40e_xmit_pkts_vec_avx2 (void *tx_queue,struct rte_mbuf **tx_pkts,uint16_t nb_pkts); +int i40e_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *value);/* For each value it means, datasheet of hardware can tell more details *
Signature · 1 line
2.17.1
PATCH v3 6/6 net/ice: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.
--- drivers/net/ice/ice_ethdev.c | 1 + drivers/net/ice/ice_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/ice/ice_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
@@ -212,6 +212,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .udp_tunnel_port_add = ice_dev_udp_tunnel_port_add, .udp_tunnel_port_del = ice_dev_udp_tunnel_port_del, .tx_done_cleanup = ice_tx_done_cleanup, + .next_rx_desc = ice_next_rx_desc, };/* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
@@ -24,6 +24,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_mask;uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask; +int ice_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ice_rx_flex_desc *rxdp; +struct ice_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.status_error0; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + *mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + +return 0 ; +} + +static inline uint64_t ice_rxdid_to_proto_xtr_ol_flag (uint8_t rxdid) {
drivers/net/ice/ice_rxtx.h +2 -0
@@ -202,5 +202,7 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);int ice_fdir_programming (struct ice_pf *pf,struct ice_fltr_desc *fdir_desc);int ice_tx_done_cleanup (void *txq,uint32_t free_cnt); +int ice_next_rx_desc (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _ICE_RXTX_H_ */
Signature · 1 line
2.17.1
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Liang Malib/librte_eal/include/generic/rte_power_intrinsics.h line 46
Quoted 7 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:
+ *
+ * @return
+ * Architecture-dependent return value.
+ */lib/librte_eal/include/generic/rte_power_intrinsics.h new file +3
-0+static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp);
Since this is generic code, and you are defining the function. You should have it return -ENOTSUPPORTED or -EINVAL.
Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback
In reply to Liang MaQuoted 9 lines · On Fri, 4 Sep 2020 11:18:57 +0100 Liang Ma <[email protected]> wrote:
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API is limited to 1 core 1 port 1 queue use case as there is no coordination between queues/cores in ethdev. 1 port map to multiple core will be supported in next version.
The common way to express is this is:
This API is not thread-safe and not preempt-safe.
There is also no mechanism for a single thread to wait on multiple queues.
Quoted 3 lines
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
nit coexist is one word
Quoted 8 lines
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
Quoted 5 lines
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.
Wording here is a problem, and "releaf" should be "relief"? Rewording into active voice grammar would be easier.
Use Pause instruction to allow processor to go into deeper C state when busy polling.
Quoted 4 lines
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.
Re: [dpdk-dev] [PATCH v3 2/6] ethdev: add simple power management API
In reply to Liang MaQuoted 1 line · On Fri, 4 Sep 2020 11:18:56 +0100 Liang Ma <[email protected]> wrote:
+#define
ETH_EMPTYPOLL_MAX512 /**< Empty poll number threshlold */
Spelling here.
Also, shouldn't this be a per-device (or per-queue) configuration value.
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Liang MaQuoted 12 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 2 lines
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>
This looks like a useful feature but needs more documentation and example. It would make sense to put an example in l3fwd-power.
Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback
In reply to Liang MaQuoted 130 lines
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API is limited to 1 core 1 port 1 queue use case as there is no coordination between queues/cores in ethdev. 1 port map to multiple core will be supported in next version.
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_power/meson.build | 3 +- lib/librte_power/rte_power.h | 38 +++++ lib/librte_power/rte_power_pmd_mgmt.c | 184 +++++++++++++++++++++++++ lib/librte_power/rte_power_version.map | 4 + 4 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 lib/librte_power/rte_power_pmd_mgmt.clib/librte_power/meson.build +2
-1@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c', 'power_kvm_vm.c', 'guest_channel.c', 'rte_power_empty_poll.c', 'power_pstate_cpufreq.c', + 'rte_power_pmd_mgmt.c', 'power_common.c') headers = files('rte_power.h','rte_power_empty_poll.h') -deps += ['timer'] +deps += ['timer' ,'ethdev']lib/librte_power/rte_power.h +38
-0@@ -14,6 +14,7 @@#include <rte_byteorder.h> #include <rte_log.h> #include <rte_string_fns.h> +#include <rte_ethdev.h> #ifdef __cplusplusextern "C" {@@ -97,6 +98,43 @@ int rte_power_init(unsigned int lcore_id);*/ int rte_power_exit (unsigned int lcore_id); +/** +* @warning +* @b EXPERIMENTAL: this API may change, or be removed, without prior notice +* +* Enable device power management. +* @param lcore_id +* lcore id. +* @param port_id +* The port identifier of the Ethernet device. +* @param mode +* The power management callback function mode. +* @return +* 0 on success +* <0 on error +*/ +__rte_experimental +int rte_power_pmd_mgmt_enable(unsigned int lcore_id, +uint16_t port_id, +enum rte_eth_dev_power_mgmt_cb_mode mode); + +/** +* @warning +* @b EXPERIMENTAL: this API may change, or be removed, without prior notice +* +* Disable device power management. +* @param lcore_id +* lcore id. +* @param port_id +* The port identifier of the Ethernet device. +* +* @return +* 0 on success +* <0 on error +*/ +__rte_experimental +int rte_power_pmd_mgmt_disable(unsigned int lcore_id, uint16_t port_id); +/** * Get the available frequencies of a specific lcore. * Function pointer definition. Review each environments lib/librte_power/rte_power_pmd_mgmt.c new file +14
-0@@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2010-2020 Intel Corporation +*/ + +#include <rte_lcore.h> +#include <rte_cycles.h> +#include <rte_atomic.h> +#include <rte_malloc.h> +#include <rte_ethdev.h> + +#include "rte_power.h" + + +
lib/librte_power/rte_power_pmd_mgmt.c line 24
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+static uint16_t +rte_power_mgmt_umwait (uint16_t port_id,uint16_t qidx, + struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ + +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +if (unlikely (nb_rx ==0 )) { + dev->empty_poll_stats[qidx].num++;
I believe there are two fundamental issues with that approach:
1. You put metadata specific lib (power) callbacks into rte_eth_dev struct.
2. These callbacks do access rte_eth_devices[] directly.
That doesn't look right to me - rte_eth_dev structure supposed to be treated as internal one librt_ether and underlying drivers and should be accessed directly by outer code.
If these callbacks need some extra metadata, then it is responsibility
of power library to allocate/manage these metadata.
You can pass pointer to this metadata via last parameter for rte_eth_add_rx_callback().
Quoted 91 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +91
-0+if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) { +volatile void *target_addr; +uint64_t expected, mask; +uint16_t ret; + +/* +* get address of next descriptor in the RX +* ring for this queue, as well as expected +* value and a mask. +*/ + ret = (*dev->dev_ops->next_rx_desc) + (dev->data->rx_queues[qidx], + &target_addr, &expected, &mask); +if (ret ==0 ) +/* -1ULL is maximum value for TSC */ +rte_power_monitor (target_addr, + expected, mask, +0 ,-1ULL ); + } + }else + dev->empty_poll_stats[qidx].num =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_pause (uint16_t port_id,uint16_t qidx, + struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +int i; + +if (unlikely (nb_rx ==0 )) { + + dev->empty_poll_stats[qidx].num++; + +if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) { + +for (i =0 ; i <RTE_ETH_PAUSE_NUM ; i++) +rte_pause (); + + } + }else + dev->empty_poll_stats[qidx].num =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_scalefreq (uint16_t port_id,uint16_t qidx, + struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +if (unlikely (nb_rx ==0 )) { + dev->empty_poll_stats[qidx].num++; +if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) { + +/*scale down freq */ +rte_power_freq_min (rte_lcore_id ()); + + } + }else { + dev->empty_poll_stats[qidx].num =0 ; +/* scal up freq */ +rte_power_freq_max (rte_lcore_id ()); + } + +return nb_rx; +} + +int +rte_power_pmd_mgmt_enable (unsigned int lcore_id, +uint16_t port_id, +enum rte_eth_dev_power_mgmt_cb_mode mode) +{ +struct rte_eth_dev *dev; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); + dev = &rte_eth_devices[port_id]; + +if (dev->pwr_mgmt_state ==RTE_ETH_DEV_POWER_MGMT_ENABLED ) +return -EINVAL ; +/* allocate memory for empty poll stats */ + dev->empty_poll_stats = rte_malloc_socket(NULL,
lib/librte_power/rte_power_pmd_mgmt.c line 125
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+sizeof (struct rte_eth_ep_stat ) + *RTE_MAX_QUEUES_PER_PORT , + 0, dev->data->numa_node); +if (dev->empty_poll_stats ==NULL ) +return -ENOMEM ; + +switch (mode) { +case RTE_ETH_DEV_POWER_MGMT_CB_WAIT : +if (!rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) +return -ENOTSUP ;
Here and in other places: in case of error return you don't' free your empty_poll_stats.
lib/librte_power/rte_power_pmd_mgmt.c line 126
Quoted 1 line
lib/librte_power/rte_power_pmd_mgmt.c new file +1
-0+ dev->cur_pwr_cb = rte_eth_add_rx_callback(port_id, 0,
Why zero for queue number, why not to pass queue_id as a parameter for that function?
lib/librte_power/rte_power_pmd_mgmt.c line 127
Quoted 1 line
lib/librte_power/rte_power_pmd_mgmt.c new file +1
-0+ rte_power_mgmt_umwait, NULL);
As I said above, instead of NULL - could be pointer to metadata struct.
Quoted 25 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +25
-0+break ; +case RTE_ETH_DEV_POWER_MGMT_CB_SCALE : +/* init scale freq */ +if (rte_power_init (lcore_id)) +return -EINVAL ; + dev->cur_pwr_cb =rte_eth_add_rx_callback (port_id,0 , + rte_power_mgmt_scalefreq,NULL ); +break ; +case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE : + dev->cur_pwr_cb =rte_eth_add_rx_callback (port_id,0 , + rte_power_mgmt_pause,NULL ); +break ; + } + + dev->cb_mode = mode; + dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_ENABLED ; +return 0 ; +} + +int +rte_power_pmd_mgmt_disable (unsigned int lcore_id, +uint16_t port_id) +{ +struct rte_eth_dev *dev; +
lib/librte_power/rte_power_pmd_mgmt.c line 162
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); + dev = &rte_eth_devices[port_id]; + +/*add flag check */ + +if (dev->pwr_mgmt_state ==RTE_ETH_DEV_POWER_MGMT_DISABLED ) +return -EINVAL ; + +/* rte_free ignores NULL so safe to call without checks */ +rte_free (dev->empty_poll_stats);
You can't free callback metadata before removing the callback itself. In fact, with current rx callback code it is not safe to free it even after (we discussed it offline).
lib/librte_power/rte_power_pmd_mgmt.c line 171
Quoted 9 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +9
-0+ +switch (dev->cb_mode) { +case RTE_ETH_DEV_POWER_MGMT_CB_WAIT : +case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE : +rte_eth_remove_rx_callback (port_id,0 , + dev->cur_pwr_cb); +break ; +case RTE_ETH_DEV_POWER_MGMT_CB_SCALE : +rte_power_freq_max (lcore_id);
Stupid q: what makes you think that lcore frequency was max, *before* you setup the callback?
Quoted 28 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13
-0+rte_eth_remove_rx_callback (port_id,0 , + dev->cur_pwr_cb); +if (rte_power_exit (lcore_id)) +return -EINVAL ; +break ; + } + + dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_DISABLED ; + dev->cur_pwr_cb =NULL ; + dev->cb_mode =0 ; + +return 0 ; +}lib/librte_power/rte_power_version.map +4
-1@@ -34,4 +34,8 @@ EXPERIMENTAL { rte_power_guest_channel_receive_msg; rte_power_poll_stat_fetch; rte_power_poll_stat_update; + # added in 20.08 + rte_power_pmd_mgmt_disable; + rte_power_pmd_mgmt_enable; + }; --2.17.1
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Liang MaQuoted 12 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 2 lines
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>
Before this is merged, please work with Arm maintainers to have a version that works on Arm 64 as well. Don't think this should be merged unless the two major platforms supported by DPDK can work with it.
Also, not sure if this mechanism can work with other drivers. You need to work with other vendors to show that the same infrastructure can work with their hardware. Once again, I don't think this can go in if it only can work on Intel. It needs to work on Broadcom, Mellanox to be useful.
Will it work in a VM? Will it work with virtio or vmxnet3?
Having a single vendor solution is a non-starter for me. They don't all have to be there to get it merged, but if the design only works on single platform then it is not helpful.
Re: [dpdk-dev] [PATCH v3 2/6] ethdev: add simple power management API
In reply to Liang MaQuoted 45 lines
Add a simple API allow ethdev get the last available queue descriptor address from PMD. Also include internal structure update.
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_ethdev/rte_ethdev.h | 22 ++++++++++++++ lib/librte_ethdev/rte_ethdev_core.h | 46 +++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-)lib/librte_ethdev/rte_ethdev.h +12
-0@@ -157,6 +157,7 @@ extern "C" {#include <rte_common.h> #include <rte_config.h> #include <rte_ether.h> +#include <rte_power_intrinsics.h> #include "rte_ethdev_trace_fp.h" #include "rte_dev_info.h" @@ -775,6 +776,7 @@ rte_eth_rss_hf_refine(uint64_t rss_hf)/** Maximum nb. of vlan per mirror rule */ #define ETH_MIRROR_MAX_VLANS 64 +#define ETH_EMPTYPOLL_MAX 512/**< Empty poll number threshlold */ #define ETH_MIRROR_VIRTUAL_POOL_UP 0x01/**< Virtual Pool uplink Mirroring. */ #define ETH_MIRROR_UPLINK_PORT 0x02/**< Uplink Port Mirroring. */ #define ETH_MIRROR_DOWNLINK_PORT 0x04/**< Downlink Port Mirroring. */ @@ -1602,6 +1604,26 @@ enum rte_eth_dev_state { RTE_ETH_DEV_REMOVED, }; +#define RTE_ETH_PAUSE_NUM 64/* How many times to pause */ +/** +* Possible power management states of an ethdev port. +*/ +enum rte_eth_dev_power_mgmt_state { +/** Device power management is disabled. */ +RTE_ETH_DEV_POWER_MGMT_DISABLED =0 , +/** Device power management is enabled. */ +RTE_ETH_DEV_POWER_MGMT_ENABLED , +};
lib/librte_ethdev/rte_ethdev.h enum rte_eth_dev_state { · line 1626
Quoted 10 lines
lib/librte_ethdev/rte_ethdev.h +10
-0+ +enum rte_eth_dev_power_mgmt_cb_mode { +/** WAIT callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_WAIT =1 , +/** PAUSE callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_PAUSE , +/** Freq Scaling callback mode. */ +RTE_ETH_DEV_POWER_MGMT_CB_SCALE , +}; +
I don't think we need to put all these power related staff into rte_ethdev library.rte_power or so, seems like much better place for it.
Quoted 25 lines
lib/librte_ethdev/rte_ethdev.h +0
-0struct rte_eth_dev_sriov {uint8_t active;/**< SRIOV is active with 16, 32 or 64 pools */ uint8_t nb_q_per_pool;/**< rx queue number per pool */ lib/librte_ethdev/rte_ethdev_core.h +14
-0@@ -603,6 +603,30 @@ typedef int (*eth_tx_hairpin_queue_setup_t)uint16_t nb_tx_desc, const struct rte_eth_hairpin_conf *hairpin_conf); +/** +* @internal +* Get the next RX ring descriptor address. +* +* @param rxq +* ethdev queue pointer. +* @param tail_desc_addr +* the pointer point to descriptor address var. +* @param expected +* the pointer point to value to be expected when descriptor is set. +* @param mask +* the pointer point to comparison bitmask for the expected value. +* @return +* Negative errno value on error, 0 on success.
lib/librte_ethdev/rte_ethdev_core.h typedef int (*eth_tx_hairpin_queue_setup_t) · line 629
Quoted 10 lines
lib/librte_ethdev/rte_ethdev_core.h +10
-0+* +* @retval 0 +* Success. +* @retval -EINVAL +* Failed to get descriptor address. +*/ +typedef int (*eth_next_rx_desc_t ) + (void *rxq,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask); +
In theory it could be anything: next RXD, doorbell, even some global variable.
So I think function name needs to be more neutral:eth_rx_wait_addr() or so.
Also I think you need a new rte_eth_ wrapper function for that dev op.
Quoted 48 lines
lib/librte_ethdev/rte_ethdev_core.h +20
-3/** * @internal A structure containing the functions exported by an Ethernet driver. */ @@ -752,6 +776,8 @@ struct eth_dev_ops {/**< Set up device RX hairpin queue. */ eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;/**< Set up device TX hairpin queue. */ +eth_next_rx_desc_t next_rx_desc; +/**< Get next RX ring descriptor address. */ };/** @@ -768,6 +794,14 @@ struct rte_eth_rxtx_callback {void *param; }; +/** +* @internal +* Structure used to hold counters for empty poll +*/ +struct rte_eth_ep_stat { +uint64_t num; +} __rte_cache_aligned; +/** * @internal * The generic data structure associated with each ethernet device. @@ -807,8 +841,16 @@ struct rte_eth_dev {enum rte_eth_dev_state state;/**< Flag indicating the port state */ void *security_ctx;/**< Context for security ops */ -uint64_t reserved_64s[4 ];/**< Reserved for future fields */ -void *reserved_ptrs[4 ];/**< Reserved for future fields */ +/**< Empty poll number */ +enum rte_eth_dev_power_mgmt_state pwr_mgmt_state; +/**< Power mgmt Callback mode */ +enum rte_eth_dev_power_mgmt_cb_mode cb_mode; +uint64_t reserved_64s[3 ];/**< Reserved for future fields */ + +/**< Flag indicating the port power state */ +struct rte_eth_ep_stat *empty_poll_stats; +const struct rte_eth_rxtx_callback *cur_pwr_cb; +void *reserved_ptrs[2 ];/**< Reserved for future fields */ } __rte_cache_aligned;struct rte_eth_dev_sriov ; --2.17.1
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Liang Malib/librte_eal/x86/include/rte_power_intrinsics.h line 6
Quoted 13 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +6
-0@@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_X86_64_H_ +#define _RTE_POWER_INTRINSIC_X86_64_H_
As a nit - if the function below are supported for both 64 and 32 ISA, then probably: RTE_POWER_INTRINSIC_X86_H_
Quoted 137 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +137
-0+ +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_atomic.h> +#include <rte_common.h> + +#include "generic/rte_power_intrinsics.h" + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* This function uses UMONITOR/UMWAIT instructions. For more information about +* their usage, please refer to Intel(R) 64 and IA-32 Architectures Software +* Developer's Manual. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number. Can be 0 (C0.2) or +* 1 (C0.1). +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to memory write or other reasons. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp) +{ +const uint32_t tsc_l = (uint32_t )tsc_timestamp; +const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 ); +/* the rflags need match native register size */ +#ifdef RTE_ARCH_I686 +uint32_t rflags; +#else +uint64_t rflags; +#endif +/* +* we're using raw byte codes for now as only the newest compiler +* versions support this instruction natively. +*/ + +/* set address for UMONITOR */ + asmvolatile (".byte 0xf3, 0x0f, 0xae, 0xf7;" + : + :"D" (p)); + +if (value_mask) { +const uint64_t cur_value = *(const volatile uint64_t *)p; +const uint64_t masked = cur_value & value_mask; +/* if the masked value is already matching, abort */ +if (masked == expected_value) +return 0 ; + } +/* execute UMWAIT */ + asmvolatile (".byte 0xf2, 0x0f, 0xae, 0xf7;\n" +/* +* UMWAIT sets CF flag in RFLAGS, so PUSHF to push them +* onto the stack, then pop them back into `rflags` so that +* we can read it. +*/ +"pushf;\n" +"pop %0;\n" + :"=r" (rflags) + :"D" (state),"a" (tsc_l),"d" (tsc_h)); + +/* we're interested in the first bit (the carry flag) */ +return rflags &0x1 ; +} + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* This function uses TPAUSE instruction. For more information about its usage, +* please refer to Intel(R) 64 and IA-32 Architectures Software Developer's +* Manual. +* +* @param state +* Architecture-dependent optimized power state number. Can be 0 (C0.2) or +* 1 (C0.1). +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to other reasons. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp) +{ +const uint32_t tsc_l = (uint32_t )tsc_timestamp; +const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 ); +/* the rflags need match native register size */ +#ifdef RTE_ARCH_I686 +uint32_t rflags; +#else +uint64_t rflags; +#endif + +/* execute TPAUSE */ + asmvolatile (".byte 0x66, 0x0f, 0xae, 0xf7;\n" +/* +* TPAUSE sets CF flag in RFLAGS, so PUSHF to push them +* onto the stack, then pop them back into `rflags` so that +* we can read it. +*/ +"pushf;\n" +"pop %0;\n" + :"=r" (rflags) + :"D" (state),"a" (tsc_l),"d" (tsc_h)); + +/* we're interested in the first bit (the carry flag) */ +return rflags &0x1 ; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_POWER_INTRINSIC_X86_64_H_ */
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Stephen HemmingerHi Stephen,
Agree. v4 will address this.
Regards
Liang
Quoted 13 lines · Stephen Hemminger
lib/librte_eal/include/generic/rte_power_intrinsics.h line 46
Quoted 7 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:
+ *
+ * @return
+ * Architecture-dependent return value.
+ */lib/librte_eal/include/generic/rte_power_intrinsics.h new file +3
-0+static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp);Since this is generic code, and you are defining the function. You should have it return
-ENOTSUPPORTEDor-EINVAL.
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Stephen HemmingerHi Stephen,
v4 patch will include the l3fwd-power udpate.
Regards
Liang
Quoted 21 lines · Stephen Hemminger
Quoted 12 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 2 lines
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>This looks like a useful feature but needs more documentation and example. It would make sense to put an example in l3fwd-power.
Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback
In reply to Stephen Hemminger<snip>
Hi Stephen,
v4 will support 1 port with multiple core(still 1 queue per core)support this part description will be updated according to the design change.
Regards
Liang
Quoted 38 lines
The common way to express is this is:
This API is not thread-safe and not preempt-safe.
There is also no mechanism for a single thread to wait on multiple queues.Quoted 3 lines
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
nit coexist is one word
Quoted 8 lines
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
Quoted 5 lines
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.
Wording here is a problem, and "releaf" should be "relief"? Rewording into active voice grammar would be easier.
Use Pause instruction to allow processor to go into deeper C state when busy polling.
Quoted 4 lines
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.
Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback
In reply to Ananyev, KonstantinOn 04 Sep 11:33, Ananyev, Konstantin wrote:
<snip>
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c line 24
Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4
-0+struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +if (unlikely (nb_rx ==0 )) { +dev->empty_poll_stats[qidx].num++;
Hi Konstantin,
Agree, v4 will relocate the meta data to seperate structure. and without touch the rte_ethdev structure.
Quoted 114 lines
I believe there are two fundamental issues with that approach:
1. You put metadata specific lib (power) callbacks intorte_eth_devstruct.
2. These callbacks do access rte_eth_devices[] directly.
That doesn't look right to me -rte_eth_devstructure supposed to be treated as internal onelibrt_etherand underlying drivers and should be accessed directly by outer code.
If these callbacks need some extra metadata, then it is responsibility
of power library to allocate/manage these metadata.
You can pass pointer to this metadata via last parameter forrte_eth_add_rx_callback().Quoted 91 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +91
-0+if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) { +volatile void *target_addr; +uint64_t expected, mask; +uint16_t ret; + +/* +* get address of next descriptor in the RX +* ring for this queue, as well as expected +* value and a mask. +*/ +ret = (*dev->dev_ops->next_rx_desc) +(dev->data->rx_queues[qidx], + &target_addr, &expected, &mask); +if (ret ==0 ) +/* -1ULL is maximum value for TSC */ +rte_power_monitor (target_addr, + expected, mask, +0 ,-1ULL ); +} +}else +dev->empty_poll_stats[qidx].num =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_pause (uint16_t port_id,uint16_t qidx, +struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, +uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +int i; + +if (unlikely (nb_rx ==0 )) { + +dev->empty_poll_stats[qidx].num++; + +if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) { + +for (i =0 ; i <RTE_ETH_PAUSE_NUM ; i++) +rte_pause (); + +} +}else +dev->empty_poll_stats[qidx].num =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_scalefreq (uint16_t port_id,uint16_t qidx, +struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, +uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +if (unlikely (nb_rx ==0 )) { +dev->empty_poll_stats[qidx].num++; +if (unlikely (dev->empty_poll_stats[qidx].num > +ETH_EMPTYPOLL_MAX )) { + +/*scale down freq */ +rte_power_freq_min (rte_lcore_id ()); + +} +}else { +dev->empty_poll_stats[qidx].num =0 ; +/* scal up freq */ +rte_power_freq_max (rte_lcore_id ()); +} + +return nb_rx; +} + +int +rte_power_pmd_mgmt_enable (unsigned int lcore_id, +uint16_t port_id, +enum rte_eth_dev_power_mgmt_cb_mode mode) +{ +struct rte_eth_dev *dev; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); +dev = &rte_eth_devices[port_id]; + +if (dev->pwr_mgmt_state ==RTE_ETH_DEV_POWER_MGMT_ENABLED ) +return -EINVAL ; +/* allocate memory for empty poll stats */ +dev->empty_poll_stats = rte_malloc_socket(NULL,lib/librte_power/rte_power_pmd_mgmt.c line 125
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+sizeof (struct rte_eth_ep_stat ) + *RTE_MAX_QUEUES_PER_PORT , + 0, dev->data->numa_node); +if (dev->empty_poll_stats ==NULL ) +return -ENOMEM ; + +switch (mode) { +case RTE_ETH_DEV_POWER_MGMT_CB_WAIT : +if (!rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) +return -ENOTSUP ;Here and in other places: in case of error return you don't' free your
empty_poll_stats.
Quoted 3 lines
Quoted 1 line
+dev->cur_pwr_cb = rte_eth_add_rx_callback(port_id, 0,
Why zero for queue number, why not to pass
queue_idas a parameter for that function?
v4 will move to use queue_id instead of 0. v3 still assume only queue 0 is used.
Quoted 4 lines
Quoted 2 lines
+rte_power_mgmt_umwait, NULL);
As I said above, instead of NULL - could be pointer to metadata struct.
v4 will address this.
Quoted 32 lines
Quoted 32 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +31
-0+break ; +case RTE_ETH_DEV_POWER_MGMT_CB_SCALE : +/* init scale freq */ +if (rte_power_init (lcore_id)) +return -EINVAL ; +dev->cur_pwr_cb =rte_eth_add_rx_callback (port_id,0 , +rte_power_mgmt_scalefreq,NULL ); +break ; +case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE : +dev->cur_pwr_cb =rte_eth_add_rx_callback (port_id,0 , +rte_power_mgmt_pause,NULL ); +break ; +} + +dev->cb_mode = mode; +dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_ENABLED ; +return 0 ; +} + +int +rte_power_pmd_mgmt_disable (unsigned int lcore_id, +uint16_t port_id) +{ +struct rte_eth_dev *dev; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); +dev = &rte_eth_devices[port_id]; + +/*add flag check */ + +if (dev->pwr_mgmt_state ==RTE_ETH_DEV_POWER_MGMT_DISABLED )
Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 162
Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4
-0+return -EINVAL ; + +/* rte_free ignores NULL so safe to call without checks */ +rte_free (dev->empty_poll_stats);You can't free callback metadata before removing the callback itself. In fact, with current rx callback code it is not safe to free it even after (we discussed it offline).
agree.
Quoted 13 lines
lib/librte_power/rte_power_pmd_mgmt.c line 171
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +9
-0+ +switch (dev->cb_mode) { +case RTE_ETH_DEV_POWER_MGMT_CB_WAIT : +case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE : +rte_eth_remove_rx_callback (port_id,0 , + dev->cur_pwr_cb); +break ; +case RTE_ETH_DEV_POWER_MGMT_CB_SCALE : +rte_power_freq_max (lcore_id);Stupid q: what makes you think that lcore frequency was max, *before* you setup the callback?
that is because the rte_power_init() has figured out the system max. the init code invocate rte_power_init() already.
Quoted 30 lines
Quoted 29 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13
-0+rte_eth_remove_rx_callback (port_id,0 , + dev->cur_pwr_cb); +if (rte_power_exit (lcore_id)) +return -EINVAL ; +break ; +} + +dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_DISABLED ; +dev->cur_pwr_cb =NULL ; +dev->cb_mode =0 ; + +return 0 ; +}lib/librte_power/rte_power_version.map +4
-1@@ -34,4 +34,8 @@ EXPERIMENTAL { rte_power_guest_channel_receive_msg; rte_power_poll_stat_fetch; rte_power_poll_stat_update; +# added in 20.08 +rte_power_pmd_mgmt_disable; +rte_power_pmd_mgmt_enable; + }; --2.17.1
Re: [dpdk-dev] [PATCH v3 2/6] ethdev: add simple power management API
In reply to Stephen Hemmingeragree, will be addressed
Quoted 10 lines · Stephen Hemminger
Quoted 1 line · On Fri, 4 Sep 2020 11:18:56 +0100 Liang Ma <[email protected]> wrote:
+#define
ETH_EMPTYPOLL_MAX512 /**< Empty poll number threshlold */Spelling here.
Also, shouldn't this be a per-device (or per-queue) configuration value.
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Stephen HemmingerOn 04 Sep 11:42, Stephen Hemminger wrote:
<snip>
we are very open to discuss design with other vendor.
Quoted 8 lines
Before this is merged, please work with Arm maintainers to have a version that works on Arm 64 as well. Don't think this should be merged unless the two major platforms supported by DPDK can work with it.
Also, not sure if this mechanism can work with other drivers. You need to work with other vendors to show that the same infrastructure can work with their hardware. Once again, I don't think this can go in if it only can work on Intel. It needs to work on Broadcom, Mellanox to be useful.
this mechanism should work with any device use a HW ring descriptor mechanism. I think most Mellanox and Broadcom NIC can support it easily.
Quoted 2 lines
Will it work in a VM? Will it work with virtio or vmxnet3?
General speaking, Guest OS is not very easy to use this. However, virtio is under invetigation.
Quoted 3 lines
Having a single vendor solution is a non-starter for me. They don't all have to be there to get it merged, but if the design only works on single platform then it is not helpful.
Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback
In reply to Liang, MaQuoted 15 lines
Quoted 15 lines
lib/librte_power/rte_power_pmd_mgmt.c line 171
Quoted 12 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +9
-0+ +switch (dev->cb_mode) { +case RTE_ETH_DEV_POWER_MGMT_CB_WAIT : +case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE : +rte_eth_remove_rx_callback (port_id,0 , + dev->cur_pwr_cb); +break ; +case RTE_ETH_DEV_POWER_MGMT_CB_SCALE : +rte_power_freq_max (lcore_id);Stupid q: what makes you think that lcore frequency was max, *before* you setup the callback?
Quoted 2 lines
that is because the
rte_power_init()has figured out the system max. the init code invocaterte_power_init()already.
So rte_power_init(lcore) always raises lcore frequency to max possible value?
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13
-0+rte_eth_remove_rx_callback (port_id,0 , + dev->cur_pwr_cb); +if (rte_power_exit (lcore_id)) +return -EINVAL ; +break ; +} + +dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_DISABLED ; +dev->cur_pwr_cb =NULL ; +dev->cb_mode =0 ; + +return 0 ; +}
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Stephen HemmingerOn 04 Sep 11:42, Stephen Hemminger wrote:
<snip>
we have discussed with arm developer in the past.
Please ref https://patches.dpdk.org/patch/70662/
There was no objection, in my opinoin.
Also the API we proposed has experimental tag, other vendor still can change it.
For the ethdev internal ops we introduced should work with any NIC use ring descriptor writeback mechansim. But we lack the internal sight of Mellanox or Broadcom NIC.
AF_XDP PMD and virtio-net is under investigation.
I hope above explaination addressed your concern.
Quoted 14 lines
Before this is merged, please work with Arm maintainers to have a version that works on Arm 64 as well. Don't think this should be merged unless the two major platforms supported by DPDK can work with it.
Also, not sure if this mechanism can work with other drivers. You need to work with other vendors to show that the same infrastructure can work with their hardware. Once again, I don't think this can go in if it only can work on Intel. It needs to work on Broadcom, Mellanox to be useful.
Will it work in a VM? Will it work with virtio or vmxnet3?
Having a single vendor solution is a non-starter for me. They don't all have to be there to get it merged, but if the design only works on single platform then it is not helpful.
Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback
In reply to Ananyev, KonstantinOn 16 Sep 07:53, Ananyev, Konstantin wrote:
<snip>
Yes. we only has two gear. min or max. However, user still can customize their system max with power mgmt python script on Intel platform.
Quoted 17 lines
So
rte_power_init(lcore)always raises lcore frequency to max possible value?Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13
-0+rte_eth_remove_rx_callback (port_id,0 , + dev->cur_pwr_cb); +if (rte_power_exit (lcore_id)) +return -EINVAL ; +break ; +} + +dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_DISABLED ; +dev->cur_pwr_cb =NULL ; +dev->cb_mode =0 ; + +return 0 ; +}
Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback
Quoted 4 lines · Konstantin
<snip>
Yes. we only has two gear. min or max. However, user still can customize their system max with power mgmt python script on Intel platform.
Ok, thanks for explanation.
Quoted 17 lines
Quoted 17 lines
So
rte_power_init(lcore)always raises lcore frequency to max possible value?Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13
-0+rte_eth_remove_rx_callback (port_id,0 , + dev->cur_pwr_cb); +if (rte_power_exit (lcore_id)) +return -EINVAL ; +break ; +} + +dev->pwr_mgmt_state =RTE_ETH_DEV_POWER_MGMT_DISABLED ; +dev->cur_pwr_cb =NULL ; +dev->cb_mode =0 ; + +return 0 ; +}
Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics
In reply to Liang MaQuoted 33 lines · Liang Ma
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>lib/librte_eal/x86/include/rte_power_intrinsics.h new file +16
-0+ +#include "generic/rte_power_intrinsics.h" + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* This function uses UMONITOR/UMWAIT instructions. For more information about +* their usage, please refer to Intel(R) 64 and IA-32 Architectures Software +* Developer's Manual.
[snip]
lib/librte_eal/x86/include/rte_power_intrinsics.h line 50
Quoted 4 lines
+ */
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +3
-0+static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp)
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as functions[1] or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..
This will help the consumer to create workers based on the instruction features which can NOT be abstracted as a generic feature across the architectures.
[1]
struct rte_arch_inst_feat {
uint32_t power_monitor : 1; /**< Power monitor */
...
}
void rte_arch_inst_feat_get(struct rte_arch_inst_feat *feat);
PATCH v4 2/10 eal: add power management intrinsics
In reply to Liang MaAdd two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
--- .../include/generic/rte_power_intrinsics.h | 64 ++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + .../x86/include/rte_power_intrinsics.h | 143 ++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
@@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_H_ +#define _RTE_POWER_INTRINSIC_H_ + +#include <inttypes.h> + +/** +* @file +* Advanced power management operations. +* +* This file define APIs for advanced power management, +* which are architecture-dependent. +*/ + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp); + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp); + +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
@@ -60,6 +60,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +143 -0
143 lines not on this page · raw message
Signature · 1 line
2.17.1
PATCH v4 1/10 eal: add new x86 cpuid support for WAITPKG
In reply to Liang MaAdd new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.
--- lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++ lib/librte_eal/x86/rte_cpuflags.c | 2 ++ 2 files changed, 4 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_MOVDIR64B ,/**< Direct Store Instructions 64B */ RTE_CPUFLAG_AVX512VP2INTERSECT ,/**< AVX512 Two Register Intersection */ +/**< UMWAIT/TPAUSE Instructions */ +RTE_CPUFLAG_WAITPKG ,/**< UMINITOR/UMWAIT/TPAUSE */ /* The last item */ RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */ };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 )
Signature · 1 line
2.17.1
PATCH v4 4/10 power: add simple power management API and callback
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API support 1 port to multiple core use case.
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to relief the processor from busy polling.
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.
--- lib/librte_power/meson.build | 5 +- lib/librte_power/pmd_mgmt.h | 49 ++++++ lib/librte_power/rte_power_pmd_mgmt.c | 208 +++++++++++++++++++++++++ lib/librte_power/rte_power_pmd_mgmt.h | 88 +++++++++++ lib/librte_power/rte_power_version.map | 4 + 5 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 lib/librte_power/pmd_mgmt.h create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
lib/librte_power/meson.build +3 -2
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c', 'power_kvm_vm.c', 'guest_channel.c', 'rte_power_empty_poll.c', 'power_pstate_cpufreq.c', + 'rte_power_pmd_mgmt.c', 'power_common.c') -headers = files('rte_power.h','rte_power_empty_poll.h') -deps += ['timer'] +headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h') +deps += ['timer' ,'ethdev']
lib/librte_power/pmd_mgmt.h new file +49 -0
49 lines not on this page · raw message
lib/librte_power/rte_power_pmd_mgmt.c new file +208 -0
208 lines not on this page · raw message
lib/librte_power/rte_power_pmd_mgmt.h new file +88 -0
88 lines not on this page · raw message
lib/librte_power/rte_power_version.map +4 -0
@@ -34,4 +34,8 @@ EXPERIMENTAL { rte_power_guest_channel_receive_msg; rte_power_poll_stat_fetch; rte_power_poll_stat_update; + # added in 20.11 + rte_power_pmd_mgmt_queue_enable; + rte_power_pmd_mgmt_queue_disable; + };
Signature · 1 line
2.17.1
PATCH v4 7/10 net/ice: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.
--- drivers/net/ice/ice_ethdev.c | 1 + drivers/net/ice/ice_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/ice/ice_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
@@ -216,6 +216,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .udp_tunnel_port_add = ice_dev_udp_tunnel_port_add, .udp_tunnel_port_del = ice_dev_udp_tunnel_port_del, .tx_done_cleanup = ice_tx_done_cleanup, + .get_wake_addr = ice_get_wake_addr, };/* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
@@ -25,6 +25,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;uint64_t rte_net_ice_dynflag_proto_xtr_ip_offset_mask; +int ice_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ice_rx_flex_desc *rxdp; +struct ice_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.status_error0; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + *mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + +return 0 ; +} + +static inline uint8_t ice_proto_xtr_type_to_rxdid (uint8_t xtr_type) {
drivers/net/ice/ice_rxtx.h +2 -0
@@ -250,6 +250,8 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);int ice_fdir_programming (struct ice_pf *pf,struct ice_fltr_desc *fdir_desc);int ice_tx_done_cleanup (void *txq,uint32_t free_cnt); +int ice_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#define FDIR_PARSING_ENABLE_PER_QUEUE (ad, on) do { \ int i; \
Signature · 1 line
2.17.1
PATCH v4 10/10 doc: update the programming guide for PMD power management
In reply to Liang MaUpdate programming guide and sample application l3fwd-power document for PMD power management
--- doc/guides/prog_guide/power_man.rst | 40 +++++++++++++++++++ .../sample_app_ug/l3_forward_power_man.rst | 15 ++++++- 2 files changed, 54 insertions(+), 1 deletion(-)
doc/guides/prog_guide/power_man.rst +40 -0
@@ -188,6 +188,43 @@ API Overview for Empty Poll Power Management * **Detect empty poll state change**: empty poll state change detection algorithm then take action. +PMD Power Management API +------------------------ + +Abstract +~~~~~~~~ +Given existing power management mechanism, developer need change application design or code to use it. +In order to solve the problem, it's very helpful to make the design transparent to application. +The proposed solution is to leverage RX_CALLBACK mechanism which allow three different power management +methodology co exist. The trigger condition is empty poll number beyond defined threshold. + + * umwait/umonitor + + The new umwait/umonitor instruction monitoring the wake address then transfer processor to sub-state. + Once the content of address is changed, the processor will be wake up from the sub-state. Timeout is + setup as well, in case, there is no wake event happen, processor still will wake up after timeout + timer expired. + + * Pause instruction + + Instead of move the core into deeper C state, this lightweight method use Pause instruction + to relief the processor from busy polling. + + * Frequency Scaling + + Reuse exist rte power library to scale up/down core frequency + depend on traffic volume. + +The proposed solution support multiple port and each port can map to multiple core. But 1 core only can map +1 queue(regardless which port). In theory, each queue belongs to same port can apply different power scheme. +It's strongly recommend to use same power scheme for all queues belong to same port. + +API Overview for PMD Power Management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* **Queue Enable**: Enable specific power scheme for certain queue/port/core + +* **Queue Disable**: Disable power scheme for certain queue/port/core + User Cases ---------- The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
@@ -200,3 +237,6 @@ References * The :doc:`../sample_app_ug/vm_power_management` chapter in the :doc:`../sample_app_ug/index` section. + +* The :doc:`../sample_app_ug/rxtx_callbacks` + chapter in the :doc:`../sample_app_ug/index` section.
doc/guides/sample_app_ug/l3_forward_power_man.rst +14 -1
@@ -107,7 +107,9 @@ where, * --empty-poll: Traffic Aware power management. See below for details -* --telemetry: Telemetry mode. +* --telemetry: Telemetry mode. + +* --pmd-mgmt: PMD power management mode. See :doc:`l3_forward` for details. The L3fwd-power example reuses the L3fwd command line options.
@@ -459,3 +461,14 @@ reference cycles and accordingly busy rate is set to either 0% or The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``. + +PMD power management Mode +------------------------- + +The PMD power management mode support for ``l3fwd-power`` is a standalone mode, in this mode +``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific +port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API. + +.. code-block:: console + + ./examples/l3fwd-power/build/l3fwd-power --pmd-mgmt -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)"
Signature · 1 line
2.17.1
PATCH v4 6/10 net/i40e: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.
--- drivers/net/i40e/i40e_ethdev.c | 1 + drivers/net/i40e/i40e_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/i40e/i40e_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = { .mtu_set = i40e_dev_mtu_set, .tm_ops_get = i40e_tm_ops_get, .tx_done_cleanup = i40e_tx_done_cleanup, + .get_wake_addr = i40e_get_wake_addr, };/* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
@@ -71,6 +71,29 @@#define I40E_TX_OFFLOAD_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK) +int +i40e_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +struct i40e_rx_queue *rxq = rx_queue; +volatile union i40e_rx_desc *rxdp; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.qword1.status_error_len; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + *mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + +return 0 ; +} +static inline void i40e_rxd_to_vlan_tci (struct rte_mbuf *mb,volatile union i40e_rx_desc *rxdp) {
drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);uint16_t i40e_xmit_pkts_vec_avx2 (void *tx_queue,struct rte_mbuf **tx_pkts,uint16_t nb_pkts); +int i40e_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *value);/* For each value it means, datasheet of hardware can tell more details *
Signature · 1 line
2.17.1
PATCH v4 5/10 net/ixgbe: implement power management API
In reply to Liang MaImplement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.
--- drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 ++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 ++ 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = { .udp_tunnel_port_del = ixgbe_dev_udp_tunnel_port_del, .tm_ops_get = ixgbe_tm_ops_get, .tx_done_cleanup = ixgbe_dev_tx_done_cleanup, + .get_wake_addr = ixgbe_get_wake_addr, };/*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
@@ -1366,6 +1366,28 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +int ixgbe_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ixgbe_adv_rx_desc *rxdp; +struct ixgbe_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.upper.status_error; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + *mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + +return 0 ; +} +/* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */ static inline uint32_t ixgbe_rxd_pkt_info_to_pkt_type (uint32_t pkt_info,uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_queue_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_port_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_tx_queue_offloads (struct rte_eth_dev *dev); +int ixgbe_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
PATCH v4 8/10 examples/l3fwd-power: enable PMD power mgmt
In reply to Liang MaAdd pmd power mgmt feature support.
--- examples/l3fwd-power/main.c | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-)
examples/l3fwd-power/main.c +43 -1
@@ -47,6 +47,8 @@#include <rte_power_empty_poll.h> #include <rte_metrics.h> #include <rte_telemetry.h> +#include <rte_power_pmd_mgmt.h> +#include "perf_core.h" #include "main.h"
@@ -199,7 +201,8 @@ enum appmode {APP_MODE_LEGACY ,APP_MODE_EMPTY_POLL ,APP_MODE_TELEMETRY , - APP_MODE_INTERRUPT +APP_MODE_INTERRUPT , + APP_MODE_PMD_MGMT };enum appmode app_mode;
@@ -1750,6 +1753,7 @@ parse_ep_config(const char *q_arg)#define CMD_LINE_OPT_EMPTY_POLL "empty-poll"#define CMD_LINE_OPT_INTERRUPT_ONLY "interrupt-only"#define CMD_LINE_OPT_TELEMETRY "telemetry" +#define CMD_LINE_OPT_PMD_MGMT "pmd-mgmt"/* Parse the argument given in the command line of the application */ static int
@@ -1771,6 +1775,7 @@ parse_args(int argc, char **argv) {CMD_LINE_OPT_LEGACY, 0, 0, 0}, {CMD_LINE_OPT_TELEMETRY, 0, 0, 0}, {CMD_LINE_OPT_INTERRUPT_ONLY, 0, 0, 0}, + {CMD_LINE_OPT_PMD_MGMT, 0, 0, 0}, {NULL, 0, 0, 0} };
@@ -1881,6 +1886,16 @@ parse_args(int argc, char **argv)printf ("telemetry mode is enabled\n" ); } +if (!strncmp (lgopts[option_index].name, +CMD_LINE_OPT_PMD_MGMT , +sizeof (CMD_LINE_OPT_PMD_MGMT ))) { +if (app_mode !=APP_MODE_DEFAULT ) { +printf (" power mgmt mode is mutually exclusive with other modes\n" ); +return -1 ; + } + app_mode =APP_MODE_PMD_MGMT ; +printf ("PMD power mgmt mode is enabled\n" ); + }if (!strncmp (lgopts[option_index].name,CMD_LINE_OPT_INTERRUPT_ONLY ,sizeof (CMD_LINE_OPT_INTERRUPT_ONLY ))) {
@@ -2437,6 +2452,9 @@ mode_to_str(enum appmode mode)return "telemetry" ;case APP_MODE_INTERRUPT :return "interrupt-only" ; +case APP_MODE_PMD_MGMT : +return "pmd mgmt" ; +default :return "invalid" ; }
@@ -2705,6 +2723,12 @@ main(int argc, char **argv) }else if (!check_ptype (portid))rte_exit (EXIT_FAILURE ,"PMD can not provide needed ptypes\n" ); +if (app_mode ==APP_MODE_PMD_MGMT ) { +rte_power_pmd_mgmt_queue_enable (lcore_id, + portid, queueid, +RTE_POWER_MGMT_TYPE_SCALE ); + + } } }
@@ -2790,8 +2814,12 @@ main(int argc, char **argv) SKIP_MASTER); }else if (app_mode ==APP_MODE_INTERRUPT ) {rte_eal_mp_remote_launch (main_intr_loop,NULL ,CALL_MASTER ); + }else if (app_mode ==APP_MODE_PMD_MGMT ) { +rte_eal_mp_remote_launch (main_telemetry_loop,NULL , +CALL_MASTER ); } +if (app_mode ==APP_MODE_EMPTY_POLL || app_mode ==APP_MODE_TELEMETRY )launch_timer (rte_lcore_id ());
@@ -2812,6 +2840,20 @@ main(int argc, char **argv)if (app_mode ==APP_MODE_EMPTY_POLL )rte_power_empty_poll_stat_free (); +if (app_mode ==APP_MODE_PMD_MGMT ) { +for (lcore_id =0 ; lcore_id <RTE_MAX_LCORE ; lcore_id++) { +if (rte_lcore_is_enabled (lcore_id) ==0 ) +continue ; + qconf = &lcore_conf[lcore_id]; +for (queue =0 ; queue < qconf->n_rx_queue; ++queue) { + portid = qconf->rx_queue_list[queue].port_id; + queueid = qconf->rx_queue_list[queue].queue_id; +rte_power_pmd_mgmt_queue_disable (lcore_id, + portid, queueid); + } + } + } +if ((app_mode ==APP_MODE_LEGACY || app_mode ==APP_MODE_EMPTY_POLL ) &&deinit_power_library ())rte_exit (EXIT_FAILURE ,"deinit_power_library failed\n" );
Signature · 1 line
2.17.1
PATCH v4 9/10 doc: update release notes for PMD power management
In reply to Liang MaAdd release notes for PMD power management
--- doc/guides/rel_notes/release_20_11.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
doc/guides/rel_notes/release_20_11.rst +16 -0
@@ -55,6 +55,11 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **ethdev: add 1 new EXPERIMENTAL API for PMD power management.** + + * ``rte_eth_get_wake_addr()`` + * add new eth_dev_ops ``get_wake_addr`` + * **Updated Broadcom bnxt driver.** Updated the Broadcom bnxt driver with new features and improvements, including:
@@ -107,6 +112,17 @@ New Features * Extern objects and functions can be plugged into the pipeline. * Transaction-oriented table updates. +* **Add PMD power management mechanism** + + 3 new PMD power managmeent mechanism is added through existing + RX_ETH_CALLBACK infrastructure. + + * Add umwait power saving scheme + * Add pause power saving scheme + * Add frequency scaling power saving scheme + * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_enable()`` + * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_disable()`` + Removed Items -------------
Signature · 1 line
2.17.1
PATCH v4 3/10 ethdev: add simple power management API
In reply to Liang MaAdd a simple API allow ethdev get wake up address from PMD. Also include internal structure update.
--- lib/librte_ethdev/rte_ethdev.c | 19 ++++++++++++++++ lib/librte_ethdev/rte_ethdev.h | 24 ++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 28 ++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 1 + 4 files changed, 72 insertions(+)
lib/librte_ethdev/rte_ethdev.c +19 -0
@@ -4804,6 +4804,25 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode)); } +int +rte_eth_get_wake_addr (uint16_t port_id,uint16_t queue_id, +volatile void **wake_addr, +uint64_t *expected,uint64_t *mask) +{ +struct rte_eth_dev *dev; +uint16_t ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + + dev = &rte_eth_devices[port_id]; + + ret = (*dev->dev_ops->get_wake_addr) + (dev->data->rx_queues[queue_id], + wake_addr, expected, mask); + +return ret; +} + int rte_eth_dev_set_mc_addr_list(uint16_t port_id, struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +24 -0
@@ -4014,6 +4014,30 @@ __rte_experimentalint rte_eth_tx_burst_mode_get (uint16_t port_id,uint16_t queue_id,struct rte_eth_burst_mode *mode); +/** +* Retrieve the wake up address from specific queue +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The Tx queue on the Ethernet device for which information +* will be retrieved. +* @param wake_addr +* The pointer point to the address which is used for monitoring. +* @param expected +* The pointer point to value to be expected when descriptor is set. +* @param mask +* The pointer point to comparison bitmask for the expected value. +* +* @return +* - 0: Success. +* -EINVAL: Failed to get wake address. +*/ +__rte_experimental +int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id, +volatile void **wake_addr, +uint64_t *expected,uint64_t *mask); +/** * Retrieve device registers and register attributes (number of registers and * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)uint16_t nb_tx_desc, const struct rte_eth_hairpin_conf *hairpin_conf); +/** +* @internal +* Get the Wake up address. +* +* @param rxq +* Ethdev queue pointer. +* @param tail_desc_addr +* The pointer point to descriptor address var. +* @param expected +* The pointer point to value to be expected when descriptor is set. +* @param mask +* The pointer point to comparison bitmask for the expected value. +* @return +* Negative errno value on error, 0 on success. +* +* @retval 0 +* Success. +* @retval -EINVAL +* Failed to get descriptor address. +*/ +typedef int (*eth_get_wake_addr_t ) + (void *rxq,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask); + +/** * @internal A structure containing the functions exported by an Ethernet driver. */
@@ -713,6 +738,9 @@ struct eth_dev_ops {/**< Set up device RX hairpin queue. */ eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;/**< Set up device TX hairpin queue. */ +eth_get_wake_addr_t get_wake_addr; +/**< Get wake up address. */ + };/**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
@@ -229,6 +229,7 @@ EXPERIMENTAL { # added in 20.11 rte_eth_link_speed_to_str; rte_eth_link_to_str; + rte_eth_get_wake_addr; }; INTERNAL {
Signature · 1 line
2.17.1
Re: [dpdk-dev] [PATCH v4 01/10] eal: add new x86 cpuid support for WAITPKG
In reply to Liang MaQuoted 16 lines · Liang Ma
Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++ lib/librte_eal/x86/rte_cpuflags.c | 2 ++ 2 files changed, 4 insertions(+)lib/librte_eal/x86/include/rte_cpuflags.h +0
-0
lib/librte_eal/x86/include/rte_cpuflags.h enum rte_cpu_flag_t { · line 136
Quoted 5 lines
lib/librte_eal/x86/include/rte_cpuflags.h +2
-0@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_MOVDIR64B ,/**< Direct Store Instructions 64B */ RTE_CPUFLAG_AVX512VP2INTERSECT ,/**< AVX512 Two Register Intersection */ +/**< UMWAIT/TPAUSE Instructions */ + RTE_CPUFLAG_WAITPKG, /**< UMINITOR/UMWAIT/TPAUSE */
Typo: UMINITOR
Quoted 19 lines
lib/librte_eal/x86/include/rte_cpuflags.h +0
-0/* The last item */ RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */ };lib/librte_eal/x86/rte_cpuflags.c +2
-0@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 )Signature · 1 line
2.17.1
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Liang MaQuoted 5 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Also please mark the new functions as experimental.
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 13 lines · Thomas Monjalon
Quoted 13 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 4 lines
Quoted 1 line
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html
Quoted 3 lines
Also please mark the new functions as experimental.
Re: [dpdk-dev] [PATCH v4 03/10] ethdev: add simple power management API
In reply to Liang MaQuoted 13 lines
lib/librte_ethdev/rte_ethdev.h +13
-0+/** +* Retrieve the wake up address from specific queue +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The Tx queue on the Ethernet device for which information +* will be retrieved. +* @param wake_addr +* The pointer point to the address which is used for monitoring. +* @param expected +* The pointer point to value to be expected when descriptor is set. +* @param mask
lib/librte_ethdev/rte_ethdev.h __rte_experimental · line 4039
Quoted 10 lines
lib/librte_ethdev/rte_ethdev.h +10
-0+* The pointer point to comparison bitmask for the expected value. +* +* @return +* - 0: Success. +* -EINVAL: Failed to get wake address. +*/ +__rte_experimental +int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id, +volatile void **wake_addr, +uint64_t *expected,uint64_t *mask);
It looks to be a very low-level API.
Can't we do something more "ready-to-use" at ethdev level?
Cc'in the relevant maintainers...
Note: sorry this comment come late but ethdev maintainers were not Cc.
Reminder: having no feedback is not a good sign, you should request comments.
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Jerin Jacob08/10/2020 10:44, Jerin Jacob:
Quoted 14 lines · Thomas Monjalon
Quoted 13 lines
Quoted 13 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html
This comment was sent on September 18.
Later this v4 was sent without replying to the comments. This is blocking the series.
I am considering this feature as low priority.
Quoted 1 line
Quoted 1 line
Also please mark the new functions as experimental.
Re: [dpdk-dev] [PATCH v4 03/10] ethdev: add simple power management API
In reply to Thomas MonjalonQuoted 20 lines
Quoted 20 lines
+/**
+ * Retrieve the wake up address from specific queue
+ *
+ * @paramport_id
+ * The port identifier of the Ethernet device.
+ * @paramqueue_id
+ * The Tx queue on the Ethernet device for which information
+ * will be retrieved.
+ * @paramwake_addr
+ * The pointer point to the address which is used for monitoring.
+ * @param expected
+ * The pointer point to value to be expected when descriptor is set.
+ * @param mask
+ * The pointer point to comparison bitmask for the expected value.
+ *
+ * @return
+ * - 0: Success.
+ *-EINVAL: Failed to get wake address.
Quoted 8 lines
lib/librte_ethdev/rte_ethdev.h __rte_experimental · line 4039
Quoted 5 lines
+ */
lib/librte_ethdev/rte_ethdev.h +4
-0+__rte_experimental +int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id, +volatile void **wake_addr, +uint64_t *expected,uint64_t *mask);It looks to be a very low-level API.
Can't we do something more "ready-to-use" at ethdev level?
I think that series provides both:
There is a low-level API at ethdev/eal to retrieve information to wait for and actual function to put core to sleep.
Plus there is a high-level API at rte_power lib:
rte_power_pmd_mgmt_queue_enable()/rte_power_pmd_mgmt_queue_disable() that uses these low-level ones and puts some high-level logic around it. From my perspective it is a good design choice,
as it keeps all power-related burden inside rte_power library and provides user a lot of flexibility in terms of API usage. Konstantin
Quoted 5 lines
Cc'in the relevant maintainers...
Note: sorry this comment come late but ethdev maintainers were not Cc.
Reminder: having no feedback is not a good sign, you should request comments.
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Jerin JacobQuoted 14 lines · Jerin Jacob
Quoted 13 lines · Thomas Monjalon
Quoted 13 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 11 lines
Quoted 4 lines
Quoted 1 line
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Quoted 7 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as functions[1] or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the instruction features which can NOT be abstracted as a generic feature across the architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.
[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , function rte_power_pmd_mgmt_queue_enable()
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.
Quoted 15 lines
If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.
[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , functionrte_power_pmd_mgmt_queue_enable()--
Thanks,
Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 54 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.
I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here... Might be just something like:
rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
/* not supported path */
}To check is that feature supported or not.
Quoted 15 lines
Quoted 15 lines
If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.
[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , functionrte_power_pmd_mgmt_queue_enable()--
Thanks,
Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Liang MaQuoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.
Quoted 259 lines
For more details, Please reference Intel SDM Volume 2.
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- .../include/generic/rte_power_intrinsics.h | 64 ++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/x86/include/meson.build | 1 + .../x86/include/rte_power_intrinsics.h | 143 ++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.hlib/librte_eal/include/generic/rte_power_intrinsics.h new file +64
-0@@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_H_ +#define _RTE_POWER_INTRINSIC_H_ + +#include <inttypes.h> + +/** +* @file +* Advanced power management operations. +* +* This file define APIs for advanced power management, +* which are architecture-dependent. +*/ + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp); + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* @param state +* Architecture-dependent optimized power state number +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp); + +#endif /* _RTE_POWER_INTRINSIC_H_ */ lib/librte_eal/include/meson.build +1
-0@@ -60,6 +60,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',lib/librte_eal/x86/include/meson.build +1
-0@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',lib/librte_eal/x86/include/rte_power_intrinsics.h new file +143
-1@@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_X86_64_H_ +#define _RTE_POWER_INTRINSIC_X86_64_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_atomic.h> +#include <rte_common.h> + +#include "generic/rte_power_intrinsics.h" + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, or a certain TSC timestamp is reached. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* This function uses UMONITOR/UMWAIT instructions. For more information about +* their usage, please refer to Intel(R) 64 and IA-32 Architectures Software +* Developer's Manual. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param state +* Architecture-dependent optimized power state number. Can be 0 (C0.2) or +* 1 (C0.1). +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to memory write or other reasons. +*/ +static inline int rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint32_t state,const uint64_t tsc_timestamp) +{ +const uint32_t tsc_l = (uint32_t )tsc_timestamp; +const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 ); +/* the rflags need match native register size */ +#ifdef RTE_ARCH_I686 +uint32_t rflags; +#else +uint64_t rflags; +#endif +/* +* we're using raw byte codes for now as only the newest compiler +* versions support this instruction natively. +*/ + +/* set address for UMONITOR */ + asmvolatile (".byte 0xf3, 0x0f, 0xae, 0xf7;" + : + :"D" (p)); + +if (value_mask) { +const uint64_t cur_value = *(const volatile uint64_t *)p; +const uint64_t masked = cur_value & value_mask; +/* if the masked value is already matching, abort */ +if (masked == expected_value) +return 0 ; + } +/* execute UMWAIT */ + asmvolatile (".byte 0xf2, 0x0f, 0xae, 0xf7;\n" +/* +* UMWAIT sets CF flag in RFLAGS, so PUSHF to push them +* onto the stack, then pop them back into `rflags` so that +* we can read it. +*/ +"pushf;\n" +"pop %0;\n" + :"=r" (rflags) + :"D" (state),"a" (tsc_l),"d" (tsc_h)); + +/* we're interested in the first bit (the carry flag) */ +return rflags &0x1 ; +} + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* This function uses TPAUSE instruction. For more information about its usage, +* please refer to Intel(R) 64 and IA-32 Architectures Software Developer's +* Manual. +* +* @param state +* Architecture-dependent optimized power state number. Can be 0 (C0.2) or +* 1 (C0.1). +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to other reasons. +*/ +static inline int rte_power_pause (const uint32_t state, +const uint64_t tsc_timestamp) +{ +const uint32_t tsc_l = (uint32_t )tsc_timestamp; +const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 ); +/* the rflags need match native register size */ +#ifdef RTE_ARCH_I686 +uint32_t rflags; +#else +uint64_t rflags; +#endif + +/* execute TPAUSE */ + asmvolatile (".byte 0x66, 0x0f, 0xae, 0xf7;\n" +/* +* TPAUSE sets CF flag in RFLAGS, so PUSHF to push them +* onto the stack, then pop them back into `rflags` so that +* we can read it. +*/ +"pushf;\n" +"pop %0;\n" + :"=r" (rflags) + :"D" (state),"a" (tsc_l),"d" (tsc_h)); + +/* we're interested in the first bit (the carry flag) */ +return rflags &0x1 ; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_POWER_INTRINSIC_X86_64_H_ */ --2.17.1
Re: [dpdk-dev] [PATCH v4 01/10] eal: add new x86 cpuid support for WAITPKG
In reply to Liang MaQuoted 30 lines
Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++ lib/librte_eal/x86/rte_cpuflags.c | 2 ++ 2 files changed, 4 insertions(+)lib/librte_eal/x86/include/rte_cpuflags.h +2
-0@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_MOVDIR64B ,/**< Direct Store Instructions 64B */ RTE_CPUFLAG_AVX512VP2INTERSECT ,/**< AVX512 Two Register Intersection */ +/**< UMWAIT/TPAUSE Instructions */ +RTE_CPUFLAG_WAITPKG ,/**< UMINITOR/UMWAIT/TPAUSE */ /* The last item */ RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */ };lib/librte_eal/x86/rte_cpuflags.c +0
-0
lib/librte_eal/x86/rte_cpuflags.c const struct feature_entry rte_cpu_feature_table[] = {
Quoted 9 lines
lib/librte_eal/x86/rte_cpuflags.c +2
-1@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 ) --
Quoted 1 line
2.17.1
Re: [dpdk-dev] [PATCH v4 03/10] ethdev: add simple power management API
In reply to Liang MaQuoted 26 lines
Add a simple API allow ethdev get wake up address from PMD. Also include internal structure update.
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_ethdev/rte_ethdev.c | 19 ++++++++++++++++ lib/librte_ethdev/rte_ethdev.h | 24 ++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 28 ++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 1 + 4 files changed, 72 insertions(+)lib/librte_ethdev/rte_ethdev.c +5
-0@@ -4804,6 +4804,25 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode)); } +int +rte_eth_get_wake_addr (uint16_t port_id,uint16_t queue_id, +volatile void **wake_addr, +uint64_t *expected,uint64_t *mask) +{
lib/librte_ethdev/rte_ethdev.c rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, · line 4821
Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10
-0+struct rte_eth_dev *dev; +uint16_t ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + + dev = &rte_eth_devices[port_id]; + + ret = (*dev->dev_ops->get_wake_addr) + (dev->data->rx_queues[queue_id], + wake_addr, expected, mask);
This is an optional dev_ops, so I think you need to check that get_wake_addr() is defined for that PMD.
Plus you need to check that queue_id is valid.
Quoted 102 lines
lib/librte_ethdev/rte_ethdev.c +4
-0+ +return ret; +} + int rte_eth_dev_set_mc_addr_list(uint16_t port_id, struct rte_ether_addr *mc_addr_set,lib/librte_ethdev/rte_ethdev.h +24
-0@@ -4014,6 +4014,30 @@ __rte_experimentalint rte_eth_tx_burst_mode_get (uint16_t port_id,uint16_t queue_id,struct rte_eth_burst_mode *mode); +/** +* Retrieve the wake up address from specific queue +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The Tx queue on the Ethernet device for which information +* will be retrieved. +* @param wake_addr +* The pointer point to the address which is used for monitoring. +* @param expected +* The pointer point to value to be expected when descriptor is set. +* @param mask +* The pointer point to comparison bitmask for the expected value. +* +* @return +* - 0: Success. +* -EINVAL: Failed to get wake address. +*/ +__rte_experimental +int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id, +volatile void **wake_addr, +uint64_t *expected,uint64_t *mask); +/** * Retrieve device registers and register attributes (number of registers and * register size) lib/librte_ethdev/rte_ethdev_driver.h +28
-0@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)uint16_t nb_tx_desc, const struct rte_eth_hairpin_conf *hairpin_conf); +/** +* @internal +* Get the Wake up address. +* +* @param rxq +* Ethdev queue pointer. +* @param tail_desc_addr +* The pointer point to descriptor address var. +* @param expected +* The pointer point to value to be expected when descriptor is set. +* @param mask +* The pointer point to comparison bitmask for the expected value. +* @return +* Negative errno value on error, 0 on success. +* +* @retval 0 +* Success. +* @retval -EINVAL +* Failed to get descriptor address. +*/ +typedef int (*eth_get_wake_addr_t ) + (void *rxq,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask); + +/** * @internal A structure containing the functions exported by an Ethernet driver. */ @@ -713,6 +738,9 @@ struct eth_dev_ops {/**< Set up device RX hairpin queue. */ eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;/**< Set up device TX hairpin queue. */ +eth_get_wake_addr_t get_wake_addr; +/**< Get wake up address. */ + };/** lib/librte_ethdev/rte_ethdev_version.map +1
-1@@ -229,6 +229,7 @@ EXPERIMENTAL { # added in 20.11 rte_eth_link_speed_to_str; rte_eth_link_to_str; + rte_eth_get_wake_addr; }; INTERNAL { --2.17.1
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Ananyev, KonstantinQuoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.
Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.
Quoted 27 lines
Might be just something like:
rte_power_monitor(...)==-ENOTSUP
be enough indication for that?
So user can just do:if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Quoted 15 lines
Quoted 15 lines
If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.
[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , functionrte_power_pmd_mgmt_queue_enable()--
Thanks,
Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Ananyev, KonstantinQuoted 13 lines · Konstantin
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 6 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 3 lines
I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.
I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Jerin JacobQuoted 67 lines · Jerin Jacob
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...
Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...)==-ENOTSUP
be enough indication for that?
So user can just do:if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.
[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , functionrte_power_pmd_mgmt_queue_enable()--
Thanks,
Anatoly
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
09/10/2020 11:25, Burakov, Anatoly:
Quoted 94 lines · Jerin Jacob
Quoted 67 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...)==-ENOTSUP
be enough indication for that?
So user can just do:if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Quoted 6 lines
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Sorry I don't understand what you mean, too many "it" and "this" :)
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 95 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 94 lines · Jerin Jacob
Quoted 92 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Quoted 9 lines
Quoted 6 lines
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 104 lines · Anatoly
Quoted 102 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 100 lines · Jerin Jacob
Quoted 67 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.
Quoted 9 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
--
Thanks,
Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 115 lines · Jerin Jacob
Quoted 104 lines · Anatoly
Quoted 102 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 100 lines · Jerin Jacob
Quoted 67 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
Quoted 6 lines
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific). I guess we could remove that and set return value to either 0 or -ENOTSUP if that would resolve the issue?
Quoted 5 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.
IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
Quoted 11 lines
Quoted 11 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
--
Thanks,
Anatoly
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
09/10/2020 12:03, Burakov, Anatoly:
Quoted 119 lines · Jerin Jacob
Quoted 111 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
Quoted 6 lines
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */
Quoted 2 lines
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).
Obviously an API definition should *never* be "implementation-defined".
Quoted 4 lines
I guess we could remove
that and set return value to either 0 or-ENOTSUPif that would resolve the issue?
Quoted 8 lines
Quoted 5 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
It is not call "power-x86", so we must assume it could work on any architecture.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Burakov, AnatolyQuoted 124 lines · Anatoly
Quoted 115 lines · Jerin Jacob
Quoted 104 lines · Anatoly
Quoted 102 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 100 lines · Jerin Jacob
Quoted 67 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
Quoted 8 lines
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 9 lines
Quoted 3 lines
IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as
functions[1]
Quoted 4 lines
or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not
rte_x86_..This will help the consumer to create workers based on the
instruction features
Quoted 8 lines
Quoted 1 line
which can NOT be abstracted as a generic feature across the
architectures.
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
Quoted 6 lines
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */
Quoted 4 lines
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific). I guess we could remove that and set return value to either 0 or
-ENOTSUPif that would resolve the issue?
returning -ENOTSUP should be OK if we don't to take generic feature-get framework path.
Quoted 9 lines
Quoted 6 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
Just checked now, librte_power compiles at least for arm64.
Quoted 17 lines
Quoted 4 lines
Quoted 4 lines
Quoted 8 lines
Quoted 8 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
--
Thanks,
Anatoly--
Thanks,
Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Thomas MonjalonQuoted 120 lines · Thomas Monjalon
09/10/2020 12:03, Burakov, Anatoly:
Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 14 lines
Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.
Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 12 lines
> IMO, We must introduce some arch feature-capability _get_ scheme to tell > the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the > API marked as generic ie rte_power_* notrte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.Quoted 5 lines
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */
Quoted 4 lines
Quoted 2 lines
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).
Obviously an API definition should *never* be "implementation-defined".
If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy rte_pause).
Quoted 12 lines
Quoted 12 lines
I guess we could remove
that and set return value to either 0 or-ENOTSUPif that would resolve the issue?Quoted 5 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.
Quoted 5 lines
Quoted 2 lines
IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
It is not call "power-x86", so we must assume it could work on any architecture.
#ifdef it is!
Quoted 10 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.
UMWAIT is a best-effort mechanism with no side-effects. It's perfectly legal for a UMWAIT to not sleep at all, thus rendering it effectively a noop. So i don't think it's all that different.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 159 lines · Anatoly
Quoted 120 lines · Thomas Monjalon
09/10/2020 12:03, Burakov, Anatoly:
Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 12 lines
> IMO, We must introduce some arch feature-capability _get_ scheme to tell > the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the > API marked as generic ie rte_power_* notrte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.Quoted 5 lines
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */Quoted 4 lines
Quoted 2 lines
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).
Obviously an API definition should *never* be "implementation-defined".
If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy
rte_pause).Quoted 12 lines
Quoted 12 lines
I guess we could remove
that and set return value to either 0 or-ENOTSUPif that would resolve the issue?Quoted 5 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.Quoted 5 lines
Quoted 2 lines
IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
It is not call "power-x86", so we must assume it could work on any architecture.
#ifdef it is!
Quoted 7 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
Quoted 7 lines
Quoted 3 lines
CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.
UMWAIT is a best-effort mechanism with no side-effects. It's perfectly legal for a UMWAIT to not sleep at all, thus rendering it effectively a noop. So i don't think it's all that different.
If a platform does not support UMWAIT in ALL case IMO, no consumer takes this the path for power saving. So IMO, t is different than CLDEMOTE
Quoted 4 lines
--
Thanks,
Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Burakov, AnatolyQuoted 143 lines · Thomas Monjalon
Quoted 120 lines
09/10/2020 12:03, Burakov, Anatoly:
Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlQuoted 3 lines
Also please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 12 lines
> IMO, We must introduce some arch feature-capability _get_ scheme to tell > the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the > API marked as generic ie rte_power_* notrte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.Quoted 5 lines
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */Quoted 4 lines
Quoted 2 lines
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).
Obviously an API definition should *never* be "implementation-defined".
If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy
rte_pause).Quoted 12 lines
Quoted 12 lines
I guess we could remove
that and set return value to either 0 or-ENOTSUPif that would resolve the issue?Quoted 5 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.
Quoted 13 lines
Quoted 5 lines
Quoted 2 lines
IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
It is not call "power-x86", so we must assume it could work on any architecture.
#ifdef it is!
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well
I wouldn't consider these two as totally equal.
Yes, both are just hints to CPU, that can be ignored,
but if not, then consequences of executing are quite different. If UMWAIT is not supported by cpu at all, then user might want to use some different power saving mechanism (pause, frequence scaling, etc.). Without information is UMWAIT supported or not, user can't make such choice.
Quoted 10 lines
, yet Jerin has acked that one and has explicitly
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.
UMWAIT is a best-effort mechanism with no side-effects. It's perfectly legal for a UMWAIT to not sleep at all, thus rendering it effectively a noop. So i don't think it's all that different.
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 157 lines · Konstantin
Quoted 143 lines · Thomas Monjalon
Quoted 120 lines
09/10/2020 12:03, Burakov, Anatoly:
Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
On Thu, Oct 8, 2020 at 2:04 PM Thomas Monjalon <[email protected]> wrote:
Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.Quoted 8 lines
Quoted 6 lines
Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlAlso please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 12 lines
> IMO, We must introduce some arch feature-capability _get_ scheme to tell > the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the > API marked as generic ie rte_power_* notrte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.Quoted 5 lines
I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?
Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */Quoted 4 lines
Quoted 2 lines
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).
Obviously an API definition should *never* be "implementation-defined".
If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy
rte_pause).Quoted 12 lines
Quoted 12 lines
I guess we could remove
that and set return value to either 0 or-ENOTSUPif that would resolve the issue?Quoted 5 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.Quoted 13 lines
Quoted 5 lines
Quoted 2 lines
IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
It is not call "power-x86", so we must assume it could work on any architecture.
#ifdef it is!
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well
Quoted 7 lines
I wouldn't consider these two as totally equal.
Yes, both are just hints to CPU, that can be ignored,
but if not, then consequences of executing are quite different. If UMWAIT is not supported by cpu at all, then user might want to use some different power saving mechanism (pause, frequence scaling, etc.). Without information is UMWAIT supported or not, user can't make such choice.
After some attempts at implementing this, i actually came to the conclusion that some generic way to check support for this feature is necessary, because we end up with a usability inconsistency:
1) on non-x86, if you call the function, it returns -ENOTSUP
2) on x86, since we're not checking CPUID flags on every single call, it'll either succeed, or crash the process - the burden is on the user to check for CPUID flags, but it can't be done in an arch agnostic way because the CPUID flags are only defined for x86, thus requiring a special code path for x86
Where would be the best place to add such an infrastructure? I'm thinking rte_cpuflags.h?
Quoted 15 lines
Quoted 11 lines
, yet Jerin has acked that one and has explicitly
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
stated that he's OK with leaving CLDEMOTE as a noop on other architectures.
CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.
UMWAIT is a best-effort mechanism with no side-effects. It's perfectly legal for a UMWAIT to not sleep at all, thus rendering it effectively a noop. So i don't think it's all that different.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 177 lines · Anatoly
Quoted 157 lines · Konstantin
Quoted 143 lines · Thomas Monjalon
Quoted 120 lines
09/10/2020 12:03, Burakov, Anatoly:
Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 28 lines · Anatoly
On 08-Oct-20 9:44 AM, Jerin Jacob wrote:
On Thu, Oct 8, 2020 at 2:04 PM Thomas Monjalon <[email protected]> wrote:Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlAlso please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
Quoted 17 lines
> IMO, We must introduce some arch feature-capability _get_ scheme to tell
> the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the
> API marked as generic ie rte_power_* not rte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we
will add those in future revisions, but what does your proposed runtime
check accomplish that cannot currently be done with CPUID flags?Quoted 4 lines
RTE_CPUFLAG_WAITPKGflag definition is not available in other architectures. i.eRTE_CPUFLAG_WAITPKGdefined inlib/librte_eal/x86/include/rte_cpuflags.hand it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */Quoted 4 lines
Quoted 2 lines
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).
Obviously an API definition should *never* be "implementation-defined".
If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy
rte_pause).Quoted 12 lines
Quoted 12 lines
I guess we could remove
that and set return value to either 0 or-ENOTSUPif that would resolve the issue?Quoted 5 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.Quoted 13 lines
Quoted 5 lines
Quoted 2 lines
IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
It is not call "power-x86", so we must assume it could work on any architecture.
#ifdef it is!
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well
Quoted 7 lines
I wouldn't consider these two as totally equal.
Yes, both are just hints to CPU, that can be ignored,
but if not, then consequences of executing are quite different. If UMWAIT is not supported by cpu at all, then user might want to use some different power saving mechanism (pause, frequence scaling, etc.). Without information is UMWAIT supported or not, user can't make such choice.After some attempts at implementing this, i actually came to the conclusion that some generic way to check support for this feature is necessary, because we end up with a usability inconsistency:
1) on non-x86, if you call the function, it returns
-ENOTSUP
2) on x86, since we're not checking CPUID flags on every single call, it'll either succeed, or crash the process - the burden is on the user to check for CPUID flags, but it can't be done in an arch agnostic way because the CPUID flags are only defined for x86, thus requiring a special code path for x86
Quoted 3 lines
Where would be the best place to add such an infrastructure? I'm thinking
rte_cpuflags.h?
Time to relook at some of the contents of patchset:
http://patches.dpdk.org/project/dpdk/list/?series=4811&archive=both&state=*
The idea of that set (IIRC) was to replace the per-architecture enums with just strings to avoid situations like this - or at least make them less awkward.
/Bruce
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 181 lines · Bruce Richardson
Quoted 177 lines · Anatoly
Quoted 157 lines · Konstantin
Quoted 143 lines · Thomas Monjalon
Quoted 120 lines
09/10/2020 12:03, Burakov, Anatoly:
Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon
09/10/2020 11:25, Burakov, Anatoly:
Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 56 lines
On Thu, Oct 8, 2020 at 6:57 PM Burakov, Anatoly
<[email protected]> wrote:
On 08-Oct-20 9:44 AM, Jerin Jacob wrote:
On Thu, Oct 8, 2020 at 2:04 PM Thomas Monjalon <[email protected]> wrote:Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.For more details, Please reference Intel SDM Volume 2.
I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.htmlAlso please mark the new functions as experimental.
Hi Jerin,
Hi Anatoly,
> IMO, We must introduce some arch feature-capability _get_ scheme to tell
> the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the
> API marked as generic ie rte_power_* not rte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.I'm not entirely sure what you mean by that.
I mean, yes, we should have added stubs for other architectures, and we
will add those in future revisions, but what does your proposed runtime
check accomplish that cannot currently be done with CPUID flags?RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures.
i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h
and it is used in http://patches.dpdk.org/patch/79540/ as generic API.
I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.Quoted 3 lines
I am agree with Jerin, that we need some generic way to figure-out does platform supports
power_monitor()or not. Though not sure do we need to create a new feature-get framework here...Quoted 25 lines
That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.Quoted 9 lines
Might be just something like:
rte_power_monitor(...) == -ENOTSUP be enough indication for that? So user can just do: if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) { /* not supported path */ }To check is that feature supported or not.
Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.
If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.
Quoted 8 lines
Quoted 2 lines
Sorry I don't understand what you mean, too many "it" and "this" :)
Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).
If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */Quoted 4 lines
Quoted 2 lines
In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).
Obviously an API definition should *never* be "implementation-defined".
If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy
rte_pause).Quoted 12 lines
Quoted 12 lines
I guess we could remove
that and set return value to either 0 or-ENOTSUPif that would resolve the issue?Quoted 5 lines
Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add-ENOTSUPreturn or generic feature-get framework.Quoted 13 lines
Quoted 5 lines
Quoted 2 lines
IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.
It is not call "power-x86", so we must assume it could work on any architecture.
#ifdef it is!
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well
Quoted 7 lines
I wouldn't consider these two as totally equal.
Yes, both are just hints to CPU, that can be ignored,
but if not, then consequences of executing are quite different. If UMWAIT is not supported by cpu at all, then user might want to use some different power saving mechanism (pause, frequence scaling, etc.). Without information is UMWAIT supported or not, user can't make such choice.After some attempts at implementing this, i actually came to the conclusion that some generic way to check support for this feature is necessary, because we end up with a usability inconsistency:
1) on non-x86, if you call the function, it returns
-ENOTSUP
2) on x86, since we're not checking CPUID flags on every single call, it'll either succeed, or crash the process - the burden is on the user to check for CPUID flags, but it can't be done in an arch agnostic way because the CPUID flags are only defined for x86, thus requiring a special code path for x86Quoted 3 lines
Where would be the best place to add such an infrastructure? I'm thinking
rte_cpuflags.h?
Quoted 9 lines
Time to relook at some of the contents of patchset:
http://patches.dpdk.org/project/dpdk/list/?series=4811&archive=both&state=*The idea of that set (IIRC) was to replace the per-architecture enums with just strings to avoid situations like this - or at least make them less awkward.
/Bruce
Yes, that patchset looks like it would work nicely in this case. If there is consensus to resurrect it and make it work, i'll drop the "generic feature get" thing, but for now i'll continue working on it - easier to remove code than to add it :D
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Burakov, AnatolyQuoted 15 lines · Konstantin
Quoted 13 lines
Quoted 12 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 9 lines
Quoted 3 lines
I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.
I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.
Yes, I think we either need a syscall that would do an IPI for us
(on top of my head - membarrier() does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:uint64_t val = atomic_load(addr);CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin
Re: [dpdk-dev] [PATCH v4 05/10] net/ixgbe: implement power management API
In reply to Liang MaQuoted 8 lines
Implement support for the power management API by implementing a
get_wake_addrfunction that will return an address of an RX ring's status bit.Signed-off-by Anatoly Burakov <[email protected]>Signed-off-by Liang Ma <[email protected]>---
Quoted 1 line
2.17.1
Re: [dpdk-dev] [PATCH v4 06/10] net/i40e: implement power management API
In reply to Liang MaQuoted 8 lines
Implement support for the power management API by implementing a
get_wake_addrfunction that will return an address of an RX ring's status bit.Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
Quoted 1 line
2.17.1
PATCH v5 1/10 eal: add new x86 cpuid support for WAITPKG
In reply to Liang MaFrom: Liang Ma <[email protected]>
Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.
--- lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++ lib/librte_eal/x86/rte_cpuflags.c | 2 ++ 2 files changed, 4 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_MOVDIR64B ,/**< Direct Store Instructions 64B */ RTE_CPUFLAG_AVX512VP2INTERSECT ,/**< AVX512 Two Register Intersection */ +/**< UMWAIT/TPAUSE Instructions */ +RTE_CPUFLAG_WAITPKG ,/**< UMINITOR/UMWAIT/TPAUSE */ /* The last item */ RTE_CPUFLAG_NUMFLAGS, /**< This should always be the last! */ };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = { FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16) FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18) + FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5) + FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX, 0)FEAT_DEF (LZCNT ,0x80000001 ,0 ,RTE_REG_ECX ,4 )
Signature · 1 line
2.17.1
PATCH v5 2/10 eal: add power management intrinsics
From: Liang Ma <[email protected]>
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.
---
Notes:
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs
lib/librte_eal/arm/include/meson.build | 1 + .../arm/include/rte_power_intrinsics.h | 62 ++++++++++ .../include/generic/rte_power_intrinsics.h | 61 ++++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/ppc/include/meson.build | 1 + .../ppc/include/rte_power_intrinsics.h | 62 ++++++++++ lib/librte_eal/x86/include/meson.build | 1 + .../x86/include/rte_power_intrinsics.h | 106 ++++++++++++++++++ 8 files changed, 295 insertions(+) create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/arm/include/meson.build +1 -0
@@ -20,6 +20,7 @@ arch_headers = files( 'rte_pause_32.h', 'rte_pause_64.h', 'rte_pause.h', + 'rte_power_intrinsics.h', 'rte_prefetch_32.h', 'rte_prefetch_64.h', 'rte_prefetch.h',
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +62 -0
62 lines not on this page · raw message
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +61 -0
61 lines not on this page · raw message
lib/librte_eal/include/meson.build +1 -0
@@ -60,6 +60,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',
lib/librte_eal/ppc/include/meson.build +1 -0
@@ -10,6 +10,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_pause.h', + 'rte_power_intrinsics.h', 'rte_prefetch.h', 'rte_rwlock.h', 'rte_spinlock.h',
lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +62 -0
62 lines not on this page · raw message
lib/librte_eal/x86/include/meson.build +1 -0
@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +106 -0
106 lines not on this page · raw message
Signature · 1 line
2.17.1
PATCH v5 3/10 eal: add intrinsics support check infrastructure
In reply to Anatoly BurakovCurrently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.
This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.
--- .../arm/include/rte_power_intrinsics.h | 8 ++++++ lib/librte_eal/arm/rte_cpuflags.c | 6 +++++ lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++ .../include/generic/rte_power_intrinsics.h | 8 ++++++ .../ppc/include/rte_power_intrinsics.h | 8 ++++++ lib/librte_eal/ppc/rte_cpuflags.c | 6 +++++ lib/librte_eal/rte_eal_version.map | 1 + .../x86/include/rte_power_intrinsics.h | 8 ++++++ lib/librte_eal/x86/rte_cpuflags.c | 12 +++++++++ 9 files changed, 83 insertions(+)
lib/librte_eal/arm/include/rte_power_intrinsics.h +8 -0
@@ -17,6 +17,10 @@ extern "C" {/** * This function is not supported on ARM. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param p * Address to monitor for changes. Must be aligned on an 64-byte boundary. * @param expected_value
@@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,/** * This function is not supported on ARM. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param tsc_timestamp * Maximum TSC timestamp to wait for. *
lib/librte_eal/arm/rte_cpuflags.c +6 -0
@@ -138,3 +138,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)return NULL ;return rte_cpu_feature_table[feature].name; } + +void +rte_cpu_get_intrinsics_support (struct rte_cpu_intrinsics *intrinsics) +{ +memset (intrinsics,0 ,sizeof (*intrinsics)); +}
lib/librte_eal/include/generic/rte_cpuflags.h +26 -0
@@ -13,6 +13,32 @@#include "rte_common.h" #include <errno.h> +#include <rte_compat.h> + +/** +* Structure used to describe platform-specific intrinsics that may or may not +* be supported at runtime. +*/ +struct rte_cpu_intrinsics { +uint32_t power_monitor :1 ; +/**< indicates support for rte_power_monitor function */ +uint32_t power_pause :1 ; +/**< indicates support for rte_power_pause function */ +}; + +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* Check CPU support for various intrinsics at runtime. +* +* @param intrinsics +* Pointer to a structure to be filled. +*/ +__rte_experimental +void +rte_cpu_get_intrinsics_support (struct rte_cpu_intrinsics *intrinsics); +/** * Enumeration of all CPU features supported */
lib/librte_eal/include/generic/rte_power_intrinsics.h +8 -0
@@ -26,6 +26,10 @@* checked against the expected value, and if they match, the entering of * optimized power state may be aborted. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param p * Address to monitor for changes. Must be aligned on an 64-byte boundary. * @param expected_value
@@ -49,6 +53,10 @@ static inline void rte_power_monitor(const volatile void *p,* Enter an architecture-defined optimized power state until a certain TSC * timestamp is reached. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param tsc_timestamp * Maximum TSC timestamp to wait for. Note that the wait behavior is * architecture-dependent.
lib/librte_eal/ppc/include/rte_power_intrinsics.h +8 -0
@@ -17,6 +17,10 @@ extern "C" {/** * This function is not supported on PPC64. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param p * Address to monitor for changes. Must be aligned on an 64-byte boundary. * @param expected_value
@@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,/** * This function is not supported on PPC64. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param tsc_timestamp * Maximum TSC timestamp to wait for. *
lib/librte_eal/ppc/rte_cpuflags.c +6 -0
@@ -108,3 +108,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)return NULL ;return rte_cpu_feature_table[feature].name; } + +void +rte_cpu_get_intrinsics_support (struct rte_cpu_intrinsics *intrinsics) +{ +memset (intrinsics,0 ,sizeof (*intrinsics)); +}
lib/librte_eal/rte_eal_version.map +1 -0
@@ -400,6 +400,7 @@ EXPERIMENTAL { # added in 20.11 __rte_eal_trace_generic_size_t; rte_service_lcore_may_be_active; + rte_cpu_get_intrinsics_support; }; INTERNAL {
lib/librte_eal/x86/include/rte_power_intrinsics.h +8 -0
@@ -29,6 +29,10 @@ extern "C" {* For more information about usage of these instructions, please refer to * Intel(R) 64 and IA-32 Architectures Software Developer's Manual. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param p * Address to monitor for changes. Must be aligned on an 64-byte boundary. * @param expected_value
@@ -80,6 +84,10 @@ static inline void rte_power_monitor(const volatile void *p,* information about usage of this instruction, please refer to Intel(R) 64 and * IA-32 Architectures Software Developer's Manual. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param tsc_timestamp * Maximum TSC timestamp to wait for. *
lib/librte_eal/x86/rte_cpuflags.c +12 -0
@@ -7,6 +7,7 @@#include <stdio.h> #include <errno.h> #include <stdint.h> +#include <string.h> #include "rte_cpuid.h"
@@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)return NULL ;return rte_cpu_feature_table[feature].name; } + +void +rte_cpu_get_intrinsics_support (struct rte_cpu_intrinsics *intrinsics) +{ +memset (intrinsics,0 ,sizeof (*intrinsics)); + +if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { + intrinsics->power_monitor =1 ; + intrinsics->power_pause =1 ; + } +}
Signature · 1 line
2.17.1
PATCH v5 4/10 ethdev: add simple power management API
In reply to Anatoly BurakovFrom: Liang Ma <[email protected]>
Add a simple API to allow getting address of next RX descriptor from the PMD, as well as release notes information.
---
Notes:
v5:
- Bring function format in line with other functions in the file
- Ensure the API is supported by the driver before calling it (Konstantin)
doc/guides/rel_notes/release_20_11.rst | 16 ++++++++++++++ lib/librte_ethdev/rte_ethdev.c | 17 ++++++++++++++ lib/librte_ethdev/rte_ethdev.h | 24 ++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 28 ++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 1 + 5 files changed, 86 insertions(+)
doc/guides/rel_notes/release_20_11.rst +16 -0
@@ -55,6 +55,11 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **ethdev: add 1 new EXPERIMENTAL API for PMD power management.** + + * ``rte_eth_get_wake_addr()`` + * add new eth_dev_ops ``get_wake_addr`` + * **Updated Broadcom bnxt driver.** Updated the Broadcom bnxt driver with new features and improvements, including:
@@ -136,6 +141,17 @@ New Features * Extern objects and functions can be plugged into the pipeline. * Transaction-oriented table updates. +* **Add PMD power management mechanism** + + 3 new Ethernet PMD power management mechanism is added through existing + RX callback infrastructure. + + * Add power saving scheme based on UMWAIT instruction (x86 only) + * Add power saving scheme based on ``rte_pause()`` + * Add power saving scheme based on frequency scaling through the power library + * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_enable()`` + * Add new EXPERIMENTAL API ``rte_power_pmd_mgmt_queue_disable()`` + Removed Items -------------
lib/librte_ethdev/rte_ethdev.c +17 -0
@@ -4804,6 +4804,23 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode)); } +int +rte_eth_get_wake_addr (uint16_t port_id,uint16_t queue_id, +volatile void **wake_addr,uint64_t *expected,uint64_t *mask) +{ +struct rte_eth_dev *dev; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + + dev = &rte_eth_devices[port_id]; + +RTE_FUNC_PTR_OR_ERR_RET (*dev->dev_ops->get_wake_addr, -ENOTSUP ); + +return eth_err (port_id, + dev->dev_ops->get_wake_addr (dev->data->rx_queues[queue_id], + wake_addr, expected, mask)); +} + int rte_eth_dev_set_mc_addr_list(uint16_t port_id, struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +24 -0
@@ -4014,6 +4014,30 @@ __rte_experimentalint rte_eth_tx_burst_mode_get (uint16_t port_id,uint16_t queue_id,struct rte_eth_burst_mode *mode); +/** +* Retrieve the wake up address from specific queue +* +* @param port_id +* The port identifier of the Ethernet device. +* @param queue_id +* The Tx queue on the Ethernet device for which information +* will be retrieved. +* @param wake_addr +* The pointer point to the address which is used for monitoring. +* @param expected +* The pointer point to value to be expected when descriptor is set. +* @param mask +* The pointer point to comparison bitmask for the expected value. +* +* @return +* - 0: Success. +* -EINVAL: Failed to get wake address. +*/ +__rte_experimental +int rte_eth_get_wake_addr(uint16_t port_id, uint16_t queue_id, +volatile void **wake_addr, +uint64_t *expected,uint64_t *mask); +/** * Retrieve device registers and register attributes (number of registers and * register size)
lib/librte_ethdev/rte_ethdev_driver.h +28 -0
@@ -574,6 +574,31 @@ typedef int (*eth_tx_hairpin_queue_setup_t)uint16_t nb_tx_desc, const struct rte_eth_hairpin_conf *hairpin_conf); +/** +* @internal +* Get the Wake up address. +* +* @param rxq +* Ethdev queue pointer. +* @param tail_desc_addr +* The pointer point to descriptor address var. +* @param expected +* The pointer point to value to be expected when descriptor is set. +* @param mask +* The pointer point to comparison bitmask for the expected value. +* @return +* Negative errno value on error, 0 on success. +* +* @retval 0 +* Success. +* @retval -EINVAL +* Failed to get descriptor address. +*/ +typedef int (*eth_get_wake_addr_t ) + (void *rxq,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask); + +/** * @internal A structure containing the functions exported by an Ethernet driver. */
@@ -713,6 +738,9 @@ struct eth_dev_ops {/**< Set up device RX hairpin queue. */ eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;/**< Set up device TX hairpin queue. */ +eth_get_wake_addr_t get_wake_addr; +/**< Get wake up address. */ + };/**
lib/librte_ethdev/rte_ethdev_version.map +1 -0
@@ -229,6 +229,7 @@ EXPERIMENTAL { # added in 20.11 rte_eth_link_speed_to_str; rte_eth_link_to_str; + rte_eth_get_wake_addr; }; INTERNAL {
Signature · 1 line
2.17.1
PATCH v5 5/10 power: add PMD power management API and callback
In reply to Anatoly BurakovFrom: Liang Ma <[email protected]>
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).
This design is using PMD RX callbacks.
1. UMWAIT/UMONITOR:
When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.
2. Pause instruction
Instead of move the core into deeper C state, this method uses the pause instruction to avoid busy polling.
3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.
---
Notes:
v5:
- Make error checking more robust
- Prevent initializing scaling if ACPI or PSTATE env wasn't set
- Prevent initializing UMWAIT path if PMD doesn't support get_wake_addr
- Add some debug logging
- Replace x86-specific code path to generic path using the intrinsic check
lib/librte_power/meson.build | 5 +- lib/librte_power/pmd_mgmt.h | 38 ++++ lib/librte_power/rte_power_pmd_mgmt.c | 244 +++++++++++++++++++++++++ lib/librte_power/rte_power_pmd_mgmt.h | 88 +++++++++ lib/librte_power/rte_power_version.map | 4 + 5 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 lib/librte_power/pmd_mgmt.h create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
lib/librte_power/meson.build +3 -2
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c', 'power_kvm_vm.c', 'guest_channel.c', 'rte_power_empty_poll.c', 'power_pstate_cpufreq.c', + 'rte_power_pmd_mgmt.c', 'power_common.c') -headers = files('rte_power.h','rte_power_empty_poll.h') -deps += ['timer'] +headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h') +deps += ['timer' ,'ethdev']
lib/librte_power/pmd_mgmt.h new file +38 -0
@@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2010-2020 Intel Corporation +*/ + +#ifndef _PMD_MGMT_H +#define _PMD_MGMT_H + +/** +* @file +* Power Management +*/ + +/** +* Possible power management states of an ethdev port. +*/ +enum pmd_mgmt_state { +/** Device power management is disabled. */ +PMD_MGMT_DISABLED =0 , +/** Device power management is enabled. */ +PMD_MGMT_ENABLED , +}; + +struct pmd_queue_cfg { +enum pmd_mgmt_state pwr_mgmt_state; +/**< Power mgmt Callback mode */ +enum rte_power_pmd_mgmt_type cb_mode; +/**< Empty poll number */ +uint16_t empty_poll_stats; +/**< Callback instance */ +const struct rte_eth_rxtx_callback *cur_cb; +} __rte_cache_aligned; + +struct pmd_port_cfg { +int ref_cnt; +struct pmd_queue_cfg *queue_cfg; +} __rte_cache_aligned; + +#endif
lib/librte_power/rte_power_pmd_mgmt.c new file +244 -0
244 lines not on this page · raw message
lib/librte_power/rte_power_pmd_mgmt.h new file +88 -0
88 lines not on this page · raw message
lib/librte_power/rte_power_version.map +4 -0
@@ -34,4 +34,8 @@ EXPERIMENTAL { rte_power_guest_channel_receive_msg; rte_power_poll_stat_fetch; rte_power_poll_stat_update; + # added in 20.11 + rte_power_pmd_mgmt_queue_enable; + rte_power_pmd_mgmt_queue_disable; + };
Signature · 1 line
2.17.1
PATCH v5 6/10 net/ixgbe: implement power management API
In reply to Anatoly BurakovFrom: Liang Ma <[email protected]>
Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.
--- drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 ++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 ++ 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = { .udp_tunnel_port_del = ixgbe_dev_udp_tunnel_port_del, .tm_ops_get = ixgbe_tm_ops_get, .tx_done_cleanup = ixgbe_dev_tx_done_cleanup, + .get_wake_addr = ixgbe_get_wake_addr, };/*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
@@ -1366,6 +1366,28 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +int ixgbe_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ixgbe_adv_rx_desc *rxdp; +struct ixgbe_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.upper.status_error; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + *mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + +return 0 ; +} +/* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */ static inline uint32_t ixgbe_rxd_pkt_info_to_pkt_type (uint32_t pkt_info,uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_queue_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_rx_port_offloads (struct rte_eth_dev *dev);uint64_t ixgbe_get_tx_queue_offloads (struct rte_eth_dev *dev); +int ixgbe_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
PATCH v5 7/10 net/i40e: implement power management API
In reply to Anatoly BurakovFrom: Liang Ma <[email protected]>
Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.
--- drivers/net/i40e/i40e_ethdev.c | 1 + drivers/net/i40e/i40e_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/i40e/i40e_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
@@ -513,6 +513,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = { .mtu_set = i40e_dev_mtu_set, .tm_ops_get = i40e_tm_ops_get, .tx_done_cleanup = i40e_tx_done_cleanup, + .get_wake_addr = i40e_get_wake_addr, };/* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
@@ -71,6 +71,29 @@#define I40E_TX_OFFLOAD_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK) +int +i40e_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +struct i40e_rx_queue *rxq = rx_queue; +volatile union i40e_rx_desc *rxdp; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.qword1.status_error_len; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + *mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); + +return 0 ; +} +static inline void i40e_rxd_to_vlan_tci (struct rte_mbuf *mb,volatile union i40e_rx_desc *rxdp) {
drivers/net/i40e/i40e_rxtx.h +2 -0
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts);uint16_t i40e_xmit_pkts_vec_avx2 (void *tx_queue,struct rte_mbuf **tx_pkts,uint16_t nb_pkts); +int i40e_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *value);/* For each value it means, datasheet of hardware can tell more details *
Signature · 1 line
2.17.1
PATCH v5 8/10 net/ice: implement power management API
In reply to Anatoly BurakovFrom: Liang Ma <[email protected]>
Implement support for the power management API by implementing a get_wake_addr function that will return an address of an RX ring's status bit.
--- drivers/net/ice/ice_ethdev.c | 1 + drivers/net/ice/ice_rxtx.c | 23 +++++++++++++++++++++++ drivers/net/ice/ice_rxtx.h | 2 ++ 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
@@ -216,6 +216,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .udp_tunnel_port_add = ice_dev_udp_tunnel_port_add, .udp_tunnel_port_del = ice_dev_udp_tunnel_port_del, .tx_done_cleanup = ice_tx_done_cleanup, + .get_wake_addr = ice_get_wake_addr, };/* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
@@ -25,6 +25,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;uint64_t rte_net_ice_dynflag_proto_xtr_ip_offset_mask; +int ice_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ice_rx_flex_desc *rxdp; +struct ice_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.status_error0; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + *mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); + +return 0 ; +} + +static inline uint8_t ice_proto_xtr_type_to_rxdid (uint8_t xtr_type) {
drivers/net/ice/ice_rxtx.h +2 -0
@@ -250,6 +250,8 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);int ice_fdir_programming (struct ice_pf *pf,struct ice_fltr_desc *fdir_desc);int ice_tx_done_cleanup (void *txq,uint32_t free_cnt); +int ice_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask);#define FDIR_PARSING_ENABLE_PER_QUEUE (ad, on) do { \ int i; \
Signature · 1 line
2.17.1
PATCH v5 9/10 examples/l3fwd-power: enable PMD power mgmt
In reply to Anatoly BurakovFrom: Liang Ma <[email protected]>
Add PMD power management feature support to l3fwd-power sample app.
---
Notes:
v5:
- Moved doc update here
- Some minor formatting fixes
.../sample_app_ug/l3_forward_power_man.rst | 13 ++++++ examples/l3fwd-power/main.c | 41 ++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +13 -0
@@ -109,6 +109,8 @@ where, * --telemetry: Telemetry mode. +* --pmd-mgmt: PMD power management mode. + See :doc:`l3_forward` for details. The L3fwd-power example reuses the L3fwd command line options.
@@ -459,3 +461,14 @@ reference cycles and accordingly busy rate is set to either 0% or The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``. + +PMD power management Mode +------------------------- + +The PMD power management mode support for ``l3fwd-power`` is a standalone mode, in this mode +``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific +port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API. + +.. code-block:: console + + ./examples/l3fwd-power/build/l3fwd-power --pmd-mgmt -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)"
examples/l3fwd-power/main.c +40 -1
95 lines not on this page · raw message
Signature · 1 line
2.17.1
PATCH v5 10/10 doc: update programmer's guide for power library
In reply to Anatoly BurakovFrom: Liang Ma <[email protected]>
Update programmer's guide to document PMD power management usage.
---
Notes:
v5:
- Moved l3fwd-power update to the l3fwd-power-related commit
- Some rewordings and clarifications
doc/guides/prog_guide/power_man.rst | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
doc/guides/prog_guide/power_man.rst +42 -0
@@ -192,6 +192,45 @@ User Cases ---------- The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA. +PMD Power Management API +------------------------ + +Abstract +~~~~~~~~ +Existing power management mechanisms require developers to change application +design or change code to make use of it. The PMD power management API provides a +convenient alternative by utilizing Ethernet PMD RX callbacks, and triggering +power saving whenever empty poll count reaches a certain number. + + * UMWAIT/UMONITOR + + This power saving scheme will put the CPU into optimized power state and use + the UMWAIT/UMONITOR instructions to monitor the Ethernet PMD RX descriptor + address, and wake the CPU up whenever there's new traffic. + + * Pause + + This power saving scheme will use the `rte_pause` function to avoid busy + polling. + + * Frequency scaling + + This power saving scheme will use existing power library functionality to + scale the core frequency up/down depending on traffic volume. + + +.. note:: + + Currently, this power management API is limited to mandatory mapping of 1 + queue to 1 core (multiple queues are supported, but they must be polled from + different cores). + +API Overview for PMD Power Management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* **Queue Enable**: Enable specific power scheme for certain queue/port/core + +* **Queue Disable**: Disable power scheme for certain queue/port/core + References ----------
@@ -200,3 +239,6 @@ References * The :doc:`../sample_app_ug/vm_power_management` chapter in the :doc:`../sample_app_ug/index` section. + +* The :doc:`../sample_app_ug/rxtx_callbacks` + chapter in the :doc:`../sample_app_ug/index` section.
Signature · 1 line
2.17.1
Re: [dpdk-dev] [PATCH v5 02/10] eal: add power management intrinsics
In reply to Anatoly BurakovQuoted 81 lines · Anatoly Burakov
From: Liang Ma <[email protected]>
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubslib/librte_eal/arm/include/meson.build | 1 + .../arm/include/rte_power_intrinsics.h | 62 ++++++++++ .../include/generic/rte_power_intrinsics.h | 61 ++++++++++ lib/librte_eal/include/meson.build | 1 + lib/librte_eal/ppc/include/meson.build | 1 + .../ppc/include/rte_power_intrinsics.h | 62 ++++++++++ lib/librte_eal/x86/include/meson.build | 1 + .../x86/include/rte_power_intrinsics.h | 106 ++++++++++++++++++ 8 files changed, 295 insertions(+) create mode 100644 lib/librte_eal/arm/include/rte_power_intrinsics.h create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h create mode 100644 lib/librte_eal/ppc/include/rte_power_intrinsics.h create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.hlib/librte_eal/arm/include/meson.build +1
-0@@ -20,6 +20,7 @@ arch_headers = files( 'rte_pause_32.h', 'rte_pause_64.h', 'rte_pause.h', + 'rte_power_intrinsics.h', 'rte_prefetch_32.h', 'rte_prefetch_64.h', 'rte_prefetch.h',lib/librte_eal/arm/include/rte_power_intrinsics.h new file +21
-0@@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_ARM_H_ +#define _RTE_POWER_INTRINSIC_ARM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_atomic.h> +#include <rte_common.h> + +#include "generic/rte_power_intrinsics.h" + +/** + * This function is not supported on ARM. + * + * @param p + * Address to monitor for changes. Must be aligned on an 64-byte boundary.
lib/librte_eal/arm/include/rte_power_intrinsics.h line 31
Quoted 10 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +10
-0+* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 0 on success
remove return as it is a void function
Quoted 316 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +31
-0+*/ +static inline void rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint64_t tsc_timestamp) +{ +RTE_SET_USED (p); +RTE_SET_USED (expected_value); +RTE_SET_USED (value_mask); +RTE_SET_USED (tsc_timestamp); +} + +/** +* This function is not supported on ARM. +* +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to other reasons. +*/ +static inline void rte_power_pause (const uint64_t tsc_timestamp) +{ +RTE_SET_USED (tsc_timestamp); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_POWER_INTRINSIC_ARM_H_ */ lib/librte_eal/include/generic/rte_power_intrinsics.h new file +61
-0@@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_H_ +#define _RTE_POWER_INTRINSIC_H_ + +#include <inttypes.h> + +/** +* @file +* Advanced power management operations. +* +* This file define APIs for advanced power management, +* which are architecture-dependent. +*/ + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, a certain TSC timestamp is reached, or other +* reasons cause the CPU to wake up. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* - 0 on success +* - -ENOTSUP if not supported +*/ +static inline void rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint64_t tsc_timestamp); + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* Architecture-dependent return value. +*/ +static inline void rte_power_pause (const uint64_t tsc_timestamp); + +#endif /* _RTE_POWER_INTRINSIC_H_ */ lib/librte_eal/include/meson.build +1
-0@@ -60,6 +60,7 @@ generic_headers = files( 'generic/rte_memcpy.h', 'generic/rte_pause.h', 'generic/rte_prefetch.h', + 'generic/rte_power_intrinsics.h', 'generic/rte_rwlock.h', 'generic/rte_spinlock.h', 'generic/rte_ticketlock.h',lib/librte_eal/ppc/include/meson.build +1
-0@@ -10,6 +10,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_pause.h', + 'rte_power_intrinsics.h', 'rte_prefetch.h', 'rte_rwlock.h', 'rte_spinlock.h',lib/librte_eal/ppc/include/rte_power_intrinsics.h new file +62
-0@@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_PPC_H_ +#define _RTE_POWER_INTRINSIC_PPC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_atomic.h> +#include <rte_common.h> + +#include "generic/rte_power_intrinsics.h" + +/** +* This function is not supported on PPC64. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 0 on success +*/ +static inline void rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint64_t tsc_timestamp) +{ +RTE_SET_USED (p); +RTE_SET_USED (expected_value); +RTE_SET_USED (value_mask); +RTE_SET_USED (tsc_timestamp); +} + +/** +* This function is not supported on PPC64. +* +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to other reasons. +*/ +static inline void rte_power_pause (const uint64_t tsc_timestamp) +{ +RTE_SET_USED (tsc_timestamp); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_POWER_INTRINSIC_PPC_H_ */ lib/librte_eal/x86/include/meson.build +1
-0@@ -13,6 +13,7 @@ arch_headers = files( 'rte_io.h', 'rte_memcpy.h', 'rte_prefetch.h', + 'rte_power_intrinsics.h', 'rte_pause.h', 'rte_rtm.h', 'rte_rwlock.h',lib/librte_eal/x86/include/rte_power_intrinsics.h new file +106
-1@@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2020 Intel Corporation +*/ + +#ifndef _RTE_POWER_INTRINSIC_X86_64_H_ +#define _RTE_POWER_INTRINSIC_X86_64_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rte_atomic.h> +#include <rte_common.h> + +#include "generic/rte_power_intrinsics.h" + +/** +* Monitor specific address for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either the specified +* memory address is written to, a certain TSC timestamp is reached, or other +* reasons cause the CPU to wake up. +* +* Additionally, an `expected` 64-bit value and 64-bit mask are provided. If +* mask is non-zero, the current value pointed to by the `p` pointer will be +* checked against the expected value, and if they match, the entering of +* optimized power state may be aborted. +* +* This function uses UMONITOR/UMWAIT instructions and will enter C0.2 state. +* For more information about usage of these instructions, please refer to +* Intel(R) 64 and IA-32 Architectures Software Developer's Manual. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 0 on success +*/ +static inline void rte_power_monitor (const volatile void *p, +const uint64_t expected_value,const uint64_t value_mask, +const uint64_t tsc_timestamp) +{ +const uint32_t tsc_l = (uint32_t )tsc_timestamp; +const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 ); +/* +* we're using raw byte codes for now as only the newest compiler +* versions support this instruction natively. +*/ + +/* set address for UMONITOR */ + asmvolatile (".byte 0xf3, 0x0f, 0xae, 0xf7;" + : + :"D" (p)); + +if (value_mask) { +const uint64_t cur_value = *(const volatile uint64_t *)p; +const uint64_t masked = cur_value & value_mask; +/* if the masked value is already matching, abort */ +if (masked == expected_value) +return ; + } +/* execute UMWAIT */ + asmvolatile (".byte 0xf2, 0x0f, 0xae, 0xf7;" + :/* ignore rflags */ + :"D" (0 ),/* enter C0.2 */ +"a" (tsc_l),"d" (tsc_h)); +} + +/** +* Enter an architecture-defined optimized power state until a certain TSC +* timestamp is reached. +* +* This function uses TPAUSE instruction and will enter C0.2 state. For more +* information about usage of this instruction, please refer to Intel(R) 64 and +* IA-32 Architectures Software Developer's Manual. +* +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. +* +* @return +* - 1 if wakeup was due to TSC timeout expiration. +* - 0 if wakeup was due to other reasons. +*/ +static inline void rte_power_pause (const uint64_t tsc_timestamp) +{ +const uint32_t tsc_l = (uint32_t )tsc_timestamp; +const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 ); + +/* execute TPAUSE */ + asmvolatile (".byte 0x66, 0x0f, 0xae, 0xf7;" + :/* ignore rflags */ + :"D" (0 ),/* enter C0.2 */ +"a" (tsc_l),"d" (tsc_h)); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_POWER_INTRINSIC_X86_64_H_ */ --2.17.1
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Ananyev, KonstantinQuoted 25 lines · Konstantin
Quoted 15 lines · Konstantin
Quoted 13 lines
Quoted 12 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 9 lines
Quoted 3 lines
I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.
I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.
Quoted 16 lines
Yes, I think we either need a syscall that would do an IPI for us
(on top of my head -membarrier()does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:uint64_tval =atomic_load(addr);CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin
This implies knowing the value the core is sleeping on. That's not always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 03/10] ethdev: add simple power management API
In reply to Ananyev, KonstantinQuoted 33 lines · Konstantin
Quoted 33 lines
Add a simple API allow ethdev get wake up address from PMD. Also include internal structure update.
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_ethdev/rte_ethdev.c | 19 ++++++++++++++++ lib/librte_ethdev/rte_ethdev.h | 24 ++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_driver.h | 28 ++++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev_version.map | 1 + 4 files changed, 72 insertions(+)lib/librte_ethdev/rte_ethdev.c +12
-0@@ -4804,6 +4804,25 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode)); } +int +rte_eth_get_wake_addr (uint16_t port_id,uint16_t queue_id, +volatile void **wake_addr, +uint64_t *expected,uint64_t *mask) +{ +struct rte_eth_dev *dev; +uint16_t ret; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -ENODEV ); + +dev = &rte_eth_devices[port_id]; +
Quoted 9 lines
lib/librte_ethdev/rte_ethdev.c rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id, · line 4821
Quoted 3 lines
lib/librte_ethdev/rte_ethdev.c +3
-0+ret = (*dev->dev_ops->get_wake_addr) +(dev->data->rx_queues[queue_id], + wake_addr, expected, mask);This is an optional
dev_ops, so I think you need to check thatget_wake_addr()is defined for that PMD.
Plus you need to check thatqueue_idis valid.
Sorry, added dev_ops check but left out the queue id part :( Will fix in v6.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v5 02/10] eal: add power management intrinsics
In reply to Jerin JacobQuoted 29 lines · Jerin Jacob
Quoted 27 lines · Anatoly Burakov
From: Liang Ma <[email protected]>
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
For more details, please refer to Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2.
Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v5:
- Removed return values
- Simplified intrinsics and hardcoded C0.2 state
- Added other arch stubs
<snip>
Quoted 11 lines
Quoted 11 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h new file +11
-0+ +/** +* This function is not supported on ARM. +* +* @param p +* Address to monitor for changes. Must be aligned on an 64-byte boundary. +* @param expected_value +* Before attempting the monitoring, the `p` address may be read and compared +* against this value. If `value_mask` is zero, this step will be skipped. +* @param value_mask +* The 64-bit mask to use to extract current value from `p`.
Quoted 8 lines
Quoted 5 lines
+ * @param
tsc_timestamp
+ * Maximum TSC timestamp to wait for.
+ *
+ * @return
+ * - 0 on successremove return as it is a void function
Oops, will fix in v6. Thanks!
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 04/10] power: add simple power management API and callback
In reply to Liang MaQuoted 137 lines
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API support 1 port to multiple core use case.
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to relief the processor from busy polling.
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_power/meson.build | 5 +- lib/librte_power/pmd_mgmt.h | 49 ++++++ lib/librte_power/rte_power_pmd_mgmt.c | 208 +++++++++++++++++++++++++ lib/librte_power/rte_power_pmd_mgmt.h | 88 +++++++++++ lib/librte_power/rte_power_version.map | 4 + 5 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 lib/librte_power/pmd_mgmt.h create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c create mode 100644 lib/librte_power/rte_power_pmd_mgmt.hlib/librte_power/meson.build +3
-2@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c', 'power_kvm_vm.c', 'guest_channel.c', 'rte_power_empty_poll.c', 'power_pstate_cpufreq.c', + 'rte_power_pmd_mgmt.c', 'power_common.c') -headers = files('rte_power.h','rte_power_empty_poll.h') -deps += ['timer'] +headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h') +deps += ['timer' ,'ethdev']lib/librte_power/pmd_mgmt.h new file +49
-0@@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2010-2020 Intel Corporation +*/ + +#ifndef _PMD_MGMT_H +#define _PMD_MGMT_H + +/** +* @file +* Power Management +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Possible power management states of an ethdev port. +*/ +enum pmd_mgmt_state { +/** Device power management is disabled. */ +PMD_MGMT_DISABLED =0 , +/** Device power management is enabled. */ +PMD_MGMT_ENABLED , +}; + +struct pmd_queue_cfg { +enum pmd_mgmt_state pwr_mgmt_state; +/**< Power mgmt Callback mode */ +enum rte_power_pmd_mgmt_type cb_mode; +/**< Empty poll number */ +uint16_t empty_poll_stats; +/**< Callback instance */ +const struct rte_eth_rxtx_callback *cur_cb; +} __rte_cache_aligned; + +struct pmd_port_cfg { +int ref_cnt; +struct pmd_queue_cfg *queue_cfg; +} __rte_cache_aligned; + + + + +#ifdef __cplusplus +} +#endif + +#endif lib/librte_power/rte_power_pmd_mgmt.c new file +21
-0@@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2010-2020 Intel Corporation +*/ + +#include <rte_lcore.h> +#include <rte_cycles.h> +#include <rte_malloc.h> +#include <rte_ethdev.h> +#include <rte_power_intrinsics.h> + +#include "rte_power_pmd_mgmt.h" +#include "pmd_mgmt.h" + + +#define EMPTYPOLL_MAX 512 +#define PAUSE_NUM 64 + +static struct pmd_port_cfg port_cfg[RTE_MAX_ETHPORTS ]; + +static uint16_t +rte_power_mgmt_umwait(uint16_t port_id, uint16_t qidx,
lib/librte_power/rte_power_pmd_mgmt.c line 31
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+ struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ + + struct pmd_queue_cfg *q_conf; + q_conf = &port_cfg[port_id].queue_cfg[qidx]; + +if (unlikely (nb_rx ==0 )) { + q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) {
Here and in other places - wouldn't it be better to empty_poll_max as configurable parameter, instead of constant value?
Quoted 7 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +7
-0+volatile void *target_addr; +uint64_t expected, mask; +uint16_t ret; + +/* +* get address of next descriptor in the RX +* ring for this queue, as well as expected
lib/librte_power/rte_power_pmd_mgmt.c line 48
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+* value and a mask. +*/ + ret =rte_eth_get_wake_addr (port_id, qidx, + &target_addr, &expected, + &mask); +if (ret ==0 ) +/* -1ULL is maximum value for TSC */ +rte_power_monitor (target_addr, + expected, mask, +0 ,-1ULL );
Why not make timeout a user specified parameter?
Quoted 11 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +11
-0+ } + }else + q_conf->empty_poll_stats =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_pause (uint16_t port_id,uint16_t qidx, + struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused)
lib/librte_power/rte_power_pmd_mgmt.c line 69
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+{ +struct pmd_queue_cfg *q_conf; +int i; + q_conf = &port_cfg[port_id].queue_cfg[qidx]; + +if (unlikely (nb_rx ==0 )) { + q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) { +for (i =0 ; i <PAUSE_NUM ; i++) +rte_pause ();
Just rte_delay_us(timeout) instead of this loop?
Quoted 21 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +21
-0+ } + }else + q_conf->empty_poll_stats =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_scalefreq (uint16_t port_id,uint16_t qidx, + struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, + uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct pmd_queue_cfg *q_conf; + q_conf = &port_cfg[port_id].queue_cfg[qidx]; + +if (unlikely (nb_rx ==0 )) { + q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) { +/*scale down freq */ +rte_power_freq_min (rte_lcore_id ()); +
lib/librte_power/rte_power_pmd_mgmt.c line 100
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+ } + }else { + q_conf->empty_poll_stats =0 ; +/* scal up freq */ +rte_power_freq_max (rte_lcore_id ()); + } + +return nb_rx; +} +
Probably worth to mention in comments that these functions enable/disable are not MT safe.
Quoted 43 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +43
-0+int +rte_power_pmd_mgmt_queue_enable (unsigned int lcore_id, +uint16_t port_id, +uint16_t queue_id, +enum rte_power_pmd_mgmt_type mode) +{ +struct rte_eth_dev *dev; +struct pmd_queue_cfg *queue_cfg; +int ret =0 ; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); + dev = &rte_eth_devices[port_id]; + +if (port_cfg[port_id].queue_cfg ==NULL ) { + port_cfg[port_id].ref_cnt =0 ; +/* allocate memory for empty poll stats */ + port_cfg[port_id].queue_cfg =rte_malloc_socket (NULL , +sizeof (struct pmd_queue_cfg ) + *RTE_MAX_QUEUES_PER_PORT , +0 , dev->data->numa_node); +if (port_cfg[port_id].queue_cfg ==NULL ) +return -ENOMEM ; + } + + queue_cfg = &port_cfg[port_id].queue_cfg[queue_id]; + +if (queue_cfg->pwr_mgmt_state ==PMD_MGMT_ENABLED ) { + ret = -EINVAL ; + goto failure_handler; + } + +switch (mode) { +case RTE_POWER_MGMT_TYPE_WAIT : +if (!rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { + ret = -ENOTSUP ; + goto failure_handler; + } + queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, + rte_power_mgmt_umwait,NULL ); +break ; +case RTE_POWER_MGMT_TYPE_SCALE : +/* init scale freq */ +if (rte_power_init (lcore_id)) {
lib/librte_power/rte_power_pmd_mgmt.c line 153
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+ ret = -EINVAL ; + goto failure_handler; + } + queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, + rte_power_mgmt_scalefreq,NULL ); +break ; +case RTE_POWER_MGMT_TYPE_PAUSE : + queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, + rte_power_mgmt_pause,NULL ); +break ;
default: ....
Quoted 21 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +21
-0+ } + queue_cfg->cb_mode = mode; + port_cfg[port_id].ref_cnt++; + queue_cfg->pwr_mgmt_state =PMD_MGMT_ENABLED ; +return ret; + +failure_handler: +if (port_cfg[port_id].ref_cnt ==0 ) { +rte_free (port_cfg[port_id].queue_cfg); + port_cfg[port_id].queue_cfg =NULL ; + } +return ret; +} + +int +rte_power_pmd_mgmt_queue_disable (unsigned int lcore_id, +uint16_t port_id, +uint16_t queue_id) +{ +struct pmd_queue_cfg *queue_cfg; +
lib/librte_power/rte_power_pmd_mgmt.c line 184
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+if (port_cfg[port_id].ref_cnt <=0 ) +return -EINVAL ; + + queue_cfg = &port_cfg[port_id].queue_cfg[queue_id]; + +if (queue_cfg->pwr_mgmt_state ==PMD_MGMT_DISABLED ) +return -EINVAL ; + +switch (queue_cfg->cb_mode) { +case RTE_POWER_MGMT_TYPE_WAIT :
Think we need wakeup(lcore_id) here.
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+case RTE_POWER_MGMT_TYPE_PAUSE : +rte_eth_remove_rx_callback (port_id, queue_id, + queue_cfg->cur_cb); +break ; +case RTE_POWER_MGMT_TYPE_SCALE : +rte_power_freq_max (lcore_id); +rte_eth_remove_rx_callback (port_id, queue_id, + queue_cfg->cur_cb); +rte_power_exit (lcore_id); +break ;
lib/librte_power/rte_power_pmd_mgmt.c line 204
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+ } +/* it's not recommend to free callback instance here. +* it cause memory leak which is a known issue. +*/ + queue_cfg->cur_cb =NULL ; + queue_cfg->pwr_mgmt_state =PMD_MGMT_DISABLED ; + port_cfg[port_id].ref_cnt--; + +if (port_cfg[port_id].ref_cnt ==0 ) { +rte_free (port_cfg[port_id].queue_cfg);
It is not safe to do so, unless device is already stopped.
Otherwise you need some sync mechanism here (hand-made as bpf lib, or rcu online/offline, or...)
Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4
-0+ port_cfg[port_id].queue_cfg =NULL ; + } +return 0 ; +}
Re: [dpdk-dev] [PATCH v4 04/10] power: add simple power management API and callback
Quoted 143 lines · Konstantin
Quoted 143 lines
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API support 1 port to multiple core use case.
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to relief the processor from busy polling.
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_power/meson.build | 5 +- lib/librte_power/pmd_mgmt.h | 49 ++++++ lib/librte_power/rte_power_pmd_mgmt.c | 208 +++++++++++++++++++++++++ lib/librte_power/rte_power_pmd_mgmt.h | 88 +++++++++++ lib/librte_power/rte_power_version.map | 4 + 5 files changed, 352 insertions(+), 2 deletions(-)create mode 100644
lib/librte_power/pmd_mgmt.hcreate mode 100644lib/librte_power/rte_power_pmd_mgmt.ccreate mode 100644lib/librte_power/rte_power_pmd_mgmt.hlib/librte_power/meson.build +3
-2@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c', 'power_kvm_vm.c', 'guest_channel.c', 'rte_power_empty_poll.c', 'power_pstate_cpufreq.c', +'rte_power_pmd_mgmt.c', 'power_common.c') -headers = files('rte_power.h','rte_power_empty_poll.h') -deps += ['timer'] +headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h') +deps += ['timer' ,'ethdev']lib/librte_power/pmd_mgmt.h new file +49
-0@@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2010-2020 Intel Corporation +*/ + +#ifndef _PMD_MGMT_H +#define _PMD_MGMT_H + +/** +* @file +* Power Management +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Possible power management states of an ethdev port. +*/ +enum pmd_mgmt_state { +/** Device power management is disabled. */ +PMD_MGMT_DISABLED =0 , +/** Device power management is enabled. */ +PMD_MGMT_ENABLED , +}; + +struct pmd_queue_cfg { +enum pmd_mgmt_state pwr_mgmt_state; +/**< Power mgmt Callback mode */ +enum rte_power_pmd_mgmt_type cb_mode; +/**< Empty poll number */ +uint16_t empty_poll_stats; +/**< Callback instance */ +const struct rte_eth_rxtx_callback *cur_cb; +} __rte_cache_aligned; + +struct pmd_port_cfg { +int ref_cnt; +struct pmd_queue_cfg *queue_cfg; +} __rte_cache_aligned; + + + + +#ifdef __cplusplus +} +#endif + +#endif lib/librte_power/rte_power_pmd_mgmt.c new file +27
-0@@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2010-2020 Intel Corporation +*/ + +#include <rte_lcore.h> +#include <rte_cycles.h> +#include <rte_malloc.h> +#include <rte_ethdev.h> +#include <rte_power_intrinsics.h> + +#include "rte_power_pmd_mgmt.h" +#include "pmd_mgmt.h" + + +#define EMPTYPOLL_MAX 512 +#define PAUSE_NUM 64 + +static struct pmd_port_cfg port_cfg[RTE_MAX_ETHPORTS ]; + +static uint16_t +rte_power_mgmt_umwait (uint16_t port_id,uint16_t qidx, +struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, +uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ + +struct pmd_queue_cfg *q_conf; +q_conf = &port_cfg[port_id].queue_cfg[qidx];
Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 31
Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4
-0+ +if (unlikely (nb_rx ==0 )) { +q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) {Here and in other places - wouldn't it be better to
empty_poll_maxas configurable parameter, instead of constant value?
It would be more flexible, but i don't think it's "better" in the sense that providing additional options will only make using this (already under-utilized!) API harder than it needs to be.
Quoted 13 lines
Quoted 13 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +12
-0+volatile void *target_addr; +uint64_t expected, mask; +uint16_t ret; + +/* +* get address of next descriptor in the RX +* ring for this queue, as well as expected +* value and a mask. +*/ +ret =rte_eth_get_wake_addr (port_id, qidx, + &target_addr, &expected, + &mask);
Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 48
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5
-0+if (ret ==0 ) +/* -1ULL is maximum value for TSC */ +rte_power_monitor (target_addr, + expected, mask, +0 ,-1ULL );Why not make timeout a user specified parameter?
This is meant to be an "easy to use" API, we were trying to keep the amount of configuration to an absolute minimum. If the user wants to use custom timeouts, they can do so with using rte_power_monitor API explicitly.
Quoted 16 lines
Quoted 16 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +15
-0+} +}else +q_conf->empty_poll_stats =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_pause (uint16_t port_id,uint16_t qidx, +struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, +uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct pmd_queue_cfg *q_conf; +int i; +q_conf = &port_cfg[port_id].queue_cfg[qidx];
Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 69
Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +6
-0+ +if (unlikely (nb_rx ==0 )) { +q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) { +for (i =0 ; i <PAUSE_NUM ; i++) +rte_pause ();Just
rte_delay_us(timeout)instead of this loop?
Yes, seems better, thanks.
Quoted 27 lines
Quoted 27 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +26
-0+} +}else +q_conf->empty_poll_stats =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_scalefreq (uint16_t port_id,uint16_t qidx, +struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, +uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct pmd_queue_cfg *q_conf; +q_conf = &port_cfg[port_id].queue_cfg[qidx]; + +if (unlikely (nb_rx ==0 )) { +q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) { +/*scale down freq */ +rte_power_freq_min (rte_lcore_id ()); + +} +}else { +q_conf->empty_poll_stats =0 ; +/* scal up freq */ +rte_power_freq_max (rte_lcore_id ());
Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 55
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5
-0+} + +return nb_rx; +} +Probably worth to mention in comments that these functions enable/disable are not MT safe.
Will do in v6.
Quoted 49 lines
Quoted 49 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +48
-0+int +rte_power_pmd_mgmt_queue_enable (unsigned int lcore_id, +uint16_t port_id, +uint16_t queue_id, +enum rte_power_pmd_mgmt_type mode) +{ +struct rte_eth_dev *dev; +struct pmd_queue_cfg *queue_cfg; +int ret =0 ; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); +dev = &rte_eth_devices[port_id]; + +if (port_cfg[port_id].queue_cfg ==NULL ) { +port_cfg[port_id].ref_cnt =0 ; +/* allocate memory for empty poll stats */ +port_cfg[port_id].queue_cfg =rte_malloc_socket (NULL , +sizeof (struct pmd_queue_cfg ) +*RTE_MAX_QUEUES_PER_PORT , +0 , dev->data->numa_node); +if (port_cfg[port_id].queue_cfg ==NULL ) +return -ENOMEM ; +} + +queue_cfg = &port_cfg[port_id].queue_cfg[queue_id]; + +if (queue_cfg->pwr_mgmt_state ==PMD_MGMT_ENABLED ) { +ret = -EINVAL ; +goto failure_handler; +} + +switch (mode) { +case RTE_POWER_MGMT_TYPE_WAIT : +if (!rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { +ret = -ENOTSUP ; +goto failure_handler; +} +queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, +rte_power_mgmt_umwait,NULL ); +break ; +case RTE_POWER_MGMT_TYPE_SCALE : +/* init scale freq */ +if (rte_power_init (lcore_id)) { +ret = -EINVAL ; +goto failure_handler; +} +queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, +rte_power_mgmt_scalefreq,NULL );
Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 153
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5
-0+break ; +case RTE_POWER_MGMT_TYPE_PAUSE : +queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, +rte_power_mgmt_pause,NULL ); +break ;default:
....
Will add in v6.
Quoted 26 lines
Quoted 26 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +25
-0+} +queue_cfg->cb_mode = mode; +port_cfg[port_id].ref_cnt++; +queue_cfg->pwr_mgmt_state =PMD_MGMT_ENABLED ; +return ret; + +failure_handler: +if (port_cfg[port_id].ref_cnt ==0 ) { +rte_free (port_cfg[port_id].queue_cfg); +port_cfg[port_id].queue_cfg =NULL ; +} +return ret; +} + +int +rte_power_pmd_mgmt_queue_disable (unsigned int lcore_id, +uint16_t port_id, +uint16_t queue_id) +{ +struct pmd_queue_cfg *queue_cfg; + +if (port_cfg[port_id].ref_cnt <=0 ) +return -EINVAL ; + +queue_cfg = &port_cfg[port_id].queue_cfg[queue_id];
Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 184
Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +6
-0+ +if (queue_cfg->pwr_mgmt_state ==PMD_MGMT_DISABLED ) +return -EINVAL ; + +switch (queue_cfg->cb_mode) { +case RTE_POWER_MGMT_TYPE_WAIT :Think we need
wakeup(lcore_id)here.
Not sure what you mean? Could you please elaborate?
Quoted 16 lines
Quoted 16 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +15
-0+case RTE_POWER_MGMT_TYPE_PAUSE : +rte_eth_remove_rx_callback (port_id, queue_id, + queue_cfg->cur_cb); +break ; +case RTE_POWER_MGMT_TYPE_SCALE : +rte_power_freq_max (lcore_id); +rte_eth_remove_rx_callback (port_id, queue_id, + queue_cfg->cur_cb); +rte_power_exit (lcore_id); +break ; +} +/* it's not recommend to free callback instance here. +* it cause memory leak which is a known issue. +*/ +queue_cfg->cur_cb =NULL ;
Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 204
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5
-0+queue_cfg->pwr_mgmt_state =PMD_MGMT_DISABLED ; +port_cfg[port_id].ref_cnt--; + +if (port_cfg[port_id].ref_cnt ==0 ) { +rte_free (port_cfg[port_id].queue_cfg);It is not safe to do so, unless device is already stopped.
Otherwise you need some sync mechanism here (hand-made as bpf lib, or rcu online/offline, or...)
Not sure what you mean. We're not freeing the callback structure, we're freeing the local data structure holding the per-port status.
Quoted 5 lines
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4
-0+port_cfg[port_id].queue_cfg =NULL ; +} +return 0 ; +}
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 04/10] power: add simple power management API and callback
Quoted 370 lines · Konstantin
Quoted 143 lines
Quoted 143 lines
Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.
This API support 1 port to multiple core use case.
This design leverage RX Callback mechnaism which allow three different power management methodology co exist.
1. umwait/umonitor:
The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.
2. Pause instruction
Instead of move the core into deeper C state, this lightweight method use Pause instruction to relief the processor from busy polling.
3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- lib/librte_power/meson.build | 5 +- lib/librte_power/pmd_mgmt.h | 49 ++++++ lib/librte_power/rte_power_pmd_mgmt.c | 208 +++++++++++++++++++++++++ lib/librte_power/rte_power_pmd_mgmt.h | 88 +++++++++++ lib/librte_power/rte_power_version.map | 4 + 5 files changed, 352 insertions(+), 2 deletions(-)create mode 100644
lib/librte_power/pmd_mgmt.hcreate mode 100644lib/librte_power/rte_power_pmd_mgmt.ccreate mode 100644lib/librte_power/rte_power_pmd_mgmt.hlib/librte_power/meson.build +3
-2@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c', 'power_kvm_vm.c', 'guest_channel.c', 'rte_power_empty_poll.c', 'power_pstate_cpufreq.c', +'rte_power_pmd_mgmt.c', 'power_common.c') -headers = files('rte_power.h','rte_power_empty_poll.h') -deps += ['timer'] +headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h') +deps += ['timer' ,'ethdev']lib/librte_power/pmd_mgmt.h new file +49
-0@@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2010-2020 Intel Corporation +*/ + +#ifndef _PMD_MGMT_H +#define _PMD_MGMT_H + +/** +* @file +* Power Management +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Possible power management states of an ethdev port. +*/ +enum pmd_mgmt_state { +/** Device power management is disabled. */ +PMD_MGMT_DISABLED =0 , +/** Device power management is enabled. */ +PMD_MGMT_ENABLED , +}; + +struct pmd_queue_cfg { +enum pmd_mgmt_state pwr_mgmt_state; +/**< Power mgmt Callback mode */ +enum rte_power_pmd_mgmt_type cb_mode; +/**< Empty poll number */ +uint16_t empty_poll_stats; +/**< Callback instance */ +const struct rte_eth_rxtx_callback *cur_cb; +} __rte_cache_aligned; + +struct pmd_port_cfg { +int ref_cnt; +struct pmd_queue_cfg *queue_cfg; +} __rte_cache_aligned; + + + + +#ifdef __cplusplus +} +#endif + +#endif lib/librte_power/rte_power_pmd_mgmt.c new file +27
-0@@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2010-2020 Intel Corporation +*/ + +#include <rte_lcore.h> +#include <rte_cycles.h> +#include <rte_malloc.h> +#include <rte_ethdev.h> +#include <rte_power_intrinsics.h> + +#include "rte_power_pmd_mgmt.h" +#include "pmd_mgmt.h" + + +#define EMPTYPOLL_MAX 512 +#define PAUSE_NUM 64 + +static struct pmd_port_cfg port_cfg[RTE_MAX_ETHPORTS ]; + +static uint16_t +rte_power_mgmt_umwait (uint16_t port_id,uint16_t qidx, +struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, +uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ + +struct pmd_queue_cfg *q_conf; +q_conf = &port_cfg[port_id].queue_cfg[qidx];Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 31
Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4
-0+ +if (unlikely (nb_rx ==0 )) { +q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) {Here and in other places - wouldn't it be better to
empty_poll_maxas configurable parameter, instead of constant value?It would be more flexible, but i don't think it's "better" in the sense that providing additional options will only make using this (already under-utilized!) API harder than it needs to be.
Quoted 13 lines
Quoted 13 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +12
-0+volatile void *target_addr; +uint64_t expected, mask; +uint16_t ret; + +/* +* get address of next descriptor in the RX +* ring for this queue, as well as expected +* value and a mask. +*/ +ret =rte_eth_get_wake_addr (port_id, qidx, + &target_addr, &expected, + &mask);Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 48
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5
-0+if (ret ==0 ) +/* -1ULL is maximum value for TSC */ +rte_power_monitor (target_addr, + expected, mask, +0 ,-1ULL );Why not make timeout a user specified parameter?
This is meant to be an "easy to use" API, we were trying to keep the amount of configuration to an absolute minimum. If the user wants to use custom timeouts, they can do so with using
rte_power_monitorAPI explicitly.Quoted 16 lines
Quoted 16 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +15
-0+} +}else +q_conf->empty_poll_stats =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_pause (uint16_t port_id,uint16_t qidx, +struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, +uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct pmd_queue_cfg *q_conf; +int i; +q_conf = &port_cfg[port_id].queue_cfg[qidx];Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 69
Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +6
-0+ +if (unlikely (nb_rx ==0 )) { +q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) { +for (i =0 ; i <PAUSE_NUM ; i++) +rte_pause ();Just
rte_delay_us(timeout)instead of this loop?Yes, seems better, thanks.
Quoted 27 lines
Quoted 27 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +26
-0+} +}else +q_conf->empty_poll_stats =0 ; + +return nb_rx; +} + +static uint16_t +rte_power_mgmt_scalefreq (uint16_t port_id,uint16_t qidx, +struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, +uint16_t max_pkts __rte_unused, void *_ __rte_unused) +{ +struct pmd_queue_cfg *q_conf; +q_conf = &port_cfg[port_id].queue_cfg[qidx]; + +if (unlikely (nb_rx ==0 )) { +q_conf->empty_poll_stats++; +if (unlikely (q_conf->empty_poll_stats >EMPTYPOLL_MAX )) { +/*scale down freq */ +rte_power_freq_min (rte_lcore_id ()); + +} +}else { +q_conf->empty_poll_stats =0 ; +/* scal up freq */ +rte_power_freq_max (rte_lcore_id ());Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 55
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5
-0+} + +return nb_rx; +} +Probably worth to mention in comments that these functions enable/disable are not MT safe.
Will do in v6.
Quoted 49 lines
Quoted 49 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +48
-0+int +rte_power_pmd_mgmt_queue_enable (unsigned int lcore_id, +uint16_t port_id, +uint16_t queue_id, +enum rte_power_pmd_mgmt_type mode) +{ +struct rte_eth_dev *dev; +struct pmd_queue_cfg *queue_cfg; +int ret =0 ; + +RTE_ETH_VALID_PORTID_OR_ERR_RET (port_id, -EINVAL ); +dev = &rte_eth_devices[port_id]; + +if (port_cfg[port_id].queue_cfg ==NULL ) { +port_cfg[port_id].ref_cnt =0 ; +/* allocate memory for empty poll stats */ +port_cfg[port_id].queue_cfg =rte_malloc_socket (NULL , +sizeof (struct pmd_queue_cfg ) +*RTE_MAX_QUEUES_PER_PORT , +0 , dev->data->numa_node); +if (port_cfg[port_id].queue_cfg ==NULL ) +return -ENOMEM ; +} + +queue_cfg = &port_cfg[port_id].queue_cfg[queue_id]; + +if (queue_cfg->pwr_mgmt_state ==PMD_MGMT_ENABLED ) { +ret = -EINVAL ; +goto failure_handler; +} + +switch (mode) { +case RTE_POWER_MGMT_TYPE_WAIT : +if (!rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { +ret = -ENOTSUP ; +goto failure_handler; +} +queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, +rte_power_mgmt_umwait,NULL ); +break ; +case RTE_POWER_MGMT_TYPE_SCALE : +/* init scale freq */ +if (rte_power_init (lcore_id)) { +ret = -EINVAL ; +goto failure_handler; +} +queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, +rte_power_mgmt_scalefreq,NULL );Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 153
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5
-0+break ; +case RTE_POWER_MGMT_TYPE_PAUSE : +queue_cfg->cur_cb =rte_eth_add_rx_callback (port_id, queue_id, +rte_power_mgmt_pause,NULL ); +break ;default:
....Will add in v6.
Quoted 26 lines
Quoted 26 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +25
-0+} +queue_cfg->cb_mode = mode; +port_cfg[port_id].ref_cnt++; +queue_cfg->pwr_mgmt_state =PMD_MGMT_ENABLED ; +return ret; + +failure_handler: +if (port_cfg[port_id].ref_cnt ==0 ) { +rte_free (port_cfg[port_id].queue_cfg); +port_cfg[port_id].queue_cfg =NULL ; +} +return ret; +} + +int +rte_power_pmd_mgmt_queue_disable (unsigned int lcore_id, +uint16_t port_id, +uint16_t queue_id) +{ +struct pmd_queue_cfg *queue_cfg; + +if (port_cfg[port_id].ref_cnt <=0 ) +return -EINVAL ; + +queue_cfg = &port_cfg[port_id].queue_cfg[queue_id];Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 184
Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +6
-0+ +if (queue_cfg->pwr_mgmt_state ==PMD_MGMT_DISABLED ) +return -EINVAL ; + +switch (queue_cfg->cb_mode) { +case RTE_POWER_MGMT_TYPE_WAIT :Think we need
wakeup(lcore_id)here.Not sure what you mean? Could you please elaborate?
Quoted 16 lines
Quoted 16 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +15
-0+case RTE_POWER_MGMT_TYPE_PAUSE : +rte_eth_remove_rx_callback (port_id, queue_id, + queue_cfg->cur_cb); +break ; +case RTE_POWER_MGMT_TYPE_SCALE : +rte_power_freq_max (lcore_id); +rte_eth_remove_rx_callback (port_id, queue_id, + queue_cfg->cur_cb); +rte_power_exit (lcore_id); +break ; +} +/* it's not recommend to free callback instance here. +* it cause memory leak which is a known issue. +*/ +queue_cfg->cur_cb =NULL ;Quoted 8 lines
lib/librte_power/rte_power_pmd_mgmt.c line 204
Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +5
-0+queue_cfg->pwr_mgmt_state =PMD_MGMT_DISABLED ; +port_cfg[port_id].ref_cnt--; + +if (port_cfg[port_id].ref_cnt ==0 ) { +rte_free (port_cfg[port_id].queue_cfg);It is not safe to do so, unless device is already stopped.
Otherwise you need some sync mechanism here (hand-made as bpf lib, or rcu online/offline, or...)
Quoted 2 lines
Not sure what you mean. We're not freeing the callback structure, we're freeing the local data structure holding the per-port status.
What is the difference?
You still trying to free memory that might be used by your DP thread that still executes the callback.
Quoted 11 lines
Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c line 208
Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4
-0+port_cfg[port_id].queue_cfg =NULL ; +} +return 0 ; +}--
Thanks,
Anatoly
Re: [dpdk-dev] [PATCH v4 04/10] power: add simple power management API and callback
Quoted 25 lines · Konstantin
Quoted 25 lines
Quoted 24 lines
Quoted 11 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+case RTE_POWER_MGMT_TYPE_PAUSE : +rte_eth_remove_rx_callback (port_id, queue_id, + queue_cfg->cur_cb); +break ; +case RTE_POWER_MGMT_TYPE_SCALE : +rte_power_freq_max (lcore_id); +rte_eth_remove_rx_callback (port_id, queue_id, + queue_cfg->cur_cb); +rte_power_exit (lcore_id); +break ;lib/librte_power/rte_power_pmd_mgmt.c line 204
Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10
-0+} +/* it's not recommend to free callback instance here. +* it cause memory leak which is a known issue. +*/ +queue_cfg->cur_cb =NULL ; +queue_cfg->pwr_mgmt_state =PMD_MGMT_DISABLED ; +port_cfg[port_id].ref_cnt--; + +if (port_cfg[port_id].ref_cnt ==0 ) { +rte_free (port_cfg[port_id].queue_cfg);It is not safe to do so, unless device is already stopped.
Otherwise you need some sync mechanism here (hand-made as bpf lib, or rcu online/offline, or...)
Quoted 6 lines
Quoted 2 lines
Not sure what you mean. We're not freeing the callback structure, we're freeing the local data structure holding the per-port status.
What is the difference?
You still trying to free memory that might be used by your DP thread that still executes the callback.
Welp, you're right :/ I'll see what i can do to fix it.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Burakov, AnatolyQuoted 45 lines · Konstantin
Quoted 25 lines
Quoted 15 lines · Konstantin
Quoted 13 lines
Quoted 12 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 9 lines
Quoted 3 lines
I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.
I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.
Quoted 16 lines
Yes, I think we either need a syscall that would do an IPI for us
(on top of my head -membarrier()does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:uint64_tval =atomic_load(addr);CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin
Quoted 1 line
This implies knowing the value the core is sleeping on.
You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.
Quoted 3 lines
That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.
That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
Quoted 45 lines · Konstantin
Quoted 45 lines · Konstantin
Quoted 41 lines
Quoted 15 lines · Konstantin
Quoted 13 lines
Quoted 12 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 9 lines
Quoted 3 lines
I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.
I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.
Yes, I think we either need a syscall that would do an IPI for us
(on top of my head -membarrier()does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:uint64_tval =atomic_load(addr);CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin
Quoted 5 lines
Quoted 1 line
This implies knowing the value the core is sleeping on.
You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as
monitor()does.
Sorry, i meant the address. We don't know the address we're sleeping on.
Quoted 8 lines
Quoted 4 lines
That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.
The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v5 01/10] eal: add new x86 cpuid support for WAITPKG
In reply to Anatoly BurakovQuoted 9 lines · Anatoly Burakov
From: Liang Ma <[email protected]>
Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.Signed-off-by Liang Ma <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>
The work on this patchset is clearly going to take a few more days, but this particular patch is high priority as there are other dependencies on this patch for DLB drivers. Would it be possible to accept this particular patch now...
Quoted 10 lines
--- lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++ lib/librte_eal/x86/rte_cpuflags.c | 2 ++ 2 files changed, 4 insertions(+)lib/librte_eal/x86/include/rte_cpuflags.h +0
-0
lib/librte_eal/x86/include/rte_cpuflags.h enum rte_cpu_flag_t { · line 136
Quoted 5 lines
lib/librte_eal/x86/include/rte_cpuflags.h +2
-0@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {RTE_CPUFLAG_MOVDIR64B ,/**< Direct Store Instructions 64B */ RTE_CPUFLAG_AVX512VP2INTERSECT ,/**< AVX512 Two Register Intersection */ +/**< UMWAIT/TPAUSE Instructions */ + RTE_CPUFLAG_WAITPKG, /**< UMINITOR/UMWAIT/TPAUSE */
...with typo fix (UMONITOR rather than UMINITOR)?
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics
In reply to Burakov, AnatolyQuoted 54 lines
Quoted 41 lines
Quoted 41 lines
Quoted 40 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines
Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.
The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.
Quoted 9 lines
Quoted 3 lines
I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.
I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.
Yes, I think we either need a syscall that would do an IPI for us
(on top of my head -membarrier()does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:uint64_tval =atomic_load(addr);CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
KonstantinQuoted 5 lines
Quoted 1 line
This implies knowing the value the core is sleeping on.
You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as
monitor()does.Sorry, i meant the address. We don't know the address we're sleeping on.
Quoted 5 lines
Quoted 4 lines
That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.
Quoted 7 lines
Quoted 3 lines
That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.
The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.
Yes, we'll need something to sync here for sure.
Sorry, I should say it straightway, to avoid further misunderstanding. Let say, associate a spin_lock with monitor(), by analogy with pthread_cond_wait(). Konstantin
Re: [dpdk-dev] [PATCH v5 03/10] eal: add intrinsics support check infrastructure
In reply to Anatoly BurakovQuoted 29 lines · Anatoly Burakov
Currently, it is not possible to check support for intrinsics that are platform-specific, cannot be abstracted in a generic way, or do not have support on all architectures. The CPUID flags can be used to some extent, but they are only defined for their platform, while intrinsics will be available to all code as they are in generic headers.
This patch introduces infrastructure to check support for certain platform-specific intrinsics, and adds support for checking support for IA power management-related intrinsics for UMWAIT/UMONITOR and TPAUSE.
Signed-off-by Anatoly Burakov <[email protected]>--- .../arm/include/rte_power_intrinsics.h | 8 ++++++ lib/librte_eal/arm/rte_cpuflags.c | 6 +++++ lib/librte_eal/include/generic/rte_cpuflags.h | 26 +++++++++++++++++++ .../include/generic/rte_power_intrinsics.h | 8 ++++++ .../ppc/include/rte_power_intrinsics.h | 8 ++++++ lib/librte_eal/ppc/rte_cpuflags.c | 6 +++++ lib/librte_eal/rte_eal_version.map | 1 + .../x86/include/rte_power_intrinsics.h | 8 ++++++ lib/librte_eal/x86/rte_cpuflags.c | 12 +++++++++ 9 files changed, 83 insertions(+)lib/librte_eal/arm/include/rte_power_intrinsics.h +0
-0
lib/librte_eal/arm/include/rte_power_intrinsics.h extern "C" { · line 22
Quoted 6 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h +3
-0@@ -17,6 +17,10 @@ extern "C" {/** * This function is not supported on ARM. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error.
See below
lib/librte_eal/arm/include/rte_power_intrinsics.h static inline void rte_power_monitor(const volatile void *p, · line 53
Quoted 12 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h +5
-0+* * @param p * Address to monitor for changes. Must be aligned on an 64-byte boundary. * @param expected_value @@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,/** * This function is not supported on ARM. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +*
See below
This patch looks to me.
Since rte_power_monitor() API is public API, I think, only in the generic header file, you need to have
these warnings and API documentation rather than repeating everywhere.
Quoted 59 lines
lib/librte_eal/arm/include/rte_power_intrinsics.h +0
-0* @param tsc_timestamp * Maximum TSC timestamp to wait for. * lib/librte_eal/arm/rte_cpuflags.c +6
-0@@ -138,3 +138,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)return NULL ;return rte_cpu_feature_table[feature].name; } + +void +rte_cpu_get_intrinsics_support (struct rte_cpu_intrinsics *intrinsics) +{ +memset (intrinsics,0 ,sizeof (*intrinsics)); +}lib/librte_eal/include/generic/rte_cpuflags.h +26
-0@@ -13,6 +13,32 @@#include "rte_common.h" #include <errno.h> +#include <rte_compat.h> + +/** +* Structure used to describe platform-specific intrinsics that may or may not +* be supported at runtime. +*/ +struct rte_cpu_intrinsics { +uint32_t power_monitor :1 ; +/**< indicates support for rte_power_monitor function */ +uint32_t power_pause :1 ; +/**< indicates support for rte_power_pause function */ +}; + +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* Check CPU support for various intrinsics at runtime. +* +* @param intrinsics +* Pointer to a structure to be filled. +*/ +__rte_experimental +void +rte_cpu_get_intrinsics_support (struct rte_cpu_intrinsics *intrinsics); +/** * Enumeration of all CPU features supported */ lib/librte_eal/include/generic/rte_power_intrinsics.h +0
-0
lib/librte_eal/include/generic/rte_power_intrinsics.h line 31
Quoted 6 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +3
-0@@ -26,6 +26,10 @@* checked against the expected value, and if they match, the entering of * optimized power state may be aborted. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error.
See above
Quoted 122 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +5
-0+* * @param p * Address to monitor for changes. Must be aligned on an 64-byte boundary. * @param expected_value @@ -49,6 +53,10 @@ static inline void rte_power_monitor(const volatile void *p,* Enter an architecture-defined optimized power state until a certain TSC * timestamp is reached. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param tsc_timestamp * Maximum TSC timestamp to wait for. Note that the wait behavior is * architecture-dependent. lib/librte_eal/ppc/include/rte_power_intrinsics.h +8
-0@@ -17,6 +17,10 @@ extern "C" {/** * This function is not supported on PPC64. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param p * Address to monitor for changes. Must be aligned on an 64-byte boundary. * @param expected_value @@ -43,6 +47,10 @@ static inline void rte_power_monitor(const volatile void *p,/** * This function is not supported on PPC64. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param tsc_timestamp * Maximum TSC timestamp to wait for. * lib/librte_eal/ppc/rte_cpuflags.c +6
-0@@ -108,3 +108,9 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)return NULL ;return rte_cpu_feature_table[feature].name; } + +void +rte_cpu_get_intrinsics_support (struct rte_cpu_intrinsics *intrinsics) +{ +memset (intrinsics,0 ,sizeof (*intrinsics)); +}lib/librte_eal/rte_eal_version.map +1
-0@@ -400,6 +400,7 @@ EXPERIMENTAL { # added in 20.11 __rte_eal_trace_generic_size_t; rte_service_lcore_may_be_active; + rte_cpu_get_intrinsics_support; }; INTERNAL {lib/librte_eal/x86/include/rte_power_intrinsics.h +8
-0@@ -29,6 +29,10 @@ extern "C" {* For more information about usage of these instructions, please refer to * Intel(R) 64 and IA-32 Architectures Software Developer's Manual. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param p * Address to monitor for changes. Must be aligned on an 64-byte boundary. * @param expected_value @@ -80,6 +84,10 @@ static inline void rte_power_monitor(const volatile void *p,* information about usage of this instruction, please refer to Intel(R) 64 and * IA-32 Architectures Software Developer's Manual. * +* @warning It is responsibility of the user to check if this function is +* supported at runtime using `rte_cpu_get_features()` API call. Failing to do +* so may result in an illegal CPU instruction error. +* * @param tsc_timestamp * Maximum TSC timestamp to wait for. * lib/librte_eal/x86/rte_cpuflags.c +12
-1@@ -7,6 +7,7 @@#include <stdio.h> #include <errno.h> #include <stdint.h> +#include <string.h> #include "rte_cpuid.h" @@ -179,3 +180,14 @@ rte_cpu_get_flag_name(enum rte_cpu_flag_t feature)return NULL ;return rte_cpu_feature_table[feature].name; } + +void +rte_cpu_get_intrinsics_support (struct rte_cpu_intrinsics *intrinsics) +{ +memset (intrinsics,0 ,sizeof (*intrinsics)); + +if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { + intrinsics->power_monitor =1 ; + intrinsics->power_pause =1 ; + } +} --2.17.1
Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API
In reply to Anatoly BurakovHi Liang,
Quoted 57 lines
-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management APIFrom: Liang Ma <[email protected]>
Implement support for the power management API by implementing a
get_wake_addrfunction that will return an address of an RX ring's status bit.Signed-off-by Anatoly Burakov <[email protected]>Signed-off-by Liang Ma <[email protected]>--- drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 ++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 ++ 3 files changed, 25 insertions(+)drivers/net/ixgbe/ixgbe_ethdev.c +1
-0@@ -588,6 +588,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = { .udp_tunnel_port_del = ixgbe_dev_udp_tunnel_port_del, .tm_ops_get = ixgbe_tm_ops_get, .tx_done_cleanup = ixgbe_dev_tx_done_cleanup, + .get_wake_addr = ixgbe_get_wake_addr, };/* drivers/net/ixgbe/ixgbe_rxtx.c +12
-0@@ -1366,6 +1366,28 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +int ixgbe_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ixgbe_adv_rx_desc *rxdp; +struct ixgbe_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc]; +/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.upper.status_error; +
drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1390
Quoted 10 lines
drivers/net/ixgbe/ixgbe_rxtx.c +10
-0+/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + *mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + +return 0 ; +} +
I'm wondering that whether the '.get_wake_addr' can be specific to like 'rxq_tailq_addr_get' ? So that one day this wake up mechanism can be applied to 'txq_tailq_addr_get' ? :-)
Also, "volatile void **tail_desc_addr, uint64_t *expected, uint64_t *mask" can be merged into 'struct xxx' ? So that you can expand the API easily.
Just my thoughts.
Anyway, LGTM
Quoted 2 lines
drivers/net/ixgbe/ixgbe_rxtx.c +0
-1--2.17.1
Re: [dpdk-dev] [PATCH v5 06/10] net/ixgbe: implement power management API
In reply to Anatoly BurakovHi Liang,
Quoted 37 lines
-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Saturday, October 10, 2020 00:02
To: [email protected]
Cc: Ma, Liang J <[email protected]>; Guo, Jia <[email protected]>; Wang, Haiyue <[email protected]>; Hunt, David <[email protected]>; Ananyev, Konstantin <[email protected]>; [email protected]; Richardson, Bruce <[email protected]>; [email protected]; McDaniel, Timothy <[email protected]>; Eads, Gage <[email protected]>; Macnamara, Chris <[email protected]>
Subject: [PATCH v5 06/10] net/ixgbe: implement power management APIFrom: Liang Ma <[email protected]>
Implement support for the power management API by implementing a
get_wake_addrfunction that will return an address of an RX ring's status bit.Signed-off-by Anatoly Burakov <[email protected]>Signed-off-by Liang Ma <[email protected]>--- drivers/net/ixgbe/ixgbe_ethdev.c | 1 + drivers/net/ixgbe/ixgbe_rxtx.c | 22 ++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_rxtx.h | 2 ++ 3 files changed, 25 insertions(+)drivers/net/ixgbe/ixgbe_rxtx.c +9
-0+int ixgbe_get_wake_addr (void *rx_queue,volatile void **tail_desc_addr, +uint64_t *expected,uint64_t *mask) +{ +volatile union ixgbe_adv_rx_desc *rxdp; +struct ixgbe_rx_queue *rxq = rx_queue; +uint16_t desc; + + desc = rxq->rx_tail; + rxdp = &rxq->rx_ring[desc];
drivers/net/ixgbe/ixgbe_rxtx.c const uint32_t · line 1387
Quoted 10 lines
drivers/net/ixgbe/ixgbe_rxtx.c +10
-0+/* watch for changes in status bit */ + *tail_desc_addr = &rxdp->wb.upper.status_error; + +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ + *expected =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); + *mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +
Seems have one issue about the byte endian:
Like for BIG endian:
*expected = rte_bswap32(IXGBE_RXDADV_STAT_DD)
!=
*expected = rte_bswap64(IXGBE_RXDADV_STAT_DD)
And in API 'rte_power_monitor', use uint64_t type to access the wake up data:
static inline void rte_power_monitor(const volatile void *p,
const uint64_t expected_value, const uint64_t value_mask, const uint64_t tsc_timestamp)
{
if (value_mask) {
const uint64_t cur_value = *(const volatile uint64_t *)p;
const uint64_t masked = cur_value & value_mask;
/* if the masked value is already matching, abort */
if (masked == expected_value)
return;
}So that we need the wake up address type like 16/32/64b ?
Quoted 2 lines
--
2.17.1