On 11.01.2018 15:15, Ilya Maximets wrote:
> I guess, this version was compile tested only.
> 
> Comments inline.
> 
> Best regards, Ilya Maximets.
> 
> On 11.01.2018 10:39, Jan Scheurich wrote:
>> Add module dpif-netdev-perf to host all PMD performance-related
>> data structures and functions in dpif-netdev. Refactor the PMD
>> stats handling in dpif-netdev and delegate whatever possible into
>> the new module, using clean interfaces to shield dpif-netdev from
>> the implementation details. Accordingly, the all PMD statistics
>> members are moved from the main struct dp_netdev_pmd_thread into
>> a dedicated member of type struct pmd_perf_stats.
>>
>> Include Darrel's prior refactoring of PMD stats contained in
>> [PATCH v5,2/3] dpif-netdev: Refactor some pmd stats:
>>
>> 1. The cycles per packet counts are now based on packets
>> received rather than packet passes through the datapath.
>>
>> 2. Packet counters are now kept for packets received and
>> packets recirculated. These are kept as separate counters for
>> maintainability reasons. The cost of incrementing these counters
>> is negligible.  These new counters are also displayed to the user.
>>
>> 3. A display statistic is added for the average number of
>> datapath passes per packet. This should be useful for user
>> debugging and understanding of packet processing.
>>
>> 4. The user visible 'miss' counter is used for successful upcalls,
>> rather than the sum of sucessful and unsuccessful upcalls. Hence,
>> this becomes what user historically understands by OVS 'miss upcall'.
>> The user display is annotated to make this clear as well.
>>
>> 5. The user visible 'lost' counter remains as failed upcalls, but
>> is annotated to make it clear what the meaning is.
>>
>> 6. The enum pmd_stat_type is annotated to make the usage of the
>> stats counters clear.
>>
>> 7. The subtable lookup stats is renamed to make it clear that it
>> relates to masked lookups.
>>
>> 8. The PMD stats test is updated to handle the new user stats of
>> packets received, packets recirculated and average number of datapath
>> passes per packet.
>>
>> On top of that introduce a "-pmd <core>" option to the PMD info
>> commands to filter the output for a single PMD.
>>
>> Signed-off-by: Jan Scheurich <[email protected]>
>> Co-authored-by: Darrell Ball <[email protected]>
>> Signed-off-by: Darrell Ball <[email protected]>
>> ---
>>  lib/automake.mk        |   2 +
>>  lib/dpif-netdev-perf.c |  67 +++++++++
>>  lib/dpif-netdev-perf.h | 151 +++++++++++++++++++++
>>  lib/dpif-netdev.c      | 360 
>> +++++++++++++++++++++----------------------------
>>  tests/pmd.at           |  22 +--
>>  5 files changed, 384 insertions(+), 218 deletions(-)
>>  create mode 100644 lib/dpif-netdev-perf.c
>>  create mode 100644 lib/dpif-netdev-perf.h
>>
>> diff --git a/lib/automake.mk b/lib/automake.mk
>> index 4b38a11..159319f 100644
>> --- a/lib/automake.mk
>> +++ b/lib/automake.mk
>> @@ -80,6 +80,8 @@ lib_libopenvswitch_la_SOURCES = \
>>      lib/dpdk.h \
>>      lib/dpif-netdev.c \
>>      lib/dpif-netdev.h \
>> +    lib/dpif-netdev-perf.c \
>> +    lib/dpif-netdev-perf.h \
>>      lib/dpif-provider.h \
>>      lib/dpif.c \
>>      lib/dpif.h \
>> diff --git a/lib/dpif-netdev-perf.c b/lib/dpif-netdev-perf.c
>> new file mode 100644
>> index 0000000..f853fd8
>> --- /dev/null
>> +++ b/lib/dpif-netdev-perf.c
>> @@ -0,0 +1,67 @@
>> +/*
>> + * Copyright (c) 2017 Ericsson AB.
>> + *
>> + * Licensed under the Apache License, Version 2.0 (the "License");
>> + * you may not use this file except in compliance with the License.
>> + * You may obtain a copy of the License at:
>> + *
>> + *     http://www.apache.org/licenses/LICENSE-2.0
>> + *
>> + * Unless required by applicable law or agreed to in writing, software
>> + * distributed under the License is distributed on an "AS IS" BASIS,
>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>> + * See the License for the specific language governing permissions and
>> + * limitations under the License.
>> + */
>> +
>> +#include <config.h>
>> +
>> +#ifdef DPDK_NETDEV
>> +#include <rte_cycles.h>
>> +#endif
>> +
>> +#include "openvswitch/dynamic-string.h"
>> +#include "openvswitch/vlog.h"
>> +#include "dpif-netdev-perf.h"
>> +#include "timeval.h"
>> +
>> +VLOG_DEFINE_THIS_MODULE(pmd_perf);
>> +
>> +void
>> +pmd_perf_stats_init(struct pmd_perf_stats *s)
>> +{
>> +    memset(s, 0 , sizeof(*s));
>> +    s->start_ms = time_msec();
>> +}
>> +
>> +void
>> +pmd_perf_read_counters(struct pmd_perf_stats *s,
>> +                       uint64_t stats[PMD_N_STATS])
>> +{
>> +    uint64_t val;
>> +
>> +    /* These loops subtracts reference values (.zero[*]) from the counters.
>> +     * Since loads and stores are relaxed, it might be possible for a 
>> .zero[*]
>> +     * value to be more recent than the current value we're reading from the
>> +     * counter.  This is not a big problem, since these numbers are not
>> +     * supposed to be 100% accurate, but we should at least make sure that
>> +     * the result is not negative. */
>> +    for (int i = 0; i < PMD_N_STATS; i++) {
>> +        atomic_read_relaxed(&s->counters.n[i], &val);
>> +        if (val > s->counters.zero[i]) {
>> +            stats[i] = val - s->counters.zero[i];
>> +        } else {
>> +            stats[i] = 0;
>> +        }
>> +    }
>> +}
>> +
>> +void
>> +pmd_perf_stats_clear(struct pmd_perf_stats *s)
>> +{
>> +    s->start_ms = 0; /* Marks start of clearing. */
>> +    for (int i = 0; i < PMD_N_STATS; i++) {
>> +        atomic_read_relaxed(&s->counters.n[i], &s->counters.zero[i]);
>> +    }
>> +    s->start_ms = time_msec(); /* Clearing finished. */
>> +}
>> diff --git a/lib/dpif-netdev-perf.h b/lib/dpif-netdev-perf.h
>> new file mode 100644
>> index 0000000..41f4e85
>> --- /dev/null
>> +++ b/lib/dpif-netdev-perf.h
>> @@ -0,0 +1,151 @@
>> +/*
>> + * Copyright (c) 2017 Ericsson AB.
>> + *
>> + * Licensed under the Apache License, Version 2.0 (the "License");
>> + * you may not use this file except in compliance with the License.
>> + * You may obtain a copy of the License at:
>> + *
>> + *     http://www.apache.org/licenses/LICENSE-2.0
>> + *
>> + * Unless required by applicable law or agreed to in writing, software
>> + * distributed under the License is distributed on an "AS IS" BASIS,
>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>> + * See the License for the specific language governing permissions and
>> + * limitations under the License.
>> + */
>> +
>> +#ifndef DPIF_NETDEV_PERF_H
>> +#define DPIF_NETDEV_PERF_H 1
>> +
>> +#include <stdbool.h>
>> +#include <stddef.h>
>> +#include <stdint.h>
>> +#include <string.h>
>> +#include <math.h>
>> +
>> +#include "openvswitch/vlog.h"
>> +#include "ovs-atomic.h"
>> +#include "timeval.h"
>> +#include "unixctl.h"
>> +#include "util.h"
>> +
>> +#ifdef  __cplusplus
>> +extern "C" {
>> +#endif
>> +
>> +/* This module encapsulates data structures and functions to maintain PMD
>> + * performance metrics such as packet counters, execution cycles. It
>> + * provides a clean API for dpif-netdev to initialize, update and read and
>> + * reset these metrics.
>> + */
>> +
>> +/* Set of counter types maintained in pmd_perf_stats. */
>> +
>> +enum pmd_stat_type {
>> +    PMD_STAT_EXACT_HIT,     /* Packets that had an exact match (emc). */
>> +    PMD_STAT_MASKED_HIT,    /* Packets that matched in the flow table. */
>> +    PMD_STAT_MISS,          /* Packets that did not match and upcall was 
>> ok. */
>> +    PMD_STAT_LOST,          /* Packets that did not match and upcall 
>> failed. */
>> +                            /* The above statistics account for the total
>> +                             * number of packet passes through the datapath
>> +                             * pipeline and should not be overlapping with 
>> each
>> +                             * other. */
>> +    PMD_STAT_MASKED_LOOKUP, /* Number of subtable lookups for flow table
>> +                               hits. Each MASKED_HIT hit will have >= 1
>> +                               MASKED_LOOKUP(s). */
>> +    PMD_STAT_RECV,          /* Packets entering the datapath pipeline from 
>> an
>> +                             * interface. */
>> +    PMD_STAT_RECIRC,        /* Packets reentering the datapath pipeline due 
>> to
>> +                             * recirculation. */
>> +    PMD_STAT_SENT_PKTS,     /* Packets that have been sent. */
>> +    PMD_STAT_SENT_BATCHES,  /* Number of batches sent. */
>> +    PMD_CYCLES_POLL_IDLE,   /* Cycles spent unsuccessful polling. */
>> +    PMD_CYCLES_POLL_BUSY,   /* Cycles spent successfully polling and
>> +                             * processing polled packets. */
>> +    PMD_CYCLES_OVERHEAD,    /* Cycles spent for other tasks. */
>> +    PMD_CYCLES_ITER_IDLE,   /* Cycles spent in idle iterations. */
>> +    PMD_CYCLES_ITER_BUSY,   /* Cycles spent in busy iterations. */
>> +    PMD_N_STATS
>> +};
>> +
>> +/* Array of PMD counters indexed by enum pmd_stat_type.
>> + * The n[] array contains the actual counter values since initialization
>> + * of the PMD. Counters are atomically updated from the PMD but are
>> + * read and cleared also from other processes. To clear the counters at
>> + * PMD run-time, the current counter values are copied over to the zero[]
>> + * array. To read counters we subtract zero[] value from n[]. */
>> +
>> +struct pmd_counters {
>> +    atomic_uint64_t n[PMD_N_STATS];     /* Value since _init(). */
>> +    uint64_t zero[PMD_N_STATS];         /* Value at last _clear().  */
>> +};
>> +
>> +/* Container for all performance metrics of a PMD.
>> + * Part of the struct dp_netdev_pmd_thread. */
>> +
>> +struct pmd_perf_stats {
>> +    /* Start of the current performance measurement period.
>> +     * While a new measurement period is being started with
>> +     * ovs-appctl dpif-netdev/pmd-stats-clear, start_ms is set
>> +     * to zero to lock out operations from accessing inconsistent
>> +     * data. */
>> +    uint64_t start_ms;
>> +    /* Start of the current PMD iteration in TSC cycles.*/
>> +    uint64_t last_tsc;
>> +    /* Set of PMD counters with their zero offsets. */
>> +    struct pmd_counters counters;
>> +};
>> +
>> +void pmd_perf_stats_init(struct pmd_perf_stats *s);
>> +void pmd_perf_stats_clear(struct pmd_perf_stats *s);
>> +void pmd_perf_read_counters(struct pmd_perf_stats *s,
>> +                            uint64_t stats[PMD_N_STATS]);
>> +
>> +/* PMD performance counters are updated lock-less. For real PMDs
>> + * they are only updated from the PMD thread itself. In the case of the
>> + * 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
>> + * operations are atomic also on 32-bit systems so that readers cannot
>> + * not read garbage. On 64-bit systems this incurs no overhead. */
>> +
>> +static inline void
>> +pmd_perf_update_counter(struct pmd_perf_stats *s,
>> +                        enum pmd_stat_type counter, int delta)
>> +{
>> +    uint64_t tmp;
>> +    atomic_read_relaxed(&s->counters.n[counter], &tmp);
>> +    tmp += delta;
>> +    atomic_store_relaxed(&s->counters.n[counter], tmp);
>> +}
>> +
>> +static inline void
>> +pmd_perf_start_iteration(struct pmd_perf_stats *s, uint64_t now_tsc)
>> +{
>> +    if (OVS_UNLIKELY(s->start_ms == 0)) {
>> +        /* Stats not yet fully initialized. */
>> +        return;
>> +    }
>> +    s->last_tsc = now_tsc;
>> +}
>> +
>> +static inline void
>> +pmd_perf_end_iteration(struct pmd_perf_stats *s, uint64_t now_tsc,
>> +                       int packets)
>> +{
>> +    uint64_t cycles = now_tsc - s->last_tsc;
>> +
>> +    /* No need for atomic updates as only invoked within PMD thread. */
>> +    if (packets > 0) {
>> +        s->counters.n[PMD_CYCLES_ITER_BUSY] += cycles;
>> +    } else {
>> +        s->counters.n[PMD_CYCLES_ITER_IDLE] += cycles;
>> +    }
>> +}
>> +
>> +#ifdef  __cplusplus
>> +}
>> +#endif
>> +
>> +#endif /* DPIF_NETDEV_PERF_H */
>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>> index c7d157a..538d5ce 100644
>> --- a/lib/dpif-netdev.c
>> +++ b/lib/dpif-netdev.c
>> @@ -44,6 +44,7 @@
>>  #include "csum.h"
>>  #include "dp-packet.h"
>>  #include "dpif.h"
>> +#include "dpif-netdev-perf.h"
>>  #include "dpif-provider.h"
>>  #include "dummy.h"
>>  #include "fat-rwlock.h"
>> @@ -331,25 +332,6 @@ static struct dp_netdev_port 
>> *dp_netdev_lookup_port(const struct dp_netdev *dp,
>>                                                      odp_port_t)
>>      OVS_REQUIRES(dp->port_mutex);
>>  
>> -enum dp_stat_type {
>> -    DP_STAT_EXACT_HIT,          /* Packets that had an exact match (emc). */
>> -    DP_STAT_MASKED_HIT,         /* Packets that matched in the flow table. 
>> */
>> -    DP_STAT_MISS,               /* Packets that did not match. */
>> -    DP_STAT_LOST,               /* Packets not passed up to the client. */
>> -    DP_STAT_LOOKUP_HIT,         /* Number of subtable lookups for flow table
>> -                                   hits */
>> -    DP_STAT_SENT_PKTS,          /* Packets that has been sent. */
>> -    DP_STAT_SENT_BATCHES,       /* Number of batches sent. */
>> -    DP_N_STATS
>> -};
>> -
>> -enum pmd_cycles_counter_type {
>> -    PMD_CYCLES_IDLE,            /* Cycles spent idle or unsuccessful 
>> polling */
>> -    PMD_CYCLES_PROCESSING,      /* Cycles spent successfully polling and
>> -                                 * processing polled packets */
>> -    PMD_N_CYCLES
>> -};
>> -
>>  enum rxq_cycles_counter_type {
>>      RXQ_CYCLES_PROC_CURR,       /* Cycles spent successfully polling and
>>                                     processing packets during the current
>> @@ -499,21 +481,6 @@ struct dp_netdev_actions *dp_netdev_flow_get_actions(
>>      const struct dp_netdev_flow *);
>>  static void dp_netdev_actions_free(struct dp_netdev_actions *);
>>  
>> -/* Contained by struct dp_netdev_pmd_thread's 'stats' member.  */
>> -struct dp_netdev_pmd_stats {
>> -    /* Indexed by DP_STAT_*. */
>> -    atomic_ullong n[DP_N_STATS];
>> -};
>> -
>> -/* Contained by struct dp_netdev_pmd_thread's 'cycle' member.  */
>> -struct dp_netdev_pmd_cycles {
>> -    /* Indexed by PMD_CYCLES_*. */
>> -    atomic_ullong n[PMD_N_CYCLES];
>> -};
>> -
>> -static void dp_netdev_count_packet(struct dp_netdev_pmd_thread *,
>> -                                   enum dp_stat_type type, int cnt);
>> -
>>  struct polled_queue {
>>      struct dp_netdev_rxq *rxq;
>>      odp_port_t port_no;
>> @@ -595,12 +562,6 @@ struct dp_netdev_pmd_thread {
>>         are stored for each polled rxq. */
>>      long long int rxq_next_cycle_store;
>>  
>> -    /* Statistics. */
>> -    struct dp_netdev_pmd_stats stats;
>> -
>> -    /* Cycles counters */
>> -    struct dp_netdev_pmd_cycles cycles;
>> -
>>      /* Current context of the PMD thread. */
>>      struct dp_netdev_pmd_thread_ctx ctx;
>>  
>> @@ -638,12 +599,8 @@ struct dp_netdev_pmd_thread {
>>      struct hmap tnl_port_cache;
>>      struct hmap send_port_cache;
>>  
>> -    /* Only a pmd thread can write on its own 'cycles' and 'stats'.
>> -     * The main thread keeps 'stats_zero' and 'cycles_zero' as base
>> -     * values and subtracts them from 'stats' and 'cycles' before
>> -     * reporting to the user */
>> -    unsigned long long stats_zero[DP_N_STATS];
>> -    uint64_t cycles_zero[PMD_N_CYCLES];
>> +    /* Keep track of detailed PMD performance statistics. */
>> +    struct pmd_perf_stats perf_stats;
>>  
>>      /* Set to true if the pmd thread needs to be reloaded. */
>>      bool need_reload;
>> @@ -833,47 +790,10 @@ enum pmd_info_type {
>>  };
>>  
>>  static void
>> -pmd_info_show_stats(struct ds *reply,
>> -                    struct dp_netdev_pmd_thread *pmd,
>> -                    unsigned long long stats[DP_N_STATS],
>> -                    uint64_t cycles[PMD_N_CYCLES])
>> +format_pmd_thread(struct ds *reply, struct dp_netdev_pmd_thread *pmd)
>>  {
>> -    unsigned long long total_packets;
>> -    uint64_t total_cycles = 0;
>> -    double lookups_per_hit = 0, packets_per_batch = 0;
>> -    int i;
>> -
>> -    /* These loops subtracts reference values ('*_zero') from the counters.
>> -     * Since loads and stores are relaxed, it might be possible for a 
>> '*_zero'
>> -     * value to be more recent than the current value we're reading from the
>> -     * counter.  This is not a big problem, since these numbers are not
>> -     * supposed to be too accurate, but we should at least make sure that
>> -     * the result is not negative. */
>> -    for (i = 0; i < DP_N_STATS; i++) {
>> -        if (stats[i] > pmd->stats_zero[i]) {
>> -            stats[i] -= pmd->stats_zero[i];
>> -        } else {
>> -            stats[i] = 0;
>> -        }
>> -    }
>> -
>> -    /* Sum of all the matched and not matched packets gives the total.  */
>> -    total_packets = stats[DP_STAT_EXACT_HIT] + stats[DP_STAT_MASKED_HIT]
>> -                    + stats[DP_STAT_MISS];
>> -
>> -    for (i = 0; i < PMD_N_CYCLES; i++) {
>> -        if (cycles[i] > pmd->cycles_zero[i]) {
>> -           cycles[i] -= pmd->cycles_zero[i];
>> -        } else {
>> -            cycles[i] = 0;
>> -        }
>> -
>> -        total_cycles += cycles[i];
>> -    }
>> -
>>      ds_put_cstr(reply, (pmd->core_id == NON_PMD_CORE_ID)
>>                          ? "main thread" : "pmd thread");
>> -
>>      if (pmd->numa_id != OVS_NUMA_UNSPEC) {
>>          ds_put_format(reply, " numa_id %d", pmd->numa_id);
>>      }
>> @@ -881,23 +801,52 @@ pmd_info_show_stats(struct ds *reply,
>>          ds_put_format(reply, " core_id %u", pmd->core_id);
>>      }
>>      ds_put_cstr(reply, ":\n");
>> +}
>> +
>> +static void
>> +pmd_info_show_stats(struct ds *reply,
>> +                    struct dp_netdev_pmd_thread *pmd)
>> +{
>> +    uint64_t stats[PMD_N_STATS];
>> +    uint64_t total_cycles, total_packets;
>> +    double passes_per_pkt = 0;
>> +    double lookups_per_hit = 0;
>> +    double packets_per_batch = 0;
>> +
>> +    pmd_perf_read_counters(&pmd->perf_stats, stats);
>> +    total_cycles = stats[PMD_CYCLES_ITER_IDLE]
>> +                         + stats[PMD_CYCLES_ITER_BUSY];
>> +    total_packets = stats[PMD_STAT_RECV];
>> +
>> +    format_pmd_thread(reply, pmd);
>>  
>> -    if (stats[DP_STAT_MASKED_HIT] > 0) {
>> -        lookups_per_hit = stats[DP_STAT_LOOKUP_HIT]
>> -                          / (double) stats[DP_STAT_MASKED_HIT];
>> +    if (total_packets > 0) {
>> +        passes_per_pkt = (total_packets + stats[PMD_STAT_RECIRC])
>> +                            / (double) total_packets;
>>      }
>> -    if (stats[DP_STAT_SENT_BATCHES] > 0) {
>> -        packets_per_batch = stats[DP_STAT_SENT_PKTS]
>> -                            / (double) stats[DP_STAT_SENT_BATCHES];
>> +    if (stats[PMD_STAT_MASKED_HIT] > 0) {
>> +        lookups_per_hit = stats[PMD_STAT_MASKED_LOOKUP]
>> +                            / (double) stats[PMD_STAT_MASKED_HIT];
>> +    }
>> +    if (stats[PMD_STAT_SENT_BATCHES] > 0) {
>> +        packets_per_batch = stats[PMD_STAT_SENT_PKTS]
>> +                            / (double) stats[PMD_STAT_SENT_BATCHES];
>>      }
>>  
>>      ds_put_format(reply,
>> -                  "\temc hits:%llu\n\tmegaflow hits:%llu\n"
>> -                  "\tavg. subtable lookups per hit:%.2f\n"
>> -                  "\tmiss:%llu\n\tlost:%llu\n"
>> -                  "\tavg. packets per output batch: %.2f\n",
>> -                  stats[DP_STAT_EXACT_HIT], stats[DP_STAT_MASKED_HIT],
>> -                  lookups_per_hit, stats[DP_STAT_MISS], stats[DP_STAT_LOST],
>> +                  "\tpackets received:%"PRIu64"\n"
>> +                  "\tpacket recirculations:%"PRIu64"\n"
>> +                  "\tavg. datapath passes per packet:%.02f\n"
>> +                  "\temc hits:%"PRIu64"\n"
>> +                  "\tmegaflow hits:%"PRIu64"\n"
>> +                  "\tavg. subtable lookups per megaflow hit:%.02f\n"
>> +                  "\tmiss with success upcall:%"PRIu64"\n"
>> +                  "\tmiss with failed upcall:%"PRIu64"\n"
>> +                  "\tavg. packets per output batch:%.02f\n",
>> +                  total_packets, stats[PMD_STAT_RECIRC],
>> +                  passes_per_pkt, stats[PMD_STAT_EXACT_HIT],
>> +                  stats[PMD_STAT_MASKED_HIT], lookups_per_hit,
>> +                  stats[PMD_STAT_MISS], stats[PMD_STAT_LOST],
>>                    packets_per_batch);
>>  
>>      if (total_cycles == 0) {
>> @@ -907,46 +856,25 @@ pmd_info_show_stats(struct ds *reply,
>>      ds_put_format(reply,
>>                    "\tidle cycles:%"PRIu64" (%.02f%%)\n"
>>                    "\tprocessing cycles:%"PRIu64" (%.02f%%)\n",
>> -                  cycles[PMD_CYCLES_IDLE],
>> -                  cycles[PMD_CYCLES_IDLE] / (double)total_cycles * 100,
>> -                  cycles[PMD_CYCLES_PROCESSING],
>> -                  cycles[PMD_CYCLES_PROCESSING] / (double)total_cycles * 
>> 100);
>> +                  stats[PMD_CYCLES_ITER_IDLE],
>> +                  stats[PMD_CYCLES_ITER_IDLE] / (double) total_cycles * 100,
>> +                  stats[PMD_CYCLES_ITER_BUSY],
>> +                  stats[PMD_CYCLES_ITER_BUSY] / (double) total_cycles * 
>> 100);
>>  
>>      if (total_packets == 0) {
>>          return;
>>      }
>>  
>>      ds_put_format(reply,
>> -                  "\tavg cycles per packet: %.02f (%"PRIu64"/%llu)\n",
>> -                  total_cycles / (double)total_packets,
>> +                  "\tavg cycles per packet:%.02f (%"PRIu64"/%"PRIu64")\n",
>> +                  total_cycles / (double) total_packets,
>>                    total_cycles, total_packets);
>>  
>>      ds_put_format(reply,
>> -                  "\tavg processing cycles per packet: "
>> -                  "%.02f (%"PRIu64"/%llu)\n",
>> -                  cycles[PMD_CYCLES_PROCESSING] / (double)total_packets,
>> -                  cycles[PMD_CYCLES_PROCESSING], total_packets);
>> -}
>> -
>> -static void
>> -pmd_info_clear_stats(struct ds *reply OVS_UNUSED,
>> -                    struct dp_netdev_pmd_thread *pmd,
>> -                    unsigned long long stats[DP_N_STATS],
>> -                    uint64_t cycles[PMD_N_CYCLES])
>> -{
>> -    int i;
>> -
>> -    /* We cannot write 'stats' and 'cycles' (because they're written by 
>> other
>> -     * threads) and we shouldn't change 'stats' (because they're used to 
>> count
>> -     * datapath stats, which must not be cleared here).  Instead, we save 
>> the
>> -     * current values and subtract them from the values to be displayed in 
>> the
>> -     * future */
>> -    for (i = 0; i < DP_N_STATS; i++) {
>> -        pmd->stats_zero[i] = stats[i];
>> -    }
>> -    for (i = 0; i < PMD_N_CYCLES; i++) {
>> -        pmd->cycles_zero[i] = cycles[i];
>> -    }
>> +                  "\tavg processing cycles per packet:"
>> +                  "%.02f (%"PRIu64"/%"PRIu64")\n",
>> +                  stats[PMD_CYCLES_ITER_BUSY] / (double) total_packets,
>> +                  stats[PMD_CYCLES_ITER_BUSY], total_packets);
>>  }
>>  
>>  static int
>> @@ -1106,23 +1034,37 @@ dpif_netdev_pmd_info(struct unixctl_conn *conn, int 
>> argc, const char *argv[],
>>      struct ds reply = DS_EMPTY_INITIALIZER;
>>      struct dp_netdev_pmd_thread **pmd_list;
>>      struct dp_netdev *dp = NULL;
>> -    size_t n;
>>      enum pmd_info_type type = *(enum pmd_info_type *) aux;
>> +    unsigned int core_id;
>> +    bool filter_on_pmd = false;
>> +    size_t n;
>>  
>>      ovs_mutex_lock(&dp_netdev_mutex);
>>  
>> -    if (argc == 2) {
>> -        dp = shash_find_data(&dp_netdevs, argv[1]);
>> -    } else if (shash_count(&dp_netdevs) == 1) {
>> -        /* There's only one datapath */
>> -        dp = shash_first(&dp_netdevs)->data;
>> +    while (argc > 0) {
> 
> This causes OVS crash on any invoked appctl.
> Should be "argc > 1"
> 
>> +        if (!strcmp(argv[1], "-pmd") && argc >= 2) {
>> +            if (str_to_uint(argv[2], 10, &core_id)) {
>> +                filter_on_pmd = true;
>> +            }
>> +            argc -= 2;
>> +            argv += 2;
>> +        } else {
>> +            dp = shash_find_data(&dp_netdevs, argv[1]);
>> +            argc -= 1;
>> +            argv += 1;
>> +        }
>>      }
>>  
>>      if (!dp) {
>> -        ovs_mutex_unlock(&dp_netdev_mutex);
>> -        unixctl_command_reply_error(conn,
>> -                                    "please specify an existing datapath");
>> -        return;
>> +        if (shash_count(&dp_netdevs) == 1) {
>> +            /* There's only one datapath */
>> +            dp = shash_first(&dp_netdevs)->data;
>> +        } else {
>> +            ovs_mutex_unlock(&dp_netdev_mutex);
>> +            unixctl_command_reply_error(conn,
>> +                                        "please specify an existing 
>> datapath");
>> +            return;
>> +        }
>>      }
>>  
>>      sorted_poll_thread_list(dp, &pmd_list, &n);
>> @@ -1131,26 +1073,15 @@ dpif_netdev_pmd_info(struct unixctl_conn *conn, int 
>> argc, const char *argv[],
>>          if (!pmd) {
>>              break;
>>          }
>> -
>> +        if (filter_on_pmd && pmd->core_id != core_id) {
>> +            continue;
>> +        }
>>          if (type == PMD_INFO_SHOW_RXQ) {
>>              pmd_info_show_rxq(&reply, pmd);
>> -        } else {
>> -            unsigned long long stats[DP_N_STATS];
>> -            uint64_t cycles[PMD_N_CYCLES];
>> -
>> -            /* Read current stats and cycle counters */
>> -            for (size_t j = 0; j < ARRAY_SIZE(stats); j++) {
>> -                atomic_read_relaxed(&pmd->stats.n[j], &stats[j]);
>> -            }
>> -            for (size_t j = 0; j < ARRAY_SIZE(cycles); j++) {
>> -                atomic_read_relaxed(&pmd->cycles.n[j], &cycles[j]);
>> -            }
>> -
>> -            if (type == PMD_INFO_CLEAR_STATS) {
>> -                pmd_info_clear_stats(&reply, pmd, stats, cycles);
>> -            } else if (type == PMD_INFO_SHOW_STATS) {
>> -                pmd_info_show_stats(&reply, pmd, stats, cycles);
>> -            }
>> +        } else if (type == PMD_INFO_CLEAR_STATS) {
>> +            pmd_perf_stats_clear(&pmd->perf_stats);
>> +        } else if (type == PMD_INFO_SHOW_STATS) {
>> +            pmd_info_show_stats(&reply, pmd);
>>          }
>>      }
>>      free(pmd_list);
>> @@ -1168,14 +1099,14 @@ dpif_netdev_init(void)
>>                                clear_aux = PMD_INFO_CLEAR_STATS,
>>                                poll_aux = PMD_INFO_SHOW_RXQ;
>>  
>> -    unixctl_command_register("dpif-netdev/pmd-stats-show", "[dp]",
>> -                             0, 1, dpif_netdev_pmd_info,
>> +    unixctl_command_register("dpif-netdev/pmd-stats-show", "[-pmd core] 
>> [dp]",
>> +                             0, 2, dpif_netdev_pmd_info,
>>                               (void *)&show_aux);
>> -    unixctl_command_register("dpif-netdev/pmd-stats-clear", "[dp]",
>> -                             0, 1, dpif_netdev_pmd_info,
>> +    unixctl_command_register("dpif-netdev/pmd-stats-clear", "[-pmd core] 
>> [dp]",
>> +                             0, 2, dpif_netdev_pmd_info,
>>                               (void *)&clear_aux);
>> -    unixctl_command_register("dpif-netdev/pmd-rxq-show", "[dp]",
>> -                             0, 1, dpif_netdev_pmd_info,
>> +    unixctl_command_register("dpif-netdev/pmd-rxq-show", "[-pmd core] [dp]",
>> +                             0, 2, dpif_netdev_pmd_info,
>>                               (void *)&poll_aux);
>>      unixctl_command_register("dpif-netdev/pmd-rxq-rebalance", "[dp]",
>>                               0, 1, dpif_netdev_pmd_rebalance,
>> @@ -1511,23 +1442,19 @@ dpif_netdev_get_stats(const struct dpif *dpif, 
>> struct dpif_dp_stats *stats)
>>  {
>>      struct dp_netdev *dp = get_dp_netdev(dpif);
>>      struct dp_netdev_pmd_thread *pmd;
>> +    uint64_t pmd_stats[PMD_N_STATS];
>>  
>> -    stats->n_flows = stats->n_hit = stats->n_missed = stats->n_lost = 0;
>> +    stats->n_flows = stats->n_hit =
>> +            stats->n_mask_hit = stats->n_missed = stats->n_lost = 0;
>>      CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
>> -        unsigned long long n;
>>          stats->n_flows += cmap_count(&pmd->flow_table);
>> -
>> -        atomic_read_relaxed(&pmd->stats.n[DP_STAT_MASKED_HIT], &n);
>> -        stats->n_hit += n;
>> -        atomic_read_relaxed(&pmd->stats.n[DP_STAT_EXACT_HIT], &n);
>> -        stats->n_hit += n;
>> -        atomic_read_relaxed(&pmd->stats.n[DP_STAT_MISS], &n);
>> -        stats->n_missed += n;
>> -        atomic_read_relaxed(&pmd->stats.n[DP_STAT_LOST], &n);
>> -        stats->n_lost += n;
>> +        pmd_perf_read_counters(&pmd->perf_stats, pmd_stats);
>> +        stats->n_hit += pmd_stats[PMD_STAT_EXACT_HIT];
>> +        stats->n_mask_hit += pmd_stats[PMD_STAT_MASKED_HIT];
>> +        stats->n_missed += pmd_stats[PMD_STAT_MISS];
>> +        stats->n_lost += pmd_stats[PMD_STAT_LOST];
>>      }
>>      stats->n_masks = UINT32_MAX;
>> -    stats->n_mask_hit = UINT64_MAX;
>>  
>>      return 0;
>>  }
>> @@ -3209,28 +3136,28 @@ cycles_count_start(struct dp_netdev_pmd_thread *pmd)
>>  /* Stop counting cycles and add them to the counter 'type' */
>>  static inline void
>>  cycles_count_end(struct dp_netdev_pmd_thread *pmd,
>> -                 enum pmd_cycles_counter_type type)
>> +                 enum pmd_stat_type type)
>>      OVS_RELEASES(&cycles_counter_fake_mutex)
>>      OVS_NO_THREAD_SAFETY_ANALYSIS
>>  {
>>      unsigned long long interval = cycles_counter() - pmd->ctx.last_cycles;
>>  
>> -    non_atomic_ullong_add(&pmd->cycles.n[type], interval);
>> +    pmd_perf_update_counter(&pmd->perf_stats, type, interval);
>>  }
>>  
>>  /* Calculate the intermediate cycle result and add to the counter 'type' */
>>  static inline void
>>  cycles_count_intermediate(struct dp_netdev_pmd_thread *pmd,
>>                            struct dp_netdev_rxq *rxq,
>> -                          enum pmd_cycles_counter_type type)
>> +                          enum pmd_stat_type type)
>>      OVS_NO_THREAD_SAFETY_ANALYSIS
>>  {
>>      unsigned long long new_cycles = cycles_counter();
>>      unsigned long long interval = new_cycles - pmd->ctx.last_cycles;
>>      pmd->ctx.last_cycles = new_cycles;
>>  
>> -    non_atomic_ullong_add(&pmd->cycles.n[type], interval);
>> -    if (rxq && (type == PMD_CYCLES_PROCESSING)) {
>> +    pmd_perf_update_counter(&pmd->perf_stats, type, interval);
>> +    if (rxq && (type == PMD_CYCLES_POLL_BUSY)) {
>>          /* Add to the amount of current processing cycles. */
>>          non_atomic_ullong_add(&rxq->cycles[RXQ_CYCLES_PROC_CURR], interval);
>>      }
>> @@ -3289,8 +3216,8 @@ dp_netdev_pmd_flush_output_on_port(struct 
>> dp_netdev_pmd_thread *pmd,
>>      netdev_send(p->port->netdev, tx_qid, &p->output_pkts, dynamic_txqs);
>>      dp_packet_batch_init(&p->output_pkts);
>>  
>> -    dp_netdev_count_packet(pmd, DP_STAT_SENT_PKTS, output_cnt);
>> -    dp_netdev_count_packet(pmd, DP_STAT_SENT_BATCHES, 1);
>> +    pmd_perf_update_counter(&pmd->perf_stats, PMD_STAT_SENT_PKTS, 
>> output_cnt);
>> +    pmd_perf_update_counter(&pmd->perf_stats, PMD_STAT_SENT_BATCHES, 1);
>>  }
>>  
>>  static void
>> @@ -3971,12 +3898,12 @@ dpif_netdev_run(struct dpif *dpif)
>>                                                     port->port_no);
>>                      cycles_count_intermediate(non_pmd, NULL,
>>                                                process_packets
>> -                                              ? PMD_CYCLES_PROCESSING
>> -                                              : PMD_CYCLES_IDLE);
>> +                                              ? PMD_CYCLES_POLL_BUSY
>> +                                              : PMD_CYCLES_POLL_IDLE);
>>                  }
>>              }
>>          }
>> -        cycles_count_end(non_pmd, PMD_CYCLES_IDLE);
>> +        cycles_count_end(non_pmd, PMD_CYCLES_POLL_IDLE);
>>          pmd_thread_ctx_time_update(non_pmd);
>>          dpif_netdev_xps_revalidate_pmd(non_pmd, false);
>>          ovs_mutex_unlock(&dp->non_pmd_mutex);
>> @@ -4121,6 +4048,7 @@ static void *
>>  pmd_thread_main(void *f_)
>>  {
>>      struct dp_netdev_pmd_thread *pmd = f_;
>> +    struct pmd_perf_stats *s = &pmd->perf_stats;
>>      unsigned int lc = 0;
>>      struct polled_queue *poll_list;
>>      bool exiting;
>> @@ -4156,13 +4084,17 @@ reload:
>>  
>>      cycles_count_start(pmd);
>>      for (;;) {
>> +        uint64_t iter_packets = 0;
>> +        pmd_perf_start_iteration(s, pmd->ctx.last_cycles);
>>          for (i = 0; i < poll_cnt; i++) {
>>              process_packets =
>>                  dp_netdev_process_rxq_port(pmd, poll_list[i].rxq->rx,
>>                                             poll_list[i].port_no);
>>              cycles_count_intermediate(pmd, poll_list[i].rxq,
>> -                                      process_packets ? 
>> PMD_CYCLES_PROCESSING
>> -                                                      : PMD_CYCLES_IDLE);
>> +                                      process_packets
>> +                                      ? PMD_CYCLES_POLL_BUSY
>> +                                      : PMD_CYCLES_POLL_IDLE);
>> +            iter_packets += process_packets;
>>          }
>>  
>>          if (lc++ > 1024) {
>> @@ -4183,10 +4115,12 @@ reload:
>>              if (reload) {
>>                  break;
>>              }
>> +            cycles_count_intermediate(pmd, NULL, PMD_CYCLES_OVERHEAD);
>>          }
>> +        pmd_perf_end_iteration(s, pmd->ctx.last_cycles, iter_packets);
>>      }
>>  
>> -    cycles_count_end(pmd, PMD_CYCLES_IDLE);
>> +    cycles_count_end(pmd, PMD_CYCLES_OVERHEAD);
>>  
>>      poll_cnt = pmd_load_queues_and_ports(pmd, &poll_list);
>>      exiting = latch_is_set(&pmd->exit_latch);
>> @@ -4638,6 +4572,7 @@ dp_netdev_configure_pmd(struct dp_netdev_pmd_thread 
>> *pmd, struct dp_netdev *dp,
>>          emc_cache_init(&pmd->flow_cache);
>>          pmd_alloc_static_tx_qid(pmd);
>>      }
>> +    pmd_perf_stats_init(&pmd->perf_stats);
>>      cmap_insert(&dp->poll_threads, CONST_CAST(struct cmap_node *, 
>> &pmd->node),
>>                  hash_int(core_id, 0));
>>  }
>> @@ -4838,13 +4773,6 @@ dp_netdev_flow_used(struct dp_netdev_flow 
>> *netdev_flow, int cnt, int size,
>>      atomic_store_relaxed(&netdev_flow->stats.tcp_flags, flags);
>>  }
>>  
>> -static void
>> -dp_netdev_count_packet(struct dp_netdev_pmd_thread *pmd,
>> -                       enum dp_stat_type type, int cnt)
>> -{
>> -    non_atomic_ullong_add(&pmd->stats.n[type], cnt);
>> -}
>> -
>>  static int
>>  dp_netdev_upcall(struct dp_netdev_pmd_thread *pmd, struct dp_packet 
>> *packet_,
>>                   struct flow *flow, struct flow_wildcards *wc, ovs_u128 
>> *ufid,
>> @@ -5017,6 +4945,9 @@ emc_processing(struct dp_netdev_pmd_thread *pmd,
>>      int i;
>>  
>>      atomic_read_relaxed(&pmd->dp->emc_insert_min, &cur_min);
>> +    pmd_perf_update_counter(&pmd->perf_stats,
>> +                            md_is_valid ? PMD_STAT_RECIRC : PMD_STAT_RECV,
>> +                            cnt);
>>  
>>      DP_PACKET_BATCH_REFILL_FOR_EACH (i, cnt, packet, packets_) {
>>          struct dp_netdev_flow *flow;
>> @@ -5065,18 +4996,17 @@ emc_processing(struct dp_netdev_pmd_thread *pmd,
>>          }
>>      }
>>  
>> -    dp_netdev_count_packet(pmd, DP_STAT_EXACT_HIT,
>> -                           cnt - n_dropped - n_missed);
>> +    pmd_perf_update_counter(&pmd->perf_stats, PMD_STAT_EXACT_HIT,
>> +                            cnt - n_dropped - n_missed);
>>  
>>      return dp_packet_batch_size(packets_);
>>  }
>>  
>> -static inline void
>> +static inline int
>>  handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
>>                       struct dp_packet *packet,
>>                       const struct netdev_flow_key *key,
>> -                     struct ofpbuf *actions, struct ofpbuf *put_actions,
>> -                     int *lost_cnt)
>> +                     struct ofpbuf *actions, struct ofpbuf *put_actions)
>>  {
>>      struct ofpbuf *add_actions;
>>      struct dp_packet_batch b;
>> @@ -5096,8 +5026,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
>>                               put_actions);
>>      if (OVS_UNLIKELY(error && error != ENOSPC)) {
>>          dp_packet_delete(packet);
>> -        (*lost_cnt)++;
>> -        return;
>> +        return error;
>>      }
>>  
>>      /* The Netlink encoding of datapath flow keys cannot express
>> @@ -5137,6 +5066,9 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
>>          ovs_mutex_unlock(&pmd->flow_mutex);
>>          emc_probabilistic_insert(pmd, key, netdev_flow);
>>      }
>> +    /* Only error ENOSPC can reach here. We process the packet but do not
>> +     * install a datapath flow. Treat as successful. */
>> +    return 0;
>>  }
>>  
>>  static inline void
>> @@ -5158,7 +5090,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
>>      struct dpcls *cls;
>>      struct dpcls_rule *rules[PKT_ARRAY_SIZE];
>>      struct dp_netdev *dp = pmd->dp;
>> -    int miss_cnt = 0, lost_cnt = 0;
>> +    int upcall_ok_cnt = 0, upcall_fail_cnt = 0;
>>      int lookup_cnt = 0, add_lookup_cnt;
>>      bool any_miss;
>>      size_t i;
>> @@ -5200,9 +5132,14 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
>>                  continue;
>>              }
>>  
>> -            miss_cnt++;
>> -            handle_packet_upcall(pmd, packet, &keys[i], &actions,
>> -                                 &put_actions, &lost_cnt);
>> +            int error = handle_packet_upcall(pmd, packet, &keys[i],
>> +                                             &actions, &put_actions);
>> +
>> +            if (OVS_UNLIKELY(error)) {
>> +                upcall_fail_cnt++;
>> +            } else {
>> +                upcall_ok_cnt++;
>> +            }
>>          }
>>  
>>          ofpbuf_uninit(&actions);
>> @@ -5212,8 +5149,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
>>          DP_PACKET_BATCH_FOR_EACH (packet, packets_) {
>>              if (OVS_UNLIKELY(!rules[i])) {
>>                  dp_packet_delete(packet);
>> -                lost_cnt++;
>> -                miss_cnt++;
>> +                upcall_fail_cnt++;
>>              }
>>          }
>>      }
>> @@ -5231,10 +5167,14 @@ fast_path_processing(struct dp_netdev_pmd_thread 
>> *pmd,
>>          dp_netdev_queue_batches(packet, flow, &keys[i].mf, batches, 
>> n_batches);
>>      }
>>  
>> -    dp_netdev_count_packet(pmd, DP_STAT_MASKED_HIT, cnt - miss_cnt);
>> -    dp_netdev_count_packet(pmd, DP_STAT_LOOKUP_HIT, lookup_cnt);
>> -    dp_netdev_count_packet(pmd, DP_STAT_MISS, miss_cnt);
>> -    dp_netdev_count_packet(pmd, DP_STAT_LOST, lost_cnt);
>> +    pmd_perf_update_counter(&pmd->perf_stats, PMD_STAT_MASKED_HIT,
>> +                            cnt - upcall_ok_cnt - upcall_fail_cnt);
>> +    pmd_perf_update_counter(&pmd->perf_stats, PMD_STAT_MASKED_LOOKUP,
>> +                            lookup_cnt);
>> +    pmd_perf_update_counter(&pmd->perf_stats, PMD_STAT_MISS,
>> +                            upcall_ok_cnt);
>> +    pmd_perf_update_counter(&pmd->perf_stats, PMD_STAT_LOST,
>> +                            upcall_fail_cnt);
>>  }
>>  
>>  /* Packets enter the datapath from a port (or from recirculation) here.
>> diff --git a/tests/pmd.at b/tests/pmd.at
>> index e39a23a..0356f87 100644
>> --- a/tests/pmd.at
>> +++ b/tests/pmd.at
>> @@ -170,13 +170,16 @@ dummy@ovs-dummy: hit:0 missed:0
>>              p0 7/1: (dummy-pmd: configured_rx_queues=4, 
>> configured_tx_queues=<cleared>, requested_rx_queues=4, 
>> requested_tx_queues=<cleared>)
>>  ])
>>  
>> -AT_CHECK([ovs-appctl dpif-netdev/pmd-stats-show | sed SED_NUMA_CORE_PATTERN 
>> | sed '/cycles/d' | grep pmd -A 5], [0], [dnl
>> +AT_CHECK([ovs-appctl dpif-netdev/pmd-stats-show | sed SED_NUMA_CORE_PATTERN 
>> | sed '/cycles/d' | grep pmd -A 8], [0], [dnl
>>  pmd thread numa_id <cleared> core_id <cleared>:
>> +    packets received:0
>> +    packet recirculations:0
>> +    avg. datapath passes per packet:0.00
>>      emc hits:0
>>      megaflow hits:0
>> -    avg. subtable lookups per hit:0.00
>> -    miss:0
>> -    lost:0
>> +    avg. subtable lookups per megaflow hit:0.00
>> +    miss(i.e. lookup miss with success upcall):0
>> +    lost(i.e. lookup miss with failed upcall):0
>>  ])
>>  
>>  ovs-appctl time/stop
>> @@ -197,13 +200,16 @@ AT_CHECK([cat ovs-vswitchd.log | filter_flow_install | 
>> strip_xout], [0], [dnl
>>  
>> recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:77,dst=50:54:00:00:01:78),eth_type(0x0800),ipv4(frag=no),
>>  actions: <del>
>>  ])
>>  
>> -AT_CHECK([ovs-appctl dpif-netdev/pmd-stats-show | sed SED_NUMA_CORE_PATTERN 
>> | sed '/cycles/d' | grep pmd -A 5], [0], [dnl
>> +AT_CHECK([ovs-appctl dpif-netdev/pmd-stats-show | sed SED_NUMA_CORE_PATTERN 
>> | sed '/cycles/d' | grep pmd -A 8], [0], [dnl
>>  pmd thread numa_id <cleared> core_id <cleared>:
>> +    packets received:20
>> +    packet recirculations:0
>> +    avg. datapath passes per packet:1.00
>>      emc hits:19
>>      megaflow hits:0
>> -    avg. subtable lookups per hit:0.00
>> -    miss:1
>> -    lost:0
>> +    avg. subtable lookups per megaflow hit:0.00
>> +    miss(i.e. lookup miss with success upcall):1
>> +    lost(i.e. lookup miss with failed upcall):0
>>  ])
>>  
>>  OVS_VSWITCHD_STOP
>>
> 
> In addition to not updated tests above, I also see failures of
> test "1165. ofproto-dpif.at:7478: testing ofproto-dpif - patch ports":
> 
> ./ofproto-dpif.at:7514: ovs-appctl dpif/show
> --- -   2018-01-11 15:06:46.324839417 +0300
> +++ /tests/testsuite.dir/at-groups/1165/stdout
> @@ -1,4 +1,4 @@
> -dummy@ovs-dummy: hit:13 missed:2
> +dummy@ovs-dummy: hit:0 missed:2
>         br0:
>                 br0 65534/100: (dummy-internal)
>                 p2 2/2: (dummy)
> 
> 

I found the reason why this test fails. It happens because 'stats->n_hit'
in 'dpif_netdev_get_stats' should be the sum of PMD_STAT_EXACT_HIT and
PMD_STAT_MASKED_HIT.
Additionally, no need to set 'stats->n_mask_hit' because it only useful
if 'stats->n_masks' set properly.


So, following incremental required to make at least unit tests work:
--------------------------------------------------------------------
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index c7a4a21..ed14dde 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1054,7 +1054,7 @@ dpif_netdev_pmd_info(struct unixctl_conn *conn, int argc, 
const char *argv[],
 
     ovs_mutex_lock(&dp_netdev_mutex);
 
-    while (argc > 0) {
+    while (argc > 1) {
         if (!strcmp(argv[1], "-pmd") && argc >= 2) {
             if (str_to_uint(argv[2], 10, &core_id)) {
                 filter_on_pmd = true;
@@ -1464,11 +1464,12 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct 
dpif_dp_stats *stats)
         stats->n_flows += cmap_count(&pmd->flow_table);
         pmd_perf_read_counters(&pmd->perf_stats, pmd_stats);
         stats->n_hit += pmd_stats[PMD_STAT_EXACT_HIT];
-        stats->n_mask_hit += pmd_stats[PMD_STAT_MASKED_HIT];
+        stats->n_hit += pmd_stats[PMD_STAT_MASKED_HIT];
         stats->n_missed += pmd_stats[PMD_STAT_MISS];
         stats->n_lost += pmd_stats[PMD_STAT_LOST];
     }
     stats->n_masks = UINT32_MAX;
+    stats->n_mask_hit = UINT64_MAX;
 
     return 0;
 }
diff --git a/tests/pmd.at b/tests/pmd.at
index 6e7ba50..80f7414 100644
--- a/tests/pmd.at
+++ b/tests/pmd.at
@@ -178,8 +178,8 @@ pmd thread numa_id <cleared> core_id <cleared>:
        emc hits:0
        megaflow hits:0
        avg. subtable lookups per megaflow hit:0.00
-       miss(i.e. lookup miss with success upcall):0
-       lost(i.e. lookup miss with failed upcall):0
+       miss with success upcall:0
+       miss with failed upcall:0
 ])
 
 ovs-appctl time/stop
@@ -208,8 +208,8 @@ pmd thread numa_id <cleared> core_id <cleared>:
        emc hits:19
        megaflow hits:0
        avg. subtable lookups per megaflow hit:0.00
-       miss(i.e. lookup miss with success upcall):1
-       lost(i.e. lookup miss with failed upcall):0
+       miss with success upcall:1
+       miss with failed upcall:0
 ])
 
 OVS_VSWITCHD_STOP
--------------------------------------------------------------------
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to