On 2 Dec 2021, at 11:05, 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]>
>
> ---
> v4:
> - Fix comments on the patch.
> - Change API from an overloaded method of counting, to returning the
>   old and new subtable structs. This allows the caller to identify the
>   modified subtable implementations, and update the statistics accordingly.
> 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             | 70 +++++++++++++++++++++++-----
>  lib/dpif-netdev-lookup.h             | 20 +++++++-
>  lib/dpif-netdev.c                    | 61 +++++++++++++++++-------
>  tests/pmd.at                         | 16 +++----
>  5 files changed, 137 insertions(+), 46 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..0aa79e27c 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 = ATOMIC_COUNT_INIT(0), },
>
>      /* The default scalar C code implementation. */
>      { .prio = 1,
>        .probe = dpcls_subtable_generic_probe,
> -      .name = "generic", },
> +      .name = "generic",
> +      .usage_cnt = ATOMIC_COUNT_INIT(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 = ATOMIC_COUNT_INIT(0), },
>  #else
>      /* Disabling AVX512 at compile time, as compile time requirements not 
> met.
>       * This could be due to a number of reasons:
> @@ -93,27 +96,46 @@ 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,
> +                             struct dpcls_subtable_lookup_info_t **old_info,
> +                             struct dpcls_subtable_lookup_info_t **new_info)

I still feel this API is really ugly. See my proposed patch at the end.
>
>  {
>      /* Iter over each subtable impl, and get highest priority one. */
>      int32_t prio = -1;

This was not changed in this patch, but I guess this can be changed to int.

>      const char *name = NULL;
> +    int best_idx = 0;
>      dpcls_subtable_lookup_func best_func = NULL;
>
>      for (int i = 0; i < ARRAY_SIZE(subtable_lookups); i++) {
>          int32_t probed_prio = subtable_lookups[i].prio;

Same as above should be int.

> +        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;
> +        }
> +
> +        /* Return the replaced info struct to the user for usage statistics. 
> */
> +        if (probed_func == old_func && old_info) {
> +            *old_info = &subtable_lookups[i];
>          }
>      }
>
> +    /* Return the newly used info struct to the user for usage statistics. */
> +    if (new_info) {
> +        *new_info = &subtable_lookups[best_idx];
> +    }
> +
>      VLOG_DBG("Subtable lookup function '%s' with units (%d,%d), priority 
> %d\n",
>               name, u0_bit_count, u1_bit_count, prio);
>
> @@ -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)

All external functions have dpcls_xxxx, and reason why this one has 
dp_dpcls_xxxx? I would change this one also to dpcls_impl_print_stats().


