Hi Kumar,

See inline comments below…

//Eelco


On 20 Oct 2021, at 6:52, Kumar Amber wrote:

> Modified the dplcs info-get command output to include
> the count for different dpcls implementations.
>
> $ovs-appctl dpif-netdev/subtable-lookup-prio-get
>
> Available dpcls implementations:
>   autovalidator (Use count: 1, Priority: 5)
>   generic (Use count: 0, Priority: 1)
>   avx512_gather (Use count: 0, Priority: 3)
>
> Test case to verify changes:
>       1021: PMD - dpcls configuration     ok
>
> Signed-off-by: Kumar Amber <kumar.am...@intel.com>
> Signed-off-by: Harry van Haaren <harry.van.haa...@intel.com>
> Co-authored-by: Harry van Haaren <harry.van.haa...@intel.com>
>
> ---
> v2: Dependency merged rebased to master
>
> ---
> ---
>  Documentation/topics/dpdk/bridge.rst | 16 +++---
>  lib/dpif-netdev-lookup.c             | 80 ++++++++++++++++++++++------
>  lib/dpif-netdev-lookup.h             | 19 ++++++-
>  lib/dpif-netdev.c                    | 30 +++++------
>  tests/pmd.at                         | 16 +++---
>  5 files changed, 111 insertions(+), 50 deletions(-)
>
> diff --git a/Documentation/topics/dpdk/bridge.rst 
> b/Documentation/topics/dpdk/bridge.rst
> index f645b9ade..63a54da1c 100644
> --- a/Documentation/topics/dpdk/bridge.rst
> +++ b/Documentation/topics/dpdk/bridge.rst
> @@ -156,10 +156,10 @@ OVS provides multiple implementations of dpcls. The 
> following command enables
>  the user to check what implementations are available in a running instance ::
>
>      $ ovs-appctl dpif-netdev/subtable-lookup-prio-get
> -    Available lookup functions (priority : name)
> -            0 : autovalidator
> -            1 : generic
> -            0 : avx512_gather
> +    Available dpcls implementations:
> +            autovalidator (Use count: 1, Priority: 5)
> +            generic (Use count: 0, Priority: 1)
> +            avx512_gather (Use count: 0, Priority: 3)
>
>  To set the priority of a lookup function, run the ``prio-set`` command ::
>
> @@ -172,10 +172,10 @@ function due to the command being run. To verify the 
> prioritization, re-run the
>  get command, note the updated priority of the ``avx512_gather`` function ::
>
>      $ ovs-appctl dpif-netdev/subtable-lookup-prio-get
> -    Available lookup functions (priority : name)
> -            0 : autovalidator
> -            1 : generic
> -            5 : avx512_gather
> +    Available dpcls implementations:
> +            autovalidator (Use count: 0, Priority: 0)
> +            generic (Use count: 0, Priority: 0)
> +            avx512_gather (Use count: 1, Priority: 5)
>
>  If two lookup functions have the same priority, the first one in the list is
>  chosen, and the 2nd occurance of that priority is not used. Put in logical
> diff --git a/lib/dpif-netdev-lookup.c b/lib/dpif-netdev-lookup.c
> index bd0a99abe..c0b137299 100644
> --- a/lib/dpif-netdev-lookup.c
> +++ b/lib/dpif-netdev-lookup.c
> @@ -36,18 +36,21 @@ static struct dpcls_subtable_lookup_info_t 
> subtable_lookups[] = {
>      { .prio = 0,
>  #endif
>        .probe = dpcls_subtable_autovalidator_probe,
> -      .name = "autovalidator", },
> +      .name = "autovalidator",
> +      .usage_cnt = 0,},
>
>      /* The default scalar C code implementation. */
>      { .prio = 1,
>        .probe = dpcls_subtable_generic_probe,
> -      .name = "generic", },
> +      .name = "generic",
> +      .usage_cnt = 0, },
>
>  #if (__x86_64__ && HAVE_AVX512F && HAVE_LD_AVX512_GOOD && __SSE4_2__)
>      /* Only available on x86_64 bit builds with SSE 4.2 used for OVS core. */
>      { .prio = 0,
>        .probe = dpcls_subtable_avx512_gather_probe,
> -      .name = "avx512_gather", },
> +      .name = "avx512_gather",
> +      .usage_cnt = 0,},
>  #else
>      /* Disabling AVX512 at compile time, as compile time requirements not 
> met.
>       * This could be due to a number of reasons:
> @@ -93,32 +96,79 @@ dpcls_subtable_set_prio(const char *name, uint8_t 
> priority)
>  }
>
>  dpcls_subtable_lookup_func
> -dpcls_subtable_get_best_impl(uint32_t u0_bit_count, uint32_t u1_bit_count)
> +dpcls_subtable_get_best_impl(uint32_t u0_bit_count, uint32_t u1_bit_count,
> +                             dpcls_subtable_lookup_func old_func,
> +                             uint32_t will_use_result)

Why uint32_t and not a boolean?

>  {
>      /* Iter over each subtable impl, and get highest priority one. */
>      int32_t prio = -1;
> +    uint32_t i;
>      const char *name = NULL;
> +    uint32_t best_idx = 0;
> +    uint32_t usage_cnt = 0;
>      dpcls_subtable_lookup_func best_func = NULL;
>
> -    for (int i = 0; i < ARRAY_SIZE(subtable_lookups); i++) {
> +    for (i = 0; i < ARRAY_SIZE(subtable_lookups); i++) {
>          int32_t probed_prio = subtable_lookups[i].prio;
> +        dpcls_subtable_lookup_func probed_func;

Add extra blanc line here

> +        probed_func = subtable_lookups[i].probe(u0_bit_count,
> +                                u1_bit_count);

Indentation is off

> +        if (!probed_func) {
> +            continue;
> +        }
> +
> +        /* Better candidate - track this to return it later. */
>          if (probed_prio > prio) {
> -            dpcls_subtable_lookup_func probed_func;
> -            probed_func = subtable_lookups[i].probe(u0_bit_count,
> -                                    u1_bit_count);
> -            if (probed_func) {
> -                best_func = probed_func;
> -                prio = probed_prio;
> -                name = subtable_lookups[i].name;
> -            }
> +            best_func = probed_func;
> +            best_idx = i;
> +            prio = probed_prio;
> +            name = subtable_lookups[i].name;
> +        }
> +
> +        /* Statistics keeping, reduce old func usage count. */
> +        if (probed_func == old_func) {

Should this check also not include “&& will_use_result“?
Guess you overload this function to do a counter update, which I do not like 
(see comments below).

> +            atomic_read_relaxed(&subtable_lookups[i].usage_cnt, &usage_cnt);
> +            usage_cnt--;
> +            atomic_store_relaxed(&subtable_lookups[i].usage_cnt, usage_cnt);

Not sure what you are trying here, but looks like you make an atomic operation, 
not atomic ;)

We have the following APIs which I think you should use; 
atomic_count_init()/atomic_count_inc()/atomic_count_dec().

>          }
>      }
>
> -    VLOG_DBG("Subtable lookup function '%s' with units (%d,%d), priority 
> %d\n",
> -             name, u0_bit_count, u1_bit_count, prio);
> +    /* Update stats for usage. */
> +    if (will_use_result) {
> +        atomic_read_relaxed(&subtable_lookups[best_idx].usage_cnt, 
> &usage_cnt);
> +        usage_cnt++;
> +        atomic_store_relaxed(&subtable_lookups[best_idx].usage_cnt, 
> usage_cnt);
> +    } else {
> +       VLOG_DBG(
> +           "Subtable lookup function '%s' with units (%d,%d), priority %d\n",
> +           name, u0_bit_count, u1_bit_count, prio);
> +    }

