summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-06-17 14:46:55 -0400
committerBen Gamari <ben@smart-cactus.org>2022-06-17 14:49:21 -0400
commit2aef370f387e2cfbb03b401052fff2c5b2397d67 (patch)
tree075b706c3305ceffc9c7f56285f4a039e4f2925a
parent8e31c947f56daee867d7ff7a6d62a0cae84cd37a (diff)
downloadhaskell-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.c45
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_.