Skip to contentSkip to conversation

Power-optimized RX for Ethernet devices

RFC In review Anatoly Burakov 20 participants 421 messages May 27, 2020 – Jan 29, 2021 Page 2 of 4

Subsystems (3)
lore
Share & tools
lore
#109 lore raw

PATCH v16 11/11 examples/l3fwd-power: enable PMD power mgmt

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Notes:
v12:
- Allow selecting PMD power management scheme from command-line
- Enforce 1 core 1 queue rule

 .../sample_app_ug/l3_forward_power_man.rst    | 35 ++++++++
 examples/l3fwd-power/main.c                   | 89 ++++++++++++++++++-
 2 files changed, 122 insertions(+), 2 deletions(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +35 -0
index 85a78a5c1e..aaa9367fae 100644
@@ -109,6 +109,8 @@ where,
 
 *   --telemetry:  Telemetry mode.
 
+*   --pmd-mgmt: PMD power management mode.
+
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
 
@@ -456,3 +458,36 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./build/examples/dpdk-l3fwd-power -l 1-3 --  --pmd-mgmt -p 0x0f --config="(0,0,2),(0,1,3)"
+
+PMD Power Management Mode
+-------------------------
+There is also a traffic-aware operating mode that, instead of using explicit
+power management, will use automatic PMD power management. This mode is limited
+to one queue per core, and has three available power management schemes:
+
+* ``monitor`` - this will use ``rte_power_monitor()`` function to enter a
+  power-optimized state (subject to platform support).
+
+* ``pause`` - this will use ``rte_power_pause()`` or ``rte_pause()`` to avoid
+  busy looping when there is no traffic.
+
+* ``scale`` - this will use frequency scaling routines available in the
+  ``librte_power`` library.
+
+See :doc:`Power Management<../prog_guide/power_man>` chapter in the DPDK
+Programmer's Guide for more details on PMD power management.
+
+.. code-block:: console
+
+        ./<build_dir>/examples/dpdk-l3fwd-power -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)" --pmd-mgmt=scale
examples/l3fwd-power/main.c +87 -2

165 lines not on this page · raw message

Signature · 1 line
2.25.1
#110 lore raw

Re: [dpdk-dev] [PATCH v16 00/11] Add PMD power management

In reply to Anatoly Burakov
Quoted 34 lines · Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.

To achieve power savings, there is a very simple mechanism used: we're counting empty polls, and if a certain threshold is reached, we employ one of the suggested power management schemes automatically, from within a Rx callback inside the PMD. Once there's traffic again, the empty poll counter is reset.

