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