> +{
> +    struct dpcls_subtable_lookup_info_t *lookup_funcs = NULL;
> +    int32_t count = dpcls_subtable_lookup_info_get(&lookup_funcs);

Guess this should have been int, but the dpcls_subtable_lookup_info_get() and 
dpcls_subtable_set_prio() should have returned int. Maybe, this can be fixed in 
a separate patch.

> +
> +    /* 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");
> +    }
> +
> +}

<SNIP>

Proposal of changes to this patch API (only compile tested/selftest tested on 
non AVX512):



diff --git a/lib/dpif-netdev-lookup.c b/lib/dpif-netdev-lookup.c
index 0aa79e27c..e641e4028 100644
--- a/lib/dpif-netdev-lookup.c
+++ b/lib/dpif-netdev-lookup.c
@@ -67,7 +67,7 @@ static struct dpcls_subtable_lookup_info_t subtable_lookups[] 
= {
 #endif
 };

-int32_t
+int
 dpcls_subtable_lookup_info_get(struct dpcls_subtable_lookup_info_t **out_ptr)
 {
     if (out_ptr == NULL) {
@@ -79,7 +79,7 @@ dpcls_subtable_lookup_info_get(struct 
dpcls_subtable_lookup_info_t **out_ptr)
 }

 /* sets the priority of the lookup function with "name". */
-int32_t
+int
 dpcls_subtable_set_prio(const char *name, uint8_t priority)
 {
     for (int i = 0; i < ARRAY_SIZE(subtable_lookups); i++) {
@@ -97,59 +97,65 @@ 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_lookup_func old_func,
-                             struct dpcls_subtable_lookup_info_t **old_info,
-                             struct dpcls_subtable_lookup_info_t **new_info)
+                             struct dpcls_subtable_lookup_info_t **info)
 {
-    /* Iter over each subtable impl, and get highest priority one. */
-    int32_t prio = -1;
-    const char *name = NULL;
-    int best_idx = 0;
+    struct dpcls_subtable_lookup_info_t *best_info = NULL;
     dpcls_subtable_lookup_func best_func = NULL;
+    int prio = -1;

+    /* Iter over each subtable impl, and get highest priority one. */
     for (int i = 0; i < ARRAY_SIZE(subtable_lookups); i++) {
-        int32_t probed_prio = subtable_lookups[i].prio;
+        struct dpcls_subtable_lookup_info_t *impl_info = &subtable_lookups[i];
         dpcls_subtable_lookup_func probed_func;

+        if (impl_info->prio <= prio) {
+            continue;
+        }
+
         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) {
-            best_func = probed_func;
-            best_idx = i;
-            prio = probed_prio;
-            name = subtable_lookups[i].name;
-        }
-
-        /* Return the replaced info struct to the user for usage statistics. */
-        if (probed_func == old_func && old_info) {
-            *old_info = &subtable_lookups[i];
-        }
+        best_func = probed_func;
+        best_info = impl_info;
+        prio = impl_info->prio;
     }

-    /* Return the newly used info struct to the user for usage statistics. */
-    if (new_info) {
-        *new_info = &subtable_lookups[best_idx];
-    }
+    /* Programming error - we must always return a valid func ptr. */
+    ovs_assert(best_func != NULL && best_info != NULL);

     VLOG_DBG("Subtable lookup function '%s' with units (%d,%d), priority %d\n",
-             name, u0_bit_count, u1_bit_count, prio);
-
-    /* Programming error - we must always return a valid func ptr. */
-    ovs_assert(best_func != NULL);
+             best_info->name, u0_bit_count, u1_bit_count, prio);

+    if (info) {
+        *info = best_info;
+    }
     return best_func;
 }

 void
-dp_dpcls_impl_print_stats(struct ds *reply)
+dpcls_info_inc_usage(struct dpcls_subtable_lookup_info_t *info)
+{
+    if (info) {
+        atomic_count_inc(&info->usage_cnt);
+    }
+}
+
+void
+dpcls_info_dec_usage(struct dpcls_subtable_lookup_info_t *info)
+{
+    if (info) {
+        atomic_count_dec(&info->usage_cnt);
+    }
+}
+
+void
+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);
+    int count = dpcls_subtable_lookup_info_get(&lookup_funcs);

     /* Add all DPCLS functions to reply string. */
     ds_put_cstr(reply, "Available dpcls implementations:\n");
diff --git a/lib/dpif-netdev-lookup.h b/lib/dpif-netdev-lookup.h
index 762147b4e..7f124a46e 100644
--- a/lib/dpif-netdev-lookup.h
+++ b/lib/dpif-netdev-lookup.h
@@ -68,30 +68,24 @@ struct dpcls_subtable_lookup_info_t {
     atomic_count usage_cnt;
 };

-int32_t dpcls_subtable_set_prio(const char *name, uint8_t priority);
+int dpcls_subtable_set_prio(const char *name, uint8_t priority);
+void dpcls_info_inc_usage(struct dpcls_subtable_lookup_info_t *info);
+void dpcls_info_dec_usage(struct dpcls_subtable_lookup_info_t *info);

-/* Lookup the best subtable lookup implementation for the given u0,u1 count.
- * When replacing an existing lookup func, the old_func pointer, old_info
- * and new_func are used for tracking the current and old implementations
- * which are further used for incrementing or decrementing implementation
- * statistics.
- */
+/* Lookup the best subtable lookup implementation for the given u0,u1 count. */
 dpcls_subtable_lookup_func
 dpcls_subtable_get_best_impl(uint32_t u0_bit_count, uint32_t u1_bit_count,
-                             dpcls_subtable_lookup_func old_func,
-                             struct dpcls_subtable_lookup_info_t **old_info,
-                             struct dpcls_subtable_lookup_info_t **new_func);
-
+                             struct dpcls_subtable_lookup_info_t **info);

 /* Retrieve the array of lookup implementations for iteration.
  * On error, returns a negative number.
  * On success, returns the size of the arrays pointed to by the out parameter.
  */
-int32_t
+int
 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);