This patchset also introduces a few changes into existing power management-related intrinsics, namely to provide a native way of waking up a sleeping core without application being responsible for it, as well as general robustness improvements. There's quite a bit of locking going on, but these locks are per-thread and very little (if any) contention is expected, so the performance impact shouldn't be that bad (and in any case the locking happens when we're about to sleep anyway).

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

Quoted 4 lines

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue

If we want to save power, it is likely we would poll more rxqs on a thread.

Quoted 7 lines

- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

v16:
- Implemented Konstantin's suggestions and comments
- Added return values to the API

- This revision breaks SPDK build (reported by UNH):
http://mails.dpdk.org/archives/test-report/2021-January/174069.html

- Build is broken for ARM and PPC at patch:
86491d5bd4 - (HEAD) eal: add monitor wakeup function (25 minutes ago) <Anatoly Burakov>

Only pasting the ARM failure:
ninja: Entering directory `/home/dmarchan/builds/build-arm64-host-clang' [1/297] Compiling C object 'lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o'.
FAILED: lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o aarch64-linux-gnu-gcc -Ilib/76b5a35@@rte_eal@sta -Ilib -I../../dpdk/lib -I. -I../../dpdk/ -Iconfig -I../../dpdk/config -Ilib/librte_eal/include -I../../dpdk/lib/librte_eal/include -Ilib/librte_eal/linux/include -I../../dpdk/lib/librte_eal/linux/include -Ilib/librte_eal/arm/include -I../../dpdk/lib/librte_eal/arm/include -Ilib/librte_eal/common -I../../dpdk/lib/librte_eal/common -Ilib/librte_eal -I../../dpdk/lib/librte_eal -Ilib/librte_kvargs -I../../dpdk/lib/librte_kvargs -Ilib/librte_telemetry/../librte_metrics -I../../dpdk/lib/librte_telemetry/../librte_metrics -Ilib/librte_telemetry -I../../dpdk/lib/librte_telemetry -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Werror -O2 -g -include rte_config.h -Wextra -Wcast-qual -Wdeprecated -Wformat -Wformat-nonliteral -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wpointer-arith -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings -Wno-packed-not-aligned -Wno-missing-field-initializers -D_GNU_SOURCE -fPIC -march=armv8-a+crc -DALLOW_EXPERIMENTAL_API -DALLOW_INTERNAL_API -Wno-format-truncation '-DABI_VERSION="21.1"' -DRTE_LIBEAL_USE_GETENTROPY -MD -MQ 'lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o' -MF 'lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o.d' -o 'lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o' -c ../../dpdk/lib/librte_eal/arm/rte_power_intrinsics.c ../../dpdk/lib/librte_eal/arm/rte_power_intrinsics.c:35:1: error:
conflicting types for ‘rte_power_monitor_wakeup’
rte_power_monitor_wakeup(const unsigned int lcore_id) ^~~~~~~~~~~~~~~~~~~~~~~~
In file included from ../../dpdk/lib/librte_eal/arm/include/rte_power_intrinsics.h:14,

                 from ../../dpdk/lib/librte_eal/arm/rte_power_intrinsics.c:5:
../../dpdk/lib/librte_eal/include/generic/rte_power_intrinsics.h:79:5:
note: previous declaration of ‘rte_power_monitor_wakeup’ was here
 int rte_power_monitor_wakeup(const unsigned int lcore_id);
     ^~~~~~~~~~~~~~~~~~~~~~~~

ninja: build stopped: subcommand failed.

- The ABI check is still not happy as I reported earlier. Reproduced on v16 (GHA had a hiccup on this revision, but previous ones had the failure too):

1 Changed variable:

[C] 'rte_eth_dev rte_eth_devices[]' was changed at rte_ethdev_core.h:196:1:
type of variable changed:
array element type 'struct rte_eth_dev' changed:
type size hasn't changed
1 data member change:
type of 'const eth_dev_ops* rte_eth_dev::dev_ops' changed:
in pointed to type 'const eth_dev_ops':
in unqualified underlying type 'struct eth_dev_ops' at
rte_ethdev_driver.h:789:1:
type size changed from 6208 to 6272 (in bits)
1 data member insertion:
'eth_get_monitor_addr_t
eth_dev_ops::get_monitor_addr', at offset 6208 (in bits) at rte_ethdev_driver.h:940:1
no data member changes (94 filtered);
type size hasn't changed

Error: ABI issue reported for 'abidiff --suppr /home/dmarchan/dpdk/devtools/../devtools/libabigail.abignore --no-added-syms --headers-dir1 /home/dmarchan/abi/v20.11/build-gcc-static/usr/local/include --headers-dir2 /home/dmarchan/builds/build-gcc-static/install/usr/local/include /home/dmarchan/abi/v20.11/build-gcc-static/dump/librte_ethdev.dump /home/dmarchan/builds/build-gcc-static/install/dump/librte_ethdev.dump'

ABIDIFF_ABI_CHANGE, this change requires a review (abidiff flagged this as a potential issue).

One solution is to add an exception on the eth_dev_ops structure.

devtools/libabigail.abignore +4 -0
@@ -7,3 +7,7 @@
         symbol_version = INTERNAL
 [suppress_variable]
         symbol_version = INTERNAL
+
+; Explicit ignore for driver-only ABI
+[suppress_type]
+        name = eth_dev_ops
Signature · 1 line
David marchand
#111 lore raw

Re: [dpdk-dev] [PATCH v16 00/11] Add PMD power management

Quoted 36 lines · David Marchand
Quoted 34 lines · Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.

To achieve power savings, there is a very simple mechanism used: we're counting empty polls, and if a certain threshold is reached, we employ one of the suggested power management schemes automatically, from within a Rx callback inside the PMD. Once there's traffic again, the empty poll counter is reset.

This patchset also introduces a few changes into existing power management-related intrinsics, namely to provide a native way of waking up a sleeping core without application being responsible for it, as well as general robustness improvements. There's quite a bit of locking going on, but these locks are per-thread and very little (if any) contention is expected, so the performance impact shouldn't be that bad (and in any case the locking happens when we're about to sleep anyway).

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

Quoted 6 lines
Quoted 4 lines

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue

If we want to save power, it is likely we would poll more rxqs on a thread.

We are investigating possibilities to make that happen, but for this patchset, this is the limitation.

Quoted 54 lines
Quoted 9 lines

- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

v16:
- Implemented Konstantin's suggestions and comments
- Added return values to the API

- This revision breaks SPDK build (reported by UNH):
http://mails.dpdk.org/archives/test-report/2021-January/174069.html

- Build is broken for ARM and PPC at patch:
86491d5bd4 - (HEAD) eal: add monitor wakeup function (25 minutes ago) <Anatoly Burakov>

Only pasting the ARM failure:
ninja: Entering directory `/home/dmarchan/builds/build-arm64-host-clang' [1/297] Compiling C object 'lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o'.
FAILED: lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o aarch64-linux-gnu-gcc -Ilib/76b5a35@@rte_eal@sta -Ilib

(quoted diff) +0 -19
-I../../dpdk/lib -I. -I../../dpdk/ -Iconfig -I../../dpdk/config
-Ilib/librte_eal/include -I../../dpdk/lib/librte_eal/include
-Ilib/librte_eal/linux/include
-I../../dpdk/lib/librte_eal/linux/include -Ilib/librte_eal/arm/include
-I../../dpdk/lib/librte_eal/arm/include -Ilib/librte_eal/common
-I../../dpdk/lib/librte_eal/common -Ilib/librte_eal
-I../../dpdk/lib/librte_eal -Ilib/librte_kvargs
-I../../dpdk/lib/librte_kvargs
-Ilib/librte_telemetry/../librte_metrics
-I../../dpdk/lib/librte_telemetry/../librte_metrics
-Ilib/librte_telemetry -I../../dpdk/lib/librte_telemetry
-fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall
-Winvalid-pch -Werror -O2 -g -include rte_config.h -Wextra -Wcast-qual
-Wdeprecated -Wformat -Wformat-nonliteral -Wformat-security
-Wmissing-declarations -Wmissing-prototypes -Wnested-externs
-Wold-style-definition -Wpointer-arith -Wsign-compare
-Wstrict-prototypes -Wundef -Wwrite-strings -Wno-packed-not-aligned
-Wno-missing-field-initializers -D_GNU_SOURCE -fPIC -march=armv8-a+crc
-DALLOW_EXPERIMENTAL_API -DALLOW_INTERNAL_API -Wno-format-truncation

'-DABI_VERSION="21.1"' -DRTE_LIBEAL_USE_GETENTROPY -MD -MQ 'lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o' -MF 'lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o.d'

(quoted diff) +0 -2
-o 'lib/76b5a35@@rte_eal@sta/librte_eal_arm_rte_power_intrinsics.c.o'
-c ../../dpdk/lib/librte_eal/arm/rte_power_intrinsics.c

../../dpdk/lib/librte_eal/arm/rte_power_intrinsics.c:35:1: error:
conflicting types for ‘rte_power_monitor_wakeup’
rte_power_monitor_wakeup(const unsigned int lcore_id) ^~~~~~~~~~~~~~~~~~~~~~~~
In file included from ../../dpdk/lib/librte_eal/arm/include/rte_power_intrinsics.h:14,

Quoted 6 lines
                  from ../../dpdk/lib/librte_eal/arm/rte_power_intrinsics.c:5:
../../dpdk/lib/librte_eal/include/generic/rte_power_intrinsics.h:79:5:
note: previous declaration of ‘rte_power_monitor_wakeup’ was here
  int rte_power_monitor_wakeup(const unsigned int lcore_id);
      ^~~~~~~~~~~~~~~~~~~~~~~~

ninja: build stopped: subcommand failed.

Woops, wrong return value in the .c files. Will fix!

Quoted 44 lines

- The ABI check is still not happy as I reported earlier. Reproduced on v16 (GHA had a hiccup on this revision, but previous ones had the failure too):

1 Changed variable:

[C] 'rte_eth_dev rte_eth_devices[]' was changed at rte_ethdev_core.h:196:1:
type of variable changed:
array element type 'struct rte_eth_dev' changed:
type size hasn't changed
1 data member change:
type of 'const eth_dev_ops* rte_eth_dev::dev_ops' changed:
in pointed to type 'const eth_dev_ops':
in unqualified underlying type 'struct eth_dev_ops' at
rte_ethdev_driver.h:789:1:
type size changed from 6208 to 6272 (in bits)
1 data member insertion:
'eth_get_monitor_addr_t
eth_dev_ops::get_monitor_addr', at offset 6208 (in bits) at rte_ethdev_driver.h:940:1
no data member changes (94 filtered);
type size hasn't changed

Error: ABI issue reported for 'abidiff --suppr /home/dmarchan/dpdk/devtools/../devtools/libabigail.abignore --no-added-syms --headers-dir1 /home/dmarchan/abi/v20.11/build-gcc-static/usr/local/include --headers-dir2 /home/dmarchan/builds/build-gcc-static/install/usr/local/include /home/dmarchan/abi/v20.11/build-gcc-static/dump/librte_ethdev.dump /home/dmarchan/builds/build-gcc-static/install/dump/librte_ethdev.dump'

ABIDIFF_ABI_CHANGE, this change requires a review (abidiff flagged this as a potential issue).

One solution is to add an exception on the eth_dev_ops structure.

devtools/libabigail.abignore line 13

Quoted 7 lines
devtools/libabigail.abignore +4 -0
@@ -7,3 +7,7 @@
          symbol_version = INTERNAL
  [suppress_variable]
          symbol_version = INTERNAL
+
+; Explicit ignore for driver-only ABI
+[suppress_type]
+        name = eth_dev_ops

Right, OK. I didn't realize an "exception" is something you actually do in code, not an ad-hoc community process type thing :) I'll add this in the next revision.

Signature · 2 lines
Thanks,
Anatoly
#112 lore raw

v17 cover Add PMD power management

In reply to Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.

To achieve power savings, there is a very simple mechanism used: we're counting empty polls, and if a certain threshold is reached, we employ one of the suggested power management schemes automatically, from within a Rx callback inside the PMD. Once there's traffic again, the empty poll counter is reset.

This patchset also introduces a few changes into existing power management-related intrinsics, namely to provide a native way of waking up a sleeping core without application being responsible for it, as well as general robustness improvements. There's quite a bit of locking going on, but these locks are per-thread and very little (if any) contention is expected, so the performance impact shouldn't be that bad (and in any case the locking happens when we're about to sleep anyway).

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

v17:
- Added exception for ethdev driver-only ABI
- Added memory barriers for monitor/wakeup (Konstantin)
- Fixed compiled issues on non-x86 platforms (hopefully!)

v16:
- Implemented Konstantin's suggestions and comments
- Added return values to the API

v15:
- Fixed incorrect check in UMWAIT callback
- Fixed accidental whitespace changes

v14:
- Fixed ARM/PPC builds
- Addressed various review comments

v13:
- Reworked the librte_power code to require less locking and handle invalid parameters better
- Fix numerous rebase errors present in v12

v12:
- Rebase on top of 21.02
- Rework of power intrinsics code

Anatoly Burakov (5):
eal: uninline power intrinsics
eal: avoid invalid API usage in power intrinsics
eal: change API of power intrinsics
eal: remove sync version of power monitor
eal: add monitor wakeup function

Liang Ma (6):
ethdev: add simple power management API
power: add PMD power management API and callback net/ixgbe: implement power management API net/i40e: implement power management API net/ice: implement power management API examples/l3fwd-power: enable PMD power mgmt

 devtools/libabigail.abignore                  |   3 +
 doc/guides/prog_guide/power_man.rst           |  44 +++
 doc/guides/rel_notes/release_21_02.rst        |  15 +
 .../sample_app_ug/l3_forward_power_man.rst    |  35 ++
 drivers/event/dlb/dlb.c                       |  10 +-
 drivers/event/dlb2/dlb2.c                     |  10 +-
 drivers/net/i40e/i40e_ethdev.c                |   1 +
 drivers/net/i40e/i40e_rxtx.c                  |  25 ++
 drivers/net/i40e/i40e_rxtx.h                  |   1 +
 drivers/net/ice/ice_ethdev.c                  |   1 +
 drivers/net/ice/ice_rxtx.c                    |  26 ++
 drivers/net/ice/ice_rxtx.h                    |   1 +
 drivers/net/ixgbe/ixgbe_ethdev.c              |   1 +
 drivers/net/ixgbe/ixgbe_rxtx.c                |  25 ++
 drivers/net/ixgbe/ixgbe_rxtx.h                |   1 +
 examples/l3fwd-power/main.c                   |  89 ++++-
 .../arm/include/rte_power_intrinsics.h        |  40 --
 lib/librte_eal/arm/meson.build                |   1 +
 lib/librte_eal/arm/rte_power_intrinsics.c     |  40 ++
 .../include/generic/rte_power_intrinsics.h    |  88 ++---
 .../ppc/include/rte_power_intrinsics.h        |  40 --
 lib/librte_eal/ppc/meson.build                |   1 +
 lib/librte_eal/ppc/rte_power_intrinsics.c     |  40 ++
 lib/librte_eal/version.map                    |   3 +
 .../x86/include/rte_power_intrinsics.h        | 115 ------
 lib/librte_eal/x86/meson.build                |   1 +
 lib/librte_eal/x86/rte_power_intrinsics.c     | 215 +++++++++++
 lib/librte_ethdev/rte_ethdev.c                |  28 ++
 lib/librte_ethdev/rte_ethdev.h                |  25 ++
 lib/librte_ethdev/rte_ethdev_driver.h         |  22 ++
 lib/librte_ethdev/version.map                 |   3 +
 lib/librte_power/meson.build                  |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c         | 364 ++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h         |  90 +++++
 lib/librte_power/version.map                  |   5 +
 35 files changed, 1155 insertions(+), 259 deletions(-)
 create mode 100644 lib/librte_eal/arm/rte_power_intrinsics.c
 create mode 100644 lib/librte_eal/ppc/rte_power_intrinsics.c
 create mode 100644 lib/librte_eal/x86/rte_power_intrinsics.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
Signature · 1 line
2.25.1
#113 lore raw

PATCH v17 1/11 eal: uninline power intrinsics

Currently, power intrinsics are inline functions. Make them part of the ABI so that we can have various internal data associated with them without exposing said data to the outside world.

---

Notes:
v14:
- Fix compile issues on ARM and PPC64 by moving implementations to .c files

 .../arm/include/rte_power_intrinsics.h        |  40 ------
 lib/librte_eal/arm/meson.build                |   1 +
 lib/librte_eal/arm/rte_power_intrinsics.c     |  45 +++++++
 .../include/generic/rte_power_intrinsics.h    |   6 +-
 .../ppc/include/rte_power_intrinsics.h        |  40 ------
 lib/librte_eal/ppc/meson.build                |   1 +
 lib/librte_eal/ppc/rte_power_intrinsics.c     |  45 +++++++
 lib/librte_eal/version.map                    |   3 +
 .../x86/include/rte_power_intrinsics.h        | 115 -----------------
 lib/librte_eal/x86/meson.build                |   1 +
 lib/librte_eal/x86/rte_power_intrinsics.c     | 120 ++++++++++++++++++
 11 files changed, 219 insertions(+), 198 deletions(-)
 create mode 100644 lib/librte_eal/arm/rte_power_intrinsics.c
 create mode 100644 lib/librte_eal/ppc/rte_power_intrinsics.c
 create mode 100644 lib/librte_eal/x86/rte_power_intrinsics.c
lib/librte_eal/arm/include/rte_power_intrinsics.h +0 -40
index a4a1bc1159..9e498e9ebf 100644
@@ -13,46 +13,6 @@ extern "C" {
 
 #include "generic/rte_power_intrinsics.h"
 
-/**
- * This function is not supported on ARM.
- */
-static inline void
-rte_power_monitor(const volatile void *p, const uint64_t expected_value,
-		const uint64_t value_mask, const uint64_t tsc_timestamp,
-		const uint8_t data_sz)
-{
-	RTE_SET_USED(p);
-	RTE_SET_USED(expected_value);
-	RTE_SET_USED(value_mask);
-	RTE_SET_USED(tsc_timestamp);
-	RTE_SET_USED(data_sz);
-}
-
-/**
- * This function is not supported on ARM.
- */
-static inline void
-rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
-		const uint64_t value_mask, const uint64_t tsc_timestamp,
-		const uint8_t data_sz, rte_spinlock_t *lck)
-{
-	RTE_SET_USED(p);
-	RTE_SET_USED(expected_value);
-	RTE_SET_USED(value_mask);
-	RTE_SET_USED(tsc_timestamp);
-	RTE_SET_USED(lck);
-	RTE_SET_USED(data_sz);
-}
-
-/**
- * This function is not supported on ARM.
- */
-static inline void
-rte_power_pause(const uint64_t tsc_timestamp)
-{
-	RTE_SET_USED(tsc_timestamp);
-}
-
 #ifdef __cplusplus
 }
 #endif
lib/librte_eal/arm/meson.build +1 -0
index d62875ebae..6ec53ea03a 100644
@@ -7,4 +7,5 @@ sources += files(
 	'rte_cpuflags.c',
 	'rte_cycles.c',
 	'rte_hypervisor.c',
+	'rte_power_intrinsics.c',
 )
lib/librte_eal/arm/rte_power_intrinsics.c new file +45 -0

45 lines not on this page · raw message

lib/librte_eal/include/generic/rte_power_intrinsics.h +3 -3
index dd520d90fa..67977bd511 100644
@@ -52,7 +52,7 @@
  *   to undefined result.
  */
 __rte_experimental
-static inline void rte_power_monitor(const volatile void *p,
+void rte_power_monitor(const volatile void *p,
 		const uint64_t expected_value, const uint64_t value_mask,
 		const uint64_t tsc_timestamp, const uint8_t data_sz);
 
@@ -97,7 +97,7 @@ static inline void rte_power_monitor(const volatile void *p,
  *   wakes up.
  */
 __rte_experimental
-static inline void rte_power_monitor_sync(const volatile void *p,
+void rte_power_monitor_sync(const volatile void *p,
 		const uint64_t expected_value, const uint64_t value_mask,
 		const uint64_t tsc_timestamp, const uint8_t data_sz,
 		rte_spinlock_t *lck);
@@ -118,6 +118,6 @@ static inline void rte_power_monitor_sync(const volatile void *p,
  *   architecture-dependent.
  */
 __rte_experimental
-static inline void rte_power_pause(const uint64_t tsc_timestamp);
+void rte_power_pause(const uint64_t tsc_timestamp);
 
 #endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/ppc/include/rte_power_intrinsics.h +0 -40
index 4ed03d521f..c0e9ac279f 100644
@@ -13,46 +13,6 @@ extern "C" {
 
 #include "generic/rte_power_intrinsics.h"
 
-/**
- * This function is not supported on PPC64.
- */
-static inline void
-rte_power_monitor(const volatile void *p, const uint64_t expected_value,
-		const uint64_t value_mask, const uint64_t tsc_timestamp,
-		const uint8_t data_sz)
-{
-	RTE_SET_USED(p);
-	RTE_SET_USED(expected_value);
-	RTE_SET_USED(value_mask);
-	RTE_SET_USED(tsc_timestamp);
-	RTE_SET_USED(data_sz);
-}
-
-/**
- * This function is not supported on PPC64.
- */
-static inline void
-rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
-		const uint64_t value_mask, const uint64_t tsc_timestamp,
-		const uint8_t data_sz, rte_spinlock_t *lck)
-{
-	RTE_SET_USED(p);
-	RTE_SET_USED(expected_value);
-	RTE_SET_USED(value_mask);
-	RTE_SET_USED(tsc_timestamp);
-	RTE_SET_USED(lck);
-	RTE_SET_USED(data_sz);
-}
-
-/**
- * This function is not supported on PPC64.
- */
-static inline void
-rte_power_pause(const uint64_t tsc_timestamp)
-{
-	RTE_SET_USED(tsc_timestamp);
-}
-
 #ifdef __cplusplus
 }
 #endif
lib/librte_eal/ppc/meson.build +1 -0
index f4b6d95c42..43c46542fb 100644
@@ -7,4 +7,5 @@ sources += files(
 	'rte_cpuflags.c',
 	'rte_cycles.c',
 	'rte_hypervisor.c',
+	'rte_power_intrinsics.c',
 )
lib/librte_eal/ppc/rte_power_intrinsics.c new file +45 -0

45 lines not on this page · raw message

lib/librte_eal/version.map +3 -0
index b1db7ec795..32eceb8869 100644
@@ -405,6 +405,9 @@ EXPERIMENTAL {
 	rte_vect_set_max_simd_bitwidth;
 
 	# added in 21.02
+	rte_power_monitor;
+	rte_power_monitor_sync;
+	rte_power_pause;
 	rte_thread_tls_key_create;
 	rte_thread_tls_key_delete;
 	rte_thread_tls_value_get;
lib/librte_eal/x86/include/rte_power_intrinsics.h +0 -115

121 lines not on this page · raw message

lib/librte_eal/x86/meson.build +1 -0
index e78f29002e..dfd42dee0c 100644
@@ -8,4 +8,5 @@ sources += files(
 	'rte_cycles.c',
 	'rte_hypervisor.c',
 	'rte_spinlock.c',
+	'rte_power_intrinsics.c',
 )
lib/librte_eal/x86/rte_power_intrinsics.c new file +120 -0

120 lines not on this page · raw message

Signature · 1 line
2.25.1
#114 lore raw

PATCH v17 2/11 eal: avoid invalid API usage in power intrinsics

In reply to Anatoly Burakov

Currently, the API documentation mandates that if the user wants to use the power management intrinsics, they need to call the rte_cpu_get_intrinsics_support API and check support for specific intrinsics.

However, if the user does not do that, it is possible to get illegal instruction error because we're using raw instruction opcodes, which may or may not be supported at runtime.

Now that we have everything in a C file, we can check for support at startup and prevent the user from possibly encountering illegal instruction errors.

We also add return values to the API's as well, because why not.

---

Notes:
v16:
- Add return values and proper error handling to the API

v15:
- Remove accidental whitespace changes

v14:
- Replace uint8_t with bool

v14:
- Replace uint8_t with bool

 lib/librte_eal/arm/rte_power_intrinsics.c     | 12 +++-
 .../include/generic/rte_power_intrinsics.h    | 24 +++++--
 lib/librte_eal/ppc/rte_power_intrinsics.c     | 12 +++-
 lib/librte_eal/x86/rte_power_intrinsics.c     | 64 +++++++++++++++++--
 4 files changed, 94 insertions(+), 18 deletions(-)
lib/librte_eal/arm/rte_power_intrinsics.c +9 -3
index ab1f44f611..7e7552fa8a 100644
@@ -7,7 +7,7 @@
 /**
  * This function is not supported on ARM.
  */
-void
+int
 rte_power_monitor(const volatile void *p, const uint64_t expected_value,
 		const uint64_t value_mask, const uint64_t tsc_timestamp,
 		const uint8_t data_sz)
@@ -17,12 +17,14 @@ rte_power_monitor(const volatile void *p, const uint64_t expected_value,
 	RTE_SET_USED(value_mask);
 	RTE_SET_USED(tsc_timestamp);
 	RTE_SET_USED(data_sz);
+
+	return -ENOTSUP;
 }
 
 /**
  * This function is not supported on ARM.
  */
-void
+int
 rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
 		const uint64_t value_mask, const uint64_t tsc_timestamp,
 		const uint8_t data_sz, rte_spinlock_t *lck)
@@ -33,13 +35,17 @@ rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
 	RTE_SET_USED(tsc_timestamp);
 	RTE_SET_USED(lck);
 	RTE_SET_USED(data_sz);
+
+	return -ENOTSUP;
 }
 
 /**
  * This function is not supported on ARM.
  */
-void
+int
 rte_power_pause(const uint64_t tsc_timestamp)
 {
 	RTE_SET_USED(tsc_timestamp);
+
+	return -ENOTSUP;
 }
lib/librte_eal/include/generic/rte_power_intrinsics.h +18 -6
index 67977bd511..37e4ec0414 100644
@@ -34,7 +34,6 @@
  *
  * @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 p
  *   Address to monitor for changes.
@@ -50,9 +49,14 @@
  *   Data size (in bytes) that will be used to compare expected value with the
  *   memory address. Can be 1, 2, 4 or 8. Supplying any other value will lead
  *   to undefined result.
+ *
+ * @return
+ *   0 on success
+ *   -EINVAL on invalid parameters
+ *   -ENOTSUP if unsupported
  */
 __rte_experimental
-void rte_power_monitor(const volatile void *p,
+int rte_power_monitor(const volatile void *p,
 		const uint64_t expected_value, const uint64_t value_mask,
 		const uint64_t tsc_timestamp, const uint8_t data_sz);
 
@@ -75,7 +79,6 @@ void rte_power_monitor(const volatile void *p,
  *
  * @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 p
  *   Address to monitor for changes.
@@ -95,9 +98,14 @@ void rte_power_monitor(const volatile void *p,
  *   A spinlock that must be locked before entering the function, will be
  *   unlocked while the CPU is sleeping, and will be locked again once the CPU
  *   wakes up.
+ *
+ * @return
+ *   0 on success
+ *   -EINVAL on invalid parameters
+ *   -ENOTSUP if unsupported
  */
 __rte_experimental
-void rte_power_monitor_sync(const volatile void *p,
+int rte_power_monitor_sync(const volatile void *p,
 		const uint64_t expected_value, const uint64_t value_mask,
 		const uint64_t tsc_timestamp, const uint8_t data_sz,
 		rte_spinlock_t *lck);
@@ -111,13 +119,17 @@ void rte_power_monitor_sync(const volatile void *p,
  *
  * @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 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
-void rte_power_pause(const uint64_t tsc_timestamp);
+int rte_power_pause(const uint64_t tsc_timestamp);
 
 #endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/ppc/rte_power_intrinsics.c +9 -3
index 84340ca2a4..929e0611b0 100644
@@ -7,7 +7,7 @@
 /**
  * This function is not supported on PPC64.
  */
-void
+int
 rte_power_monitor(const volatile void *p, const uint64_t expected_value,
 		const uint64_t value_mask, const uint64_t tsc_timestamp,
 		const uint8_t data_sz)
@@ -17,12 +17,14 @@ rte_power_monitor(const volatile void *p, const uint64_t expected_value,
 	RTE_SET_USED(value_mask);
 	RTE_SET_USED(tsc_timestamp);
 	RTE_SET_USED(data_sz);
+
+	return -ENOTSUP;
 }
 
 /**
  * This function is not supported on PPC64.
  */
-void
+int
 rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
 		const uint64_t value_mask, const uint64_t tsc_timestamp,
 		const uint8_t data_sz, rte_spinlock_t *lck)
@@ -33,13 +35,17 @@ rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
 	RTE_SET_USED(tsc_timestamp);
 	RTE_SET_USED(lck);
 	RTE_SET_USED(data_sz);
+
+	return -ENOTSUP;
 }
 
 /**
  * This function is not supported on PPC64.
  */
-void
+int
 rte_power_pause(const uint64_t tsc_timestamp)
 {
 	RTE_SET_USED(tsc_timestamp);
+
+	return -ENOTSUP;
 }
lib/librte_eal/x86/rte_power_intrinsics.c +58 -6

142 lines not on this page · raw message

Signature · 1 line
2.25.1
#115 lore raw

PATCH v17 3/11 eal: change API of power intrinsics

In reply to Anatoly Burakov

Instead of passing around pointers and integers, collect everything into struct. This makes API design around these intrinsics much easier.

---

Notes:
v16:
- Add error handling

 drivers/event/dlb/dlb.c                       | 10 ++--
 drivers/event/dlb2/dlb2.c                     | 10 ++--
 lib/librte_eal/arm/rte_power_intrinsics.c     | 20 +++-----
 .../include/generic/rte_power_intrinsics.h    | 50 ++++++++-----------
 lib/librte_eal/ppc/rte_power_intrinsics.c     | 20 +++-----
 lib/librte_eal/x86/rte_power_intrinsics.c     | 42 +++++++++-------
 6 files changed, 70 insertions(+), 82 deletions(-)
drivers/event/dlb/dlb.c +7 -3
index 0c95c4793d..d2f2026291 100644
@@ -3161,6 +3161,7 @@ dlb_dequeue_wait(struct dlb_eventdev *dlb,
 		/* Interrupts not supported by PF PMD */
 		return 1;
 	} else if (dlb->umwait_allowed) {
+		struct rte_power_monitor_cond pmc;
 		volatile struct dlb_dequeue_qe *cq_base;
 		union {
 			uint64_t raw_qe[2];
@@ -3181,9 +3182,12 @@ dlb_dequeue_wait(struct dlb_eventdev *dlb,
 		else
 			expected_value = 0;
 
-		rte_power_monitor(monitor_addr, expected_value,
-				  qe_mask.raw_qe[1], timeout + start_ticks,
-				  sizeof(uint64_t));
+		pmc.addr = monitor_addr;
+		pmc.val = expected_value;
+		pmc.mask = qe_mask.raw_qe[1];
+		pmc.data_sz = sizeof(uint64_t);
+
+		rte_power_monitor(&pmc, timeout + start_ticks);
 
 		DLB_INC_STAT(ev_port->stats.traffic.rx_umonitor_umwait, 1);
 	} else {
drivers/event/dlb2/dlb2.c +7 -3
index 86724863f2..c9a8a02278 100644
@@ -2870,6 +2870,7 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2,
 	if (elapsed_ticks >= timeout) {
 		return 1;
 	} else if (dlb2->umwait_allowed) {
+		struct rte_power_monitor_cond pmc;
 		volatile struct dlb2_dequeue_qe *cq_base;
 		union {
 			uint64_t raw_qe[2];
@@ -2890,9 +2891,12 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2,
 		else
 			expected_value = 0;
 
-		rte_power_monitor(monitor_addr, expected_value,
-				  qe_mask.raw_qe[1], timeout + start_ticks,
-				  sizeof(uint64_t));
+		pmc.addr = monitor_addr;
+		pmc.val = expected_value;
+		pmc.mask = qe_mask.raw_qe[1];
+		pmc.data_sz = sizeof(uint64_t);
+
+		rte_power_monitor(&pmc, timeout + start_ticks);
 
 		DLB2_INC_STAT(ev_port->stats.traffic.rx_umonitor_umwait, 1);
 	} else {
lib/librte_eal/arm/rte_power_intrinsics.c +6 -14
index 7e7552fa8a..5f1caaf25b 100644
@@ -8,15 +8,11 @@
  * This function is not supported on ARM.
  */
 int
-rte_power_monitor(const volatile void *p, const uint64_t expected_value,
-		const uint64_t value_mask, const uint64_t tsc_timestamp,
-		const uint8_t data_sz)
+rte_power_monitor(const struct rte_power_monitor_cond *pmc,
+		const uint64_t tsc_timestamp)
 {
-	RTE_SET_USED(p);
-	RTE_SET_USED(expected_value);
-	RTE_SET_USED(value_mask);
+	RTE_SET_USED(pmc);
 	RTE_SET_USED(tsc_timestamp);
-	RTE_SET_USED(data_sz);
 
 	return -ENOTSUP;
 }
@@ -25,16 +21,12 @@ rte_power_monitor(const volatile void *p, const uint64_t expected_value,
  * This function is not supported on ARM.
  */
 int
-rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
-		const uint64_t value_mask, const uint64_t tsc_timestamp,
-		const uint8_t data_sz, rte_spinlock_t *lck)
+rte_power_monitor_sync(const struct rte_power_monitor_cond *pmc,
+		const uint64_t tsc_timestamp, rte_spinlock_t *lck)
 {
-	RTE_SET_USED(p);
-	RTE_SET_USED(expected_value);
-	RTE_SET_USED(value_mask);
+	RTE_SET_USED(pmc);
 	RTE_SET_USED(tsc_timestamp);
 	RTE_SET_USED(lck);
-	RTE_SET_USED(data_sz);
 
 	return -ENOTSUP;
 }
lib/librte_eal/include/generic/rte_power_intrinsics.h +20 -30

86 lines not on this page · raw message

lib/librte_eal/ppc/rte_power_intrinsics.c +6 -14
index 929e0611b0..5e5a1fff5a 100644
@@ -8,15 +8,11 @@
  * This function is not supported on PPC64.
  */
 int
-rte_power_monitor(const volatile void *p, const uint64_t expected_value,
-		const uint64_t value_mask, const uint64_t tsc_timestamp,
-		const uint8_t data_sz)
+rte_power_monitor(const struct rte_power_monitor_cond *pmc,
+		const uint64_t tsc_timestamp)
 {
-	RTE_SET_USED(p);
-	RTE_SET_USED(expected_value);
-	RTE_SET_USED(value_mask);
+	RTE_SET_USED(pmc);
 	RTE_SET_USED(tsc_timestamp);
-	RTE_SET_USED(data_sz);
 
 	return -ENOTSUP;
 }
@@ -25,16 +21,12 @@ rte_power_monitor(const volatile void *p, const uint64_t expected_value,
  * This function is not supported on PPC64.
  */
 int
-rte_power_monitor_sync(const volatile void *p, const uint64_t expected_value,
-		const uint64_t value_mask, const uint64_t tsc_timestamp,
-		const uint8_t data_sz, rte_spinlock_t *lck)
+rte_power_monitor_sync(const struct rte_power_monitor_cond *pmc,
+		const uint64_t tsc_timestamp, rte_spinlock_t *lck)
 {
-	RTE_SET_USED(p);
-	RTE_SET_USED(expected_value);
-	RTE_SET_USED(value_mask);
+	RTE_SET_USED(pmc);
 	RTE_SET_USED(tsc_timestamp);
 	RTE_SET_USED(lck);
-	RTE_SET_USED(data_sz);
 
 	return -ENOTSUP;
 }
lib/librte_eal/x86/rte_power_intrinsics.c +24 -18

84 lines not on this page · raw message

Signature · 1 line
2.25.1
#116 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

14/01/2021 15:46, Anatoly Burakov:

lib/librte_eal/include/generic/rte_power_intrinsics.h line 24

Quoted 4 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

lib/librte_eal/include/generic/rte_power_intrinsics.h line 30

Quoted 6 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +6 -0
+	                       **/
+	uint64_t mask;   /**< 64-bit mask to extract current value from addr */
+	uint8_t data_sz; /**< Data size (in bytes) that will be used to compare
+	                  *   expected value with the memory address. Can be 1,
+	                  *   2, 4, or 8. Supplying any other value will lead to
+	                  *   undefined result. */

Other parameters are not prefixed with "data_", so I think this field could be simply named "size".

Quoted 1 line

+};

I understand this struct is a direct translation of what existed in 20.11 as function parameters and comments.
If you agree, these comments could be addressed in a separate patch.

#117 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

Quoted 8 lines · Thomas Monjalon

14/01/2021 15:46, Anatoly Burakov:

lib/librte_eal/include/generic/rte_power_intrinsics.h line 24

Quoted 4 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Yes, if the mask is not set.

Quoted 10 lines

lib/librte_eal/include/generic/rte_power_intrinsics.h line 30

Quoted 7 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +6 -0
+	                       **/
+	uint64_t mask;   /**< 64-bit mask to extract current value from addr */
+	uint8_t data_sz; /**< Data size (in bytes) that will be used to compare
+	                  *   expected value with the memory address. Can be 1,
+	                  *   2, 4, or 8. Supplying any other value will lead to
+	                  *   undefined result. */

Other parameters are not prefixed with "data_", so I think this field could be simply named "size".

OK.

Quoted 7 lines
Quoted 2 lines

+};

I understand this struct is a direct translation of what existed in 20.11 as function parameters and comments.
If you agree, these comments could be addressed in a separate patch.

I'll be respinning anyway, so might as well do some quick fixups.

Signature · 2 lines
Thanks,
Anatoly
#118 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

19/01/2021 11:29, Burakov, Anatoly:

Quoted 11 lines · Thomas Monjalon
Quoted 8 lines

14/01/2021 15:46, Anatoly Burakov:

lib/librte_eal/include/generic/rte_power_intrinsics.h line 24

Quoted 4 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Yes, if the mask is not set.

If the mask is not set, the address is "read" anyway or it is only "watched" for any change?

Sorry the mechanism is really not clear to me.

#119 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

Quoted 11 lines · Thomas Monjalon

19/01/2021 11:29, Burakov, Anatoly:

Quoted 10 lines · Thomas Monjalon
Quoted 8 lines

14/01/2021 15:46, Anatoly Burakov:

lib/librte_eal/include/generic/rte_power_intrinsics.h line 24

Quoted 4 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Quoted 7 lines
Quoted 1 line

Yes, if the mask is not set.

If the mask is not set, the address is "read" anyway or it is only "watched" for any change?

Sorry the mechanism is really not clear to me.

The "value" is only used to avoid the sleep, i.e. to check if the write has already happened. We're waiting on *a write* rather than *a value*, so it's not equivalent to "wait until equal" call. It's more of a "sleep until something happens".

Signature · 2 lines
Thanks,
Anatoly
#120 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

19/01/2021 12:23, Burakov, Anatoly:

Quoted 17 lines · Thomas Monjalon
Quoted 16 lines

19/01/2021 11:29, Burakov, Anatoly:

Quoted 11 lines · Thomas Monjalon
Quoted 8 lines

14/01/2021 15:46, Anatoly Burakov:

lib/librte_eal/include/generic/rte_power_intrinsics.h line 24

Quoted 4 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Yes, if the mask is not set.

If the mask is not set, the address is "read" anyway or it is only "watched" for any change?

Quoted 7 lines
Quoted 2 lines

Sorry the mechanism is really not clear to me.

The "value" is only used to avoid the sleep, i.e. to check if the write has already happened. We're waiting on *a write* rather than *a value*, so it's not equivalent to "wait until equal" call. It's more of a "sleep until something happens".

Please make things explicit in doxygen.
The behaviour of each case should be explained crystal clear. Thanks

#121 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

Quoted 21 lines · Thomas Monjalon

19/01/2021 12:23, Burakov, Anatoly:

Quoted 20 lines · Thomas Monjalon
Quoted 18 lines

19/01/2021 11:29, Burakov, Anatoly:

Quoted 11 lines · Thomas Monjalon
Quoted 8 lines

14/01/2021 15:46, Anatoly Burakov:

lib/librte_eal/include/generic/rte_power_intrinsics.h line 24

Quoted 4 lines
lib/librte_eal/include/generic/rte_power_intrinsics.h +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Yes, if the mask is not set.

If the mask is not set, the address is "read" anyway or it is only "watched" for any change?

Sorry the mechanism is really not clear to me.

Quoted 10 lines
Quoted 4 lines

The "value" is only used to avoid the sleep, i.e. to check if the write has already happened. We're waiting on *a write* rather than *a value*, so it's not equivalent to "wait until equal" call. It's more of a "sleep until something happens".

Please make things explicit in doxygen.
The behaviour of each case should be explained crystal clear. Thanks

It is explained in the comments to rte_power_monitor() call. But OK, i'll add more clarification for the struct too.

Signature · 2 lines
Thanks,
Anatoly
#122 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

20/01/2021 11:32, Burakov, Anatoly:

Quoted 27 lines · Thomas Monjalon
Quoted 26 lines

19/01/2021 12:23, Burakov, Anatoly:

Quoted 24 lines · Thomas Monjalon
Quoted 11 lines

19/01/2021 11:29, Burakov, Anatoly:

Quoted 10 lines · Thomas Monjalon
Quoted 8 lines

14/01/2021 15:46, Anatoly Burakov:

Review

Quoted 4 lines
(quoted diff) +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Quoted 7 lines
Quoted 1 line

Yes, if the mask is not set.

If the mask is not set, the address is "read" anyway or it is only "watched" for any change?

Sorry the mechanism is really not clear to me.

The "value" is only used to avoid the sleep, i.e. to check if the write has already happened. We're waiting on *a write* rather than *a value*, so it's not equivalent to "wait until equal" call. It's more of a "sleep until something happens".

Quoted 6 lines
Quoted 3 lines

Please make things explicit in doxygen.
The behaviour of each case should be explained crystal clear. Thanks

It is explained in the comments to rte_power_monitor() call. But OK, i'll add more clarification for the struct too.

Please avoid the word "may" in API description.

This is what is explained in rte_power_monitor:
"
* Additionally, an expected 64-bit value and 64-bit mask are provided. If
* mask is non-zero, the current value pointed to by the p pointer will be
* checked against the expected value, and if they match, the entering of
* optimized power state may be aborted.
"

Can we replace "may" by "will"?

#123 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

Quoted 45 lines · Thomas Monjalon

20/01/2021 11:32, Burakov, Anatoly:

Quoted 27 lines · Thomas Monjalon
Quoted 26 lines

19/01/2021 12:23, Burakov, Anatoly:

Quoted 24 lines · Thomas Monjalon
Quoted 11 lines

19/01/2021 11:29, Burakov, Anatoly:

Quoted 10 lines · Thomas Monjalon
Quoted 8 lines

14/01/2021 15:46, Anatoly Burakov:

Review

Quoted 4 lines
(quoted diff) +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Quoted 7 lines
Quoted 1 line

Yes, if the mask is not set.

If the mask is not set, the address is "read" anyway or it is only "watched" for any change?

Sorry the mechanism is really not clear to me.

The "value" is only used to avoid the sleep, i.e. to check if the write has already happened. We're waiting on *a write* rather than *a value*, so it's not equivalent to "wait until equal" call. It's more of a "sleep until something happens".

Quoted 6 lines
Quoted 3 lines

Please make things explicit in doxygen.
The behaviour of each case should be explained crystal clear. Thanks

It is explained in the comments to rte_power_monitor() call. But OK, i'll add more clarification for the struct too.

Please avoid the word "may" in API description.

This is what is explained in rte_power_monitor:
"
* Additionally, an expected 64-bit value and 64-bit mask are provided. If
* mask is non-zero, the current value pointed to by the p pointer will be
* checked against the expected value, and if they match, the entering of
* optimized power state may be aborted.
"

Quoted 2 lines

Can we replace "may" by "will"?

Yep, we can. However, the "may" part was intended to leave some wiggle room for a different implementation, should the need arise, and i find "will" to be needlessly prescriptive. Frankly, i do not see the need for such a detailed description of what the API does under the hood, as long as it's clear what its effects are. The main purpose is waiting for a write. The mask is only used to check whether the expected write has already happened by the time we're calling the API. Whether the CPU then does or does not go to sleep is not really relevant IMO.

Signature · 2 lines
Thanks,
Anatoly
#124 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

20/01/2021 12:05, Burakov, Anatoly:

Quoted 49 lines · Thomas Monjalon
Quoted 45 lines

20/01/2021 11:32, Burakov, Anatoly:

Quoted 27 lines · Thomas Monjalon
Quoted 26 lines

19/01/2021 12:23, Burakov, Anatoly:

Quoted 24 lines · Thomas Monjalon
Quoted 11 lines

19/01/2021 11:29, Burakov, Anatoly:

Quoted 10 lines · Thomas Monjalon
Quoted 8 lines

14/01/2021 15:46, Anatoly Burakov:

Review

Quoted 4 lines
(quoted diff) +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Quoted 7 lines
Quoted 1 line

Yes, if the mask is not set.

If the mask is not set, the address is "read" anyway or it is only "watched" for any change?

Sorry the mechanism is really not clear to me.

The "value" is only used to avoid the sleep, i.e. to check if the write has already happened. We're waiting on *a write* rather than *a value*, so it's not equivalent to "wait until equal" call. It's more of a "sleep until something happens".

Quoted 6 lines
Quoted 3 lines

Please make things explicit in doxygen.
The behaviour of each case should be explained crystal clear. Thanks

It is explained in the comments to rte_power_monitor() call. But OK, i'll add more clarification for the struct too.

Please avoid the word "may" in API description.

This is what is explained in rte_power_monitor:
"
* Additionally, an expected 64-bit value and 64-bit mask are provided. If
* mask is non-zero, the current value pointed to by the p pointer will be
* checked against the expected value, and if they match, the entering of
* optimized power state may be aborted.
"

Quoted 2 lines

Can we replace "may" by "will"?

Quoted 8 lines

Yep, we can. However, the "may" part was intended to leave some wiggle room for a different implementation, should the need arise, and i find "will" to be needlessly prescriptive. Frankly, i do not see the need for such a detailed description of what the API does under the hood, as long as it's clear what its effects are. The main purpose is waiting for a write. The mask is only used to check whether the expected write has already happened by the time we're calling the API. Whether the CPU then does or does not go to sleep is not really relevant IMO.

I think it is relevant but I may be wrong.
Any other opinions?

#125 lore raw

Re: [dpdk-dev] [PATCH v17 03/11] eal: change API of power intrinsics

Quoted 59 lines · Thomas Monjalon

20/01/2021 12:05, Burakov, Anatoly:

Quoted 49 lines · Thomas Monjalon
Quoted 45 lines

20/01/2021 11:32, Burakov, Anatoly:

Quoted 27 lines · Thomas Monjalon
Quoted 26 lines

19/01/2021 12:23, Burakov, Anatoly:

Quoted 24 lines · Thomas Monjalon
Quoted 11 lines

19/01/2021 11:29, Burakov, Anatoly:

Quoted 10 lines · Thomas Monjalon
Quoted 8 lines

14/01/2021 15:46, Anatoly Burakov:

Review

Quoted 4 lines
(quoted diff) +4 -0
+struct rte_power_monitor_cond {
+	volatile void *addr;  /**< Address to monitor for changes */
+	uint64_t val;         /**< Before attempting the monitoring, the address
+	                       *   may be read and compared against this value.

"may" be read and compared?
Is there a case where there is no read and compare?

Quoted 7 lines
Quoted 1 line

Yes, if the mask is not set.

If the mask is not set, the address is "read" anyway or it is only "watched" for any change?

Sorry the mechanism is really not clear to me.

The "value" is only used to avoid the sleep, i.e. to check if the write has already happened. We're waiting on *a write* rather than *a value*, so it's not equivalent to "wait until equal" call. It's more of a "sleep until something happens".

Quoted 6 lines
Quoted 3 lines

Please make things explicit in doxygen.
The behaviour of each case should be explained crystal clear. Thanks

It is explained in the comments to rte_power_monitor() call. But OK, i'll add more clarification for the struct too.

Please avoid the word "may" in API description.

This is what is explained in rte_power_monitor:
"
* Additionally, an expected 64-bit value and 64-bit mask are provided. If
* mask is non-zero, the current value pointed to by the p pointer will be
* checked against the expected value, and if they match, the entering of
* optimized power state may be aborted.
"

Quoted 2 lines

Can we replace "may" by "will"?

Quoted 8 lines

Yep, we can. However, the "may" part was intended to leave some wiggle room for a different implementation, should the need arise, and i find "will" to be needlessly prescriptive. Frankly, i do not see the need for such a detailed description of what the API does under the hood, as long as it's clear what its effects are. The main purpose is waiting for a write. The mask is only used to check whether the expected write has already happened by the time we're calling the API. Whether the CPU then does or does not go to sleep is not really relevant IMO.

Quoted 3 lines

I think it is relevant but I may be wrong.
Any other opinions?

I have no objection in documenting that further, so i'll go ahead and do it :) It's just that i think it's not necessary to be *this* detailed about how the API does things.

Signature · 2 lines
Thanks,
Anatoly
#126 lore raw

PATCH v17 4/11 eal: remove sync version of power monitor

In reply to Anatoly Burakov

Currently, the "sync" version of power monitor intrinsic is supposed to be used for purposes of waking up a sleeping core. However, there are better ways to achieve the same result, so remove the unneeded function.

---
 lib/librte_eal/arm/rte_power_intrinsics.c     | 14 -----
 .../include/generic/rte_power_intrinsics.h    | 38 -------------
 lib/librte_eal/ppc/rte_power_intrinsics.c     | 14 -----
 lib/librte_eal/version.map                    |  1 -
 lib/librte_eal/x86/rte_power_intrinsics.c     | 54 -------------------
 5 files changed, 121 deletions(-)
lib/librte_eal/arm/rte_power_intrinsics.c +0 -14
index 5f1caaf25b..8d271dc0c1 100644
@@ -17,20 +17,6 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 	return -ENOTSUP;
 }
 
-/**
- * This function is not supported on ARM.
- */
-int
-rte_power_monitor_sync(const struct rte_power_monitor_cond *pmc,
-		const uint64_t tsc_timestamp, rte_spinlock_t *lck)
-{
-	RTE_SET_USED(pmc);
-	RTE_SET_USED(tsc_timestamp);
-	RTE_SET_USED(lck);
-
-	return -ENOTSUP;
-}
-
 /**
  * This function is not supported on ARM.
  */
lib/librte_eal/include/generic/rte_power_intrinsics.h +0 -38
index 3ad53068d5..85343bc9eb 100644
@@ -61,44 +61,6 @@ struct rte_power_monitor_cond {
 __rte_experimental
 int rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 		const uint64_t tsc_timestamp);
-/**
- * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
- *
- * Monitor specific address for changes. This will cause the CPU to enter an
- * architecture-defined optimized power state until either the specified
- * memory address is written to, a certain TSC timestamp is reached, or other
- * reasons cause the CPU to wake up.
- *
- * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
- * mask is non-zero, the current value pointed to by the `p` pointer will be
- * checked against the expected value, and if they match, the entering of
- * optimized power state may be aborted.
- *
- * This call will also lock a spinlock on entering sleep, and release it on
- * waking up the CPU.
- *
- * @warning It is responsibility of the user to check if this function is
- *   supported at runtime using `rte_cpu_get_intrinsics_support()` API call.
- *
- * @param pmc
- *   The monitoring condition structure.
- * @param tsc_timestamp
- *   Maximum TSC timestamp to wait for. Note that the wait behavior is
- *   architecture-dependent.
- * @param lck
- *   A spinlock that must be locked before entering the function, will be
- *   unlocked while the CPU is sleeping, and will be locked again once the CPU
- *   wakes up.
- *
- * @return
- *   0 on success
- *   -EINVAL on invalid parameters
- *   -ENOTSUP if unsupported
- */
-__rte_experimental
-int rte_power_monitor_sync(const struct rte_power_monitor_cond *pmc,
-		const uint64_t tsc_timestamp, rte_spinlock_t *lck);
 
 /**
  * @warning
lib/librte_eal/ppc/rte_power_intrinsics.c +0 -14
index 5e5a1fff5a..f7862ea324 100644
@@ -17,20 +17,6 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 	return -ENOTSUP;
 }
 
-/**
- * This function is not supported on PPC64.
- */
-int
-rte_power_monitor_sync(const struct rte_power_monitor_cond *pmc,
-		const uint64_t tsc_timestamp, rte_spinlock_t *lck)
-{
-	RTE_SET_USED(pmc);
-	RTE_SET_USED(tsc_timestamp);
-	RTE_SET_USED(lck);
-
-	return -ENOTSUP;
-}
-
 /**
  * This function is not supported on PPC64.
  */
lib/librte_eal/version.map +0 -1
index 32eceb8869..1fcd1d3bed 100644
@@ -406,7 +406,6 @@ EXPERIMENTAL {
 
 	# added in 21.02
 	rte_power_monitor;
-	rte_power_monitor_sync;
 	rte_power_pause;
 	rte_thread_tls_key_create;
 	rte_thread_tls_key_delete;
lib/librte_eal/x86/rte_power_intrinsics.c +0 -54

60 lines not on this page · raw message

Signature · 1 line
2.25.1
#127 lore raw

PATCH v17 5/11 eal: add monitor wakeup function

In reply to Anatoly Burakov

Now that we have everything in a C file, we can store the information about our sleep, and have a native mechanism to wake up the sleeping core. This mechanism would however only wake up a core that's sleeping while monitoring - waking up from rte_power_pause won't work.

---

Notes:
v17:
- Improve code readability with a goto (the horror!)
- Fix the compile issues for non-x86 archs

v16:
- Improve error handling
- Take a lock before UMONITOR

v13:
- Add comments around wakeup code to explain what it does
- Add lcore_id parameter checking to prevent buffer overrun

v15:
- Fix check in UMWAIT callback

v13:
- Rework the synchronization mechanism to not require locking
- Add more parameter checking
- Rework n_rx_queues access to not go through internal PMD structures and use public API instead

v13:
- Rework the synchronization mechanism to not require locking
- Add more parameter checking
- Rework n_rx_queues access to not go through internal PMD structures and use public API instead

 lib/librte_eal/arm/rte_power_intrinsics.c     | 11 +++
 .../include/generic/rte_power_intrinsics.h    | 16 ++++
 lib/librte_eal/ppc/rte_power_intrinsics.c     | 11 +++
 lib/librte_eal/version.map                    |  1 +
 lib/librte_eal/x86/rte_power_intrinsics.c     | 93 ++++++++++++++++++-
 5 files changed, 131 insertions(+), 1 deletion(-)
lib/librte_eal/arm/rte_power_intrinsics.c +11 -0
index 8d271dc0c1..e83f04072a 100644
@@ -27,3 +27,14 @@ rte_power_pause(const uint64_t tsc_timestamp)
 
 	return -ENOTSUP;
 }
+
+/**
+ * This function is not supported on ARM.
+ */
+int
+rte_power_monitor_wakeup(const unsigned int lcore_id)
+{
+	RTE_SET_USED(lcore_id);
+
+	return -ENOTSUP;
+}
lib/librte_eal/include/generic/rte_power_intrinsics.h +16 -0
index 85343bc9eb..6109d28faa 100644
@@ -62,6 +62,22 @@ __rte_experimental
 int rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 		const uint64_t tsc_timestamp);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Wake up a specific lcore that is in a power optimized state and is monitoring
+ * an address.
+ *
+ * @note This function will *not* wake up a core that is in a power optimized
+ *   state due to calling `rte_power_pause`.
+ *
+ * @param lcore_id
+ *   Lcore ID of a sleeping thread.
+ */
+__rte_experimental
+int rte_power_monitor_wakeup(const unsigned int lcore_id);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
lib/librte_eal/ppc/rte_power_intrinsics.c +11 -0
index f7862ea324..7fc9586da7 100644
@@ -27,3 +27,14 @@ rte_power_pause(const uint64_t tsc_timestamp)
 
 	return -ENOTSUP;
 }
+
+/**
+ * This function is not supported on PPC64.
+ */
+int
+rte_power_monitor_wakeup(const unsigned int lcore_id)
+{
+	RTE_SET_USED(lcore_id);
+
+	return -ENOTSUP;
+}
lib/librte_eal/version.map +1 -0
index 1fcd1d3bed..fce90a112f 100644
@@ -406,6 +406,7 @@ EXPERIMENTAL {
 
 	# added in 21.02
 	rte_power_monitor;
+	rte_power_monitor_wakeup;
 	rte_power_pause;
 	rte_thread_tls_key_create;
 	rte_thread_tls_key_delete;
lib/librte_eal/x86/rte_power_intrinsics.c +92 -1

140 lines not on this page · raw message

Signature · 1 line
2.25.1
#128 lore raw

PATCH v17 6/11 ethdev: add simple power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple API to allow getting the monitor conditions for power-optimized monitoring of the Rx queues from the PMD, as well as release notes information.

---

Notes:
v17:
- Added libabigail ignore for driver-only ABI in ethdev as suggested by David

v13:
- Fix typos and issues raised by Andrew

 devtools/libabigail.abignore           |  3 +++
 doc/guides/rel_notes/release_21_02.rst |  5 +++++
 lib/librte_ethdev/rte_ethdev.c         | 28 ++++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.h         | 25 +++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_driver.h  | 22 ++++++++++++++++++++
 lib/librte_ethdev/version.map          |  3 +++
 6 files changed, 86 insertions(+)
devtools/libabigail.abignore +3 -0
index 025f2c01bc..1c16114dce 100644
@@ -7,3 +7,6 @@
         symbol_version = INTERNAL
 [suppress_variable]
         symbol_version = INTERNAL
+; Explicit ignore for driver-only ABI
+[suppress_type]
+        name = eth_dev_ops
doc/guides/rel_notes/release_21_02.rst +5 -0
index 706cbf8f0c..ec9958a141 100644
@@ -55,6 +55,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **ethdev: added new API for PMD power management**
+
+  * ``rte_eth_get_monitor_addr()``, to be used in conjunction with
+    ``rte_power_monitor()`` to enable automatic power management for PMD's.
+
 
 Removed Items
 -------------
lib/librte_ethdev/rte_ethdev.c +28 -0
index 17ddacc78d..e19dbd838b 100644
@@ -5115,6 +5115,34 @@ rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 		       dev->dev_ops->tx_burst_mode_get(dev, queue_id, mode));
 }
 
+int
+rte_eth_get_monitor_addr(uint16_t port_id, uint16_t queue_id,
+		struct rte_power_monitor_cond *pmc)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+	dev = &rte_eth_devices[port_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->get_monitor_addr, -ENOTSUP);
+
+	if (queue_id >= dev->data->nb_rx_queues) {
+		RTE_ETHDEV_LOG(ERR, "Invalid Rx queue_id=%u\n", queue_id);
+		return -EINVAL;
+	}
+
+	if (pmc == NULL) {
+		RTE_ETHDEV_LOG(ERR, "Invalid power monitor condition=%p\n",
+				pmc);
+		return -EINVAL;
+	}
+
+	return eth_err(port_id,
+		dev->dev_ops->get_monitor_addr(dev->data->rx_queues[queue_id],
+			pmc));
+}
+
 int
 rte_eth_dev_set_mc_addr_list(uint16_t port_id,
 			     struct rte_ether_addr *mc_addr_set,
lib/librte_ethdev/rte_ethdev.h +25 -0
index f5f8919186..ca0f91312e 100644
@@ -157,6 +157,7 @@ extern "C" {
 #include <rte_common.h>
 #include <rte_config.h>
 #include <rte_ether.h>
+#include <rte_power_intrinsics.h>
 
 #include "rte_ethdev_trace_fp.h"
 #include "rte_dev_info.h"
@@ -4334,6 +4335,30 @@ __rte_experimental
 int rte_eth_tx_burst_mode_get(uint16_t port_id, uint16_t queue_id,
 	struct rte_eth_burst_mode *mode);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Retrieve the monitor condition for a given receive queue.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The Rx queue on the Ethernet device for which information
+ *   will be retrieved.
+ * @param pmc
+ *   The pointer point to power-optimized monitoring condition structure.
+ *
+ * @return
+ *   - 0: Success.
+ *   -ENOTSUP: Operation not supported.
+ *   -EINVAL: Invalid parameters.
+ *   -ENODEV: Invalid port ID.
+ */
+__rte_experimental
+int rte_eth_get_monitor_addr(uint16_t port_id, uint16_t queue_id,
+		struct rte_power_monitor_cond *pmc);
+
 /**
  * Retrieve device registers and register attributes (number of registers and
  * register size)
lib/librte_ethdev/rte_ethdev_driver.h +22 -0
index 0eacfd8425..3b3b0ec1a0 100644
@@ -763,6 +763,26 @@ typedef int (*eth_hairpin_queue_peer_unbind_t)
 	(struct rte_eth_dev *dev, uint16_t cur_queue, uint32_t direction);
 /**< @internal Unbind peer queue from the current queue. */
 
+/**
+ * @internal
+ * Get address of memory location whose contents will change whenever there is
+ * new data to be received on an Rx queue.
+ *
+ * @param rxq
+ *   Ethdev queue pointer.
+ * @param pmc
+ *   The pointer to power-optimized monitoring condition structure.
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success
+ * @retval -EINVAL
+ *   Invalid parameters
+ */
+typedef int (*eth_get_monitor_addr_t)(void *rxq,
+		struct rte_power_monitor_cond *pmc);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -917,6 +937,8 @@ struct eth_dev_ops {
 	/**< Set up the connection between the pair of hairpin queues. */
 	eth_hairpin_queue_peer_unbind_t hairpin_queue_peer_unbind;
 	/**< Disconnect the hairpin queues of a pair from each other. */
+	eth_get_monitor_addr_t get_monitor_addr;
+	/**< Get power monitoring condition for Rx queue. */
 };
 
 /**
lib/librte_ethdev/version.map +3 -0
index d3f5410806..a124e1e370 100644
@@ -240,6 +240,9 @@ EXPERIMENTAL {
 	rte_flow_get_restore_info;
 	rte_flow_tunnel_action_decap_release;
 	rte_flow_tunnel_item_release;
+
+	# added in 21.02
+	rte_eth_get_monitor_addr;
 };
 
 INTERNAL {
Signature · 1 line
2.25.1
#129 lore raw

PATCH v17 7/11 power: add PMD power management API and callback

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. TPAUSE/Pause instruction

This method uses the pause (or TPAUSE, if available) instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v17:
- Added memory barriers suggested by Konstantin
- Removed the BUSY state

 doc/guides/prog_guide/power_man.rst    |  44 +++
 doc/guides/rel_notes/release_21_02.rst |  10 +
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c  | 364 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  90 ++++++
 lib/librte_power/version.map           |   5 +
 6 files changed, 516 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
doc/guides/prog_guide/power_man.rst +44 -0
index 0a3755a901..02280dd689 100644
@@ -192,6 +192,47 @@ User Cases
 ----------
 The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
 
+PMD Power Management API
+------------------------
+
+Abstract
+~~~~~~~~
+Existing power management mechanisms require developers to change application
+design or change code to make use of it. The PMD power management API provides a
+convenient alternative by utilizing Ethernet PMD RX callbacks, and triggering
+power saving whenever empty poll count reaches a certain number.
+
+  * 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 existing ``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).
+
+API Overview for PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core
+
 References
 ----------
 
@@ -200,3 +241,6 @@ References
 
 *   The :doc:`../sample_app_ug/vm_power_management`
     chapter in the :doc:`../sample_app_ug/index` section.
+
+*   The :doc:`../sample_app_ug/rxtx_callbacks`
+    chapter in the :doc:`../sample_app_ug/index` section.
doc/guides/rel_notes/release_21_02.rst +10 -0
index ec9958a141..9cd8214e2d 100644
@@ -60,6 +60,16 @@ New Features
   * ``rte_eth_get_monitor_addr()``, to be used in conjunction with
     ``rte_power_monitor()`` to enable automatic power management for PMD's.
 
+* **Add PMD power management helper API**
+
+  A new helper API has been added to make using Ethernet PMD power management
+  easier for the user: ``rte_power_pmd_mgmt_queue_enable()``. Three power
+  management schemes are supported initially:
+
+  * Power saving based on UMWAIT instruction (x86 only)
+  * Power saving based on ``rte_pause()`` (generic) or TPAUSE instruction (x86 only)
+  * Power saving based on frequency scaling through the ``librte_power`` library
+
 
 Removed Items
 -------------
lib/librte_power/meson.build +3 -2
index 4b4cf1b90b..51a471b669 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer' ,'ethdev']
lib/librte_power/rte_power_pmd_mgmt.c new file +364 -0

364 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.h new file +90 -0

90 lines not on this page · raw message

lib/librte_power/version.map +5 -0
index 69ca9af616..61996b4d11 100644
@@ -34,4 +34,9 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+
+	# added in 21.02
+	rte_power_pmd_mgmt_queue_enable;
+	rte_power_pmd_mgmt_queue_disable;
+
 };
Signature · 1 line
2.25.1
Acked-by on v17 7/11
#130 lore raw

Re: [dpdk-dev] [PATCH v17 07/11] power: add PMD power management API and callback

Hi Anatoly,

Quoted 45 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. TPAUSE/Pause instruction

This method uses the pause (or TPAUSE, if available) instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v17:
- Added memory barriers suggested by Konstantin
- Removed the BUSY state

  doc/guides/prog_guide/power_man.rst    |  44 +++
  doc/guides/rel_notes/release_21_02.rst |  10 +
  lib/librte_power/meson.build           |   5 +-
  lib/librte_power/rte_power_pmd_mgmt.c  | 364 +++++++++++++++++++++++++
  lib/librte_power/rte_power_pmd_mgmt.h  |  90 ++++++
  lib/librte_power/version.map           |   5 +
  6 files changed, 516 insertions(+), 2 deletions(-)
Quoted 3 lines

create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h

#131 lore raw

v18 cover Add PMD power management

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

To achieve power savings, there is a very simple mechanism used: we're counting empty polls, and if a certain threshold is reached, we employ one of the suggested power management schemes automatically, from within a Rx callback inside the PMD. Once there's traffic again, the empty poll counter is reset.

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

v18:
- Rebase on top of latest main
- Address review comments by Thomas

v17:
- Added exception for ethdev driver-only ABI
- Added memory barriers for monitor/wakeup (Konstantin)
- Fixed compiled issues on non-x86 platforms (hopefully!)

v16:
- Implemented Konstantin's suggestions and comments
- Added return values to the API

v15:
- Fixed incorrect check in UMWAIT callback
- Fixed accidental whitespace changes

v14:
- Fixed ARM/PPC builds
- Addressed various review comments

v13:
- Reworked the librte_power code to require less locking and handle invalid parameters better
- Fix numerous rebase errors present in v12

v12:
- Rebase on top of 21.02
- Rework of power intrinsics code

Liang Ma (2):
power: add PMD power management API and callback examples/l3fwd-power: enable PMD power mgmt

 doc/guides/prog_guide/power_man.rst           |  41 ++
 doc/guides/rel_notes/release_21_02.rst        |  10 +
 .../sample_app_ug/l3_forward_power_man.rst    |  35 ++
 examples/l3fwd-power/main.c                   |  90 ++++-
 lib/librte_power/meson.build                  |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c         | 365 ++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h         |  91 +++++
 lib/librte_power/version.map                  |   5 +
 8 files changed, 638 insertions(+), 4 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
Signature · 1 line
2.25.1
#132 lore raw

PATCH v18 1/2 power: add PMD power management API and callback

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. TPAUSE/Pause instruction

This method uses the pause (or TPAUSE, if available) instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v17:
- Added memory barriers suggested by Konstantin
- Removed the BUSY state

 doc/guides/prog_guide/power_man.rst    |  41 +++
 doc/guides/rel_notes/release_21_02.rst |  10 +
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c  | 365 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  91 ++++++
 lib/librte_power/version.map           |   5 +
 6 files changed, 515 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
doc/guides/prog_guide/power_man.rst +41 -0
index 0a3755a901..f36ba0027c 100644
@@ -192,6 +192,47 @@ User Cases
 ----------
 The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
 
+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 existing ``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).
+
+API Overview for Ethernet PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core.
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core.
+
 References
 ----------
 
doc/guides/rel_notes/release_21_02.rst +10 -0
index be5ea4370c..1988960b76 100644
@@ -76,6 +76,16 @@ New Features
 
   * Added inner UDP/IPv4 support for VXLAN IPv4 GSO.
 
+* **Added Ethernet PMD power management helper API.**
+
+  A new helper API has been added to make using Ethernet PMD power management
+  easier for the user: ``rte_power_ethdev_pmgmt_queue_enable()``. Three power
+  management schemes are supported initially:
+
+  * Power saving based on UMWAIT instruction (x86 only)
+  * Power saving based on ``rte_pause()`` (generic) or TPAUSE instruction (x86 only)
+  * Power saving based on frequency scaling through the ``librte_power`` library
+
 
 Removed Items
 -------------
lib/librte_power/meson.build +3 -2
index 4b4cf1b90b..e5a11cb834 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer', 'ethdev']
lib/librte_power/rte_power_pmd_mgmt.c new file +365 -0

365 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.h new file +91 -0

91 lines not on this page · raw message

lib/librte_power/version.map +5 -0
index 69ca9af616..f38a380212 100644
@@ -34,4 +34,9 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+
+	# added in 21.02
+	rte_power_ethdev_pmgmt_queue_disable;
+	rte_power_ethdev_pmgmt_queue_enable;
+
 };
Signature · 1 line
2.25.1
#133 lore raw

PATCH v18 2/2 examples/l3fwd-power: enable PMD power mgmt

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Notes:
v12:
- Allow selecting PMD power management scheme from command-line
- Enforce 1 core 1 queue rule

 .../sample_app_ug/l3_forward_power_man.rst    | 35 ++++++++
 examples/l3fwd-power/main.c                   | 90 ++++++++++++++++++-
 2 files changed, 123 insertions(+), 2 deletions(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +35 -0
index 85a78a5c1e..aaa9367fae 100644
@@ -109,6 +109,8 @@ where,
 
 *   --telemetry:  Telemetry mode.
 
+*   --pmd-mgmt: PMD power management mode.
+
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
 
@@ -456,3 +458,36 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./build/examples/dpdk-l3fwd-power -l 1-3 --  --pmd-mgmt -p 0x0f --config="(0,0,2),(0,1,3)"
+
+PMD Power Management Mode
+-------------------------
+There is also a traffic-aware operating mode that, instead of using explicit
+power management, will use automatic PMD power management. This mode is limited
+to one queue per core, and has three available power management schemes:
+
+* ``monitor`` - this will use ``rte_power_monitor()`` function to enter a
+  power-optimized state (subject to platform support).
+
+* ``pause`` - this will use ``rte_power_pause()`` or ``rte_pause()`` to avoid
+  busy looping when there is no traffic.
+
+* ``scale`` - this will use frequency scaling routines available in the
+  ``librte_power`` library.
+
+See :doc:`Power Management<../prog_guide/power_man>` chapter in the DPDK
+Programmer's Guide for more details on PMD power management.
+
+.. code-block:: console
+
+        ./<build_dir>/examples/dpdk-l3fwd-power -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)" --pmd-mgmt=scale
examples/l3fwd-power/main.c +88 -2

166 lines not on this page · raw message

Signature · 1 line
2.25.1
#134 lore raw

v19 cover Add PMD power management

In reply to Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

To achieve power savings, there is a very simple mechanism used: we're counting empty polls, and if a certain threshold is reached, we employ one of the suggested power management schemes automatically, from within a Rx callback inside the PMD. Once there's traffic again, the empty poll counter is reset.

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

v19:
- Renamed "data_sz" to "size" and clarified struct comments
- Clarified documentation around rte_power_monitor/pause API

v18:
- Rebase on top of latest main
- Address review comments by Thomas

v17:
- Added exception for ethdev driver-only ABI
- Added memory barriers for monitor/wakeup (Konstantin)
- Fixed compiled issues on non-x86 platforms (hopefully!)

v16:
- Implemented Konstantin's suggestions and comments
- Added return values to the API

v15:
- Fixed incorrect check in UMWAIT callback
- Fixed accidental whitespace changes

v14:
- Fixed ARM/PPC builds
- Addressed various review comments

v13:
- Reworked the librte_power code to require less locking and handle invalid parameters better
- Fix numerous rebase errors present in v12

v12:
- Rebase on top of 21.02
- Rework of power intrinsics code

Anatoly Burakov (2):
eal: rename power monitor condition member
eal: improve comments around power monitoring API

Liang Ma (2):
power: add PMD power management API and callback examples/l3fwd-power: enable PMD power mgmt

 doc/guides/prog_guide/power_man.rst           |  41 ++
 doc/guides/rel_notes/release_21_02.rst        |  10 +
 .../sample_app_ug/l3_forward_power_man.rst    |  35 ++
 drivers/event/dlb/dlb.c                       |   2 +-
 drivers/event/dlb2/dlb2.c                     |   2 +-
 drivers/net/i40e/i40e_rxtx.c                  |   2 +-
 drivers/net/ice/ice_rxtx.c                    |   2 +-
 drivers/net/ixgbe/ixgbe_rxtx.c                |   2 +-
 examples/l3fwd-power/main.c                   |  90 ++++-
 .../include/generic/rte_power_intrinsics.h    |  39 +-
 lib/librte_eal/x86/rte_power_intrinsics.c     |   4 +-
 lib/librte_power/meson.build                  |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c         | 365 ++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h         |  91 +++++
 lib/librte_power/version.map                  |   5 +
 15 files changed, 669 insertions(+), 26 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
Signature · 1 line
2.25.1
#135 lore raw

PATCH v19 1/4 eal: rename power monitor condition member

The data_sz name is fine, but it looks out of place because nothing else has "data" prefix in that structure. Rename it to "size", as well as add more clarity to the comments around each struct member.

Fixes 6a17919b0e2a ("eal: change power intrinsics API")
---
 drivers/event/dlb/dlb.c                       |  2 +-
 drivers/event/dlb2/dlb2.c                     |  2 +-
 drivers/net/i40e/i40e_rxtx.c                  |  2 +-
 drivers/net/ice/ice_rxtx.c                    |  2 +-
 drivers/net/ixgbe/ixgbe_rxtx.c                |  2 +-
 .../include/generic/rte_power_intrinsics.h    | 19 +++++++++++--------
 lib/librte_eal/x86/rte_power_intrinsics.c     |  4 ++--
 7 files changed, 18 insertions(+), 15 deletions(-)
drivers/event/dlb/dlb.c +1 -1
index d2f2026291..a65f70882f 100644
@@ -3185,7 +3185,7 @@ dlb_dequeue_wait(struct dlb_eventdev *dlb,
 		pmc.addr = monitor_addr;
 		pmc.val = expected_value;
 		pmc.mask = qe_mask.raw_qe[1];
-		pmc.data_sz = sizeof(uint64_t);
+		pmc.size = sizeof(uint64_t);
 
 		rte_power_monitor(&pmc, timeout + start_ticks);
 
drivers/event/dlb2/dlb2.c +1 -1
index c9a8a02278..5782960158 100644
@@ -2894,7 +2894,7 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2,
 		pmc.addr = monitor_addr;
 		pmc.val = expected_value;
 		pmc.mask = qe_mask.raw_qe[1];
-		pmc.data_sz = sizeof(uint64_t);
+		pmc.size = sizeof(uint64_t);
 
 		rte_power_monitor(&pmc, timeout + start_ticks);
 
drivers/net/i40e/i40e_rxtx.c +1 -1
index 0b4220fc9c..d8e9db55d8 100644
@@ -92,7 +92,7 @@ i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 	pmc->mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
 
 	/* registers are 64-bit */
-	pmc->data_sz = sizeof(uint64_t);
+	pmc->size = sizeof(uint64_t);
 
 	return 0;
 }
drivers/net/ice/ice_rxtx.c +1 -1
index 066651dc48..5909e3707b 100644
@@ -46,7 +46,7 @@ ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 	pmc->mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
 
 	/* register is 16-bit */
-	pmc->data_sz = sizeof(uint16_t);
+	pmc->size = sizeof(uint16_t);
 
 	return 0;
 }
drivers/net/ixgbe/ixgbe_rxtx.c +1 -1
index cc8f70e6dd..c0305a8238 100644
@@ -1389,7 +1389,7 @@ ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 	pmc->mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
 
 	/* the registers are 32-bit */
-	pmc->data_sz = sizeof(uint32_t);
+	pmc->size = sizeof(uint32_t);
 
 	return 0;
 }
lib/librte_eal/include/generic/rte_power_intrinsics.h +11 -8
index 6109d28faa..5960c48c80 100644
@@ -20,14 +20,17 @@
 
 struct rte_power_monitor_cond {
 	volatile void *addr;  /**< Address to monitor for changes */
-	uint64_t val;         /**< Before attempting the monitoring, the address
-	                       *   may be read and compared against this value.
-	                       **/
-	uint64_t mask;   /**< 64-bit mask to extract current value from addr */
-	uint8_t data_sz; /**< Data size (in bytes) that will be used to compare
-	                  *   expected value with the memory address. Can be 1,
-	                  *   2, 4, or 8. Supplying any other value will lead to
-	                  *   undefined result. */
+	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
+	                  *   monitored memory location (`addr`). Can be 1, 2,
+	                  *   4, or 8. Supplying any other value will result in
+	                  *   an error.
+	                  */
 };
 
 /**
lib/librte_eal/x86/rte_power_intrinsics.c +2 -2
index af3ae3237c..39ea9fdecd 100644
@@ -88,7 +88,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 	if (pmc == NULL)
 		return -EINVAL;
 
-	if (__check_val_size(pmc->data_sz) < 0)
+	if (__check_val_size(pmc->size) < 0)
 		return -EINVAL;
 
 	s = &wait_status[lcore_id];
@@ -113,7 +113,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 	/* 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->data_sz);
+				pmc->addr, pmc->size);
 		const uint64_t masked = cur_value & pmc->mask;
 
 		/* if the masked value is already matching, abort */
Signature · 1 line
2.25.1
#136 lore raw

PATCH v19 2/4 eal: improve comments around power monitoring API

In reply to Anatoly Burakov

Currently, the API documentation is ambiguous as to what happens when certain conditions are met. Document the behavior explicitly, as well as fix some typos and outdated comments.

Fixes 6a17919b0e2a ("eal: change power intrinsics API")
---
 .../include/generic/rte_power_intrinsics.h    | 20 ++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
lib/librte_eal/include/generic/rte_power_intrinsics.h +13 -7
index 5960c48c80..dddca3d41c 100644
@@ -35,17 +35,20 @@ struct rte_power_monitor_cond {
 
 /**
  * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
+ * @b EXPERIMENTAL: this API may change without prior notice.
  *
  * Monitor specific address for changes. This will cause the CPU to enter an
  * architecture-defined optimized power state until either the specified
  * memory address is written to, a certain TSC timestamp is reached, or other
  * reasons cause the CPU to wake up.
  *
- * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
- * mask is non-zero, the current value pointed to by the `p` pointer will be
- * checked against the expected value, and if they match, the entering of
- * optimized power state may be aborted.
+ * Additionally, an expected value (`pmc->val`), mask (`pmc->mask`), and data
+ * size (`pmc->size`) are provided in the `pmc` power monitoring condition. If
+ * the mask is non-zero, the current value pointed to by the `pmc->addr` pointer
+ * will be read and compared against the expected value, and if they match, the
+ * entering of optimized power state will be aborted. This is intended to
+ * prevent the CPU from entering optimized power state and waiting on a write
+ * that has already happened by the time this API is called.
  *
  * @warning It is responsibility of the user to check if this function is
  *   supported at runtime using `rte_cpu_get_intrinsics_support()` API call.
@@ -67,11 +70,14 @@ int rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 
 /**
  * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
+ * @b EXPERIMENTAL: this API may change without prior notice.
  *
  * Wake up a specific lcore that is in a power optimized state and is monitoring
  * an address.
  *
+ * @note It is safe to call this function if the lcore in question is not
+ *   sleeping. The function will have no effect.
+ *
  * @note This function will *not* wake up a core that is in a power optimized
  *   state due to calling `rte_power_pause`.
  *
@@ -83,7 +89,7 @@ int rte_power_monitor_wakeup(const unsigned int lcore_id);
 
 /**
  * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
+ * @b EXPERIMENTAL: this API may change without prior notice.
  *
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
Signature · 1 line
2.25.1
#137 lore raw

PATCH v19 3/4 power: add PMD power management API and callback

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. TPAUSE/Pause instruction

This method uses the pause (or TPAUSE, if available) instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v17:
- Added memory barriers suggested by Konstantin
- Removed the BUSY state

 doc/guides/prog_guide/power_man.rst    |  41 +++
 doc/guides/rel_notes/release_21_02.rst |  10 +
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c  | 365 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  91 ++++++
 lib/librte_power/version.map           |   5 +
 6 files changed, 515 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
doc/guides/prog_guide/power_man.rst +41 -0
index 0a3755a901..f36ba0027c 100644
@@ -192,6 +192,47 @@ User Cases
 ----------
 The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
 
+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 existing ``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).
+
+API Overview for Ethernet PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core.
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core.
+
 References
 ----------
 
doc/guides/rel_notes/release_21_02.rst +10 -0
index be5ea4370c..1988960b76 100644
@@ -76,6 +76,16 @@ New Features
 
   * Added inner UDP/IPv4 support for VXLAN IPv4 GSO.
 
+* **Added Ethernet PMD power management helper API.**
+
+  A new helper API has been added to make using Ethernet PMD power management
+  easier for the user: ``rte_power_ethdev_pmgmt_queue_enable()``. Three power
+  management schemes are supported initially:
+
+  * Power saving based on UMWAIT instruction (x86 only)
+  * Power saving based on ``rte_pause()`` (generic) or TPAUSE instruction (x86 only)
+  * Power saving based on frequency scaling through the ``librte_power`` library
+
 
 Removed Items
 -------------
lib/librte_power/meson.build +3 -2
index 4b4cf1b90b..e5a11cb834 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer', 'ethdev']
lib/librte_power/rte_power_pmd_mgmt.c new file +365 -0

365 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.h new file +91 -0

91 lines not on this page · raw message

lib/librte_power/version.map +5 -0
index 69ca9af616..f38a380212 100644
@@ -34,4 +34,9 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+
+	# added in 21.02
+	rte_power_ethdev_pmgmt_queue_disable;
+	rte_power_ethdev_pmgmt_queue_enable;
+
 };
Signature · 1 line
2.25.1
#138 lore raw

PATCH v19 4/4 examples/l3fwd-power: enable PMD power mgmt

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Notes:
v12:
- Allow selecting PMD power management scheme from command-line
- Enforce 1 core 1 queue rule

 .../sample_app_ug/l3_forward_power_man.rst    | 35 ++++++++
 examples/l3fwd-power/main.c                   | 90 ++++++++++++++++++-
 2 files changed, 123 insertions(+), 2 deletions(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +35 -0
index 85a78a5c1e..aaa9367fae 100644
@@ -109,6 +109,8 @@ where,
 
 *   --telemetry:  Telemetry mode.
 
+*   --pmd-mgmt: PMD power management mode.
+
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
 
@@ -456,3 +458,36 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./build/examples/dpdk-l3fwd-power -l 1-3 --  --pmd-mgmt -p 0x0f --config="(0,0,2),(0,1,3)"
+
+PMD Power Management Mode
+-------------------------
+There is also a traffic-aware operating mode that, instead of using explicit
+power management, will use automatic PMD power management. This mode is limited
+to one queue per core, and has three available power management schemes:
+
+* ``monitor`` - this will use ``rte_power_monitor()`` function to enter a
+  power-optimized state (subject to platform support).
+
+* ``pause`` - this will use ``rte_power_pause()`` or ``rte_pause()`` to avoid
+  busy looping when there is no traffic.
+
+* ``scale`` - this will use frequency scaling routines available in the
+  ``librte_power`` library.
+
+See :doc:`Power Management<../prog_guide/power_man>` chapter in the DPDK
+Programmer's Guide for more details on PMD power management.
+
+.. code-block:: console
+
+        ./<build_dir>/examples/dpdk-l3fwd-power -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)" --pmd-mgmt=scale
examples/l3fwd-power/main.c +88 -2

166 lines not on this page · raw message

Signature · 1 line
2.25.1
#139 lore raw

v20 cover Add PMD power management

In reply to Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

To achieve power savings, there is a very simple mechanism used: we're counting empty polls, and if a certain threshold is reached, we employ one of the suggested power management schemes automatically, from within a Rx callback inside the PMD. Once there's traffic again, the empty poll counter is reset.

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

v20:
- Moved callback removal before port close

v19:
- Renamed "data_sz" to "size" and clarified struct comments
- Clarified documentation around rte_power_monitor/pause API

v18:
- Rebase on top of latest main
- Address review comments by Thomas

v17:
- Added exception for ethdev driver-only ABI
- Added memory barriers for monitor/wakeup (Konstantin)
- Fixed compiled issues on non-x86 platforms (hopefully!)

v16:
- Implemented Konstantin's suggestions and comments
- Added return values to the API

v15:
- Fixed incorrect check in UMWAIT callback
- Fixed accidental whitespace changes

v14:
- Fixed ARM/PPC builds
- Addressed various review comments

v13:
- Reworked the librte_power code to require less locking and handle invalid parameters better
- Fix numerous rebase errors present in v12

v12:
- Rebase on top of 21.02
- Rework of power intrinsics code

Anatoly Burakov (2):
eal: rename power monitor condition member
eal: improve comments around power monitoring API

Liang Ma (2):
power: add PMD power management API and callback examples/l3fwd-power: enable PMD power mgmt

 doc/guides/prog_guide/power_man.rst           |  41 ++
 doc/guides/rel_notes/release_21_02.rst        |  10 +
 .../sample_app_ug/l3_forward_power_man.rst    |  35 ++
 drivers/event/dlb/dlb.c                       |   2 +-
 drivers/event/dlb2/dlb2.c                     |   2 +-
 drivers/net/i40e/i40e_rxtx.c                  |   2 +-
 drivers/net/ice/ice_rxtx.c                    |   2 +-
 drivers/net/ixgbe/ixgbe_rxtx.c                |   2 +-
 examples/l3fwd-power/main.c                   |  90 ++++-
 .../include/generic/rte_power_intrinsics.h    |  39 +-
 lib/librte_eal/x86/rte_power_intrinsics.c     |   4 +-
 lib/librte_power/meson.build                  |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c         | 365 ++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h         |  91 +++++
 lib/librte_power/version.map                  |   5 +
 15 files changed, 669 insertions(+), 26 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
Signature · 1 line
2.25.1
#140 lore raw

PATCH v20 1/4 eal: rename power monitor condition member

The data_sz name is fine, but it looks out of place because nothing else has "data" prefix in that structure. Rename it to "size", as well as add more clarity to the comments around each struct member.

Fixes 6a17919b0e2a ("eal: change power intrinsics API")
---
 drivers/event/dlb/dlb.c                       |  2 +-
 drivers/event/dlb2/dlb2.c                     |  2 +-
 drivers/net/i40e/i40e_rxtx.c                  |  2 +-
 drivers/net/ice/ice_rxtx.c                    |  2 +-
 drivers/net/ixgbe/ixgbe_rxtx.c                |  2 +-
 .../include/generic/rte_power_intrinsics.h    | 19 +++++++++++--------
 lib/librte_eal/x86/rte_power_intrinsics.c     |  4 ++--
 7 files changed, 18 insertions(+), 15 deletions(-)
drivers/event/dlb/dlb.c +1 -1
index d2f2026291..a65f70882f 100644
@@ -3185,7 +3185,7 @@ dlb_dequeue_wait(struct dlb_eventdev *dlb,
 		pmc.addr = monitor_addr;
 		pmc.val = expected_value;
 		pmc.mask = qe_mask.raw_qe[1];
-		pmc.data_sz = sizeof(uint64_t);
+		pmc.size = sizeof(uint64_t);
 
 		rte_power_monitor(&pmc, timeout + start_ticks);
 
drivers/event/dlb2/dlb2.c +1 -1
index c9a8a02278..5782960158 100644
@@ -2894,7 +2894,7 @@ dlb2_dequeue_wait(struct dlb2_eventdev *dlb2,
 		pmc.addr = monitor_addr;
 		pmc.val = expected_value;
 		pmc.mask = qe_mask.raw_qe[1];
-		pmc.data_sz = sizeof(uint64_t);
+		pmc.size = sizeof(uint64_t);
 
 		rte_power_monitor(&pmc, timeout + start_ticks);
 
drivers/net/i40e/i40e_rxtx.c +1 -1
index 89560d4ee5..668edd6626 100644
@@ -92,7 +92,7 @@ i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 	pmc->mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
 
 	/* registers are 64-bit */
-	pmc->data_sz = sizeof(uint64_t);
+	pmc->size = sizeof(uint64_t);
 
 	return 0;
 }
drivers/net/ice/ice_rxtx.c +1 -1
index 7286e3a445..69f994579a 100644
@@ -46,7 +46,7 @@ ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 	pmc->mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
 
 	/* register is 16-bit */
-	pmc->data_sz = sizeof(uint16_t);
+	pmc->size = sizeof(uint16_t);
 
 	return 0;
 }
drivers/net/ixgbe/ixgbe_rxtx.c +1 -1
index cc8f70e6dd..c0305a8238 100644
@@ -1389,7 +1389,7 @@ ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
 	pmc->mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
 
 	/* the registers are 32-bit */
-	pmc->data_sz = sizeof(uint32_t);
+	pmc->size = sizeof(uint32_t);
 
 	return 0;
 }
lib/librte_eal/include/generic/rte_power_intrinsics.h +11 -8
index 6109d28faa..5960c48c80 100644
@@ -20,14 +20,17 @@
 
 struct rte_power_monitor_cond {
 	volatile void *addr;  /**< Address to monitor for changes */
-	uint64_t val;         /**< Before attempting the monitoring, the address
-	                       *   may be read and compared against this value.
-	                       **/
-	uint64_t mask;   /**< 64-bit mask to extract current value from addr */
-	uint8_t data_sz; /**< Data size (in bytes) that will be used to compare
-	                  *   expected value with the memory address. Can be 1,
-	                  *   2, 4, or 8. Supplying any other value will lead to
-	                  *   undefined result. */
+	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
+	                  *   monitored memory location (`addr`). Can be 1, 2,
+	                  *   4, or 8. Supplying any other value will result in
+	                  *   an error.
+	                  */
 };
 
 /**
lib/librte_eal/x86/rte_power_intrinsics.c +2 -2
index af3ae3237c..39ea9fdecd 100644
@@ -88,7 +88,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 	if (pmc == NULL)
 		return -EINVAL;
 
-	if (__check_val_size(pmc->data_sz) < 0)
+	if (__check_val_size(pmc->size) < 0)
 		return -EINVAL;
 
 	s = &wait_status[lcore_id];
@@ -113,7 +113,7 @@ rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 	/* 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->data_sz);
+				pmc->addr, pmc->size);
 		const uint64_t masked = cur_value & pmc->mask;
 
 		/* if the masked value is already matching, abort */
Signature · 1 line
2.25.1
Acked-by on v20 1/4
#141 lore raw

Re: [dpdk-dev] [PATCH v20 1/4] eal: rename power monitor condition member

22/01/2021 18:12, Anatoly Burakov:

Quoted 7 lines

The data_sz name is fine, but it looks out of place because nothing else has "data" prefix in that structure. Rename it to "size", as well as add more clarity to the comments around each struct member.

Fixes 6a17919b0e2a ("eal: change power intrinsics API")

Thanks for the precisions.

#142 lore raw

PATCH v20 2/4 eal: improve comments around power monitoring API

In reply to Anatoly Burakov

Currently, the API documentation is ambiguous as to what happens when certain conditions are met. Document the behavior explicitly, as well as fix some typos and outdated comments.

Fixes 6a17919b0e2a ("eal: change power intrinsics API")
---
 .../include/generic/rte_power_intrinsics.h    | 20 ++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
lib/librte_eal/include/generic/rte_power_intrinsics.h +13 -7
index 5960c48c80..dddca3d41c 100644
@@ -35,17 +35,20 @@ struct rte_power_monitor_cond {
 
 /**
  * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
+ * @b EXPERIMENTAL: this API may change without prior notice.
  *
  * Monitor specific address for changes. This will cause the CPU to enter an
  * architecture-defined optimized power state until either the specified
  * memory address is written to, a certain TSC timestamp is reached, or other
  * reasons cause the CPU to wake up.
  *
- * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
- * mask is non-zero, the current value pointed to by the `p` pointer will be
- * checked against the expected value, and if they match, the entering of
- * optimized power state may be aborted.
+ * Additionally, an expected value (`pmc->val`), mask (`pmc->mask`), and data
+ * size (`pmc->size`) are provided in the `pmc` power monitoring condition. If
+ * the mask is non-zero, the current value pointed to by the `pmc->addr` pointer
+ * will be read and compared against the expected value, and if they match, the
+ * entering of optimized power state will be aborted. This is intended to
+ * prevent the CPU from entering optimized power state and waiting on a write
+ * that has already happened by the time this API is called.
  *
  * @warning It is responsibility of the user to check if this function is
  *   supported at runtime using `rte_cpu_get_intrinsics_support()` API call.
@@ -67,11 +70,14 @@ int rte_power_monitor(const struct rte_power_monitor_cond *pmc,
 
 /**
  * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
+ * @b EXPERIMENTAL: this API may change without prior notice.
  *
  * Wake up a specific lcore that is in a power optimized state and is monitoring
  * an address.
  *
+ * @note It is safe to call this function if the lcore in question is not
+ *   sleeping. The function will have no effect.
+ *
  * @note This function will *not* wake up a core that is in a power optimized
  *   state due to calling `rte_power_pause`.
  *
@@ -83,7 +89,7 @@ int rte_power_monitor_wakeup(const unsigned int lcore_id);
 
 /**
  * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
+ * @b EXPERIMENTAL: this API may change without prior notice.
  *
  * Enter an architecture-defined optimized power state until a certain TSC
  * timestamp is reached.
Signature · 1 line
2.25.1
Acked-by on v20 2/4
#143 lore raw

Re: [dpdk-dev] [PATCH v20 2/4] eal: improve comments around power monitoring API

22/01/2021 18:12, Anatoly Burakov:

Quoted 16 lines

Currently, the API documentation is ambiguous as to what happens when certain conditions are met. Document the behavior explicitly, as well as fix some typos and outdated comments.

Fixes 6a17919b0e2a ("eal: change power intrinsics API")

---
* Monitor specific address for changes. This will cause the CPU to enter an
* architecture-defined optimized power state until either the specified
* memory address is written to, a certain TSC timestamp is reached, or other
* reasons cause the CPU to wake up.
*
- * Additionally, an expected 64-bit value and 64-bit mask are provided. If
- * mask is non-zero, the current value pointed to by the p pointer will be
- * checked against the expected value, and if they match, the entering of

Quoted 8 lines

- * optimized power state may be aborted.
+ * Additionally, an expected value (pmc->val), mask (pmc->mask), and data
+ * size (pmc->size) are provided in the pmc power monitoring condition. If
+ * the mask is non-zero, the current value pointed to by the pmc->addr pointer
+ * will be read and compared against the expected value, and if they match, the
+ * entering of optimized power state will be aborted. This is intended to
+ * prevent the CPU from entering optimized power state and waiting on a write
+ * that has already happened by the time this API is called.

I think that's a lot better. Thank you.

#144 lore raw

PATCH v20 3/4 power: add PMD power management API and callback

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API mandates a core-to-single-queue mapping (that is, multiple queued per device are supported, but they have to be polled on different cores).

This design is using PMD RX callbacks.

1. UMWAIT/UMONITOR:

When a certain threshold of empty polls is reached, the core will go into a power optimized sleep while waiting on an address of next RX descriptor to be written to.

2. TPAUSE/Pause instruction

This method uses the pause (or TPAUSE, if available) instruction to avoid busy polling.

3. Frequency scaling
Reuse existing DPDK power library to scale up/down core frequency depending on traffic volume.

---

Notes:
v17:
- Added memory barriers suggested by Konstantin
- Removed the BUSY state

 doc/guides/prog_guide/power_man.rst    |  41 +++
 doc/guides/rel_notes/release_21_02.rst |  10 +
 lib/librte_power/meson.build           |   5 +-
 lib/librte_power/rte_power_pmd_mgmt.c  | 365 +++++++++++++++++++++++++
 lib/librte_power/rte_power_pmd_mgmt.h  |  91 ++++++
 lib/librte_power/version.map           |   5 +
 6 files changed, 515 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.h
doc/guides/prog_guide/power_man.rst +41 -0
index 0a3755a901..f36ba0027c 100644
@@ -192,6 +192,47 @@ User Cases
 ----------
 The mechanism can applied to any device which is based on polling. e.g. NIC, FPGA.
 
+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 existing ``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).
+
+API Overview for Ethernet PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core.
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core.
+
 References
 ----------
 
doc/guides/rel_notes/release_21_02.rst +10 -0
index ae36b6a3fa..81b9d93cd0 100644
@@ -122,6 +122,16 @@ New Features
   * Added support for aes-cbc sha256-128-hmac cipher combination in OCTEON TX2
     crypto PMD lookaside protocol offload for IPsec.
 
+* **Added Ethernet PMD power management helper API.**
+
+  A new helper API has been added to make using Ethernet PMD power management
+  easier for the user: ``rte_power_ethdev_pmgmt_queue_enable()``. Three power
+  management schemes are supported initially:
+
+  * Power saving based on UMWAIT instruction (x86 only)
+  * Power saving based on ``rte_pause()`` (generic) or TPAUSE instruction (x86 only)
+  * Power saving based on frequency scaling through the ``librte_power`` library
+
 
 Removed Items
 -------------
lib/librte_power/meson.build +3 -2
index 4b4cf1b90b..e5a11cb834 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
-headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+headers = files('rte_power.h','rte_power_empty_poll.h','rte_power_pmd_mgmt.h')
+deps += ['timer', 'ethdev']
lib/librte_power/rte_power_pmd_mgmt.c new file +365 -0

365 lines not on this page · raw message

lib/librte_power/rte_power_pmd_mgmt.h new file +91 -0

91 lines not on this page · raw message

lib/librte_power/version.map +5 -0
index 69ca9af616..f38a380212 100644
@@ -34,4 +34,9 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+
+	# added in 21.02
+	rte_power_ethdev_pmgmt_queue_disable;
+	rte_power_ethdev_pmgmt_queue_enable;
+
 };
Signature · 1 line
2.25.1
#145 lore raw

PATCH v20 4/4 examples/l3fwd-power: enable PMD power mgmt

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Notes:
v20:
- Moved Rx callback removal to before port close

v12:
- Allow selecting PMD power management scheme from command-line
- Enforce 1 core 1 queue rule

 .../sample_app_ug/l3_forward_power_man.rst    | 35 ++++++++
 examples/l3fwd-power/main.c                   | 90 ++++++++++++++++++-
 2 files changed, 123 insertions(+), 2 deletions(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +35 -0
index 85a78a5c1e..aaa9367fae 100644
@@ -109,6 +109,8 @@ where,
 
 *   --telemetry:  Telemetry mode.
 
+*   --pmd-mgmt: PMD power management mode.
+
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
 
@@ -456,3 +458,36 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./build/examples/dpdk-l3fwd-power -l 1-3 --  --pmd-mgmt -p 0x0f --config="(0,0,2),(0,1,3)"
+
+PMD Power Management Mode
+-------------------------
+There is also a traffic-aware operating mode that, instead of using explicit
+power management, will use automatic PMD power management. This mode is limited
+to one queue per core, and has three available power management schemes:
+
+* ``monitor`` - this will use ``rte_power_monitor()`` function to enter a
+  power-optimized state (subject to platform support).
+
+* ``pause`` - this will use ``rte_power_pause()`` or ``rte_pause()`` to avoid
+  busy looping when there is no traffic.
+
+* ``scale`` - this will use frequency scaling routines available in the
+  ``librte_power`` library.
+
+See :doc:`Power Management<../prog_guide/power_man>` chapter in the DPDK
+Programmer's Guide for more details on PMD power management.
+
+.. code-block:: console
+
+        ./<build_dir>/examples/dpdk-l3fwd-power -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)" --pmd-mgmt=scale
examples/l3fwd-power/main.c +88 -2

166 lines not on this page · raw message

Signature · 1 line
2.25.1
#146 lore raw

Re: [dpdk-dev] [PATCH v20 4/4] examples/l3fwd-power: enable PMD power mgmt

22/01/2021 18:12, Anatoly Burakov:

Quoted 8 lines

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

[...]

Quoted 2 lines

+PMD Power Management Mode
+-------------------------

There should be a blank line here.

doc/guides/sample_app_ug/l3_forward_power_man.rst reference cycles and accordingly busy rate is set to either 0% or · line 486

Quoted 12 lines
doc/guides/sample_app_ug/l3_forward_power_man.rst +12 -0
+There is also a traffic-aware operating mode that, instead of using explicit
+power management, will use automatic PMD power management. This mode is limited
+to one queue per core, and has three available power management schemes:
+
+* ``monitor`` - this will use ``rte_power_monitor()`` function to enter a
+  power-optimized state (subject to platform support).
+
+* ``pause`` - this will use ``rte_power_pause()`` or ``rte_pause()`` to avoid
+  busy looping when there is no traffic.
+
+* ``scale`` - this will use frequency scaling routines available in the
+  ``librte_power`` library.

Better to use a definition list for such explanations:
https://docutils.sourceforge.io/docs/user/rst/quickref.html#definition-lists

I will update while merging.

#147 lore raw

Re: [dpdk-dev] [PATCH v20 0/4] Add PMD power management

In reply to Anatoly Burakov

22/01/2021 18:12, Anatoly Burakov:

Quoted 4 lines

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue

Is there a way to have a more generic solution?
I think it may deserve some comments in the API.

Quoted 3 lines

- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

Could it be extended to more device types?
Otherwise it should be called specifically ethdev power management.

Quoted 7 lines

Anatoly Burakov (2):
eal: rename power monitor condition member
eal: improve comments around power monitoring API

Liang Ma (2):
power: add PMD power management API and callback examples/l3fwd-power: enable PMD power mgmt

Applied with few formatting improvements, thanks

#148 lore raw

Re: [dpdk-dev] [PATCH v20 0/4] Add PMD power management

Quoted 8 lines · Thomas Monjalon

22/01/2021 18:12, Anatoly Burakov:

Quoted 4 lines

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue

Is there a way to have a more generic solution?
I think it may deserve some comments in the API.

If you're referring to possibility of monitoring multiple queues from one core, we are investigating ways to make that happen, but for now, this is the limitation.

Quoted 7 lines
Quoted 4 lines

- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

Could it be extended to more device types?
Otherwise it should be called specifically ethdev power management.

It can theoretically be extended to any device type that has callbacks. Current focus is obviously NICs, but in general, it doesn't have to be. Anything that polls and has callbacks should work.

Quoted 5 lines
Quoted 5 lines

Anatoly Burakov (2):
eal: rename power monitor condition member
eal: improve comments around power monitoring API

Quoted 7 lines
Quoted 3 lines

Liang Ma (2):
power: add PMD power management API and callback examples/l3fwd-power: enable PMD power mgmt

Applied with few formatting improvements, thanks

Thanks!

Signature · 2 lines
Thanks,
Anatoly
#149 lore raw

Re: [dpdk-dev] [PATCH v17 07/11] power: add PMD power management API and callback

In reply to Anatoly Burakov

14/01/2021 15:46, Anatoly Burakov:

doc/guides/prog_guide/power_man.rst User Cases · line 228

Quoted 5 lines

From: Liang Ma <[email protected]>

doc/guides/prog_guide/power_man.rst +3 -0
+   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).

This is quite limited.
Not sure librte_power is the right place for a flexible ethdev management.

doc/guides/prog_guide/power_man.rst User Cases · line 231

Quoted 3 lines
doc/guides/prog_guide/power_man.rst +3 -0
+
+API Overview for PMD Power Management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Underlining should be shorter please.

doc/guides/prog_guide/power_man.rst User Cases · line 234

Quoted 3 lines
doc/guides/prog_guide/power_man.rst +3 -0
+* **Queue Enable**: Enable specific power scheme for certain queue/port/core
+
+* **Queue Disable**: Disable power scheme for certain queue/port/core

Please terminate sentences with a dot.

doc/guides/prog_guide/power_man.rst References · line 246

Quoted 11 lines
doc/guides/prog_guide/power_man.rst +4 -0
+
 References
 ----------
@@ -200,3 +241,6 @@ References
 
 *   The :doc:`../sample_app_ug/vm_power_management`
     chapter in the :doc:`../sample_app_ug/index` section.
+
+*   The :doc:`../sample_app_ug/rxtx_callbacks`
+    chapter in the :doc:`../sample_app_ug/index` section.

Why the index page is mentionned here?

doc/guides/rel_notes/release_21_02.rst New Features · line 63

Quoted 3 lines
doc/guides/rel_notes/release_21_02.rst +1 -0
+* **Add PMD power management helper API**

Please follow release notes guidelines (past tense and dot).

Quoted 8 lines
doc/guides/rel_notes/release_21_02.rst +8 -0
+
+  A new helper API has been added to make using Ethernet PMD power management
+  easier for the user: ``rte_power_pmd_mgmt_queue_enable()``. Three power
+  management schemes are supported initially:
+
+  * Power saving based on UMWAIT instruction (x86 only)
+  * Power saving based on ``rte_pause()`` (generic) or TPAUSE instruction (x86 only)
+  * Power saving based on frequency scaling through the ``librte_power`` library

[...]

lib/librte_power/meson.build sources = files('rte_power.c', 'power_acpi_cpufreq.c', · line 15

Quoted 4 lines
lib/librte_power/meson.build +1 -1
-deps += ['timer']
+deps += ['timer' ,'ethdev']

Wrapping ethdev looks very strange to me.

lib/librte_power/rte_power_pmd_mgmt.c line 2

Quoted 5 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +2 -0
@@ -0,0 +1,364 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation

2010?

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+ */
+
+#include <rte_lcore.h>
+#include <rte_cycles.h>
+#include <rte_cpuflags.h>
+#include <rte_malloc.h>
+#include <rte_ethdev.h>
+#include <rte_power_intrinsics.h>
+
+#include "rte_power_pmd_mgmt.h"

lib/librte_power/rte_power_pmd_mgmt.c line 22

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+
+#define EMPTYPOLL_MAX  512
+
+static struct pmd_conf_data {
+	struct rte_cpu_intrinsics intrinsics_support;
+	/**< what do we support? */
+	uint64_t tsc_per_us;
+	/**< pre-calculated tsc diff for 1us */
+	uint64_t pause_per_us;
+	/**< how many rte_pause can we fit in a microisecond? */

Vim typo spotted: microisecond

lib/librte_power/rte_power_pmd_mgmt.c line 23

Quoted 1 line
lib/librte_power/rte_power_pmd_mgmt.c new file +1 -0
+} global_data;

Not sure about the need for a struct.
Please insert comment before the field if not on the same line. BTW, why doxygen syntax in a .c file?

Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.h new file +1 -0
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: BSD-3-Clause

lib/librte_power/rte_power_pmd_mgmt.h line 11

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.h new file +10 -0
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_PMD_MGMT_H
+#define _RTE_POWER_PMD_MGMT_H
+
+/**
+ * @file
+ * RTE PMD Power Management
+ */

blank line here?

Quoted 18 lines
lib/librte_power/rte_power_pmd_mgmt.h new file +18 -0
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_power.h>
+#include <rte_atomic.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * PMD Power Management Type
+ */
+enum rte_power_pmd_mgmt_type {
+	/** Use power-optimized monitoring to wait for incoming traffic */

lib/librte_power/rte_power_pmd_mgmt.h line 39

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.h new file +10 -0
+	RTE_POWER_MGMT_TYPE_MONITOR = 1,
+	/** Use power-optimized sleep to avoid busy polling */
+	RTE_POWER_MGMT_TYPE_PAUSE,
+	/** Use frequency scaling when traffic is low */
+	RTE_POWER_MGMT_TYPE_SCALE,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice

Dot at the end please.

lib/librte_power/rte_power_pmd_mgmt.h line 46

Quoted 7 lines
lib/librte_power/rte_power_pmd_mgmt.h new file +7 -0
+ *
+ * Enable power management on a specified RX queue and lcore.
+ *
+ * @note This function is not thread-safe.
+ *
+ * @param lcore_id
+ *   lcore_id.

Interesting comment :)

Quoted 6 lines
lib/librte_power/rte_power_pmd_mgmt.h new file +6 -0
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param queue_id
+ *   The queue identifier of the Ethernet device.
+ * @param mode
+ *   The power management callback function type.

lib/librte_power/rte_power_pmd_mgmt.h line 62

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.h new file +10 -0
+
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int
+rte_power_pmd_mgmt_queue_enable(unsigned int lcore_id,
+		uint16_t port_id, uint16_t queue_id,
+		enum rte_power_pmd_mgmt_type mode);

In reality it is an API for ethdev Rx queue, not general PMD. The function should be renamed accordingly.

[...]

lib/librte_power/version.map EXPERIMENTAL { · line 40

Quoted 5 lines
lib/librte_power/version.map +3 -0
+	# added in 21.02
+	rte_power_pmd_mgmt_queue_enable;
+	rte_power_pmd_mgmt_queue_disable;

Alpha sort please.

#150 lore raw

Re: [dpdk-dev] [PATCH v17 07/11] power: add PMD power management API and callback

Quoted 10 lines · Thomas Monjalon

14/01/2021 15:46, Anatoly Burakov:

doc/guides/prog_guide/power_man.rst User Cases · line 228

Quoted 5 lines

From: Liang Ma <[email protected]>

doc/guides/prog_guide/power_man.rst +3 -0
+   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).

This is quite limited.
Not sure librte_power is the right place for a flexible ethdev management.

It's not really "managing" ethdev as such, it just installs a callback. You could say it's building on what's available in ethdev, but aside from installing a callback it doesn't do anything else.

<snip>

Quoted 10 lines

lib/librte_power/rte_power_pmd_mgmt.c line 22

Quoted 7 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +7 -0
+static struct pmd_conf_data {
+	struct rte_cpu_intrinsics intrinsics_support;
+	/**< what do we support? */
+	uint64_t tsc_per_us;
+	/**< pre-calculated tsc diff for 1us */
+	uint64_t pause_per_us;
+	/**< how many rte_pause can we fit in a microisecond? */

Vim typo spotted: microisecond

Quoted 6 lines
Quoted 1 line

+} global_data;

Not sure about the need for a struct.
Please insert comment before the field if not on the same line. BTW, why doxygen syntax in a .c file?

The struct was really there to make autocomplete easier. I can make all of the variables static and pull them out if that's necessary, but i don't think it makes much difference.

(the rest of the comments will be implemented)

Signature · 2 lines
Thanks,
Anatoly
#151 lore raw

PATCH v17 8/11 net/ixgbe: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_monitor_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 25 +++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  1 +
 3 files changed, 27 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index d7a1806ab8..97acf35d24 100644
@@ -560,6 +560,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.get_monitor_addr     = ixgbe_get_monitor_addr,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +25 -0
index 7bb8460359..cc8f70e6dd 100644
@@ -1369,6 +1369,31 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int
+ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	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);
+
+	/* the registers are 32-bit */
+	pmc->data_sz = sizeof(uint32_t);
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +1 -0
index 6d2f7c9da3..8a25e98df6 100644
@@ -299,5 +299,6 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.25.1
#152 lore raw

PATCH v17 9/11 net/i40e: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_monitor_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 25 +++++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  1 +
 3 files changed, 27 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 14622484a0..ba1abc584f 100644
@@ -510,6 +510,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.get_monitor_addr             = i40e_get_monitor_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +25 -0
index 5df9a9df56..0b4220fc9c 100644
@@ -72,6 +72,31 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	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);
+
+	/* registers are 64-bit */
+	pmc->data_sz = sizeof(uint64_t);
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +1 -0
index 57d7b4160b..e1494525ce 100644
@@ -248,6 +248,7 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.25.1
#153 lore raw

PATCH v17 10/11 net/ice: implement power management API

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Implement support for the power management API by implementing a get_monitor_addr function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 26 ++++++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  1 +
 3 files changed, 28 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index 587f485ee3..38c6263946 100644
@@ -216,6 +216,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.get_monitor_addr             = ice_get_monitor_addr,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +26 -0
index d052bd0f1b..066651dc48 100644
@@ -26,6 +26,32 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ip_offset_mask;
 
+int
+ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	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);
+
+	/* register is 16-bit */
+	pmc->data_sz = sizeof(uint16_t);
+
+	return 0;
+}
+
+
 static inline uint8_t
 ice_proto_xtr_type_to_rxdid(uint8_t xtr_type)
 {
drivers/net/ice/ice_rxtx.h +1 -0
index 6b16716063..906fbefdc4 100644
@@ -263,6 +263,7 @@ uint16_t ice_xmit_pkts_vec_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
 				  uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
 
 #define FDIR_PARSING_ENABLE_PER_QUEUE(ad, on) do { \
 	int i; \
Signature · 1 line
2.25.1
#154 lore raw

PATCH v17 11/11 examples/l3fwd-power: enable PMD power mgmt

In reply to Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

---

Notes:
v12:
- Allow selecting PMD power management scheme from command-line
- Enforce 1 core 1 queue rule

 .../sample_app_ug/l3_forward_power_man.rst    | 35 ++++++++
 examples/l3fwd-power/main.c                   | 89 ++++++++++++++++++-
 2 files changed, 122 insertions(+), 2 deletions(-)
doc/guides/sample_app_ug/l3_forward_power_man.rst +35 -0
index 85a78a5c1e..aaa9367fae 100644
@@ -109,6 +109,8 @@ where,
 
 *   --telemetry:  Telemetry mode.
 
+*   --pmd-mgmt: PMD power management mode.
+
 See :doc:`l3_forward` for details.
 The L3fwd-power example reuses the L3fwd command line options.
 
@@ -456,3 +458,36 @@ reference cycles and accordingly busy rate is set  to either 0% or
 
 The new stats ``empty_poll`` , ``full_poll`` and ``busy_percent`` can be viewed by running the script
 ``/usertools/dpdk-telemetry-client.py`` and selecting the menu option ``Send for global Metrics``.
+
+PMD power management Mode
+-------------------------
+
+The PMD power management  mode support for ``l3fwd-power`` is a standalone mode, in this mode
+``l3fwd-power`` does simple l3fwding along with enable the power saving scheme on specific
+port/queue/lcore. Main purpose for this mode is to demonstrate how to use the PMD power management API.
+
+.. code-block:: console
+
+        ./build/examples/dpdk-l3fwd-power -l 1-3 --  --pmd-mgmt -p 0x0f --config="(0,0,2),(0,1,3)"
+
+PMD Power Management Mode
+-------------------------
+There is also a traffic-aware operating mode that, instead of using explicit
+power management, will use automatic PMD power management. This mode is limited
+to one queue per core, and has three available power management schemes:
+
+* ``monitor`` - this will use ``rte_power_monitor()`` function to enter a
+  power-optimized state (subject to platform support).
+
+* ``pause`` - this will use ``rte_power_pause()`` or ``rte_pause()`` to avoid
+  busy looping when there is no traffic.
+
+* ``scale`` - this will use frequency scaling routines available in the
+  ``librte_power`` library.
+
+See :doc:`Power Management<../prog_guide/power_man>` chapter in the DPDK
+Programmer's Guide for more details on PMD power management.
+
+.. code-block:: console
+
+        ./<build_dir>/examples/dpdk-l3fwd-power -l 1-3 -- -p 0x0f --config="(0,0,2),(0,1,3)" --pmd-mgmt=scale
examples/l3fwd-power/main.c +87 -2

165 lines not on this page · raw message

Signature · 1 line
2.25.1
Acked-by on v17 11/11
#155 lore raw

Re: [dpdk-dev] [PATCH v17 11/11] examples/l3fwd-power: enable PMD power mgmt

Hi Anatoly,

Quoted 4 lines · Anatoly Burakov

From: Liang Ma <[email protected]>

Add PMD power management feature support to l3fwd-power sample app.

Quoted 9 lines

---

Notes:
v12:
- Allow selecting PMD power management scheme from command-line
- Enforce 1 core 1 queue rule

#156 lore raw

Re: [dpdk-dev] [PATCH v17 00/11] Add PMD power management

In reply to Anatoly Burakov
Quoted 42 lines · Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.

To achieve power savings, there is a very simple mechanism used: we're counting empty polls, and if a certain threshold is reached, we employ one of the suggested power management schemes automatically, from within a Rx callback inside the PMD. Once there's traffic again, the empty poll counter is reset.

This patchset also introduces a few changes into existing power management-related intrinsics, namely to provide a native way of waking up a sleeping core without application being responsible for it, as well as general robustness improvements. There's quite a bit of locking going on, but these locks are per-thread and very little (if any) contention is expected, so the performance impact shouldn't be that bad (and in any case the locking happens when we're about to sleep anyway).

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

Quoted 4 lines

v17:
- Added exception for ethdev driver-only ABI
- Added memory barriers for monitor/wakeup (Konstantin)
- Fixed compiled issues on non-x86 platforms (hopefully!)

SPDK build is still broken.
http://mails.dpdk.org/archives/test-report/2021-January/174840.html

==== 20 line log output for Ubuntu 18.04 (dpdk_compile_spdk): ==== rte_power_pmd_mgmt.c:(.text.experimental+0x1cc): undefined reference to rte_eth_add_rx_callback' rte_power_pmd_mgmt.c:(.text.experimental+0x1f8): undefined reference to rte_eth_get_monitor_addr' rte_power_pmd_mgmt.c:(.text.experimental+0x37f): undefined reference to `rte_eth_dev_logtype' /dpdk/build/lib/librte_power.a(librte_power_rte_power_pmd_mgmt.c.o):
In function `rte_power_pmd_mgmt_queue_disable':
rte_power_pmd_mgmt.c:(.text.experimental+0x42a): undefined reference to rte_eth_dev_is_valid_port' rte_power_pmd_mgmt.c:(.text.experimental+0x4e7): undefined reference to rte_eth_remove_rx_callback' rte_power_pmd_mgmt.c:(.text.experimental+0x536): undefined reference to rte_eth_remove_rx_callback' rte_power_pmd_mgmt.c:(.text.experimental+0x54d): undefined reference to rte_eth_dev_logtype'
collect2: error: ld returned 1 exit status /spdk/mk/spdk.app.mk:65: recipe for target 'iscsi_fuzz' failed /spdk/mk/spdk.subdirs.mk:44: recipe for target 'iscsi_fuzz' failed /spdk/mk/spdk.subdirs.mk:44: recipe for target 'fuzz' failed make[4]: *** [iscsi_fuzz] Error 1
make[3]: *** [iscsi_fuzz] Error 2
make[2]: *** [fuzz] Error 2
/spdk/mk/spdk.subdirs.mk:44: recipe for target 'app' failed make[1]: *** [app] Error 2
/spdk/mk/spdk.subdirs.mk:44: recipe for target 'test' failed
make: *** [test] Error 2
[2] Error running command.

I guess this is because of the added dependency of rte_ethdev to rte_power. Afaics, SPDK does not use pkg-config:
https://github.com/spdk/spdk/blob/master/lib/env_dpdk/env.mk#L53

Signature · 1 line
David Marchand
#157 lore raw

Re: [dpdk-dev] [PATCH v17 00/11] Add PMD power management

Quoted 83 lines · David Marchand
Quoted 42 lines · Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.

To achieve power savings, there is a very simple mechanism used: we're counting empty polls, and if a certain threshold is reached, we employ one of the suggested power management schemes automatically, from within a Rx callback inside the PMD. Once there's traffic again, the empty poll counter is reset.

This patchset also introduces a few changes into existing power management-related intrinsics, namely to provide a native way of waking up a sleeping core without application being responsible for it, as well as general robustness improvements. There's quite a bit of locking going on, but these locks are per-thread and very little (if any) contention is expected, so the performance impact shouldn't be that bad (and in any case the locking happens when we're about to sleep anyway).

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

Things of note:

- Only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Support 3 type policies. Monitor/Pause/Frequency Scaling
- Power management is enabled per-queue
- The API doesn't extend to other device types

Quoted 4 lines

v17:
- Added exception for ethdev driver-only ABI
- Added memory barriers for monitor/wakeup (Konstantin)
- Fixed compiled issues on non-x86 platforms (hopefully!)

SPDK build is still broken.
http://mails.dpdk.org/archives/test-report/2021-January/174840.html

==== 20 line log output for Ubuntu 18.04 (dpdk_compile_spdk): ==== rte_power_pmd_mgmt.c:(.text.experimental+0x1cc): undefined reference to rte_eth_add_rx_callback' rte_power_pmd_mgmt.c:(.text.experimental+0x1f8): undefined reference to rte_eth_get_monitor_addr' rte_power_pmd_mgmt.c:(.text.experimental+0x37f): undefined reference to `rte_eth_dev_logtype' /dpdk/build/lib/librte_power.a(librte_power_rte_power_pmd_mgmt.c.o):
In function `rte_power_pmd_mgmt_queue_disable':
rte_power_pmd_mgmt.c:(.text.experimental+0x42a): undefined reference to rte_eth_dev_is_valid_port' rte_power_pmd_mgmt.c:(.text.experimental+0x4e7): undefined reference to rte_eth_remove_rx_callback' rte_power_pmd_mgmt.c:(.text.experimental+0x536): undefined reference to rte_eth_remove_rx_callback' rte_power_pmd_mgmt.c:(.text.experimental+0x54d): undefined reference to rte_eth_dev_logtype'
collect2: error: ld returned 1 exit status /spdk/mk/spdk.app.mk:65: recipe for target 'iscsi_fuzz' failed /spdk/mk/spdk.subdirs.mk:44: recipe for target 'iscsi_fuzz' failed /spdk/mk/spdk.subdirs.mk:44: recipe for target 'fuzz' failed make[4]: *** [iscsi_fuzz] Error 1
make[3]: *** [iscsi_fuzz] Error 2
make[2]: *** [fuzz] Error 2
/spdk/mk/spdk.subdirs.mk:44: recipe for target 'app' failed make[1]: *** [app] Error 2
/spdk/mk/spdk.subdirs.mk:44: recipe for target 'test' failed
make: *** [test] Error 2
[2] Error running command.

Quoted 5 lines

I guess this is because of the added dependency of rte_ethdev to rte_power. Afaics, SPDK does not use pkg-config:
https://github.com/spdk/spdk/blob/master/lib/env_dpdk/env.mk#L53

Sooo... this is an SPDK issue then? Because i can't see any way of fixing the issue on DPDK side.

Signature · 2 lines
Thanks,
Anatoly
#158 lore raw

Re: [dpdk-dev] [PATCH v17 00/11] Add PMD power management

18/01/2021 16:45, Burakov, Anatoly:

Quoted 11 lines · David Marchand
Quoted 10 lines
Quoted 8 lines · Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

[...]

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

The customer laziness is usually a bad justification :) I think we could achieve the same with not too much code on application side.
And I'm not sure hiding queue management is sane. Remember this rule: application must remain in control.

[...]

Quoted 2 lines
Quoted 2 lines

SPDK build is still broken.
http://mails.dpdk.org/archives/test-report/2021-January/174840.html

[...]

Quoted 6 lines
Quoted 3 lines

I guess this is because of the added dependency of rte_ethdev to rte_power. Afaics, SPDK does not use pkg-config:
https://github.com/spdk/spdk/blob/master/lib/env_dpdk/env.mk#L53

Sooo... this is an SPDK issue then? Because i can't see any way of fixing the issue on DPDK side.

Yes SPDK should not skip pkg-config.
But it raises 2 question:
- are we breaking ABI compatibility?
- is ethdev management expected for librte_power?

It makes me wonder whether we should host the few functions mixing librte_ethdev and librte_power somewhere else.
The question is where?

#159 lore raw

Re: [dpdk-dev] [PATCH v17 00/11] Add PMD power management

Quoted 13 lines · Thomas Monjalon

18/01/2021 16:45, Burakov, Anatoly:

Quoted 11 lines · David Marchand
Quoted 10 lines
Quoted 8 lines · Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive. There are multiple proposed mechanisms to achieve said power
savings: simple frequency scaling, idle loop, and monitoring the Rx queue for incoming packages. The latter is achieved through cooperation with the NIC driver that will allow us to know address of wake up event, and wait for writes on that address.

[...]

Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it with minimal changes to the application code. The current approach allows to just flip a switch and automatically have power savings.

The customer laziness is usually a bad justification :) I think we could achieve the same with not too much code on application side.

Yes, we could. Customers could basically take this patch and reimplement it inside their application, and get the same benefits (with also added benefit of having knowledge about their queue/core mapping, and so being able to use the PAUSE or SCALE schemes for more than one queue).

However, i still think it's a valid use case - if we can do it that way and have a ready-made power management story, why not?

Quoted 3 lines

And I'm not sure hiding queue management is sane. Remember this rule: application must remain in control.

The application can still be in control by just not using the API and implementing things manually instead. Nothing is being taken away from the ability of application to be in control.

Quoted 8 lines

[...]

Quoted 2 lines
Quoted 2 lines

SPDK build is still broken.
http://mails.dpdk.org/archives/test-report/2021-January/174840.html

[...]

Quoted 4 lines
Quoted 3 lines

I guess this is because of the added dependency of rte_ethdev to rte_power. Afaics, SPDK does not use pkg-config:
https://github.com/spdk/spdk/blob/master/lib/env_dpdk/env.mk#L53

Quoted 6 lines
Quoted 2 lines

Sooo... this is an SPDK issue then? Because i can't see any way of fixing the issue on DPDK side.

Yes SPDK should not skip pkg-config.
But it raises 2 question:
- are we breaking ABI compatibility?

Good question. Does including an extra intra-DPDK dependency count as ABI break? I was under impression that we didn't want DPDK to be distributed as individual libraries but rather would like it to be used as a whole, so if internal dependencies between components change, it's not a big deal (unless a third-party build system is used that explicitly specifies dependencies rather than using pkg-config).

Quoted 6 lines

- is ethdev management expected for librte_power?

It makes me wonder whether we should host the few functions mixing librte_ethdev and librte_power somewhere else.
The question is where?

That could be another possibility. We could put this into a separate library, but IMO it would serve no purpose other than avoiding adding a dependency on *internal* component to librte_power. I'm not sure it's a worthy trade off.

Signature · 2 lines
Thanks,
Anatoly
#160 lore raw

Re: [dpdk-dev] [PATCH v17 00/11] Add PMD power management

Quoted 14 lines · Anatoly
Quoted 7 lines
Quoted 2 lines
Quoted 2 lines

SPDK build is still broken.
http://mails.dpdk.org/archives/test-report/2021-January/174840.html

[...]

Quoted 4 lines
Quoted 3 lines

I guess this is because of the added dependency of rte_ethdev to rte_power. Afaics, SPDK does not use pkg-config:
https://github.com/spdk/spdk/blob/master/lib/env_dpdk/env.mk#L53

Quoted 6 lines
Quoted 2 lines

Sooo... this is an SPDK issue then? Because i can't see any way of fixing the issue on DPDK side.

Yes SPDK should not skip pkg-config.
But it raises 2 question:
- are we breaking ABI compatibility?

Quoted 6 lines

Good question. Does including an extra intra-DPDK dependency count as ABI break? I was under impression that we didn't want DPDK to be distributed as individual libraries but rather would like it to be used as a whole, so if internal dependencies between components change, it's not a big deal (unless a third-party build system is used that explicitly specifies dependencies rather than using pkg-config).

I don't get where an ABI breakage would be.

What I reported is an issue with static link.

For shared link, I would expect librte_power would expose its dependency on rte_ethdev via a DT_NEEDED entry.
The final binary does not have to be aware of it.

Signature · 1 line
David Marchand
#161 lore raw

Re: [dpdk-dev] [PATCH v17 00/11] Add PMD power management

In reply to Anatoly Burakov

14/01/2021 15:46, Anatoly Burakov:

Quoted 7 lines

Anatoly Burakov (5):
eal: uninline power intrinsics
eal: avoid invalid API usage in power intrinsics
eal: change API of power intrinsics
eal: remove sync version of power monitor
eal: add monitor wakeup function

Quoted 7 lines

Liang Ma (6):
ethdev: add simple power management API
power: add PMD power management API and callback net/ixgbe: implement power management API net/i40e: implement power management API net/ice: implement power management API examples/l3fwd-power: enable PMD power mgmt

The librte_power part may deserve another iteration. I suggest to give it a chance for a better version in -rc2.

For 21.02-rc1, the EAL and ethdev (including PMDs) parts are merged, thanks.

#162 lore raw

Re: [dpdk-dev] [PATCH v17 00/11] Add PMD power management

Quoted 16 lines · Thomas Monjalon

14/01/2021 15:46, Anatoly Burakov:

Quoted 7 lines

Anatoly Burakov (5):
eal: uninline power intrinsics
eal: avoid invalid API usage in power intrinsics
eal: change API of power intrinsics
eal: remove sync version of power monitor
eal: add monitor wakeup function

Quoted 7 lines

Liang Ma (6):
ethdev: add simple power management API
power: add PMD power management API and callback net/ixgbe: implement power management API net/i40e: implement power management API net/ice: implement power management API examples/l3fwd-power: enable PMD power mgmt

Quoted 5 lines

The librte_power part may deserve another iteration. I suggest to give it a chance for a better version in -rc2.

For 21.02-rc1, the EAL and ethdev (including PMDs) parts are merged, thanks.

Good to hear, thanks!

I'll get on the respin of remaining parts.

Signature · 2 lines
Thanks,
Anatoly
#163 lore raw

RFC 2/6 ethdev: add simple power management API

In reply to Anatoly Burakov

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API is limited to 1 core 1 queue use case as there is no coordination between queues/cores in ethdev.

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

---
 lib/librte_ethdev/rte_ethdev.c           | 39 +++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 70 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_core.h      | 41 +++++++++++++-
 lib/librte_ethdev/rte_ethdev_version.map |  4 ++
 4 files changed, 152 insertions(+), 2 deletions(-)
lib/librte_ethdev/rte_ethdev.c +39 -0
index 8e10a6fc36..0be5ecfc11 100644
@@ -16,6 +16,7 @@
 #include <netinet/in.h>
 
 #include <rte_byteorder.h>
+#include <rte_cpuflags.h>
 #include <rte_log.h>
 #include <rte_debug.h>
 #include <rte_interrupts.h>
@@ -5053,6 +5054,44 @@ rte_eth_dev_pool_ops_supported(uint16_t port_id, const char *pool)
 	return (*dev->dev_ops->pool_ops_supported)(dev, pool);
 }
 
+int
+rte_eth_dev_power_mgmt_enable(uint16_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG))
+		return -ENOTSUP;
+
+	/* allocate memory for empty poll stats */
+	dev->empty_poll_stats = rte_malloc_socket(NULL,
+		sizeof(struct rte_eth_ep_stat) * RTE_MAX_QUEUES_PER_PORT,
+		0, dev->data->numa_node);
+
+	if (dev->empty_poll_stats == NULL)
+		return -ENOMEM;
+
+	dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_ENABLED;
+	return 0;
+}
+
+int
+rte_eth_dev_power_mgmt_disable(uint16_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	/* rte_free ignores NULL so safe to call without checks */
+	rte_free(dev->empty_poll_stats);
+
+	dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_DISABLED;
+	return 0;
+}
+
 /**
  * A set of values to describe the possible states of a switch domain.
  */
