Hi Dumitru, just one small comment below. On Thu, Dec 15, 2022 at 10:29 PM Dumitru Ceara <dce...@redhat.com> wrote:
> To do this we factor the memory trimming code out into its own module, > memory-trim. We use this now for both the lflow cache (in > ovn-controller) and for ovn-northd. > > Signed-off-by: Dumitru Ceara <dce...@redhat.com> > --- > controller/lflow-cache.c | 68 +++++--------------------- > lib/automake.mk | 2 + > lib/memory-trim.c | 120 > ++++++++++++++++++++++++++++++++++++++++++++++ > lib/memory-trim.h | 33 +++++++++++++ > northd/inc-proc-northd.c | 4 +- > northd/inc-proc-northd.h | 2 - > northd/ovn-northd.c | 33 ++++++++++++- > ovn-nb.xml | 9 +++ > 8 files changed, 212 insertions(+), 59 deletions(-) > create mode 100644 lib/memory-trim.c > create mode 100644 lib/memory-trim.h > > diff --git a/controller/lflow-cache.c b/controller/lflow-cache.c > index 9fca2d7441..9d0e9cd10b 100644 > --- a/controller/lflow-cache.c > +++ b/controller/lflow-cache.c > @@ -24,10 +24,9 @@ > #include "coverage.h" > #include "lflow-cache.h" > #include "lib/uuid.h" > -#include "openvswitch/poll-loop.h" > +#include "memory-trim.h" > #include "openvswitch/vlog.h" > #include "ovn/expr.h" > -#include "timeval.h" > > VLOG_DEFINE_THIS_MODULE(lflow_cache); > > @@ -54,6 +53,7 @@ static struct vlog_rate_limit rl = > VLOG_RATE_LIMIT_INIT(5, 1); > > struct lflow_cache { > struct hmap entries[LCACHE_T_MAX]; > + struct memory_trimmer *mt; > uint32_t n_entries; > uint32_t high_watermark; > uint32_t capacity; > @@ -61,10 +61,7 @@ struct lflow_cache { > uint64_t max_mem_usage; > uint32_t trim_limit; > uint32_t trim_wmark_perc; > - uint32_t trim_timeout_ms; > uint64_t trim_count; > - long long int last_active_ms; > - bool recently_active; > bool enabled; > }; > > @@ -84,7 +81,6 @@ static struct lflow_cache_value *lflow_cache_add__( > static void lflow_cache_delete__(struct lflow_cache *lc, > struct lflow_cache_entry *lce); > static void lflow_cache_trim__(struct lflow_cache *lc, bool force); > -static void lflow_cache_record_activity__(struct lflow_cache *lc); > > struct lflow_cache * > lflow_cache_create(void) > @@ -94,6 +90,7 @@ lflow_cache_create(void) > for (size_t i = 0; i < LCACHE_T_MAX; i++) { > hmap_init(&lc->entries[i]); > } > + lc->mt = memory_trimmer_create(); > > return lc; > } > @@ -127,6 +124,7 @@ lflow_cache_destroy(struct lflow_cache *lc) > for (size_t i = 0; i < LCACHE_T_MAX; i++) { > hmap_destroy(&lc->entries[i]); > } > + memory_trimmer_destroy(lc->mt); > free(lc); > } > > @@ -146,13 +144,6 @@ lflow_cache_enable(struct lflow_cache *lc, bool > enabled, uint32_t capacity, > trim_wmark_perc = 100; > } > > - if (trim_timeout_ms < 1000) { > - VLOG_WARN_RL(&rl, "Invalid requested trim timeout: " > - "requested %"PRIu32" ms, using 1000 ms instead", > - trim_timeout_ms); > - trim_timeout_ms = 1000; > - } > - > uint64_t max_mem_usage = max_mem_usage_kb * 1024; > bool need_flush = false; > bool need_trim = false; > @@ -172,13 +163,13 @@ lflow_cache_enable(struct lflow_cache *lc, bool > enabled, uint32_t capacity, > lc->max_mem_usage = max_mem_usage; > lc->trim_limit = lflow_trim_limit; > lc->trim_wmark_perc = trim_wmark_perc; > - lc->trim_timeout_ms = trim_timeout_ms; > + memory_trimmer_set(lc->mt, trim_timeout_ms); > > if (need_flush) { > - lflow_cache_record_activity__(lc); > + memory_trimmer_record_activity(lc->mt); > lflow_cache_flush(lc); > } else if (need_trim) { > - lflow_cache_record_activity__(lc); > + memory_trimmer_record_activity(lc->mt); > lflow_cache_trim__(lc, false); > } > } > @@ -286,7 +277,7 @@ lflow_cache_delete(struct lflow_cache *lc, const > struct uuid *lflow_uuid) > lflow_cache_delete__(lc, CONTAINER_OF(lcv, struct > lflow_cache_entry, > value)); > lflow_cache_trim__(lc, false); > - lflow_cache_record_activity__(lc); > + memory_trimmer_record_activity(lc->mt); > } > } > > @@ -327,41 +318,15 @@ lflow_cache_get_memory_usage(const struct > lflow_cache *lc, struct simap *usage) > void > lflow_cache_run(struct lflow_cache *lc) > { > - if (!lc->recently_active) { > - return; > - } > - > - long long int now = time_msec(); > - if (now < lc->last_active_ms || now < lc->trim_timeout_ms) { > - VLOG_WARN_RL(&rl, "Detected cache last active timestamp > overflow"); > - lc->recently_active = false; > - lflow_cache_trim__(lc, true); > - return; > - } > - > - if (now < lc->trim_timeout_ms) { > - VLOG_WARN_RL(&rl, "Detected very large trim timeout: " > - "now %lld ms timeout %"PRIu32" ms", > - now, lc->trim_timeout_ms); > - return; > - } > - > - if (now - lc->trim_timeout_ms >= lc->last_active_ms) { > - VLOG_INFO_RL(&rl, "Detected cache inactivity " > - "(last active %lld ms ago): trimming cache", > - now - lc->last_active_ms); > + if (memory_trimmer_run(lc->mt)) { > lflow_cache_trim__(lc, true); > - lc->recently_active = false; > } > } > > void > lflow_cache_wait(struct lflow_cache *lc) > { > - if (!lc->recently_active) { > - return; > - } > - poll_timer_wait_until(lc->last_active_ms + lc->trim_timeout_ms); > + memory_trimmer_wait(lc->mt); > } > > static struct lflow_cache_value * > @@ -388,7 +353,7 @@ lflow_cache_add__(struct lflow_cache *lc, const struct > uuid *lflow_uuid, > } > } > > - lflow_cache_record_activity__(lc); > + memory_trimmer_record_activity(lc->mt); > lc->mem_usage += size; > > COVERAGE_INC(lflow_cache_add); > @@ -447,17 +412,8 @@ lflow_cache_trim__(struct lflow_cache *lc, bool force) > hmap_shrink(&lc->entries[i]); > } > > -#if HAVE_DECL_MALLOC_TRIM > - malloc_trim(0); > -#endif > + memory_trimmer_trim(lc->mt); > > lc->high_watermark = lc->n_entries; > lc->trim_count++; > } > - > -static void > -lflow_cache_record_activity__(struct lflow_cache *lc) > -{ > - lc->last_active_ms = time_msec(); > - lc->recently_active = true; > -} > diff --git a/lib/automake.mk b/lib/automake.mk > index 15d4f84bbb..b69e854b0b 100644 > --- a/lib/automake.mk > +++ b/lib/automake.mk > @@ -30,6 +30,8 @@ lib_libovn_la_SOURCES = \ > lib/mac-binding-index.h \ > lib/mcast-group-index.c \ > lib/mcast-group-index.h \ > + lib/memory-trim.c \ > + lib/memory-trim.h \ > lib/lex.c \ > lib/objdep.c \ > lib/objdep.h \ > diff --git a/lib/memory-trim.c b/lib/memory-trim.c > new file mode 100644 > index 0000000000..a6791073ee > --- /dev/null > +++ b/lib/memory-trim.c > @@ -0,0 +1,120 @@ > +/* > + * Copyright (c) 2022, Red Hat, Inc. > + * > + * 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> > + > +#if HAVE_DECL_MALLOC_TRIM > +#include <malloc.h> > +#endif > + > +#include "memory-trim.h" > + > +#include "openvswitch/poll-loop.h" > +#include "openvswitch/vlog.h" > +#include "timeval.h" > + > +VLOG_DEFINE_THIS_MODULE(memory_trim); > + > +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > + > +struct memory_trimmer { > + uint32_t trim_timeout_ms; > + long long int last_active_ms; > + bool recently_active; > +}; > + > +struct memory_trimmer * > +memory_trimmer_create(void) > +{ > + struct memory_trimmer *mt = xzalloc(sizeof *mt); > + return mt; > +} > + > +void > +memory_trimmer_destroy(struct memory_trimmer *mt) > +{ > + free(mt); > +} > + > +void > +memory_trimmer_set(struct memory_trimmer *mt, uint32_t trim_timeout_ms) > +{ > + if (trim_timeout_ms < 1000) { > + VLOG_WARN_RL(&rl, "Invalid requested trim timeout: " > + "requested %"PRIu32" ms, using 1000 ms instead", > + trim_timeout_ms); > + trim_timeout_ms = 1000; > + } > + mt->trim_timeout_ms = trim_timeout_ms; > +} > + > +/* Returns true if trimming due to inactivity should happen. */ > +bool > +memory_trimmer_run(struct memory_trimmer *mt) > IMO this name does not really reflect what the function does. I would suggest changing it to memory_trimmer_should_run/memory_trimmer_can_run. Something along those lines so it is clear that this function does not trim anything. > +{ > + if (!mt->recently_active) { > + return false; > + } > + > + long long int now = time_msec(); > + if (now < mt->last_active_ms || now < mt->trim_timeout_ms) { > + VLOG_WARN_RL(&rl, "Detected last active timestamp overflow"); > + mt->recently_active = false; > + return true; > + } > + > + if (now < mt->trim_timeout_ms) { > + VLOG_WARN_RL(&rl, "Detected very large trim timeout: " > + "now %lld ms timeout %"PRIu32" ms", > + now, mt->trim_timeout_ms); > + return false; > + } > + > + if (now - mt->trim_timeout_ms >= mt->last_active_ms) { > + VLOG_INFO_RL(&rl, "Detected inactivity " > + "(last active %lld ms ago): trimming memory", > + now - mt->last_active_ms); > + mt->recently_active = false; > + return true; > + } > + > + return false; > +} > + > +void > +memory_trimmer_wait(struct memory_trimmer *mt) > +{ > + if (!mt->recently_active) { > + return; > + } > + poll_timer_wait_until(mt->last_active_ms + mt->trim_timeout_ms); > +} > + > +void > +memory_trimmer_trim(struct memory_trimmer *mt OVS_UNUSED) > +{ > +#if HAVE_DECL_MALLOC_TRIM > + malloc_trim(0); > +#endif > +} > + > +void > +memory_trimmer_record_activity(struct memory_trimmer *mt) > +{ > + mt->last_active_ms = time_msec(); > + mt->recently_active = true; > +} > diff --git a/lib/memory-trim.h b/lib/memory-trim.h > new file mode 100644 > index 0000000000..2bf30292f0 > --- /dev/null > +++ b/lib/memory-trim.h > @@ -0,0 +1,33 @@ > +/* > + * Copyright (c) 2022, Red Hat, Inc. > + * > + * 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. > + */ > + > +#ifndef MEMORY_TRIM_H > +#define MEMORY_TRIM_H 1 > + > +#include <stdbool.h> > +#include <stdint.h> > + > +struct memory_trimmer; > + > +struct memory_trimmer *memory_trimmer_create(void); > +void memory_trimmer_destroy(struct memory_trimmer *); > +void memory_trimmer_set(struct memory_trimmer *, uint32_t > trim_timeout_ms); > +bool memory_trimmer_run(struct memory_trimmer *); > +void memory_trimmer_wait(struct memory_trimmer *); > +void memory_trimmer_trim(struct memory_trimmer *); > +void memory_trimmer_record_activity(struct memory_trimmer *); > + > +#endif /* lib/memory-trim.h */ > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c > index 363e384bd1..d23993a551 100644 > --- a/northd/inc-proc-northd.c > +++ b/northd/inc-proc-northd.c > @@ -308,7 +308,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > sbrec_address_set_by_name); > } > > -void inc_proc_northd_run(struct ovsdb_idl_txn *ovnnb_txn, > +/* Returns true if the incremental processing ended up updating nodes. */ > +bool inc_proc_northd_run(struct ovsdb_idl_txn *ovnnb_txn, > struct ovsdb_idl_txn *ovnsb_txn, > bool recompute) { > engine_init_run(); > @@ -347,6 +348,7 @@ void inc_proc_northd_run(struct ovsdb_idl_txn > *ovnnb_txn, > } else { > engine_set_force_recompute(false); > } > + return engine_has_updated(); > } > > void inc_proc_northd_cleanup(void) > diff --git a/northd/inc-proc-northd.h b/northd/inc-proc-northd.h > index 1300253791..9b81c7ee03 100644 > --- a/northd/inc-proc-northd.h > +++ b/northd/inc-proc-northd.h > @@ -8,7 +8,7 @@ > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > struct ovsdb_idl_loop *sb); > -void inc_proc_northd_run(struct ovsdb_idl_txn *ovnnb_txn, > +bool inc_proc_northd_run(struct ovsdb_idl_txn *ovnnb_txn, > struct ovsdb_idl_txn *ovnsb_txn, > bool recompute); > void inc_proc_northd_cleanup(void); > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c > index 3a575b02a5..081081f9e4 100644 > --- a/northd/ovn-northd.c > +++ b/northd/ovn-northd.c > @@ -25,6 +25,7 @@ > #include "inc-proc-northd.h" > #include "lib/ip-mcast-index.h" > #include "lib/mcast-group-index.h" > +#include "lib/memory-trim.h" > #include "memory.h" > #include "northd.h" > #include "ovs-numa.h" > @@ -727,6 +728,34 @@ run_idl_loop(struct ovsdb_idl_loop *idl_loop, const > char *name) > return txn; > } > > +#define DEFAULT_NORTHD_TRIM_TO_MS 30000 > + > +static void > +run_memory_trimmer(struct ovsdb_idl *ovnnb_idl, bool activity) > +{ > + static struct memory_trimmer *mt = NULL; > + > + if (!mt) { > + mt = memory_trimmer_create(); > + } > + > + const struct nbrec_nb_global *nb = nbrec_nb_global_first(ovnnb_idl); > + if (nb) { > + memory_trimmer_set(mt, smap_get_uint(&nb->options, > + "northd_trim_timeout", > + DEFAULT_NORTHD_TRIM_TO_MS)); > + } > + > + if (activity) { > + memory_trimmer_record_activity(mt); > + } > + > + if (memory_trimmer_run(mt)) { > + memory_trimmer_trim(mt); > + } > + memory_trimmer_wait(mt); > +} > + > int > main(int argc, char *argv[]) > { > @@ -905,7 +934,8 @@ main(int argc, char *argv[]) > > if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) { > int64_t loop_start_time = time_wall_msec(); > - inc_proc_northd_run(ovnnb_txn, ovnsb_txn, recompute); > + bool activity = inc_proc_northd_run(ovnnb_txn, ovnsb_txn, > + recompute); > recompute = false; > if (ovnsb_txn) { > check_and_add_supported_dhcp_opts_to_sb_db( > @@ -937,6 +967,7 @@ main(int argc, char *argv[]) > "force recompute next time."); > recompute = true; > } > + run_memory_trimmer(ovnnb_idl_loop.idl, activity); > } else { > /* Make sure we send any pending requests, e.g., lock. */ > ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop); > diff --git a/ovn-nb.xml b/ovn-nb.xml > index 4cceef14e0..d14d83dec0 100644 > --- a/ovn-nb.xml > +++ b/ovn-nb.xml > @@ -202,6 +202,15 @@ > </p> > </column> > > + <column name="options" key="northd_trim_timeout"> > + <p> > + When used, this configuration value specifies the time, in > + milliseconds, since the last <code>ovn-northd</code> active > operation > + after which memory trimming is performed. By default this is > set to > + 30000 (30 seconds). > + </p> > + </column> > + > <column name="options" key="use_logical_dp_groups"> > <p> > Note: This option is deprecated, the only behavior is to always > > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > With that comment addressed: Acked-by: Ales Musil <amu...@redhat.com> Thanks, Ales -- Ales Musil Senior Software Engineer - OVN Core Red Hat EMEA <https://www.redhat.com> amu...@redhat.com IM: amusil <https://red.ht/sig> _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev