Coverage Report

Created: 2025-07-11 06:11

/src/openvswitch/lib/dpif-netdev-extract-study.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2021 Intel.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at:
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <config.h>
18
#include <errno.h>
19
#include <stdint.h>
20
#include <string.h>
21
22
#include "dpif-netdev-private-thread.h"
23
#include "openvswitch/vlog.h"
24
#include "ovs-thread.h"
25
26
VLOG_DEFINE_THIS_MODULE(dpif_mfex_extract_study);
27
28
static atomic_uint32_t mfex_study_pkts_count = MFEX_MAX_PKT_COUNT;
29
30
/* Struct to hold miniflow study stats. */
31
struct study_stats {
32
    uint32_t pkt_count;
33
    uint32_t impl_hitcount[MFEX_IMPL_MAX];
34
};
35
36
/* Define per thread data to hold the study stats. */
37
DEFINE_PER_THREAD_MALLOCED_DATA(struct study_stats *, study_stats);
38
39
/* Allocate per thread PMD pointer space for study_stats. */
40
static inline struct study_stats *
41
mfex_study_get_study_stats_ptr(void)
42
0
{
43
0
    struct study_stats *stats = study_stats_get();
44
0
    if (OVS_UNLIKELY(!stats)) {
45
0
        stats = xzalloc(sizeof *stats);
46
0
        study_stats_set_unsafe(stats);
47
0
    }
48
0
    return stats;
49
0
}
50
51
int
52
mfex_set_study_pkt_cnt(uint32_t pkt_cmp_count, const char *name)
53
0
{
54
0
    struct dpif_miniflow_extract_impl *miniflow_funcs;
55
0
    miniflow_funcs = dpif_mfex_impl_info_get();
56
57
    /* If the packet count is set and implementation called is study then
58
     * set packet counter to requested number else return -EINVAL.
59
     */
60
0
    if ((strcmp(miniflow_funcs[MFEX_IMPL_STUDY].name, name) == 0) &&
61
0
        (pkt_cmp_count != 0)) {
62
63
0
        atomic_store_relaxed(&mfex_study_pkts_count, pkt_cmp_count);
64
0
        return 0;
65
0
    }
66
67
0
    return -EINVAL;
68
0
}
69
70
uint32_t
71
mfex_study_traffic(struct dp_packet_batch *packets,
72
                   struct netdev_flow_key *keys,
73
                   uint32_t keys_size, odp_port_t in_port,
74
                   struct dp_netdev_pmd_thread *pmd_handle)
75
0
{
76
0
    uint32_t hitmask = 0;
77
0
    uint32_t mask = 0;
78
0
    struct dp_netdev_pmd_thread *pmd = pmd_handle;
79
0
    struct dpif_miniflow_extract_impl *miniflow_funcs;
80
0
    struct study_stats *stats = mfex_study_get_study_stats_ptr();
81
0
    miniflow_funcs = dpif_mfex_impl_info_get();
82
83
    /* Run traffic optimized miniflow_extract to collect the hitmask
84
     * to be compared after certain packets have been hit to choose
85
     * the best miniflow_extract version for that traffic.
86
     */
87
0
    for (int i = MFEX_IMPL_START_IDX; i < MFEX_IMPL_MAX; i++) {
88
0
        if (!miniflow_funcs[i].available) {
89
0
            continue;
90
0
        }
91
92
0
        hitmask = miniflow_funcs[i].extract_func(packets, keys, keys_size,
93
0
                                                 in_port, pmd_handle);
94
0
        stats->impl_hitcount[i] += count_1bits(hitmask);
95
96
        /* If traffic is not classified then we dont overwrite the keys
97
         * array in minfiflow implementations so its safe to create a
98
         * mask for all those packets whose miniflow have been created.
99
         */
100
0
        mask |= hitmask;
101
0
    }
102
103
0
    stats->pkt_count += dp_packet_batch_size(packets);
104
105
    /* Choose the best implementation after a minimum packets have been
106
     * processed.
107
     */
108
0
    uint32_t study_cnt_pkts;
109
0
    atomic_read_relaxed(&mfex_study_pkts_count, &study_cnt_pkts);
110
111
0
    if (stats->pkt_count >= study_cnt_pkts) {
112
0
        uint32_t best_func_index = MFEX_IMPL_START_IDX;
113
0
        uint32_t max_hits = 0;
114
0
        for (int i = MFEX_IMPL_START_IDX; i < MFEX_IMPL_MAX; i++) {
115
0
            if (stats->impl_hitcount[i] > max_hits) {
116
0
                max_hits = stats->impl_hitcount[i];
117
0
                best_func_index = i;
118
0
            }
119
0
        }
120
121
        /* If 50% of the packets hit, enable the function. */
122
0
        if (max_hits >= (mfex_study_pkts_count / 2)) {
123
0
            atomic_store_relaxed(&pmd->miniflow_extract_opt,
124
0
                                 miniflow_funcs[best_func_index].extract_func);
125
0
            VLOG_INFO("MFEX study chose impl %s: (hits %u/%u pkts)",
126
0
                      miniflow_funcs[best_func_index].name, max_hits,
127
0
                      stats->pkt_count);
128
0
        } else {
129
            /* Set the implementation to null for default miniflow. */
130
0
            atomic_store_relaxed(&pmd->miniflow_extract_opt,
131
0
                    miniflow_funcs[MFEX_IMPL_SCALAR].extract_func);
132
0
            VLOG_INFO("Not enough packets matched (%u/%u), disabling"
133
0
                      " optimized MFEX.", max_hits, stats->pkt_count);
134
0
        }
135
136
        /* In debug mode show stats for all the counters. */
137
0
        if (VLOG_IS_DBG_ENABLED()) {
138
139
0
            for (int i = MFEX_IMPL_START_IDX; i < MFEX_IMPL_MAX; i++) {
140
0
                VLOG_DBG("MFEX study results for implementation %s:"
141
0
                         " (hits %u/%u pkts)", miniflow_funcs[i].name,
142
0
                         stats->impl_hitcount[i], stats->pkt_count);
143
0
            }
144
0
        }
145
146
        /* Reset stats so that study function can be called again
147
         * for next traffic type and optimal function ptr can be
148
         * chosen.
149
         */
150
0
        memset(stats, 0, sizeof(struct study_stats));
151
0
    }
152
0
    return mask;
153
0
}