lib/librte_ethdev/rte_ethdev.h +70 -0

100 lines not on this page · raw message

lib/librte_ethdev/rte_ethdev_core.h +39 -2

65 lines not on this page · raw message

lib/librte_ethdev/rte_ethdev_version.map +4 -0
index 7155056045..141361823d 100644
@@ -241,4 +241,8 @@ EXPERIMENTAL {
 	__rte_ethdev_trace_rx_burst;
 	__rte_ethdev_trace_tx_burst;
 	rte_flow_get_aged_flows;
+
+	# added in 20.08
+	rte_eth_dev_power_mgmt_disable;
+	rte_eth_dev_power_mgmt_enable;
 };
Signature · 1 line
2.17.1
#164 lore raw

Re: [dpdk-dev] [RFC 2/6] ethdev: add simple power management API

Quoted 168 lines

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API is limited to 1 core 1 queue use case as there is no coordination between queues/cores in ethdev.

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

---
 lib/librte_ethdev/rte_ethdev.c           | 39 +++++++++++++
 lib/librte_ethdev/rte_ethdev.h           | 70 ++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev_core.h      | 41 +++++++++++++-
 lib/librte_ethdev/rte_ethdev_version.map |  4 ++
 4 files changed, 152 insertions(+), 2 deletions(-)