Why not always show the log? Guess now you only show it when not using the 
return value?

>
>      /* Programming error - we must always return a valid func ptr. */
>      ovs_assert(best_func != NULL);
>
>      return best_func;
>  }
> +
> +void
> +dp_dpcls_impl_print_stats(struct ds *reply)
> +{
> +    struct dpcls_subtable_lookup_info_t *lookup_funcs = NULL;
> +    int32_t count = dpcls_subtable_lookup_info_get(&lookup_funcs);
> +
> +    /* Add all DPCLS functions to reply string. */
> +    ds_put_cstr(reply, "Available dpcls implementations:\n");

Would be nice to do some qsort() to show the entries based on priority/name?
> +
> +    for (int i = 0; i < count; i++) {
> +        ds_put_format(reply, "  %s (Use count: %d, Priority: %d",
> +                      lookup_funcs[i].name, lookup_funcs[i].usage_cnt,
> +                      lookup_funcs[i].prio);
> +
> +        if (ds_last(reply) == ' ') {
> +            ds_put_cstr(reply, "none");
> +        }
> +
> +        ds_put_cstr(reply, ")\n");
> +    }
> +
> +}
> diff --git a/lib/dpif-netdev-lookup.h b/lib/dpif-netdev-lookup.h
> index 59f51faa0..13431a3fb 100644
> --- a/lib/dpif-netdev-lookup.h
> +++ b/lib/dpif-netdev-lookup.h
> @@ -20,6 +20,7 @@
>  #include <config.h>
>  #include "dpif-netdev.h"
>  #include "dpif-netdev-private-dpcls.h"
> +#include "dpif-netdev-private-thread.h"
>
>  /* Function to perform a probe for the subtable bit fingerprint.
>   * Returns NULL if not valid, or a valid function pointer to call for this
> @@ -62,12 +63,24 @@ struct dpcls_subtable_lookup_info_t {
>
>      /* Human readable name, used in setting subtable priority commands */
>      const char *name;
> +
> +    /* Counter which holds the usage count of each implementations. */
> +    atomic_uint32_t usage_cnt;

