Enhancements for PMD power management
Subsystems (2)
PATCH v6 3/7 eal: add power monitor for multiple events
In reply to Anatoly BurakovUse RTM and WAITPKG instructions to perform a wait-for-writes similar to what UMWAIT does, but without the limitation of having to listen for just one event. This works because the optimized power state used by the TPAUSE instruction will cause a wake up on RTM transaction abort, so if we add the addresses we're interested in to the read-set, any write to those addresses will wake us up.
---
Notes:
v4:
- Fixed bugs in accessing the monitor condition
- Abort on any monitor condition not having a defined callback
v2:
- Adapt to callback mechanism
doc/guides/rel_notes/release_21_08.rst | 2 + lib/eal/arm/rte_power_intrinsics.c | 11 +++ lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 35 +++++++++ lib/eal/ppc/rte_power_intrinsics.c | 11 +++ lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 73 +++++++++++++++++++ 8 files changed, 139 insertions(+)
doc/guides/rel_notes/release_21_08.rst +2 -0
@@ -55,6 +55,8 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* eal: added ``rte_power_monitor_multi`` to support waiting for multiple events. + Removed Items -------------
lib/eal/arm/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/include/generic/rte_cpuflags.h +2 -0
@@ -24,6 +24,8 @@ struct rte_cpu_intrinsics {/**< indicates support for rte_power_monitor function */ uint32_t power_pause : 1;/**< indicates support for rte_power_pause function */ + uint32_t power_monitor_multi : 1; +/**< indicates support for rte_power_monitor_multi function */ };/**
lib/eal/include/generic/rte_power_intrinsics.h +35 -0
@@ -128,4 +128,39 @@ int rte_power_monitor_wakeup(const unsigned int lcore_id);__rte_experimental int rte_power_pause(const uint64_t tsc_timestamp); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* Monitor a set of addresses for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either one of the specified +* memory addresses is written to, a certain TSC timestamp is reached, or other +* reasons cause the CPU to wake up. +* +* Additionally, `expected` 64-bit values and 64-bit masks 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 do not 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_intrinsics_support()` API call. +* Failing to do so may result in an illegal CPU instruction error. +* +* @param pmc +* An array of monitoring condition structures. +* @param num +* Length of the `pmc` array. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* 0 on success +* -EINVAL on invalid parameters +* -ENOTSUP if unsupported +*/ +__rte_experimental +int rte_power_monitor_multi(const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp); +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/eal/ppc/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/version.map +3 -0
@@ -423,6 +423,9 @@ EXPERIMENTAL { rte_version_release; # WINDOWS_NO_EXPORT rte_version_suffix; # WINDOWS_NO_EXPORT rte_version_year; # WINDOWS_NO_EXPORT + + # added in 21.08 + rte_power_monitor_multi; # WINDOWS_NO_EXPORT }; INTERNAL {
lib/eal/x86/rte_cpuflags.c +2 -0
@@ -189,5 +189,7 @@ rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { intrinsics->power_monitor =1 ; intrinsics->power_pause =1 ; +if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_RTM )) + intrinsics->power_monitor_multi =1 ; } }
lib/eal/x86/rte_power_intrinsics.c +73 -0
100 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v6 3/7] eal: add power monitor for multiple events
Quoted 19 lines · Anatoly Burakov
Use RTM and WAITPKG instructions to perform a wait-for-writes similar to what UMWAIT does, but without the limitation of having to listen for just one event. This works because the optimized power state used by the TPAUSE instruction will cause a wake up on RTM transaction abort, so if we add the addresses we're interested in to the read-set, any write to those addresses will wake us up.
Signed-off-by Konstantin Ananyev <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v4:
- Fixed bugs in accessing the monitor condition
- Abort on any monitor condition not having a defined callbackv2:
- Adapt to callback mechanism
Quoted 10 lines
doc/guides/rel_notes/release_21_08.rst | 2 + lib/eal/arm/rte_power_intrinsics.c | 11 +++ lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 35 +++++++++ lib/eal/ppc/rte_power_intrinsics.c | 11 +++ lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 73 +++++++++++++++++++ 8 files changed, 139 insertions(+)
PATCH v6 4/7 power: remove thread safety from PMD power API's
In reply to Anatoly BurakovCurrently, we expect that only one callback can be active at any given moment, for a particular queue configuration, which is relatively easy to implement in a thread-safe way. However, we're about to add support for multiple queues per lcore, which will greatly increase the possibility of various race conditions.
We could have used something like an RCU for this use case, but absent of a pressing need for thread safety we'll go the easy way and just mandate that the API's are to be called when all affected ports are stopped, and document this limitation. This greatly simplifies the rte_power_monitor-related code.
---
Notes:
v2:
- Add check for stopped queue
- Clarified doc message
- Added release notes
doc/guides/rel_notes/release_21_08.rst | 5 + lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 133 ++++++++++--------------- lib/power/rte_power_pmd_mgmt.h | 6 ++ 4 files changed, 67 insertions(+), 80 deletions(-)
doc/guides/rel_notes/release_21_08.rst +5 -0
@@ -88,6 +88,11 @@ API Changes * eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. +* rte_power: The experimental PMD power management API is no longer considered + to be thread safe; all Rx queues affected by the API will now need to be + stopped before making any changes to the power management scheme. + + ABI Changes -----------
lib/power/meson.build +3 -0
@@ -21,4 +21,7 @@ headers = files( 'rte_power_pmd_mgmt.h', 'rte_power_guest_channel.h', ) +if cc.has_argument('-Wno-cast-qual') + cflags += '-Wno-cast-qual' +endif deps += ['timer', 'ethdev']
lib/power/rte_power_pmd_mgmt.c +53 -80
209 lines not on this page · raw message
lib/power/rte_power_pmd_mgmt.h +6 -0
@@ -43,6 +43,9 @@ enum rte_power_pmd_mgmt_type {* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue will be polled from. * @param port_id
@@ -69,6 +72,9 @@ rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id,* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue is polled from. * @param port_id
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v6 4/7] power: remove thread safety from PMD power API's
Quoted 7 lines
Currently, we expect that only one callback can be active at any given moment, for a particular queue configuration, which is relatively easy to implement in a thread-safe way. However, we're about to add support for multiple queues per lcore, which will greatly increase the possibility of various race conditions.
Quoted 9 lines
We could have used something like an RCU for this use case, but absent of a pressing need for thread safety we'll go the easy way and just mandate that the API's are to be called when all affected ports are stopped, and document this limitation. This greatly simplifies the
rte_power_monitor-related code.Signed-off-by Anatoly Burakov <[email protected]>---
Quoted 1 line
2.25.1
PATCH v6 5/7 power: support callbacks for multiple Rx queues
In reply to Anatoly BurakovCurrently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.
Also, while we're at it, update and improve the docs.
---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)
v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantin
v3:
- Move the list of supported NICs to NIC feature table
v2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues
doc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 65 ++-- doc/guides/rel_notes/release_21_08.rst | 3 + lib/power/rte_power_pmd_mgmt.c | 452 +++++++++++++++++++------ 4 files changed, 394 insertions(+), 136 deletions(-)
doc/guides/nics/features.rst +10 -0
@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``. +.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` + .. _nic_features_other: Other dev ops not represented by a Feature
doc/guides/prog_guide/power_man.rst +37 -28
74 lines not on this page · raw message
doc/guides/rel_notes/release_21_08.rst +3 -0
@@ -57,6 +57,9 @@ New Features * eal: added ``rte_power_monitor_multi`` to support waiting for multiple events. +* rte_power: The experimental PMD power management API now supports managing + multiple Ethernet Rx queues per lcore. + Removed Items -------------
lib/power/rte_power_pmd_mgmt.c +344 -108
567 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
Quoted 144 lines
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queuesdoc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 65 ++-- doc/guides/rel_notes/release_21_08.rst | 3 + lib/power/rte_power_pmd_mgmt.c | 452 +++++++++++++++++++------ 4 files changed, 394 insertions(+), 136 deletions(-)doc/guides/nics/features.rst +10
-0@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``. +.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` + .. _nic_features_other: Other dev ops not represented by a Featuredoc/guides/prog_guide/power_man.rst +35
-28@@ -198,34 +198,41 @@ Ethernet 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. - -Monitor - This power saving scheme will put the CPU into optimized power state - and use the ``rte_power_monitor()`` function - to monitor the Ethernet PMD RX descriptor address, - and wake the CPU up whenever there's new traffic. - -Pause - This power saving scheme will avoid busy polling - by either entering power-optimized sleep state - with ``rte_power_pause()`` function, - or, if it's not available, use ``rte_pause()``. - -Frequency scaling - This power saving scheme will use ``librte_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). +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. + +* Monitor + This power saving scheme will put the CPU into optimized power state and + monitor the Ethernet PMD RX descriptor address, waking the CPU up whenever + there's new traffic. Support for this scheme may not be available on all + platforms, and further limitations may apply (see below). + +* Pause + This power saving scheme will avoid busy polling by either entering + power-optimized sleep state with ``rte_power_pause()`` function, or, if it's + not supported by the underlying platform, use ``rte_pause()``. + +* Frequency scaling + This power saving scheme will use ``librte_power`` library functionality to + scale the core frequency up/down depending on traffic volume. + +The "monitor" mode is only supported in the following configurations and scenarios: + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that + ``rte_power_monitor()`` is supported by the platform, then monitoring will be + limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be + monitored from a different lcore). + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that the + ``rte_power_monitor()`` function is not supported, then monitor mode will not + be supported. + +* Not all Ethernet drivers support monitoring, even if the underlying + platform may support the necessary CPU instructions. Please refer to + :doc:`../nics/overview` for more information. +
....
Quoted 29 lines
doc/guides/prog_guide/power_man.rst +29
-0+static inline void +queue_reset(struct pmd_core_cfg *cfg, struct queue_list_entry *qcfg) +{ + const bool is_ready_to_sleep = qcfg->n_empty_polls > EMPTYPOLL_MAX; + + /* reset empty poll counter for this queue */ + qcfg->n_empty_polls = 0; + /* reset the queue sleep counter as well */ + qcfg->n_sleeps = 0; + /* remove the queue from list of cores ready to sleep */ + if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--; + /* + * no need change the lcore sleep target counter because this lcore will + * reach the n_sleeps anyway, and the other cores are already counted so + * there's no need to do anything else. + */ +} + +static inline bool +queue_can_sleep(struct pmd_core_cfg *cfg, struct queue_list_entry *qcfg) +{ + /* this function is called - that means we have an empty poll */ + qcfg->n_empty_polls++; + + /* if we haven't reached threshold for empty polls, we can't sleep */ + if (qcfg->n_empty_polls <= EMPTYPOLL_MAX) + return false; +
doc/guides/prog_guide/power_man.rst
Quoted 10 lines
doc/guides/prog_guide/power_man.rst +10
-0+ /* + * we've reached a point where we are able to sleep, but we still need + * to check if this queue has already been marked for sleeping. + */ + if (qcfg->n_sleeps == cfg->sleep_target) + return true; + + /* mark this queue as ready for sleep */ + qcfg->n_sleeps = cfg->sleep_target; + cfg->n_queues_ready_to_sleep++;
So, assuming there is no incoming traffic, should it be:
1) poll_all_queues(times=EMPTYPOLL_MAX); sleep; poll_all_queues(times=1); sleep; poll_all_queues(times=1); sleep; ...
OR
2) poll_all_queues(times=EMPTYPOLL_MAX); sleep; poll_all_queues(times= EMPTYPOLL_MAX); sleep; poll_all_queues(times= EMPTYPOLL_MAX); sleep; ... ?
My initial thought was 2) but might be the intention is 1)?
Quoted 52 lines
doc/guides/prog_guide/power_man.rst +25
-10+ + return true; +} + +static inline bool +lcore_can_sleep(struct pmd_core_cfg *cfg) +{ + /* are all queues ready to sleep? */ + if (cfg->n_queues_ready_to_sleep != cfg->n_queues) + return false; + + /* we've reached an iteration where we can sleep, reset sleep counter */ + cfg->n_queues_ready_to_sleep = 0; + cfg->sleep_target++; + + return true; +} + static uint16_t clb_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 *addr __rte_unused) + uint16_t nb_rx, uint16_t max_pkts __rte_unused, void *arg) { + struct queue_list_entry *queue_conf = arg; - struct pmd_queue_cfg *q_conf; - - q_conf = &port_cfg[port_id][qidx]; - + /* this callback can't do more than one queue, omit multiqueue logic */ if (unlikely(nb_rx == 0)) { - q_conf->empty_poll_stats++; - if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) { + queue_conf->n_empty_polls++; + if (unlikely(queue_conf->n_empty_polls > EMPTYPOLL_MAX)) { struct rte_power_monitor_cond pmc; - uint16_t ret; + int ret; /* use monitoring condition to sleep */ ret = rte_eth_get_monitor_addr(port_id, qidx,@@ -97,60 +231,77 @@ clb_umwait(uint16_t port_id, uint16_t qidx, struct rte_mbuf **pkts __rte_unused, rte_power_monitor(&pmc, UINT64_MAX); } } else - q_conf->empty_poll_stats = 0; + queue_conf->n_empty_polls = 0; return nb_rx; }
Re: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
Quoted 46 lines · Konstantin
Quoted 46 lines
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues
<snip>
Quoted 47 lines
....
Quoted 29 lines
lib/power/rte_power_pmd_mgmt.c +29
-0+static inline void +queue_reset (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +const bool is_ready_to_sleep = qcfg->n_empty_polls >EMPTYPOLL_MAX ; + +/* reset empty poll counter for this queue */ + qcfg->n_empty_polls =0 ; +/* reset the queue sleep counter as well */ + qcfg->n_sleeps =0 ; +/* remove the queue from list of cores ready to sleep */ +if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--; +/* +* no need change the lcore sleep target counter because this lcore will +* reach the n_sleeps anyway, and the other cores are already counted so +* there's no need to do anything else. +*/ +} + +static inline bool +queue_can_sleep (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +/* this function is called - that means we have an empty poll */ + qcfg->n_empty_polls++; + +/* if we haven't reached threshold for empty polls, we can't sleep */ +if (qcfg->n_empty_polls <=EMPTYPOLL_MAX ) +return false; +lib/power/rte_power_pmd_mgmt.c calc_tsc(void) · line 195
Quoted 10 lines
lib/power/rte_power_pmd_mgmt.c +10
-0+/* +* we've reached a point where we are able to sleep, but we still need +* to check if this queue has already been marked for sleeping. +*/ +if (qcfg->n_sleeps == cfg->sleep_target) +return true; + +/* mark this queue as ready for sleep */ + qcfg->n_sleeps = cfg->sleep_target; + cfg->n_queues_ready_to_sleep++;So, assuming there is no incoming traffic, should it be:
1)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times=1); sleep;poll_all_queues(times=1); sleep; ...
OR
2)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times= EMPTYPOLL_MAX); sleep;poll_all_queues(times= EMPTYPOLL_MAX); sleep; ... ?
Quoted 1 line
My initial thought was 2) but might be the intention is 1)?
The intent is 1), not 2). There's no need to wait for more empty polls once we pass the threshold - we keep sleeping until there's traffic.
Signature · 2 lines
Thanks, Anatoly
Ananyev, Konstantin
Acked-byRe: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
Quoted 94 lines
Quoted 46 lines
Quoted 46 lines
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues<snip>
Quoted 37 lines
....
Quoted 36 lines
lib/power/rte_power_pmd_mgmt.c +36
-0+static inline void +queue_reset (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +const bool is_ready_to_sleep = qcfg->n_empty_polls >EMPTYPOLL_MAX ; + +/* reset empty poll counter for this queue */ + qcfg->n_empty_polls =0 ; +/* reset the queue sleep counter as well */ + qcfg->n_sleeps =0 ; +/* remove the queue from list of cores ready to sleep */ +if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--; +/* +* no need change the lcore sleep target counter because this lcore will +* reach the n_sleeps anyway, and the other cores are already counted so +* there's no need to do anything else. +*/ +} + +static inline bool +queue_can_sleep (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +/* this function is called - that means we have an empty poll */ + qcfg->n_empty_polls++; + +/* if we haven't reached threshold for empty polls, we can't sleep */ +if (qcfg->n_empty_polls <=EMPTYPOLL_MAX ) +return false; + +/* +* we've reached a point where we are able to sleep, but we still need +* to check if this queue has already been marked for sleeping. +*/ +if (qcfg->n_sleeps == cfg->sleep_target) +return true; +Quoted 8 lines
lib/power/rte_power_pmd_mgmt.c calc_tsc(void) · line 195
Quoted 3 lines
lib/power/rte_power_pmd_mgmt.c +3
-0+/* mark this queue as ready for sleep */ + qcfg->n_sleeps = cfg->sleep_target; + cfg->n_queues_ready_to_sleep++;So, assuming there is no incoming traffic, should it be:
1)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times=1); sleep;poll_all_queues(times=1); sleep; ... OR
2)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times= EMPTYPOLL_MAX); sleep; poll_all_queues(times=
Quoted 9 lines
EMPTYPOLL_MAX); sleep; ...Quoted 3 lines
?
My initial thought was 2) but might be the intention is 1)?
The intent is 1), not 2). There's no need to wait for more empty polls once we pass the threshold - we keep sleeping until there's traffic.
Ok, then:
Probably worth to put extra explanation here on in the doc, to help people avoid wrong assumptions😉
Re: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
Quoted 104 lines · Konstantin
Quoted 94 lines
Quoted 46 lines
Quoted 46 lines
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues<snip>
Quoted 37 lines
....
Quoted 36 lines
lib/power/rte_power_pmd_mgmt.c +36
-0+static inline void +queue_reset (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +const bool is_ready_to_sleep = qcfg->n_empty_polls >EMPTYPOLL_MAX ; + +/* reset empty poll counter for this queue */ + qcfg->n_empty_polls =0 ; +/* reset the queue sleep counter as well */ + qcfg->n_sleeps =0 ; +/* remove the queue from list of cores ready to sleep */ +if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--; +/* +* no need change the lcore sleep target counter because this lcore will +* reach the n_sleeps anyway, and the other cores are already counted so +* there's no need to do anything else. +*/ +} + +static inline bool +queue_can_sleep (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +/* this function is called - that means we have an empty poll */ + qcfg->n_empty_polls++; + +/* if we haven't reached threshold for empty polls, we can't sleep */ +if (qcfg->n_empty_polls <=EMPTYPOLL_MAX ) +return false; + +/* +* we've reached a point where we are able to sleep, but we still need +* to check if this queue has already been marked for sleeping. +*/ +if (qcfg->n_sleeps == cfg->sleep_target) +return true; +Quoted 8 lines
lib/power/rte_power_pmd_mgmt.c calc_tsc(void) · line 195
Quoted 3 lines
lib/power/rte_power_pmd_mgmt.c +3
-0+/* mark this queue as ready for sleep */ + qcfg->n_sleeps = cfg->sleep_target; + cfg->n_queues_ready_to_sleep++;So, assuming there is no incoming traffic, should it be:
1)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times=1); sleep;poll_all_queues(times=1); sleep; ... OR
2)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times= EMPTYPOLL_MAX); sleep; poll_all_queues(times=Quoted 9 lines
EMPTYPOLL_MAX); sleep; ...Quoted 3 lines
?
My initial thought was 2) but might be the intention is 1)?
The intent is 1), not 2). There's no need to wait for more empty polls once we pass the threshold - we keep sleeping until there's traffic.
Quoted 6 lines
Ok, then:
Probably worth to put extra explanation here on in the doc, to help people avoid wrong assumptions😉
I don't see value in going into such details. What would be the point? Like, what difference would this information make to anyone?
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
Quoted 117 lines
-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Wednesday, July 7, 2021 12:54 PM
To: Ananyev, Konstantin <[email protected]>; [email protected]; Hunt, David <[email protected]>
Cc: Loftus, Ciara <[email protected]>
Subject: Re: [PATCH v6 5/7] power: support callbacks for multiple Rx queuesQuoted 107 lines · Konstantin
Quoted 94 lines
Quoted 46 lines
Quoted 46 lines
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues<snip>
Quoted 37 lines
....
Quoted 36 lines
lib/power/rte_power_pmd_mgmt.c +36
-0+static inline void +queue_reset (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +const bool is_ready_to_sleep = qcfg->n_empty_polls >EMPTYPOLL_MAX ; + +/* reset empty poll counter for this queue */ + qcfg->n_empty_polls =0 ; +/* reset the queue sleep counter as well */ + qcfg->n_sleeps =0 ; +/* remove the queue from list of cores ready to sleep */ +if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--; +/* +* no need change the lcore sleep target counter because this lcore will +* reach the n_sleeps anyway, and the other cores are already counted so +* there's no need to do anything else. +*/ +} + +static inline bool +queue_can_sleep (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +/* this function is called - that means we have an empty poll */ + qcfg->n_empty_polls++; + +/* if we haven't reached threshold for empty polls, we can't sleep */ +if (qcfg->n_empty_polls <=EMPTYPOLL_MAX ) +return false; + +/* +* we've reached a point where we are able to sleep, but we still need +* to check if this queue has already been marked for sleeping. +*/ +if (qcfg->n_sleeps == cfg->sleep_target) +return true; +Quoted 8 lines
lib/power/rte_power_pmd_mgmt.c calc_tsc(void) · line 195
Quoted 3 lines
lib/power/rte_power_pmd_mgmt.c +3
-0+/* mark this queue as ready for sleep */ + qcfg->n_sleeps = cfg->sleep_target; + cfg->n_queues_ready_to_sleep++;So, assuming there is no incoming traffic, should it be:
1)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times=1); sleep;poll_all_queues(times=1); sleep; ... OR
2)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times= EMPTYPOLL_MAX); sleep; poll_all_queues(times=Quoted 9 lines
EMPTYPOLL_MAX); sleep; ...Quoted 3 lines
?
My initial thought was 2) but might be the intention is 1)?
The intent is 1), not 2). There's no need to wait for more empty polls once we pass the threshold - we keep sleeping until there's traffic.
Ok, then:
Quoted 6 lines
Quoted 3 lines
Probably worth to put extra explanation here on in the doc, to help people avoid wrong assumptions😉
I don't see value in going into such details. What would be the point? Like, what difference would this information make to anyone?
I thought it is obvious: if you put extra explanation into the code, then it would be easier for anyone who reads it (reviewers/maintainers/users) to understand what it supposed to do.
Re: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
Quoted 121 lines · Konstantin
Quoted 121 lines
-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Wednesday, July 7, 2021 12:54 PM
To: Ananyev, Konstantin <[email protected]>; [email protected]; Hunt, David <[email protected]>
Cc: Loftus, Ciara <[email protected]>
Subject: Re: [PATCH v6 5/7] power: support callbacks for multiple Rx queuesQuoted 110 lines · Konstantin
Quoted 94 lines
Quoted 46 lines
Quoted 46 lines
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues<snip>
Quoted 37 lines
....
Quoted 36 lines
lib/power/rte_power_pmd_mgmt.c +36
-0+static inline void +queue_reset (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +const bool is_ready_to_sleep = qcfg->n_empty_polls >EMPTYPOLL_MAX ; + +/* reset empty poll counter for this queue */ + qcfg->n_empty_polls =0 ; +/* reset the queue sleep counter as well */ + qcfg->n_sleeps =0 ; +/* remove the queue from list of cores ready to sleep */ +if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--; +/* +* no need change the lcore sleep target counter because this lcore will +* reach the n_sleeps anyway, and the other cores are already counted so +* there's no need to do anything else. +*/ +} + +static inline bool +queue_can_sleep (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +/* this function is called - that means we have an empty poll */ + qcfg->n_empty_polls++; + +/* if we haven't reached threshold for empty polls, we can't sleep */ +if (qcfg->n_empty_polls <=EMPTYPOLL_MAX ) +return false; + +/* +* we've reached a point where we are able to sleep, but we still need +* to check if this queue has already been marked for sleeping. +*/ +if (qcfg->n_sleeps == cfg->sleep_target) +return true; +Quoted 8 lines
lib/power/rte_power_pmd_mgmt.c calc_tsc(void) · line 195
Quoted 3 lines
lib/power/rte_power_pmd_mgmt.c +3
-0+/* mark this queue as ready for sleep */ + qcfg->n_sleeps = cfg->sleep_target; + cfg->n_queues_ready_to_sleep++;So, assuming there is no incoming traffic, should it be:
1)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times=1); sleep;poll_all_queues(times=1); sleep; ... OR
2)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times= EMPTYPOLL_MAX); sleep; poll_all_queues(times=Quoted 9 lines
EMPTYPOLL_MAX); sleep; ...Quoted 3 lines
?
My initial thought was 2) but might be the intention is 1)?
The intent is 1), not 2). There's no need to wait for more empty polls once we pass the threshold - we keep sleeping until there's traffic.
Ok, then:
Probably worth to put extra explanation here on in the doc, to help people avoid wrong assumptions😉
Quoted 7 lines
Quoted 2 lines
I don't see value in going into such details. What would be the point? Like, what difference would this information make to anyone?
I thought it is obvious: if you put extra explanation into the code, then it would be easier for anyone who reads it (reviewers/maintainers/users) to understand what it supposed to do.
You're suggesting to put this *in the doc*, which implies that *the user* will find this information useful. I'm OK with adding this info as a comment somewhere perhaps, but why put it in the doc?
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
Quoted 115 lines
Quoted 115 lines
Quoted 114 lines
Quoted 105 lines
Quoted 95 lines
Quoted 47 lines
Quoted 47 lines
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues<snip>
Quoted 37 lines
....
Quoted 36 lines
(quoted diff) +36
-0+static inline void +queue_reset(struct pmd_core_cfg *cfg, struct queue_list_entry *qcfg) +{ + const bool is_ready_to_sleep = qcfg->n_empty_polls > EMPTYPOLL_MAX; + + /* reset empty poll counter for this queue */ + qcfg->n_empty_polls = 0; + /* reset the queue sleep counter as well */ + qcfg->n_sleeps = 0; + /* remove the queue from list of cores ready to sleep */ + if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--; + /* + * no need change the lcore sleep target counter because this lcore will + * reach the n_sleeps anyway, and the other cores are already counted so + * there's no need to do anything else. + */ +} + +static inline bool +queue_can_sleep(struct pmd_core_cfg *cfg, struct queue_list_entry *qcfg) +{ + /* this function is called - that means we have an empty poll */ + qcfg->n_empty_polls++; + + /* if we haven't reached threshold for empty polls, we can't sleep */ + if (qcfg->n_empty_polls <= EMPTYPOLL_MAX) + return false; + + /* + * we've reached a point where we are able to sleep, but we still need + * to check if this queue has already been marked for sleeping. + */ + if (qcfg->n_sleeps == cfg->sleep_target) + return true; +Quoted 8 lines
Review
Quoted 3 lines
(quoted diff) +3
-0+ /* mark this queue as ready for sleep */ + qcfg->n_sleeps = cfg->sleep_target; + cfg->n_queues_ready_to_sleep++;So, assuming there is no incoming traffic, should it be:
1)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times=1); sleep;poll_all_queues(times=1); sleep; ... OR
2)poll_all_queues(times=EMPTYPOLL_MAX); sleep;poll_all_queues(times= EMPTYPOLL_MAX); sleep; poll_all_queues(times=Quoted 9 lines
EMPTYPOLL_MAX); sleep; ...Quoted 3 lines
?
My initial thought was 2) but might be the intention is 1)?
The intent is 1), not 2). There's no need to wait for more empty polls once we pass the threshold - we keep sleeping until there's traffic.
Quoted 6 lines
Ok, then:
Probably worth to put extra explanation here on in the doc, to help people avoid wrong assumptions😉
I don't see value in going into such details. What would be the point? Like, what difference would this information make to anyone?
Quoted 8 lines
Quoted 4 lines
I thought it is obvious: if you put extra explanation into the code, then it would be easier for anyone who reads it (reviewers/maintainers/users) to understand what it supposed to do.
You're suggesting to put this *in the doc*, which implies that *the user* will find this information useful. I'm OK with adding this info as a comment somewhere perhaps, but why put it in the doc?
I don't really mind where you'll put it, either extra comments in that file, or few lines in the doc - both are ok to me.
Re: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
In reply to Anatoly BurakovQuoted 45 lines · Anatoly Burakov
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues
Quoted 6 lines
doc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 65 ++-- doc/guides/rel_notes/release_21_08.rst | 3 + lib/power/rte_power_pmd_mgmt.c | 452 +++++++++++++++++++------ 4 files changed, 394 insertions(+), 136 deletions(-)
--snip--
lib/power/rte_power_pmd_mgmt.c calc_tsc(void) · line 168
Quoted 13 lines
lib/power/rte_power_pmd_mgmt.c +12
-0+static inline void +queue_reset (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ +const bool is_ready_to_sleep = qcfg->n_empty_polls >EMPTYPOLL_MAX ; + +/* reset empty poll counter for this queue */ + qcfg->n_empty_polls =0 ; +/* reset the queue sleep counter as well */ + qcfg->n_sleeps =0 ; +/* remove the queue from list of cores ready to sleep */ +if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--;
Hi Anatoly,
I don't think the logic around this is bulletproof yet, in my testing I'm seeing n_queues_ready_to_sleep wrap around (i.e. decremented while already zero).
Rgds,
Dave.
--snip--
Re: [dpdk-dev] [PATCH v6 5/7] power: support callbacks for multiple Rx queues
Quoted 70 lines · David Hunt
Quoted 42 lines · Anatoly Burakov
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)
v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantin
v3:
- Move the list of supported NICs to NIC feature table
v2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queuesQuoted 6 lines
doc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 65 ++--
doc/guides/rel_notes/release_21_08.rst| 3 + lib/power/rte_power_pmd_mgmt.c | 452 +++++++++++++++++++------4 files changed, 394 insertions(+), 136 deletions(-)--snip--
lib/power/rte_power_pmd_mgmt.c calc_tsc(void) · line 168
Quoted 12 lines
lib/power/rte_power_pmd_mgmt.c +12
-0+static inline void +queue_reset (struct pmd_core_cfg *cfg,struct queue_list_entry *qcfg) +{ + const bool is_ready_to_sleep = qcfg->n_empty_polls > EMPTYPOLL_MAX; + + /* reset empty poll counter for this queue */ + qcfg->n_empty_polls = 0; + /* reset the queue sleep counter as well */ + qcfg->n_sleeps = 0; + /* remove the queue from list of cores ready to sleep */ + if (is_ready_to_sleep) + cfg->n_queues_ready_to_sleep--;Hi Anatoly,
Quoted 8 lines
I don't think the logic around this is bulletproof yet, in my
testing I'm seeingn_queues_ready_to_sleepwrap around (i.e. decremented while already zero).Rgds,
Dave.--snip--
Thanks for your testing!
It seems that number of empty polls is not a reliable indicator of whether the queue is ready to sleep, because if we get a non-empty poll right after sleep, we'll have empty poll counter still at high value, which will cause the n_queues_ready_to_sleep to decrement, even though it's at zero because we just had a sleep.
Using n_sleeps and sleep_target is better in this case. I'll submit a v7 with this fix. Thanks!
Signature · 2 lines
Thanks, Anatoly
PATCH v6 6/7 power: support monitoring multiple Rx queues
In reply to Anatoly BurakovUse the new multi-monitor intrinsic to allow monitoring multiple ethdev Rx queues while entering the energy efficient power state. The multi version will be used unconditionally if supported, and the UMWAIT one will only be used when multi-monitor is not supported by the hardware.
---
Notes:
v6:
- Fix the missed feedback from v5
v4:
- Fix possible out of bounds access
- Added missing index increment
doc/guides/prog_guide/power_man.rst | 9 ++-- lib/power/rte_power_pmd_mgmt.c | 82 ++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 5 deletions(-)
doc/guides/prog_guide/power_man.rst +6 -3
@@ -221,13 +221,16 @@ power saving whenever empty poll count reaches a certain number. The "monitor" mode is only supported in the following configurations and scenarios: * If ``rte_cpu_get_intrinsics_support()`` function indicates that + ``rte_power_monitor_multi()`` function is supported by the platform, then + monitoring multiple Ethernet Rx queues for traffic will be supported. + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that only ``rte_power_monitor()`` is supported by the platform, then monitoring will be limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be monitored from a different lcore). -* If ``rte_cpu_get_intrinsics_support()`` function indicates that the - ``rte_power_monitor()`` function is not supported, then monitor mode will not - be supported. +* If ``rte_cpu_get_intrinsics_support()`` function indicates that neither of the + two monitoring functions are supported, then monitor mode will not be supported. * Not all Ethernet drivers support monitoring, even if the underlying platform may support the necessary CPU instructions. Please refer to
lib/power/rte_power_pmd_mgmt.c +80 -2
119 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v6 6/7] power: support monitoring multiple Rx queues
Quoted 9 lines
Use the new multi-monitor intrinsic to allow monitoring multiple ethdev Rx queues while entering the energy efficient power state. The multi version will be used unconditionally if supported, and the UMWAIT one will only be used when multi-monitor is not supported by the hardware.
Signed-off-by Anatoly Burakov <[email protected]>---
Quoted 2 lines
--
2.25.1
PATCH v6 7/7 l3fwd-power: support multiqueue in PMD pmgmt modes
In reply to Anatoly BurakovCurrently, l3fwd-power enforces the limitation of having one queue per lcore. This is no longer necessary, so remove the limitation.
--- examples/l3fwd-power/main.c | 6 ------ 1 file changed, 6 deletions(-)
examples/l3fwd-power/main.c +0 -6
@@ -2723,12 +2723,6 @@ main(int argc, char **argv)printf ("\nInitializing rx queues on lcore %u ... " , lcore_id );fflush (stdout); -/* PMD power management mode can only do 1 queue per core */ -if (app_mode ==APP_MODE_PMD_MGMT && qconf->n_rx_queue >1 ) { -rte_exit (EXIT_FAILURE , -"In PMD power management mode, only one queue per lcore is allowed\n" ); - } -/* init RX queues */ for (queue =0 ; queue < qconf->n_rx_queue; ++queue) {struct rte_eth_rxconf rxq_conf;
Signature · 1 line
2.25.1
v7 cover Enhancements for PMD power management
In reply to Anatoly BurakovThis patchset introduces several changes related to PMD power management:
- Changed monitoring intrinsics to use callbacks as a comparison function, based on previous patchset [1] but incorporating feedback [2] - this hopefully will make it possible to add support for .get_monitor_addr in virtio
- Add a new intrinsic to monitor multiple addresses, based on RTM instruction set and the TPAUSE instruction
- Add support for PMD power management on multiple queues, as well as all accompanying infrastructure and example apps changes
v7:
- Fixed various bugs
v6:
- Improved the algorithm for multi-queue sleep
- Fixed segfault and addressed other feedback
v5:
- Removed "power save queue" API and replaced with mechanism suggested by Konstantin
- Addressed other feedback
v4:
- Replaced raw number with a macro
- Fixed all the bugs found by Konstantin
- Some other minor corrections
v3:
- Moved some doc updates to NIC features list
v2:
- Changed check inversion to callbacks
- Addressed feedback from Konstantin
- Added doc updates where necessary
[1] http://patches.dpdk.org/project/dpdk/list/?series=16930&state=*
[2] http://patches.dpdk.org/project/dpdk/patch/819ef1ace187365a615d3383e54579e3d9fb216e.1620747068.git.anatoly.burakov@intel.com/#133274
Anatoly Burakov (7):
power_intrinsics: use callbacks for comparison net/af_xdp: add power monitor support
eal: add power monitor for multiple events
power: remove thread safety from PMD power API's
power: support callbacks for multiple Rx queues
power: support monitoring multiple Rx queues
l3fwd-power: support multiqueue in PMD pmgmt modes
doc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 74 +- doc/guides/rel_notes/release_21_08.rst | 9 + drivers/event/dlb2/dlb2.c | 17 +- drivers/net/af_xdp/rte_eth_af_xdp.c | 34 + drivers/net/i40e/i40e_rxtx.c | 20 +- drivers/net/iavf/iavf_rxtx.c | 20 +- drivers/net/ice/ice_rxtx.c | 20 +- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +- drivers/net/mlx5/mlx5_rx.c | 17 +- examples/l3fwd-power/main.c | 6 - lib/eal/arm/rte_power_intrinsics.c | 11 + lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 68 +- lib/eal/ppc/rte_power_intrinsics.c | 11 + lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 90 ++- lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 659 +++++++++++++----- lib/power/rte_power_pmd_mgmt.h | 6 + 21 files changed, 840 insertions(+), 262 deletions(-)
Signature · 1 line
2.25.1
PATCH v7 1/7 power_intrinsics: use callbacks for comparison
Previously, the semantics of power monitor were such that we were checking current value against the expected value, and if they matched, then the sleep was aborted. This is somewhat inflexible, because it only allowed us to check for a specific value in a specific way.
This commit replaces the comparison with a user callback mechanism, so that any PMD (or other code) using rte_power_monitor() can define their own comparison semantics and decision making on how to detect the need to abort the entering of power optimized state.
Existing implementations are adjusted to follow the new semantics.
---
Notes:
v4:
- Return error if callback is set to NULL
- Replace raw number with a macro in monitor condition opaque data
v2:
- Use callback mechanism for more flexibility
- Address feedback from Konstantin
doc/guides/rel_notes/release_21_08.rst | 2 ++ drivers/event/dlb2/dlb2.c | 17 ++++++++-- drivers/net/i40e/i40e_rxtx.c | 20 +++++++---- drivers/net/iavf/iavf_rxtx.c | 20 +++++++---- drivers/net/ice/ice_rxtx.c | 20 +++++++---- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +++++++---- drivers/net/mlx5/mlx5_rx.c | 17 ++++++++-- .../include/generic/rte_power_intrinsics.h | 33 +++++++++++++++---- lib/eal/x86/rte_power_intrinsics.c | 17 +++++----- 9 files changed, 122 insertions(+), 44 deletions(-)
doc/guides/rel_notes/release_21_08.rst +2 -0
@@ -117,6 +117,8 @@ API Changes * eal: ``rte_strscpy`` sets ``rte_errno`` to ``E2BIG`` in case of string truncation. +* eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. + ABI Changes -----------
drivers/event/dlb2/dlb2.c +15 -2
@@ -3154,6 +3154,16 @@ dlb2_port_credits_inc(struct dlb2_port *qm_port, int num) } } +#define CLB_MASK_IDX 0 +#define CLB_VAL_IDX 1 +static int +dlb2_monitor_callback (const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +/* abort if the value matches */ +return (val & opaque[CLB_MASK_IDX ]) == opaque[CLB_VAL_IDX ] ?-1 :0 ; +} + static inline int dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, struct dlb2_eventdev_port *ev_port,
@@ -3194,8 +3204,11 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, expected_value =0 ; pmc.addr = monitor_addr; - pmc.val = expected_value; - pmc.mask = qe_mask.raw_qe[1 ]; +/* store expected value and comparison mask in opaque data */ + pmc.opaque[CLB_VAL_IDX ] = expected_value; + pmc.opaque[CLB_MASK_IDX ] = qe_mask.raw_qe[1 ]; +/* set up callback */ + pmc.fn = dlb2_monitor_callback; pmc.size =sizeof (uint64_t );rte_power_monitor (&pmc, timeout + start_ticks);
drivers/net/i40e/i40e_rxtx.c +14 -6
@@ -81,6 +81,18 @@#define I40E_TX_OFFLOAD_SIMPLE_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_SIMPLE_SUP_MASK) +static int +i40e_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int i40e_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -93,12 +105,8 @@ i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* comparison callback */ + pmc->fn = i40e_monitor_callback;/* registers are 64-bit */ pmc->size =sizeof (uint64_t );
drivers/net/iavf/iavf_rxtx.c +14 -6
@@ -57,6 +57,18 @@ iavf_proto_xtr_type_to_rxdid(uint8_t flex_type) rxdid_map[flex_type] : IAVF_RXDID_COMMS_OVS_1; } +static int +iavf_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int iavf_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -69,12 +81,8 @@ iavf_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* comparison callback */ + pmc->fn = iavf_monitor_callback;/* registers are 64-bit */ pmc->size =sizeof (uint64_t );
drivers/net/ice/ice_rxtx.c +14 -6
@@ -27,6 +27,18 @@ 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; +static int +ice_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ice_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -39,12 +51,8 @@ ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.status_error0; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); - pmc->mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* comparison callback */ + pmc->fn = ice_monitor_callback;/* register is 16-bit */ pmc->size =sizeof (uint16_t );
drivers/net/ixgbe/ixgbe_rxtx.c +14 -6
@@ -1369,6 +1369,18 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +static int +ixgbe_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ixgbe_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -1381,12 +1393,8 @@ ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.upper.status_error; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); - pmc->mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* comparison callback */ + pmc->fn = ixgbe_monitor_callback;/* the registers are 32-bit */ pmc->size =sizeof (uint32_t );
drivers/net/mlx5/mlx5_rx.c +15 -2
@@ -269,6 +269,18 @@ mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)return rx_queue_count (rxq); } +#define CLB_VAL_IDX 0 +#define CLB_MSK_IDX 1 +static int +mlx_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t m = opaque[CLB_MSK_IDX ]; +const uint64_t v = opaque[CLB_VAL_IDX ]; + +return (value & m) == v ?-1 :0 ; +} +int mlx5_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {struct mlx5_rxq_data *rxq = rx_queue;
@@ -282,8 +294,9 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)return -rte_errno; } pmc->addr = &cqe->op_own; - pmc->val = !!idx; - pmc->mask =MLX5_CQE_OWNER_MASK ; + pmc->opaque[CLB_VAL_IDX ] = !!idx; + pmc->opaque[CLB_MSK_IDX ] =MLX5_CQE_OWNER_MASK ; + pmc->fn = mlx_monitor_callback; pmc->size =sizeof (uint8_t );return 0 ; }
lib/eal/include/generic/rte_power_intrinsics.h +26 -7
@@ -18,19 +18,38 @@* which are architecture-dependent. */ +/** Size of the opaque data in monitor condition */ +#define RTE_POWER_MONITOR_OPAQUE_SZ 4 + +/** +* Callback definition for monitoring conditions. Callbacks with this signature +* will be used by `rte_power_monitor()` to check if the entering of power +* optimized state should be aborted. +* +* @param val +* The value read from memory. +* @param opaque +* Callback-specific data. +* +* @return +* 0 if entering of power optimized state should proceed +* -1 if entering of power optimized state should be aborted +*/ +typedef int (*rte_power_monitor_clb_t )(const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]);struct rte_power_monitor_cond {volatile void *addr;/**< Address to monitor for changes */ -uint64_t val;/**< If the `mask` is non-zero, location pointed -* to by `addr` will be read and compared -* against this value. -*/ -uint64_t mask;/**< 64-bit mask to extract value read from `addr` */ -uint8_t size;/**< Data size (in bytes) that will be used to compare -* expected value (`val`) with data read from the +uint8_t size;/**< Data size (in bytes) that will be read from the * monitored memory location (`addr`). Can be 1, 2, * 4, or 8. Supplying any other value will result in * an error. */ +rte_power_monitor_clb_t fn;/**< Callback to be used to check if +* entering power optimized state should +* be aborted. +*/ +uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]; +/**< Callback-specific data */ };/**
lib/eal/x86/rte_power_intrinsics.c +8 -9
@@ -76,6 +76,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 );const unsigned int lcore_id =rte_lcore_id ();struct power_wait_status *s; +uint64_t cur_value;/* prevent user from running this instruction if it's not supported */ if (!wait_supported)
@@ -91,6 +92,9 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,if (__check_val_size (pmc->size) <0 )return -EINVAL ; +if (pmc->fn ==NULL ) +return -EINVAL ; + s = &wait_status[lcore_id];/* update sleep address */
@@ -110,16 +114,11 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,/* now that we've put this address into monitor, we can unlock */ rte_spinlock_unlock (&s->lock); -/* if we have a comparison mask, we might not need to sleep at all */ -if (pmc->mask) { -const uint64_t cur_value =__get_umwait_val ( - pmc->addr, pmc->size); -const uint64_t masked = cur_value & pmc->mask; + cur_value =__get_umwait_val (pmc->addr, pmc->size); -/* if the masked value is already matching, abort */ -if (masked == pmc->val) - goto end; - } +/* check if callback indicates we should abort */ +if (pmc->fn (cur_value, pmc->opaque) !=0 ) + goto end;/* execute UMWAIT */ asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v7 1/7] power_intrinsics: use callbacks for comparison
Quoted 17 lines · Anatoly Burakov
Previously, the semantics of power monitor were such that we were checking current value against the expected value, and if they matched, then the sleep was aborted. This is somewhat inflexible, because it only allowed us to check for a specific value in a specific way.
This commit replaces the comparison with a user callback mechanism, so that any PMD (or other code) using
rte_power_monitor()can define their own comparison semantics and decision making on how to detect the need to abort the entering of power optimized state.Existing implementations are adjusted to follow the new semantics.
Suggested-by Konstantin Ananyev <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
Quoted 10 lines
Notes:
v4:
- Return error if callback is set to NULL
- Replace raw number with a macro in monitor condition opaque datav2:
- Use callback mechanism for more flexibility
- Address feedback from Konstantin
PATCH v7 2/7 net/af_xdp: add power monitor support
In reply to Anatoly BurakovImplement support for .get_monitor_addr in AF_XDP driver.
---
Notes:
v2:
- Rewrite using the callback mechanism
drivers/net/af_xdp/rte_eth_af_xdp.c | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
drivers/net/af_xdp/rte_eth_af_xdp.c +34 -0
@@ -37,6 +37,7 @@#include <rte_malloc.h> #include <rte_ring.h> #include <rte_spinlock.h> +#include <rte_power_intrinsics.h> #include "compat.h"
@@ -788,6 +789,38 @@ eth_dev_configure(struct rte_eth_dev *dev)return 0 ; } +#define CLB_VAL_IDX 0 +static int +eth_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t v = opaque[CLB_VAL_IDX ]; +const uint64_t m = (uint32_t )~0 ; + +/* if the value has changed, abort entering power optimized state */ +return (value & m) == v ?0 :-1 ; +} + +static int +eth_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) +{ +struct pkt_rx_queue *rxq = rx_queue; +unsigned int *prod = rxq->rx.producer; +const uint32_t cur_val = rxq->rx.cached_prod;/* use cached value */ + +/* watch for changes in producer ring */ + pmc->addr = (void *)prod; + +/* store current value */ + pmc->opaque[CLB_VAL_IDX ] = cur_val; + pmc->fn = eth_monitor_callback; + +/* AF_XDP producer ring index is 32-bit */ + pmc->size =sizeof (uint32_t ); + +return 0 ; +} +static int eth_dev_info (struct rte_eth_dev *dev,struct rte_eth_dev_info *dev_info) {
@@ -1448,6 +1481,7 @@ static const struct eth_dev_ops ops = { .link_update = eth_link_update, .stats_get = eth_stats_get, .stats_reset = eth_stats_reset, + .get_monitor_addr = eth_get_monitor_addr };/** parse busy_budget argument */
Signature · 1 line
2.25.1
PATCH v7 3/7 eal: add power monitor for multiple events
In reply to Anatoly BurakovUse RTM and WAITPKG instructions to perform a wait-for-writes similar to what UMWAIT does, but without the limitation of having to listen for just one event. This works because the optimized power state used by the TPAUSE instruction will cause a wake up on RTM transaction abort, so if we add the addresses we're interested in to the read-set, any write to those addresses will wake us up.
---
Notes:
v4:
- Fixed bugs in accessing the monitor condition
- Abort on any monitor condition not having a defined callback
v2:
- Adapt to callback mechanism
lib/eal/arm/rte_power_intrinsics.c | 11 +++ lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 35 +++++++++ lib/eal/ppc/rte_power_intrinsics.c | 11 +++ lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 73 +++++++++++++++++++ 7 files changed, 137 insertions(+)
lib/eal/arm/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/include/generic/rte_cpuflags.h +2 -0
@@ -24,6 +24,8 @@ struct rte_cpu_intrinsics {/**< indicates support for rte_power_monitor function */ uint32_t power_pause : 1;/**< indicates support for rte_power_pause function */ + uint32_t power_monitor_multi : 1; +/**< indicates support for rte_power_monitor_multi function */ };/**
lib/eal/include/generic/rte_power_intrinsics.h +35 -0
@@ -128,4 +128,39 @@ int rte_power_monitor_wakeup(const unsigned int lcore_id);__rte_experimental int rte_power_pause(const uint64_t tsc_timestamp); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* Monitor a set of addresses for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either one of the specified +* memory addresses is written to, a certain TSC timestamp is reached, or other +* reasons cause the CPU to wake up. +* +* Additionally, `expected` 64-bit values and 64-bit masks 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 do not 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_intrinsics_support()` API call. +* Failing to do so may result in an illegal CPU instruction error. +* +* @param pmc +* An array of monitoring condition structures. +* @param num +* Length of the `pmc` array. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* 0 on success +* -EINVAL on invalid parameters +* -ENOTSUP if unsupported +*/ +__rte_experimental +int rte_power_monitor_multi(const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp); +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/eal/ppc/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/version.map +3 -0
@@ -423,6 +423,9 @@ EXPERIMENTAL { rte_version_release; # WINDOWS_NO_EXPORT rte_version_suffix; # WINDOWS_NO_EXPORT rte_version_year; # WINDOWS_NO_EXPORT + + # added in 21.08 + rte_power_monitor_multi; # WINDOWS_NO_EXPORT }; INTERNAL {
lib/eal/x86/rte_cpuflags.c +2 -0
@@ -189,5 +189,7 @@ rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { intrinsics->power_monitor =1 ; intrinsics->power_pause =1 ; +if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_RTM )) + intrinsics->power_monitor_multi =1 ; } }
lib/eal/x86/rte_power_intrinsics.c +73 -0
100 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v7 3/7] eal: add power monitor for multiple events
Quoted 11 lines · Anatoly Burakov
Use RTM and WAITPKG instructions to perform a wait-for-writes similar to what UMWAIT does, but without the limitation of having to listen for just one event. This works because the optimized power state used by the TPAUSE instruction will cause a wake up on RTM transaction abort, so if we add the addresses we're interested in to the read-set, any write to those addresses will wake us up.
Signed-off-by Konstantin Ananyev <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
Quoted 8 lines
Notes:
v4:
- Fixed bugs in accessing the monitor condition
- Abort on any monitor condition not having a defined callbackv2:
- Adapt to callback mechanism
Initially I had issues running this as I couldn't see the "rtm" flag in /proc/cpuinfo, but adding "tsx=on" to the kernel parameters resolved this, and rtm was then available to use. Once this was done, I was then able to successfully see power saving when a core was configuired with multiple queues.
PATCH v7 4/7 power: remove thread safety from PMD power API's
In reply to Anatoly BurakovCurrently, we expect that only one callback can be active at any given moment, for a particular queue configuration, which is relatively easy to implement in a thread-safe way. However, we're about to add support for multiple queues per lcore, which will greatly increase the possibility of various race conditions.
We could have used something like an RCU for this use case, but absent of a pressing need for thread safety we'll go the easy way and just mandate that the API's are to be called when all affected ports are stopped, and document this limitation. This greatly simplifies the rte_power_monitor-related code.
---
Notes:
v2:
- Add check for stopped queue
- Clarified doc message
- Added release notes
doc/guides/rel_notes/release_21_08.rst | 4 + lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 133 ++++++++++--------------- lib/power/rte_power_pmd_mgmt.h | 6 ++ 4 files changed, 66 insertions(+), 80 deletions(-)
doc/guides/rel_notes/release_21_08.rst +4 -0
@@ -119,6 +119,10 @@ API Changes * eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. +* rte_power: The experimental PMD power management API is no longer considered + to be thread safe; all Rx queues affected by the API will now need to be + stopped before making any changes to the power management scheme. + ABI Changes -----------
lib/power/meson.build +3 -0
@@ -21,4 +21,7 @@ headers = files( 'rte_power_pmd_mgmt.h', 'rte_power_guest_channel.h', ) +if cc.has_argument('-Wno-cast-qual') + cflags += '-Wno-cast-qual' +endif deps += ['timer', 'ethdev']
lib/power/rte_power_pmd_mgmt.c +53 -80
209 lines not on this page · raw message
lib/power/rte_power_pmd_mgmt.h +6 -0
@@ -43,6 +43,9 @@ enum rte_power_pmd_mgmt_type {* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue will be polled from. * @param port_id
@@ -69,6 +72,9 @@ rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id,* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue is polled from. * @param port_id
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v7 4/7] power: remove thread safety from PMD power API's
Quoted 12 lines · Anatoly Burakov
Currently, we expect that only one callback can be active at any given moment, for a particular queue configuration, which is relatively easy to implement in a thread-safe way. However, we're about to add support for multiple queues per lcore, which will greatly increase the possibility of various race conditions.
We could have used something like an RCU for this use case, but absent of a pressing need for thread safety we'll go the easy way and just mandate that the API's are to be called when all affected ports are stopped, and document this limitation. This greatly simplifies the
rte_power_monitor-related code.
Quoted 9 lines
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v2:
- Add check for stopped queue
- Clarified doc message
- Added release notes
PATCH v7 5/7 power: support callbacks for multiple Rx queues
In reply to Anatoly BurakovCurrently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.
Also, while we're at it, update and improve the docs.
---
Notes:
v7:
- Fix bug where initial sleep target was always set to zero
- Fix logic in handling of n_queues_ready_to_sleep counter
- Update documentation on hardware requirements
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)
v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantin
v3:
- Move the list of supported NICs to NIC feature table
v2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues
doc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 69 ++-- doc/guides/rel_notes/release_21_08.rst | 3 + lib/power/rte_power_pmd_mgmt.c | 456 +++++++++++++++++++------ 4 files changed, 402 insertions(+), 136 deletions(-)
doc/guides/nics/features.rst +10 -0
@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``. +.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` + .. _nic_features_other: Other dev ops not represented by a Feature
doc/guides/prog_guide/power_man.rst +41 -28
78 lines not on this page · raw message
doc/guides/rel_notes/release_21_08.rst +3 -0
@@ -85,6 +85,9 @@ New Features usecases. Configuration happens via standard rawdev enq/deq operations. See the :doc:`../rawdevs/cnxk_bphy` rawdev guide for more details on this driver. +* rte_power: The experimental PMD power management API now supports managing + multiple Ethernet Rx queues per lcore. + Removed Items -------------
lib/power/rte_power_pmd_mgmt.c +348 -108
571 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v7 5/7] power: support callbacks for multiple Rx queues
Quoted 50 lines · Anatoly Burakov
Currently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.Also, while we're at it, update and improve the docs.
Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v7:
- Fix bug where initial sleep target was always set to zero
- Fix logic in handling ofn_queues_ready_to_sleepcounter
- Update documentation on hardware requirementsv6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantinv3:
- Move the list of supported NICs to NIC feature tablev2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues
Quoted 6 lines
doc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 69 ++-- doc/guides/rel_notes/release_21_08.rst | 3 + lib/power/rte_power_pmd_mgmt.c | 456 +++++++++++++++++++------ 4 files changed, 402 insertions(+), 136 deletions(-)
--snip--
Thanks Anatoly. Not seeing the rollover now, and power savings are back as expected when low traffic in both monitor and pause modes. All previous issues seem now to be resolved.
Patch set LGTM.
PATCH v7 6/7 power: support monitoring multiple Rx queues
In reply to Anatoly BurakovUse the new multi-monitor intrinsic to allow monitoring multiple ethdev Rx queues while entering the energy efficient power state. The multi version will be used unconditionally if supported, and the UMWAIT one will only be used when multi-monitor is not supported by the hardware.
---
Notes:
v6:
- Fix the missed feedback from v5
v4:
- Fix possible out of bounds access
- Added missing index increment
doc/guides/prog_guide/power_man.rst | 15 ++++-- lib/power/rte_power_pmd_mgmt.c | 82 ++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 7 deletions(-)
doc/guides/prog_guide/power_man.rst +10 -5
@@ -221,17 +221,22 @@ power saving whenever empty poll count reaches a certain number. The "monitor" mode is only supported in the following configurations and scenarios: * On Linux* x86_64, `rte_power_monitor()` requires WAITPKG instruction set being - supported by the CPU. Please refer to your platform documentation for further - information. + supported by the CPU, while `rte_power_monitor_multi()` requires WAITPKG and + RTM instruction sets being supported by the CPU. RTM instruction set may also + require booting the Linux with `tsx=on` command line parameter. Please refer + to your platform documentation for further information. * If ``rte_cpu_get_intrinsics_support()`` function indicates that + ``rte_power_monitor_multi()`` function is supported by the platform, then + monitoring multiple Ethernet Rx queues for traffic will be supported. + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that only ``rte_power_monitor()`` is supported by the platform, then monitoring will be limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be monitored from a different lcore). -* If ``rte_cpu_get_intrinsics_support()`` function indicates that the - ``rte_power_monitor()`` function is not supported, then monitor mode will not - be supported. +* If ``rte_cpu_get_intrinsics_support()`` function indicates that neither of the + two monitoring functions are supported, then monitor mode will not be supported. * Not all Ethernet drivers support monitoring, even if the underlying platform may support the necessary CPU instructions. Please refer to
lib/power/rte_power_pmd_mgmt.c +80 -2
119 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v7 6/7] power: support monitoring multiple Rx queues
Quoted 8 lines · Anatoly Burakov
Use the new multi-monitor intrinsic to allow monitoring multiple ethdev Rx queues while entering the energy efficient power state. The multi version will be used unconditionally if supported, and the UMWAIT one will only be used when multi-monitor is not supported by the hardware.
Signed-off-by Anatoly Burakov <[email protected]>---
Quoted 9 lines
Notes:
v6:
- Fix the missed feedback from v5v4:
- Fix possible out of bounds access
- Added missing index increment
--snip--
PATCH v7 7/7 l3fwd-power: support multiqueue in PMD pmgmt modes
In reply to Anatoly BurakovCurrently, l3fwd-power enforces the limitation of having one queue per lcore. This is no longer necessary, so remove the limitation.
--- examples/l3fwd-power/main.c | 6 ------ 1 file changed, 6 deletions(-)
examples/l3fwd-power/main.c +0 -6
@@ -2723,12 +2723,6 @@ main(int argc, char **argv)printf ("\nInitializing rx queues on lcore %u ... " , lcore_id );fflush (stdout); -/* PMD power management mode can only do 1 queue per core */ -if (app_mode ==APP_MODE_PMD_MGMT && qconf->n_rx_queue >1 ) { -rte_exit (EXIT_FAILURE , -"In PMD power management mode, only one queue per lcore is allowed\n" ); - } -/* init RX queues */ for (queue =0 ; queue < qconf->n_rx_queue; ++queue) {struct rte_eth_rxconf rxq_conf;
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v7 7/7] l3fwd-power: support multiqueue in PMD pmgmt modes
Quoted 15 lines · Anatoly Burakov
Currently, l3fwd-power enforces the limitation of having one queue per lcore. This is no longer necessary, so remove the limitation.
Signed-off-by Anatoly Burakov <[email protected]>--- examples/l3fwd-power/main.c | 6 ------ 1 file changed, 6 deletions(-)examples/l3fwd-power/main.c +0
-0@@ -2723,12 +2723,6 @@ main(int argc, char **argv)printf ("\nInitializing rx queues on lcore %u ... " , lcore_id );fflush (stdout);
examples/l3fwd-power/main.c main(int argc, char **argv) · line 2728
Quoted 10 lines
examples/l3fwd-power/main.c +0
-6-/* PMD power management mode can only do 1 queue per core */ -if (app_mode ==APP_MODE_PMD_MGMT && qconf->n_rx_queue >1 ) { -rte_exit (EXIT_FAILURE , -"In PMD power management mode, only one queue per lcore is allowed\n" ); - } -/* init RX queues */ for (queue =0 ; queue < qconf->n_rx_queue; ++queue) {struct rte_eth_rxconf rxq_conf;
v8 cover Enhancements for PMD power management
In reply to Anatoly BurakovThis patchset introduces several changes related to PMD power management:
- Changed monitoring intrinsics to use callbacks as a comparison function, based on previous patchset [1] but incorporating feedback [2] - this hopefully will make it possible to add support for .get_monitor_addr in virtio
- Add a new intrinsic to monitor multiple addresses, based on RTM instruction set and the TPAUSE instruction
- Add support for PMD power management on multiple queues, as well as all accompanying infrastructure and example apps changes
v8:
- Fixed checkpatch issue
- Added comment explaining empty poll handling (Konstantin)
v7:
- Fixed various bugs
v6:
- Improved the algorithm for multi-queue sleep
- Fixed segfault and addressed other feedback
v5:
- Removed "power save queue" API and replaced with mechanism suggested by Konstantin
- Addressed other feedback
v4:
- Replaced raw number with a macro
- Fixed all the bugs found by Konstantin
- Some other minor corrections
v3:
- Moved some doc updates to NIC features list
v2:
- Changed check inversion to callbacks
- Addressed feedback from Konstantin
- Added doc updates where necessary
[1] http://patches.dpdk.org/project/dpdk/list/?series=16930&state=*
[2] http://patches.dpdk.org/project/dpdk/patch/819ef1ace187365a615d3383e54579e3d9fb216e.1620747068.git.anatoly.burakov@intel.com/#133274
Anatoly Burakov (7):
power_intrinsics: use callbacks for comparison net/af_xdp: add power monitor support
eal: add power monitor for multiple events
power: remove thread safety from PMD power API's
power: support callbacks for multiple Rx queues
power: support monitoring multiple Rx queues
l3fwd-power: support multiqueue in PMD pmgmt modes
doc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 74 +- doc/guides/rel_notes/release_21_08.rst | 9 + drivers/event/dlb2/dlb2.c | 17 +- drivers/net/af_xdp/rte_eth_af_xdp.c | 34 + drivers/net/i40e/i40e_rxtx.c | 20 +- drivers/net/iavf/iavf_rxtx.c | 20 +- drivers/net/ice/ice_rxtx.c | 20 +- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +- drivers/net/mlx5/mlx5_rx.c | 17 +- examples/l3fwd-power/main.c | 6 - lib/eal/arm/rte_power_intrinsics.c | 11 + lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 68 +- lib/eal/ppc/rte_power_intrinsics.c | 11 + lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 90 ++- lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 663 +++++++++++++----- lib/power/rte_power_pmd_mgmt.h | 6 + 21 files changed, 844 insertions(+), 262 deletions(-)
Signature · 1 line
2.25.1
PATCH v8 1/7 power_intrinsics: use callbacks for comparison
Previously, the semantics of power monitor were such that we were checking current value against the expected value, and if they matched, then the sleep was aborted. This is somewhat inflexible, because it only allowed us to check for a specific value in a specific way.
This commit replaces the comparison with a user callback mechanism, so that any PMD (or other code) using rte_power_monitor() can define their own comparison semantics and decision making on how to detect the need to abort the entering of power optimized state.
Existing implementations are adjusted to follow the new semantics.
---
Notes:
v4:
- Return error if callback is set to NULL
- Replace raw number with a macro in monitor condition opaque data
v2:
- Use callback mechanism for more flexibility
- Address feedback from Konstantin
doc/guides/rel_notes/release_21_08.rst | 2 ++ drivers/event/dlb2/dlb2.c | 17 ++++++++-- drivers/net/i40e/i40e_rxtx.c | 20 +++++++---- drivers/net/iavf/iavf_rxtx.c | 20 +++++++---- drivers/net/ice/ice_rxtx.c | 20 +++++++---- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +++++++---- drivers/net/mlx5/mlx5_rx.c | 17 ++++++++-- .../include/generic/rte_power_intrinsics.h | 33 +++++++++++++++---- lib/eal/x86/rte_power_intrinsics.c | 17 +++++----- 9 files changed, 122 insertions(+), 44 deletions(-)
doc/guides/rel_notes/release_21_08.rst +2 -0
@@ -135,6 +135,8 @@ API Changes * eal: ``rte_strscpy`` sets ``rte_errno`` to ``E2BIG`` in case of string truncation. +* eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. + ABI Changes -----------
drivers/event/dlb2/dlb2.c +15 -2
@@ -3154,6 +3154,16 @@ dlb2_port_credits_inc(struct dlb2_port *qm_port, int num) } } +#define CLB_MASK_IDX 0 +#define CLB_VAL_IDX 1 +static int +dlb2_monitor_callback (const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +/* abort if the value matches */ +return (val & opaque[CLB_MASK_IDX ]) == opaque[CLB_VAL_IDX ] ?-1 :0 ; +} + static inline int dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, struct dlb2_eventdev_port *ev_port,
@@ -3194,8 +3204,11 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, expected_value =0 ; pmc.addr = monitor_addr; - pmc.val = expected_value; - pmc.mask = qe_mask.raw_qe[1 ]; +/* store expected value and comparison mask in opaque data */ + pmc.opaque[CLB_VAL_IDX ] = expected_value; + pmc.opaque[CLB_MASK_IDX ] = qe_mask.raw_qe[1 ]; +/* set up callback */ + pmc.fn = dlb2_monitor_callback; pmc.size =sizeof (uint64_t );rte_power_monitor (&pmc, timeout + start_ticks);
drivers/net/i40e/i40e_rxtx.c +14 -6
@@ -81,6 +81,18 @@#define I40E_TX_OFFLOAD_SIMPLE_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_SIMPLE_SUP_MASK) +static int +i40e_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int i40e_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -93,12 +105,8 @@ i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* comparison callback */ + pmc->fn = i40e_monitor_callback;/* registers are 64-bit */ pmc->size =sizeof (uint64_t );
drivers/net/iavf/iavf_rxtx.c +14 -6
@@ -57,6 +57,18 @@ iavf_proto_xtr_type_to_rxdid(uint8_t flex_type) rxdid_map[flex_type] : IAVF_RXDID_COMMS_OVS_1; } +static int +iavf_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int iavf_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -69,12 +81,8 @@ iavf_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* comparison callback */ + pmc->fn = iavf_monitor_callback;/* registers are 64-bit */ pmc->size =sizeof (uint64_t );
drivers/net/ice/ice_rxtx.c +14 -6
@@ -27,6 +27,18 @@ 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; +static int +ice_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ice_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -39,12 +51,8 @@ ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.status_error0; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); - pmc->mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* comparison callback */ + pmc->fn = ice_monitor_callback;/* register is 16-bit */ pmc->size =sizeof (uint16_t );
drivers/net/ixgbe/ixgbe_rxtx.c +14 -6
@@ -1369,6 +1369,18 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +static int +ixgbe_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ixgbe_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -1381,12 +1393,8 @@ ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.upper.status_error; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); - pmc->mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* comparison callback */ + pmc->fn = ixgbe_monitor_callback;/* the registers are 32-bit */ pmc->size =sizeof (uint32_t );
drivers/net/mlx5/mlx5_rx.c +15 -2
@@ -269,6 +269,18 @@ mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)return rx_queue_count (rxq); } +#define CLB_VAL_IDX 0 +#define CLB_MSK_IDX 1 +static int +mlx_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t m = opaque[CLB_MSK_IDX ]; +const uint64_t v = opaque[CLB_VAL_IDX ]; + +return (value & m) == v ?-1 :0 ; +} +int mlx5_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {struct mlx5_rxq_data *rxq = rx_queue;
@@ -282,8 +294,9 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)return -rte_errno; } pmc->addr = &cqe->op_own; - pmc->val = !!idx; - pmc->mask =MLX5_CQE_OWNER_MASK ; + pmc->opaque[CLB_VAL_IDX ] = !!idx; + pmc->opaque[CLB_MSK_IDX ] =MLX5_CQE_OWNER_MASK ; + pmc->fn = mlx_monitor_callback; pmc->size =sizeof (uint8_t );return 0 ; }
lib/eal/include/generic/rte_power_intrinsics.h +26 -7
@@ -18,19 +18,38 @@* which are architecture-dependent. */ +/** Size of the opaque data in monitor condition */ +#define RTE_POWER_MONITOR_OPAQUE_SZ 4 + +/** +* Callback definition for monitoring conditions. Callbacks with this signature +* will be used by `rte_power_monitor()` to check if the entering of power +* optimized state should be aborted. +* +* @param val +* The value read from memory. +* @param opaque +* Callback-specific data. +* +* @return +* 0 if entering of power optimized state should proceed +* -1 if entering of power optimized state should be aborted +*/ +typedef int (*rte_power_monitor_clb_t )(const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]);struct rte_power_monitor_cond {volatile void *addr;/**< Address to monitor for changes */ -uint64_t val;/**< If the `mask` is non-zero, location pointed -* to by `addr` will be read and compared -* against this value. -*/ -uint64_t mask;/**< 64-bit mask to extract value read from `addr` */ -uint8_t size;/**< Data size (in bytes) that will be used to compare -* expected value (`val`) with data read from the +uint8_t size;/**< Data size (in bytes) that will be read from the * monitored memory location (`addr`). Can be 1, 2, * 4, or 8. Supplying any other value will result in * an error. */ +rte_power_monitor_clb_t fn;/**< Callback to be used to check if +* entering power optimized state should +* be aborted. +*/ +uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]; +/**< Callback-specific data */ };/**
lib/eal/x86/rte_power_intrinsics.c +8 -9
@@ -76,6 +76,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 );const unsigned int lcore_id =rte_lcore_id ();struct power_wait_status *s; +uint64_t cur_value;/* prevent user from running this instruction if it's not supported */ if (!wait_supported)
@@ -91,6 +92,9 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,if (__check_val_size (pmc->size) <0 )return -EINVAL ; +if (pmc->fn ==NULL ) +return -EINVAL ; + s = &wait_status[lcore_id];/* update sleep address */
@@ -110,16 +114,11 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,/* now that we've put this address into monitor, we can unlock */ rte_spinlock_unlock (&s->lock); -/* if we have a comparison mask, we might not need to sleep at all */ -if (pmc->mask) { -const uint64_t cur_value =__get_umwait_val ( - pmc->addr, pmc->size); -const uint64_t masked = cur_value & pmc->mask; + cur_value =__get_umwait_val (pmc->addr, pmc->size); -/* if the masked value is already matching, abort */ -if (masked == pmc->val) - goto end; - } +/* check if callback indicates we should abort */ +if (pmc->fn (cur_value, pmc->opaque) !=0 ) + goto end;/* execute UMWAIT */ asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v8 1/7] power_intrinsics: use callbacks for comparison
Quoted 410 lines
-----Original Message-----
From: Burakov, Anatoly <[email protected]>
Sent: Thursday, July 8, 2021 9:14 AM
To: [email protected]; McDaniel, Timothy <[email protected]>; Xing, Beilei <[email protected]>; Wu, Jingjing <[email protected]>; Yang, Qiming <[email protected]>; Zhang, Qi Z <[email protected]>; Wang, Haiyue <[email protected]>; Matan Azrad <[email protected]>; Shahaf Shuler <[email protected]>; Viacheslav Ovsiienko <[email protected]>; Richardson, Bruce <[email protected]>; Ananyev, Konstantin <[email protected]>
Cc: Loftus, Ciara <[email protected]>; Hunt, David <[email protected]>
Subject: [PATCH v8 1/7]power_intrinsics: use callbacks for comparisonPreviously, the semantics of power monitor were such that we were checking current value against the expected value, and if they matched, then the sleep was aborted. This is somewhat inflexible, because it only allowed us to check for a specific value in a specific way.
This commit replaces the comparison with a user callback mechanism, so that any PMD (or other code) using
rte_power_monitor()can define their own comparison semantics and decision making on how to detect the need to abort the entering of power optimized state.Existing implementations are adjusted to follow the new semantics.
Suggested-by Konstantin Ananyev <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>---
Notes:
v4:
- Return error if callback is set to NULL
- Replace raw number with a macro in monitor condition opaque datav2:
- Use callback mechanism for more flexibility
- Address feedback from Konstantindoc/guides/rel_notes/release_21_08.rst | 2 ++ drivers/event/dlb2/dlb2.c | 17 ++++++++-- drivers/net/i40e/i40e_rxtx.c | 20 +++++++---- drivers/net/iavf/iavf_rxtx.c | 20 +++++++---- drivers/net/ice/ice_rxtx.c | 20 +++++++---- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +++++++---- drivers/net/mlx5/mlx5_rx.c | 17 ++++++++-- .../include/generic/rte_power_intrinsics.h | 33 +++++++++++++++---- lib/eal/x86/rte_power_intrinsics.c | 17 +++++----- 9 files changed, 122 insertions(+), 44 deletions(-)doc/guides/rel_notes/release_21_08.rst +2
-0@@ -135,6 +135,8 @@ API Changes * eal: ``rte_strscpy`` sets ``rte_errno`` to ``E2BIG`` in case of string truncation. +* eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. + ABI Changes -----------drivers/event/dlb2/dlb2.c +10
-0@@ -3154,6 +3154,16 @@ dlb2_port_credits_inc(struct dlb2_port *qm_port, int num) } } +#define CLB_MASK_IDX 0 +#define CLB_VAL_IDX 1 +static int +dlb2_monitor_callback (const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +/* abort if the value matches */ +return (val & opaque[CLB_MASK_IDX ]) == opaque[CLB_VAL_IDX ] ?-1 :0 ; +} + static inline intdlb2_dequeue_wait(struct
dlb2_eventdev*dlb2,drivers/event/dlb2/dlb2.c +5
-2struct dlb2_eventdev_port *ev_port,@@ -3194,8 +3204,11 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, expected_value =0 ; pmc.addr = monitor_addr; - pmc.val = expected_value; - pmc.mask = qe_mask.raw_qe[1 ]; +/* store expected value and comparison mask in opaque data */ + pmc.opaque[CLB_VAL_IDX ] = expected_value; + pmc.opaque[CLB_MASK_IDX ] = qe_mask.raw_qe[1 ]; +/* set up callback */ + pmc.fn = dlb2_monitor_callback; pmc.size =sizeof (uint64_t );rte_power_monitor (&pmc, timeout + start_ticks);drivers/net/i40e/i40e_rxtx.c +12
-0@@ -81,6 +81,18 @@#define I40E_TX_OFFLOAD_SIMPLE_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_SIMPLE_SUP_MASK) +static int +i40e_monitor_callback (const uint64_t value, +const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int
i40e_get_monitor_addr(void*rx_queue, structrte_power_monitor_cond
*pmc)
{drivers/net/i40e/i40e_rxtx.c +2
-6@@ -93,12 +105,8 @@ i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 << I40E_RX_DESC_STATUS_DD_SHIFT); +/* comparison callback */ + pmc->fn = i40e_monitor_callback;drivers/net/i40e/i40e_rxtx.c +0
-0/* registers are 64-bit */ pmc->size =sizeof (uint64_t );drivers/net/iavf/iavf_rxtx.c +12
-0@@ -57,6 +57,18 @@ iavf_proto_xtr_type_to_rxdid(uint8_t flex_type) rxdid_map[flex_type] :IAVF_RXDID_COMMS_OVS_1 ; } +static int +iavf_monitor_callback (const uint64_t value, +const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int
iavf_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc){drivers/net/iavf/iavf_rxtx.c +2
-6@@ -69,12 +81,8 @@ iavf_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 << IAVF_RX_DESC_STATUS_DD_SHIFT); +/* comparison callback */ + pmc->fn = iavf_monitor_callback;drivers/net/iavf/iavf_rxtx.c +0
-0/* registers are 64-bit */ pmc->size =sizeof (uint64_t );drivers/net/ice/ice_rxtx.c +12
-0@@ -27,6 +27,18 @@ 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; +static int +ice_monitor_callback (const uint64_t value, +const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int
ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc){drivers/net/ice/ice_rxtx.c +2
-6@@ -39,12 +51,8 @@ ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.status_error0; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); - pmc->mask =rte_cpu_to_le_16 (1 << ICE_RX_FLEX_DESC_STATUS0_DD_S); +/* comparison callback */ + pmc->fn = ice_monitor_callback;drivers/net/ice/ice_rxtx.c +0
-0/* register is 16-bit */ pmc->size =sizeof (uint16_t );drivers/net/ixgbe/ixgbe_rxtx.c +12
-0@@ -1369,6 +1369,18 @@ const uint32_tRTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +static int +ixgbe_monitor_callback (const uint64_t value, +const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ixgbe_get_monitor_addr(void
*rx_queue, structrte_power_monitor_cond
*pmc)
{drivers/net/ixgbe/ixgbe_rxtx.c +2
-6@@ -1381,12 +1393,8 @@ ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.upper.status_error; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); - pmc->mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* comparison callback */ + pmc->fn = ixgbe_monitor_callback;/* the registers are 32-bit */ drivers/net/ixgbe/ixgbe_rxtx.c +0
-0pmc->size =sizeof (uint32_t );drivers/net/mlx5/mlx5_rx.c +12
-0@@ -269,6 +269,18 @@ mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)return rx_queue_count (rxq); } +#define CLB_VAL_IDX 0 +#define CLB_MSK_IDX 1 +static int +mlx_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t m = opaque[CLB_MSK_IDX ]; +const uint64_t v = opaque[CLB_VAL_IDX ]; + +return (value & m) == v ?-1 :0 ; +} +int mlx5_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc){
drivers/net/mlx5/mlx5_rx.c +3
-2struct mlx5_rxq_data *rxq = rx_queue;@@ -282,8 +294,9 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)return -rte_errno; } pmc->addr = &cqe->op_own; - pmc->val = !!idx; - pmc->mask =MLX5_CQE_OWNER_MASK ; + pmc->opaque[CLB_VAL_IDX ] = !!idx; + pmc->opaque[CLB_MSK_IDX ] =MLX5_CQE_OWNER_MASK ; + pmc->fn = mlx_monitor_callback; pmc->size =sizeof (uint8_t );return 0 ;}
lib/eal/include/generic/rte_power_intrinsics.h +26
-7@@ -18,19 +18,38 @@* which are architecture-dependent. */ +/** Size of the opaque data in monitor condition */ +#define RTE_POWER_MONITOR_OPAQUE_SZ 4 + +/** +* Callback definition for monitoring conditions. Callbacks with this signature +* will be used by `rte_power_monitor()` to check if the entering of power +* optimized state should be aborted. +* +* @param val +* The value read from memory. +* @param opaque +* Callback-specific data. +* +* @return +* 0 if entering of power optimized state should proceed +* -1 if entering of power optimized state should be aborted +*/ +typedef int (*rte_power_monitor_clb_t )(const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]);struct rte_power_monitor_cond {volatile void *addr;/**< Address to monitor for changes */ -uint64_t val;/**< If the `mask` is non-zero, location pointed -* to by `addr` will be read and compared -* against this value. -*/ -uint64_t mask;/**< 64-bit mask to extract value read from `addr` */ -uint8_t size;/**< Data size (in bytes) that will be used to compare -* expected value (`val`) with data read from the +uint8_t size;/**< Data size (in bytes) that will be read from the * monitored memory location (`addr`). Can be 1, 2, * 4, or 8. Supplying any other value will result in * an error. */ +rte_power_monitor_clb_t fn;/**< Callback to be used to check if +* entering power optimized state should +* be aborted. +*/ +uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]; +/**< Callback-specific data */ };/** lib/eal/x86/rte_power_intrinsics.c +1
-0@@ -76,6 +76,7 @@ rte_power_monitor(const structrte_power_monitor_cond *pmc, const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);const unsigned int lcore_id =rte_lcore_id ();struct power_wait_status *s; +uint64_t cur_value;/* prevent user from running this instruction if it's not supported */ lib/eal/x86/rte_power_intrinsics.c +3
-0if (!wait_supported)@@ -91,6 +92,9 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc, if (__check_val_size(pmc->size) < 0) return -EINVAL; +if (pmc->fn ==NULL ) +return -EINVAL ; + s = &wait_status[lcore_id];lib/eal/x86/rte_power_intrinsics.c +4
-9/* update sleep address */ @@ -110,16 +114,11 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,/* now that we've put this address into monitor, we can unlock */ rte_spinlock_unlock (&s->lock); -/* if we have a comparison mask, we might not need to sleep at all */ -if (pmc->mask) { -const uint64_t cur_value =__get_umwait_val ( - pmc->addr, pmc->size); -const uint64_t masked = cur_value & pmc->mask; + cur_value =__get_umwait_val (pmc->addr, pmc->size); -/* if the masked value is already matching, abort */ -if (masked == pmc->val) - goto end; - } +/* check if callback indicates we should abort */ +if (pmc->fn (cur_value, pmc->opaque) !=0 ) + goto end;/* execute UMWAIT */
Quoted 3 lines
asm volatile(".byte
0xf2,0x0f,0xae,0xf7;"
--
2.25.1
DLB changes look good to me
Re: [dpdk-dev] [PATCH v8 1/7] power_intrinsics: use callbacks for comparison
In reply to Anatoly Burakov08/07/2021 16:13, Anatoly Burakov:
Quoted 10 lines
doc/guides/rel_notes/release_21_08.rst | 2 ++ drivers/event/dlb2/dlb2.c | 17 ++++++++-- drivers/net/i40e/i40e_rxtx.c | 20 +++++++---- drivers/net/iavf/iavf_rxtx.c | 20 +++++++---- drivers/net/ice/ice_rxtx.c | 20 +++++++---- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +++++++---- drivers/net/mlx5/mlx5_rx.c | 17 ++++++++-- .../include/generic/rte_power_intrinsics.h | 33 +++++++++++++++---- lib/eal/x86/rte_power_intrinsics.c | 17 +++++----- 9 files changed, 122 insertions(+), 44 deletions(-)
About the title, it is introducing a new prefix "power_intrinsics:" with is not so much descriptive.
Probably better to formulate with "eal:" prefix.
drivers/net/mlx5/mlx5_rx.c mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id) · line 276
Quoted 11 lines
drivers/net/mlx5/mlx5_rx.c +5
-0@@ -269,6 +269,18 @@ mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)return rx_queue_count (rxq); } +#define CLB_VAL_IDX 0 +#define CLB_MSK_IDX 1 +static int +mlx_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ])
Everything is prefixed with mlx5, let's be consistent. Please replace mlx_ with mlx5_
Re: [dpdk-dev] [PATCH v8 1/7] power_intrinsics: use callbacks for comparison
Quoted 25 lines · Thomas Monjalon
08/07/2021 16:13, Anatoly Burakov:
Quoted 10 lines
doc/guides/rel_notes/release_21_08.rst | 2 ++ drivers/event/dlb2/dlb2.c | 17 ++++++++-- drivers/net/i40e/i40e_rxtx.c | 20 +++++++---- drivers/net/iavf/iavf_rxtx.c | 20 +++++++---- drivers/net/ice/ice_rxtx.c | 20 +++++++---- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +++++++---- drivers/net/mlx5/mlx5_rx.c | 17 ++++++++-- .../include/generic/rte_power_intrinsics.h | 33 +++++++++++++++---- lib/eal/x86/rte_power_intrinsics.c | 17 +++++----- 9 files changed, 122 insertions(+), 44 deletions(-)About the title, it is introducing a new prefix "
power_intrinsics:" with is not so much descriptive.
Probably better to formulate with "eal:" prefix.Quoted 6 lines
drivers/net/mlx5/mlx5_rx.c +0
-0@@ -269,6 +269,18 @@ mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)return rx_queue_count (rxq); }
Quoted 9 lines
drivers/net/mlx5/mlx5_rx.c mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id) · line 276
Quoted 5 lines
drivers/net/mlx5/mlx5_rx.c +5
-0+#define CLB_VAL_IDX 0 +#define CLB_MSK_IDX 1 +static int +mlx_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ])Everything is prefixed with mlx5, let's be consistent. Please replace
mlx_withmlx5_
Sure, will fix.
Signature · 2 lines
Thanks, Anatoly
PATCH v8 2/7 net/af_xdp: add power monitor support
In reply to Anatoly BurakovImplement support for .get_monitor_addr in AF_XDP driver.
---
Notes:
v8:
- Fix checkpatch issue
v2:
- Rewrite using the callback mechanism
drivers/net/af_xdp/rte_eth_af_xdp.c | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
drivers/net/af_xdp/rte_eth_af_xdp.c +34 -0
@@ -37,6 +37,7 @@#include <rte_malloc.h> #include <rte_ring.h> #include <rte_spinlock.h> +#include <rte_power_intrinsics.h> #include "compat.h"
@@ -788,6 +789,38 @@ eth_dev_configure(struct rte_eth_dev *dev)return 0 ; } +#define CLB_VAL_IDX 0 +static int +eth_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t v = opaque[CLB_VAL_IDX ]; +const uint64_t m = (uint32_t )~0 ; + +/* if the value has changed, abort entering power optimized state */ +return (value & m) == v ?0 :-1 ; +} + +static int +eth_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) +{ +struct pkt_rx_queue *rxq = rx_queue; +unsigned int *prod = rxq->rx.producer; +const uint32_t cur_val = rxq->rx.cached_prod;/* use cached value */ + +/* watch for changes in producer ring */ + pmc->addr = (void *)prod; + +/* store current value */ + pmc->opaque[CLB_VAL_IDX ] = cur_val; + pmc->fn = eth_monitor_callback; + +/* AF_XDP producer ring index is 32-bit */ + pmc->size =sizeof (uint32_t ); + +return 0 ; +} +static int eth_dev_info (struct rte_eth_dev *dev,struct rte_eth_dev_info *dev_info) {
@@ -1448,6 +1481,7 @@ static const struct eth_dev_ops ops = { .link_update = eth_link_update, .stats_get = eth_stats_get, .stats_reset = eth_stats_reset, + .get_monitor_addr = eth_get_monitor_addr };/** parse busy_budget argument */
Signature · 1 line
2.25.1
PATCH v8 3/7 eal: add power monitor for multiple events
In reply to Anatoly BurakovUse RTM and WAITPKG instructions to perform a wait-for-writes similar to what UMWAIT does, but without the limitation of having to listen for just one event. This works because the optimized power state used by the TPAUSE instruction will cause a wake up on RTM transaction abort, so if we add the addresses we're interested in to the read-set, any write to those addresses will wake us up.
---
Notes:
v4:
- Fixed bugs in accessing the monitor condition
- Abort on any monitor condition not having a defined callback
v2:
- Adapt to callback mechanism
lib/eal/arm/rte_power_intrinsics.c | 11 +++ lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 35 +++++++++ lib/eal/ppc/rte_power_intrinsics.c | 11 +++ lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 73 +++++++++++++++++++ 7 files changed, 137 insertions(+)
lib/eal/arm/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/include/generic/rte_cpuflags.h +2 -0
@@ -24,6 +24,8 @@ struct rte_cpu_intrinsics {/**< indicates support for rte_power_monitor function */ uint32_t power_pause : 1;/**< indicates support for rte_power_pause function */ + uint32_t power_monitor_multi : 1; +/**< indicates support for rte_power_monitor_multi function */ };/**
lib/eal/include/generic/rte_power_intrinsics.h +35 -0
@@ -128,4 +128,39 @@ int rte_power_monitor_wakeup(const unsigned int lcore_id);__rte_experimental int rte_power_pause(const uint64_t tsc_timestamp); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* Monitor a set of addresses for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either one of the specified +* memory addresses is written to, a certain TSC timestamp is reached, or other +* reasons cause the CPU to wake up. +* +* Additionally, `expected` 64-bit values and 64-bit masks 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 do not 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_intrinsics_support()` API call. +* Failing to do so may result in an illegal CPU instruction error. +* +* @param pmc +* An array of monitoring condition structures. +* @param num +* Length of the `pmc` array. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* 0 on success +* -EINVAL on invalid parameters +* -ENOTSUP if unsupported +*/ +__rte_experimental +int rte_power_monitor_multi(const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp); +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/eal/ppc/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/version.map +3 -0
@@ -423,6 +423,9 @@ EXPERIMENTAL { rte_version_release; # WINDOWS_NO_EXPORT rte_version_suffix; # WINDOWS_NO_EXPORT rte_version_year; # WINDOWS_NO_EXPORT + + # added in 21.08 + rte_power_monitor_multi; # WINDOWS_NO_EXPORT }; INTERNAL {
lib/eal/x86/rte_cpuflags.c +2 -0
@@ -189,5 +189,7 @@ rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { intrinsics->power_monitor =1 ; intrinsics->power_pause =1 ; +if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_RTM )) + intrinsics->power_monitor_multi =1 ; } }
lib/eal/x86/rte_power_intrinsics.c +73 -0
100 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v8 4/7 power: remove thread safety from PMD power API's
In reply to Anatoly BurakovCurrently, we expect that only one callback can be active at any given moment, for a particular queue configuration, which is relatively easy to implement in a thread-safe way. However, we're about to add support for multiple queues per lcore, which will greatly increase the possibility of various race conditions.
We could have used something like an RCU for this use case, but absent of a pressing need for thread safety we'll go the easy way and just mandate that the API's are to be called when all affected ports are stopped, and document this limitation. This greatly simplifies the rte_power_monitor-related code.
---
Notes:
v2:
- Add check for stopped queue
- Clarified doc message
- Added release notes
doc/guides/rel_notes/release_21_08.rst | 4 + lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 133 ++++++++++--------------- lib/power/rte_power_pmd_mgmt.h | 6 ++ 4 files changed, 66 insertions(+), 80 deletions(-)
doc/guides/rel_notes/release_21_08.rst +4 -0
@@ -137,6 +137,10 @@ API Changes * eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. +* rte_power: The experimental PMD power management API is no longer considered + to be thread safe; all Rx queues affected by the API will now need to be + stopped before making any changes to the power management scheme. + ABI Changes -----------
lib/power/meson.build +3 -0
@@ -21,4 +21,7 @@ headers = files( 'rte_power_pmd_mgmt.h', 'rte_power_guest_channel.h', ) +if cc.has_argument('-Wno-cast-qual') + cflags += '-Wno-cast-qual' +endif deps += ['timer', 'ethdev']
lib/power/rte_power_pmd_mgmt.c +53 -80
209 lines not on this page · raw message
lib/power/rte_power_pmd_mgmt.h +6 -0
@@ -43,6 +43,9 @@ enum rte_power_pmd_mgmt_type {* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue will be polled from. * @param port_id
@@ -69,6 +72,9 @@ rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id,* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue is polled from. * @param port_id
Signature · 1 line
2.25.1
PATCH v8 5/7 power: support callbacks for multiple Rx queues
In reply to Anatoly BurakovCurrently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.
Also, while we're at it, update and improve the docs.
---
Notes:
v8:
- Added a comment explaining that we want to sleep on each empty poll after threshold has been reached
v7:
- Fix bug where initial sleep target was always set to zero
- Fix logic in handling of n_queues_ready_to_sleep counter
- Update documentation on hardware requirements
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)
v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantin
v3:
- Move the list of supported NICs to NIC feature table
v2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues
doc/guides/nics/features.rst | 10 + doc/guides/prog_guide/power_man.rst | 69 ++-- doc/guides/rel_notes/release_21_08.rst | 3 + lib/power/rte_power_pmd_mgmt.c | 460 +++++++++++++++++++------ 4 files changed, 406 insertions(+), 136 deletions(-)
doc/guides/nics/features.rst +10 -0
@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``. +.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` + .. _nic_features_other: Other dev ops not represented by a Feature
doc/guides/prog_guide/power_man.rst +41 -28
78 lines not on this page · raw message
doc/guides/rel_notes/release_21_08.rst +3 -0
@@ -103,6 +103,9 @@ New Features usecases. Configuration happens via standard rawdev enq/deq operations. See the :doc:`../rawdevs/cnxk_bphy` rawdev guide for more details on this driver. +* rte_power: The experimental PMD power management API now supports managing + multiple Ethernet Rx queues per lcore. + Removed Items -------------
lib/power/rte_power_pmd_mgmt.c +352 -108
575 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v8 5/7] power: support callbacks for multiple Rx queues
Quoted 8 lines · Anatoly Burakov
doc/guides/nics/features.rst +0
-0@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``.
doc/guides/nics/features.rst Supports to get Rx/Tx packet burst mode information. · line 924
Quoted 10 lines
doc/guides/nics/features.rst +10
-0+.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` +
- This new ethdev feature deserves its own commit.
- Adding ethdev maintainers.
We are missing a doc/guides/nics/features/default.ini. The name of the features proposed here is rather long. As far as I can see, features should be shorter than:
doc/guides/conf.py:feature_str_len = 30
I am not really inspired.. "Power mgmt address monitor"?
- pmd supporting this feature must have their .ini updated.
Quoted 3 lines
doc/guides/nics/features.rst +0
-0.. _nic_features_other: Other dev ops not represented by a Feature
Signature · 1 line
David Marchand
Re: [dpdk-dev] [PATCH v8 5/7] power: support callbacks for multiple Rx queues
Quoted 25 lines · David Marchand
Quoted 8 lines · Anatoly Burakov
doc/guides/nics/features.rst +0
-0@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``.doc/guides/nics/features.rst Supports to get Rx/Tx packet burst mode information. · line 924
Quoted 10 lines
doc/guides/nics/features.rst +10
-0+.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` +- This new ethdev feature deserves its own commit.
- Adding ethdev maintainers.
Quoted 15 lines
We are missing a doc/guides/nics/features/default.ini. The name of the features proposed here is rather long. As far as I can see, features should be shorter than:
doc/guides/conf.py:feature_str_len = 30
I am not really inspired.. "Power mgmt address monitor"?- pmd supporting this feature must have their .ini updated.
Quoted 3 lines
doc/guides/nics/features.rst +0
-0.. _nic_features_other: Other dev ops not represented by a Feature
You'd have to walk me through/translate whatever it is that you just said as i have no idea what any of that means :D
Signature · 2 lines
Thanks, Anatoly
Re: [dpdk-dev] [PATCH v8 5/7] power: support callbacks for multiple Rx queues
Quoted 2 lines · Anatoly
You'd have to walk me through/translate whatever it is that you just said as i have no idea what any of that means :D
https://git.dpdk.org/dpdk/commit/?id=fa5dbd825a
Signature · 1 line
David Marchand
Re: [dpdk-dev] [PATCH v8 5/7] power: support callbacks for multiple Rx queues
Quoted 8 lines · David Marchand
Quoted 2 lines · Anatoly
You'd have to walk me through/translate whatever it is that you just said as i have no idea what any of that means :D
Thanks, i'll separate it out into a separate commit and try to come up with a good name for it!
Signature · 2 lines
Thanks, Anatoly
PATCH v8 6/7 power: support monitoring multiple Rx queues
In reply to Anatoly BurakovUse the new multi-monitor intrinsic to allow monitoring multiple ethdev Rx queues while entering the energy efficient power state. The multi version will be used unconditionally if supported, and the UMWAIT one will only be used when multi-monitor is not supported by the hardware.
---
Notes:
v6:
- Fix the missed feedback from v5
v4:
- Fix possible out of bounds access
- Added missing index increment
doc/guides/prog_guide/power_man.rst | 15 ++++-- lib/power/rte_power_pmd_mgmt.c | 82 ++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 7 deletions(-)
doc/guides/prog_guide/power_man.rst +10 -5
@@ -221,17 +221,22 @@ power saving whenever empty poll count reaches a certain number. The "monitor" mode is only supported in the following configurations and scenarios: * On Linux* x86_64, `rte_power_monitor()` requires WAITPKG instruction set being - supported by the CPU. Please refer to your platform documentation for further - information. + supported by the CPU, while `rte_power_monitor_multi()` requires WAITPKG and + RTM instruction sets being supported by the CPU. RTM instruction set may also + require booting the Linux with `tsx=on` command line parameter. Please refer + to your platform documentation for further information. * If ``rte_cpu_get_intrinsics_support()`` function indicates that + ``rte_power_monitor_multi()`` function is supported by the platform, then + monitoring multiple Ethernet Rx queues for traffic will be supported. + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that only ``rte_power_monitor()`` is supported by the platform, then monitoring will be limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be monitored from a different lcore). -* If ``rte_cpu_get_intrinsics_support()`` function indicates that the - ``rte_power_monitor()`` function is not supported, then monitor mode will not - be supported. +* If ``rte_cpu_get_intrinsics_support()`` function indicates that neither of the + two monitoring functions are supported, then monitor mode will not be supported. * Not all Ethernet drivers support monitoring, even if the underlying platform may support the necessary CPU instructions. Please refer to
lib/power/rte_power_pmd_mgmt.c +80 -2
119 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v8 7/7 l3fwd-power: support multiqueue in PMD pmgmt modes
In reply to Anatoly BurakovCurrently, l3fwd-power enforces the limitation of having one queue per lcore. This is no longer necessary, so remove the limitation.
--- examples/l3fwd-power/main.c | 6 ------ 1 file changed, 6 deletions(-)
examples/l3fwd-power/main.c +0 -6
@@ -2723,12 +2723,6 @@ main(int argc, char **argv)printf ("\nInitializing rx queues on lcore %u ... " , lcore_id );fflush (stdout); -/* PMD power management mode can only do 1 queue per core */ -if (app_mode ==APP_MODE_PMD_MGMT && qconf->n_rx_queue >1 ) { -rte_exit (EXIT_FAILURE , -"In PMD power management mode, only one queue per lcore is allowed\n" ); - } -/* init RX queues */ for (queue =0 ; queue < qconf->n_rx_queue; ++queue) {struct rte_eth_rxconf rxq_conf;
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v8 7/7] l3fwd-power: support multiqueue in PMD pmgmt modes
Quoted 3 lines · Anatoly Burakov
Currently, l3fwd-power enforces the limitation of having one queue per lcore. This is no longer necessary, so remove the limitation.
Title prefix is examples/l3fwd-power: for consistency sake.
Signature · 1 line
David Marchand
v9 cover Enhancements for PMD power management
In reply to Anatoly BurakovThis patchset introduces several changes related to PMD power management:
- Changed monitoring intrinsics to use callbacks as a comparison function, based on previous patchset [1] but incorporating feedback [2] - this hopefully will make it possible to add support for .get_monitor_addr in virtio
- Add a new intrinsic to monitor multiple addresses, based on RTM instruction set and the TPAUSE instruction
- Add support for PMD power management on multiple queues, as well as all accompanying infrastructure and example apps changes
v9:
- Added all missing Acks and Tests
- Added a new commit with NIC features
- Addressed minor issues raised in review
v8:
- Fixed checkpatch issue
- Added comment explaining empty poll handling (Konstantin)
v7:
- Fixed various bugs
v6:
- Improved the algorithm for multi-queue sleep
- Fixed segfault and addressed other feedback
v5:
- Removed "power save queue" API and replaced with mechanism suggested by Konstantin
- Addressed other feedback
v4:
- Replaced raw number with a macro
- Fixed all the bugs found by Konstantin
- Some other minor corrections
v3:
- Moved some doc updates to NIC features list
v2:
- Changed check inversion to callbacks
- Addressed feedback from Konstantin
- Added doc updates where necessary
[1] http://patches.dpdk.org/project/dpdk/list/?series=16930&state=*
[2] http://patches.dpdk.org/project/dpdk/patch/819ef1ace187365a615d3383e54579e3d9fb216e.1620747068.git.anatoly.burakov@intel.com/#133274
Anatoly Burakov (8):
eal: use callbacks for power monitoring comparison net/af_xdp: add power monitor support
doc: add PMD power management NIC feature
eal: add power monitor for multiple events
power: remove thread safety from PMD power API's
power: support callbacks for multiple Rx queues
power: support monitoring multiple Rx queues examples/l3fwd-power: support multiq in PMD modes
doc/guides/nics/features.rst | 10 + doc/guides/nics/features/default.ini | 1 + doc/guides/prog_guide/power_man.rst | 74 +- doc/guides/rel_notes/release_21_08.rst | 11 + drivers/event/dlb2/dlb2.c | 17 +- drivers/net/af_xdp/rte_eth_af_xdp.c | 34 + drivers/net/i40e/i40e_rxtx.c | 20 +- drivers/net/iavf/iavf_rxtx.c | 20 +- drivers/net/ice/ice_rxtx.c | 20 +- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +- drivers/net/mlx5/mlx5_rx.c | 17 +- examples/l3fwd-power/main.c | 6 - lib/eal/arm/rte_power_intrinsics.c | 11 + lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 68 +- lib/eal/ppc/rte_power_intrinsics.c | 11 + lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 90 ++- lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 663 +++++++++++++----- lib/power/rte_power_pmd_mgmt.h | 6 + 22 files changed, 847 insertions(+), 262 deletions(-)
Signature · 1 line
2.25.1
PATCH v9 1/8 eal: use callbacks for power monitoring comparison
Previously, the semantics of power monitor were such that we were checking current value against the expected value, and if they matched, then the sleep was aborted. This is somewhat inflexible, because it only allowed us to check for a specific value in a specific way.
This commit replaces the comparison with a user callback mechanism, so that any PMD (or other code) using rte_power_monitor() can define their own comparison semantics and decision making on how to detect the need to abort the entering of power optimized state.
Existing implementations are adjusted to follow the new semantics.
---
Notes:
v4:
- Return error if callback is set to NULL
- Replace raw number with a macro in monitor condition opaque data
v2:
- Use callback mechanism for more flexibility
- Address feedback from Konstantin
doc/guides/rel_notes/release_21_08.rst | 2 ++ drivers/event/dlb2/dlb2.c | 17 ++++++++-- drivers/net/i40e/i40e_rxtx.c | 20 +++++++---- drivers/net/iavf/iavf_rxtx.c | 20 +++++++---- drivers/net/ice/ice_rxtx.c | 20 +++++++---- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +++++++---- drivers/net/mlx5/mlx5_rx.c | 17 ++++++++-- .../include/generic/rte_power_intrinsics.h | 33 +++++++++++++++---- lib/eal/x86/rte_power_intrinsics.c | 17 +++++----- 9 files changed, 122 insertions(+), 44 deletions(-)
doc/guides/rel_notes/release_21_08.rst +2 -0
@@ -144,6 +144,8 @@ API Changes * eal: ``rte_strscpy`` sets ``rte_errno`` to ``E2BIG`` in case of string truncation. +* eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. + ABI Changes -----------
drivers/event/dlb2/dlb2.c +15 -2
@@ -3154,6 +3154,16 @@ dlb2_port_credits_inc(struct dlb2_port *qm_port, int num) } } +#define CLB_MASK_IDX 0 +#define CLB_VAL_IDX 1 +static int +dlb2_monitor_callback (const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +/* abort if the value matches */ +return (val & opaque[CLB_MASK_IDX ]) == opaque[CLB_VAL_IDX ] ?-1 :0 ; +} + static inline int dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, struct dlb2_eventdev_port *ev_port,
@@ -3194,8 +3204,11 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, expected_value =0 ; pmc.addr = monitor_addr; - pmc.val = expected_value; - pmc.mask = qe_mask.raw_qe[1 ]; +/* store expected value and comparison mask in opaque data */ + pmc.opaque[CLB_VAL_IDX ] = expected_value; + pmc.opaque[CLB_MASK_IDX ] = qe_mask.raw_qe[1 ]; +/* set up callback */ + pmc.fn = dlb2_monitor_callback; pmc.size =sizeof (uint64_t );rte_power_monitor (&pmc, timeout + start_ticks);
drivers/net/i40e/i40e_rxtx.c +14 -6
@@ -81,6 +81,18 @@#define I40E_TX_OFFLOAD_SIMPLE_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_SIMPLE_SUP_MASK) +static int +i40e_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int i40e_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -93,12 +105,8 @@ i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* comparison callback */ + pmc->fn = i40e_monitor_callback;/* registers are 64-bit */ pmc->size =sizeof (uint64_t );
drivers/net/iavf/iavf_rxtx.c +14 -6
@@ -57,6 +57,18 @@ iavf_proto_xtr_type_to_rxdid(uint8_t flex_type) rxdid_map[flex_type] : IAVF_RXDID_COMMS_OVS_1; } +static int +iavf_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int iavf_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -69,12 +81,8 @@ iavf_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* comparison callback */ + pmc->fn = iavf_monitor_callback;/* registers are 64-bit */ pmc->size =sizeof (uint64_t );
drivers/net/ice/ice_rxtx.c +14 -6
@@ -27,6 +27,18 @@ 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; +static int +ice_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ice_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -39,12 +51,8 @@ ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.status_error0; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); - pmc->mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* comparison callback */ + pmc->fn = ice_monitor_callback;/* register is 16-bit */ pmc->size =sizeof (uint16_t );
drivers/net/ixgbe/ixgbe_rxtx.c +14 -6
@@ -1369,6 +1369,18 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +static int +ixgbe_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ixgbe_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -1381,12 +1393,8 @@ ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.upper.status_error; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); - pmc->mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* comparison callback */ + pmc->fn = ixgbe_monitor_callback;/* the registers are 32-bit */ pmc->size =sizeof (uint32_t );
drivers/net/mlx5/mlx5_rx.c +15 -2
@@ -269,6 +269,18 @@ mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)return rx_queue_count (rxq); } +#define CLB_VAL_IDX 0 +#define CLB_MSK_IDX 1 +static int +mlx5_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t m = opaque[CLB_MSK_IDX ]; +const uint64_t v = opaque[CLB_VAL_IDX ]; + +return (value & m) == v ?-1 :0 ; +} +int mlx5_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {struct mlx5_rxq_data *rxq = rx_queue;
@@ -282,8 +294,9 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)return -rte_errno; } pmc->addr = &cqe->op_own; - pmc->val = !!idx; - pmc->mask =MLX5_CQE_OWNER_MASK ; + pmc->opaque[CLB_VAL_IDX ] = !!idx; + pmc->opaque[CLB_MSK_IDX ] =MLX5_CQE_OWNER_MASK ; + pmc->fn = mlx5_monitor_callback; pmc->size =sizeof (uint8_t );return 0 ; }
lib/eal/include/generic/rte_power_intrinsics.h +26 -7
@@ -18,19 +18,38 @@* which are architecture-dependent. */ +/** Size of the opaque data in monitor condition */ +#define RTE_POWER_MONITOR_OPAQUE_SZ 4 + +/** +* Callback definition for monitoring conditions. Callbacks with this signature +* will be used by `rte_power_monitor()` to check if the entering of power +* optimized state should be aborted. +* +* @param val +* The value read from memory. +* @param opaque +* Callback-specific data. +* +* @return +* 0 if entering of power optimized state should proceed +* -1 if entering of power optimized state should be aborted +*/ +typedef int (*rte_power_monitor_clb_t )(const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]);struct rte_power_monitor_cond {volatile void *addr;/**< Address to monitor for changes */ -uint64_t val;/**< If the `mask` is non-zero, location pointed -* to by `addr` will be read and compared -* against this value. -*/ -uint64_t mask;/**< 64-bit mask to extract value read from `addr` */ -uint8_t size;/**< Data size (in bytes) that will be used to compare -* expected value (`val`) with data read from the +uint8_t size;/**< Data size (in bytes) that will be read from the * monitored memory location (`addr`). Can be 1, 2, * 4, or 8. Supplying any other value will result in * an error. */ +rte_power_monitor_clb_t fn;/**< Callback to be used to check if +* entering power optimized state should +* be aborted. +*/ +uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]; +/**< Callback-specific data */ };/**
lib/eal/x86/rte_power_intrinsics.c +8 -9
@@ -76,6 +76,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 );const unsigned int lcore_id =rte_lcore_id ();struct power_wait_status *s; +uint64_t cur_value;/* prevent user from running this instruction if it's not supported */ if (!wait_supported)
@@ -91,6 +92,9 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,if (__check_val_size (pmc->size) <0 )return -EINVAL ; +if (pmc->fn ==NULL ) +return -EINVAL ; + s = &wait_status[lcore_id];/* update sleep address */
@@ -110,16 +114,11 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,/* now that we've put this address into monitor, we can unlock */ rte_spinlock_unlock (&s->lock); -/* if we have a comparison mask, we might not need to sleep at all */ -if (pmc->mask) { -const uint64_t cur_value =__get_umwait_val ( - pmc->addr, pmc->size); -const uint64_t masked = cur_value & pmc->mask; + cur_value =__get_umwait_val (pmc->addr, pmc->size); -/* if the masked value is already matching, abort */ -if (masked == pmc->val) - goto end; - } +/* check if callback indicates we should abort */ +if (pmc->fn (cur_value, pmc->opaque) !=0 ) + goto end;/* execute UMWAIT */ asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
Signature · 1 line
2.25.1
PATCH v9 2/8 net/af_xdp: add power monitor support
In reply to Anatoly BurakovImplement support for .get_monitor_addr in AF_XDP driver.
---
Notes:
v8:
- Fix checkpatch issue
v2:
- Rewrite using the callback mechanism
drivers/net/af_xdp/rte_eth_af_xdp.c | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
drivers/net/af_xdp/rte_eth_af_xdp.c +34 -0
@@ -37,6 +37,7 @@#include <rte_malloc.h> #include <rte_ring.h> #include <rte_spinlock.h> +#include <rte_power_intrinsics.h> #include "compat.h"
@@ -788,6 +789,38 @@ eth_dev_configure(struct rte_eth_dev *dev)return 0 ; } +#define CLB_VAL_IDX 0 +static int +eth_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t v = opaque[CLB_VAL_IDX ]; +const uint64_t m = (uint32_t )~0 ; + +/* if the value has changed, abort entering power optimized state */ +return (value & m) == v ?0 :-1 ; +} + +static int +eth_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) +{ +struct pkt_rx_queue *rxq = rx_queue; +unsigned int *prod = rxq->rx.producer; +const uint32_t cur_val = rxq->rx.cached_prod;/* use cached value */ + +/* watch for changes in producer ring */ + pmc->addr = (void *)prod; + +/* store current value */ + pmc->opaque[CLB_VAL_IDX ] = cur_val; + pmc->fn = eth_monitor_callback; + +/* AF_XDP producer ring index is 32-bit */ + pmc->size =sizeof (uint32_t ); + +return 0 ; +} +static int eth_dev_info (struct rte_eth_dev *dev,struct rte_eth_dev_info *dev_info) {
@@ -1448,6 +1481,7 @@ static const struct eth_dev_ops ops = { .link_update = eth_link_update, .stats_get = eth_stats_get, .stats_reset = eth_stats_reset, + .get_monitor_addr = eth_get_monitor_addr };/** parse busy_budget argument */
Signature · 1 line
2.25.1
PATCH v9 3/8 doc: add PMD power management NIC feature
In reply to Anatoly BurakovAt this point, multiple different Ethernet drivers from multiple vendors will support the PMD power management scheme. It would be useful to add it to the NIC feature table to indicate support for it.
--- doc/guides/nics/features.rst | 10 ++++++++++ doc/guides/nics/features/default.ini | 1 + 2 files changed, 11 insertions(+)
doc/guides/nics/features.rst +10 -0
@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``. +.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` + .. _nic_features_other: Other dev ops not represented by a Feature
doc/guides/nics/features/default.ini +1 -0
@@ -76,6 +76,7 @@ x86-64 = Usage doc = Design doc = Perf doc = +Power mgmt address monitor = [rte_flow items] ah =
Signature · 1 line
2.25.1
Re: [dpdk-dev] [PATCH v9 3/8] doc: add PMD power management NIC feature
Quoted 38 lines · Anatoly Burakov
At this point, multiple different Ethernet drivers from multiple vendors will support the PMD power management scheme. It would be useful to add it to the NIC feature table to indicate support for it.
Suggested-by David Marchand <[email protected]>Signed-off-by Anatoly Burakov <[email protected]>--- doc/guides/nics/features.rst | 10 ++++++++++ doc/guides/nics/features/default.ini | 1 + 2 files changed, 11 insertions(+)doc/guides/nics/features.rst +10
-0@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``. +.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` + .. _nic_features_other: Other dev ops not represented by a Featuredoc/guides/nics/features/default.ini +0
-0
doc/guides/nics/features/default.ini x86-64 = · line 82
Quoted 7 lines
doc/guides/nics/features/default.ini +1
-0@@ -76,6 +76,7 @@ x86-64 = Usage doc = Design doc = Perf doc = +Power mgmt address monitor = [rte_flow items] ah =
Apologies, forgot to git add the driver files to the commit. Will respin shortly.
Signature · 2 lines
Thanks, Anatoly
PATCH v9 4/8 eal: add power monitor for multiple events
In reply to Anatoly BurakovUse RTM and WAITPKG instructions to perform a wait-for-writes similar to what UMWAIT does, but without the limitation of having to listen for just one event. This works because the optimized power state used by the TPAUSE instruction will cause a wake up on RTM transaction abort, so if we add the addresses we're interested in to the read-set, any write to those addresses will wake us up.
---
Notes:
v4:
- Fixed bugs in accessing the monitor condition
- Abort on any monitor condition not having a defined callback
v2:
- Adapt to callback mechanism
lib/eal/arm/rte_power_intrinsics.c | 11 +++ lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 35 +++++++++ lib/eal/ppc/rte_power_intrinsics.c | 11 +++ lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 73 +++++++++++++++++++ 7 files changed, 137 insertions(+)
lib/eal/arm/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/include/generic/rte_cpuflags.h +2 -0
@@ -24,6 +24,8 @@ struct rte_cpu_intrinsics {/**< indicates support for rte_power_monitor function */ uint32_t power_pause : 1;/**< indicates support for rte_power_pause function */ + uint32_t power_monitor_multi : 1; +/**< indicates support for rte_power_monitor_multi function */ };/**
lib/eal/include/generic/rte_power_intrinsics.h +35 -0
@@ -128,4 +128,39 @@ int rte_power_monitor_wakeup(const unsigned int lcore_id);__rte_experimental int rte_power_pause(const uint64_t tsc_timestamp); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* Monitor a set of addresses for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either one of the specified +* memory addresses is written to, a certain TSC timestamp is reached, or other +* reasons cause the CPU to wake up. +* +* Additionally, `expected` 64-bit values and 64-bit masks 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 do not 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_intrinsics_support()` API call. +* Failing to do so may result in an illegal CPU instruction error. +* +* @param pmc +* An array of monitoring condition structures. +* @param num +* Length of the `pmc` array. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* 0 on success +* -EINVAL on invalid parameters +* -ENOTSUP if unsupported +*/ +__rte_experimental +int rte_power_monitor_multi(const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp); +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/eal/ppc/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/version.map +3 -0
@@ -423,6 +423,9 @@ EXPERIMENTAL { rte_version_release; # WINDOWS_NO_EXPORT rte_version_suffix; # WINDOWS_NO_EXPORT rte_version_year; # WINDOWS_NO_EXPORT + + # added in 21.08 + rte_power_monitor_multi; # WINDOWS_NO_EXPORT }; INTERNAL {
lib/eal/x86/rte_cpuflags.c +2 -0
@@ -189,5 +189,7 @@ rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { intrinsics->power_monitor =1 ; intrinsics->power_pause =1 ; +if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_RTM )) + intrinsics->power_monitor_multi =1 ; } }
lib/eal/x86/rte_power_intrinsics.c +73 -0
100 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v9 5/8 power: remove thread safety from PMD power API's
In reply to Anatoly BurakovCurrently, we expect that only one callback can be active at any given moment, for a particular queue configuration, which is relatively easy to implement in a thread-safe way. However, we're about to add support for multiple queues per lcore, which will greatly increase the possibility of various race conditions.
We could have used something like an RCU for this use case, but absent of a pressing need for thread safety we'll go the easy way and just mandate that the API's are to be called when all affected ports are stopped, and document this limitation. This greatly simplifies the rte_power_monitor-related code.
---
Notes:
v2:
- Add check for stopped queue
- Clarified doc message
- Added release notes
doc/guides/rel_notes/release_21_08.rst | 4 + lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 133 ++++++++++--------------- lib/power/rte_power_pmd_mgmt.h | 6 ++ 4 files changed, 66 insertions(+), 80 deletions(-)
doc/guides/rel_notes/release_21_08.rst +4 -0
@@ -146,6 +146,10 @@ API Changes * eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. +* rte_power: The experimental PMD power management API is no longer considered + to be thread safe; all Rx queues affected by the API will now need to be + stopped before making any changes to the power management scheme. + ABI Changes -----------
lib/power/meson.build +3 -0
@@ -22,4 +22,7 @@ headers = files( 'rte_power_pmd_mgmt.h', 'rte_power_guest_channel.h', ) +if cc.has_argument('-Wno-cast-qual') + cflags += '-Wno-cast-qual' +endif deps += ['timer', 'ethdev']
lib/power/rte_power_pmd_mgmt.c +53 -80
209 lines not on this page · raw message
lib/power/rte_power_pmd_mgmt.h +6 -0
@@ -43,6 +43,9 @@ enum rte_power_pmd_mgmt_type {* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue will be polled from. * @param port_id
@@ -69,6 +72,9 @@ rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id,* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue is polled from. * @param port_id
Signature · 1 line
2.25.1
PATCH v9 6/8 power: support callbacks for multiple Rx queues
In reply to Anatoly BurakovCurrently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.
Also, while we're at it, update and improve the docs.
---
Notes:
v8:
- Added a comment explaining that we want to sleep on each empty poll after threshold has been reached
v7:
- Fix bug where initial sleep target was always set to zero
- Fix logic in handling of n_queues_ready_to_sleep counter
- Update documentation on hardware requirements
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)
v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantin
v3:
- Move the list of supported NICs to NIC feature table
v2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues
doc/guides/prog_guide/power_man.rst | 69 ++-- doc/guides/rel_notes/release_21_08.rst | 5 + lib/power/rte_power_pmd_mgmt.c | 460 +++++++++++++++++++------ 3 files changed, 398 insertions(+), 136 deletions(-)
doc/guides/prog_guide/power_man.rst +41 -28
@@ -198,34 +198,45 @@ Ethernet 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. - -Monitor - This power saving scheme will put the CPU into optimized power state - and use the ``rte_power_monitor()`` function - to monitor the Ethernet PMD RX descriptor address, - and wake the CPU up whenever there's new traffic. - -Pause - This power saving scheme will avoid busy polling - by either entering power-optimized sleep state - with ``rte_power_pause()`` function, - or, if it's not available, use ``rte_pause()``. - -Frequency scaling - This power saving scheme will use ``librte_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). +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. + +* Monitor + This power saving scheme will put the CPU into optimized power state and + monitor the Ethernet PMD RX descriptor address, waking the CPU up whenever + there's new traffic. Support for this scheme may not be available on all + platforms, and further limitations may apply (see below). + +* Pause + This power saving scheme will avoid busy polling by either entering + power-optimized sleep state with ``rte_power_pause()`` function, or, if it's + not supported by the underlying platform, use ``rte_pause()``. + +* Frequency scaling + This power saving scheme will use ``librte_power`` library functionality to + scale the core frequency up/down depending on traffic volume. + +The "monitor" mode is only supported in the following configurations and scenarios: + +* On Linux* x86_64, `rte_power_monitor()` requires WAITPKG instruction set being + supported by the CPU. Please refer to your platform documentation for further + information. + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that + ``rte_power_monitor()`` is supported by the platform, then monitoring will be + limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be + monitored from a different lcore). + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that the + ``rte_power_monitor()`` function is not supported, then monitor mode will not + be supported. + +* Not all Ethernet drivers support monitoring, even if the underlying + platform may support the necessary CPU instructions. Please refer to + :doc:`../nics/overview` for more information. + API Overview for Ethernet PMD Power Management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -242,3 +253,5 @@ References * The :doc:`../sample_app_ug/vm_power_management` chapter in the :doc:`../sample_app_ug/index` section. + +* The :doc:`../nics/overview` chapter in the :doc:`../nics/index` section
doc/guides/rel_notes/release_21_08.rst +5 -0
@@ -112,6 +112,11 @@ New Features Added support for cppc_cpufreq driver which works on most arm64 platforms. +* **Added multi-queue support to Ethernet PMD Power Management** + + The experimental PMD power management API now supports managing + multiple Ethernet Rx queues per lcore. + Removed Items -------------
lib/power/rte_power_pmd_mgmt.c +352 -108
575 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v9 7/8 power: support monitoring multiple Rx queues
In reply to Anatoly BurakovUse the new multi-monitor intrinsic to allow monitoring multiple ethdev Rx queues while entering the energy efficient power state. The multi version will be used unconditionally if supported, and the UMWAIT one will only be used when multi-monitor is not supported by the hardware.
---
Notes:
v6:
- Fix the missed feedback from v5
v4:
- Fix possible out of bounds access
- Added missing index increment
doc/guides/prog_guide/power_man.rst | 15 ++++-- lib/power/rte_power_pmd_mgmt.c | 82 ++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 7 deletions(-)
doc/guides/prog_guide/power_man.rst +10 -5
@@ -221,17 +221,22 @@ power saving whenever empty poll count reaches a certain number. The "monitor" mode is only supported in the following configurations and scenarios: * On Linux* x86_64, `rte_power_monitor()` requires WAITPKG instruction set being - supported by the CPU. Please refer to your platform documentation for further - information. + supported by the CPU, while `rte_power_monitor_multi()` requires WAITPKG and + RTM instruction sets being supported by the CPU. RTM instruction set may also + require booting the Linux with `tsx=on` command line parameter. Please refer + to your platform documentation for further information. * If ``rte_cpu_get_intrinsics_support()`` function indicates that + ``rte_power_monitor_multi()`` function is supported by the platform, then + monitoring multiple Ethernet Rx queues for traffic will be supported. + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that only ``rte_power_monitor()`` is supported by the platform, then monitoring will be limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be monitored from a different lcore). -* If ``rte_cpu_get_intrinsics_support()`` function indicates that the - ``rte_power_monitor()`` function is not supported, then monitor mode will not - be supported. +* If ``rte_cpu_get_intrinsics_support()`` function indicates that neither of the + two monitoring functions are supported, then monitor mode will not be supported. * Not all Ethernet drivers support monitoring, even if the underlying platform may support the necessary CPU instructions. Please refer to
lib/power/rte_power_pmd_mgmt.c +80 -2
119 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v9 8/8 examples/l3fwd-power: support multiq in PMD modes
In reply to Anatoly BurakovCurrently, l3fwd-power enforces the limitation of having one queue per lcore. This is no longer necessary, so remove the limitation.
--- examples/l3fwd-power/main.c | 6 ------ 1 file changed, 6 deletions(-)
examples/l3fwd-power/main.c +0 -6
@@ -2723,12 +2723,6 @@ main(int argc, char **argv)printf ("\nInitializing rx queues on lcore %u ... " , lcore_id );fflush (stdout); -/* PMD power management mode can only do 1 queue per core */ -if (app_mode ==APP_MODE_PMD_MGMT && qconf->n_rx_queue >1 ) { -rte_exit (EXIT_FAILURE , -"In PMD power management mode, only one queue per lcore is allowed\n" ); - } -/* init RX queues */ for (queue =0 ; queue < qconf->n_rx_queue; ++queue) {struct rte_eth_rxconf rxq_conf;
Signature · 1 line
2.25.1
v10 cover Enhancements for PMD power management
In reply to Anatoly BurakovThis patchset introduces several changes related to PMD power management:
- Changed monitoring intrinsics to use callbacks as a comparison function, based on previous patchset [1] but incorporating feedback [2] - this hopefully will make it possible to add support for .get_monitor_addr in virtio
- Add a new intrinsic to monitor multiple addresses, based on RTM instruction set and the TPAUSE instruction
- Add support for PMD power management on multiple queues, as well as all accompanying infrastructure and example apps changes
v10:
- Added missing changes to NIC feature .ini files
v9:
- Added all missing Acks and Tests
- Added a new commit with NIC features
- Addressed minor issues raised in review
v8:
- Fixed checkpatch issue
- Added comment explaining empty poll handling (Konstantin)
v7:
- Fixed various bugs
v6:
- Improved the algorithm for multi-queue sleep
- Fixed segfault and addressed other feedback
v5:
- Removed "power save queue" API and replaced with mechanism suggested by Konstantin
- Addressed other feedback
v4:
- Replaced raw number with a macro
- Fixed all the bugs found by Konstantin
- Some other minor corrections
v3:
- Moved some doc updates to NIC features list
v2:
- Changed check inversion to callbacks
- Addressed feedback from Konstantin
- Added doc updates where necessary
[1] http://patches.dpdk.org/project/dpdk/list/?series=16930&state=*
[2] http://patches.dpdk.org/project/dpdk/patch/819ef1ace187365a615d3383e54579e3d9fb216e.1620747068.git.anatoly.burakov@intel.com/#133274
Anatoly Burakov (8):
eal: use callbacks for power monitoring comparison net/af_xdp: add power monitor support
doc: add PMD power management NIC feature
eal: add power monitor for multiple events
power: remove thread safety from PMD power API's
power: support callbacks for multiple Rx queues
power: support monitoring multiple Rx queues examples/l3fwd-power: support multiq in PMD modes
doc/guides/nics/features.rst | 10 + doc/guides/nics/features/af_xdp.ini | 1 + doc/guides/nics/features/default.ini | 1 + doc/guides/nics/features/i40e.ini | 1 + doc/guides/nics/features/i40e_vf.ini | 1 + doc/guides/nics/features/iavf.ini | 1 + doc/guides/nics/features/ice.ini | 1 + doc/guides/nics/features/ixgbe.ini | 1 + doc/guides/nics/features/ixgbe_vf.ini | 1 + doc/guides/nics/features/mlx5.ini | 1 + doc/guides/prog_guide/power_man.rst | 74 +- doc/guides/rel_notes/release_21_08.rst | 11 + drivers/event/dlb2/dlb2.c | 17 +- drivers/net/af_xdp/rte_eth_af_xdp.c | 34 + drivers/net/i40e/i40e_rxtx.c | 20 +- drivers/net/iavf/iavf_rxtx.c | 20 +- drivers/net/ice/ice_rxtx.c | 20 +- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +- drivers/net/mlx5/mlx5_rx.c | 17 +- examples/l3fwd-power/main.c | 6 - lib/eal/arm/rte_power_intrinsics.c | 11 + lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 68 +- lib/eal/ppc/rte_power_intrinsics.c | 11 + lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 90 ++- lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 663 +++++++++++++----- lib/power/rte_power_pmd_mgmt.h | 6 + 30 files changed, 855 insertions(+), 262 deletions(-)
Signature · 1 line
2.25.1
PATCH v10 1/8 eal: use callbacks for power monitoring comparison
Previously, the semantics of power monitor were such that we were checking current value against the expected value, and if they matched, then the sleep was aborted. This is somewhat inflexible, because it only allowed us to check for a specific value in a specific way.
This commit replaces the comparison with a user callback mechanism, so that any PMD (or other code) using rte_power_monitor() can define their own comparison semantics and decision making on how to detect the need to abort the entering of power optimized state.
Existing implementations are adjusted to follow the new semantics.
---
Notes:
v4:
- Return error if callback is set to NULL
- Replace raw number with a macro in monitor condition opaque data
v2:
- Use callback mechanism for more flexibility
- Address feedback from Konstantin
doc/guides/rel_notes/release_21_08.rst | 2 ++ drivers/event/dlb2/dlb2.c | 17 ++++++++-- drivers/net/i40e/i40e_rxtx.c | 20 +++++++---- drivers/net/iavf/iavf_rxtx.c | 20 +++++++---- drivers/net/ice/ice_rxtx.c | 20 +++++++---- drivers/net/ixgbe/ixgbe_rxtx.c | 20 +++++++---- drivers/net/mlx5/mlx5_rx.c | 17 ++++++++-- .../include/generic/rte_power_intrinsics.h | 33 +++++++++++++++---- lib/eal/x86/rte_power_intrinsics.c | 17 +++++----- 9 files changed, 122 insertions(+), 44 deletions(-)
doc/guides/rel_notes/release_21_08.rst +2 -0
@@ -144,6 +144,8 @@ API Changes * eal: ``rte_strscpy`` sets ``rte_errno`` to ``E2BIG`` in case of string truncation. +* eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. + ABI Changes -----------
drivers/event/dlb2/dlb2.c +15 -2
@@ -3154,6 +3154,16 @@ dlb2_port_credits_inc(struct dlb2_port *qm_port, int num) } } +#define CLB_MASK_IDX 0 +#define CLB_VAL_IDX 1 +static int +dlb2_monitor_callback (const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +/* abort if the value matches */ +return (val & opaque[CLB_MASK_IDX ]) == opaque[CLB_VAL_IDX ] ?-1 :0 ; +} + static inline int dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, struct dlb2_eventdev_port *ev_port,
@@ -3194,8 +3204,11 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2, expected_value =0 ; pmc.addr = monitor_addr; - pmc.val = expected_value; - pmc.mask = qe_mask.raw_qe[1 ]; +/* store expected value and comparison mask in opaque data */ + pmc.opaque[CLB_VAL_IDX ] = expected_value; + pmc.opaque[CLB_MASK_IDX ] = qe_mask.raw_qe[1 ]; +/* set up callback */ + pmc.fn = dlb2_monitor_callback; pmc.size =sizeof (uint64_t );rte_power_monitor (&pmc, timeout + start_ticks);
drivers/net/i40e/i40e_rxtx.c +14 -6
@@ -81,6 +81,18 @@#define I40E_TX_OFFLOAD_SIMPLE_NOTSUP_MASK \ (PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_SIMPLE_SUP_MASK) +static int +i40e_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int i40e_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -93,12 +105,8 @@ i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 <<I40E_RX_DESC_STATUS_DD_SHIFT ); +/* comparison callback */ + pmc->fn = i40e_monitor_callback;/* registers are 64-bit */ pmc->size =sizeof (uint64_t );
drivers/net/iavf/iavf_rxtx.c +14 -6
@@ -57,6 +57,18 @@ iavf_proto_xtr_type_to_rxdid(uint8_t flex_type) rxdid_map[flex_type] : IAVF_RXDID_COMMS_OVS_1; } +static int +iavf_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int iavf_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -69,12 +81,8 @@ iavf_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.qword1.status_error_len; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); - pmc->mask =rte_cpu_to_le_64 (1 <<IAVF_RX_DESC_STATUS_DD_SHIFT ); +/* comparison callback */ + pmc->fn = iavf_monitor_callback;/* registers are 64-bit */ pmc->size =sizeof (uint64_t );
drivers/net/ice/ice_rxtx.c +14 -6
@@ -27,6 +27,18 @@ 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; +static int +ice_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ice_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -39,12 +51,8 @@ ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.status_error0; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); - pmc->mask =rte_cpu_to_le_16 (1 <<ICE_RX_FLEX_DESC_STATUS0_DD_S ); +/* comparison callback */ + pmc->fn = ice_monitor_callback;/* register is 16-bit */ pmc->size =sizeof (uint16_t );
drivers/net/ixgbe/ixgbe_rxtx.c +14 -6
@@ -1369,6 +1369,18 @@ const uint32_t RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP, }; +static int +ixgbe_monitor_callback (const uint64_t value, + const uint64_t arg[RTE_POWER_MONITOR_OPAQUE_SZ] __rte_unused) +{ +const uint64_t m =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* +* we expect the DD bit to be set to 1 if this descriptor was already +* written to. +*/ +return (value & m) == m ?-1 :0 ; +} +int ixgbe_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {
@@ -1381,12 +1393,8 @@ ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)/* watch for changes in status bit */ pmc->addr = &rxdp->wb.upper.status_error; -/* -* we expect the DD bit to be set to 1 if this descriptor was already -* written to. -*/ - pmc->val =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); - pmc->mask =rte_cpu_to_le_32 (IXGBE_RXDADV_STAT_DD ); +/* comparison callback */ + pmc->fn = ixgbe_monitor_callback;/* the registers are 32-bit */ pmc->size =sizeof (uint32_t );
drivers/net/mlx5/mlx5_rx.c +15 -2
@@ -269,6 +269,18 @@ mlx5_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)return rx_queue_count (rxq); } +#define CLB_VAL_IDX 0 +#define CLB_MSK_IDX 1 +static int +mlx5_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t m = opaque[CLB_MSK_IDX ]; +const uint64_t v = opaque[CLB_VAL_IDX ]; + +return (value & m) == v ?-1 :0 ; +} +int mlx5_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) {struct mlx5_rxq_data *rxq = rx_queue;
@@ -282,8 +294,9 @@ int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)return -rte_errno; } pmc->addr = &cqe->op_own; - pmc->val = !!idx; - pmc->mask =MLX5_CQE_OWNER_MASK ; + pmc->opaque[CLB_VAL_IDX ] = !!idx; + pmc->opaque[CLB_MSK_IDX ] =MLX5_CQE_OWNER_MASK ; + pmc->fn = mlx5_monitor_callback; pmc->size =sizeof (uint8_t );return 0 ; }
lib/eal/include/generic/rte_power_intrinsics.h +26 -7
@@ -18,19 +18,38 @@* which are architecture-dependent. */ +/** Size of the opaque data in monitor condition */ +#define RTE_POWER_MONITOR_OPAQUE_SZ 4 + +/** +* Callback definition for monitoring conditions. Callbacks with this signature +* will be used by `rte_power_monitor()` to check if the entering of power +* optimized state should be aborted. +* +* @param val +* The value read from memory. +* @param opaque +* Callback-specific data. +* +* @return +* 0 if entering of power optimized state should proceed +* -1 if entering of power optimized state should be aborted +*/ +typedef int (*rte_power_monitor_clb_t )(const uint64_t val, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]);struct rte_power_monitor_cond {volatile void *addr;/**< Address to monitor for changes */ -uint64_t val;/**< If the `mask` is non-zero, location pointed -* to by `addr` will be read and compared -* against this value. -*/ -uint64_t mask;/**< 64-bit mask to extract value read from `addr` */ -uint8_t size;/**< Data size (in bytes) that will be used to compare -* expected value (`val`) with data read from the +uint8_t size;/**< Data size (in bytes) that will be read from the * monitored memory location (`addr`). Can be 1, 2, * 4, or 8. Supplying any other value will result in * an error. */ +rte_power_monitor_clb_t fn;/**< Callback to be used to check if +* entering power optimized state should +* be aborted. +*/ +uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]; +/**< Callback-specific data */ };/**
lib/eal/x86/rte_power_intrinsics.c +8 -9
@@ -76,6 +76,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,const uint32_t tsc_h = (uint32_t )(tsc_timestamp >>32 );const unsigned int lcore_id =rte_lcore_id ();struct power_wait_status *s; +uint64_t cur_value;/* prevent user from running this instruction if it's not supported */ if (!wait_supported)
@@ -91,6 +92,9 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,if (__check_val_size (pmc->size) <0 )return -EINVAL ; +if (pmc->fn ==NULL ) +return -EINVAL ; + s = &wait_status[lcore_id];/* update sleep address */
@@ -110,16 +114,11 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,/* now that we've put this address into monitor, we can unlock */ rte_spinlock_unlock (&s->lock); -/* if we have a comparison mask, we might not need to sleep at all */ -if (pmc->mask) { -const uint64_t cur_value =__get_umwait_val ( - pmc->addr, pmc->size); -const uint64_t masked = cur_value & pmc->mask; + cur_value =__get_umwait_val (pmc->addr, pmc->size); -/* if the masked value is already matching, abort */ -if (masked == pmc->val) - goto end; - } +/* check if callback indicates we should abort */ +if (pmc->fn (cur_value, pmc->opaque) !=0 ) + goto end;/* execute UMWAIT */ asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;"
Signature · 1 line
2.25.1
PATCH v10 2/8 net/af_xdp: add power monitor support
In reply to Anatoly BurakovImplement support for .get_monitor_addr in AF_XDP driver.
---
Notes:
v8:
- Fix checkpatch issue
v2:
- Rewrite using the callback mechanism
drivers/net/af_xdp/rte_eth_af_xdp.c | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
drivers/net/af_xdp/rte_eth_af_xdp.c +34 -0
@@ -37,6 +37,7 @@#include <rte_malloc.h> #include <rte_ring.h> #include <rte_spinlock.h> +#include <rte_power_intrinsics.h> #include "compat.h"
@@ -788,6 +789,38 @@ eth_dev_configure(struct rte_eth_dev *dev)return 0 ; } +#define CLB_VAL_IDX 0 +static int +eth_monitor_callback (const uint64_t value, +const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ ]) +{ +const uint64_t v = opaque[CLB_VAL_IDX ]; +const uint64_t m = (uint32_t )~0 ; + +/* if the value has changed, abort entering power optimized state */ +return (value & m) == v ?0 :-1 ; +} + +static int +eth_get_monitor_addr (void *rx_queue,struct rte_power_monitor_cond *pmc) +{ +struct pkt_rx_queue *rxq = rx_queue; +unsigned int *prod = rxq->rx.producer; +const uint32_t cur_val = rxq->rx.cached_prod;/* use cached value */ + +/* watch for changes in producer ring */ + pmc->addr = (void *)prod; + +/* store current value */ + pmc->opaque[CLB_VAL_IDX ] = cur_val; + pmc->fn = eth_monitor_callback; + +/* AF_XDP producer ring index is 32-bit */ + pmc->size =sizeof (uint32_t ); + +return 0 ; +} +static int eth_dev_info (struct rte_eth_dev *dev,struct rte_eth_dev_info *dev_info) {
@@ -1448,6 +1481,7 @@ static const struct eth_dev_ops ops = { .link_update = eth_link_update, .stats_get = eth_stats_get, .stats_reset = eth_stats_reset, + .get_monitor_addr = eth_get_monitor_addr };/** parse busy_budget argument */
Signature · 1 line
2.25.1
PATCH v10 3/8 doc: add PMD power management NIC feature
In reply to Anatoly BurakovAt this point, multiple different Ethernet drivers from multiple vendors will support the PMD power management scheme. It would be useful to add it to the NIC feature table to indicate support for it.
---
Notes:
v10:
- Added missing NIC feature support in ini files
doc/guides/nics/features.rst | 10 ++++++++++ doc/guides/nics/features/af_xdp.ini | 1 + doc/guides/nics/features/default.ini | 1 + doc/guides/nics/features/i40e.ini | 1 + doc/guides/nics/features/i40e_vf.ini | 1 + doc/guides/nics/features/iavf.ini | 1 + doc/guides/nics/features/ice.ini | 1 + doc/guides/nics/features/ixgbe.ini | 1 + doc/guides/nics/features/ixgbe_vf.ini | 1 + doc/guides/nics/features/mlx5.ini | 1 + 10 files changed, 19 insertions(+)
doc/guides/nics/features.rst +10 -0
@@ -912,6 +912,16 @@ Supports to get Rx/Tx packet burst mode information. * **[implements] eth_dev_ops**: ``rx_burst_mode_get``, ``tx_burst_mode_get``. * **[related] API**: ``rte_eth_rx_burst_mode_get()``, ``rte_eth_tx_burst_mode_get()``. +.. _nic_features_get_monitor_addr: + +PMD power management using monitor addresses +-------------------------------------------- + +Supports getting a monitoring condition to use together with Ethernet PMD power +management (see :doc:`../prog_guide/power_man` for more details). + +* **[implements] eth_dev_ops**: ``get_monitor_addr`` + .. _nic_features_other: Other dev ops not represented by a Feature
doc/guides/nics/features/af_xdp.ini +1 -0
@@ -9,3 +9,4 @@ MTU update = Y Promiscuous mode = Y Stats per queue = Y x86-64 = Y +Power mgmt address monitor = Y
doc/guides/nics/features/default.ini +1 -0
@@ -76,6 +76,7 @@ x86-64 = Usage doc = Design doc = Perf doc = +Power mgmt address monitor = [rte_flow items] ah =
doc/guides/nics/features/i40e.ini +1 -0
@@ -51,6 +51,7 @@ x86-32 = Y x86-64 = Y ARMv8 = Y Power8 = Y +Power mgmt address monitor = Y [rte_flow items] ah = Y
doc/guides/nics/features/i40e_vf.ini +1 -0
@@ -37,3 +37,4 @@ FreeBSD = Y Linux = Y x86-32 = Y x86-64 = Y +Power mgmt address monitor = Y
doc/guides/nics/features/iavf.ini +1 -0
@@ -33,6 +33,7 @@ FreeBSD = Y Linux = Y x86-32 = Y x86-64 = Y +Power mgmt address monitor = Y [rte_flow items] ah = Y
doc/guides/nics/features/ice.ini +1 -0
@@ -42,6 +42,7 @@ Linux = Y Windows = Y x86-32 = Y x86-64 = Y +Power mgmt address monitor = Y [rte_flow items] ah = Y
doc/guides/nics/features/ixgbe.ini +1 -0
@@ -54,6 +54,7 @@ Linux = Y ARMv8 = Y x86-32 = Y x86-64 = Y +Power mgmt address monitor = Y [rte_flow items] eth = Y
doc/guides/nics/features/ixgbe_vf.ini +1 -0
@@ -38,3 +38,4 @@ Linux = Y ARMv8 = Y x86-32 = Y x86-64 = Y +Power mgmt address monitor = Y
doc/guides/nics/features/mlx5.ini +1 -0
@@ -51,6 +51,7 @@ Power8 = Y x86-32 = Y x86-64 = Y Usage doc = Y +Power mgmt address monitor = Y [rte_flow items] conntrack = Y
Signature · 1 line
2.25.1
PATCH v10 4/8 eal: add power monitor for multiple events
In reply to Anatoly BurakovUse RTM and WAITPKG instructions to perform a wait-for-writes similar to what UMWAIT does, but without the limitation of having to listen for just one event. This works because the optimized power state used by the TPAUSE instruction will cause a wake up on RTM transaction abort, so if we add the addresses we're interested in to the read-set, any write to those addresses will wake us up.
---
Notes:
v4:
- Fixed bugs in accessing the monitor condition
- Abort on any monitor condition not having a defined callback
v2:
- Adapt to callback mechanism
lib/eal/arm/rte_power_intrinsics.c | 11 +++ lib/eal/include/generic/rte_cpuflags.h | 2 + .../include/generic/rte_power_intrinsics.h | 35 +++++++++ lib/eal/ppc/rte_power_intrinsics.c | 11 +++ lib/eal/version.map | 3 + lib/eal/x86/rte_cpuflags.c | 2 + lib/eal/x86/rte_power_intrinsics.c | 73 +++++++++++++++++++ 7 files changed, 137 insertions(+)
lib/eal/arm/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/include/generic/rte_cpuflags.h +2 -0
@@ -24,6 +24,8 @@ struct rte_cpu_intrinsics {/**< indicates support for rte_power_monitor function */ uint32_t power_pause : 1;/**< indicates support for rte_power_pause function */ + uint32_t power_monitor_multi : 1; +/**< indicates support for rte_power_monitor_multi function */ };/**
lib/eal/include/generic/rte_power_intrinsics.h +35 -0
@@ -128,4 +128,39 @@ int rte_power_monitor_wakeup(const unsigned int lcore_id);__rte_experimental int rte_power_pause(const uint64_t tsc_timestamp); +/** +* @warning +* @b EXPERIMENTAL: this API may change without prior notice +* +* Monitor a set of addresses for changes. This will cause the CPU to enter an +* architecture-defined optimized power state until either one of the specified +* memory addresses is written to, a certain TSC timestamp is reached, or other +* reasons cause the CPU to wake up. +* +* Additionally, `expected` 64-bit values and 64-bit masks 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 do not 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_intrinsics_support()` API call. +* Failing to do so may result in an illegal CPU instruction error. +* +* @param pmc +* An array of monitoring condition structures. +* @param num +* Length of the `pmc` array. +* @param tsc_timestamp +* Maximum TSC timestamp to wait for. Note that the wait behavior is +* architecture-dependent. +* +* @return +* 0 on success +* -EINVAL on invalid parameters +* -ENOTSUP if unsupported +*/ +__rte_experimental +int rte_power_monitor_multi(const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp); +#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/eal/ppc/rte_power_intrinsics.c +11 -0
@@ -38,3 +38,14 @@ rte_power_monitor_wakeup(const unsigned int lcore_id)return -ENOTSUP ; } + +int +rte_power_monitor_multi (const struct rte_power_monitor_cond pmc[], +const uint32_t num,const uint64_t tsc_timestamp) +{ +RTE_SET_USED (pmc); +RTE_SET_USED (num); +RTE_SET_USED (tsc_timestamp); + +return -ENOTSUP ; +}
lib/eal/version.map +3 -0
@@ -423,6 +423,9 @@ EXPERIMENTAL { rte_version_release; # WINDOWS_NO_EXPORT rte_version_suffix; # WINDOWS_NO_EXPORT rte_version_year; # WINDOWS_NO_EXPORT + + # added in 21.08 + rte_power_monitor_multi; # WINDOWS_NO_EXPORT }; INTERNAL {
lib/eal/x86/rte_cpuflags.c +2 -0
@@ -189,5 +189,7 @@ rte_cpu_get_intrinsics_support(struct rte_cpu_intrinsics *intrinsics)if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_WAITPKG )) { intrinsics->power_monitor =1 ; intrinsics->power_pause =1 ; +if (rte_cpu_get_flag_enabled (RTE_CPUFLAG_RTM )) + intrinsics->power_monitor_multi =1 ; } }
lib/eal/x86/rte_power_intrinsics.c +73 -0
100 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v10 5/8 power: remove thread safety from PMD power API's
In reply to Anatoly BurakovCurrently, we expect that only one callback can be active at any given moment, for a particular queue configuration, which is relatively easy to implement in a thread-safe way. However, we're about to add support for multiple queues per lcore, which will greatly increase the possibility of various race conditions.
We could have used something like an RCU for this use case, but absent of a pressing need for thread safety we'll go the easy way and just mandate that the API's are to be called when all affected ports are stopped, and document this limitation. This greatly simplifies the rte_power_monitor-related code.
---
Notes:
v2:
- Add check for stopped queue
- Clarified doc message
- Added release notes
doc/guides/rel_notes/release_21_08.rst | 4 + lib/power/meson.build | 3 + lib/power/rte_power_pmd_mgmt.c | 133 ++++++++++--------------- lib/power/rte_power_pmd_mgmt.h | 6 ++ 4 files changed, 66 insertions(+), 80 deletions(-)
doc/guides/rel_notes/release_21_08.rst +4 -0
@@ -146,6 +146,10 @@ API Changes * eal: the ``rte_power_intrinsics`` API changed to use a callback mechanism. +* rte_power: The experimental PMD power management API is no longer considered + to be thread safe; all Rx queues affected by the API will now need to be + stopped before making any changes to the power management scheme. + ABI Changes -----------
lib/power/meson.build +3 -0
@@ -22,4 +22,7 @@ headers = files( 'rte_power_pmd_mgmt.h', 'rte_power_guest_channel.h', ) +if cc.has_argument('-Wno-cast-qual') + cflags += '-Wno-cast-qual' +endif deps += ['timer', 'ethdev']
lib/power/rte_power_pmd_mgmt.c +53 -80
209 lines not on this page · raw message
lib/power/rte_power_pmd_mgmt.h +6 -0
@@ -43,6 +43,9 @@ enum rte_power_pmd_mgmt_type {* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue will be polled from. * @param port_id
@@ -69,6 +72,9 @@ rte_power_ethdev_pmgmt_queue_enable(unsigned int lcore_id,* * @note This function is not thread-safe. * +* @warning This function must be called when all affected Ethernet queues are +* stopped and no Rx/Tx is in progress! +* * @param lcore_id * The lcore the Rx queue is polled from. * @param port_id
Signature · 1 line
2.25.1
PATCH v10 6/8 power: support callbacks for multiple Rx queues
In reply to Anatoly BurakovCurrently, there is a hard limitation on the PMD power management support that only allows it to support a single queue per lcore. This is not ideal as most DPDK use cases will poll multiple queues per core.
The PMD power management mechanism relies on ethdev Rx callbacks, so it is very difficult to implement such support because callbacks are effectively stateless and have no visibility into what the other ethdev devices are doing. This places limitations on what we can do within the framework of Rx callbacks, but the basics of this implementation are as follows:
- Replace per-queue structures with per-lcore ones, so that any device polled from the same lcore can share data
- Any queue that is going to be polled from a specific lcore has to be added to the list of queues to poll, so that the callback is aware of other queues being polled by the same lcore
- Both the empty poll counter and the actual power saving mechanism is shared between all queues polled on a particular lcore, and is only activated when all queues in the list were polled and were determined to have no traffic.
- The limitation on UMWAIT-based polling is not removed because UMWAIT is incapable of monitoring more than one address.
Also, while we're at it, update and improve the docs.
---
Notes:
v8:
- Added a comment explaining that we want to sleep on each empty poll after threshold has been reached
v7:
- Fix bug where initial sleep target was always set to zero
- Fix logic in handling of n_queues_ready_to_sleep counter
- Update documentation on hardware requirements
v6:
- Track each individual queue sleep status (Konstantin)
- Fix segfault (Dave)
v5:
- Remove the "power save queue" API and replace it with mechanism suggested by Konstantin
v3:
- Move the list of supported NICs to NIC feature table
v2:
- Use a TAILQ for queues instead of a static array
- Address feedback from Konstantin
- Add additional checks for stopped queues
doc/guides/prog_guide/power_man.rst | 69 ++-- doc/guides/rel_notes/release_21_08.rst | 5 + lib/power/rte_power_pmd_mgmt.c | 460 +++++++++++++++++++------ 3 files changed, 398 insertions(+), 136 deletions(-)
doc/guides/prog_guide/power_man.rst +41 -28
@@ -198,34 +198,45 @@ Ethernet 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. - -Monitor - This power saving scheme will put the CPU into optimized power state - and use the ``rte_power_monitor()`` function - to monitor the Ethernet PMD RX descriptor address, - and wake the CPU up whenever there's new traffic. - -Pause - This power saving scheme will avoid busy polling - by either entering power-optimized sleep state - with ``rte_power_pause()`` function, - or, if it's not available, use ``rte_pause()``. - -Frequency scaling - This power saving scheme will use ``librte_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). +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. + +* Monitor + This power saving scheme will put the CPU into optimized power state and + monitor the Ethernet PMD RX descriptor address, waking the CPU up whenever + there's new traffic. Support for this scheme may not be available on all + platforms, and further limitations may apply (see below). + +* Pause + This power saving scheme will avoid busy polling by either entering + power-optimized sleep state with ``rte_power_pause()`` function, or, if it's + not supported by the underlying platform, use ``rte_pause()``. + +* Frequency scaling + This power saving scheme will use ``librte_power`` library functionality to + scale the core frequency up/down depending on traffic volume. + +The "monitor" mode is only supported in the following configurations and scenarios: + +* On Linux* x86_64, `rte_power_monitor()` requires WAITPKG instruction set being + supported by the CPU. Please refer to your platform documentation for further + information. + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that + ``rte_power_monitor()`` is supported by the platform, then monitoring will be + limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be + monitored from a different lcore). + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that the + ``rte_power_monitor()`` function is not supported, then monitor mode will not + be supported. + +* Not all Ethernet drivers support monitoring, even if the underlying + platform may support the necessary CPU instructions. Please refer to + :doc:`../nics/overview` for more information. + API Overview for Ethernet PMD Power Management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -242,3 +253,5 @@ References * The :doc:`../sample_app_ug/vm_power_management` chapter in the :doc:`../sample_app_ug/index` section. + +* The :doc:`../nics/overview` chapter in the :doc:`../nics/index` section
doc/guides/rel_notes/release_21_08.rst +5 -0
@@ -112,6 +112,11 @@ New Features Added support for cppc_cpufreq driver which works on most arm64 platforms. +* **Added multi-queue support to Ethernet PMD Power Management** + + The experimental PMD power management API now supports managing + multiple Ethernet Rx queues per lcore. + Removed Items -------------
lib/power/rte_power_pmd_mgmt.c +352 -108
575 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v10 7/8 power: support monitoring multiple Rx queues
In reply to Anatoly BurakovUse the new multi-monitor intrinsic to allow monitoring multiple ethdev Rx queues while entering the energy efficient power state. The multi version will be used unconditionally if supported, and the UMWAIT one will only be used when multi-monitor is not supported by the hardware.
---
Notes:
v6:
- Fix the missed feedback from v5
v4:
- Fix possible out of bounds access
- Added missing index increment
doc/guides/prog_guide/power_man.rst | 15 ++++-- lib/power/rte_power_pmd_mgmt.c | 82 ++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 7 deletions(-)
doc/guides/prog_guide/power_man.rst +10 -5
@@ -221,17 +221,22 @@ power saving whenever empty poll count reaches a certain number. The "monitor" mode is only supported in the following configurations and scenarios: * On Linux* x86_64, `rte_power_monitor()` requires WAITPKG instruction set being - supported by the CPU. Please refer to your platform documentation for further - information. + supported by the CPU, while `rte_power_monitor_multi()` requires WAITPKG and + RTM instruction sets being supported by the CPU. RTM instruction set may also + require booting the Linux with `tsx=on` command line parameter. Please refer + to your platform documentation for further information. * If ``rte_cpu_get_intrinsics_support()`` function indicates that + ``rte_power_monitor_multi()`` function is supported by the platform, then + monitoring multiple Ethernet Rx queues for traffic will be supported. + +* If ``rte_cpu_get_intrinsics_support()`` function indicates that only ``rte_power_monitor()`` is supported by the platform, then monitoring will be limited to a mapping of 1 core 1 queue (thus, each Rx queue will have to be monitored from a different lcore). -* If ``rte_cpu_get_intrinsics_support()`` function indicates that the - ``rte_power_monitor()`` function is not supported, then monitor mode will not - be supported. +* If ``rte_cpu_get_intrinsics_support()`` function indicates that neither of the + two monitoring functions are supported, then monitor mode will not be supported. * Not all Ethernet drivers support monitoring, even if the underlying platform may support the necessary CPU instructions. Please refer to
lib/power/rte_power_pmd_mgmt.c +80 -2
119 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v10 8/8 examples/l3fwd-power: support multiq in PMD modes
In reply to Anatoly BurakovCurrently, l3fwd-power enforces the limitation of having one queue per lcore. This is no longer necessary, so remove the limitation.
--- examples/l3fwd-power/main.c | 6 ------ 1 file changed, 6 deletions(-)
examples/l3fwd-power/main.c +0 -6
@@ -2723,12 +2723,6 @@ main(int argc, char **argv)printf ("\nInitializing rx queues on lcore %u ... " , lcore_id );fflush (stdout); -/* PMD power management mode can only do 1 queue per core */ -if (app_mode ==APP_MODE_PMD_MGMT && qconf->n_rx_queue >1 ) { -rte_exit (EXIT_FAILURE , -"In PMD power management mode, only one queue per lcore is allowed\n" ); - } -/* init RX queues */ for (queue =0 ; queue < qconf->n_rx_queue; ++queue) {struct rte_eth_rxconf rxq_conf;
Signature · 1 line
2.25.1
Quoted 51 lines · Anatoly Burakov
This patchset introduces several changes related to PMD power management:
- Changed monitoring intrinsics to use callbacks as a comparison function, based on previous patchset [1] but incorporating feedback [2] - this hopefully will make it possible to add support for .get_monitor_addr in virtio
- Add a new intrinsic to monitor multiple addresses, based on RTM instruction set and the TPAUSE instruction
- Add support for PMD power management on multiple queues, as well as all accompanying infrastructure and example apps changesv10:
- Added missing changes to NIC feature .ini filesv9:
- Added all missing Acks and Tests
- Added a new commit with NIC features
- Addressed minor issues raised in reviewv8:
- Fixed checkpatch issue
- Added comment explaining empty poll handling (Konstantin)v7:
- Fixed various bugsv6:
- Improved the algorithm for multi-queue sleep
- Fixed segfault and addressed other feedbackv5:
- Removed "power save queue" API and replaced with mechanism suggested by Konstantin
- Addressed other feedbackv4:
- Replaced raw number with a macro
- Fixed all the bugs found by Konstantin
- Some other minor correctionsv3:
- Moved some doc updates to NIC features listv2:
- Changed check inversion to callbacks
- Addressed feedback from Konstantin
- Added doc updates where necessary[1] http://patches.dpdk.org/project/dpdk/list/?series=16930&state=*
[2] http://patches.dpdk.org/project/dpdk/patch/819ef1ace187365a615d3383e54579e3d9fb216e.1620747068.git.anatoly.burakov@intel.com/#133274
Quoted 9 lines
Anatoly Burakov (8):
eal: use callbacks for power monitoring comparisonnet/af_xdp: add power monitor support
doc: add PMD power management NIC feature
eal: add power monitor for multiple events
power: remove thread safety from PMD power API's
power: support callbacks for multiple Rx queues
power: support monitoring multiple Rx queues examples/l3fwd-power: support multiq in PMD modes
Overall, the series lgtm.
I still have a comment on the opaque pointer passed in callbacks. This is not blocking, we can still go with followup patches in this release.
It would be great if drivers maintainers could implement this new ops in their driver or give feedback on what should be enhanced.
Series applied, thanks.
Signature · 1 line
David Marchand