lib/librte_ethdev/rte_ethdev.c +39 -0
index 8e10a6fc36..0be5ecfc11 100644
@@ -16,6 +16,7 @@
 #include <netinet/in.h>
 
 #include <rte_byteorder.h>
+#include <rte_cpuflags.h>
 #include <rte_log.h>
 #include <rte_debug.h>
 #include <rte_interrupts.h>
@@ -5053,6 +5054,44 @@ rte_eth_dev_pool_ops_supported(uint16_t port_id, const char *pool)
 	return (*dev->dev_ops->pool_ops_supported)(dev, pool);
 }
 
+int
+rte_eth_dev_power_mgmt_enable(uint16_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG))
+		return -ENOTSUP;
+
+	/* allocate memory for empty poll stats */
+	dev->empty_poll_stats = rte_malloc_socket(NULL,
+		sizeof(struct rte_eth_ep_stat) * RTE_MAX_QUEUES_PER_PORT,
+		0, dev->data->numa_node);
+
+	if (dev->empty_poll_stats == NULL)
+		return -ENOMEM;
+
+	dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_ENABLED;
+	return 0;
+}
+
+int
+rte_eth_dev_power_mgmt_disable(uint16_t port_id)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	/* rte_free ignores NULL so safe to call without checks */
+	rte_free(dev->empty_poll_stats);
+
+	dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_DISABLED;
+	return 0;
+}
+
 /**
  * A set of values to describe the possible states of a switch domain.
  */
