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