Guess this needs to be atomic_count
>  };
>
>  int32_t dpcls_subtable_set_prio(const char *name, uint8_t priority);
>
> +/* Lookup the best subtable lookup implementation for the given u0,u1 count.
> + * When replacing an existing lookup func, the old_func pointer is provied
> + * and statistics will be tracked accordingly and will_use parameter would
> + * be set to 1 if the result of the function is going to be used for a
> + * subtable lookup else when set to 0, the statistics will refect that the
> + * result is not being used.
> + */

See below, as I do not like the API.

>  dpcls_subtable_lookup_func
> -dpcls_subtable_get_best_impl(uint32_t u0_bit_count, uint32_t u1_bit_count);
> +dpcls_subtable_get_best_impl(uint32_t u0_bit_count, uint32_t u1_bit_count,
> +                             dpcls_subtable_lookup_func old_func,
> +                             uint32_t will_use);
>
>  /* Retrieve the array of lookup implementations for iteration.
>   * On error, returns a negative number.
> @@ -76,4 +89,8 @@ dpcls_subtable_get_best_impl(uint32_t u0_bit_count, 
> uint32_t u1_bit_count);
>  int32_t
>  dpcls_subtable_lookup_info_get(struct dpcls_subtable_lookup_info_t 
> **out_ptr);
>
> +/* Prints dpcls subtables in use for different implementations. */
> +void
> +dp_dpcls_impl_print_stats(struct ds *reply);
> +
>  #endif /* dpif-netdev-lookup.h */
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index b078c2da5..c4ca3ce51 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -911,21 +911,8 @@ dpif_netdev_subtable_lookup_get(struct unixctl_conn 
> *conn, int argc OVS_UNUSED,
>                                  const char *argv[] OVS_UNUSED,
>                                  void *aux OVS_UNUSED)
>  {
> -    /* Get a list of all lookup functions. */
> -    struct dpcls_subtable_lookup_info_t *lookup_funcs = NULL;
> -    int32_t count = dpcls_subtable_lookup_info_get(&lookup_funcs);
> -    if (count < 0) {
> -        unixctl_command_reply_error(conn, "error getting lookup names");
> -        return;
> -    }
> -
> -    /* Add all lookup functions to reply string. */
>      struct ds reply = DS_EMPTY_INITIALIZER;
> -    ds_put_cstr(&reply, "Available lookup functions (priority : name)\n");
> -    for (int i = 0; i < count; i++) {
> -        ds_put_format(&reply, "  %d : %s\n", lookup_funcs[i].prio,
> -                      lookup_funcs[i].name);
> -    }

Add extra enter between variable declaration and code.

> +    dp_dpcls_impl_print_stats(&reply);
>      unixctl_command_reply(conn, ds_cstr(&reply));
>      ds_destroy(&reply);
>  }
> @@ -8940,6 +8927,10 @@ dpcls_destroy_subtable(struct dpcls *cls, struct 
> dpcls_subtable *subtable)
>      pvector_remove(&cls->subtables, subtable);
>      cmap_remove(&cls->subtables_map, &subtable->cmap_node,
>                  subtable->mask.hash);
> +
> +    dpcls_subtable_get_best_impl(subtable->mf_bits_set_unit0,
> +                                 subtable->mf_bits_set_unit1,
> +                                 subtable->lookup_func, 0);

First, the 0, should probably be a false bool. But in general, I do not like 
this API overload. Why would you call a dpcls_subtable_get_best_impl() to reset 
a counter? Can we not add a new API in form or
dpcls_update_impl_use_count(struct dpcls_subtable *ubtable, bool increase), or 
something else thats is more clear?