lib/librte_ethdev/rte_ethdev.h +51 -0
index a49242bcd2..b8318f7e91 100644
@@ -157,6 +157,7 @@ extern "C" {
 #include <rte_common.h>
 #include <rte_config.h>
 #include <rte_ether.h>
+#include <rte_power_intrinsics.h>
 
 #include "rte_ethdev_trace_fp.h"
 #include "rte_dev_info.h"
@@ -666,6 +667,7 @@ rte_eth_rss_hf_refine(uint64_t rss_hf)
 /** Maximum nb. of vlan per mirror rule */
 #define ETH_MIRROR_MAX_VLANS       64
 
+#define ETH_EMPTYPOLL_MAX          512 /**< Empty poll number threshlold */
 #define ETH_MIRROR_VIRTUAL_POOL_UP     0x01  /**< Virtual Pool uplink Mirroring. */
 #define ETH_MIRROR_UPLINK_PORT         0x02  /**< Uplink Port Mirroring. */
 #define ETH_MIRROR_DOWNLINK_PORT       0x04  /**< Downlink Port Mirroring. */
@@ -1490,6 +1492,16 @@ enum rte_eth_dev_state {
 	RTE_ETH_DEV_REMOVED,
 };
 
+/**
+ * Possible power managment states of an ethdev port.
+ */
+enum rte_eth_dev_power_mgmt_state {
+	/** Device power management is disabled. */
+	RTE_ETH_DEV_POWER_MGMT_DISABLED = 0,
+	/** Device power management is enabled. */
+	RTE_ETH_DEV_POWER_MGMT_ENABLED
+};
+
 struct rte_eth_dev_sriov {
 	uint8_t active;               /**< SRIOV is active with 16, 32 or 64 pools */
 	uint8_t nb_q_per_pool;        /**< rx queue number per pool */
@@ -4302,6 +4314,38 @@ __rte_experimental
 int rte_eth_dev_hairpin_capability_get(uint16_t port_id,
 				       struct rte_eth_hairpin_cap *cap);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Enable device power management.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ *
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int rte_eth_dev_power_mgmt_enable(uint16_t port_id);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Disable device power management.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ *
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int rte_eth_dev_power_mgmt_disable(uint16_t port_id);
+
 #include <rte_ethdev_core.h>
 
 /**
@@ -4417,6 +4461,32 @@ rte_eth_rx_burst(uint16_t port_id, uint16_t queue_id,
 		} while (cb != NULL);
 	}
 #endif
+	if (dev->pwr_mgmt_state == RTE_ETH_DEV_POWER_MGMT_ENABLED) {
+		if (unlikely(nb_rx == 0)) {
+			dev->empty_poll_stats[queue_id].num++;
+			if (unlikely(dev->empty_poll_stats[queue_id].num >
+					ETH_EMPTYPOLL_MAX)) {
+				volatile void *target_addr;
+				uint64_t expected, mask;

lib/librte_ethdev/rte_ethdev.h rte_eth_rx_burst(uint16_t port_id, uint16_t queue_id, · line 4480

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.h +10 -0
+				int ret;
+
+				/*
+				 * get address of next descriptor in the RX
+				 * ring for this queue, as well as expected
+				 * value and a mask.
+				 */
+				ret = (*dev->dev_ops->next_rx_desc)
+					(dev->data->rx_queues[queue_id],
+					 &target_addr, &expected, &mask);

That makes every PMD that doesn't support next_rx_desc op to crash.
One simple way to avoid it - check in rte_eth_dev_power_mgmt_enable() that PMD does implement ops->next_rx_desc.
Though I don't think introducing such new op is a best approach, as it implies that PMD does have HW RX descriptor mapped into WB-type memory, and dictates
to PMD on what it should sleep on.
Though depending on HW/SW capabilities and implementation PMD might choose to sleep on different thing (HW doorbell, SW cond var, etc.).
Another thing - I doubt it is a good idea to pollute generic RX function with power specific code (again, as I said above it probably wouldn't be that generic for all possible PMDs). From my perspective we have 2 alternatives to implement such functionality:
1. Keep rte_eth_dev_power_mgmt_enable/disable(port, queue) and move actual *wait_on* code into the PMD RX implementations (we probably can still have some common. logic about allowed number of empty polls, max timeout to sleep, etc.).
2. Drop rte_eth_dev_power_mgmt_enable/disable and introduce explicit:
rte_eth_dev_wait_for_packet(port, queue, timeout) API function.

In both cases PMD will have a full freedom to implement *wait_on_packet* functionality in a most convenient way.
For 2) user would have to do some extra work himself
(count number of consecutive empty polls, call *wait_on_packet* function explicitly). Though I think it can be easily hidden inside some wrapper API on top
of rte_eth_rx_burst()/rte_eth-dev_wait_for_packet().
Something like rte_eth_rx_burst_wait() or so.
We can have logic about allowed number of empty polls,
might be some other conditions in that top level function.
In that case changes in the user app will still be minimal.
From other side 2) gives user explicit control on where and when to sleep, so from my perspective it seems more straightforward and flexible.

Quoted 100 lines
lib/librte_ethdev/rte_ethdev.h +9 -0
+				if (ret == 0)
+					/* -1ULL is maximum value for TSC */
+					rte_power_monitor(target_addr,
+							  expected, mask,
+							  0, -1ULL);
+			}
+		} else
+			dev->empty_poll_stats[queue_id].num = 0;
+	}
 
 	rte_ethdev_trace_rx_burst(port_id, queue_id, (void **)rx_pkts, nb_rx);
 	return nb_rx;
lib/librte_ethdev/rte_ethdev_core.h +39 -2
index 32407dd418..4e23d465f0 100644
@@ -603,6 +603,27 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
 	 uint16_t nb_tx_desc,
 	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the next RX ring descriptor address.
+ *
+ * @param rxq
+ *   ethdev queue pointer.
+ * @param tail_desc_addr
+ *   the pointer point to descriptor address var.
+ *
+ * @return
+ *   Negative errno value on error, 0 on success.
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */
+typedef int (*eth_next_rx_desc_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -752,6 +773,8 @@ struct eth_dev_ops {
 	/**< Set up device RX hairpin queue. */
 	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
 	/**< Set up device TX hairpin queue. */
+	eth_next_rx_desc_t next_rx_desc;
+	/**< Get next RX ring descriptor address. */
 };
 
 /**
@@ -768,6 +791,14 @@ struct rte_eth_rxtx_callback {
 	void *param;
 };
 
+/**
+ * @internal
+ * Structure used to hold counters for empty poll
+ */
+struct rte_eth_ep_stat {
+	uint64_t num;
+} __rte_cache_aligned;
+
 /**
  * @internal
  * The generic data structure associated with each ethernet device.
@@ -807,8 +838,14 @@ struct rte_eth_dev {
 	enum rte_eth_dev_state state; /**< Flag indicating the port state */
 	void *security_ctx; /**< Context for security ops */
 
-	uint64_t reserved_64s[4]; /**< Reserved for future fields */
-	void *reserved_ptrs[4];   /**< Reserved for future fields */
+	/**< Empty poll number */
+	enum rte_eth_dev_power_mgmt_state pwr_mgmt_state;
+	uint32_t reserved_32;
+	uint64_t reserved_64s[3]; /**< Reserved for future fields */
+
+	/**< Flag indicating the port power state */
+	struct rte_eth_ep_stat *empty_poll_stats;
+	void *reserved_ptrs[3];   /**< Reserved for future fields */
 } __rte_cache_aligned;
 
 struct rte_eth_dev_sriov;
lib/librte_ethdev/rte_ethdev_version.map +4 -1
index 7155056045..141361823d 100644
@@ -241,4 +241,8 @@ EXPERIMENTAL {
 	__rte_ethdev_trace_rx_burst;
 	__rte_ethdev_trace_tx_burst;
 	rte_flow_get_aged_flows;
+
+	# added in 20.08
+	rte_eth_dev_power_mgmt_disable;
+	rte_eth_dev_power_mgmt_enable;
 };
--

2.17.1

#165 lore raw

RFC 3/6 net/ixgbe: implement power management API

In reply to Anatoly Burakov

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index a4e5c539de..190d11d98d 100644
@@ -605,6 +605,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.next_rx_desc         = ixgbe_next_rx_desc,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
index 2e20e18c7a..ef2fb5fca9 100644
@@ -1366,6 +1366,28 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
index 20a8b291d4..6c35966c78 100644
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
#166 lore raw

RFC 4/6 net/i40e: implement power management API

In reply to Anatoly Burakov

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 749d85f544..f3ce54911b 100644
@@ -526,6 +526,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.next_rx_desc	              = i40e_next_rx_desc,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
index 5e7c86ed82..76dfbb2098 100644
@@ -71,6 +71,29 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +2 -0
index 8f11f011a7..72d810475b 100644
@@ -245,6 +245,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.17.1
#167 lore raw

RFC 5/6 net/ice: implement power management API

In reply to Anatoly Burakov

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index d5110c4392..db8269a548 100644
@@ -219,6 +219,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.next_rx_desc	              = ice_next_rx_desc,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
index 1c9f31efdf..80fd6bd134 100644
@@ -24,6 +24,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 
+int ice_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.status_error0;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+	*mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+
+	return 0;
+}
+
+
 static inline uint64_t
 ice_rxdid_to_proto_xtr_ol_flag(uint8_t rxdid)
 {
drivers/net/ice/ice_rxtx.h +2 -0
index 2fdcfb7d04..7eb6fa904e 100644
@@ -202,5 +202,7 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 				uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _ICE_RXTX_H_ */
Signature · 1 line
2.17.1
#168 lore raw

RFC 6/6 app/testpmd: add command for power management on a port

In reply to Anatoly Burakov

A quick-and-dirty testpmd command to enable power management on a specific port.

---
 app/test-pmd/cmdline.c | 48 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
app/test-pmd/cmdline.c +48 -0
index 996a498768..e3a5e19485 100644
@@ -1773,6 +1773,53 @@ cmdline_parse_inst_t cmd_config_speed_specific = {
 	},
 };
 
+/* *** enable power management for specific port *** */
+struct cmd_port_pmgmt {
+	cmdline_fixed_string_t port;
+	portid_t id;
+	cmdline_fixed_string_t pmgmt;
+	cmdline_fixed_string_t on;
+};
+
+static void
+cmd_port_pmgmt_parsed(void *parsed_result,
+				__rte_unused struct cmdline *cl,
+				__rte_unused void *data)
+{
+	struct cmd_port_pmgmt *res = parsed_result;
+
+	if (port_id_is_invalid(res->id, ENABLED_WARN))
+		return;
+
+	if (!strcmp(res->on, "on"))
+		rte_eth_dev_power_mgmt_enable(res->id);
+	else if (!strcmp(res->on, "off"))
+		rte_eth_dev_power_mgmt_disable(res->id);
+}
+
+
+cmdline_parse_token_string_t cmd_port_pmgmt_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_pmgmt, port, "port");
+cmdline_parse_token_num_t cmd_port_pmgmt_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_pmgmt, id, UINT16);
+cmdline_parse_token_string_t cmd_port_pmgmt_item1 =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_pmgmt, pmgmt, "power-mgmt");
+cmdline_parse_token_string_t cmd_port_pmgmt_value1 =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_pmgmt, on, "on#off");
+
+cmdline_parse_inst_t cmd_port_pmgmt = {
+	.f = cmd_port_pmgmt_parsed,
+	.data = NULL,
+	.help_str = "port <port_id> power-mgmt on|off",
+	.tokens = {
+		(void *)&cmd_port_pmgmt_port,
+		(void *)&cmd_port_pmgmt_id,
+		(void *)&cmd_port_pmgmt_item1,
+		(void *)&cmd_port_pmgmt_value1,
+		NULL,
+	},
+};
+
 /* *** configure loopback for all ports *** */
 struct cmd_config_loopback_all {
 	cmdline_fixed_string_t port;
@@ -19692,6 +19739,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_set_raw,
 	(cmdline_parse_inst_t *)&cmd_show_set_raw_all,
 	(cmdline_parse_inst_t *)&cmd_config_tx_dynf_specific,
+	(cmdline_parse_inst_t *)&cmd_port_pmgmt,
 	NULL,
 };
 
Signature · 1 line
2.17.1
#169 lore raw
In reply to Anatoly Burakov
Quoted 50 lines · Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive, along with a set of (hopefully generic) intrinsics that facilitate that. This is achieved through cooperation with the NIC driver that will allow us to know address of the next NIC RX ring packet descriptor, and wait for writes on it.

On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.

To achieve power savings, there is a very simple mechanism
used: we're counting empty polls, and if a certain threshold is reached, we get the address of next RX ring descriptor from the NIC driver, arm the monitoring hardware, and enter a power-optimized state. We will then wake up when either a timeout happens, or a write happens (or generally whenever CPU feels like waking up - this is platform- specific), and proceed as normal. The empty poll counter is reset whenever we actually get packets, so we only go to sleep when we know nothing is going on.

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it wit minimal changes to the application code. The current approach allows to just flip a switch and automagically have power savings.

There are certain limitations in this patchset right now:
- Currently, only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Currently, power management is enabled per-port, not per-queue
- There is potential to greatly increase TX latency if we are buffering things, and go to sleep before sending packets
- The API is not perfect and could use some improvement and discussion
- The API doesn't extend to other device types
- The intrinsics are platform-specific, so ethdev has some platform-specific code in it
- Support was only implemented for devices using net/ixgbe, net/i40e and net/ice drivers

Quoted 2 lines

Hopefully this would generate enough feedback to clear a path forward!

Just for my understanding:

How/Is this solution is superior than Rx queue interrupt based scheme that applied in l3fwd-power?

What I meant by superior here, as an example,
a)Is there any power savings in mill watt vs interrupt scheme?
b) Is there improvement on time reduction between switching from/to a different state
(i.e how fast it can move from low power state to full power state) vs interrupt scheme.
etc

or This just for just pushing all the logic to ethdev so that applications can be transparent?

Quoted 35 lines

Anatoly Burakov (6):
eal: add power management intrinsics
ethdev: add simple power management API net/ixgbe: implement power management API net/i40e: implement power management API net/ice: implement power management API app/testpmd: add command for power management on a port

 app/test-pmd/cmdline.c                        |  48 +++++++
 drivers/net/i40e/i40e_ethdev.c                |   1 +
 drivers/net/i40e/i40e_rxtx.c                  |  23 +++
 drivers/net/i40e/i40e_rxtx.h                  |   2 +
 drivers/net/ice/ice_ethdev.c                  |   1 +
 drivers/net/ice/ice_rxtx.c                    |  23 +++
 drivers/net/ice/ice_rxtx.h                    |   2 +
 drivers/net/ixgbe/ixgbe_ethdev.c              |   1 +
 drivers/net/ixgbe/ixgbe_rxtx.c                |  22 +++
 drivers/net/ixgbe/ixgbe_rxtx.h                |   2 +
 .../include/generic/rte_power_intrinsics.h    |  64 +++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/x86/include/meson.build        |   1 +
 lib/librte_eal/x86/include/rte_cpuflags.h     |   1 +
 .../x86/include/rte_power_intrinsics.h        | 134 ++++++++++++++++++
 lib/librte_eal/x86/rte_cpuflags.c             |   2 +
 lib/librte_ethdev/rte_ethdev.c                |  39 +++++
 lib/librte_ethdev/rte_ethdev.h                |  70 +++++++++
 lib/librte_ethdev/rte_ethdev_core.h           |  41 +++++-
 lib/librte_ethdev/rte_ethdev_version.map      |   4 +
 20 files changed, 480 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h

--
2.17.1

#170 lore raw
Quoted 68 lines · On Wed, 27 May 2020 23:03:59 +0530 Jerin Jacob <[email protected]> wrote:
Quoted 50 lines · Anatoly Burakov

This patchset proposes a simple API for Ethernet drivers to cause the CPU to enter a power-optimized state while waiting for packets to arrive, along with a set of (hopefully generic) intrinsics that facilitate that. This is achieved through cooperation with the NIC driver that will allow us to know address of the next NIC RX ring packet descriptor, and wait for writes on it.

On IA, this is achieved through using UMONITOR/UMWAIT instructions. They are used in their raw opcode form because there is no widespread compiler support for them yet. Still, the API is made generic enough to hopefully support other architectures, if they happen to implement similar instructions.

To achieve power savings, there is a very simple mechanism
used: we're counting empty polls, and if a certain threshold is reached, we get the address of next RX ring descriptor from the NIC driver, arm the monitoring hardware, and enter a power-optimized state. We will then wake up when either a timeout happens, or a write happens (or generally whenever CPU feels like waking up - this is platform- specific), and proceed as normal. The empty poll counter is reset whenever we actually get packets, so we only go to sleep when we know nothing is going on.

Why are we putting it into ethdev as opposed to leaving this up to the application? Our customers specifically requested a way to do it wit minimal changes to the application code. The current approach allows to just flip a switch and automagically have power savings.

There are certain limitations in this patchset right now:
- Currently, only 1:1 core to queue mapping is supported, meaning that each lcore must at most handle RX on a single queue
- Currently, power management is enabled per-port, not per-queue
- There is potential to greatly increase TX latency if we are buffering things, and go to sleep before sending packets
- The API is not perfect and could use some improvement and discussion
- The API doesn't extend to other device types
- The intrinsics are platform-specific, so ethdev has some platform-specific code in it
- Support was only implemented for devices using net/ixgbe, net/i40e and net/ice drivers

Quoted 2 lines

Hopefully this would generate enough feedback to clear a path forward!

Just for my understanding:

How/Is this solution is superior than Rx queue interrupt based scheme that applied in l3fwd-power?

What I meant by superior here, as an example,
a)Is there any power savings in mill watt vs interrupt scheme?
b) Is there improvement on time reduction between switching from/to a different state
(i.e how fast it can move from low power state to full power state) vs interrupt scheme.
etc

Quoted 3 lines

or This just for just pushing all the logic to ethdev so that applications can be transparent?

The interrupt scheme is going to get better power management since the core can go to WAIT. This scheme does look interesting in theory since it will be lower latency.

but has a number of issues:
* changing drivers
* can not multiplex multiple queues per core; you are assuming a certain threading model
* what if thread is preempted
* what about thread in a VM
* platform specific: ARM and x86 have different semantics here

#171 lore raw

RFC v2 1/5 eal: add power management intrinsics

In reply to Anatoly Burakov

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

---
 .../include/generic/rte_power_intrinsics.h    |  64 ++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/x86/include/meson.build        |   1 +
 lib/librte_eal/x86/include/rte_cpuflags.h     |   1 +
 .../x86/include/rte_power_intrinsics.h        | 138 ++++++++++++++++++
 lib/librte_eal/x86/rte_cpuflags.c             |   2 +
 6 files changed, 207 insertions(+)
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
new file mode 100644
index 000000000..8646c4ac1
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_H_
+#define _RTE_POWER_INTRINSIC_H_
+
+#include <inttypes.h>
+
+/**
+ * @file
+ * Advanced power management operations.
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, or a certain TSC timestamp is reached.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 8-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp);
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_pause(const uint32_t state,
+		const uint64_t tsc_timestamp);
+
+#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
index cd0902795..3a12e87e1 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2f..494a8142a 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_cpuflags.h +1 -0
index c1d20364d..94d6a4376 100644
@@ -110,6 +110,7 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_RDTSCP,                 /**< RDTSCP */
 	RTE_CPUFLAG_EM64T,                  /**< EM64T */
 
+	RTE_CPUFLAG_WAITPKG,                 /**< UMINITOR/UMWAIT/TPAUSE */
 	/* (EAX 80000007h) EDX features */
 	RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
 
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +138 -0

138 lines not on this page · raw message

lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e795..0325c4b93 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#172 lore raw

RFC v2 2/5 ethdev: add simple power management API and callback

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API is limited to 1 core 1 queue use case as there is no coordination between queues/cores in ethdev.

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

---
 config/common_base                       |   4 +-
 lib/Makefile                             |   1 +
 lib/librte_ethdev/Makefile               |   2 +-
 lib/librte_ethdev/meson.build            |   2 +-
 lib/librte_ethdev/rte_ethdev.c           | 198 +++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.h           |  59 +++++++
 lib/librte_ethdev/rte_ethdev_core.h      |  43 ++++-
 lib/librte_ethdev/rte_ethdev_version.map |   4 +
 lib/meson.build                          |   5 +-
 mk/rte.app.mk                            |   2 +-
 10 files changed, 311 insertions(+), 9 deletions(-)
config/common_base +2 -2
index f76585f16..e0948f0cb 100644
@@ -155,7 +155,7 @@ CONFIG_RTE_MAX_ETHPORTS=32
 CONFIG_RTE_MAX_QUEUES_PER_PORT=1024
 CONFIG_RTE_LIBRTE_IEEE1588=n
 CONFIG_RTE_ETHDEV_QUEUE_STAT_CNTRS=16
-CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=y
+CONFIG_RTE_ETHDEV_RXTX_CALLBACKS=n
 CONFIG_RTE_ETHDEV_PROFILE_WITH_VTUNE=n
 
 #
@@ -978,7 +978,7 @@ CONFIG_RTE_LIBRTE_ACL_DEBUG=n
 #
 # Compile librte_power
 #
-CONFIG_RTE_LIBRTE_POWER=n
+CONFIG_RTE_LIBRTE_POWER=y
 CONFIG_RTE_LIBRTE_POWER_DEBUG=n
 CONFIG_RTE_MAX_LCORE_FREQS=64
 
lib/Makefile +1 -0
index 8f5b68a2d..87646698a 100644
@@ -28,6 +28,7 @@ DEPDIRS-librte_ethdev := librte_net librte_eal librte_mempool librte_ring
 DEPDIRS-librte_ethdev += librte_mbuf
 DEPDIRS-librte_ethdev += librte_kvargs
 DEPDIRS-librte_ethdev += librte_meter
+DEPDIRS-librte_ethdev += librte_power
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
lib/librte_ethdev/Makefile +1 -1
index 47747150b..6a4ce14cf 100644
@@ -11,7 +11,7 @@ LIB = librte_ethdev.a
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf -lrte_kvargs -lrte_meter -lrte_telemetry
+LDLIBS += -lrte_mbuf -lrte_kvargs -lrte_meter -lrte_telemetry -lrte_power
 
 EXPORT_MAP := rte_ethdev_version.map
 
lib/librte_ethdev/meson.build +1 -1
index 8fc24e8c8..e09e2395e 100644
@@ -27,4 +27,4 @@ headers = files('rte_ethdev.h',
 	'rte_tm.h',
 	'rte_tm_driver.h')
 
-deps += ['net', 'kvargs', 'meter', 'telemetry']
+deps += ['net', 'kvargs', 'meter', 'telemetry', 'power']
lib/librte_ethdev/rte_ethdev.c +198 -0

222 lines not on this page · raw message

lib/librte_ethdev/rte_ethdev.h +59 -0

95 lines not on this page · raw message

lib/librte_ethdev/rte_ethdev_core.h +41 -2

67 lines not on this page · raw message

lib/librte_ethdev/rte_ethdev_version.map +4 -0
index 1212a17d3..4d5b63a5b 100644
@@ -241,6 +241,10 @@ EXPERIMENTAL {
 	__rte_ethdev_trace_rx_burst;
 	__rte_ethdev_trace_tx_burst;
 	rte_flow_get_aged_flows;
+
+	# added in 20.08
+	rte_eth_dev_power_mgmt_disable;
+	rte_eth_dev_power_mgmt_enable;
 };
 
 INTERNAL {
lib/meson.build +3 -2
index 3852c0156..54cc0db7d 100644
@@ -14,17 +14,18 @@ libraries = [
 	'eal', # everything depends on eal
 	'ring',
 	'rcu', # rcu depends on ring
+	'timer',   # eventdev depends on this
+	'power',   # eventdev depends on this
 	'mempool', 'mbuf', 'net', 'meter', 'ethdev', 'pci', # core
 	'cmdline',
 	'metrics', # bitrate/latency stats depends on this
 	'hash',    # efd depends on this
-	'timer',   # eventdev depends on this
 	'acl', 'bbdev', 'bitratestats', 'cfgfile',
 	'compressdev', 'cryptodev',
 	'distributor', 'efd', 'eventdev',
 	'gro', 'gso', 'ip_frag', 'jobstats',
 	'kni', 'latencystats', 'lpm', 'member',
-	'power', 'pdump', 'rawdev', 'regexdev',
+	'pdump', 'rawdev', 'regexdev',
 	'rib', 'reorder', 'sched', 'security', 'stack', 'vhost',
 	# ipsec lib depends on net, crypto and security
 	'ipsec',
mk/rte.app.mk +1 -1
index a54425997..b87abb26e 100644
@@ -58,7 +58,6 @@ endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_METRICS)        += --no-whole-archive
 _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)        += -lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
-_LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
 _LDLIBS-$(CONFIG_RTE_LIBRTE_BPF)            += -lrte_bpf
@@ -80,6 +79,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_KVARGS)         += -lrte_kvargs
 _LDLIBS-y                                   += -lrte_telemetry
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NET)            += -lrte_net
+_LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lrte_ethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_BBDEV)          += -lrte_bbdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
Signature · 1 line
2.17.1
#173 lore raw

Re: [dpdk-dev] [RFC v2 2/5] ethdev: add simple power management API and callback

On 11 Aug 11:27, Liang Ma wrote:
<snip>

