diff options
author | Ben Gamari <ben@smart-cactus.org> | 2022-06-17 14:46:55 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2022-06-17 14:49:21 -0400 |
commit | 2aef370f387e2cfbb03b401052fff2c5b2397d67 (patch) | |
tree | 075b706c3305ceffc9c7f56285f4a039e4f2925a | |
parent | 8e31c947f56daee867d7ff7a6d62a0cae84cd37a (diff) | |
download | haskell-wip/ghc-9.2-fb-linker.tar.gz |
rts/CheckUnload: optimize time required to clean up cost centreswip/ghc-9.2-fb-linker
Right now because we traverse the CC_LIST for every object we are about
to unload, it may take a long time to `:load` in haxlsh. Loading the
exact same modules may take up to 40s because of that. With this
optimization, loading the exact same modules would only take ~22s, which
is the expected time required to rebuild the dependency graph.
Test Plan:
- `tp2_build`
- `tp2_use_local ghc`
- `buck run @mode/opt sigma/haxl/haxlsh:haxlsh` and verifies that
loading time is much better
- also added diagnostics print and verified that the time required to
gcCostCentres were almost instant (before the fix, it took seconds).
The code with the diagnostics print can be seen here P120395039
-rw-r--r-- | rts/CheckUnload.c | 45 |
1 files changed, 14 insertions, 31 deletions
diff --git a/rts/CheckUnload.c b/rts/CheckUnload.c index 91af500990..668b70b45d 100644 --- a/rts/CheckUnload.c +++ b/rts/CheckUnload.c @@ -495,36 +495,17 @@ gcCostCentreStacks (CostCentreStack *ccs) } } -static bool objectContains (ObjectCode *oc, const void *addr) -{ - int i; - - if (oc != NULL) { - for (i = 0; i < oc->n_sections; i++) { - if (oc->sections[i].kind != SECTIONKIND_OTHER) { - if ((W_)addr >= (W_)oc->sections[i].start && - (W_)addr < (W_)oc->sections[i].start - + oc->sections[i].size) { - return true; - } - } - } - } - - return false; -} - -// -// Remove all CostCentres which are statically allocated in the given object -// from the global CC_LIST. -// -static void gcCostCentres(ObjectCode *oc) +// Remove from the global CC_LIST all CostCentres which are statically +// allocated in an unloaded object that we are about to free in this GC cycle. +static void gcCostCentres(OCSectionIndices *s_indices) { CostCentre *cc, *prev, *next; + ObjectCode *oc; prev = NULL; for (cc = CC_LIST; cc != NULL; cc = next) { next = cc->link; - if (objectContains(oc, cc)) { + oc = findOC(s_indices, cc); + if (oc != NULL && oc->mark == 0) { if (prev == NULL) { CC_LIST = cc->link; } else { @@ -556,18 +537,20 @@ void checkUnload() markObjectLive(NULL, (W_)oc, NULL); } +#if defined(PROFILING) + // At this point, we know what object should be unloaded based on the + // referenced field in its metadata ObjetCode* struct. Thus, we can + // traverse CC_LIST to prune CCs that belong to one of the unloaded + // objects. + gcCostCentres(s_indices); +#endif + // Free unmarked objects ObjectCode *next = NULL; for (ObjectCode *oc = old_objects; oc != NULL; oc = next) { next = oc->next; ASSERT(oc->status == OBJECT_UNLOADED); -#if defined(PROFILING) - // The CCS tree isn't keeping this object alive, and it is unloaded, - // so we can prune the global CC_LIST of any CCs from this object. - gcCostCentres(oc); -#endif - removeOCSectionIndices(s_indices, oc); // Symbols should be removed by unloadObj_. |