[ovs-dev] [PATCH v14 03/11] dpif-netdev: Add study function to select the best mfex function
Eelco Chaudron
echaudro at redhat.com
Fri Jul 16 09:16:08 UTC 2021
This one also has some indentation issue. Maybe Ian can fix on commit.
On 15 Jul 2021, at 18:06, kumar Amber wrote:
> From: Kumar Amber <kumar.amber at intel.com>
>
> The study function runs all the available implementations
> of miniflow_extract and makes a choice whose hitmask has
> maximum hits and sets the mfex to that function.
>
> Study can be run at runtime using the following command:
>
> $ ovs-appctl dpif-netdev/miniflow-parser-set study
>
> Signed-off-by: Kumar Amber <kumar.amber at intel.com>
> Co-authored-by: Harry van Haaren <harry.van.haaren at intel.com>
> Signed-off-by: Harry van Haaren <harry.van.haaren at intel.com>
> Acked-by: Eelco Chaudron <echaudro at redhat.com>
> Acked-by: Flavio Leitner <fbl at sysclose.org>
> ---
> v11:
> - fix minor comments from Eelco
> v10:
> - fix minor comments from Eelco
> v9:
> - fix comments Flavio
> v8:
> - fix review comments Flavio
> v7:
> - fix review comments(Eelco)
> v5:
> - fix review comments(Ian, Flavio, Eelco)
> - add Atomic set in study
> ---
> ---
> NEWS | 3 +
> lib/automake.mk | 1 +
> lib/dpif-netdev-extract-study.c | 136 ++++++++++++++++++++++++++++++
> lib/dpif-netdev-private-extract.c | 12 +++
> lib/dpif-netdev-private-extract.h | 19 +++++
> 5 files changed, 171 insertions(+)
> create mode 100644 lib/dpif-netdev-extract-study.c
>
> diff --git a/NEWS b/NEWS
> index cf254bcfe..4a7b89409 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -35,6 +35,9 @@ Post-v2.15.0
> * Add command line option to switch between MFEX function pointers.
> * Add miniflow extract auto-validator function to compare different
> miniflow extract implementations against default implementation.
> + * Add study function to miniflow function table which studies packet
> + and automatically chooses the best miniflow implementation for that
> + traffic.
> - ovs-ctl:
> * New option '--no-record-hostname' to disable hostname configuration
> in ovsdb on startup.
> diff --git a/lib/automake.mk b/lib/automake.mk
> index 53b8abc0f..f4f36325e 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -107,6 +107,7 @@ lib_libopenvswitch_la_SOURCES = \
> lib/dp-packet.h \
> lib/dp-packet.c \
> lib/dpdk.h \
> + lib/dpif-netdev-extract-study.c \
> lib/dpif-netdev-lookup.h \
> lib/dpif-netdev-lookup.c \
> lib/dpif-netdev-lookup-autovalidator.c \
> diff --git a/lib/dpif-netdev-extract-study.c b/lib/dpif-netdev-extract-study.c
> new file mode 100644
> index 000000000..02b709f8b
> --- /dev/null
> +++ b/lib/dpif-netdev-extract-study.c
> @@ -0,0 +1,136 @@
> +/*
> + * Copyright (c) 2021 Intel.
> + *
> + * 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>
> +#include <errno.h>
> +#include <stdint.h>
> +#include <string.h>
> +
> +#include "dpif-netdev-private-thread.h"
> +#include "openvswitch/vlog.h"
> +#include "ovs-thread.h"
> +
> +VLOG_DEFINE_THIS_MODULE(dpif_mfex_extract_study);
> +
> +static atomic_uint32_t mfex_study_pkts_count = 0;
> +
> +/* Struct to hold miniflow study stats. */
> +struct study_stats {
> + uint32_t pkt_count;
> + uint32_t impl_hitcount[MFEX_IMPL_MAX];
> +};
> +
> +/* Define per thread data to hold the study stats. */
> +DEFINE_PER_THREAD_MALLOCED_DATA(struct study_stats *, study_stats);
> +
> +/* Allocate per thread PMD pointer space for study_stats. */
> +static inline struct study_stats *
> +mfex_study_get_study_stats_ptr(void)
> +{
> + struct study_stats *stats = study_stats_get();
> + if (OVS_UNLIKELY(!stats)) {
> + stats = xzalloc(sizeof *stats);
> + study_stats_set_unsafe(stats);
The above two are not indented correctly.
> + }
> + return stats;
> +}
> +
> +uint32_t
> +mfex_study_traffic(struct dp_packet_batch *packets,
> + struct netdev_flow_key *keys,
> + uint32_t keys_size, odp_port_t in_port,
> + struct dp_netdev_pmd_thread *pmd_handle)
> +{
> + uint32_t hitmask = 0;
> + uint32_t mask = 0;
> + struct dp_netdev_pmd_thread *pmd = pmd_handle;
> + struct dpif_miniflow_extract_impl *miniflow_funcs;
> + struct study_stats *stats = mfex_study_get_study_stats_ptr();
> + miniflow_funcs = dpif_mfex_impl_info_get();
> +
> + /* Run traffic optimized miniflow_extract to collect the hitmask
> + * to be compared after certain packets have been hit to choose
> + * the best miniflow_extract version for that traffic.
> + */
> + for (int i = MFEX_IMPL_START_IDX; i < MFEX_IMPL_MAX; i++) {
> + if (!miniflow_funcs[i].available) {
> + continue;
> + }
> +
> + hitmask = miniflow_funcs[i].extract_func(packets, keys, keys_size,
> + in_port, pmd_handle);
> + stats->impl_hitcount[i] += count_1bits(hitmask);
> +
> + /* If traffic is not classified then we dont overwrite the keys
> + * array in minfiflow implementations so its safe to create a
> + * mask for all those packets whose miniflow have been created.
> + */
> + mask |= hitmask;
> + }
> +
> + stats->pkt_count += dp_packet_batch_size(packets);
> +
> + /* Choose the best implementation after a minimum packets have been
> + * processed.
> + */
> + if (stats->pkt_count >= MFEX_MAX_PKT_COUNT) {
> + uint32_t best_func_index = MFEX_IMPL_START_IDX;
> + uint32_t max_hits = 0;
> + for (int i = MFEX_IMPL_START_IDX; i < MFEX_IMPL_MAX; i++) {
> + if (stats->impl_hitcount[i] > max_hits) {
> + max_hits = stats->impl_hitcount[i];
> + best_func_index = i;
> + }
> + }
> +
> + /* If 50% of the packets hit, enable the function. */
> + if (max_hits >= (mfex_study_pkts_count / 2)) {
> + miniflow_extract_func mf_func =
> + miniflow_funcs[best_func_index].extract_func;
> + atomic_uintptr_t *pmd_func = (void *)&pmd->miniflow_extract_opt;
> + atomic_store_relaxed(pmd_func, (uintptr_t) mf_func);
> + VLOG_INFO("MFEX study chose impl %s: (hits %u/%u pkts)",
> + miniflow_funcs[best_func_index].name, max_hits,
> + stats->pkt_count);
> + } else {
> + /* Set the implementation to null for default miniflow. */
> + miniflow_extract_func mf_func =
> + miniflow_funcs[MFEX_IMPL_SCALAR].extract_func;
> + atomic_uintptr_t *pmd_func = (void *)&pmd->miniflow_extract_opt;
> + atomic_store_relaxed(pmd_func, (uintptr_t) mf_func);
> + VLOG_INFO("Not enough packets matched (%u/%u), disabling"
> + " optimized MFEX.", max_hits, stats->pkt_count);
> + }
> +
> + /* In debug mode show stats for all the counters. */
> + if (VLOG_IS_DBG_ENABLED()) {
> +
> + for (int i = MFEX_IMPL_START_IDX; i < MFEX_IMPL_MAX; i++) {
> + VLOG_DBG("MFEX study results for implementation %s:"
> + " (hits %u/%u pkts)",
> + miniflow_funcs[i].name, stats->impl_hitcount[i],
> + stats->pkt_count);
> + }
> + }
> +
> + /* Reset stats so that study function can be called again
> + * for next traffic type and optimal function ptr can be
> + * chosen.
> + */
> + memset(stats, 0, sizeof(struct study_stats));
> + }
> + return mask;
> +}
> diff --git a/lib/dpif-netdev-private-extract.c b/lib/dpif-netdev-private-extract.c
> index c283ff3e1..f1e81a451 100644
> --- a/lib/dpif-netdev-private-extract.c
> +++ b/lib/dpif-netdev-private-extract.c
> @@ -47,6 +47,11 @@ static struct dpif_miniflow_extract_impl mfex_impls[] = {
> .probe = NULL,
> .extract_func = NULL,
> .name = "scalar", },
> +
> + [MFEX_IMPL_STUDY] = {
> + .probe = NULL,
> + .extract_func = mfex_study_traffic,
> + .name = "study", },
> };
>
> BUILD_ASSERT_DECL(MFEX_IMPL_MAX == ARRAY_SIZE(mfex_impls));
> @@ -166,6 +171,13 @@ dp_mfex_impl_get_by_name(const char *name, miniflow_extract_func *out_func)
> return -ENOENT;
> }
>
> +struct dpif_miniflow_extract_impl *
> +dpif_mfex_impl_info_get(void) {
> +
> + return mfex_impls;
> +
> +}
> +
> uint32_t
> dpif_miniflow_extract_autovalidator(struct dp_packet_batch *packets,
> struct netdev_flow_key *keys,
> diff --git a/lib/dpif-netdev-private-extract.h b/lib/dpif-netdev-private-extract.h
> index 88c517506..9c03a1aa0 100644
> --- a/lib/dpif-netdev-private-extract.h
> +++ b/lib/dpif-netdev-private-extract.h
> @@ -80,6 +80,7 @@ struct dpif_miniflow_extract_impl {
> enum dpif_miniflow_extract_impl_idx {
> MFEX_IMPL_AUTOVALIDATOR,
> MFEX_IMPL_SCALAR,
> + MFEX_IMPL_STUDY,
> MFEX_IMPL_MAX
> };
>
> @@ -91,6 +92,9 @@ extern struct ovs_mutex dp_netdev_mutex;
>
> #define MFEX_IMPL_START_IDX MFEX_IMPL_MAX
>
> +/* Max count of packets to be compared. */
> +#define MFEX_MAX_PKT_COUNT (128)
> +
> /* This function returns all available implementations to the caller. The
> * quantity of implementations is returned by the int return value.
> */
> @@ -111,6 +115,9 @@ miniflow_extract_func dp_mfex_impl_get_default(void);
> /* Overrides the default MFEX with the user set MFEX. */
> int dp_mfex_impl_set_default_by_name(const char *name);
>
> +/* Retrieve the array of miniflow implementations for iteration. */
> +struct dpif_miniflow_extract_impl *
> +dpif_mfex_impl_info_get(void);
>
> /* Initializes the available miniflow extract implementations by probing for
> * the CPU ISA requirements. As the runtime available CPU ISA does not change
> @@ -132,4 +139,16 @@ dpif_miniflow_extract_autovalidator(struct dp_packet_batch *batch,
> uint32_t keys_size, odp_port_t in_port,
> struct dp_netdev_pmd_thread *pmd_handle);
>
> +/* Retrieve the number of packets by studying packets using different miniflow
> + * implementations to choose the best implementation using the maximum hitmask
> + * count.
> + * On error, returns a zero for no packets.
> + * On success, returns mask of the packets hit.
> + */
> +uint32_t
> +mfex_study_traffic(struct dp_packet_batch *packets,
> + struct netdev_flow_key *keys,
> + uint32_t keys_size, odp_port_t in_port,
> + struct dp_netdev_pmd_thread *pmd_handle);
> +
> #endif /* MFEX_AVX512_EXTRACT */
> --
> 2.25.1
More information about the dev
mailing list