Quoted 26 lines
lib/librte_ethdev/rte_ethdev.c +26 -0
+static uint16_t
+rte_ethdev_pmgmt_umait(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+	if (dev->pwr_mgmt_state == RTE_ETH_DEV_POWER_MGMT_ENABLED) {
+		if (unlikely(nb_rx == 0)) {
+			dev->empty_poll_stats[qidx].num++;
+			if (unlikely(dev->empty_poll_stats[qidx].num >
+					ETH_EMPTYPOLL_MAX)) {
+				volatile void *target_addr;
+				uint64_t expected, mask;
+				uint16_t ret;
+
+				/*
+				 * get address of next descriptor in the RX
+				 * ring for this queue, as well as expected
+				 * value and a mask.
+				 */
+				ret = (*dev->dev_ops->next_rx_desc)
+					(dev->data->rx_queues[qidx],
+					 &target_addr, &expected, &mask);
+				if (ret == 0)

lib/librte_ethdev/rte_ethdev.c enum { · line 226

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10 -0
+					/* -1ULL is maximum value for TSC */
+					rte_power_monitor(target_addr,
+							  expected, mask,
+							  0, -1ULL);
+			}
+		} else
+			dev->empty_poll_stats[qidx].num = 0;
+	}
+
+	return 0;

should return nb_rx here. that's fixed in v3.

Quoted 18 lines
lib/librte_ethdev/rte_ethdev.c +18 -0
+}
+
+static uint16_t
+rte_ethdev_pmgmt_pause(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+	int i;
+
+	if (dev->pwr_mgmt_state == RTE_ETH_DEV_POWER_MGMT_ENABLED) {
+		if (unlikely(nb_rx == 0)) {
+
+			dev->empty_poll_stats[qidx].num++;
+
+			if (unlikely(dev->empty_poll_stats[qidx].num >
+					ETH_EMPTYPOLL_MAX)) {

lib/librte_ethdev/rte_ethdev.c enum { · line 254

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10 -0
+
+				for (i = 0; i < RTE_ETH_PAUSE_NUM; i++)
+					rte_pause();
+
+			}
+		} else
+			dev->empty_poll_stats[qidx].num = 0;
+	}
+
+	return 0;

should return nb_rx here. that's fixed in v3.

Quoted 17 lines
lib/librte_ethdev/rte_ethdev.c +17 -0
+}
+
+static uint16_t
+rte_ethdev_pmgmt_scalefreq(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+	if (dev->pwr_mgmt_state == RTE_ETH_DEV_POWER_MGMT_ENABLED) {
+		if (unlikely(nb_rx == 0)) {
+			dev->empty_poll_stats[qidx].num++;
+			if (unlikely(dev->empty_poll_stats[qidx].num >
+					ETH_EMPTYPOLL_MAX)) {
+
+				/*scale down freq */
+				rte_power_freq_min(rte_lcore_id());

lib/librte_ethdev/rte_ethdev.c enum { · line 281

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.c +10 -0
+
+			}
+		} else {
+			dev->empty_poll_stats[qidx].num = 0;
+			/* scal up freq */
+			rte_power_freq_max(rte_lcore_id());
+		}
+	}
+
+	return 0;

should return nb_rx here. that's fixed in v3.

Review

Quoted 2 lines
(quoted diff) +2 -0
+}
+

</snip>

--

Quoted 2 lines

2.17.1

#174 lore raw

RFC v2 3/5 net/ixgbe: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index fd0cb9b0e..618fc1573 100644
@@ -592,6 +592,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.next_rx_desc         = ixgbe_next_rx_desc,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
index 977ecf513..d1d015dea 100644
@@ -1366,6 +1366,28 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
index 7e09291b2..826f451be 100644
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
#175 lore raw

RFC v2 4/5 net/i40e: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 05d5f2861..f0797c3cb 100644
@@ -515,6 +515,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.next_rx_desc	              = i40e_next_rx_desc,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
index fe7f9200c..9d7eea8ae 100644
@@ -71,6 +71,29 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +2 -0
index 57d7b4160..bfda5b6ad 100644
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.17.1
#176 lore raw

RFC v2 5/5 net/ice: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index 7dd3fcd27..7a636cd11 100644
@@ -212,6 +212,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.next_rx_desc	              = ice_next_rx_desc,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
index cc3139042..ce7e025b6 100644
@@ -24,6 +24,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 
+int ice_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.status_error0;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+	*mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+
+	return 0;
+}
+
+
 static inline uint64_t
 ice_rxdid_to_proto_xtr_ol_flag(uint8_t rxdid)
 {
drivers/net/ice/ice_rxtx.h +2 -0
index 2fdcfb7d0..7eb6fa904 100644
@@ -202,5 +202,7 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 				uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _ICE_RXTX_H_ */
Signature · 1 line
2.17.1
#177 lore raw

Re: [dpdk-dev] [RFC v2 1/5] eal: add power management intrinsics

In reply to Liang Ma
Quoted 15 lines · Liang Ma

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

---

<snip>

lib/librte_eal/x86/include/rte_cpuflags.h enum rte_cpu_flag_t { · line 113

Quoted 9 lines
lib/librte_eal/x86/include/rte_cpuflags.h +1 -0
index c1d20364d..94d6a4376 100644
@@ -110,6 +110,7 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_RDTSCP,                 /**< RDTSCP */
 	RTE_CPUFLAG_EM64T,                  /**< EM64T */
 
+	RTE_CPUFLAG_WAITPKG,                 /**< UMINITOR/UMWAIT/TPAUSE */

need re-work the order to avoid breaking ABI

lib/librte_eal/x86/include/rte_cpuflags.h enum rte_cpu_flag_t { · line 116

Quoted 3 lines
lib/librte_eal/x86/include/rte_cpuflags.h +0 -0
 	/* (EAX 80000007h) EDX features */
 	RTE_CPUFLAG_INVTSC,                 /**< INVTSC */
 

</snip>

Quoted 3 lines
Signature · 1 line
2.17.1
#178 lore raw

RFC PATCH v3 1/6 eal: add power management intrinsics

In reply to Liang Ma

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

---
 .../include/generic/rte_power_intrinsics.h    |  64 ++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/x86/include/meson.build        |   1 +
 lib/librte_eal/x86/include/rte_cpuflags.h     |   2 +
 .../x86/include/rte_power_intrinsics.h        | 143 ++++++++++++++++++
 lib/librte_eal/x86/rte_cpuflags.c             |   2 +
 6 files changed, 213 insertions(+)
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
new file mode 100644
index 0000000000..cd7f8070ac
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_H_
+#define _RTE_POWER_INTRINSIC_H_
+
+#include <inttypes.h>
+
+/**
+ * @file
+ * Advanced power management operations.
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, or a certain TSC timestamp is reached.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp);
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_pause(const uint32_t state,
+		const uint64_t tsc_timestamp);
+
+#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
index c1d20364d1..5041a830a7 100644
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	/**< UMWAIT/TPAUSE Instructions */
+	RTE_CPUFLAG_WAITPKG,                /**< UMINITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +143 -0

143 lines not on this page · raw message

lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#179 lore raw

RFC PATCH v3 2/6 ethdev: add simple power management API

Add a simple API allow ethdev get the last available queue descriptor address from PMD. Also include internal structure update.

---
 lib/librte_ethdev/rte_ethdev.h      | 22 ++++++++++++++
 lib/librte_ethdev/rte_ethdev_core.h | 46 +++++++++++++++++++++++++++--
 2 files changed, 66 insertions(+), 2 deletions(-)
lib/librte_ethdev/rte_ethdev.h +22 -0
index 70295d7ab7..d9312d3e11 100644
@@ -157,6 +157,7 @@ extern "C" {
 #include <rte_common.h>
 #include <rte_config.h>
 #include <rte_ether.h>
+#include <rte_power_intrinsics.h>
 
 #include "rte_ethdev_trace_fp.h"
 #include "rte_dev_info.h"
@@ -775,6 +776,7 @@ rte_eth_rss_hf_refine(uint64_t rss_hf)
 /** Maximum nb. of vlan per mirror rule */
 #define ETH_MIRROR_MAX_VLANS       64
 
+#define ETH_EMPTYPOLL_MAX          512 /**< Empty poll number threshlold */
 #define ETH_MIRROR_VIRTUAL_POOL_UP     0x01  /**< Virtual Pool uplink Mirroring. */
 #define ETH_MIRROR_UPLINK_PORT         0x02  /**< Uplink Port Mirroring. */
 #define ETH_MIRROR_DOWNLINK_PORT       0x04  /**< Downlink Port Mirroring. */
@@ -1602,6 +1604,26 @@ enum rte_eth_dev_state {
 	RTE_ETH_DEV_REMOVED,
 };
 
+#define  RTE_ETH_PAUSE_NUM  64    /* How many times to pause */
+/**
+ * Possible power management states of an ethdev port.
+ */
+enum rte_eth_dev_power_mgmt_state {
+	/** Device power management is disabled. */
+	RTE_ETH_DEV_POWER_MGMT_DISABLED = 0,
+	/** Device power management is enabled. */
+	RTE_ETH_DEV_POWER_MGMT_ENABLED,
+};
+
+enum rte_eth_dev_power_mgmt_cb_mode {
+	/** WAIT callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_WAIT = 1,
+	/** PAUSE callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_PAUSE,
+	/** Freq Scaling callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_SCALE,
+};
+
 struct rte_eth_dev_sriov {
 	uint8_t active;               /**< SRIOV is active with 16, 32 or 64 pools */
 	uint8_t nb_q_per_pool;        /**< rx queue number per pool */
lib/librte_ethdev/rte_ethdev_core.h +44 -2

70 lines not on this page · raw message

Signature · 1 line
2.17.1
#180 lore raw

RFC PATCH v3 3/6 power: add simple power management API and callback

In reply to Liang Ma

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API is limited to 1 core 1 port 1 queue use case as there is no coordination between queues/cores in ethdev. 1 port map to multiple core will be supported in next version.

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

---
 lib/librte_power/meson.build           |   3 +-
 lib/librte_power/rte_power.h           |  38 +++++
 lib/librte_power/rte_power_pmd_mgmt.c  | 184 +++++++++++++++++++++++++
 lib/librte_power/rte_power_version.map |   4 +
 4 files changed, 228 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
lib/librte_power/meson.build +2 -1
index 78c031c943..44b01afce2 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
 headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+deps += ['timer' ,'ethdev']
lib/librte_power/rte_power.h +38 -0
index bbbde4dfb4..06d5a9984f 100644
@@ -14,6 +14,7 @@
 #include <rte_byteorder.h>
 #include <rte_log.h>
 #include <rte_string_fns.h>
+#include <rte_ethdev.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -97,6 +98,43 @@ int rte_power_init(unsigned int lcore_id);
  */
 int rte_power_exit(unsigned int lcore_id);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Enable device power management.
+ * @param lcore_id
+ *   lcore id.
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mode
+ *   The power management callback function mode.
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int rte_power_pmd_mgmt_enable(unsigned int lcore_id,
+				  uint16_t port_id,
+				  enum rte_eth_dev_power_mgmt_cb_mode mode);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Disable device power management.
+ * @param lcore_id
+ *   lcore id.
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ *
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int rte_power_pmd_mgmt_disable(unsigned int lcore_id, uint16_t port_id);
+
 /**
  * Get the available frequencies of a specific lcore.
  * Function pointer definition. Review each environments
lib/librte_power/rte_power_pmd_mgmt.c new file +184 -0

184 lines not on this page · raw message

lib/librte_power/rte_power_version.map +4 -0
index 00ee5753e2..ade83cfd4f 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+	# added in 20.08
+	rte_power_pmd_mgmt_disable;
+	rte_power_pmd_mgmt_enable;
+
 };
Signature · 1 line
2.17.1
#181 lore raw

RFC PATCH v3 4/6 net/ixgbe: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index fd0cb9b0e2..618fc15732 100644
@@ -592,6 +592,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.next_rx_desc         = ixgbe_next_rx_desc,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
index 977ecf5137..d1d015deae 100644
@@ -1366,6 +1366,28 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
index 7e09291b22..826f451bee 100644
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
#182 lore raw

RFC PATCH v3 5/6 net/i40e: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 11c02b1888..94e9298d7c 100644
@@ -517,6 +517,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.next_rx_desc	              = i40e_next_rx_desc,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
index fe7f9200c1..9d7eea8aed 100644
@@ -71,6 +71,29 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +2 -0
index 57d7b4160b..bfda5b6ad3 100644
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.17.1
#183 lore raw

RFC PATCH v3 6/6 net/ice: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index 8d435e8892..7d7e1dcbac 100644
@@ -212,6 +212,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.next_rx_desc	              = ice_next_rx_desc,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
index 2e1f06d2c0..c043181ceb 100644
@@ -24,6 +24,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 
+int ice_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.status_error0;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+	*mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+
+	return 0;
+}
+
+
 static inline uint64_t
 ice_rxdid_to_proto_xtr_ol_flag(uint8_t rxdid)
 {
drivers/net/ice/ice_rxtx.h +2 -0
index 2fdcfb7d04..7eb6fa904e 100644
@@ -202,5 +202,7 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 				uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _ICE_RXTX_H_ */
Signature · 1 line
2.17.1
#184 lore raw

PATCH v3 1/6 eal: add power management intrinsics

In reply to Liang Ma

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

---
 .../include/generic/rte_power_intrinsics.h    |  64 ++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/x86/include/meson.build        |   1 +
 lib/librte_eal/x86/include/rte_cpuflags.h     |   2 +
 .../x86/include/rte_power_intrinsics.h        | 143 ++++++++++++++++++
 lib/librte_eal/x86/rte_cpuflags.c             |   2 +
 6 files changed, 213 insertions(+)
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
new file mode 100644
index 0000000000..cd7f8070ac
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_H_
+#define _RTE_POWER_INTRINSIC_H_
+
+#include <inttypes.h>
+
+/**
+ * @file
+ * Advanced power management operations.
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, or a certain TSC timestamp is reached.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp);
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_pause(const uint32_t state,
+		const uint64_t tsc_timestamp);
+
+#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
index c1d20364d1..5041a830a7 100644
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	/**< UMWAIT/TPAUSE Instructions */
+	RTE_CPUFLAG_WAITPKG,                /**< UMINITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +143 -0

143 lines not on this page · raw message

lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#185 lore raw

PATCH v3 2/6 ethdev: add simple power management API

Add a simple API allow ethdev get the last available queue descriptor address from PMD. Also include internal structure update.

---
 lib/librte_ethdev/rte_ethdev.h      | 22 ++++++++++++++
 lib/librte_ethdev/rte_ethdev_core.h | 46 +++++++++++++++++++++++++++--
 2 files changed, 66 insertions(+), 2 deletions(-)
lib/librte_ethdev/rte_ethdev.h +22 -0
index 70295d7ab7..d9312d3e11 100644
@@ -157,6 +157,7 @@ extern "C" {
 #include <rte_common.h>
 #include <rte_config.h>
 #include <rte_ether.h>
+#include <rte_power_intrinsics.h>
 
 #include "rte_ethdev_trace_fp.h"
 #include "rte_dev_info.h"
@@ -775,6 +776,7 @@ rte_eth_rss_hf_refine(uint64_t rss_hf)
 /** Maximum nb. of vlan per mirror rule */
 #define ETH_MIRROR_MAX_VLANS       64
 
+#define ETH_EMPTYPOLL_MAX          512 /**< Empty poll number threshlold */
 #define ETH_MIRROR_VIRTUAL_POOL_UP     0x01  /**< Virtual Pool uplink Mirroring. */
 #define ETH_MIRROR_UPLINK_PORT         0x02  /**< Uplink Port Mirroring. */
 #define ETH_MIRROR_DOWNLINK_PORT       0x04  /**< Downlink Port Mirroring. */
@@ -1602,6 +1604,26 @@ enum rte_eth_dev_state {
 	RTE_ETH_DEV_REMOVED,
 };
 
+#define  RTE_ETH_PAUSE_NUM  64    /* How many times to pause */
+/**
+ * Possible power management states of an ethdev port.
+ */
+enum rte_eth_dev_power_mgmt_state {
+	/** Device power management is disabled. */
+	RTE_ETH_DEV_POWER_MGMT_DISABLED = 0,
+	/** Device power management is enabled. */
+	RTE_ETH_DEV_POWER_MGMT_ENABLED,
+};
+
+enum rte_eth_dev_power_mgmt_cb_mode {
+	/** WAIT callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_WAIT = 1,
+	/** PAUSE callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_PAUSE,
+	/** Freq Scaling callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_SCALE,
+};
+
 struct rte_eth_dev_sriov {
 	uint8_t active;               /**< SRIOV is active with 16, 32 or 64 pools */
 	uint8_t nb_q_per_pool;        /**< rx queue number per pool */
lib/librte_ethdev/rte_ethdev_core.h +44 -2

70 lines not on this page · raw message

Signature · 1 line
2.17.1
#186 lore raw

Re: [dpdk-dev] [PATCH v3 2/6] ethdev: add simple power management API

Quoted 1 line · On Fri, 4 Sep 2020 11:18:56 +0100 Liang Ma <[email protected]> wrote:

+#define ETH_EMPTYPOLL_MAX 512 /**< Empty poll number threshlold */

Spelling here.

Also, shouldn't this be a per-device (or per-queue) configuration value.

#187 lore raw

Re: [dpdk-dev] [PATCH v3 2/6] ethdev: add simple power management API

agree, will be addressed

Quoted 10 lines · Stephen Hemminger
Quoted 1 line · On Fri, 4 Sep 2020 11:18:56 +0100 Liang Ma <[email protected]> wrote:

+#define ETH_EMPTYPOLL_MAX 512 /**< Empty poll number threshlold */

Spelling here.

Also, shouldn't this be a per-device (or per-queue) configuration value.

#188 lore raw

Re: [dpdk-dev] [PATCH v3 2/6] ethdev: add simple power management API

In reply to Liang Ma
Quoted 45 lines

Add a simple API allow ethdev get the last available queue descriptor address from PMD. Also include internal structure update.

---
 lib/librte_ethdev/rte_ethdev.h      | 22 ++++++++++++++
 lib/librte_ethdev/rte_ethdev_core.h | 46 +++++++++++++++++++++++++++--
 2 files changed, 66 insertions(+), 2 deletions(-)
lib/librte_ethdev/rte_ethdev.h +12 -0
index 70295d7ab7..d9312d3e11 100644
@@ -157,6 +157,7 @@ extern "C" {
 #include <rte_common.h>
 #include <rte_config.h>
 #include <rte_ether.h>
+#include <rte_power_intrinsics.h>
 
 #include "rte_ethdev_trace_fp.h"
 #include "rte_dev_info.h"
@@ -775,6 +776,7 @@ rte_eth_rss_hf_refine(uint64_t rss_hf)
 /** Maximum nb. of vlan per mirror rule */
 #define ETH_MIRROR_MAX_VLANS       64
 
+#define ETH_EMPTYPOLL_MAX          512 /**< Empty poll number threshlold */
 #define ETH_MIRROR_VIRTUAL_POOL_UP     0x01  /**< Virtual Pool uplink Mirroring. */
 #define ETH_MIRROR_UPLINK_PORT         0x02  /**< Uplink Port Mirroring. */
 #define ETH_MIRROR_DOWNLINK_PORT       0x04  /**< Downlink Port Mirroring. */
@@ -1602,6 +1604,26 @@ enum rte_eth_dev_state {
 	RTE_ETH_DEV_REMOVED,
 };
 
+#define  RTE_ETH_PAUSE_NUM  64    /* How many times to pause */
+/**
+ * Possible power management states of an ethdev port.
+ */
+enum rte_eth_dev_power_mgmt_state {
+	/** Device power management is disabled. */
+	RTE_ETH_DEV_POWER_MGMT_DISABLED = 0,
+	/** Device power management is enabled. */
+	RTE_ETH_DEV_POWER_MGMT_ENABLED,
+};

lib/librte_ethdev/rte_ethdev.h enum rte_eth_dev_state { · line 1626

Quoted 10 lines
lib/librte_ethdev/rte_ethdev.h +10 -0
+
+enum rte_eth_dev_power_mgmt_cb_mode {
+	/** WAIT callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_WAIT = 1,
+	/** PAUSE callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_PAUSE,
+	/** Freq Scaling callback mode. */
+	RTE_ETH_DEV_POWER_MGMT_CB_SCALE,
+};
+

I don't think we need to put all these power related staff into rte_ethdev library.
rte_power or so, seems like much better place for it.

Quoted 25 lines
lib/librte_ethdev/rte_ethdev.h +0 -0
 struct rte_eth_dev_sriov {
 	uint8_t active;               /**< SRIOV is active with 16, 32 or 64 pools */
 	uint8_t nb_q_per_pool;        /**< rx queue number per pool */
lib/librte_ethdev/rte_ethdev_core.h +14 -0
index 32407dd418..16e54bb4e4 100644
@@ -603,6 +603,30 @@ typedef int (*eth_tx_hairpin_queue_setup_t)
 	 uint16_t nb_tx_desc,
 	 const struct rte_eth_hairpin_conf *hairpin_conf);
 
+/**
+ * @internal
+ * Get the next RX ring descriptor address.
+ *
+ * @param rxq
+ *   ethdev queue pointer.
+ * @param tail_desc_addr
+ *   the pointer point to descriptor address var.
+ * @param expected
+ *   the pointer point to value to be expected when descriptor is set.
+ * @param mask
+ *   the pointer point to comparison bitmask for the expected value.
+ * @return
+ *   Negative errno value on error, 0 on success.

lib/librte_ethdev/rte_ethdev_core.h typedef int (*eth_tx_hairpin_queue_setup_t) · line 629

Quoted 10 lines
lib/librte_ethdev/rte_ethdev_core.h +10 -0
+ *
+ * @retval 0
+ *   Success.
+ * @retval -EINVAL
+ *   Failed to get descriptor address.
+ */
+typedef int (*eth_next_rx_desc_t)
+	(void *rxq, volatile void **tail_desc_addr,
+	 uint64_t *expected, uint64_t *mask);
+

In theory it could be anything: next RXD, doorbell, even some global variable.
So I think function name needs to be more neutral:
eth_rx_wait_addr() or so.
Also I think you need a new rte_eth_ wrapper function for that dev op.

Quoted 48 lines
lib/librte_ethdev/rte_ethdev_core.h +20 -3
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -752,6 +776,8 @@ struct eth_dev_ops {
 	/**< Set up device RX hairpin queue. */
 	eth_tx_hairpin_queue_setup_t tx_hairpin_queue_setup;
 	/**< Set up device TX hairpin queue. */
+	eth_next_rx_desc_t next_rx_desc;
+	/**< Get next RX ring descriptor address. */
 };
 
 /**
@@ -768,6 +794,14 @@ struct rte_eth_rxtx_callback {
 	void *param;
 };
 
+/**
+ * @internal
+ * Structure used to hold counters for empty poll
+ */
+struct rte_eth_ep_stat {
+	uint64_t num;
+} __rte_cache_aligned;
+
 /**
  * @internal
  * The generic data structure associated with each ethernet device.
@@ -807,8 +841,16 @@ struct rte_eth_dev {
 	enum rte_eth_dev_state state; /**< Flag indicating the port state */
 	void *security_ctx; /**< Context for security ops */
 
-	uint64_t reserved_64s[4]; /**< Reserved for future fields */
-	void *reserved_ptrs[4];   /**< Reserved for future fields */
+	/**< Empty poll number */
+	enum rte_eth_dev_power_mgmt_state pwr_mgmt_state;
+	/**< Power mgmt Callback mode */
+	enum rte_eth_dev_power_mgmt_cb_mode cb_mode;
+	uint64_t reserved_64s[3]; /**< Reserved for future fields */
+
+	/**< Flag indicating the port power state */
+	struct rte_eth_ep_stat *empty_poll_stats;
+	const struct rte_eth_rxtx_callback *cur_pwr_cb;
+	void *reserved_ptrs[2];   /**< Reserved for future fields */
 } __rte_cache_aligned;
 
 struct rte_eth_dev_sriov;
--

2.17.1

#189 lore raw

PATCH v3 3/6 power: add simple power management API and callback

In reply to Liang Ma

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API is limited to 1 core 1 port 1 queue use case as there is no coordination between queues/cores in ethdev. 1 port map to multiple core will be supported in next version.

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

---
 lib/librte_power/meson.build           |   3 +-
 lib/librte_power/rte_power.h           |  38 +++++
 lib/librte_power/rte_power_pmd_mgmt.c  | 184 +++++++++++++++++++++++++
 lib/librte_power/rte_power_version.map |   4 +
 4 files changed, 228 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
lib/librte_power/meson.build +2 -1
index 78c031c943..44b01afce2 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
 headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+deps += ['timer' ,'ethdev']
lib/librte_power/rte_power.h +38 -0
index bbbde4dfb4..06d5a9984f 100644
@@ -14,6 +14,7 @@
 #include <rte_byteorder.h>
 #include <rte_log.h>
 #include <rte_string_fns.h>
+#include <rte_ethdev.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -97,6 +98,43 @@ int rte_power_init(unsigned int lcore_id);
  */
 int rte_power_exit(unsigned int lcore_id);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Enable device power management.
+ * @param lcore_id
+ *   lcore id.
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mode
+ *   The power management callback function mode.
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int rte_power_pmd_mgmt_enable(unsigned int lcore_id,
+				  uint16_t port_id,
+				  enum rte_eth_dev_power_mgmt_cb_mode mode);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Disable device power management.
+ * @param lcore_id
+ *   lcore id.
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ *
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int rte_power_pmd_mgmt_disable(unsigned int lcore_id, uint16_t port_id);
+
 /**
  * Get the available frequencies of a specific lcore.
  * Function pointer definition. Review each environments
lib/librte_power/rte_power_pmd_mgmt.c new file +184 -0

184 lines not on this page · raw message

lib/librte_power/rte_power_version.map +4 -0
index 00ee5753e2..ade83cfd4f 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+	# added in 20.08
+	rte_power_pmd_mgmt_disable;
+	rte_power_pmd_mgmt_enable;
+
 };
Signature · 1 line
2.17.1
#190 lore raw

Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback

Quoted 9 lines · On Fri, 4 Sep 2020 11:18:57 +0100 Liang Ma <[email protected]> wrote:

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API is limited to 1 core 1 port 1 queue use case as there is no coordination between queues/cores in ethdev. 1 port map to multiple core will be supported in next version.

The common way to express is this is:

This API is not thread-safe and not preempt-safe.
There is also no mechanism for a single thread to wait on multiple queues.

Quoted 3 lines

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

nit coexist is one word

Quoted 8 lines

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

Quoted 5 lines

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.

Wording here is a problem, and "releaf" should be "relief"? Rewording into active voice grammar would be easier.

Use Pause instruction to allow processor to go into deeper C state when busy polling.

Quoted 4 lines

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

#191 lore raw

Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback

<snip>
Hi Stephen,
v4 will support 1 port with multiple core(still 1 queue per core)support this part description will be updated according to the design change.
Regards
Liang

Quoted 38 lines

The common way to express is this is:

This API is not thread-safe and not preempt-safe.
There is also no mechanism for a single thread to wait on multiple queues.

Quoted 3 lines

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

nit coexist is one word

Quoted 8 lines

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

Quoted 5 lines

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.

Wording here is a problem, and "releaf" should be "relief"? Rewording into active voice grammar would be easier.

Use Pause instruction to allow processor to go into deeper C state when busy polling.

Quoted 4 lines

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

#192 lore raw

Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback

In reply to Liang Ma
Quoted 130 lines

Add a simple on/off switch that will enable saving power when no packets are arriving. It is based on counting the number of empty polls and, when the number reaches a certain threshold, entering an architecture-defined optimized power state that will either wait until a TSC timestamp expires, or when packets arrive.

This API is limited to 1 core 1 port 1 queue use case as there is no coordination between queues/cores in ethdev. 1 port map to multiple core will be supported in next version.

This design leverage RX Callback mechnaism which allow three different power management methodology co exist.

1. umwait/umonitor:

The TSC timestamp is automatically calculated using current link speed and RX descriptor ring size, such that the sleep time is not longer than it would take for a NIC to fill its entire RX descriptor ring.

2. Pause instruction

Instead of move the core into deeper C state, this lightweight method use Pause instruction to releaf the processor from busy polling.

3. Frequency Scaling
Reuse exist rte power library to scale up/down core frequency depend on traffic volume.

---
 lib/librte_power/meson.build           |   3 +-
 lib/librte_power/rte_power.h           |  38 +++++
 lib/librte_power/rte_power_pmd_mgmt.c  | 184 +++++++++++++++++++++++++
 lib/librte_power/rte_power_version.map |   4 +
 4 files changed, 228 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_power/rte_power_pmd_mgmt.c
lib/librte_power/meson.build +2 -1
index 78c031c943..44b01afce2 100644
@@ -9,6 +9,7 @@ sources = files('rte_power.c', 'power_acpi_cpufreq.c',
 		'power_kvm_vm.c', 'guest_channel.c',
 		'rte_power_empty_poll.c',
 		'power_pstate_cpufreq.c',
+		'rte_power_pmd_mgmt.c',
 		'power_common.c')
 headers = files('rte_power.h','rte_power_empty_poll.h')
-deps += ['timer']
+deps += ['timer' ,'ethdev']
lib/librte_power/rte_power.h +38 -0
index bbbde4dfb4..06d5a9984f 100644
@@ -14,6 +14,7 @@
 #include <rte_byteorder.h>
 #include <rte_log.h>
 #include <rte_string_fns.h>
+#include <rte_ethdev.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -97,6 +98,43 @@ int rte_power_init(unsigned int lcore_id);
  */
 int rte_power_exit(unsigned int lcore_id);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Enable device power management.
+ * @param lcore_id
+ *   lcore id.
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param mode
+ *   The power management callback function mode.
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int rte_power_pmd_mgmt_enable(unsigned int lcore_id,
+				  uint16_t port_id,
+				  enum rte_eth_dev_power_mgmt_cb_mode mode);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Disable device power management.
+ * @param lcore_id
+ *   lcore id.
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ *
+ * @return
+ *   0 on success
+ *   <0 on error
+ */
+__rte_experimental
+int rte_power_pmd_mgmt_disable(unsigned int lcore_id, uint16_t port_id);
+
 /**
  * Get the available frequencies of a specific lcore.
  * Function pointer definition. Review each environments
lib/librte_power/rte_power_pmd_mgmt.c new file +14 -0
new file mode 100644
index 0000000000..a445153ede
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2020 Intel Corporation
+ */
+
+#include <rte_lcore.h>
+#include <rte_cycles.h>
+#include <rte_atomic.h>
+#include <rte_malloc.h>
+#include <rte_ethdev.h>
+
+#include "rte_power.h"
+
+
+

lib/librte_power/rte_power_pmd_mgmt.c line 24

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+static uint16_t
+rte_power_mgmt_umwait(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+	if (unlikely(nb_rx == 0)) {
+		dev->empty_poll_stats[qidx].num++;

I believe there are two fundamental issues with that approach:
1. You put metadata specific lib (power) callbacks into rte_eth_dev struct.
2. These callbacks do access rte_eth_devices[] directly.
That doesn't look right to me - rte_eth_dev structure supposed to be treated as internal one librt_ether and underlying drivers and should be accessed directly by outer code.
If these callbacks need some extra metadata, then it is responsibility
of power library to allocate/manage these metadata.
You can pass pointer to this metadata via last parameter for rte_eth_add_rx_callback().

Quoted 91 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +91 -0
+		if (unlikely(dev->empty_poll_stats[qidx].num >
+			     ETH_EMPTYPOLL_MAX)) {
+			volatile void *target_addr;
+			uint64_t expected, mask;
+			uint16_t ret;
+
+			/*
+			 * get address of next descriptor in the RX
+			 * ring for this queue, as well as expected
+			 * value and a mask.
+			 */
+			ret = (*dev->dev_ops->next_rx_desc)
+				(dev->data->rx_queues[qidx],
+				 &target_addr, &expected, &mask);
+			if (ret == 0)
+				/* -1ULL is maximum value for TSC */
+				rte_power_monitor(target_addr,
+						  expected, mask,
+						  0, -1ULL);
+		}
+	} else
+		dev->empty_poll_stats[qidx].num = 0;
+
+	return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_pause(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+	int i;
+
+	if (unlikely(nb_rx == 0)) {
+
+		dev->empty_poll_stats[qidx].num++;
+
+		if (unlikely(dev->empty_poll_stats[qidx].num >
+			     ETH_EMPTYPOLL_MAX)) {
+
+			for (i = 0; i < RTE_ETH_PAUSE_NUM; i++)
+				rte_pause();
+
+		}
+	} else
+		dev->empty_poll_stats[qidx].num = 0;
+
+	return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_scalefreq(uint16_t port_id, uint16_t qidx,
+		struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+		uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+	if (unlikely(nb_rx == 0)) {
+		dev->empty_poll_stats[qidx].num++;
+		if (unlikely(dev->empty_poll_stats[qidx].num >
+			     ETH_EMPTYPOLL_MAX)) {
+
+			/*scale down freq */
+			rte_power_freq_min(rte_lcore_id());
+
+		}
+	} else {
+		dev->empty_poll_stats[qidx].num = 0;
+		/* scal up freq */
+		rte_power_freq_max(rte_lcore_id());
+	}
+
+	return nb_rx;
+}
+
+int
+rte_power_pmd_mgmt_enable(unsigned int lcore_id,
+			uint16_t port_id,
+			enum rte_eth_dev_power_mgmt_cb_mode mode)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	if (dev->pwr_mgmt_state == RTE_ETH_DEV_POWER_MGMT_ENABLED)
+		return -EINVAL;
+	/* allocate memory for empty poll stats */
+	dev->empty_poll_stats = rte_malloc_socket(NULL,

lib/librte_power/rte_power_pmd_mgmt.c line 125

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+						  sizeof(struct rte_eth_ep_stat)
+						  * RTE_MAX_QUEUES_PER_PORT,
+						  0, dev->data->numa_node);
+	if (dev->empty_poll_stats == NULL)
+		return -ENOMEM;
+
+	switch (mode) {
+	case RTE_ETH_DEV_POWER_MGMT_CB_WAIT:
+		if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG))
+			return -ENOTSUP;

Here and in other places: in case of error return you don't' free your empty_poll_stats.

lib/librte_power/rte_power_pmd_mgmt.c line 126

Quoted 1 line
lib/librte_power/rte_power_pmd_mgmt.c new file +1 -0
+		dev->cur_pwr_cb = rte_eth_add_rx_callback(port_id, 0,

Why zero for queue number, why not to pass queue_id as a parameter for that function?

lib/librte_power/rte_power_pmd_mgmt.c line 127

Quoted 1 line
lib/librte_power/rte_power_pmd_mgmt.c new file +1 -0
+						rte_power_mgmt_umwait, NULL);

As I said above, instead of NULL - could be pointer to metadata struct.

Quoted 25 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +25 -0
+		break;
+	case RTE_ETH_DEV_POWER_MGMT_CB_SCALE:
+		/* init scale freq */
+		if (rte_power_init(lcore_id))
+			return -EINVAL;
+		dev->cur_pwr_cb = rte_eth_add_rx_callback(port_id, 0,
+					rte_power_mgmt_scalefreq, NULL);
+		break;
+	case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE:
+		dev->cur_pwr_cb = rte_eth_add_rx_callback(port_id, 0,
+						rte_power_mgmt_pause, NULL);
+		break;
+	}
+
+	dev->cb_mode = mode;
+	dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_ENABLED;
+	return 0;
+}
+
+int
+rte_power_pmd_mgmt_disable(unsigned int lcore_id,
+				uint16_t port_id)
+{
+	struct rte_eth_dev *dev;
+

lib/librte_power/rte_power_pmd_mgmt.c line 162

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+	dev = &rte_eth_devices[port_id];
+
+	/*add flag check */
+
+	if (dev->pwr_mgmt_state == RTE_ETH_DEV_POWER_MGMT_DISABLED)
+		return -EINVAL;
+
+	/* rte_free ignores NULL so safe to call without checks */
+	rte_free(dev->empty_poll_stats);

You can't free callback metadata before removing the callback itself. In fact, with current rx callback code it is not safe to free it even after (we discussed it offline).

lib/librte_power/rte_power_pmd_mgmt.c line 171

Quoted 9 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +9 -0
+
+	switch (dev->cb_mode) {
+	case RTE_ETH_DEV_POWER_MGMT_CB_WAIT:
+	case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE:
+		rte_eth_remove_rx_callback(port_id, 0,
+					   dev->cur_pwr_cb);
+		break;
+	case RTE_ETH_DEV_POWER_MGMT_CB_SCALE:
+		rte_power_freq_max(lcore_id);

Stupid q: what makes you think that lcore frequency was max, *before* you setup the callback?

Quoted 28 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13 -0
+		rte_eth_remove_rx_callback(port_id, 0,
+					   dev->cur_pwr_cb);
+		if (rte_power_exit(lcore_id))
+			return -EINVAL;
+		break;
+	}
+
+	dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_DISABLED;
+	dev->cur_pwr_cb = NULL;
+	dev->cb_mode = 0;
+
+	return 0;
+}
lib/librte_power/rte_power_version.map +4 -1
index 00ee5753e2..ade83cfd4f 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 	rte_power_guest_channel_receive_msg;
 	rte_power_poll_stat_fetch;
 	rte_power_poll_stat_update;
+	# added in 20.08
+	rte_power_pmd_mgmt_disable;
+	rte_power_pmd_mgmt_enable;
+
 };
--

2.17.1

#193 lore raw

Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback

On 04 Sep 11:33, Ananyev, Konstantin wrote:

<snip>

Quoted 5 lines

lib/librte_power/rte_power_pmd_mgmt.c line 24

Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4 -0
+struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+if (unlikely(nb_rx == 0)) {
+dev->empty_poll_stats[qidx].num++;

Hi Konstantin,
Agree, v4 will relocate the meta data to seperate structure. and without touch the rte_ethdev structure.

Quoted 114 lines

I believe there are two fundamental issues with that approach:
1. You put metadata specific lib (power) callbacks into rte_eth_dev struct.
2. These callbacks do access rte_eth_devices[] directly.
That doesn't look right to me - rte_eth_dev structure supposed to be treated as internal one librt_ether and underlying drivers and should be accessed directly by outer code.
If these callbacks need some extra metadata, then it is responsibility
of power library to allocate/manage these metadata.
You can pass pointer to this metadata via last parameter for rte_eth_add_rx_callback().

Quoted 91 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +91 -0
+if (unlikely(dev->empty_poll_stats[qidx].num >
+     ETH_EMPTYPOLL_MAX)) {
+volatile void *target_addr;
+uint64_t expected, mask;
+uint16_t ret;
+
+/*
+ * get address of next descriptor in the RX
+ * ring for this queue, as well as expected
+ * value and a mask.
+ */
+ret = (*dev->dev_ops->next_rx_desc)
+(dev->data->rx_queues[qidx],
+ &target_addr, &expected, &mask);
+if (ret == 0)
+/* -1ULL is maximum value for TSC */
+rte_power_monitor(target_addr,
+  expected, mask,
+  0, -1ULL);
+}
+} else
+dev->empty_poll_stats[qidx].num = 0;
+
+return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_pause(uint16_t port_id, uint16_t qidx,
+struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+int i;
+
+if (unlikely(nb_rx == 0)) {
+
+dev->empty_poll_stats[qidx].num++;
+
+if (unlikely(dev->empty_poll_stats[qidx].num >
+     ETH_EMPTYPOLL_MAX)) {
+
+for (i = 0; i < RTE_ETH_PAUSE_NUM; i++)
+rte_pause();
+
+}
+} else
+dev->empty_poll_stats[qidx].num = 0;
+
+return nb_rx;
+}
+
+static uint16_t
+rte_power_mgmt_scalefreq(uint16_t port_id, uint16_t qidx,
+struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx,
+uint16_t max_pkts __rte_unused, void *_  __rte_unused)
+{
+struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+
+if (unlikely(nb_rx == 0)) {
+dev->empty_poll_stats[qidx].num++;
+if (unlikely(dev->empty_poll_stats[qidx].num >
+     ETH_EMPTYPOLL_MAX)) {
+
+/*scale down freq */
+rte_power_freq_min(rte_lcore_id());
+
+}
+} else {
+dev->empty_poll_stats[qidx].num = 0;
+/* scal up freq */
+rte_power_freq_max(rte_lcore_id());
+}
+
+return nb_rx;
+}
+
+int
+rte_power_pmd_mgmt_enable(unsigned int lcore_id,
+uint16_t port_id,
+enum rte_eth_dev_power_mgmt_cb_mode mode)
+{
+struct rte_eth_dev *dev;
+
+RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+dev = &rte_eth_devices[port_id];
+
+if (dev->pwr_mgmt_state == RTE_ETH_DEV_POWER_MGMT_ENABLED)
+return -EINVAL;
+/* allocate memory for empty poll stats */
+dev->empty_poll_stats = rte_malloc_socket(NULL,

lib/librte_power/rte_power_pmd_mgmt.c line 125

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +10 -0
+  sizeof(struct rte_eth_ep_stat)
+  * RTE_MAX_QUEUES_PER_PORT,
+  0, dev->data->numa_node);
+if (dev->empty_poll_stats == NULL)
+return -ENOMEM;
+
+switch (mode) {
+case RTE_ETH_DEV_POWER_MGMT_CB_WAIT:
+if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG))
+return -ENOTSUP;

Here and in other places: in case of error return you don't' free your empty_poll_stats.

Quoted 3 lines
Quoted 1 line

+dev->cur_pwr_cb = rte_eth_add_rx_callback(port_id, 0,

Why zero for queue number, why not to pass queue_id as a parameter for that function?

v4 will move to use queue_id instead of 0. v3 still assume only queue 0 is used.

Quoted 4 lines
Quoted 2 lines

+rte_power_mgmt_umwait, NULL);

As I said above, instead of NULL - could be pointer to metadata struct.

v4 will address this.

Quoted 32 lines
Quoted 32 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +31 -0
+break;
+case RTE_ETH_DEV_POWER_MGMT_CB_SCALE:
+/* init scale freq */
+if (rte_power_init(lcore_id))
+return -EINVAL;
+dev->cur_pwr_cb = rte_eth_add_rx_callback(port_id, 0,
+rte_power_mgmt_scalefreq, NULL);
+break;
+case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE:
+dev->cur_pwr_cb = rte_eth_add_rx_callback(port_id, 0,
+rte_power_mgmt_pause, NULL);
+break;
+}
+
+dev->cb_mode = mode;
+dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_ENABLED;
+return 0;
+}
+
+int
+rte_power_pmd_mgmt_disable(unsigned int lcore_id,
+uint16_t port_id)
+{
+struct rte_eth_dev *dev;
+
+RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
+dev = &rte_eth_devices[port_id];
+
+/*add flag check */
+
+if (dev->pwr_mgmt_state == RTE_ETH_DEV_POWER_MGMT_DISABLED)
Quoted 8 lines

lib/librte_power/rte_power_pmd_mgmt.c line 162

Quoted 4 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +4 -0
+return -EINVAL;
+
+/* rte_free ignores NULL so safe to call without checks */
+rte_free(dev->empty_poll_stats);

You can't free callback metadata before removing the callback itself. In fact, with current rx callback code it is not safe to free it even after (we discussed it offline).

agree.

Quoted 13 lines

lib/librte_power/rte_power_pmd_mgmt.c line 171

Quoted 10 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +9 -0
+
+switch (dev->cb_mode) {
+case RTE_ETH_DEV_POWER_MGMT_CB_WAIT:
+case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE:
+rte_eth_remove_rx_callback(port_id, 0,
+   dev->cur_pwr_cb);
+break;
+case RTE_ETH_DEV_POWER_MGMT_CB_SCALE:
+rte_power_freq_max(lcore_id);

Stupid q: what makes you think that lcore frequency was max, *before* you setup the callback?

that is because the rte_power_init() has figured out the system max. the init code invocate rte_power_init() already.

Quoted 30 lines
Quoted 29 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13 -0
+rte_eth_remove_rx_callback(port_id, 0,
+   dev->cur_pwr_cb);
+if (rte_power_exit(lcore_id))
+return -EINVAL;
+break;
+}
+
+dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_DISABLED;
+dev->cur_pwr_cb = NULL;
+dev->cb_mode = 0;
+
+return 0;
+}
lib/librte_power/rte_power_version.map +4 -1
index 00ee5753e2..ade83cfd4f 100644
@@ -34,4 +34,8 @@ EXPERIMENTAL {
 rte_power_guest_channel_receive_msg;
 rte_power_poll_stat_fetch;
 rte_power_poll_stat_update;
+# added in 20.08
+rte_power_pmd_mgmt_disable;
+rte_power_pmd_mgmt_enable;
+
 };
--

2.17.1

#194 lore raw

Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback

Quoted 15 lines
Quoted 15 lines

lib/librte_power/rte_power_pmd_mgmt.c line 171

Quoted 12 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +9 -0
+
+switch (dev->cb_mode) {
+case RTE_ETH_DEV_POWER_MGMT_CB_WAIT:
+case RTE_ETH_DEV_POWER_MGMT_CB_PAUSE:
+rte_eth_remove_rx_callback(port_id, 0,
+   dev->cur_pwr_cb);
+break;
+case RTE_ETH_DEV_POWER_MGMT_CB_SCALE:
+rte_power_freq_max(lcore_id);

Stupid q: what makes you think that lcore frequency was max, *before* you setup the callback?

Quoted 2 lines

that is because the rte_power_init() has figured out the system max. the init code invocate rte_power_init() already.

So rte_power_init(lcore) always raises lcore frequency to max possible value?

Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13 -0
+rte_eth_remove_rx_callback(port_id, 0,
+   dev->cur_pwr_cb);
+if (rte_power_exit(lcore_id))
+return -EINVAL;
+break;
+}
+
+dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_DISABLED;
+dev->cur_pwr_cb = NULL;
+dev->cb_mode = 0;
+
+return 0;
+}
#195 lore raw

Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback

On 16 Sep 07:53, Ananyev, Konstantin wrote:
<snip>
Yes. we only has two gear. min or max. However, user still can customize their system max with power mgmt python script on Intel platform.

Quoted 17 lines

So rte_power_init(lcore) always raises lcore frequency to max possible value?

Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13 -0
+rte_eth_remove_rx_callback(port_id, 0,
+   dev->cur_pwr_cb);
+if (rte_power_exit(lcore_id))
+return -EINVAL;
+break;
+}
+
+dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_DISABLED;
+dev->cur_pwr_cb = NULL;
+dev->cb_mode = 0;
+
+return 0;
+}
#196 lore raw

Re: [dpdk-dev] [PATCH v3 3/6] power: add simple power management API and callback

Quoted 4 lines · Konstantin

<snip>
Yes. we only has two gear. min or max. However, user still can customize their system max with power mgmt python script on Intel platform.

Ok, thanks for explanation.

Quoted 17 lines
Quoted 17 lines

So rte_power_init(lcore) always raises lcore frequency to max possible value?

Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
lib/librte_power/rte_power_pmd_mgmt.c new file +13 -0
+rte_eth_remove_rx_callback(port_id, 0,
+   dev->cur_pwr_cb);
+if (rte_power_exit(lcore_id))
+return -EINVAL;
+break;
+}
+
+dev->pwr_mgmt_state = RTE_ETH_DEV_POWER_MGMT_DISABLED;
+dev->cur_pwr_cb = NULL;
+dev->cb_mode = 0;
+
+return 0;
+}
#197 lore raw

