Hi Kumar,

Thanks for fixing the previously mentioned issues, however, we still need to 
finish the API discussion. I copied over the discussion from v2 below.

//Eelco

On 28 Oct 2021, at 11:50, 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 <[email protected]>
> Signed-off-by: Harry van Haaren <[email protected]>
> Co-authored-by: Harry van Haaren <[email protected]>
>
> ---
> v3:
> - Fix comments on the patch.
> - Function API remains same, see discussion on OVS ML here:
>   "https://mail.openvswitch.org/pipermail/ovs-dev/2021-October/388737.html";
> v2:
> - Dependency merged rebased to master.
>
> ---
> ---
>  Documentation/topics/dpdk/bridge.rst | 16 +++----
>  lib/dpif-netdev-lookup.c             | 72 +++++++++++++++++++++++-----
>  lib/dpif-netdev-lookup.h             | 19 +++++++-
>  lib/dpif-netdev.c                    | 31 +++++-------
>  tests/pmd.at                         | 16 +++----
>  5 files changed, 106 insertions(+), 48 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..8a95c84e1 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.count = 0,},

Use the ATOMIC_COUNT_INIT() macro, and also add a space after the comma:

      .usage_cnt = ATOMIC_COUNT_INIT(0), },
>
>      /* The default scalar C code implementation. */
>      { .prio = 1,
>        .probe = dpcls_subtable_generic_probe,
> -      .name = "generic", },
> +      .name = "generic",
> +      .usage_cnt.count = 0,},

Same as above

>
>  #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.count = 0,},

Same as above

>  #else
>      /* Disabling AVX512 at compile time, as compile time requirements not 
> met.
>       * This could be due to a number of reasons:
> @@ -93,25 +96,44 @@ 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,
> +                             bool will_use_result)
>  {
>      /* Iter over each subtable impl, and get highest priority one. */
>      int32_t prio = -1;
> +    uint32_t i;

In this code you use a lot of (u)int32_t, however in OVS for this kind of use 
cases please stick to just int, and if really needed unsigned int.

>      const char *name = NULL;
> +    uint32_t best_idx = 0;

See above, just use int here.

>      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++) {

Think we should just keep the (int i) definition as is here.

>          int32_t probed_prio = subtable_lookups[i].prio;
> +        dpcls_subtable_lookup_func probed_func;
> +
> +        probed_func = subtable_lookups[i].probe(u0_bit_count,
> +                                                u1_bit_count);
> +        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) {
> +            atomic_count_dec(&subtable_lookups[i].usage_cnt);
> +        }
> +    }
> +
> +    /* Update stats for usage. */
> +    if (will_use_result) {
> +        atomic_count_inc(&subtable_lookups[best_idx].usage_cnt);
>      }
>
>      VLOG_DBG("Subtable lookup function '%s' with units (%d,%d), priority 
> %d\n",
> @@ -122,3 +144,27 @@ dpcls_subtable_get_best_impl(uint32_t u0_bit_count, 
> uint32_t u1_bit_count)
>
>      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");
> +
> +    for (int i = 0; i < count; i++) {
> +        ds_put_format(reply, "  %s (Use count: %d, Priority: %d",
> +                      lookup_funcs[i].name,
> +                      atomic_count_get(&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..c0dee4ff0 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_count usage_cnt;
>  };
>
>  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.
> + */
>  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,
> +                             bool will_use);
>

First some cut/pastes from the V2 discussion which was not completed:

EC> Guess you overload this function to do a counter update, which I do not 
like (see comments below).

HH> Yes - correct. I'd prefer keep separate APIs too, but in reality the 
implementation to increment a counter
HH> would require a search through all subtables (which we've already just 
done). So iterating all dpcls implementations
HH> a second time, doing a brute-force search in order to increment a variable 
seemed too much effort, as well as
HH> maintaining 2x implementations.

HH> The goal of adding the "will use result" parameter (overloading API) was to 
reduce code maintenance effort...

---

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

HH> As per above, the "dpcls_update_impl_use_count()" would require a 
brute-force search through the tables again.
HH> By incorporating the "increment" in the API, we can just iterate the 
implementations once.
HH> I think it is worth the complexity to avoid re-iterating implementations a 
2nd time.

---

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

HH> I see where you're going with this approach - see above comments.
HH> Would documenting the reasoning clearly as to why the API is overloaded, 
and keeping
HH> implementation (1 function, overloeaded with will_use_result) the same as 
is today be acceptable?

---

I think we should keep the API as clean as possible, and adding flags for all 
kinds of exceptions is not the way forward. This will result in a mess.

I’m sure you guys can come up with a nice solution. Without giving this much 
thought, you could maybe have dpcls_subtable_get_best_impl() return a pointer 
to dpcls_subtable_lookup_info_t and store/use that in dpcls_subtable, and have 
dpcls_update_impl_use_count() use a pointer to 
dpcls_subtable->dpcls_subtable_lookup_info_t?

>  /* 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..194e6914f 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -911,21 +911,9 @@ 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);
> -    }
> +
> +    dp_dpcls_impl_print_stats(&reply);
>      unixctl_command_reply(conn, ds_cstr(&reply));
>      ds_destroy(&reply);
>  }
> @@ -8940,6 +8928,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, false);
>      ovsrcu_postpone(dpcls_subtable_destroy_cb, subtable);
>  }
>
> @@ -8987,8 +8979,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,
> +                                                         true);
>      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 +9020,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;
> -        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, true);
> +        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
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to