>      ovsrcu_postpone(dpcls_subtable_destroy_cb, subtable);
>  }
>
> @@ -8987,8 +8978,8 @@ dpcls_create_subtable(struct dpcls *cls, const struct 
> netdev_flow_key *mask)
>       * The function is guaranteed to always return a valid implementation, 
> and
>       * possibly an ISA optimized, and/or specialized implementation.
>       */
> -    subtable->lookup_func = dpcls_subtable_get_best_impl(unit0, unit1);
> -
> +    subtable->lookup_func = dpcls_subtable_get_best_impl(unit0, unit1, NULL,
> +                                                         1);

If dpcls_subtable_get_best_impl() would always increase the use count, no 
changes should be needed here.

>      cmap_insert(&cls->subtables_map, &subtable->cmap_node, mask->hash);
>      /* Add the new subtable at the end of the pvector (with no hits yet) */
>      pvector_insert(&cls->subtables, subtable, 0);
> @@ -9028,8 +9019,11 @@ dpcls_subtable_lookup_reprobe(struct dpcls *cls)
>          uint32_t u0_bits = subtable->mf_bits_set_unit0;
>          uint32_t u1_bits = subtable->mf_bits_set_unit1;
>          void *old_func = subtable->lookup_func;

Guess here we could do dpcls_update_impl_use_count(subtable->lookup_func, false)
And then call dpcls_subtable_get_best_impl() which will increase the use count.
> -        subtable->lookup_func = dpcls_subtable_get_best_impl(u0_bits, 
> u1_bits);
> -        subtables_changed += (old_func != subtable->lookup_func);
> +        subtable->lookup_func = dpcls_subtable_get_best_impl(u0_bits, 
> u1_bits,
> +                                                             old_func, 1);
> +        if (old_func != subtable->lookup_func) {
> +            subtables_changed += 1;
> +        }
>      }
>      pvector_publish(pvec);
>
> diff --git a/tests/pmd.at b/tests/pmd.at
> index c875a744f..e61bb27d3 100644
> --- a/tests/pmd.at
> +++ b/tests/pmd.at
> @@ -1091,11 +1091,11 @@ AT_CHECK([ovs-vsctl add-port br0 p1 -- set Interface 
> p1 type=dummy-pmd])
>
>  AT_CHECK([ovs-vsctl show], [], [stdout])
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-get | grep generic], 
> [], [dnl
> -  1 : generic
> +  generic (Use count: 0, Priority: 1)
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-get | grep 
> autovalidator], [], [dnl
> -  0 : autovalidator
> +  autovalidator (Use count: 0, Priority: 0)
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-set autovalidator 3], 
> [0], [dnl
> @@ -1103,7 +1103,7 @@ Lookup priority change affected 0 dpcls ports and 0 
> subtables.
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-get | grep 
> autovalidator], [], [dnl
> -  3 : autovalidator
> +  autovalidator (Use count: 0, Priority: 3)
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-set generic 4], [0], 
> [dnl
> @@ -1111,7 +1111,7 @@ Lookup priority change affected 0 dpcls ports and 0 
> subtables.
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-get | grep generic], 
> [], [dnl
> -  4 : generic
> +  generic (Use count: 0, Priority: 4)
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-set generic 8], [0], 
> [dnl
> @@ -1119,7 +1119,7 @@ Lookup priority change affected 0 dpcls ports and 0 
> subtables.
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-get | grep generic], 
> [], [dnl
> -  8 : generic
> +  generic (Use count: 0, Priority: 8)
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-set autovalidator 8], 
> [0], [dnl
> @@ -1127,7 +1127,7 @@ Lookup priority change affected 0 dpcls ports and 0 
> subtables.
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-get | grep 
> autovalidator], [], [dnl
> -  8 : autovalidator
> +  autovalidator (Use count: 0, Priority: 8)
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-set generic 0], [0], 
> [dnl
> @@ -1135,7 +1135,7 @@ Lookup priority change affected 0 dpcls ports and 0 
> subtables.
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-get | grep generic], 
> [], [dnl
> -  0 : generic
> +  generic (Use count: 0, Priority: 0)
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-set generic 255], [0], 
> [dnl
> @@ -1143,7 +1143,7 @@ Lookup priority change affected 0 dpcls ports and 0 
> subtables.
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-get | grep generic], 
> [], [dnl
> -  255 : generic
> +  generic (Use count: 0, Priority: 255)
>  ])
>
>  AT_CHECK([ovs-appctl dpif-netdev/subtable-lookup-prio-set generic -1], [2],
> -- 
> 2.25.1

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to