PATCH v3 4/6 net/ixgbe: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/ixgbe/ixgbe_ethdev.c |  1 +
 drivers/net/ixgbe/ixgbe_rxtx.c   | 22 ++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_rxtx.h   |  2 ++
 3 files changed, 25 insertions(+)
drivers/net/ixgbe/ixgbe_ethdev.c +1 -0
index fd0cb9b0e2..618fc15732 100644
@@ -592,6 +592,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.udp_tunnel_port_del  = ixgbe_dev_udp_tunnel_port_del,
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
+	.next_rx_desc         = ixgbe_next_rx_desc,
 };
 
 /*
drivers/net/ixgbe/ixgbe_rxtx.c +22 -0
index 977ecf5137..d1d015deae 100644
@@ -1366,6 +1366,28 @@ const uint32_t
 		RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
 };
 
+int ixgbe_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ixgbe_adv_rx_desc *rxdp;
+	struct ixgbe_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.upper.status_error;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+	*mask = rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD);
+
+	return 0;
+}
+
 /* @note: fix ixgbe_dev_supported_ptypes_get() if any change here. */
 static inline uint32_t
 ixgbe_rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint16_t ptype_mask)
drivers/net/ixgbe/ixgbe_rxtx.h +2 -0
index 7e09291b22..826f451bee 100644
@@ -299,5 +299,7 @@ uint64_t ixgbe_get_tx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_queue_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_rx_port_offloads(struct rte_eth_dev *dev);
 uint64_t ixgbe_get_tx_queue_offloads(struct rte_eth_dev *dev);
+int ixgbe_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _IXGBE_RXTX_H_ */
Signature · 1 line
2.17.1
#198 lore raw

PATCH v3 5/6 net/i40e: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/i40e/i40e_ethdev.c |  1 +
 drivers/net/i40e/i40e_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/i40e/i40e_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/i40e/i40e_ethdev.c +1 -0
index 11c02b1888..94e9298d7c 100644
@@ -517,6 +517,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
 	.mtu_set                      = i40e_dev_mtu_set,
 	.tm_ops_get                   = i40e_tm_ops_get,
 	.tx_done_cleanup              = i40e_tx_done_cleanup,
+	.next_rx_desc	              = i40e_next_rx_desc,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/i40e/i40e_rxtx.c +23 -0
index fe7f9200c1..9d7eea8aed 100644
@@ -71,6 +71,29 @@
 #define I40E_TX_OFFLOAD_NOTSUP_MASK \
 		(PKT_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_MASK)
 
+int
+i40e_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rxdp;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.qword1.status_error_len;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+	*mask = rte_cpu_to_le_64(1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+	return 0;
+}
+
 static inline void
 i40e_rxd_to_vlan_tci(struct rte_mbuf *mb, volatile union i40e_rx_desc *rxdp)
 {
drivers/net/i40e/i40e_rxtx.h +2 -0
index 57d7b4160b..bfda5b6ad3 100644
@@ -248,6 +248,8 @@ uint16_t i40e_recv_scattered_pkts_vec_avx2(void *rx_queue,
 	struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 uint16_t i40e_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 	uint16_t nb_pkts);
+int i40e_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *value);
 
 /* For each value it means, datasheet of hardware can tell more details
  *
Signature · 1 line
2.17.1
#199 lore raw

PATCH v3 6/6 net/ice: implement power management API

In reply to Liang Ma

Implement support for the power management API by implementing a next_rx_desc function that will return an address of an RX ring's status bit.

---
 drivers/net/ice/ice_ethdev.c |  1 +
 drivers/net/ice/ice_rxtx.c   | 23 +++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |  2 ++
 3 files changed, 26 insertions(+)
drivers/net/ice/ice_ethdev.c +1 -0
index 8d435e8892..7d7e1dcbac 100644
@@ -212,6 +212,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
 	.udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
 	.udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
 	.tx_done_cleanup              = ice_tx_done_cleanup,
+	.next_rx_desc	              = ice_next_rx_desc,
 };
 
 /* store statistics names and its offset in stats structure */
drivers/net/ice/ice_rxtx.c +23 -0
index 2e1f06d2c0..c043181ceb 100644
@@ -24,6 +24,29 @@ uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_ipv6_flow_mask;
 uint64_t rte_net_ice_dynflag_proto_xtr_tcp_mask;
 
+int ice_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask)
+{
+	volatile union ice_rx_flex_desc *rxdp;
+	struct ice_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+
+	desc = rxq->rx_tail;
+	rxdp = &rxq->rx_ring[desc];
+	/* watch for changes in status bit */
+	*tail_desc_addr = &rxdp->wb.status_error0;
+
+	/*
+	 * we expect the DD bit to be set to 1 if this descriptor was already
+	 * written to.
+	 */
+	*expected = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+	*mask = rte_cpu_to_le_16(1 << ICE_RX_FLEX_DESC_STATUS0_DD_S);
+
+	return 0;
+}
+
+
 static inline uint64_t
 ice_rxdid_to_proto_xtr_ol_flag(uint8_t rxdid)
 {
drivers/net/ice/ice_rxtx.h +2 -0
index 2fdcfb7d04..7eb6fa904e 100644
@@ -202,5 +202,7 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
 				uint16_t nb_pkts);
 int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
 int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
+int ice_next_rx_desc(void *rx_queue, volatile void **tail_desc_addr,
+		uint64_t *expected, uint64_t *mask);
 
 #endif /* _ICE_RXTX_H_ */
Signature · 1 line
2.17.1
#200 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

In reply to Liang Ma

lib/librte_eal/include/generic/rte_power_intrinsics.h line 46

Quoted 7 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:

+ *
+ * @return
+ * Architecture-dependent return value.
+ */

lib/librte_eal/include/generic/rte_power_intrinsics.h new file +3 -0
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp);

Since this is generic code, and you are defining the function. You should have it return -ENOTSUPPORTED or -EINVAL.

#201 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

Hi Stephen,
Agree. v4 will address this.
Regards
Liang

Quoted 13 lines · Stephen Hemminger

lib/librte_eal/include/generic/rte_power_intrinsics.h line 46

Quoted 7 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:

+ *
+ * @return
+ * Architecture-dependent return value.
+ */

lib/librte_eal/include/generic/rte_power_intrinsics.h new file +3 -0
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp);

Since this is generic code, and you are defining the function. You should have it return -ENOTSUPPORTED or -EINVAL.

#202 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

In reply to Liang Ma
Quoted 12 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 2 lines

This looks like a useful feature but needs more documentation and example. It would make sense to put an example in l3fwd-power.

#203 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

Hi Stephen,
v4 patch will include the l3fwd-power udpate.
Regards
Liang

Quoted 21 lines · Stephen Hemminger
Quoted 12 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 2 lines

This looks like a useful feature but needs more documentation and example. It would make sense to put an example in l3fwd-power.

#204 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

In reply to Liang Ma
Quoted 12 lines · On Fri, 4 Sep 2020 11:18:55 +0100 Liang Ma <[email protected]> wrote:

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 2 lines

Before this is merged, please work with Arm maintainers to have a version that works on Arm 64 as well. Don't think this should be merged unless the two major platforms supported by DPDK can work with it.

Also, not sure if this mechanism can work with other drivers. You need to work with other vendors to show that the same infrastructure can work with their hardware. Once again, I don't think this can go in if it only can work on Intel. It needs to work on Broadcom, Mellanox to be useful.

Will it work in a VM? Will it work with virtio or vmxnet3?

Having a single vendor solution is a non-starter for me. They don't all have to be there to get it merged, but if the design only works on single platform then it is not helpful.

#205 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

On 04 Sep 11:42, Stephen Hemminger wrote:
<snip>
we are very open to discuss design with other vendor.

Quoted 8 lines

Before this is merged, please work with Arm maintainers to have a version that works on Arm 64 as well. Don't think this should be merged unless the two major platforms supported by DPDK can work with it.

Also, not sure if this mechanism can work with other drivers. You need to work with other vendors to show that the same infrastructure can work with their hardware. Once again, I don't think this can go in if it only can work on Intel. It needs to work on Broadcom, Mellanox to be useful.

this mechanism should work with any device use a HW ring descriptor mechanism. I think most Mellanox and Broadcom NIC can support it easily.

Quoted 2 lines

Will it work in a VM? Will it work with virtio or vmxnet3?

General speaking, Guest OS is not very easy to use this. However, virtio is under invetigation.

Quoted 3 lines

Having a single vendor solution is a non-starter for me. They don't all have to be there to get it merged, but if the design only works on single platform then it is not helpful.

#206 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

In reply to Stephen Hemminger

On 04 Sep 11:42, Stephen Hemminger wrote:
<snip>

we have discussed with arm developer in the past.
Please ref https://patches.dpdk.org/patch/70662/
There was no objection, in my opinoin.
Also the API we proposed has experimental tag, other vendor still can change it.

For the ethdev internal ops we introduced should work with any NIC use ring descriptor writeback mechansim. But we lack the internal sight of Mellanox or Broadcom NIC.

AF_XDP PMD and virtio-net is under investigation.

I hope above explaination addressed your concern.

Quoted 14 lines

Before this is merged, please work with Arm maintainers to have a version that works on Arm 64 as well. Don't think this should be merged unless the two major platforms supported by DPDK can work with it.

Also, not sure if this mechanism can work with other drivers. You need to work with other vendors to show that the same infrastructure can work with their hardware. Once again, I don't think this can go in if it only can work on Intel. It needs to work on Broadcom, Mellanox to be useful.

Will it work in a VM? Will it work with virtio or vmxnet3?

Having a single vendor solution is a non-starter for me. They don't all have to be there to get it merged, but if the design only works on single platform then it is not helpful.

#207 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

In reply to Liang Ma

lib/librte_eal/x86/include/rte_power_intrinsics.h line 6

Quoted 13 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +6 -0
new file mode 100644
index 0000000000..6dd1cdc939
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_X86_64_H_
+#define _RTE_POWER_INTRINSIC_X86_64_H_

As a nit - if the function below are supported for both 64 and 32 ISA, then probably: RTE_POWER_INTRINSIC_X86_H_

Quoted 137 lines
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +137 -0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, or a certain TSC timestamp is reached.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * This function uses UMONITOR/UMWAIT instructions. For more information about
+ * their usage, please refer to Intel(R) 64 and IA-32 Architectures Software
+ * Developer's Manual.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param state
+ *   Architecture-dependent optimized power state number. Can be 0 (C0.2) or
+ *   1 (C0.1).
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 1 if wakeup was due to TSC timeout expiration.
+ *   - 0 if wakeup was due to memory write or other reasons.
+ */
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp)
+{
+	const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+	const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+	/* the rflags need match native register size */
+#ifdef RTE_ARCH_I686
+	uint32_t rflags;
+#else
+	uint64_t rflags;
+#endif
+	/*
+	 * we're using raw byte codes for now as only the newest compiler
+	 * versions support this instruction natively.
+	 */
+
+	/* set address for UMONITOR */
+	asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
+			:
+			: "D"(p));
+
+	if (value_mask) {
+		const uint64_t cur_value = *(const volatile uint64_t *)p;
+		const uint64_t masked = cur_value & value_mask;
+		/* if the masked value is already matching, abort */
+		if (masked == expected_value)
+			return 0;
+	}
+	/* execute UMWAIT */
+	asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;\n"
+		/*
+		 * UMWAIT sets CF flag in RFLAGS, so PUSHF to push them
+		 * onto the stack, then pop them back into `rflags` so that
+		 * we can read it.
+		 */
+		"pushf;\n"
+		"pop %0;\n"
+		: "=r"(rflags)
+		: "D"(state), "a"(tsc_l), "d"(tsc_h));
+
+	/* we're interested in the first bit (the carry flag) */
+	return rflags & 0x1;
+}
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * This function uses TPAUSE instruction. For more information about its usage,
+ * please refer to Intel(R) 64 and IA-32 Architectures Software Developer's
+ * Manual.
+ *
+ * @param state
+ *   Architecture-dependent optimized power state number. Can be 0 (C0.2) or
+ *   1 (C0.1).
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 1 if wakeup was due to TSC timeout expiration.
+ *   - 0 if wakeup was due to other reasons.
+ */
+static inline int rte_power_pause(const uint32_t state,
+		const uint64_t tsc_timestamp)
+{
+	const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+	const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+	/* the rflags need match native register size */
+#ifdef RTE_ARCH_I686
+	uint32_t rflags;
+#else
+	uint64_t rflags;
+#endif
+
+	/* execute TPAUSE */
+	asm volatile(".byte 0x66, 0x0f, 0xae, 0xf7;\n"
+		     /*
+		      * TPAUSE sets CF flag in RFLAGS, so PUSHF to push them
+		      * onto the stack, then pop them back into `rflags` so that
+		      * we can read it.
+		      */
+		     "pushf;\n"
+		     "pop %0;\n"
+		     : "=r"(rflags)
+		     : "D"(state), "a"(tsc_l), "d"(tsc_h));
+
+	/* we're interested in the first bit (the carry flag) */
+	return rflags & 0x1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_X86_64_H_ */
#208 lore raw

Re: [dpdk-dev] [PATCH v3 1/6] eal: add power management intrinsics

In reply to Liang Ma
Quoted 33 lines · Liang Ma

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

lib/librte_eal/x86/include/rte_power_intrinsics.h new file +16 -0
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, or a certain TSC timestamp is reached.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * This function uses UMONITOR/UMWAIT instructions. For more information about
+ * their usage, please refer to Intel(R) 64 and IA-32 Architectures Software
+ * Developer's Manual.

[snip]

lib/librte_eal/x86/include/rte_power_intrinsics.h line 50

Quoted 4 lines

+ */

lib/librte_eal/x86/include/rte_power_intrinsics.h new file +3 -0
+static inline int rte_power_monitor(const volatile void *p,
+               const uint64_t expected_value, const uint64_t value_mask,
+               const uint32_t state, const uint64_t tsc_timestamp)

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as functions[1] or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the instruction features which can NOT be abstracted as a generic feature across the architectures.

[1]
struct rte_arch_inst_feat {
uint32_t power_monitor : 1; /**< Power monitor */
...
}

void rte_arch_inst_feat_get(struct rte_arch_inst_feat *feat);

#209 lore raw

PATCH v4 1/10 eal: add new x86 cpuid support for WAITPKG

In reply to Liang Ma

Add new x86 cpuid support for WAITPKG.
This flag indicate processor support umwait/umonitor/tpause instruction.

---
 lib/librte_eal/x86/include/rte_cpuflags.h | 2 ++
 lib/librte_eal/x86/rte_cpuflags.c         | 2 ++
 2 files changed, 4 insertions(+)
lib/librte_eal/x86/include/rte_cpuflags.h +2 -0
index c1d20364d1..5041a830a7 100644
@@ -132,6 +132,8 @@ enum rte_cpu_flag_t {
 	RTE_CPUFLAG_MOVDIR64B,              /**< Direct Store Instructions 64B */
 	RTE_CPUFLAG_AVX512VP2INTERSECT,     /**< AVX512 Two Register Intersection */
 
+	/**< UMWAIT/TPAUSE Instructions */
+	RTE_CPUFLAG_WAITPKG,                /**< UMINITOR/UMWAIT/TPAUSE */
 	/* The last item */
 	RTE_CPUFLAG_NUMFLAGS,               /**< This should always be the last! */
 };
lib/librte_eal/x86/rte_cpuflags.c +2 -0
index 30439e7951..0325c4b93b 100644
@@ -110,6 +110,8 @@ const struct feature_entry rte_cpu_feature_table[] = {
 	FEAT_DEF(AVX512F, 0x00000007, 0, RTE_REG_EBX, 16)
 	FEAT_DEF(RDSEED, 0x00000007, 0, RTE_REG_EBX, 18)
 
+	FEAT_DEF(WAITPKG, 0x00000007, 0, RTE_REG_ECX, 5)
+
 	FEAT_DEF(LAHF_SAHF, 0x80000001, 0, RTE_REG_ECX,  0)
 	FEAT_DEF(LZCNT, 0x80000001, 0, RTE_REG_ECX,  4)
 
Signature · 1 line
2.17.1
#210 lore raw

PATCH v4 2/10 eal: add power management intrinsics

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

---
 .../include/generic/rte_power_intrinsics.h    |  64 ++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 143 ++++++++++++++++++
 4 files changed, 209 insertions(+)
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
new file mode 100644
index 0000000000..cd7f8070ac
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_H_
+#define _RTE_POWER_INTRINSIC_H_
+
+#include <inttypes.h>
+
+/**
+ * @file
+ * Advanced power management operations.
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, or a certain TSC timestamp is reached.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp);
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_pause(const uint32_t state,
+		const uint64_t tsc_timestamp);
+
+#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +143 -0

143 lines not on this page · raw message

Signature · 1 line
2.17.1
#211 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 5 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Also please mark the new functions as experimental.

#212 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 13 lines · Thomas Monjalon
Quoted 13 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 4 lines
Quoted 1 line

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

#213 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

08/10/2020 10:44, Jerin Jacob:

Quoted 14 lines · Thomas Monjalon
Quoted 13 lines
Quoted 13 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

This comment was sent on September 18.
Later this v4 was sent without replying to the comments. This is blocking the series.
I am considering this feature as low priority.

Quoted 1 line
Quoted 1 line

Also please mark the new functions as experimental.

#214 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

In reply to Jerin Jacob
Quoted 14 lines · Jerin Jacob
Quoted 13 lines · Thomas Monjalon
Quoted 13 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 11 lines
Quoted 4 lines
Quoted 1 line

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Quoted 7 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as functions[1] or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the instruction features which can NOT be abstracted as a generic feature across the architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.

[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , function rte_power_pmd_mgmt_queue_enable()

Signature · 2 lines
Thanks,
Anatoly
#215 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 15 lines

If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.

[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , function rte_power_pmd_mgmt_queue_enable()

--
Thanks,
Anatoly

#216 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 54 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here... Might be just something like:
rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:

if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
	/* not supported  path */
}

To check is that feature supported or not.

Quoted 15 lines
Quoted 15 lines

If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.

[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , function rte_power_pmd_mgmt_queue_enable()

--
Thanks,
Anatoly

#217 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 27 lines

Might be just something like:
rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:

if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
        /* not supported  path */
}

To check is that feature supported or not.

Quoted 15 lines
Quoted 15 lines

If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.

[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , function rte_power_pmd_mgmt_queue_enable()

--
Thanks,
Anatoly

#218 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 67 lines · Jerin Jacob
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:
rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:

if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
         /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines

If you look at patch 1 [1], we added CPUID flags that the user can check, and in fact this is precisely what we do in patch 4 [2] before enabling the UMWAIT path. We could perhaps document this better and outline the dependency on the WAITPKG CPUID flag more explicitly, but otherwise i don't see how what you're proposing isn't already possible to do.

[1] http://patches.dpdk.org/patch/79539/
[2] http://patches.dpdk.org/patch/79540/ , function rte_power_pmd_mgmt_queue_enable()

--
Thanks,
Anatoly

Signature · 2 lines
Thanks,
Anatoly
#219 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

09/10/2020 11:25, Burakov, Anatoly:

Quoted 94 lines · Jerin Jacob
Quoted 67 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:
rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:

if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
         /* not supported  path */
}

To check is that feature supported or not.

Quoted 6 lines

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Sorry I don't understand what you mean, too many "it" and "this" :)

#220 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 95 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 94 lines · Jerin Jacob
Quoted 92 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

   rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
          /* not supported  path */
}

To check is that feature supported or not.

Quoted 9 lines
Quoted 6 lines

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

Signature · 2 lines
Thanks,
Anatoly
#221 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 104 lines · Anatoly
Quoted 102 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 100 lines · Jerin Jacob
Quoted 67 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

   rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
          /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

Quoted 9 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

--
Thanks,
Anatoly

#222 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 115 lines · Jerin Jacob
Quoted 104 lines · Anatoly
Quoted 102 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 100 lines · Jerin Jacob
Quoted 67 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

    rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
           /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

Quoted 6 lines

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific). I guess we could remove that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

Quoted 5 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

Quoted 11 lines
Quoted 11 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

--
Thanks,
Anatoly

Signature · 2 lines
Thanks,
Anatoly
#223 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

09/10/2020 12:03, Burakov, Anatoly:

Quoted 119 lines · Jerin Jacob
Quoted 111 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

    rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
           /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

Quoted 6 lines

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Quoted 2 lines

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).

Obviously an API definition should *never* be "implementation-defined".

Quoted 4 lines

I guess we could remove
that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

Quoted 8 lines
Quoted 5 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

It is not call "power-x86", so we must assume it could work on any architecture.

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.

#224 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 120 lines · Thomas Monjalon

09/10/2020 12:03, Burakov, Anatoly:

Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 14 lines

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 12 lines

> IMO, We must introduce some arch feature-capability _get_ scheme to tell > the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the > API marked as generic ie rte_power_* not rte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.

Quoted 5 lines

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

     rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
            /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Quoted 4 lines
Quoted 2 lines

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).

Obviously an API definition should *never* be "implementation-defined".

If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy rte_pause).

Quoted 12 lines
Quoted 12 lines

I guess we could remove
that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

Quoted 5 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

Quoted 5 lines
Quoted 2 lines

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

It is not call "power-x86", so we must assume it could work on any architecture.

#ifdef it is!

Quoted 10 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.

UMWAIT is a best-effort mechanism with no side-effects. It's perfectly legal for a UMWAIT to not sleep at all, thus rendering it effectively a noop. So i don't think it's all that different.

Signature · 2 lines
Thanks,
Anatoly
#225 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 159 lines · Anatoly
Quoted 120 lines · Thomas Monjalon

09/10/2020 12:03, Burakov, Anatoly:

Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 12 lines

> IMO, We must introduce some arch feature-capability _get_ scheme to tell > the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the > API marked as generic ie rte_power_* not rte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.

Quoted 5 lines

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

     rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
            /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Quoted 4 lines
Quoted 2 lines

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).

Obviously an API definition should *never* be "implementation-defined".

If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy rte_pause).

Quoted 12 lines
Quoted 12 lines

I guess we could remove
that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

Quoted 5 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

Quoted 5 lines
Quoted 2 lines

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

It is not call "power-x86", so we must assume it could work on any architecture.

#ifdef it is!

Quoted 7 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

Quoted 7 lines
Quoted 3 lines

CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.

UMWAIT is a best-effort mechanism with no side-effects. It's perfectly legal for a UMWAIT to not sleep at all, thus rendering it effectively a noop. So i don't think it's all that different.

If a platform does not support UMWAIT in ALL case IMO, no consumer takes this the path for power saving. So IMO, t is different than CLDEMOTE

Quoted 4 lines

--
Thanks,
Anatoly

#226 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

In reply to Burakov, Anatoly
Quoted 143 lines · Thomas Monjalon
Quoted 120 lines

09/10/2020 12:03, Burakov, Anatoly:

Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 12 lines

> IMO, We must introduce some arch feature-capability _get_ scheme to tell > the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the > API marked as generic ie rte_power_* not rte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.

Quoted 5 lines

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

     rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
            /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Quoted 4 lines
Quoted 2 lines

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).

Obviously an API definition should *never* be "implementation-defined".

If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy rte_pause).

Quoted 12 lines
Quoted 12 lines

I guess we could remove
that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

Quoted 5 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

Quoted 13 lines
Quoted 5 lines
Quoted 2 lines

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

It is not call "power-x86", so we must assume it could work on any architecture.

#ifdef it is!

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well

I wouldn't consider these two as totally equal.
Yes, both are just hints to CPU, that can be ignored,
but if not, then consequences of executing are quite different. If UMWAIT is not supported by cpu at all, then user might want to use some different power saving mechanism (pause, frequence scaling, etc.). Without information is UMWAIT supported or not, user can't make such choice.

Quoted 10 lines

, yet Jerin has acked that one and has explicitly

Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line

stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.

UMWAIT is a best-effort mechanism with no side-effects. It's perfectly legal for a UMWAIT to not sleep at all, thus rendering it effectively a noop. So i don't think it's all that different.

#227 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 157 lines · Konstantin
Quoted 143 lines · Thomas Monjalon
Quoted 120 lines

09/10/2020 12:03, Burakov, Anatoly:

Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 20 lines · Anatoly
Quoted 19 lines · Jerin Jacob

On Thu, Oct 8, 2020 at 2:04 PM Thomas Monjalon <[email protected]> wrote:

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 12 lines

> IMO, We must introduce some arch feature-capability _get_ scheme to tell > the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the > API marked as generic ie rte_power_* not rte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.

Quoted 5 lines

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

      rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
             /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Quoted 4 lines
Quoted 2 lines

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).

Obviously an API definition should *never* be "implementation-defined".

If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy rte_pause).

Quoted 12 lines
Quoted 12 lines

I guess we could remove
that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

Quoted 5 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

Quoted 13 lines
Quoted 5 lines
Quoted 2 lines

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

It is not call "power-x86", so we must assume it could work on any architecture.

#ifdef it is!

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well

Quoted 7 lines

I wouldn't consider these two as totally equal.
Yes, both are just hints to CPU, that can be ignored,
but if not, then consequences of executing are quite different. If UMWAIT is not supported by cpu at all, then user might want to use some different power saving mechanism (pause, frequence scaling, etc.). Without information is UMWAIT supported or not, user can't make such choice.

After some attempts at implementing this, i actually came to the conclusion that some generic way to check support for this feature is necessary, because we end up with a usability inconsistency:

1) on non-x86, if you call the function, it returns -ENOTSUP
2) on x86, since we're not checking CPUID flags on every single call, it'll either succeed, or crash the process - the burden is on the user to check for CPUID flags, but it can't be done in an arch agnostic way because the CPUID flags are only defined for x86, thus requiring a special code path for x86

Where would be the best place to add such an infrastructure? I'm thinking rte_cpuflags.h?

Quoted 15 lines
Quoted 11 lines

, yet Jerin has acked that one and has explicitly

Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line

stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

CLDEMOTE is used for optimization, while UMWAIT can be used in a logic, that's why the expectations may be different.

UMWAIT is a best-effort mechanism with no side-effects. It's perfectly legal for a UMWAIT to not sleep at all, thus rendering it effectively a noop. So i don't think it's all that different.

Signature · 2 lines
Thanks,
Anatoly
#228 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 177 lines · Anatoly
Quoted 157 lines · Konstantin
Quoted 143 lines · Thomas Monjalon
Quoted 120 lines

09/10/2020 12:03, Burakov, Anatoly:

Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 52 lines
Quoted 28 lines · Anatoly

On 08-Oct-20 9:44 AM, Jerin Jacob wrote:
On Thu, Oct 8, 2020 at 2:04 PM Thomas Monjalon <[email protected]> wrote:

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 17 lines

> IMO, We must introduce some arch feature-capability _get_ scheme to tell
> the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the
> API marked as generic ie rte_power_* not rte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we
will add those in future revisions, but what does your proposed runtime
check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

      rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
             /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Quoted 4 lines
Quoted 2 lines

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).

