On 4/16/26 12:40 PM, Kevin Traynor wrote:
> On 4/8/26 6:16 PM, Ilya Maximets wrote:
>> The 'pmd-perf-show' command provides all the same information and more.
>> It is also better visually structured and easier to read as a result.
>>
>> Let's remove the old 'pmd-stats-show' command, as there is no real need
>> to have two commands reporting the same data.
>>
>> The only difference until now was that 'pmd-perf-show' didn't provide
>> information for the "main" thread. This change makes it report the
>> statistics for the aggregated "main" thread as well, omitting things
>> related to CPU cycles, as we can't collect those for threads that are
>> not pinned. For the same reason histograms are also always disabled.
>> Omission is done by checking the total number of iterations to be zero.
>> "main" thread doesn't start/end iterations.
>>
>> The actual unixctl command is preserved undocumented and serves as an
>> alias for 'pmd-perf-show'. This should allow old scripts that are just
>> capturing the output for humans (or LLMs?) to read to keep working.
>> Note, however, that the exact output format for unixctl commands was
>> never a guarantee, so scripts that attempt to parse the output may
>> still break.
>>
>
> Hi Ilya,
>
> thanks for this, couple of comment below, otherwise LGTM.
>
>> Signed-off-by: Ilya Maximets <[email protected]>
>> ---
>>
>> Note: I believe the change in system-dpdk-offloads.at is correct,
>> but I didn't run the testsuite, as I have no hardware for it.
>>
>> Documentation/intro/install/afxdp.rst | 2 +-
>> Documentation/intro/install/dpdk.rst | 2 +-
>> Documentation/topics/dpdk/bridge.rst | 4 +-
>> Documentation/topics/dpdk/pmd.rst | 4 -
>> NEWS | 4 +
>> lib/dpif-netdev-perf.c | 39 +++--
>> lib/dpif-netdev-perf.h | 2 +-
>> lib/dpif-netdev-unixctl.man | 62 ++++---
>> lib/dpif-netdev.c | 158 ++++--------------
>> tests/dpif-netdev.at | 20 +--
>> tests/pmd.at | 47 +++---
>> tests/system-dpdk-offloads.at | 8 +-
>> .../plugins/system-logs/openvswitch.xml | 2 +-
>> 13 files changed, 136 insertions(+), 218 deletions(-)
>>
>> diff --git a/Documentation/intro/install/afxdp.rst
>> b/Documentation/intro/install/afxdp.rst
>> index 63a10e328..07225a885 100644
>> --- a/Documentation/intro/install/afxdp.rst
>> +++ b/Documentation/intro/install/afxdp.rst
>> @@ -273,7 +273,7 @@ Measure your system call rate by doing::
>>
>> Or, use OVS pmd tool::
>>
>> - ovs-appctl dpif-netdev/pmd-stats-show
>> + ovs-appctl dpif-netdev/pmd-perf-show
>>
>>
>> Example Script
>> diff --git a/Documentation/intro/install/dpdk.rst
>> b/Documentation/intro/install/dpdk.rst
>> index 6f4687bde..d5c897e8b 100644
>> --- a/Documentation/intro/install/dpdk.rst
>> +++ b/Documentation/intro/install/dpdk.rst
>> @@ -709,7 +709,7 @@ level:
>>
>> The average number of packets per output batch can be checked in PMD stats::
>>
>> - $ ovs-appctl dpif-netdev/pmd-stats-show
>> + $ ovs-appctl dpif-netdev/pmd-perf-show
>>
>> Limitations
>> ------------
>> diff --git a/Documentation/topics/dpdk/bridge.rst
>> b/Documentation/topics/dpdk/bridge.rst
>> index 03c4dd4e3..4468b904b 100644
>> --- a/Documentation/topics/dpdk/bridge.rst
>> +++ b/Documentation/topics/dpdk/bridge.rst
>> @@ -103,7 +103,7 @@ the packet itself and others (for example, VLAN tag or
>> Ethernet type) can be
>> extracted without fully parsing the packet. This allows OVS to
>> significantly
>> speed up packet forwarding for these flows with simple match criteria.
>> Statistics on the number of packets matched in this way can be found in a
>> -`simple match hits` counter of `ovs-appctl dpif-netdev/pmd-stats-show`
>> command.
>> +`Simple Match hits` counter of `ovs-appctl dpif-netdev/pmd-perf-show`
>> command.
>>
>> EMC Insertion Probability
>> -------------------------
>> @@ -127,7 +127,7 @@ If ``N`` is set to 1, an insertion will be performed for
>> every flow. If set to
>> With default ``N`` set to 100, higher megaflow hits will occur initially as
>> observed with pmd stats::
>>
>> - $ ovs-appctl dpif-netdev/pmd-stats-show
>> + $ ovs-appctl dpif-netdev/pmd-perf-show
>>
>> For certain traffic profiles with many parallel flows, it's recommended to
>> set
>> ``N`` to '0' to achieve higher forwarding performance.
>> diff --git a/Documentation/topics/dpdk/pmd.rst
>> b/Documentation/topics/dpdk/pmd.rst
>> index 2e8cf5edb..1589d521c 100644
>> --- a/Documentation/topics/dpdk/pmd.rst
>> +++ b/Documentation/topics/dpdk/pmd.rst
>> @@ -57,10 +57,6 @@ PMD Thread Statistics
>>
>> To show current stats::
>>
>> - $ ovs-appctl dpif-netdev/pmd-stats-show
>> -
>> -or::
>> -
>> $ ovs-appctl dpif-netdev/pmd-perf-show
>>
>> Detailed performance metrics for ``pmd-perf-show`` can also be enabled::
>> diff --git a/NEWS b/NEWS
>> index 1a3044cbf..b35bcff6e 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -3,6 +3,10 @@ Post-v3.7.0
>> - Userspace datapath:
>> * ARP/ND lookups for native tunnel are now rate limited. The holdout
>> timer can be configured with 'tnl/neigh/retrans_time'.
>> + - ovs-appctl:
>> + * 'dpif-netdev/pmd-stats-show' command was removed in favor of the more
>> + informative and better structured 'dpif-netdev/pmd-perf-show', which
>> + now also provides statistics for the "main" thread.
>>
>>
>> v3.7.0 - 16 Feb 2026
>> diff --git a/lib/dpif-netdev-perf.c b/lib/dpif-netdev-perf.c
>> index 1cd4ee084..ba370d7c1 100644
>> --- a/lib/dpif-netdev-perf.c
>> +++ b/lib/dpif-netdev-perf.c
>> @@ -233,7 +233,8 @@ pmd_perf_format_overall_stats(struct ds *str, struct
>> pmd_perf_stats *s,
>> uint64_t sleep_iter = stats[PMD_SLEEP_ITER];
>> uint64_t tot_sleep_cycles = stats[PMD_CYCLES_SLEEP];
>>
>> - ds_put_format(str,
>> + if (tot_iter) {
>
> While the change is to cater for main thread, it also changes display
> for pmd cores with no iterations. Previously there was:
>
> pmd thread numa_id 1 core_id 9:
>
> Iterations: 0 (0.00 us/it)
> - Used TSC cycles: 0 ( 0.0 % of total cycles)
> - idle iterations: 0 ( 0.0 % of used cycles)
> - busy iterations: 0 ( 0.0 % of used cycles)
> - sleep iterations: 0 ( 0.0 % of iterations)
> Sleep time (us): 0 ( 0 us/iteration avg.)
> Rx packets: 0
> Tx packets: 0
>
> That is now changed so that iterations of zero are implicit.
>
> pmd thread numa_id 1 core_id 11:
>
> Rx packets: 0
> Tx packets: 0
>
>
> Considering we can also have a case where there are iterations but no
> packets like below, i think we should leave zero iterations explicit for
> pmd thread as it currently is.
>
> pmd thread numa_id 0 core_id 8:
>
> Iterations: 17369522 (0.15 us/it)
> - Used TSC cycles: 6816002305 ( 80.1 % of total cycles)
> - idle iterations: 17369522 (100.0 % of used cycles)
> - busy iterations: 0 ( 0.0 % of used cycles)
> - sleep iterations: 0 ( 0.0 % of iterations)
> Sleep time (us): 0 ( 0 us/iteration avg.)
> Rx packets: 0
> Tx packets: 0
>
>
> I agree that for main thread it doesn't make sense to display it, so
> maybe we could add a bool to pmd_perf_format_overall_stats() args to
> make showing the iteration section conditional, then set differently
> when the non pmd core in pmd_info_show_perf().
Makes sense. I'll add an argument to this function.
>
>> + ds_put_format(str,
>> " Iterations: %12"PRIu64" (%.2f us/it)\n"
>
>> " - Used TSC cycles: %12"PRIu64" (%5.1f %% of total
>> cycles)\n"
>
> aside from comments above, with current version there is no need to
> re-check for tot_iter (not shown in diff)
True. Though I'll need to keep the code as-is in v2, since the 'if'
condition will change to the new function argument and we'll still
need to check the tot_iter.
>
>> " - idle iterations: %12"PRIu64" (%5.1f %% of used cycles)\n"
>> @@ -252,9 +253,18 @@ pmd_perf_format_overall_stats(struct ds *str, struct
>> pmd_perf_stats *s,
>> sleep_iter, tot_iter ? 100.0 * sleep_iter / tot_iter : 0,
>> tot_sleep_cycles * us_per_cycle,
>> sleep_iter ? (tot_sleep_cycles * us_per_cycle) / sleep_iter :
>> 0);
>> + }
>> if (rx_packets > 0) {
>> ds_put_format(str,
>> - " Rx packets: %12"PRIu64" (%.0f Kpps, %.0f
>> cycles/pkt)\n"
>> + " Rx packets: %12"PRIu64" (%.0f Kpps",
>> + rx_packets, (rx_packets / duration) / 1000);
>> + if (tot_iter) {
>> + ds_put_format(str, ", %.0f cycles/pkt",
>> + 1.0 * stats[PMD_CYCLES_ITER_BUSY] / rx_packets);
>> + }
>> + ds_put_cstr(str, ")\n");
>> +
>> + ds_put_format(str,
>> " Datapath passes: %12"PRIu64" (%.2f passes/pkt)\n"
>> " - PHWOL hits: %12"PRIu64" (%5.1f %%)\n"
>> " - MFEX Opt hits: %12"PRIu64" (%5.1f %%)\n"
>> @@ -262,11 +272,7 @@ pmd_perf_format_overall_stats(struct ds *str, struct
>> pmd_perf_stats *s,
>> " - EMC hits: %12"PRIu64" (%5.1f %%)\n"
>> " - SMC hits: %12"PRIu64" (%5.1f %%)\n"
>> " - Megaflow hits: %12"PRIu64" (%5.1f %%, %.2f "
>> - "subtbl lookups/hit)\n"
>> - " - Upcalls: %12"PRIu64" (%5.1f %%, %.1f
>> us/upcall)\n"
>> - " - Lost upcalls: %12"PRIu64" (%5.1f %%)\n",
>> - rx_packets, (rx_packets / duration) / 1000,
>> - 1.0 * stats[PMD_CYCLES_ITER_BUSY] / rx_packets,
>> + "subtbl lookups/hit)\n",
>> passes, 1.0 * passes / rx_packets,
>> stats[PMD_STAT_PHWOL_HIT],
>> 100.0 * stats[PMD_STAT_PHWOL_HIT] / passes,
>> @@ -282,11 +288,20 @@ pmd_perf_format_overall_stats(struct ds *str, struct
>> pmd_perf_stats *s,
>> 100.0 * stats[PMD_STAT_MASKED_HIT] / passes,
>> stats[PMD_STAT_MASKED_HIT]
>> ? 1.0 * stats[PMD_STAT_MASKED_LOOKUP] /
>> stats[PMD_STAT_MASKED_HIT]
>> - : 0,
>> - upcalls, 100.0 * upcalls / passes,
>> - upcalls ? (upcall_cycles * us_per_cycle) / upcalls : 0,
>> - stats[PMD_STAT_LOST],
>> - 100.0 * stats[PMD_STAT_LOST] / passes);
>> + : 0);
>> +
>> + ds_put_format(str,
>> + " - Upcalls: %12"PRIu64" (%5.1f %%",
>> + upcalls, 100.0 * upcalls / passes);
>> + if (tot_iter) {
>> + ds_put_format(str, ", %.1f us/upcall",
>> + upcalls ? (upcall_cycles * us_per_cycle) / upcalls : 0);
>> + }
>> + ds_put_cstr(str, ")\n");
>> +
>> + ds_put_format(str,
>> + " - Lost upcalls: %12"PRIu64" (%5.1f %%)\n",
>> + stats[PMD_STAT_LOST], 100.0 * stats[PMD_STAT_LOST] / passes);
>> } else {
>> ds_put_format(str,
>> " Rx packets: %12d\n", 0);
>> diff --git a/lib/dpif-netdev-perf.h b/lib/dpif-netdev-perf.h
>> index 84beced15..8a41afa8a 100644
>> --- a/lib/dpif-netdev-perf.h
>> +++ b/lib/dpif-netdev-perf.h
>> @@ -317,7 +317,7 @@ void pmd_perf_read_counters(struct pmd_perf_stats *s,
>> * NON-PMD they might be updated from multiple threads, but we can live
>> * with losing a rare update as 100% accuracy is not required.
>> * However, as counters are read for display from outside the PMD thread
>> - * with e.g. pmd-stats-show, we make sure that the 64-bit read and store
>> + * with e.g. pmd-perf-show, we make sure that the 64-bit read and store
>> * operations are atomic also on 32-bit systems so that readers cannot
>> * not read garbage. On 64-bit systems this incurs no overhead. */
>>
>> diff --git a/lib/dpif-netdev-unixctl.man b/lib/dpif-netdev-unixctl.man
>> index 8cd847416..3d5ab437c 100644
>> --- a/lib/dpif-netdev-unixctl.man
>> +++ b/lib/dpif-netdev-unixctl.man
>> @@ -6,44 +6,22 @@ argument can be omitted. By default the commands present
>> data for all pmd
>> threads in the datapath. By specifying the "-pmd Core" option one can filter
>> the output for a single pmd in the datapath.
>> .
>> -.IP "\fBdpif-netdev/pmd-stats-show\fR [\fB-pmd\fR \fIcore\fR] [\fIdp\fR]"
>> -Shows performance statistics for one or all pmd threads of the datapath
>> -\fIdp\fR. The special thread "main" sums up the statistics of every non pmd
>> -thread.
>> -
>> -The sum of "phwol hits", "simple match hits", "emc hits", "smc hits",
>> -"megaflow hits" and "miss" is the number of packet lookups performed by the
>> -datapath. Beware that a recirculated packet experiences one additional
>> lookup
>> -per recirculation, so there may be more lookups than forwarded packets in
>> the
>> -datapath.
>> -
>> -The MFEX Opt hits displays the number of packets that are processed by the
>> -optimized miniflow extract implementations.
>> -
>> -Cycles are counted using the TSC or similar facilities (when available on
>> -the platform). The duration of one cycle depends on the processing platform.
>> -
>> -"idle cycles" refers to cycles spent in PMD iterations not forwarding any
>> -any packets. "processing cycles" refers to cycles spent in PMD iterations
>> -forwarding at least one packet, including the cost for polling, processing
>> and
>> -transmitting said packets.
>> -
>> -To reset these counters use \fBdpif-netdev/pmd-stats-clear\fR.
>> -.
>> .IP "\fBdpif-netdev/pmd-stats-clear\fR [\fIdp\fR]"
>> Resets to zero the per pmd thread performance numbers shown by the
>> -\fBdpif-netdev/pmd-stats-show\fR and \fBdpif-netdev/pmd-perf-show\fR
>> commands.
>> -It will NOT reset datapath or bridge statistics, only the values shown by
>> -the above commands.
>> +\fBdpif-netdev/pmd-perf-show\fR command. It will NOT reset datapath or
>> bridge
>> +statistics, only the values shown by the above command.
>> .
>> .IP "\fBdpif-netdev/pmd-perf-show\fR [\fB-nh\fR] [\fB-it\fR \fIiter_len\fR]
>> \
>> [\fB-ms\fR \fIms_len\fR] [\fB-pmd\fR \fIcore\fR] [\fIdp\fR]"
>> Shows detailed performance metrics for one or all pmds threads of the
>> -user space datapath.
>> +user space datapath. The special thread "main" sums up the statistics of
>> every
>> +non pmd thread.
>>
>> -The collection of detailed statistics can be controlled by a new
>> -configuration parameter "other_config:pmd-perf-metrics". By default it
>> -is disabled. The run-time overhead, when enabled, is in the order of 1%.
>> +The collection of additional detailed statistics can be controlled by a
>> +configuration parameter \fBother-config:pmd-perf-metrics\fR. By default it
>> is
>> +disabled. The run-time overhead, when enabled, is in the order of 1%.
>> +
>> +Collected statistics include:
>>
>> .RS
>> .IP
>> @@ -153,8 +131,26 @@ pmd thread numa_id 0 core_id 1:
>> .RE
>> .IP
>> Here "Rx packets" actually reflects the number of packets forwarded by the
>> -datapath. "Datapath passes" matches the number of packet lookups as
>> -reported by the \fBdpif-netdev/pmd-stats-show\fR command.
>> +datapath.
>> +
>> +The sum of "PHWOL hits", "Simple Match hits", "EMC hits", "SMC hits",
>> +"Megaflow hits" and "Upcalls" is the number of packet lookups performed by
>> the
>> +datapath and it is reported as "Datapath passes". Beware that a
>> recirculated
>> +packet experiences one additional lookup per recirculation, so there may be
>> +more lookups than forwarded packets in the datapath.
>> +
>> +The "MFEX Opt hits" displays the number of packets that are processed by the
>> +optimized miniflow extract implementations.
>> +
>> +Cycles are counted using the TSC or similar facilities (when available on
>> +the platform). The duration of one cycle depends on the processing
>> platform.
>> +Statistics based on cycles are not reported for the "main" thread, since the
>> +accurate accounting of CPU cycles is not possible in this case.
>> +
>> +"idle iterations" refers to PMD iterations that didn't not result in
>> processing
>
> typo, "didn't not"
Yep. Thanks!
Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev