On 7/10/23 22:20, Vladislav Odintsov wrote: > Hi Dumitru, > > thanks for digging into this! I highly appreciate your help! >
No worries, my pleasure! :) > Please, see my answers inline. > >> On 10 Jul 2023, at 15:28, Dumitru Ceara <dce...@redhat.com> wrote: >> >> On 7/10/23 12:57, Dumitru Ceara wrote: >>> On 7/6/23 13:00, Vladislav Odintsov wrote: >>>> >>>> >>>>> On 5 Jul 2023, at 20:07, Vladislav Odintsov <odiv...@gmail.com> wrote: >>>>> >>>>> Hi Dumitru, >>>>> >>>>> thanks for the quick response! >>>>> >>>>>> On 5 Jul 2023, at 19:53, Dumitru Ceara <dce...@redhat.com> wrote: >>>>>> >>>>>> On 7/5/23 17:14, Vladislav Odintsov wrote: >>>>>>> Hi, >>>>>>> >>>>>> >>>>>> Hi Vladislav, >>>>>> >>>>>>> we’ve noticed there is a huge ovn-controller memory consumption >>>>>>> introduced with [0] comparing to version without its changes in >>>>>>> ovn-controller.c part (just OVS submodule bump without ovn-controller >>>>>>> changes doesn’t trigger such behaviour). >>>>>>> >>>>>> >>>>>> Thanks for reporting this! >>>>>> >>>>>>> On an empty host connected to working cluster ovn-controller normally >>>>>>> consumes ~175 MiB RSS, and the same host updated to a version with >>>>>>> commit [0] consumes 3.3 GiB RSS. The start time and CPU consumption >>>>>>> during process start of an affected version is higher that for the >>>>>>> normal version. >>>>>>> >>>>>>> Before upgrade (normal functioning): >>>>>>> >>>>>>> #ovn-appctl -t ovn-controller memory/show ;ps-mem -p $(pidof >>>>>>> ovn-controller)| grep ovn >>>>>>> idl-cells-OVN_Southbound:343855 idl-cells-Open_vSwitch:14131 >>>>>>> ofctrl_desired_flow_usage-KB:76 ofctrl_installed_flow_usage-KB:60 >>>>>>> ofctrl_sb_flow_ref_usage-KB:18 >>>>>>> 174.2 MiB + 327.5 KiB = 174.5 MiB ovn-controller >>>>>>> >>>>>>> After upgrade to an affected version I’ve checked memory report while >>>>>>> ovn-controller was starting and at some time there was a bigger amount >>>>>>> of OVN_Southbound cells comparing to "after start" time: >>>>>>> >>>>>>> during start: >>>>>>> >>>>>>> # ovn-appctl -t ovn-controller memory/show ;ps-mem -p $(pidof >>>>>>> ovn-controller)| grep ovn >>>>>>> idl-cells-OVN_Southbound:11388742 idl-cells-Open_vSwitch:14131 >>>>>>> idl-outstanding-txns-Open_vSwitch:1 >>>>>>> 3.3 GiB + 327.0 KiB = 3.3 GiB ovn-controller >>>>>>> >>>>>>> after start: >>>>>>> >>>>>>> # ovn-appctl -t ovn-controller memory/show ;ps-mem -p $(pidof >>>>>>> ovn-controller)| grep ovn >>>>>>> idl-cells-OVN_Southbound:343896 idl-cells-Open_vSwitch:14131 >>>>>>> idl-outstanding-txns-Open_vSwitch:1 >>>>>>> 3.3 GiB + 327.0 KiB = 3.3 GiB ovn-controller >>>>>>> >>>>>>> >>>>>>> cells during start: >>>>>>> 11388742 >>>>>>> >>>>>>> cells after start: >>>>>>> 343896 >>>>>>> >>>>>> >>>>>> Are you running with ovn-monitor-all=true on this host? >>>>> >>>>> No, it has default false. >>>>> >>>>>> >>>>>> I guess it's unlikely but I'll try just in case: would it be possible to >>>>>> share the SB database? >>>>> >>>>> Unfortunately, no. But I can say it’s about 450 M in size after >>>>> compaction. And there are about 1M mac_bindings if it’s important :). >>>> >>> >>> I tried in a sandbox, before and after the commit in question, with a >>> script that adds 1M mac bindings on top of the sample topology built by >>> tutorial/ovn-setup.sh. >>> >>> I see ovn-controller memory usage going to >3GB in before the commit you >>> blamed and to >1.9GB after the same commit. So it looks different than >>> what you reported but still worrying that we use so much memory for mac >>> bindings. >>> >>> I'm assuming however that quite a few of the 1M mac bindings in your >>> setup are stale so would it be possible to enable mac_binding aging? It >>> needs to be enabled per router with something like: >>> >>> $ ovn-nbctl set logical_router RTR options:mac_binding_age_threshold=60 >>> >>> The threshold is in seconds and is a hard limit (for now) after which a >>> mac binding entry is removed. There's work in progress to only clear >>> arp cache entries that are really stale [1]. > > Yeah, I know about mac_binding ageing, but we currently use our own mechanism > to delete excess records and waiting for patchset you’ve mentioned. > Ack. >>> >>>> But if you are interested in any specific information, let me know it, I >>>> can check. >>>> >>> >>> How many "local" datapaths do we have on the hosts that exhibit high >>> memory usage? >>> >>> The quickest way I can think of to get this info is to run this on the >>> hypervisor: >>> $ ovn-appctl ct-zone-list | grep snat -c >>> >>> Additional question: how many mac_bindings are "local", i.e., associated >>> to local datapaths? > > For both questions: 0. > OK, that really suggests that malloc_trim() didn't get called. There's really no reason (especially with ovn-monitor-all=false) to have such a high memory usage in ovn-controller if there's no local datapath. >>> >>>>> >>>>>> >>>>>>> I guess it could be connected with this problem. Can anyone look at >>>>>>> this and comment please? >>>>>>> >>>>>> >>>>>> Does the memory usage persist after SB is upgraded too? I see the >>>>>> number of SB idl-cells goes down eventually which means that eventually >>>>>> the periodic malloc_trim() call would free up memory. We trim on idle >>>>>> since >>>>>> https://github.com/ovn-org/ovn/commit/b4c593d23bd959e98fcc9ada4a973ac933579ded >>>>>> >>>>> >>>>> In this upgrade DB schemas not upgraded, so they’re up to date. >>>>> >>>>>> Are you using a different allocator? E.g., jemalloc. >>>>> >>>>> No, this issue reproduces with gcc. >>>>> >>> >>> Can we run a test and see if malloc_trim() was actually called? I'd >>> first disable lflow-cache log rate limiting: >>> >>> $ ovn-appctl vlog/disable-rate-limit lflow_cache >>> >>> Then check if malloc_trim() was called after the lflow-cache detected >>> inactivity. You'd see logs like: >>> >>> "lflow_cache|INFO|Detected cache inactivity (last active 30005 ms ago): >>> trimming cache" >>> >>> The fact that the number of SB idl-cells goes down and memory doesn't >>> seems to indicate we might have a bug in the auto cache trimming mechanism. >>> >>> In any case, a malloc_trim() can be manually triggered by flushing the >>> lflow cache: >>> >>> $ ovn-appctl lflow-cache/flush > > Wow, all the excess memory was released. Memory consumption by ovn-controller > process decreased from 3.3GiB to ~275MiB. > >>> >>> Thanks, >>> Dumitru >>> >>>>>> >>>>>>> >>>>>>> 0: >>>>>>> https://github.com/ovn-org/ovn/commit/1b0dbde940706e5de6e60221be78a278361fa76d >>> >>> [1] https://patchwork.ozlabs.org/project/ovn/list/?series=359894&state=* >>> >> >> I think I spotted an issue with the auto-trimming mechanism if the flows >> we're removing are not in the lflow cache (I think that's the case for >> the mac binding ones). Would it be possible to try out the following >> quick'n'dirty patch that should trigger trimming more often? > > Thanks for the patch, I’ll try it tomorrow! > Thanks, I'll wait for confirmation before preparing a formal patch. Regards, Dumitru >> >> Thanks! >> >> diff --git a/controller/lflow-cache.c b/controller/lflow-cache.c >> index f723eab8a0..1a23e133ae 100644 >> --- a/controller/lflow-cache.c >> +++ b/controller/lflow-cache.c >> @@ -24,7 +24,6 @@ >> #include "coverage.h" >> #include "lflow-cache.h" >> #include "lib/uuid.h" >> -#include "memory-trim.h" >> #include "openvswitch/vlog.h" >> #include "ovn/expr.h" >> >> @@ -83,14 +82,14 @@ static void lflow_cache_delete__(struct lflow_cache *lc, >> static void lflow_cache_trim__(struct lflow_cache *lc, bool force); >> >> struct lflow_cache * >> -lflow_cache_create(void) >> +lflow_cache_create(struct memory_trimmer *mt) >> { >> struct lflow_cache *lc = xzalloc(sizeof *lc); >> >> for (size_t i = 0; i < LCACHE_T_MAX; i++) { >> hmap_init(&lc->entries[i]); >> } >> - lc->mt = memory_trimmer_create(); >> + lc->mt = mt; >> >> return lc; >> } >> @@ -124,7 +123,6 @@ 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); >> } >> >> diff --git a/controller/lflow-cache.h b/controller/lflow-cache.h >> index 300a560770..07e017e25e 100644 >> --- a/controller/lflow-cache.h >> +++ b/controller/lflow-cache.h >> @@ -21,6 +21,7 @@ >> #include "openvswitch/dynamic-string.h" >> #include "openvswitch/hmap.h" >> #include "openvswitch/uuid.h" >> +#include "memory-trim.h" >> #include "simap.h" >> >> struct lflow_cache; >> @@ -56,7 +57,7 @@ struct lflow_cache_value { >> }; >> }; >> >> -struct lflow_cache *lflow_cache_create(void); >> +struct lflow_cache *lflow_cache_create(struct memory_trimmer *); >> void lflow_cache_flush(struct lflow_cache *); >> void lflow_cache_destroy(struct lflow_cache *); >> void lflow_cache_enable(struct lflow_cache *, bool enabled, uint32_t >> capacity, >> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c >> index 96d01219e1..89ff37e747 100644 >> --- a/controller/ovn-controller.c >> +++ b/controller/ovn-controller.c >> @@ -5057,8 +5057,9 @@ main(int argc, char *argv[]) >> unsigned int ovnsb_cond_seqno = UINT_MAX; >> unsigned int ovnsb_expected_cond_seqno = UINT_MAX; >> >> + struct memory_trimmer *mt = memory_trimmer_create(); >> struct controller_engine_ctx ctrl_engine_ctx = { >> - .lflow_cache = lflow_cache_create(), >> + .lflow_cache = lflow_cache_create(mt), >> .if_mgr = if_status_mgr_create(), >> }; >> struct if_status_mgr *if_mgr = ctrl_engine_ctx.if_mgr; >> @@ -5447,6 +5448,10 @@ main(int argc, char *argv[]) >> engine_set_force_recompute(false); >> } >> >> + if (engine_has_updated()) { >> + memory_trimmer_record_activity(mt); >> + } >> + >> store_nb_cfg(ovnsb_idl_txn, ovs_idl_txn, chassis_private, >> br_int, delay_nb_cfg_report); >> >> @@ -5552,6 +5557,7 @@ loop_done: >> } >> } >> >> + memory_trimmer_destroy(mt); >> engine_set_context(NULL); >> engine_cleanup(); >> >> diff --git a/controller/test-lflow-cache.c b/controller/test-lflow-cache.c >> index 7ce9993605..1a73b8aad7 100644 >> --- a/controller/test-lflow-cache.c >> +++ b/controller/test-lflow-cache.c >> @@ -108,7 +108,8 @@ test_lflow_cache_stats__(struct lflow_cache *lc) >> static void >> test_lflow_cache_operations(struct ovs_cmdl_context *ctx) >> { >> - struct lflow_cache *lc = lflow_cache_create(); >> + struct memory_trimmer *mt = memory_trimmer_create(); >> + struct lflow_cache *lc = lflow_cache_create(mt); >> struct expr *e = expr_create_boolean(true); >> bool enabled = !strcmp(ctx->argv[1], "true"); >> struct uuid *lflow_uuids = NULL; >> @@ -235,6 +236,7 @@ test_lflow_cache_operations(struct ovs_cmdl_context *ctx) >> test_lflow_cache_stats__(lc); >> } >> done: >> + memory_trimmer_destroy(mt); >> lflow_cache_destroy(lc); >> free(lflow_uuids); >> expr_destroy(e); >> @@ -259,7 +261,7 @@ test_lflow_cache_negative(struct ovs_cmdl_context *ctx >> OVS_UNUSED) >> >> struct lflow_cache *lcs[] = { >> NULL, >> - lflow_cache_create(), >> + lflow_cache_create(memory_trimmer_create()), >> }; >> >> for (size_t i = 0; i < ARRAY_SIZE(lcs); i++) { > > > Regards, > Vladislav Odintsov > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev