The statistics were stored as allocated object for each individual
statistic and linked together via list. Store them in vector instead
which allows us to avoid a lot of small allocations and free right
after using the statistic.

The same applies to the buffered packets, use vector instead of moving
around single allocated objects. This should reduce the fragmentation.

Signed-off-by: Ales Musil <amu...@redhat.com>
---
v4: Rebase on top of current main.
    Adjust the thhreshold define names.
    Add missing vector_destroy.
v3: Rebase on top of current main.
v2: Rebase on top of current main.
---
 controller/mac-cache.c | 191 +++++++++++++++++------------------------
 controller/mac-cache.h |  39 +++++----
 controller/pinctrl.c   |  15 +++-
 controller/statctrl.c  |  54 ++++++------
 4 files changed, 141 insertions(+), 158 deletions(-)

diff --git a/controller/mac-cache.c b/controller/mac-cache.c
index 18236c440..3237677dc 100644
--- a/controller/mac-cache.c
+++ b/controller/mac-cache.c
@@ -18,6 +18,7 @@
 
 #include "lflow.h"
 #include "lib/mac-binding-index.h"
+#include "lib/vec.h"
 #include "local_data.h"
 #include "lport.h"
 #include "mac-cache.h"
@@ -339,43 +340,30 @@ fdbs_clear(struct hmap *map)
     }
 }
 
-struct mac_cache_stats {
-    struct ovs_list list_node;
-
-    int64_t idle_age_ms;
-
-    union {
-        /* Common data to identify MAC binding. */
-        struct mac_binding_data mb;
-        /* Common data to identify FDB. */
-        struct fdb_data fdb;
-    } data;
-};
-
 /* MAC binding stat processing. */
 void
-mac_binding_stats_process_flow_stats(struct ovs_list *stats_list,
+mac_binding_stats_process_flow_stats(struct vector *stats_vec,
                                      struct ofputil_flow_stats *ofp_stats)
 {
-    struct mac_cache_stats *stats = xmalloc(sizeof *stats);
-
-    stats->idle_age_ms = ofp_stats->idle_age * 1000;
-    stats->data.mb = (struct mac_binding_data) {
-        .cookie = ntohll(ofp_stats->cookie),
-        /* The port_key must be zero to match mac_binding_data_from_sbrec. */
-        .port_key = 0,
-        .dp_key = ntohll(ofp_stats->match.flow.metadata),
-        .mac = ofp_stats->match.flow.dl_src
+    struct mac_cache_stats stats = (struct mac_cache_stats) {
+        .idle_age_ms = ofp_stats->idle_age * 1000,
+        .data.mb = (struct mac_binding_data) {
+            .cookie = ntohll(ofp_stats->cookie),
+            /* The port_key must be zero to match
+             * mac_binding_data_from_sbrec. */
+            .port_key = 0,
+            .dp_key = ntohll(ofp_stats->match.flow.metadata),
+            .mac = ofp_stats->match.flow.dl_src
+        },
     };
 
     if (ofp_stats->match.flow.dl_type == htons(ETH_TYPE_IP) ||
         ofp_stats->match.flow.dl_type == htons(ETH_TYPE_ARP)) {
-        stats->data.mb.ip = in6_addr_mapped_ipv4(ofp_stats->match.flow.nw_src);
+        stats.data.mb.ip = in6_addr_mapped_ipv4(ofp_stats->match.flow.nw_src);
     } else {
-        stats->data.mb.ip = ofp_stats->match.flow.ipv6_src;
+        stats.data.mb.ip = ofp_stats->match.flow.ipv6_src;
     }
-
-    ovs_list_push_back(stats_list, &stats->list_node);
+    vector_push(stats_vec, &stats);
 }
 
 static void
@@ -409,19 +397,18 @@ void
 mac_binding_stats_run(
         struct rconn *swconn OVS_UNUSED,
         struct ovsdb_idl_index *sbrec_port_binding_by_name OVS_UNUSED,
-        struct ovs_list *stats_list, uint64_t *req_delay, void *data)
+        struct vector *stats_vec, uint64_t *req_delay, void *data)
 {
     struct mac_cache_data *cache_data = data;
     long long timewall_now = time_wall_msec();
 
     struct mac_cache_stats *stats;
-    LIST_FOR_EACH_POP (stats, list_node, stats_list) {
+    VECTOR_FOR_EACH_PTR (stats_vec, stats) {
         struct mac_binding *mb = mac_binding_find(&cache_data->mac_bindings,
                                                   &stats->data.mb);
         if (!mb) {
             mac_binding_update_log("Not found in the cache:", &stats->data.mb,
                                    false, NULL, 0, 0);
-            free(stats);
             continue;
         }
 
@@ -449,7 +436,6 @@ mac_binding_stats_run(
                                    threshold, stats->idle_age_ms,
                                    since_updated_ms);
         }
-        free(stats);
     }
 
     mac_cache_update_req_delay(&cache_data->thresholds, req_delay);
@@ -460,19 +446,18 @@ mac_binding_stats_run(
 
 /* FDB stat processing. */
 void
-fdb_stats_process_flow_stats(struct ovs_list *stats_list,
+fdb_stats_process_flow_stats(struct vector *stats_vec,
                              struct ofputil_flow_stats *ofp_stats)
 {
-    struct mac_cache_stats *stats = xmalloc(sizeof *stats);
-
-    stats->idle_age_ms = ofp_stats->idle_age * 1000;
-    stats->data.fdb = (struct fdb_data) {
+    struct mac_cache_stats stats = (struct mac_cache_stats) {
+        .idle_age_ms = ofp_stats->idle_age * 1000,
+        .data.fdb = (struct fdb_data) {
             .port_key = ofp_stats->match.flow.regs[MFF_LOG_INPORT - MFF_REG0],
             .dp_key = ntohll(ofp_stats->match.flow.metadata),
             .mac = ofp_stats->match.flow.dl_src
+        },
     };
-
-    ovs_list_push_back(stats_list, &stats->list_node);
+    vector_push(stats_vec, &stats);
 }
 
 static void
@@ -506,20 +491,19 @@ fdb_update_log(const char *action,
 void
 fdb_stats_run(struct rconn *swconn OVS_UNUSED,
               struct ovsdb_idl_index *sbrec_port_binding_by_name OVS_UNUSED,
-              struct ovs_list *stats_list,
+              struct vector *stats_vec,
               uint64_t *req_delay, void *data)
 {
     struct mac_cache_data *cache_data = data;
     long long timewall_now = time_wall_msec();
 
     struct mac_cache_stats *stats;
-    LIST_FOR_EACH_POP (stats, list_node, stats_list) {
+    VECTOR_FOR_EACH_PTR (stats_vec, stats) {
         struct fdb *fdb = fdb_find(&cache_data->fdbs, &stats->data.fdb);
 
         if (!fdb) {
             fdb_update_log("Not found in the cache:", &stats->data.fdb,
                            false, NULL, 0, 0);
-            free(stats);
             continue;
         }
 
@@ -546,8 +530,6 @@ fdb_stats_run(struct rconn *swconn OVS_UNUSED,
             fdb_update_log("Not updating non-active", &fdb->data, true,
                            threshold, stats->idle_age_ms, since_updated_ms);
         }
-
-        free(stats);
     }
 
     mac_cache_update_req_delay(&cache_data->thresholds, req_delay);
@@ -557,34 +539,10 @@ fdb_stats_run(struct rconn *swconn OVS_UNUSED,
 }
 
 /* Packet buffering. */
-struct bp_packet_data *
-bp_packet_data_create(const struct ofputil_packet_in *pin,
-                      const struct ofpbuf *continuation) {
-    struct bp_packet_data *pd = xmalloc(sizeof *pd);
-
-    pd->pin = (struct ofputil_packet_in) {
-            .packet = xmemdup(pin->packet, pin->packet_len),
-            .packet_len = pin->packet_len,
-            .flow_metadata = pin->flow_metadata,
-            .reason = pin->reason,
-            .table_id = pin->table_id,
-            .cookie = pin->cookie,
-            /* Userdata are empty on purpose,
-             * it is not needed for the continuation. */
-            .userdata = NULL,
-            .userdata_len = 0,
-    };
-    pd->continuation = ofpbuf_clone(continuation);
-
-    return pd;
-}
-
-
 void
 bp_packet_data_destroy(struct bp_packet_data *pd) {
     free(pd->pin.packet);
     ofpbuf_delete(pd->continuation);
-    free(pd);
 }
 
 struct buffered_packets *
@@ -604,7 +562,8 @@ buffered_packets_add(struct buffered_packets_ctx *ctx,
         /* Schedule the freshly added buffered packet to do lookup
          * immediately. */
         bp->lookup_at_ms = 0;
-        ovs_list_init(&bp->queue);
+        bp->queue = VECTOR_CAPACITY_INITIALIZER(struct bp_packet_data,
+                                                BUFFER_QUEUE_DEPTH);
     }
 
     bp->expire_at_ms = time_msec() + BUFFERED_PACKETS_TIMEOUT_MS;
@@ -614,14 +573,32 @@ buffered_packets_add(struct buffered_packets_ctx *ctx,
 
 void
 buffered_packets_packet_data_enqueue(struct buffered_packets *bp,
-                                     struct bp_packet_data *pd) {
-    if (ovs_list_size(&bp->queue) == BUFFER_QUEUE_DEPTH) {
-        struct bp_packet_data *p = CONTAINER_OF(ovs_list_pop_front(&bp->queue),
-                                                struct bp_packet_data, node);
-
-        bp_packet_data_destroy(p);
+                                     const struct ofputil_packet_in *pin,
+                                     const struct ofpbuf *continuation)
+{
+    if (vector_len(&bp->queue) == BUFFER_QUEUE_DEPTH) {
+        struct bp_packet_data pd;
+        vector_remove(&bp->queue, 0, &pd);
+        bp_packet_data_destroy(&pd);
     }
-    ovs_list_push_back(&bp->queue, &pd->node);
+
+    struct bp_packet_data pd = (struct bp_packet_data) {
+        .pin = (struct ofputil_packet_in) {
+            .packet = xmemdup(pin->packet, pin->packet_len),
+            .packet_len = pin->packet_len,
+            .flow_metadata = pin->flow_metadata,
+            .reason = pin->reason,
+            .table_id = pin->table_id,
+            .cookie = pin->cookie,
+            /* Userdata are empty on purpose,
+             * it is not needed for the continuation. */
+            .userdata = NULL,
+            .userdata_len = 0,
+        },
+        .continuation = ofpbuf_clone(continuation),
+    };
+
+    vector_push(&bp->queue, &pd);
 }
 
 void
@@ -661,16 +638,18 @@ buffered_packets_ctx_run(struct buffered_packets_ctx *ctx,
         }
 
         struct bp_packet_data *pd;
-        LIST_FOR_EACH_POP (pd, node, &bp->queue) {
+        VECTOR_FOR_EACH_PTR (&bp->queue, pd) {
             struct dp_packet packet;
             dp_packet_use_const(&packet, pd->pin.packet, pd->pin.packet_len);
 
             struct eth_header *eth = dp_packet_data(&packet);
             eth->eth_dst = mac;
-
-            ovs_list_push_back(&ctx->ready_packets_data, &pd->node);
         }
 
+        vector_push_array(&ctx->ready_packets_data,
+                          vector_get_array(&bp->queue),
+                          vector_len(&bp->queue));
+        vector_clear(&bp->queue);
         buffered_packets_remove(ctx, bp);
     }
 
@@ -679,7 +658,7 @@ buffered_packets_ctx_run(struct buffered_packets_ctx *ctx,
 
 bool
 buffered_packets_ctx_is_ready_to_send(struct buffered_packets_ctx *ctx) {
-    return !ovs_list_is_empty(&ctx->ready_packets_data);
+    return !vector_is_empty(&ctx->ready_packets_data);
 }
 
 bool
@@ -689,16 +668,17 @@ buffered_packets_ctx_has_packets(struct 
buffered_packets_ctx *ctx) {
 
 void
 buffered_packets_ctx_init(struct buffered_packets_ctx *ctx) {
+    ctx->ready_packets_data = VECTOR_EMPTY_INITIALIZER(struct bp_packet_data);
     hmap_init(&ctx->buffered_packets);
-    ovs_list_init(&ctx->ready_packets_data);
 }
 
 void
 buffered_packets_ctx_destroy(struct buffered_packets_ctx *ctx) {
     struct bp_packet_data *pd;
-    LIST_FOR_EACH_POP (pd, node, &ctx->ready_packets_data) {
+    VECTOR_FOR_EACH_PTR (&ctx->ready_packets_data, pd) {
         bp_packet_data_destroy(pd);
     }
+    vector_destroy(&ctx->ready_packets_data);
 
     struct buffered_packets *bp;
     HMAP_FOR_EACH_SAFE (bp, hmap_node, &ctx->buffered_packets) {
@@ -707,16 +687,6 @@ buffered_packets_ctx_destroy(struct buffered_packets_ctx 
*ctx) {
     hmap_destroy(&ctx->buffered_packets);
 }
 
-
-void
-mac_cache_stats_destroy(struct ovs_list *stats_list)
-{
-    struct mac_cache_stats *stats;
-    LIST_FOR_EACH_POP (stats, list_node, stats_list) {
-        free(stats);
-    }
-}
-
 static uint32_t
 mac_binding_data_hash(const struct mac_binding_data *mb_data)
 {
@@ -815,11 +785,12 @@ static void
 buffered_packets_remove(struct buffered_packets_ctx *ctx,
                         struct buffered_packets *bp) {
     struct bp_packet_data *pd;
-    LIST_FOR_EACH_POP (pd, node, &bp->queue) {
+    VECTOR_FOR_EACH_PTR (&bp->queue, pd) {
         bp_packet_data_destroy(pd);
     }
 
     hmap_remove(&ctx->buffered_packets, &bp->hmap_node);
+    vector_destroy(&bp->queue);
     free(bp);
 }
 
@@ -861,48 +832,49 @@ buffered_packets_db_lookup(struct buffered_packets *bp, 
struct ds *ip,
 
 void
 mac_binding_probe_stats_process_flow_stats(
-        struct ovs_list *stats_list,
+        struct vector *stats_vec,
         struct ofputil_flow_stats *ofp_stats)
 {
-    struct mac_cache_stats *stats = xmalloc(sizeof *stats);
-
-    stats->idle_age_ms = ofp_stats->idle_age * 1000;
-    stats->data.mb = (struct mac_binding_data) {
-        .cookie = ntohll(ofp_stats->cookie),
-        /* The port_key must be zero to match mac_binding_data_from_sbrec. */
-        .port_key = 0,
-        .dp_key = ntohll(ofp_stats->match.flow.metadata),
+    struct mac_cache_stats stats = (struct mac_cache_stats) {
+        .idle_age_ms = ofp_stats->idle_age * 1000,
+        .data.mb = (struct mac_binding_data) {
+            .cookie = ntohll(ofp_stats->cookie),
+            /* The port_key must be zero to match
+             * mac_binding_data_from_sbrec. */
+            .port_key = 0,
+            .dp_key = ntohll(ofp_stats->match.flow.metadata),
+            .mac = ofp_stats->match.flow.dl_src
+        },
     };
 
     if (ofp_stats->match.flow.regs[0]) {
-        stats->data.mb.ip =
+        stats.data.mb.ip =
             in6_addr_mapped_ipv4(htonl(ofp_stats->match.flow.regs[0]));
     } else {
         ovs_be128 ip6 = hton128(flow_get_xxreg(&ofp_stats->match.flow, 1));
-        memcpy(&stats->data.mb.ip, &ip6, sizeof stats->data.mb.ip);
+        memcpy(&stats.data.mb.ip, &ip6, sizeof stats.data.mb.ip);
     }
 
-    ovs_list_push_back(stats_list, &stats->list_node);
+    vector_push(stats_vec, &stats);
 }
 
 void
 mac_binding_probe_stats_run(
         struct rconn *swconn,
         struct ovsdb_idl_index *sbrec_port_binding_by_name,
-        struct ovs_list *stats_list,
+        struct vector *stats_vec,
         uint64_t *req_delay, void *data)
 {
     long long timewall_now = time_wall_msec();
     struct mac_cache_data *cache_data = data;
 
     struct mac_cache_stats *stats;
-    LIST_FOR_EACH_POP (stats, list_node, stats_list) {
+    VECTOR_FOR_EACH_PTR (stats_vec, stats) {
         struct mac_binding *mb = mac_binding_find(&cache_data->mac_bindings,
                                                   &stats->data.mb);
         if (!mb) {
             mac_binding_update_log("Probe: not found in the cache:",
                                    &stats->data.mb, false, NULL, 0, 0);
-            free(stats);
             continue;
         }
 
@@ -915,7 +887,6 @@ mac_binding_probe_stats_run(
             mac_binding_update_log("Not sending ARP/ND request for non-active",
                                    &mb->data, true, threshold,
                                    stats->idle_age_ms, since_updated_ms);
-            free(stats);
             continue;
         }
 
@@ -924,7 +895,6 @@ mac_binding_probe_stats_run(
                     "Not sending ARP/ND request for recently updated",
                     &mb->data, true, threshold, stats->idle_age_ms,
                     since_updated_ms);
-            free(stats);
             continue;
         }
 
@@ -932,13 +902,11 @@ mac_binding_probe_stats_run(
             lport_lookup_by_name(sbrec_port_binding_by_name,
                                  sbrec->logical_port);
         if (!pb) {
-            free(stats);
             continue;
         }
 
         struct lport_addresses laddr;
         if (!extract_lsp_addresses(pb->mac[0], &laddr)) {
-            free(stats);
             continue;
         }
 
@@ -960,7 +928,6 @@ mac_binding_probe_stats_run(
                                               OFTABLE_LOCAL_OUTPUT);
         }
 
-        free(stats);
         destroy_lport_addresses(&laddr);
     }
 
diff --git a/controller/mac-cache.h b/controller/mac-cache.h
index f5dbaf813..bdaec064b 100644
--- a/controller/mac-cache.h
+++ b/controller/mac-cache.h
@@ -28,6 +28,7 @@
 #include "ovn-sb-idl.h"
 
 struct ovsdb_idl_index;
+struct vector;
 
 struct mac_cache_data {
     /* 'struct mac_cache_threshold' by datapath's tunnel_key. */
@@ -89,9 +90,18 @@ struct fdb {
     long long timestamp;
 };
 
-struct bp_packet_data {
-    struct ovs_list node;
+struct mac_cache_stats {
+    int64_t idle_age_ms;
+
+    union {
+        /* Common data to identify MAC binding. */
+        struct mac_binding_data mb;
+        /* Common data to identify FDB. */
+        struct fdb_data fdb;
+    } data;
+};
 
+struct bp_packet_data {
     struct ofpbuf *continuation;
     struct ofputil_packet_in pin;
 };
@@ -102,7 +112,7 @@ struct buffered_packets {
     struct mac_binding_data mb_data;
 
     /* Queue of packet_data associated with this struct. */
-    struct ovs_list queue;
+    struct vector queue;
 
     /* Timestamp in ms when the buffered packet should expire. */
     long long int expire_at_ms;
@@ -115,7 +125,7 @@ struct buffered_packets_ctx {
     /* Map of all buffered packets waiting for the MAC address. */
     struct hmap buffered_packets;
     /* List of packet data that are ready to be sent. */
-    struct ovs_list ready_packets_data;
+    struct vector ready_packets_data;
 };
 
 /* Thresholds. */
@@ -177,30 +187,24 @@ void fdbs_clear(struct hmap *map);
 
 /* MAC binding stat processing. */
 void
-mac_binding_stats_process_flow_stats(struct ovs_list *stats_list,
+mac_binding_stats_process_flow_stats(struct vector *stats_vec,
                                      struct ofputil_flow_stats *ofp_stats);
 
 void mac_binding_stats_run(
         struct rconn *swconn OVS_UNUSED,
         struct ovsdb_idl_index *sbrec_port_binding_by_name OVS_UNUSED,
-        struct ovs_list *stats_list, uint64_t *req_delay, void *data);
+        struct vector *stats_vec, uint64_t *req_delay, void *data);
 
 /* FDB stat processing. */
-void fdb_stats_process_flow_stats(struct ovs_list *stats_list,
+void fdb_stats_process_flow_stats(struct vector *stats_vec,
                                   struct ofputil_flow_stats *ofp_stats);
 
 void fdb_stats_run(
         struct rconn *swconn OVS_UNUSED,
         struct ovsdb_idl_index *sbrec_port_binding_by_name OVS_UNUSED,
-        struct ovs_list *stats_list, uint64_t *req_delay, void *data);
-
-void mac_cache_stats_destroy(struct ovs_list *stats_list);
+        struct vector *stats_vec, uint64_t *req_delay, void *data);
 
 /* Packet buffering. */
-struct bp_packet_data *
-bp_packet_data_create(const struct ofputil_packet_in *pin,
-                      const struct ofpbuf *continuation);
-
 void bp_packet_data_destroy(struct bp_packet_data *pd);
 
 struct buffered_packets *
@@ -208,7 +212,8 @@ buffered_packets_add(struct buffered_packets_ctx *ctx,
                      struct mac_binding_data mb_data);
 
 void buffered_packets_packet_data_enqueue(struct buffered_packets *bp,
-                                          struct bp_packet_data *pd);
+                                          const struct ofputil_packet_in *pin,
+                                          const struct ofpbuf *continuation);
 
 void buffered_packets_ctx_run(struct buffered_packets_ctx *ctx,
                               const struct hmap *recent_mbs,
@@ -226,12 +231,12 @@ bool buffered_packets_ctx_is_ready_to_send(struct 
buffered_packets_ctx *ctx);
 bool buffered_packets_ctx_has_packets(struct buffered_packets_ctx *ctx);
 
 void mac_binding_probe_stats_process_flow_stats(
-        struct ovs_list *stats_list,
+        struct vector *stats_vec,
         struct ofputil_flow_stats *ofp_stats);
 
 void mac_binding_probe_stats_run(
         struct rconn *swconn,
         struct ovsdb_idl_index *sbrec_port_binding_by_name,
-        struct ovs_list *stats_list, uint64_t *req_delay, void *data);
+        struct vector *stats_vec, uint64_t *req_delay, void *data);
 
 #endif /* controller/mac-cache.h */
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 34fb2e6bf..0647f053d 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -1570,8 +1570,7 @@ OVS_REQUIRES(pinctrl_mutex)
         return;
     }
 
-    struct bp_packet_data *pd = bp_packet_data_create(pin, continuation);
-    buffered_packets_packet_data_enqueue(bp, pd);
+    buffered_packets_packet_data_enqueue(bp, pin, continuation);
 
     /* There is a chance that the MAC binding was already created. */
     notify_pinctrl_main();
@@ -4738,6 +4737,8 @@ pinctrl_handle_put_mac_binding(const struct flow *md,
     notify_pinctrl_main();
 }
 
+#define READY_PACKETS_VEC_CAPACITY_THRESHOLD 1024
+
 /* Called with in the pinctrl_handler thread context. */
 static void
 send_mac_binding_buffered_pkts(struct rconn *swconn)
@@ -4745,15 +4746,21 @@ send_mac_binding_buffered_pkts(struct rconn *swconn)
 {
     enum ofp_version version = rconn_get_version(swconn);
     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
+    struct vector *rpd = &buffered_packets_ctx.ready_packets_data;
 
     struct bp_packet_data *pd;
-    LIST_FOR_EACH_POP (pd, node, &buffered_packets_ctx.ready_packets_data) {
+    VECTOR_FOR_EACH_PTR (rpd, pd) {
         queue_msg(swconn, ofputil_encode_resume(&pd->pin, pd->continuation,
                                                 proto));
         bp_packet_data_destroy(pd);
     }
 
-    ovs_list_init(&buffered_packets_ctx.ready_packets_data);
+    vector_clear(rpd);
+    if (vector_capacity(rpd) >= READY_PACKETS_VEC_CAPACITY_THRESHOLD) {
+        VLOG_DBG("The ready_packets_data vector capacity (%"PRIuSIZE") "
+                 "is over threshold.", vector_capacity(rpd));
+        vector_shrink_to_fit(rpd);
+    }
 }
 
 /* Update or add an IP-MAC binding for 'logical_port'.
diff --git a/controller/statctrl.c b/controller/statctrl.c
index f0c5bd904..454314dda 100644
--- a/controller/statctrl.c
+++ b/controller/statctrl.c
@@ -19,6 +19,7 @@
 #include "dirs.h"
 #include "latch.h"
 #include "lflow.h"
+#include "lib/vec.h"
 #include "mac-cache.h"
 #include "openvswitch/ofp-errors.h"
 #include "openvswitch/ofp-flow.h"
@@ -37,6 +38,8 @@
 
 VLOG_DEFINE_THIS_MODULE(statctrl);
 
+#define STATS_VEC_CAPACITY_THRESHOLD 1024
+
 enum stat_type {
     STATS_MAC_BINDING = 0,
     STATS_FDB,
@@ -53,39 +56,33 @@ struct stats_node {
     int64_t next_request_timestamp;
     /* Request delay in ms. */
     uint64_t request_delay;
-    /* List of processed statistics. */
-    struct ovs_list stats_list;
-    /* Function to clean up the node.
-     * This function runs in main thread. */
-    void (*destroy)(struct ovs_list *stats_list);
+    /* Vector of processed statistics. */
+    struct vector stats;
     /* Function to process the response and store it in the list.
      * This function runs in statctrl thread locked behind mutex. */
-    void (*process_flow_stats)(struct ovs_list *stats_list,
+    void (*process_flow_stats)(struct vector *stats,
                                struct ofputil_flow_stats *ofp_stats);
     /* Function to process the parsed stats.
      * This function runs in main thread locked behind mutex. */
     void (*run)(struct rconn *swconn,
                 struct ovsdb_idl_index *sbrec_port_binding_by_name,
-                struct ovs_list *stats_list,
+                struct vector *stats,
                 uint64_t *req_delay, void *data);
-    /* Name of the stats node corresponding stopwatch. */
-    const char *stopwatch_name;
+    /* Name of the stats node. */
+    const char *name;
 };
 
-#define STATS_NODE(NAME, REQUEST, DESTROY, PROCESS, RUN)                   \
+#define STATS_NODE(NAME, REQUEST, STAT_TYPE, PROCESS, RUN)                 \
     do {                                                                   \
         statctrl_ctx.nodes[STATS_##NAME] = (struct stats_node) {           \
             .request = REQUEST,                                            \
             .xid = 0,                                                      \
             .next_request_timestamp = INT64_MAX,                           \
             .request_delay = 0,                                            \
-            .stats_list =                                                  \
-                OVS_LIST_INITIALIZER(                                      \
-                    &statctrl_ctx.nodes[STATS_##NAME].stats_list),         \
-            .destroy = DESTROY,                                            \
+            .stats = VECTOR_EMPTY_INITIALIZER(STAT_TYPE),                  \
             .process_flow_stats = PROCESS,                                 \
             .run = RUN,                                                    \
-            .stopwatch_name = OVS_STRINGIZE(stats_##NAME),                 \
+            .name = OVS_STRINGIZE(stats_##NAME),                 \
         };                                                                 \
         stopwatch_create(OVS_STRINGIZE(stats_##NAME), SW_MS);              \
     } while (0)
@@ -143,7 +140,7 @@ statctrl_init(void)
             .out_group = OFPG_ANY,
             .table_id = OFTABLE_MAC_CACHE_USE,
     };
-    STATS_NODE(MAC_BINDING, mac_binding_request, mac_cache_stats_destroy,
+    STATS_NODE(MAC_BINDING, mac_binding_request, struct mac_cache_stats,
                mac_binding_stats_process_flow_stats, mac_binding_stats_run);
 
     struct ofputil_flow_stats_request fdb_request = {
@@ -153,7 +150,7 @@ statctrl_init(void)
             .out_group = OFPG_ANY,
             .table_id = OFTABLE_LOOKUP_FDB,
     };
-    STATS_NODE(FDB, fdb_request, mac_cache_stats_destroy,
+    STATS_NODE(FDB, fdb_request, struct mac_cache_stats,
                fdb_stats_process_flow_stats, fdb_stats_run);
 
     struct ofputil_flow_stats_request mac_binding_probe_request = {
@@ -164,7 +161,7 @@ statctrl_init(void)
             .table_id = OFTABLE_MAC_BINDING,
     };
     STATS_NODE(MAC_BINDING_PROBE, mac_binding_probe_request,
-               mac_cache_stats_destroy,
+               struct mac_cache_stats,
                mac_binding_probe_stats_process_flow_stats,
                mac_binding_probe_stats_run);
 
@@ -196,11 +193,18 @@ statctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
         struct stats_node *node = &statctrl_ctx.nodes[i];
         uint64_t prev_delay = node->request_delay;
 
-        stopwatch_start(node->stopwatch_name, time_msec());
+        stopwatch_start(node->name, time_msec());
         node->run(statctrl_ctx.swconn,
-                  sbrec_port_binding_by_name, &node->stats_list,
+                  sbrec_port_binding_by_name, &node->stats,
                   &node->request_delay, node_data[i]);
-        stopwatch_stop(node->stopwatch_name, time_msec());
+        vector_clear(&node->stats);
+        if (vector_capacity(&node->stats) >= STATS_VEC_CAPACITY_THRESHOLD) {
+            VLOG_DBG("The statistics vector for node '%s' capacity "
+                     "(%"PRIuSIZE") is over threshold.", node->name,
+                     vector_capacity(&node->stats));
+            vector_shrink_to_fit(&node->stats);
+        }
+        stopwatch_stop(node->name, time_msec());
 
         schedule_updated |=
                 statctrl_update_next_request_timestamp(node, now, prev_delay);
@@ -233,7 +237,7 @@ statctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn)
     ovs_mutex_lock(&mutex);
     for (size_t i = 0; i < STATS_MAX; i++) {
         struct stats_node *node = &statctrl_ctx.nodes[i];
-        if (!ovs_list_is_empty(&node->stats_list)) {
+        if (!vector_is_empty(&node->stats)) {
             poll_immediate_wake();
         }
     }
@@ -254,7 +258,7 @@ statctrl_destroy(void)
 
     for (size_t i = 0; i < STATS_MAX; i++) {
         struct stats_node *node = &statctrl_ctx.nodes[i];
-        node->destroy(&node->stats_list);
+        vector_destroy(&node->stats);
     }
 }
 
@@ -364,7 +368,7 @@ statctrl_decode_statistics_reply(struct stats_node *node, 
struct ofpbuf *msg)
             break;
         }
 
-        node->process_flow_stats(&node->stats_list, &fs);
+        node->process_flow_stats(&node->stats, &fs);
     }
 
     ofpbuf_uninit(&ofpacts);
@@ -399,7 +403,7 @@ static void
 statctrl_notify_main_thread(struct statctrl_ctx *ctx)
 {
     for (size_t i = 0; i < STATS_MAX; i++) {
-        if (!ovs_list_is_empty(&ctx->nodes[i].stats_list)) {
+        if (!vector_is_empty(&ctx->nodes[i].stats)) {
             seq_change(ctx->main_seq);
             return;
         }
-- 
2.49.0

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to