+dpcls_impl_print_stats(struct ds *reply);

 #endif /* dpif-netdev-lookup.h */
diff --git a/lib/dpif-netdev-private-dpcls.h b/lib/dpif-netdev-private-dpcls.h
index 7c4a840cb..06e896bef 100644
--- a/lib/dpif-netdev-private-dpcls.h
+++ b/lib/dpif-netdev-private-dpcls.h
@@ -85,6 +85,7 @@ struct dpcls_subtable {
      * used for the lookup) then this can point at an optimized version of
      * the lookup function for this particular subtable. */
     dpcls_subtable_lookup_func lookup_func;
+    struct dpcls_subtable_lookup_info_t *lookup_func_info;

     /* Caches the masks to match a packet to, reducing runtime calculations. */
     uint64_t *mf_masks;
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index fba02f141..4c36753ca 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -913,7 +913,7 @@ dpif_netdev_subtable_lookup_get(struct unixctl_conn *conn, 
int argc OVS_UNUSED,
 {
     struct ds reply = DS_EMPTY_INITIALIZER;

-    dp_dpcls_impl_print_stats(&reply);
+    dpcls_impl_print_stats(&reply);
     unixctl_command_reply(conn, ds_cstr(&reply));
     ds_destroy(&reply);
 }
@@ -8928,21 +8928,7 @@ 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);
-
-    struct dpcls_subtable_lookup_info_t *old_info = NULL;
-    dpcls_subtable_get_best_impl(subtable->mf_bits_set_unit0,
-                                 subtable->mf_bits_set_unit1,
-                                 subtable->lookup_func,
-                                 &old_info,
-                                 NULL);
-
-    /* Reduce the usage count as this subtable is being destroyed. */
-    if (OVS_UNLIKELY(!old_info)) {
-        VLOG_ERR("Subtable destory: No subtable to destroy\n");
-    } else  {
-        atomic_count_dec(&old_info->usage_cnt);
-    }
-
+    dpcls_info_dec_usage(subtable->lookup_func_info);
     ovsrcu_postpone(dpcls_subtable_destroy_cb, subtable);
 }

@@ -8968,7 +8954,6 @@ static struct dpcls_subtable *
 dpcls_create_subtable(struct dpcls *cls, const struct netdev_flow_key *mask)
 {
     struct dpcls_subtable *subtable;
-    struct dpcls_subtable_lookup_info_t *new_info = NULL;

     /* Need to add one. */
     subtable = xmalloc(sizeof *subtable
@@ -8991,11 +8976,9 @@ 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, NULL,
-                                                         NULL, &new_info);
-    if (new_info) {
-        atomic_count_inc(&new_info->usage_cnt);
-    }
+    subtable->lookup_func = dpcls_subtable_get_best_impl(
+        unit0, unit1, &subtable->lookup_func_info);
+    dpcls_info_inc_usage(subtable->lookup_func_info);

     cmap_insert(&cls->subtables_map, &subtable->cmap_node, mask->hash);
     /* Add the new subtable at the end of the pvector (with no hits yet) */
@@ -9036,26 +9019,21 @@ 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;
-        struct dpcls_subtable_lookup_info_t *old_info = NULL;
-        struct dpcls_subtable_lookup_info_t *new_info = NULL;
+        struct dpcls_subtable_lookup_info_t *old_info;
+
+        old_info = subtable->lookup_func_info;
+        subtable->lookup_func = dpcls_subtable_get_best_impl(
+            u0_bits, u1_bits, &subtable->lookup_func_info);

-        /* get best implementaiton, and pointers to old/new info structs to
-         * keep usage statistics up to date.
-         */
-        subtable->lookup_func = dpcls_subtable_get_best_impl(u0_bits, u1_bits,
-                                                             old_func,
-                                                             &old_info,
-                                                             &new_info);
         if (old_func != subtable->lookup_func) {
             subtables_changed += 1;
         }

-        if (old_info) {
-            atomic_count_dec(&old_info->usage_cnt);
-        }
-
-        if (new_info) {
-            atomic_count_inc(&new_info->usage_cnt);
+        if (old_info != subtable->lookup_func_info) {
+            /* In theory, functions can be shared between implementations, so
+             * do an explicit check on the function info structures. */
+            dpcls_info_dec_usage(old_info);
+            dpcls_info_inc_usage(subtable->lookup_func_info);
         }
     }
     pvector_publish(pvec);

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to