[project @ 2003-09-23 15:38:35 by simonmar]
[ghc-hetmet.git] / ghc / rts / Storage.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Storage.c,v 1.80 2003/09/23 15:38:36 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Storage manager front end
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11 #include "Rts.h"
12 #include "RtsUtils.h"
13 #include "RtsFlags.h"
14 #include "Stats.h"
15 #include "Hooks.h"
16 #include "BlockAlloc.h"
17 #include "MBlock.h"
18 #include "Weak.h"
19 #include "Sanity.h"
20 #include "Arena.h"
21
22 #include "Storage.h"
23 #include "Schedule.h"
24 #include "OSThreads.h"
25 #include "StoragePriv.h"
26
27 #include "RetainerProfile.h"    // for counting memory blocks (memInventory)
28
29 #include <stdlib.h>
30 #include <string.h>
31
32 StgClosure    *caf_list         = NULL;
33
34 bdescr *small_alloc_list;       /* allocate()d small objects */
35 bdescr *pinned_object_block;    /* allocate pinned objects into this block */
36 nat alloc_blocks;               /* number of allocate()d blocks since GC */
37 nat alloc_blocks_lim;           /* approximate limit on alloc_blocks */
38
39 StgPtr alloc_Hp    = NULL;      /* next free byte in small_alloc_list */
40 StgPtr alloc_HpLim = NULL;      /* end of block at small_alloc_list   */
41
42 generation *generations = NULL; /* all the generations */
43 generation *g0          = NULL; /* generation 0, for convenience */
44 generation *oldest_gen  = NULL; /* oldest generation, for convenience */
45 step *g0s0              = NULL; /* generation 0, step 0, for convenience */
46
47 lnat total_allocated = 0;       /* total memory allocated during run */
48
49 /*
50  * Storage manager mutex:  protects all the above state from
51  * simultaneous access by two STG threads.
52  */
53 #ifdef SMP
54 Mutex sm_mutex = INIT_MUTEX_VAR;
55 #endif
56
57 /*
58  * Forward references
59  */
60 static void *stgAllocForGMP   (size_t size_in_bytes);
61 static void *stgReallocForGMP (void *ptr, size_t old_size, size_t new_size);
62 static void  stgDeallocForGMP (void *ptr, size_t size);
63
64 void
65 initStorage( void )
66 {
67   nat g, s;
68   step *stp;
69   generation *gen;
70
71   if (generations != NULL) {
72       // multi-init protection
73       return;
74   }
75
76   /* Sanity check to make sure the LOOKS_LIKE_ macros appear to be
77    * doing something reasonable.
78    */
79   ASSERT(LOOKS_LIKE_INFO_PTR(&stg_BLACKHOLE_info));
80   ASSERT(LOOKS_LIKE_CLOSURE_PTR(&stg_dummy_ret_closure));
81   ASSERT(!HEAP_ALLOCED(&stg_dummy_ret_closure));
82   
83   if (RtsFlags.GcFlags.maxHeapSize != 0 &&
84       RtsFlags.GcFlags.heapSizeSuggestion > 
85       RtsFlags.GcFlags.maxHeapSize) {
86     RtsFlags.GcFlags.maxHeapSize = RtsFlags.GcFlags.heapSizeSuggestion;
87   }
88
89   if (RtsFlags.GcFlags.maxHeapSize != 0 &&
90       RtsFlags.GcFlags.minAllocAreaSize > 
91       RtsFlags.GcFlags.maxHeapSize) {
92       prog_belch("maximum heap size (-M) is smaller than minimum alloc area size (-A)");
93       exit(1);
94   }
95
96   initBlockAllocator();
97   
98 #if defined(SMP)
99   initMutex(&sm_mutex);
100 #endif
101
102   /* allocate generation info array */
103   generations = (generation *)stgMallocBytes(RtsFlags.GcFlags.generations 
104                                              * sizeof(struct _generation),
105                                              "initStorage: gens");
106
107   /* Initialise all generations */
108   for(g = 0; g < RtsFlags.GcFlags.generations; g++) {
109     gen = &generations[g];
110     gen->no = g;
111     gen->mut_list = END_MUT_LIST;
112     gen->mut_once_list = END_MUT_LIST;
113     gen->collections = 0;
114     gen->failed_promotions = 0;
115     gen->max_blocks = 0;
116   }
117
118   /* A couple of convenience pointers */
119   g0 = &generations[0];
120   oldest_gen = &generations[RtsFlags.GcFlags.generations-1];
121
122   /* Allocate step structures in each generation */
123   if (RtsFlags.GcFlags.generations > 1) {
124     /* Only for multiple-generations */
125
126     /* Oldest generation: one step */
127     oldest_gen->n_steps = 1;
128     oldest_gen->steps = 
129       stgMallocBytes(1 * sizeof(struct _step), "initStorage: last step");
130
131     /* set up all except the oldest generation with 2 steps */
132     for(g = 0; g < RtsFlags.GcFlags.generations-1; g++) {
133       generations[g].n_steps = RtsFlags.GcFlags.steps;
134       generations[g].steps  = 
135         stgMallocBytes (RtsFlags.GcFlags.steps * sizeof(struct _step),
136                         "initStorage: steps");
137     }
138     
139   } else {
140     /* single generation, i.e. a two-space collector */
141     g0->n_steps = 1;
142     g0->steps = stgMallocBytes (sizeof(struct _step), "initStorage: steps");
143   }
144
145   /* Initialise all steps */
146   for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
147     for (s = 0; s < generations[g].n_steps; s++) {
148       stp = &generations[g].steps[s];
149       stp->no = s;
150       stp->blocks = NULL;
151       stp->n_to_blocks = 0;
152       stp->n_blocks = 0;
153       stp->gen = &generations[g];
154       stp->gen_no = g;
155       stp->hp = NULL;
156       stp->hpLim = NULL;
157       stp->hp_bd = NULL;
158       stp->scan = NULL;
159       stp->scan_bd = NULL;
160       stp->large_objects = NULL;
161       stp->n_large_blocks = 0;
162       stp->new_large_objects = NULL;
163       stp->scavenged_large_objects = NULL;
164       stp->n_scavenged_large_blocks = 0;
165       stp->is_compacted = 0;
166       stp->bitmap = NULL;
167     }
168   }
169   
170   /* Set up the destination pointers in each younger gen. step */
171   for (g = 0; g < RtsFlags.GcFlags.generations-1; g++) {
172     for (s = 0; s < generations[g].n_steps-1; s++) {
173       generations[g].steps[s].to = &generations[g].steps[s+1];
174     }
175     generations[g].steps[s].to = &generations[g+1].steps[0];
176   }
177   
178   /* The oldest generation has one step and it is compacted. */
179   if (RtsFlags.GcFlags.compact) {
180       if (RtsFlags.GcFlags.generations == 1) {
181           belch("WARNING: compaction is incompatible with -G1; disabled");
182       } else {
183           oldest_gen->steps[0].is_compacted = 1;
184       }
185   }
186   oldest_gen->steps[0].to = &oldest_gen->steps[0];
187
188   /* generation 0 is special: that's the nursery */
189   generations[0].max_blocks = 0;
190
191   /* G0S0: the allocation area.  Policy: keep the allocation area
192    * small to begin with, even if we have a large suggested heap
193    * size.  Reason: we're going to do a major collection first, and we
194    * don't want it to be a big one.  This vague idea is borne out by 
195    * rigorous experimental evidence.
196    */
197   g0s0 = &generations[0].steps[0];
198
199   allocNurseries();
200
201   weak_ptr_list = NULL;
202   caf_list = NULL;
203    
204   /* initialise the allocate() interface */
205   small_alloc_list = NULL;
206   alloc_blocks = 0;
207   alloc_blocks_lim = RtsFlags.GcFlags.minAllocAreaSize;
208
209   /* Tell GNU multi-precision pkg about our custom alloc functions */
210   mp_set_memory_functions(stgAllocForGMP, stgReallocForGMP, stgDeallocForGMP);
211
212   IF_DEBUG(gc, statDescribeGens());
213 }
214
215 void
216 exitStorage (void)
217 {
218     stat_exit(calcAllocated());
219 }
220
221 /* -----------------------------------------------------------------------------
222    CAF management.
223
224    The entry code for every CAF does the following:
225      
226       - builds a CAF_BLACKHOLE in the heap
227       - pushes an update frame pointing to the CAF_BLACKHOLE
228       - invokes UPD_CAF(), which:
229           - calls newCaf, below
230           - updates the CAF with a static indirection to the CAF_BLACKHOLE
231       
232    Why do we build a BLACKHOLE in the heap rather than just updating
233    the thunk directly?  It's so that we only need one kind of update
234    frame - otherwise we'd need a static version of the update frame too.
235
236    newCaf() does the following:
237        
238       - it puts the CAF on the oldest generation's mut-once list.
239         This is so that we can treat the CAF as a root when collecting
240         younger generations.
241
242    For GHCI, we have additional requirements when dealing with CAFs:
243
244       - we must *retain* all dynamically-loaded CAFs ever entered,
245         just in case we need them again.
246       - we must be able to *revert* CAFs that have been evaluated, to
247         their pre-evaluated form.
248
249       To do this, we use an additional CAF list.  When newCaf() is
250       called on a dynamically-loaded CAF, we add it to the CAF list
251       instead of the old-generation mutable list, and save away its
252       old info pointer (in caf->saved_info) for later reversion.
253
254       To revert all the CAFs, we traverse the CAF list and reset the
255       info pointer to caf->saved_info, then throw away the CAF list.
256       (see GC.c:revertCAFs()).
257
258       -- SDM 29/1/01
259
260    -------------------------------------------------------------------------- */
261
262 void
263 newCAF(StgClosure* caf)
264 {
265   /* Put this CAF on the mutable list for the old generation.
266    * This is a HACK - the IND_STATIC closure doesn't really have
267    * a mut_link field, but we pretend it has - in fact we re-use
268    * the STATIC_LINK field for the time being, because when we
269    * come to do a major GC we won't need the mut_link field
270    * any more and can use it as a STATIC_LINK.
271    */
272   ACQUIRE_SM_LOCK;
273
274   ((StgIndStatic *)caf)->saved_info = NULL;
275   ((StgMutClosure *)caf)->mut_link = oldest_gen->mut_once_list;
276   oldest_gen->mut_once_list = (StgMutClosure *)caf;
277
278   RELEASE_SM_LOCK;
279
280 #ifdef PAR
281   /* If we are PAR or DIST then  we never forget a CAF */
282   { globalAddr *newGA;
283     //belch("<##> Globalising CAF %08x %s",caf,info_type(caf));
284     newGA=makeGlobal(caf,rtsTrue); /*given full weight*/
285     ASSERT(newGA);
286   } 
287 #endif /* PAR */
288 }
289
290 // An alternate version of newCaf which is used for dynamically loaded
291 // object code in GHCi.  In this case we want to retain *all* CAFs in
292 // the object code, because they might be demanded at any time from an
293 // expression evaluated on the command line.
294 //
295 // The linker hackily arranges that references to newCaf from dynamic
296 // code end up pointing to newDynCAF.
297 void
298 newDynCAF(StgClosure *caf)
299 {
300     ACQUIRE_SM_LOCK;
301
302     ((StgIndStatic *)caf)->saved_info  = (StgInfoTable *)caf->header.info;
303     ((StgIndStatic *)caf)->static_link = caf_list;
304     caf_list = caf;
305
306     RELEASE_SM_LOCK;
307 }
308
309 /* -----------------------------------------------------------------------------
310    Nursery management.
311    -------------------------------------------------------------------------- */
312
313 void
314 allocNurseries( void )
315
316 #ifdef SMP
317   Capability *cap;
318   bdescr *bd;
319
320   g0s0->blocks = NULL;
321   g0s0->n_blocks = 0;
322   for (cap = free_capabilities; cap != NULL; cap = cap->link) {
323     cap->r.rNursery = allocNursery(NULL, RtsFlags.GcFlags.minAllocAreaSize);
324     cap->r.rCurrentNursery = cap->r.rNursery;
325     /* Set the back links to be equal to the Capability,
326      * so we can do slightly better informed locking.
327      */
328     for (bd = cap->r.rNursery; bd != NULL; bd = bd->link) {
329       bd->u.back = (bdescr *)cap;
330     }
331   }
332 #else /* SMP */
333   g0s0->blocks      = allocNursery(NULL, RtsFlags.GcFlags.minAllocAreaSize);
334   g0s0->n_blocks    = RtsFlags.GcFlags.minAllocAreaSize;
335   g0s0->to_blocks   = NULL;
336   g0s0->n_to_blocks = 0;
337   MainCapability.r.rNursery        = g0s0->blocks;
338   MainCapability.r.rCurrentNursery = g0s0->blocks;
339   /* hp, hpLim, hp_bd, to_space etc. aren't used in G0S0 */
340 #endif
341 }
342       
343 void
344 resetNurseries( void )
345 {
346   bdescr *bd;
347 #ifdef SMP
348   Capability *cap;
349   
350   /* All tasks must be stopped */
351   ASSERT(n_free_capabilities == RtsFlags.ParFlags.nNodes);
352
353   for (cap = free_capabilities; cap != NULL; cap = cap->link) {
354     for (bd = cap->r.rNursery; bd; bd = bd->link) {
355       bd->free = bd->start;
356       ASSERT(bd->gen_no == 0);
357       ASSERT(bd->step == g0s0);
358       IF_DEBUG(sanity,memset(bd->start, 0xaa, BLOCK_SIZE));
359     }
360     cap->r.rCurrentNursery = cap->r.rNursery;
361   }
362 #else
363   for (bd = g0s0->blocks; bd; bd = bd->link) {
364     bd->free = bd->start;
365     ASSERT(bd->gen_no == 0);
366     ASSERT(bd->step == g0s0);
367     IF_DEBUG(sanity,memset(bd->start, 0xaa, BLOCK_SIZE));
368   }
369   MainCapability.r.rNursery = g0s0->blocks;
370   MainCapability.r.rCurrentNursery = g0s0->blocks;
371 #endif
372 }
373
374 bdescr *
375 allocNursery (bdescr *tail, nat blocks)
376 {
377   bdescr *bd;
378   nat i;
379
380   // Allocate a nursery: we allocate fresh blocks one at a time and
381   // cons them on to the front of the list, not forgetting to update
382   // the back pointer on the tail of the list to point to the new block.
383   for (i=0; i < blocks; i++) {
384     // @LDV profiling
385     /*
386       processNursery() in LdvProfile.c assumes that every block group in
387       the nursery contains only a single block. So, if a block group is
388       given multiple blocks, change processNursery() accordingly.
389      */
390     bd = allocBlock();
391     bd->link = tail;
392     // double-link the nursery: we might need to insert blocks
393     if (tail != NULL) {
394         tail->u.back = bd;
395     }
396     bd->step = g0s0;
397     bd->gen_no = 0;
398     bd->flags = 0;
399     bd->free = bd->start;
400     tail = bd;
401   }
402   tail->u.back = NULL;
403   return tail;
404 }
405
406 void
407 resizeNursery ( nat blocks )
408 {
409   bdescr *bd;
410   nat nursery_blocks;
411
412 #ifdef SMP
413   barf("resizeNursery: can't resize in SMP mode");
414 #endif
415
416   nursery_blocks = g0s0->n_blocks;
417   if (nursery_blocks == blocks) {
418     return;
419   }
420
421   else if (nursery_blocks < blocks) {
422     IF_DEBUG(gc, fprintf(stderr, "Increasing size of nursery to %d blocks\n", 
423                          blocks));
424     g0s0->blocks = allocNursery(g0s0->blocks, blocks-nursery_blocks);
425   } 
426
427   else {
428     bdescr *next_bd;
429     
430     IF_DEBUG(gc, fprintf(stderr, "Decreasing size of nursery to %d blocks\n", 
431                          blocks));
432
433     bd = g0s0->blocks;
434     while (nursery_blocks > blocks) {
435         next_bd = bd->link;
436         next_bd->u.back = NULL;
437         nursery_blocks -= bd->blocks; // might be a large block
438         freeGroup(bd);
439         bd = next_bd;
440     }
441     g0s0->blocks = bd;
442     // might have gone just under, by freeing a large block, so make
443     // up the difference.
444     if (nursery_blocks < blocks) {
445         g0s0->blocks = allocNursery(g0s0->blocks, blocks-nursery_blocks);
446     }
447   }
448   
449   g0s0->n_blocks = blocks;
450   ASSERT(countBlocks(g0s0->blocks) == g0s0->n_blocks);
451 }
452
453 /* -----------------------------------------------------------------------------
454    The allocate() interface
455
456    allocate(n) always succeeds, and returns a chunk of memory n words
457    long.  n can be larger than the size of a block if necessary, in
458    which case a contiguous block group will be allocated.
459    -------------------------------------------------------------------------- */
460
461 StgPtr
462 allocate( nat n )
463 {
464   bdescr *bd;
465   StgPtr p;
466
467   ACQUIRE_SM_LOCK;
468
469   TICK_ALLOC_HEAP_NOCTR(n);
470   CCS_ALLOC(CCCS,n);
471
472   /* big allocation (>LARGE_OBJECT_THRESHOLD) */
473   /* ToDo: allocate directly into generation 1 */
474   if (n >= LARGE_OBJECT_THRESHOLD/sizeof(W_)) {
475     nat req_blocks =  (lnat)BLOCK_ROUND_UP(n*sizeof(W_)) / BLOCK_SIZE;
476     bd = allocGroup(req_blocks);
477     dbl_link_onto(bd, &g0s0->large_objects);
478     bd->gen_no  = 0;
479     bd->step = g0s0;
480     bd->flags = BF_LARGE;
481     bd->free = bd->start + n;
482     /* don't add these blocks to alloc_blocks, since we're assuming
483      * that large objects are likely to remain live for quite a while
484      * (eg. running threads), so garbage collecting early won't make
485      * much difference.
486      */
487     alloc_blocks += req_blocks;
488     RELEASE_SM_LOCK;
489     return bd->start;
490
491   /* small allocation (<LARGE_OBJECT_THRESHOLD) */
492   } else if (small_alloc_list == NULL || alloc_Hp + n > alloc_HpLim) {
493     if (small_alloc_list) {
494       small_alloc_list->free = alloc_Hp;
495     }
496     bd = allocBlock();
497     bd->link = small_alloc_list;
498     small_alloc_list = bd;
499     bd->gen_no = 0;
500     bd->step = g0s0;
501     bd->flags = 0;
502     alloc_Hp = bd->start;
503     alloc_HpLim = bd->start + BLOCK_SIZE_W;
504     alloc_blocks++;
505   }
506
507   p = alloc_Hp;
508   alloc_Hp += n;
509   RELEASE_SM_LOCK;
510   return p;
511 }
512
513 lnat
514 allocated_bytes( void )
515 {
516     lnat allocated;
517
518     allocated = alloc_blocks * BLOCK_SIZE_W - (alloc_HpLim - alloc_Hp);
519     if (pinned_object_block != NULL) {
520         allocated -= (pinned_object_block->start + BLOCK_SIZE_W) - 
521             pinned_object_block->free;
522     }
523         
524     return allocated;
525 }
526
527 void
528 tidyAllocateLists (void)
529 {
530     if (small_alloc_list != NULL) {
531         ASSERT(alloc_Hp >= small_alloc_list->start && 
532                alloc_Hp <= small_alloc_list->start + BLOCK_SIZE);
533         small_alloc_list->free = alloc_Hp;
534     }
535 }
536
537 /* ---------------------------------------------------------------------------
538    Allocate a fixed/pinned object.
539
540    We allocate small pinned objects into a single block, allocating a
541    new block when the current one overflows.  The block is chained
542    onto the large_object_list of generation 0 step 0.
543
544    NOTE: The GC can't in general handle pinned objects.  This
545    interface is only safe to use for ByteArrays, which have no
546    pointers and don't require scavenging.  It works because the
547    block's descriptor has the BF_LARGE flag set, so the block is
548    treated as a large object and chained onto various lists, rather
549    than the individual objects being copied.  However, when it comes
550    to scavenge the block, the GC will only scavenge the first object.
551    The reason is that the GC can't linearly scan a block of pinned
552    objects at the moment (doing so would require using the
553    mostly-copying techniques).  But since we're restricting ourselves
554    to pinned ByteArrays, not scavenging is ok.
555
556    This function is called by newPinnedByteArray# which immediately
557    fills the allocated memory with a MutableByteArray#.
558    ------------------------------------------------------------------------- */
559
560 StgPtr
561 allocatePinned( nat n )
562 {
563     StgPtr p;
564     bdescr *bd = pinned_object_block;
565
566     // If the request is for a large object, then allocate()
567     // will give us a pinned object anyway.
568     if (n >= LARGE_OBJECT_THRESHOLD/sizeof(W_)) {
569         return allocate(n);
570     }
571
572     ACQUIRE_SM_LOCK;
573     
574     TICK_ALLOC_HEAP_NOCTR(n);
575     CCS_ALLOC(CCCS,n);
576
577     // we always return 8-byte aligned memory.  bd->free must be
578     // 8-byte aligned to begin with, so we just round up n to
579     // the nearest multiple of 8 bytes.
580     if (sizeof(StgWord) == 4) {
581         n = (n+1) & ~1;
582     }
583
584     // If we don't have a block of pinned objects yet, or the current
585     // one isn't large enough to hold the new object, allocate a new one.
586     if (bd == NULL || (bd->free + n) > (bd->start + BLOCK_SIZE_W)) {
587         pinned_object_block = bd = allocBlock();
588         dbl_link_onto(bd, &g0s0->large_objects);
589         bd->gen_no = 0;
590         bd->step   = g0s0;
591         bd->flags  = BF_PINNED | BF_LARGE;
592         bd->free   = bd->start;
593         alloc_blocks++;
594     }
595
596     p = bd->free;
597     bd->free += n;
598     RELEASE_SM_LOCK;
599     return p;
600 }
601
602 /* -----------------------------------------------------------------------------
603    Allocation functions for GMP.
604
605    These all use the allocate() interface - we can't have any garbage
606    collection going on during a gmp operation, so we use allocate()
607    which always succeeds.  The gmp operations which might need to
608    allocate will ask the storage manager (via doYouWantToGC()) whether
609    a garbage collection is required, in case we get into a loop doing
610    only allocate() style allocation.
611    -------------------------------------------------------------------------- */
612
613 static void *
614 stgAllocForGMP (size_t size_in_bytes)
615 {
616   StgArrWords* arr;
617   nat data_size_in_words, total_size_in_words;
618   
619   /* round up to a whole number of words */
620   data_size_in_words  = (size_in_bytes + sizeof(W_) + 1) / sizeof(W_);
621   total_size_in_words = sizeofW(StgArrWords) + data_size_in_words;
622   
623   /* allocate and fill it in. */
624   arr = (StgArrWords *)allocate(total_size_in_words);
625   SET_ARR_HDR(arr, &stg_ARR_WORDS_info, CCCS, data_size_in_words);
626   
627   /* and return a ptr to the goods inside the array */
628   return(BYTE_ARR_CTS(arr));
629 }
630
631 static void *
632 stgReallocForGMP (void *ptr, size_t old_size, size_t new_size)
633 {
634     void *new_stuff_ptr = stgAllocForGMP(new_size);
635     nat i = 0;
636     char *p = (char *) ptr;
637     char *q = (char *) new_stuff_ptr;
638
639     for (; i < old_size; i++, p++, q++) {
640         *q = *p;
641     }
642
643     return(new_stuff_ptr);
644 }
645
646 static void
647 stgDeallocForGMP (void *ptr STG_UNUSED, 
648                   size_t size STG_UNUSED)
649 {
650     /* easy for us: the garbage collector does the dealloc'n */
651 }
652
653 /* -----------------------------------------------------------------------------
654  * Stats and stuff
655  * -------------------------------------------------------------------------- */
656
657 /* -----------------------------------------------------------------------------
658  * calcAllocated()
659  *
660  * Approximate how much we've allocated: number of blocks in the
661  * nursery + blocks allocated via allocate() - unused nusery blocks.
662  * This leaves a little slop at the end of each block, and doesn't
663  * take into account large objects (ToDo).
664  * -------------------------------------------------------------------------- */
665
666 lnat
667 calcAllocated( void )
668 {
669   nat allocated;
670   bdescr *bd;
671
672 #ifdef SMP
673   Capability *cap;
674
675   /* All tasks must be stopped.  Can't assert that all the
676      capabilities are owned by the scheduler, though: one or more
677      tasks might have been stopped while they were running (non-main)
678      threads. */
679   /*  ASSERT(n_free_capabilities == RtsFlags.ParFlags.nNodes); */
680
681   allocated = 
682     n_free_capabilities * RtsFlags.GcFlags.minAllocAreaSize * BLOCK_SIZE_W
683     + allocated_bytes();
684
685   for (cap = free_capabilities; cap != NULL; cap = cap->link) {
686     for ( bd = cap->r.rCurrentNursery->link; bd != NULL; bd = bd->link ) {
687       allocated -= BLOCK_SIZE_W;
688     }
689     if (cap->r.rCurrentNursery->free < cap->r.rCurrentNursery->start 
690         + BLOCK_SIZE_W) {
691       allocated -= (cap->r.rCurrentNursery->start + BLOCK_SIZE_W)
692         - cap->r.rCurrentNursery->free;
693     }
694   }
695
696 #else /* !SMP */
697   bdescr *current_nursery = MainCapability.r.rCurrentNursery;
698
699   allocated = (g0s0->n_blocks * BLOCK_SIZE_W) + allocated_bytes();
700   for ( bd = current_nursery->link; bd != NULL; bd = bd->link ) {
701     allocated -= BLOCK_SIZE_W;
702   }
703   if (current_nursery->free < current_nursery->start + BLOCK_SIZE_W) {
704     allocated -= (current_nursery->start + BLOCK_SIZE_W)
705       - current_nursery->free;
706   }
707 #endif
708
709   total_allocated += allocated;
710   return allocated;
711 }  
712
713 /* Approximate the amount of live data in the heap.  To be called just
714  * after garbage collection (see GarbageCollect()).
715  */
716 extern lnat 
717 calcLive(void)
718 {
719   nat g, s;
720   lnat live = 0;
721   step *stp;
722
723   if (RtsFlags.GcFlags.generations == 1) {
724     live = (g0s0->n_to_blocks - 1) * BLOCK_SIZE_W + 
725       ((lnat)g0s0->hp_bd->free - (lnat)g0s0->hp_bd->start) / sizeof(W_);
726     return live;
727   }
728
729   for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
730     for (s = 0; s < generations[g].n_steps; s++) {
731       /* approximate amount of live data (doesn't take into account slop
732        * at end of each block).
733        */
734       if (g == 0 && s == 0) { 
735           continue; 
736       }
737       stp = &generations[g].steps[s];
738       live += (stp->n_large_blocks + stp->n_blocks - 1) * BLOCK_SIZE_W;
739       if (stp->hp_bd != NULL) {
740           live += ((lnat)stp->hp_bd->free - (lnat)stp->hp_bd->start) 
741               / sizeof(W_);
742       }
743     }
744   }
745   return live;
746 }
747
748 /* Approximate the number of blocks that will be needed at the next
749  * garbage collection.
750  *
751  * Assume: all data currently live will remain live.  Steps that will
752  * be collected next time will therefore need twice as many blocks
753  * since all the data will be copied.
754  */
755 extern lnat 
756 calcNeeded(void)
757 {
758     lnat needed = 0;
759     nat g, s;
760     step *stp;
761     
762     for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
763         for (s = 0; s < generations[g].n_steps; s++) {
764             if (g == 0 && s == 0) { continue; }
765             stp = &generations[g].steps[s];
766             if (generations[g].steps[0].n_blocks +
767                 generations[g].steps[0].n_large_blocks 
768                 > generations[g].max_blocks
769                 && stp->is_compacted == 0) {
770                 needed += 2 * stp->n_blocks;
771             } else {
772                 needed += stp->n_blocks;
773             }
774         }
775     }
776     return needed;
777 }
778
779 /* -----------------------------------------------------------------------------
780    Debugging
781
782    memInventory() checks for memory leaks by counting up all the
783    blocks we know about and comparing that to the number of blocks
784    allegedly floating around in the system.
785    -------------------------------------------------------------------------- */
786
787 #ifdef DEBUG
788
789 void
790 memInventory(void)
791 {
792   nat g, s;
793   step *stp;
794   bdescr *bd;
795   lnat total_blocks = 0, free_blocks = 0;
796
797   /* count the blocks we current have */
798
799   for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
800     for (s = 0; s < generations[g].n_steps; s++) {
801       stp = &generations[g].steps[s];
802       total_blocks += stp->n_blocks;
803       if (RtsFlags.GcFlags.generations == 1) {
804         /* two-space collector has a to-space too :-) */
805         total_blocks += g0s0->n_to_blocks;
806       }
807       for (bd = stp->large_objects; bd; bd = bd->link) {
808         total_blocks += bd->blocks;
809         /* hack for megablock groups: they have an extra block or two in
810            the second and subsequent megablocks where the block
811            descriptors would normally go.
812         */
813         if (bd->blocks > BLOCKS_PER_MBLOCK) {
814           total_blocks -= (MBLOCK_SIZE / BLOCK_SIZE - BLOCKS_PER_MBLOCK)
815                           * (bd->blocks/(MBLOCK_SIZE/BLOCK_SIZE));
816         }
817       }
818     }
819   }
820
821   /* any blocks held by allocate() */
822   for (bd = small_alloc_list; bd; bd = bd->link) {
823     total_blocks += bd->blocks;
824   }
825
826 #ifdef PROFILING
827   if (RtsFlags.ProfFlags.doHeapProfile == HEAP_BY_RETAINER) {
828       total_blocks += retainerStackBlocks();
829   }
830 #endif
831
832   // count the blocks allocated by the arena allocator
833   total_blocks += arenaBlocks();
834
835   /* count the blocks on the free list */
836   free_blocks = countFreeList();
837
838   if (total_blocks + free_blocks != mblocks_allocated *
839       BLOCKS_PER_MBLOCK) {
840     fprintf(stderr, "Blocks: %ld live + %ld free  = %ld total (%ld around)\n",
841             total_blocks, free_blocks, total_blocks + free_blocks,
842             mblocks_allocated * BLOCKS_PER_MBLOCK);
843   }
844
845   ASSERT(total_blocks + free_blocks == mblocks_allocated * BLOCKS_PER_MBLOCK);
846 }
847
848
849 nat
850 countBlocks(bdescr *bd)
851 {
852     nat n;
853     for (n=0; bd != NULL; bd=bd->link) {
854         n += bd->blocks;
855     }
856     return n;
857 }
858
859 /* Full heap sanity check. */
860 void
861 checkSanity( void )
862 {
863     nat g, s;
864
865     if (RtsFlags.GcFlags.generations == 1) {
866         checkHeap(g0s0->to_blocks);
867         checkChain(g0s0->large_objects);
868     } else {
869         
870         for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
871             for (s = 0; s < generations[g].n_steps; s++) {
872                 ASSERT(countBlocks(generations[g].steps[s].blocks)
873                        == generations[g].steps[s].n_blocks);
874                 ASSERT(countBlocks(generations[g].steps[s].large_objects)
875                        == generations[g].steps[s].n_large_blocks);
876                 if (g == 0 && s == 0) { continue; }
877                 checkHeap(generations[g].steps[s].blocks);
878                 checkChain(generations[g].steps[s].large_objects);
879                 if (g > 0) {
880                     checkMutableList(generations[g].mut_list, g);
881                     checkMutOnceList(generations[g].mut_once_list, g);
882                 }
883             }
884         }
885         checkFreeListSanity();
886     }
887 }
888
889 // handy function for use in gdb, because Bdescr() is inlined.
890 extern bdescr *_bdescr( StgPtr p );
891
892 bdescr *
893 _bdescr( StgPtr p )
894 {
895     return Bdescr(p);
896 }
897
898 #endif