Obviously an API definition should *never* be "implementation-defined".

If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy rte_pause).

Quoted 12 lines
Quoted 12 lines

I guess we could remove
that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

Quoted 5 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

Quoted 13 lines
Quoted 5 lines
Quoted 2 lines

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

It is not call "power-x86", so we must assume it could work on any architecture.

#ifdef it is!

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well

Quoted 7 lines

I wouldn't consider these two as totally equal.
Yes, both are just hints to CPU, that can be ignored,
but if not, then consequences of executing are quite different. If UMWAIT is not supported by cpu at all, then user might want to use some different power saving mechanism (pause, frequence scaling, etc.). Without information is UMWAIT supported or not, user can't make such choice.

After some attempts at implementing this, i actually came to the conclusion that some generic way to check support for this feature is necessary, because we end up with a usability inconsistency:

1) on non-x86, if you call the function, it returns -ENOTSUP
2) on x86, since we're not checking CPUID flags on every single call, it'll either succeed, or crash the process - the burden is on the user to check for CPUID flags, but it can't be done in an arch agnostic way because the CPUID flags are only defined for x86, thus requiring a special code path for x86

Quoted 3 lines

Where would be the best place to add such an infrastructure? I'm thinking rte_cpuflags.h?

Time to relook at some of the contents of patchset:
http://patches.dpdk.org/project/dpdk/list/?series=4811&archive=both&state=*

The idea of that set (IIRC) was to replace the per-architecture enums with just strings to avoid situations like this - or at least make them less awkward.

/Bruce

#229 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 181 lines · Bruce Richardson
Quoted 177 lines · Anatoly
Quoted 157 lines · Konstantin
Quoted 143 lines · Thomas Monjalon
Quoted 120 lines

09/10/2020 12:03, Burakov, Anatoly:

Quoted 119 lines · Jerin Jacob
Quoted 117 lines
Quoted 100 lines · Anatoly
Quoted 99 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 97 lines · Jerin Jacob
Quoted 64 lines
Quoted 58 lines · Konstantin
Quoted 56 lines

On Thu, Oct 8, 2020 at 6:57 PM Burakov, Anatoly
<[email protected]> wrote:
On 08-Oct-20 9:44 AM, Jerin Jacob wrote:
On Thu, Oct 8, 2020 at 2:04 PM Thomas Monjalon <[email protected]> wrote:

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions
are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

The power management instructions provide an architecture-specific
function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already
happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers.
Unfortunately they were not Cc'ed.

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

> IMO, We must introduce some arch feature-capability _get_ scheme to tell
> the consumer of this API is only supported on x86. Probably as
functions[1]
> or macro flags scheme and have a stub for the other architectures as the
> API marked as generic ie rte_power_* not rte_x86_..
>
> This will help the consumer to create workers based on the
instruction features
> which can NOT be abstracted as a generic feature across the
architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we
will add those in future revisions, but what does your proposed runtime
check accomplish that cannot currently be done with CPUID flags?

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures.
i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h
and it is used in http://patches.dpdk.org/patch/79540/ as generic API.
I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

       rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
              /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Quoted 4 lines
Quoted 2 lines

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific).

Obviously an API definition should *never* be "implementation-defined".

If there isn't a meaningful return value, we could either make it a void, or return 0/-ENOTSUP so. I'm OK with either as nop is a valid result for a UMWAIT, and there are no side-effects to the intrinsic itself (it's basically a fancy rte_pause).

Quoted 12 lines
Quoted 12 lines

I guess we could remove
that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

Quoted 5 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

Quoted 13 lines
Quoted 5 lines
Quoted 2 lines

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

It is not call "power-x86", so we must assume it could work on any architecture.

#ifdef it is!

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well

Quoted 7 lines

I wouldn't consider these two as totally equal.
Yes, both are just hints to CPU, that can be ignored,
but if not, then consequences of executing are quite different. If UMWAIT is not supported by cpu at all, then user might want to use some different power saving mechanism (pause, frequence scaling, etc.). Without information is UMWAIT supported or not, user can't make such choice.

After some attempts at implementing this, i actually came to the conclusion that some generic way to check support for this feature is necessary, because we end up with a usability inconsistency:

1) on non-x86, if you call the function, it returns -ENOTSUP
2) on x86, since we're not checking CPUID flags on every single call, it'll either succeed, or crash the process - the burden is on the user to check for CPUID flags, but it can't be done in an arch agnostic way because the CPUID flags are only defined for x86, thus requiring a special code path for x86

Quoted 3 lines

Where would be the best place to add such an infrastructure? I'm thinking rte_cpuflags.h?

Quoted 9 lines

Time to relook at some of the contents of patchset:
http://patches.dpdk.org/project/dpdk/list/?series=4811&archive=both&state=*

The idea of that set (IIRC) was to replace the per-architecture enums with just strings to avoid situations like this - or at least make them less awkward.

/Bruce

Yes, that patchset looks like it would work nicely in this case. If there is consensus to resurrect it and make it work, i'll drop the "generic feature get" thing, but for now i'll continue working on it - easier to remove code than to add it :D

Signature · 2 lines
Thanks,
Anatoly
#230 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

In reply to Burakov, Anatoly
Quoted 124 lines · Anatoly
Quoted 115 lines · Jerin Jacob
Quoted 104 lines · Anatoly
Quoted 102 lines · Thomas Monjalon

09/10/2020 11:25, Burakov, Anatoly:

Quoted 100 lines · Jerin Jacob
Quoted 67 lines
Quoted 61 lines · Konstantin
Quoted 55 lines
Quoted 21 lines · Anatoly
Quoted 19 lines · Jerin Jacob
Quoted 17 lines · Thomas Monjalon
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 8 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

For more details, Please reference Intel SDM Volume 2.

I really would like to see feedbacks from other arch maintainers. Unfortunately they were not Cc'ed.

Quoted 8 lines
Quoted 6 lines

Shared the feedback from the arm64 perspective here. Yet to get a reply on this.
http://mails.dpdk.org/archives/dev/2020-September/181646.html

Quoted 3 lines

Also please mark the new functions as experimental.

Hi Jerin,

Hi Anatoly,

Quoted 9 lines
Quoted 3 lines

IMO, We must introduce some arch feature-capability _get_ scheme to tell the consumer of this API is only supported on x86. Probably as

functions[1]

Quoted 4 lines

or macro flags scheme and have a stub for the other architectures as the API marked as generic ie rte_power_* not rte_x86_..

This will help the consumer to create workers based on the

instruction features

Quoted 8 lines
Quoted 1 line

which can NOT be abstracted as a generic feature across the

architectures.

I'm not entirely sure what you mean by that.

I mean, yes, we should have added stubs for other architectures, and we will add those in future revisions, but what does your proposed runtime check accomplish that cannot currently be done with CPUID flags?

Quoted 4 lines

RTE_CPUFLAG_WAITPKG flag definition is not available in other architectures. i.e RTE_CPUFLAG_WAITPKG defined in lib/librte_eal/x86/include/rte_cpuflags.h and it is used in http://patches.dpdk.org/patch/79540/ as generic API. I doubt http://patches.dpdk.org/patch/79540/ would compile on non-x86.

Quoted 3 lines

I am agree with Jerin, that we need some generic way to figure-out does platform supports power_monitor() or not. Though not sure do we need to create a new feature-get framework here...

Quoted 25 lines

That's works too. Some means of generic probing is fine. Following schemed needs
more documentation on that usage, as, it is not straight forward compare to feature-get framework. Also, on the other thread, we are adding the new instructions like
demote cacheline etc, maybe if the user wants to KNOW if the arch supports it then
the feature-get framework is good.
If we think, there is no other usecase for generic arch feature-get framework then
we can keep the below scheme else generic arch feature is better for more forward
looking use cases.

Quoted 9 lines

Might be just something like:

    rte_power_monitor(...) == -ENOTSUP
be enough indication for that?
So user can just do:
if (rte_power_monitor(NULL, 0, 0, 0, 0) == -ENOTSUP) {
           /* not supported  path */
}

To check is that feature supported or not.

Looking at CLDEMOTE patches, CLDEMOTE is a noop on other archs. I think we can safely make this intrinsic as a noop on other archs as well, as it's functionally identical to waking up immediately.

If we're not creating this for CLDEMOTE, we don't need it here as well. If we do need it for this, then we arguably need it for CLDEMOTE too.

Quoted 8 lines
Quoted 2 lines

Sorry I don't understand what you mean, too many "it" and "this" :)

Sorry, i meant "the generic feature-get framework". CLDEMOTE doesn't exist on other archs, this doesn't too, so it's a fairly similar situation. Stubbing UMWAIT with a noop is a valid approach because it's equivalent to sleeping and then immediately waking up (which can happen for a host of reasons unrelated to the code itself).

Quoted 6 lines

If we are keeping the following return in the public API then it can not be NOP
+ * @return
+ * - 1 if wakeup was due to TSC timeout expiration.
+ * - 0 if wakeup was due to memory write or other reasons.
+ */

Quoted 4 lines

In the generic header, it is specified that return value is implementation-defined (i.e. arch-specific). I guess we could remove that and set return value to either 0 or -ENOTSUP if that would resolve the issue?

returning -ENOTSUP should be OK if we don't to take generic feature-get framework path.

Quoted 9 lines
Quoted 6 lines

Also, we need to fix compilation issue if any with
http://patches.dpdk.org/patch/79540/
as it has direct reference to if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_WAITPKG)) {
Either we need to add -ENOTSUP return or generic feature-get framework.

IIRC power library isn't compiled on anything other than x86, so this code wouldn't get compiled.

Just checked now, librte_power compiles at least for arm64.

Quoted 17 lines
Quoted 4 lines
Quoted 4 lines
Quoted 8 lines
Quoted 8 lines

I'm not against a generic feature-get framework, i'm just pointing out that if this is what's preventing the merge, it should prevent the merge of CLDEMOTE as well, yet Jerin has acked that one and has explicitly stated that he's OK with leaving CLDEMOTE as a noop on other architectures.

--
Thanks,
Anatoly

--
Thanks,
Anatoly

#231 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

In reply to Liang Ma
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 6 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

Quoted 259 lines

For more details, Please reference Intel SDM Volume 2.

---
 .../include/generic/rte_power_intrinsics.h    |  64 ++++++++
 lib/librte_eal/include/meson.build            |   1 +
 lib/librte_eal/x86/include/meson.build        |   1 +
 .../x86/include/rte_power_intrinsics.h        | 143 ++++++++++++++++++
 4 files changed, 209 insertions(+)
 create mode 100644 lib/librte_eal/include/generic/rte_power_intrinsics.h
 create mode 100644 lib/librte_eal/x86/include/rte_power_intrinsics.h
lib/librte_eal/include/generic/rte_power_intrinsics.h new file +64 -0
new file mode 100644
index 0000000000..cd7f8070ac
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_H_
+#define _RTE_POWER_INTRINSIC_H_
+
+#include <inttypes.h>
+
+/**
+ * @file
+ * Advanced power management operations.
+ *
+ * This file define APIs for advanced power management,
+ * which are architecture-dependent.
+ */
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, or a certain TSC timestamp is reached.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp);
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * @param state
+ *   Architecture-dependent optimized power state number
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for. Note that the wait behavior is
+ *   architecture-dependent.
+ *
+ * @return
+ *   Architecture-dependent return value.
+ */
+static inline int rte_power_pause(const uint32_t state,
+		const uint64_t tsc_timestamp);
+
+#endif /* _RTE_POWER_INTRINSIC_H_ */
lib/librte_eal/include/meson.build +1 -0
index cd09027958..3a12e87e19 100644
@@ -60,6 +60,7 @@ generic_headers = files(
 	'generic/rte_memcpy.h',
 	'generic/rte_pause.h',
 	'generic/rte_prefetch.h',
+	'generic/rte_power_intrinsics.h',
 	'generic/rte_rwlock.h',
 	'generic/rte_spinlock.h',
 	'generic/rte_ticketlock.h',
lib/librte_eal/x86/include/meson.build +1 -0
index f0e998c2fe..494a8142a2 100644
@@ -13,6 +13,7 @@ arch_headers = files(
 	'rte_io.h',
 	'rte_memcpy.h',
 	'rte_prefetch.h',
+	'rte_power_intrinsics.h',
 	'rte_pause.h',
 	'rte_rtm.h',
 	'rte_rwlock.h',
lib/librte_eal/x86/include/rte_power_intrinsics.h new file +143 -1
new file mode 100644
index 0000000000..6dd1cdc939
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _RTE_POWER_INTRINSIC_X86_64_H_
+#define _RTE_POWER_INTRINSIC_X86_64_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+
+#include "generic/rte_power_intrinsics.h"
+
+/**
+ * Monitor specific address for changes. This will cause the CPU to enter an
+ * architecture-defined optimized power state until either the specified
+ * memory address is written to, or a certain TSC timestamp is reached.
+ *
+ * Additionally, an `expected` 64-bit value and 64-bit mask are provided. If
+ * mask is non-zero, the current value pointed to by the `p` pointer will be
+ * checked against the expected value, and if they match, the entering of
+ * optimized power state may be aborted.
+ *
+ * This function uses UMONITOR/UMWAIT instructions. For more information about
+ * their usage, please refer to Intel(R) 64 and IA-32 Architectures Software
+ * Developer's Manual.
+ *
+ * @param p
+ *   Address to monitor for changes. Must be aligned on an 64-byte boundary.
+ * @param expected_value
+ *   Before attempting the monitoring, the `p` address may be read and compared
+ *   against this value. If `value_mask` is zero, this step will be skipped.
+ * @param value_mask
+ *   The 64-bit mask to use to extract current value from `p`.
+ * @param state
+ *   Architecture-dependent optimized power state number. Can be 0 (C0.2) or
+ *   1 (C0.1).
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 1 if wakeup was due to TSC timeout expiration.
+ *   - 0 if wakeup was due to memory write or other reasons.
+ */
+static inline int rte_power_monitor(const volatile void *p,
+		const uint64_t expected_value, const uint64_t value_mask,
+		const uint32_t state, const uint64_t tsc_timestamp)
+{
+	const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+	const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+	/* the rflags need match native register size */
+#ifdef RTE_ARCH_I686
+	uint32_t rflags;
+#else
+	uint64_t rflags;
+#endif
+	/*
+	 * we're using raw byte codes for now as only the newest compiler
+	 * versions support this instruction natively.
+	 */
+
+	/* set address for UMONITOR */
+	asm volatile(".byte 0xf3, 0x0f, 0xae, 0xf7;"
+			:
+			: "D"(p));
+
+	if (value_mask) {
+		const uint64_t cur_value = *(const volatile uint64_t *)p;
+		const uint64_t masked = cur_value & value_mask;
+		/* if the masked value is already matching, abort */
+		if (masked == expected_value)
+			return 0;
+	}
+	/* execute UMWAIT */
+	asm volatile(".byte 0xf2, 0x0f, 0xae, 0xf7;\n"
+		/*
+		 * UMWAIT sets CF flag in RFLAGS, so PUSHF to push them
+		 * onto the stack, then pop them back into `rflags` so that
+		 * we can read it.
+		 */
+		"pushf;\n"
+		"pop %0;\n"
+		: "=r"(rflags)
+		: "D"(state), "a"(tsc_l), "d"(tsc_h));
+
+	/* we're interested in the first bit (the carry flag) */
+	return rflags & 0x1;
+}
+
+/**
+ * Enter an architecture-defined optimized power state until a certain TSC
+ * timestamp is reached.
+ *
+ * This function uses TPAUSE instruction. For more information about its usage,
+ * please refer to Intel(R) 64 and IA-32 Architectures Software Developer's
+ * Manual.
+ *
+ * @param state
+ *   Architecture-dependent optimized power state number. Can be 0 (C0.2) or
+ *   1 (C0.1).
+ * @param tsc_timestamp
+ *   Maximum TSC timestamp to wait for.
+ *
+ * @return
+ *   - 1 if wakeup was due to TSC timeout expiration.
+ *   - 0 if wakeup was due to other reasons.
+ */
+static inline int rte_power_pause(const uint32_t state,
+		const uint64_t tsc_timestamp)
+{
+	const uint32_t tsc_l = (uint32_t)tsc_timestamp;
+	const uint32_t tsc_h = (uint32_t)(tsc_timestamp >> 32);
+	/* the rflags need match native register size */
+#ifdef RTE_ARCH_I686
+	uint32_t rflags;
+#else
+	uint64_t rflags;
+#endif
+
+	/* execute TPAUSE */
+	asm volatile(".byte 0x66, 0x0f, 0xae, 0xf7;\n"
+		     /*
+		      * TPAUSE sets CF flag in RFLAGS, so PUSHF to push them
+		      * onto the stack, then pop them back into `rflags` so that
+		      * we can read it.
+		      */
+		     "pushf;\n"
+		     "pop %0;\n"
+		     : "=r"(rflags)
+		     : "D"(state), "a"(tsc_l), "d"(tsc_h));
+
+	/* we're interested in the first bit (the carry flag) */
+	return rflags & 0x1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_POWER_INTRINSIC_X86_64_H_ */
--

2.17.1

#232 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 13 lines · Konstantin
Quoted 6 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

Quoted 6 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 3 lines

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.

Signature · 2 lines
Thanks,
Anatoly
#233 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 15 lines · Konstantin
Quoted 13 lines
Quoted 12 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 9 lines
Quoted 3 lines

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.

Yes, I think we either need a syscall that would do an IPI for us
(on top of my head - membarrier() does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin

#234 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 25 lines · Konstantin
Quoted 15 lines · Konstantin
Quoted 13 lines
Quoted 12 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 9 lines
Quoted 3 lines

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.

Quoted 16 lines

Yes, I think we either need a syscall that would do an IPI for us
(on top of my head - membarrier() does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin

This implies knowing the value the core is sleeping on. That's not always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

Signature · 2 lines
Thanks,
Anatoly
#235 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 45 lines · Konstantin
Quoted 25 lines
Quoted 15 lines · Konstantin
Quoted 13 lines
Quoted 12 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 9 lines
Quoted 3 lines

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.

Quoted 16 lines

Yes, I think we either need a syscall that would do an IPI for us
(on top of my head - membarrier() does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin

Quoted 1 line

This implies knowing the value the core is sleeping on.

You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.

Quoted 3 lines

That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.

#236 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 45 lines · Konstantin
Quoted 45 lines · Konstantin
Quoted 41 lines
Quoted 15 lines · Konstantin
Quoted 13 lines
Quoted 12 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 9 lines
Quoted 3 lines

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.

Yes, I think we either need a syscall that would do an IPI for us
(on top of my head - membarrier() does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin

Quoted 5 lines
Quoted 1 line

This implies knowing the value the core is sleeping on.

You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.

Sorry, i meant the address. We don't know the address we're sleeping on.

Quoted 8 lines
Quoted 4 lines

That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.

The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.

Signature · 2 lines
Thanks,
Anatoly
#237 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 54 lines
Quoted 41 lines
Quoted 41 lines
Quoted 40 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 9 lines
Quoted 3 lines

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.

Yes, I think we either need a syscall that would do an IPI for us
(on top of my head - membarrier() does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin

Quoted 5 lines
Quoted 1 line

This implies knowing the value the core is sleeping on.

You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.

Sorry, i meant the address. We don't know the address we're sleeping on.

Quoted 5 lines
Quoted 4 lines

That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

Quoted 7 lines
Quoted 3 lines

That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.

The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.

Yes, we'll need something to sync here for sure.
Sorry, I should say it straightway, to avoid further misunderstanding. Let say, associate a spin_lock with monitor(), by analogy with pthread_cond_wait(). Konstantin

#238 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 58 lines · Konstantin
Quoted 58 lines
Quoted 41 lines
Quoted 41 lines
Quoted 40 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 9 lines
Quoted 3 lines

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.

Yes, I think we either need a syscall that would do an IPI for us
(on top of my head - membarrier() does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin

Quoted 5 lines
Quoted 1 line

This implies knowing the value the core is sleeping on.

You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.

Sorry, i meant the address. We don't know the address we're sleeping on.

Quoted 8 lines
Quoted 4 lines

That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.

Quoted 9 lines
Quoted 3 lines

The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.

Yes, we'll need something to sync here for sure.
Sorry, I should say it straightway, to avoid further misunderstanding. Let say, associate a spin_lock with monitor(), by analogy with pthread_cond_wait(). Konstantin

The idea was to provide an intrinsic-like function - as in, raw instruction call, without anything extra. We even added the masks/values etc. only because there's no race-less way to combine UMONITOR/UMWAIT without those.

Perhaps we can provide a synchronize-able wrapper around it to avoid adding overhead to calls that function but doesn't need the sync mechanism?

Signature · 2 lines
Thanks,
Anatoly
#239 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 69 lines · Anatoly
Quoted 58 lines · Konstantin
Quoted 58 lines
Quoted 41 lines
Quoted 41 lines
Quoted 40 lines
Quoted 14 lines
Quoted 14 lines
Quoted 13 lines

Add two new power management intrinsics, and provide an implementation in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread compiler support for these instructions.

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or optionally wait until either a TSC timestamp is reached or a memory location is written to. The monitor function also provides an optional comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 9 lines
Quoted 3 lines

I think what this API is missing - a function to wakeup sleeping core. If user can/should use some system call to achieve that, then at least it has to be clearly documented, even better some wrapper provided.

I don't think it's possible to do that without severely overcomplicating the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or trigger a write to the cache-line in question.

Yes, I think we either need a syscall that would do an IPI for us
(on top of my head - membarrier() does that, might be there are some other syscalls too), or something hand-made. For hand-made, I wonder would something like that be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases
Konstantin

Quoted 5 lines
Quoted 1 line

This implies knowing the value the core is sleeping on.

You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.

Sorry, i meant the address. We don't know the address we're sleeping on.

Quoted 8 lines
Quoted 4 lines

That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.

Quoted 9 lines
Quoted 3 lines

The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.

Yes, we'll need something to sync here for sure.
Sorry, I should say it straightway, to avoid further misunderstanding. Let say, associate a spin_lock with monitor(), by analogy with pthread_cond_wait(). Konstantin

Quoted 4 lines

The idea was to provide an intrinsic-like function - as in, raw instruction call, without anything extra. We even added the masks/values etc. only because there's no race-less way to combine UMONITOR/UMWAIT without those.

Perhaps we can provide a synchronize-able wrapper around it to avoid adding overhead to calls that function but doesn't need the sync mechanism?

Also, how would having a spinlock help to synchronize? Are you suggesting we do UMWAIT on a spinlock address, or something to that effect?

Signature · 2 lines
Thanks,
Anatoly
#240 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 82 lines
Quoted 82 lines
Quoted 81 lines
Quoted 67 lines
Quoted 54 lines
Quoted 54 lines
Quoted 53 lines
Quoted 25 lines
Quoted 19 lines
Quoted 9 lines

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

Quoted 9 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 5 lines

I think what this API is missing - a function to wakeup sleeping core.
If user can/should use some system call to achieve that, then at least
it has to be clearly documented, even better some wrapper provided.

Quoted 7 lines

I don't think it's possible to do that without severely overcomplicating
the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or
trigger a write to the cache-line in question.

Yes, I think we either need a syscall that would do an IPI for us (on top of my head - membarrier() does that, might be there are some other syscalls too),
or something hand-made. For hand-made, I wonder would something like that
be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep
have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases Konstantin

Quoted 5 lines
Quoted 1 line

This implies knowing the value the core is sleeping on.

You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.

Sorry, i meant the address. We don't know the address we're sleeping on.

Quoted 5 lines
Quoted 4 lines

That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

Quoted 7 lines
Quoted 3 lines

That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.

The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.

Yes, we'll need something to sync here for sure.
Sorry, I should say it straightway, to avoid further misunderstanding. Let say, associate a spin_lock with monitor(), by analogy with pthread_cond_wait().
Konstantin

Quoted 7 lines
Quoted 7 lines

The idea was to provide an intrinsic-like function - as in, raw instruction call, without anything extra. We even added the masks/values etc. only because there's no race-less way to combine UMONITOR/UMWAIT without those.

Perhaps we can provide a synchronize-able wrapper around it to avoid adding overhead to calls that function but doesn't need the sync mechanism?

Yes, might be two flavours, something like
rte_power_monitor() and rte_power_monitor_sync()
or whatever would be a better name.

Quoted 5 lines
Quoted 1 line

Also, how would having a spinlock help to synchronize? Are you suggesting we do UMWAIT on a spinlock address, or something to that effect?

I thought about something very similar to cond_wait() working model:

/*
* Caller has to obtain lock before calling that function.
*/
static inline int rte_power_monitor_sync(const volatile void *p,
const uint64_t expected_value, const uint64_t value_mask, const uint32_t state, const uint64_t tsc_timestamp, rte_spinlock_t *lck)

{
	/* do whatever preparations are needed */
               ....
	umonitor(p);

	if (value_mask != 0 && *((const uint64_t *)p) & value_mask == expected_value) {
		return 0;

}

	/* release lock and go to sleep */
	rte_spinlock_unlock(lck);
	rflags = umwait();

	/* grab lock back after wakeup */
	rte_spinlock_lock(lck);

	/* do rest of processing */
	....
}

/* similar go cond_signal */
static inline void rte_power_monitor_wakeup(volatile void *p)

{
	uint64_t v;

	v = __atomic_load_n(p, __ATOMIC_RELAXED);
	__atomic_compare_exchange_n(p, v, &v, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
}               

Now in librte_power:

struct pmd_queue_cfg {
       /* to protect state and wait_addr */
       rte_spinlock_t lck;
       enum pmd_mgmt_state pwr_mgmt_state;
       void *wait_addr;
       /* rest fields */
      ....
} __rte_cache_aligned;

static uint16_t
rte_power_mgmt_umwait(uint16_t port_id, uint16_t qidx,
struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, uint16_t max_pkts __rte_unused, void *_ __rte_unused)
{

        struct pmd_queue_cfg *q_conf;
        q_conf = &port_cfg[port_id].queue_cfg[qidx];

        if (unlikely(nb_rx == 0)) {
                q_conf->empty_poll_stats++;
                if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
                        volatile void *target_addr;
                        uint64_t expected, mask;
                        uint16_t ret;
		
	         /* grab the lock and check the state */
                       rte_spinlock_lock(&q_conf->lck);
	         If (q-conf->state == ENABLED) {
	                        ret = rte_eth_get_wake_addr(port_id, qidx,
                                                    &target_addr, &expected, &mask);
		          If (ret == 0) {
			q_conf->wait_addr = target_addr;
			rte_power_monitor(target_addr, ..., &q_conf->lck);
		         }	
		          /* reset the wait_addr */
		          q_conf->wait_addr = NULL;
	         }
	         rte_spinlock_unlock(&q_conf->lck);	
	         ....
}

nt
rte_power_pmd_mgmt_queue_disable(unsigned int lcore_id,

                                uint16_t port_id,
                                uint16_t queue_id)
{
	...
	/* grab the lock and change the state */
               rte_spinlock_lock(&q_conf->lck);
	queue_cfg->state = DISABLED;

	/* wakeup if necessary */
	If (queue_cfg->wakeup_addr != NULL)
		rte_power_monitor_wakeup(queue_cfg->wakeup_addr);

	rte_spinlock_unlock(&q_conf->lck);
	...
}
#241 lore raw

Re: [dpdk-dev] [PATCH v4 02/10] eal: add power management intrinsics

Quoted 192 lines · Konstantin
Quoted 82 lines
Quoted 82 lines
Quoted 81 lines
Quoted 67 lines
Quoted 54 lines
Quoted 54 lines
Quoted 53 lines
Quoted 25 lines
Quoted 19 lines
Quoted 9 lines

Add two new power management intrinsics, and provide an implementation
in eal/x86 based on UMONITOR/UMWAIT instructions. The instructions are implemented as raw byte opcodes because there is not yet widespread
compiler support for these instructions.

Quoted 9 lines

The power management instructions provide an architecture-specific function to either wait until a specified TSC timestamp is reached, or
optionally wait until either a TSC timestamp is reached or a memory
location is written to. The monitor function also provides an optional
comparison, to avoid sleeping when the expected write has already happened, and no more writes are expected.

Quoted 5 lines

I think what this API is missing - a function to wakeup sleeping core.
If user can/should use some system call to achieve that, then at least
it has to be clearly documented, even better some wrapper provided.

Quoted 7 lines

I don't think it's possible to do that without severely overcomplicating
the intrinsic and its usage, because AFAIK the only way to wake up a sleeping core would be to send some kind of interrupt to the core, or
trigger a write to the cache-line in question.

Yes, I think we either need a syscall that would do an IPI for us (on top of my head - membarrier() does that, might be there are some other syscalls too),
or something hand-made. For hand-made, I wonder would something like that
be safe and sufficient:
uint64_t val = atomic_load(addr);
CAS(addr, val, &val);
?
Anyway, one way or another - I think ability to wakeup core we put to sleep
have to be an essential part of this feature.
As I understand linux kernel will limit max amount of sleep time for these instructions:
https://lwn.net/Articles/790920/
But relying just on that, seems too vague for me:
- user can adjust that value
- wouldn't apply to older kernels and non-linux cases Konstantin

Quoted 5 lines
Quoted 1 line

This implies knowing the value the core is sleeping on.

You don't the value to wait for, you just need an address. And you can make wakeup function to accept address as a parameter, same as monitor() does.

Sorry, i meant the address. We don't know the address we're sleeping on.

Quoted 5 lines
Quoted 4 lines

That's not
always the case - with this particular PMD power management scheme, we get the address from the PMD and it stays inside the callback.

Quoted 7 lines
Quoted 3 lines

That's fine - you can store address inside you callback metadata and do wakeup as part of _disable_ function.

The address may be different, and by the time we access the address it may become stale, so i don't see how that would help unless you're suggesting to have some kind of synchronization mechanism there.

Yes, we'll need something to sync here for sure.
Sorry, I should say it straightway, to avoid further misunderstanding. Let say, associate a spin_lock with monitor(), by analogy with pthread_cond_wait().
Konstantin

Quoted 7 lines
Quoted 7 lines

The idea was to provide an intrinsic-like function - as in, raw instruction call, without anything extra. We even added the masks/values etc. only because there's no race-less way to combine UMONITOR/UMWAIT without those.

Perhaps we can provide a synchronize-able wrapper around it to avoid adding overhead to calls that function but doesn't need the sync mechanism?

Yes, might be two flavours, something like
rte_power_monitor() and rte_power_monitor_sync()
or whatever would be a better name.

Quoted 5 lines
Quoted 1 line

Also, how would having a spinlock help to synchronize? Are you suggesting we do UMWAIT on a spinlock address, or something to that effect?

I thought about something very similar to cond_wait() working model:

/*
* Caller has to obtain lock before calling that function.
*/
static inline int rte_power_monitor_sync(const volatile void *p,
const uint64_t expected_value, const uint64_t value_mask, const uint32_t state, const uint64_t tsc_timestamp, rte_spinlock_t *lck)
{
/* do whatever preparations are needed */

                ....

umonitor(p);

if (value_mask != 0 && *((const uint64_t *)p) & value_mask == expected_value) { return 0;
}

/* release lock and go to sleep */
rte_spinlock_unlock(lck);
rflags = umwait();

/* grab lock back after wakeup */
rte_spinlock_lock(lck);

/* do rest of processing */
....
}

/* similar go cond_signal */
static inline void rte_power_monitor_wakeup(volatile void *p) {
uint64_t v;

v = __atomic_load_n(p, __ATOMIC_RELAXED); __atomic_compare_exchange_n(p, v, &v, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED); }

Now in librte_power:

struct pmd_queue_cfg {
        /* to protect state and wait_addr */
        rte_spinlock_t lck;
        enum pmd_mgmt_state pwr_mgmt_state;
        void *wait_addr;
        /* rest fields */
       ....
} __rte_cache_aligned;

static uint16_t
rte_power_mgmt_umwait(uint16_t port_id, uint16_t qidx,
struct rte_mbuf **pkts __rte_unused, uint16_t nb_rx, uint16_t max_pkts __rte_unused, void *_ __rte_unused)
{

         struct pmd_queue_cfg *q_conf;
         q_conf = &port_cfg[port_id].queue_cfg[qidx];

         if (unlikely(nb_rx == 0)) {
                 q_conf->empty_poll_stats++;
                 if (unlikely(q_conf->empty_poll_stats > EMPTYPOLL_MAX)) {
                         volatile void *target_addr;
                         uint64_t expected, mask;
                         uint16_t ret;

          /* grab the lock and check the state */
                        rte_spinlock_lock(&q_conf->lck);
          If (q-conf->state == ENABLED) {
                         ret = rte_eth_get_wake_addr(port_id, qidx,
                                                     &target_addr, &expected, &mask);
           If (ret == 0) {
q_conf->wait_addr = target_addr;
rte_power_monitor(target_addr, ..., &q_conf->lck);
          }
           /* reset the wait_addr */
           q_conf->wait_addr = NULL;
          }
          rte_spinlock_unlock(&q_conf->lck);
          ....
}

nt
rte_power_pmd_mgmt_queue_disable(unsigned int lcore_id,

                                 uint16_t port_id,
                                 uint16_t queue_id)
{
...
/* grab the lock and change the state */
                rte_spinlock_lock(&q_conf->lck);

queue_cfg->state = DISABLED;

Quoted 8 lines

/* wakeup if necessary */
If (queue_cfg->wakeup_addr != NULL)
rte_power_monitor_wakeup(queue_cfg->wakeup_addr);

rte_spinlock_unlock(&q_conf->lck);
...
}

Yeah, seems that i understood you correctly the first time then. I'm not completely convinced that this overhead and complexity is worth the trouble, to be honest. I mean, it's not like we're going to sleep indefinitely, this isn't like pthread wait - the biggest sleep time i've seen was around half a second and i'm not sure there is a use case for enabling/disabling this functionality willy nilly ever 5 seconds.

Signature · 2 lines
Thanks,
Anatoly