@@ -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
@@ -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)
{
/* 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;
+ 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_read_relaxed(&subtable_lookups[i].usage_cnt, &usage_cnt);
+ usage_cnt--;
+ atomic_store_relaxed(&subtable_lookups[i].usage_cnt, usage_cnt);
}
}
- 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);
+ }
/* 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");
+
+ 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");
+ }
+
+}
@@ -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;
};
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,
+ 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 */
@@ -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);
- }
+ dp_dpcls_impl_print_stats(&reply);
unixctl_command_reply(conn, ds_cstr(&reply));
ds_destroy(&reply);
}
@@ -8919,6 +8906,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);
ovsrcu_postpone(dpcls_subtable_destroy_cb, subtable);
}
@@ -8966,8 +8957,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);
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);
@@ -9007,8 +8998,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, 1);
+ if (old_func != subtable->lookup_func) {
+ subtables_changed += 1;
+ }
}
pvector_publish(pvec);
@@ -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],