diff options
author | Simon Marlow <simonmar@microsoft.com> | 2006-11-21 13:45:51 +0000 |
---|---|---|
committer | Simon Marlow <simonmar@microsoft.com> | 2006-11-21 13:45:51 +0000 |
commit | fec956d14d1cbad5a28a1cad7c7d5c0859136f69 (patch) | |
tree | bc8b4d24b43d1b1b1f58136f019299c0f61e5efc /rts/sm | |
parent | 2b49cf43578194443e0481b4680c3542c3d31bff (diff) | |
download | haskell-fec956d14d1cbad5a28a1cad7c7d5c0859136f69.tar.gz |
optimisation to freeGroup() to avoid an O(N^2) pathalogical case
In the free list, we don't strictly speaking need to have every block
in a coalesced group point to the head block, although this is an
invariant for non-free blocks. Dropping this invariant for the free
list means that coalesce() is O(1) rather than O(N), and freeGroup()
is therefore O(N) not O(N^2).
The bad case probably didn't happen most of the time, indeed it has
never shown up in a profile that I've seen. I had a report from a
while back that this was a problem with really large heaps, though.
Fortunately the fix is easy.
Diffstat (limited to 'rts/sm')
-rw-r--r-- | rts/sm/BlockAlloc.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/rts/sm/BlockAlloc.c b/rts/sm/BlockAlloc.c index d2f08eeb62..1149260026 100644 --- a/rts/sm/BlockAlloc.c +++ b/rts/sm/BlockAlloc.c @@ -80,10 +80,7 @@ allocGroup(nat n) for (bd = free_list; bd != NULL; bd = bd->link) { if (bd->blocks == n) { /* exactly the right size! */ *last = bd->link; - /* no initialisation necessary - this is already a - * self-contained block group. */ - bd->free = bd->start; /* block isn't free now */ - bd->link = NULL; + initGroup(n, bd); /* initialise it */ return bd; } if (bd->blocks > n) { /* block too big... */ @@ -219,20 +216,26 @@ allocMegaGroup(nat n) STATIC_INLINE bdescr * coalesce(bdescr *p) { - bdescr *bd, *q; - nat i, blocks; + bdescr *q; q = p->link; if (q != NULL && p->start + p->blocks * BLOCK_SIZE_W == q->start) { /* can coalesce */ p->blocks += q->blocks; p->link = q->link; - blocks = q->blocks; - for (i = 0, bd = q; i < blocks; bd++, i++) { - bd->free = 0; - bd->blocks = 0; - bd->link = p; +#ifdef DEBUG + { + nat i, blocks; + bdescr *bd; + // not strictly necessary to do this, but helpful if we have a + // random ptr and want to figure out what block it belongs to. + for (i = 0, bd = q; i < q->blocks; bd++, i++) { + bd->free = 0; + bd->blocks = 0; + bd->link = p; + } } +#endif return p; } return q; |