Commit dfd7d6d0 authored by simonmar's avatar simonmar

[project @ 2001-07-23 17:23:19 by simonmar]

Add a compacting garbage collector.

It isn't enabled by default, as there are still a couple of problems:
there's a fallback case I haven't implemented yet which means it will
occasionally bomb out, and speed-wise it's quite a bit slower than the
copying collector (about 1.8x slower).

Until I can make it go faster, it'll only be useful when you're
actually running low on real memory.

'+RTS -c' to enable it.

Oh, and I cleaned up a few things in the RTS while I was there, and
fixed one or two possibly real bugs in the existing GC.
parent 9528fa3e
/* -----------------------------------------------------------------------------
* $Id: Block.h,v 1.8 2001/07/23 10:47:16 simonmar Exp $
* $Id: Block.h,v 1.9 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
......@@ -44,11 +44,14 @@ typedef struct _bdescr {
StgPtr start; /* start addr of memory */
StgPtr free; /* first free byte of memory */
struct _bdescr *link; /* used for chaining blocks together */
struct _bdescr *back; /* used (occasionally) for doubly-linked lists*/
union {
struct _bdescr *back; /* used (occasionally) for doubly-linked lists*/
StgWord *bitmap;
} u;
unsigned int gen_no; /* generation */
struct _step *step; /* step */
StgWord32 blocks; /* no. of blocks (if grp head, 0 otherwise) */
StgWord32 evacuated; /* block is in to-space */
StgWord32 flags; /* block is in to-space */
#if SIZEOF_VOID_P == 8
StgWord32 _padding[2];
#else
......@@ -66,6 +69,9 @@ typedef struct _bdescr {
#define BDESCR_SHIFT 5
#endif
#define BF_EVACUATED 1
#define BF_LARGE 2
/* Finding the block descriptor for a given block -------------------------- */
static inline bdescr *Bdescr(StgPtr p)
......
/* ----------------------------------------------------------------------------
* $Id: ClosureTypes.h,v 1.15 2001/03/22 03:51:09 hwloidl Exp $
* $Id: ClosureTypes.h,v 1.16 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
......@@ -67,20 +67,21 @@
#define MUT_ARR_PTRS 53
#define MUT_ARR_PTRS_FROZEN 54
#define MUT_VAR 55
#define WEAK 56
#define FOREIGN 57
#define STABLE_NAME 58
#define MUT_CONS 56
#define WEAK 57
#define FOREIGN 58
#define STABLE_NAME 59
#define TSO 59
#define BLOCKED_FETCH 60
#define FETCH_ME 61
#define FETCH_ME_BQ 62
#define RBH 63
#define TSO 60
#define BLOCKED_FETCH 61
#define FETCH_ME 62
#define FETCH_ME_BQ 63
#define RBH 64
#define EVACUATED 64
#define EVACUATED 65
#define REMOTE_REF 65
#define REMOTE_REF 66
#define N_CLOSURE_TYPES 66
#define N_CLOSURE_TYPES 67
#endif /* CLOSURETYPES_H */
/* -----------------------------------------------------------------------------
* $Id: Stable.h,v 1.7 2000/11/07 17:05:47 simonmar Exp $
* $Id: Stable.h,v 1.8 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-2000
*
......@@ -33,6 +33,7 @@ extern StgStablePtr getStablePtr(StgPtr p);
typedef struct {
StgPtr addr; /* Haskell object, free list, or NULL */
StgPtr old; /* old Haskell object, used during GC */
StgWord weight; /* used for reference counting */
StgClosure *sn_obj; /* the StableName object (or NULL) */
} snEntry;
......
/* -----------------------------------------------------------------------------
* $Id: StgStorage.h,v 1.8 2001/07/23 10:47:16 simonmar Exp $
* $Id: StgStorage.h,v 1.9 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
......@@ -55,17 +55,19 @@ typedef struct _step {
struct _generation *gen; /* generation this step belongs to */
unsigned int gen_no; /* generation number (cached) */
bdescr *large_objects; /* large objects (doubly linked) */
int is_compacted; /* compact this step */
/* temporary use during GC: */
StgPtr hp; /* next free locn in to-space */
StgPtr hpLim; /* end of current to-space block */
bdescr *hp_bd; /* bdescr of current to-space block */
bdescr *to_space; /* bdescr of first to-space block */
unsigned int to_blocks; /* number of blocks in to-space */
bdescr *to_blocks; /* bdescr of first to-space block */
unsigned int n_to_blocks; /* number of blocks in to-space */
bdescr *scan_bd; /* block currently being scanned */
StgPtr scan; /* scan pointer in current block */
bdescr *new_large_objects; /* large objects collected so far */
bdescr *scavenged_large_objects; /* live large objects after GC (dbl link) */
bdescr *bitmap; /* bitmap for compacting collection */
} step;
typedef struct _generation {
......@@ -104,12 +106,18 @@ typedef struct _generation {
#define CloseNursery(hp) (CurrentNursery->free = (P_)(hp)+1)
/* -----------------------------------------------------------------------------
Prototype for an evacuate-like function
-------------------------------------------------------------------------- */
typedef void (*evac_fn)(StgClosure **);
/* -----------------------------------------------------------------------------
Trigger a GC from Haskell land.
-------------------------------------------------------------------------- */
extern void performGC(void);
extern void performMajorGC(void);
extern void performGCWithRoots(void (*get_roots)(void));
extern void performGCWithRoots(void (*get_roots)(evac_fn));
#endif /* STGSTORAGE_H */
/* -----------------------------------------------------------------------------
* $Id: StgTypes.h,v 1.15 2000/11/07 17:05:47 simonmar Exp $
* $Id: StgTypes.h,v 1.16 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-2000
*
......@@ -97,6 +97,8 @@ typedef StgWord32 StgWord;
#endif
#endif
#define W_MASK (sizeof(W_)-1)
typedef void* StgAddr;
/*
......
/* -----------------------------------------------------------------------------
* $Id: BlockAlloc.c,v 1.8 2001/07/23 10:47:16 simonmar Exp $
* $Id: BlockAlloc.c,v 1.9 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team 1998-2000
*
......@@ -63,6 +63,8 @@ allocGroup(nat n)
void *mblock;
bdescr *bd, **last;
ASSERT(n != 0);
if (n > BLOCKS_PER_MBLOCK) {
return allocMegaGroup(BLOCKS_TO_MBLOCKS(n));
}
......
/* -----------------------------------------------------------------------------
* $Id: ClosureFlags.c,v 1.9 2001/03/22 03:51:10 hwloidl Exp $
* $Id: ClosureFlags.c,v 1.10 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team 1998-1999
*
......@@ -25,7 +25,7 @@ StgWord16 closure_flags[] = {
/* 0 1 2 3 4 5 6 7 */
/* HNF BTM NS STA THU MUT UPT SRT */
[INVALID_OBJECT ] = ( 0 ),
[CONSTR ] = (_HNF| _NS ),
[CONSTR_1_0 ] = (_HNF| _NS ),
......@@ -60,7 +60,7 @@ StgWord16 closure_flags[] = {
[IND_PERM ] = ( _NS |_IND ),
[IND_OLDGEN_PERM ] = ( _NS |_IND ),
[IND_STATIC ] = ( _NS|_STA |_IND ),
[CAF_BLACKHOLE ] = ( _BTM|_NS| _MUT|_UPT ),
[CAF_BLACKHOLE ] = ( _BTM|_NS| _UPT ),
[RET_BCO ] = ( _BTM ),
[RET_SMALL ] = ( _BTM| _SRT ),
[RET_VEC_SMALL ] = ( _BTM| _SRT ),
......@@ -71,15 +71,16 @@ StgWord16 closure_flags[] = {
[CATCH_FRAME ] = ( _BTM ),
[STOP_FRAME ] = ( _BTM ),
[SEQ_FRAME ] = ( _BTM ),
[BLACKHOLE ] = ( _NS| _MUT|_UPT ),
[BLACKHOLE ] = ( _NS| _UPT ),
[BLACKHOLE_BQ ] = ( _NS| _MUT|_UPT ),
[SE_BLACKHOLE ] = ( _NS| _UPT ),
[SE_CAF_BLACKHOLE ] = ( _NS| _UPT ),
[MVAR ] = (_HNF| _NS| _MUT|_UPT ),
[ARR_WORDS ] = (_HNF| _NS| _UPT ),
[MUT_ARR_PTRS ] = (_HNF| _NS| _MUT|_UPT ),
[MUT_ARR_PTRS_FROZEN ] = (_HNF| _NS| _MUT|_UPT ),
[MUT_ARR_PTRS_FROZEN ] = (_HNF| _NS| _UPT ),
[MUT_VAR ] = (_HNF| _NS| _MUT|_UPT ),
[MUT_CONS ] = (_HNF| _NS| _UPT ),
[WEAK ] = (_HNF| _NS| _UPT ),
[FOREIGN ] = (_HNF| _NS| _UPT ),
[STABLE_NAME ] = (_HNF| _NS| _UPT ),
......
This diff is collapsed.
/* -----------------------------------------------------------------------------
* $Id: GC.h,v 1.6 2000/04/11 16:36:53 sewardj Exp $
*
* (c) The GHC Team, 1998-1999
*
* Prototypes for functions in GC.c
*
* ---------------------------------------------------------------------------*/
void threadPaused(StgTSO *);
StgClosure *isAlive(StgClosure *p);
void GarbageCollect ( void (*get_roots)(void), rtsBool force_major_gc );
This diff is collapsed.
/* -----------------------------------------------------------------------------
* $Id: GCCompact.h,v 1.1 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team 1998-1999
*
* Compacting garbage collector
*
* ---------------------------------------------------------------------------*/
static inline void
mark(StgPtr p, bdescr *bd)
{
nat offset_within_block = p - bd->start; // in words
StgPtr bitmap_word = (StgPtr)bd->u.bitmap +
(offset_within_block / (sizeof(W_)*BITS_PER_BYTE));
nat bit_mask = 1 << (offset_within_block & (sizeof(W_)*BITS_PER_BYTE - 1));
*bitmap_word |= bit_mask;
}
static inline int
is_marked(StgPtr p, bdescr *bd)
{
nat offset_within_block = p - bd->start; // in words
StgPtr bitmap_word = (StgPtr)bd->u.bitmap +
(offset_within_block / (sizeof(W_)*BITS_PER_BYTE));
nat bit_mask = 1 << (offset_within_block & (sizeof(W_)*BITS_PER_BYTE - 1));
return (*bitmap_word & bit_mask);
}
void compact( void (*get_roots)(evac_fn) );
/* -----------------------------------------------------------------------------
* $Id: PrimOps.hc,v 1.79 2001/07/06 14:11:38 simonmar Exp $
* $Id: PrimOps.hc,v 1.80 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-2000
*
......@@ -594,8 +594,23 @@ FN_(word64ToIntegerzh_fast)
FE_
}
#elif SIZEOF_VOID_P == 8
#endif /* HAVE_LONG_LONG */
FN_(word64ToIntegerzh_fast)
{
FB_
JMP_(wordToIntegerzh_fast);
FE_
}
FN_(int64ToIntegerzh_fast)
{
FB_
JMP_(intToIntegerzh_fast);
FE_
}
#endif /* SUPPORT_LONG_LONGS || SIZEOF_VOID_P == 8 */
/* ToDo: this is shockingly inefficient */
......
/* -----------------------------------------------------------------------------
* $Id: Printer.c,v 1.40 2001/04/03 10:09:23 rrt Exp $
* $Id: Printer.c,v 1.41 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1994-2000.
*
......@@ -941,7 +941,7 @@ findPtr(P_ p, int follow)
for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
for (s = 0; s < generations[g].n_steps; s++) {
if (RtsFlags.GcFlags.generations == 1) {
bd = generations[g].steps[s].to_space;
bd = generations[g].steps[s].to_blocks;
} else {
bd = generations[g].steps[s].blocks;
}
......
/* -----------------------------------------------------------------------------
* $Id: ProfHeap.c,v 1.22 2001/07/19 07:28:00 andy Exp $
* $Id: ProfHeap.c,v 1.23 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-2000
*
......@@ -573,7 +573,7 @@ heapCensus(void)
/* Only do heap profiling in a two-space heap */
ASSERT(RtsFlags.GcFlags.generations == 1);
bd = g0s0->to_space;
bd = g0s0->to_blocks;
fprintf(hp_file, "BEGIN_SAMPLE %0.2f\n", time);
......
/* -----------------------------------------------------------------------------
* $Id: RtsFlags.c,v 1.40 2001/07/23 10:42:37 simonmar Exp $
* $Id: RtsFlags.c,v 1.41 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The AQUA Project, Glasgow University, 1994-1997
* (c) The GHC Team, 1998-1999
......@@ -235,6 +235,7 @@ void initRtsFlagsDefaults(void)
#else
RtsFlags.GcFlags.generations = 2;
RtsFlags.GcFlags.steps = 2;
RtsFlags.GcFlags.compact = rtsFalse;
RtsFlags.GcFlags.squeezeUpdFrames = rtsTrue;
#endif
#ifdef RTS_GTK_FRONTPANEL
......@@ -387,6 +388,7 @@ usage_text[] = {
" -m<n>% Minimum % of heap which must be available (default 3%)",
" -G<n> Number of generations (default: 2)",
" -T<n> Number of steps in younger generations (default: 2)",
" -c Enable compaction for the oldest generation",
"",
" -t<file> One-line GC statistics (default file: <program>.stat)",
" -s<file> Summary GC statistics (with -Sstderr going to stderr)",
......@@ -617,6 +619,10 @@ error = rtsTrue;
RtsFlags.GcFlags.ringBell = rtsTrue;
break;
case 'c':
RtsFlags.GcFlags.compact = rtsTrue;
break;
case 'F':
RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
......
/* -----------------------------------------------------------------------------
* $Id: RtsFlags.h,v 1.33 2001/07/19 07:28:00 andy Exp $
* $Id: RtsFlags.h,v 1.34 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
......@@ -33,11 +33,10 @@ struct GC_FLAGS {
nat generations;
nat steps;
rtsBool ringBell;
rtsBool compact;
rtsBool squeezeUpdFrames;
rtsBool ringBell;
rtsBool frontpanel;
};
......
This diff is collapsed.
/* -----------------------------------------------------------------------------
* $Id: Sanity.h,v 1.8 2001/03/22 03:51:10 hwloidl Exp $
* $Id: Sanity.h,v 1.9 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
......@@ -17,27 +17,35 @@
# endif
/* debugging routines */
extern void checkHeap ( bdescr *bd, StgPtr start );
extern void checkHeap ( bdescr *bd );
extern void checkHeapChunk ( StgPtr start, StgPtr end );
extern void checkChain ( bdescr *bd );
extern void checkStack ( StgPtr sp, StgPtr stack_end, StgUpdateFrame* su );
extern void checkTSO ( StgTSO* tso );
extern void checkGlobalTSOList (rtsBool checkTSOs);
extern void checkStaticObjects ( void );
extern void checkChain ( bdescr *bd );
extern void checkStack ( StgPtr sp, StgPtr stack_end, StgUpdateFrame* su );
extern void checkTSO ( StgTSO* tso );
extern void checkGlobalTSOList ( rtsBool checkTSOs );
extern void checkStaticObjects ( StgClosure* static_objects );
extern void checkStackChunk ( StgPtr sp, StgPtr stack_end );
extern StgOffset checkClosure ( StgClosure* p );
extern void checkMutableList ( StgMutClosure *p, nat gen );
extern void checkMutOnceList ( StgMutClosure *p, nat gen );
#if defined(GRAN)
extern void checkTSOsSanity(void);
extern rtsBool checkThreadQSanity (PEs proc, rtsBool check_TSO_too);
extern rtsBool checkThreadQsSanity (rtsBool check_TSO_too);
#endif
#if defined(PAR)
extern void checkBQ (StgBlockingQueueElement *bqe, StgClosure *closure);
extern void checkLAGAtable(rtsBool check_closures);
extern void checkHeapChunk(StgPtr start, StgPtr end);
#else
extern void checkBQ (StgTSO *bqe, StgClosure *closure);
#endif
extern StgOffset checkClosure( StgClosure* p );
#if defined(PAR)
extern void checkLAGAtable(rtsBool check_closures);
extern void checkHeapChunk(StgPtr start, StgPtr end);
#endif
/* test whether an object is already on update list */
extern rtsBool isBlackhole( StgTSO* tso, StgClosure* p );
......
/* ---------------------------------------------------------------------------
* $Id: Schedule.c,v 1.96 2001/06/04 16:26:54 simonmar Exp $
* $Id: Schedule.c,v 1.97 2001/07/23 17:23:19 simonmar Exp $
*
* (c) The GHC Team, 1998-2000
*
......@@ -81,7 +81,6 @@
#include "Storage.h"
#include "StgRun.h"
#include "StgStartup.h"
#include "GC.h"
#include "Hooks.h"
#include "Schedule.h"
#include "StgMiscClosures.h"
......@@ -181,7 +180,7 @@ StgTSO *all_threads;
*/
static StgTSO *suspended_ccalling_threads;
static void GetRoots(void);
static void GetRoots(evac_fn);
static StgTSO *threadStackOverflow(StgTSO *tso);
/* KH: The following two flags are shared memory locations. There is no need
......@@ -911,7 +910,7 @@ schedule( void )
#else
cap = &MainRegTable;
#endif
cap->rCurrentTSO = t;
/* context switches are now initiated by the timer signal, unless
......@@ -2093,7 +2092,7 @@ take_off_run_queue(StgTSO *tso) {
KH @ 25/10/99
*/
static void GetRoots(void)
static void GetRoots(evac_fn evac)
{
StgMainThread *m;
......@@ -2102,16 +2101,16 @@ static void GetRoots(void)
nat i;
for (i=0; i<=RtsFlags.GranFlags.proc; i++) {
if ((run_queue_hds[i] != END_TSO_QUEUE) && ((run_queue_hds[i] != NULL)))
run_queue_hds[i] = (StgTSO *)MarkRoot((StgClosure *)run_queue_hds[i]);
evac((StgClosure **)&run_queue_hds[i]);
if ((run_queue_tls[i] != END_TSO_QUEUE) && ((run_queue_tls[i] != NULL)))
run_queue_tls[i] = (StgTSO *)MarkRoot((StgClosure *)run_queue_tls[i]);
evac((StgClosure **)&run_queue_tls[i]);
if ((blocked_queue_hds[i] != END_TSO_QUEUE) && ((blocked_queue_hds[i] != NULL)))
blocked_queue_hds[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hds[i]);
evac((StgClosure **)&blocked_queue_hds[i]);
if ((blocked_queue_tls[i] != END_TSO_QUEUE) && ((blocked_queue_tls[i] != NULL)))
blocked_queue_tls[i] = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tls[i]);
evac((StgClosure **)&blocked_queue_tls[i]);
if ((ccalling_threadss[i] != END_TSO_QUEUE) && ((ccalling_threadss[i] != NULL)))
ccalling_threadss[i] = (StgTSO *)MarkRoot((StgClosure *)ccalling_threadss[i]);
evac((StgClosure **)&ccalling_threads[i]);
}
}
......@@ -2119,31 +2118,31 @@ static void GetRoots(void)
#else /* !GRAN */
if (run_queue_hd != END_TSO_QUEUE) {
ASSERT(run_queue_tl != END_TSO_QUEUE);
run_queue_hd = (StgTSO *)MarkRoot((StgClosure *)run_queue_hd);
run_queue_tl = (StgTSO *)MarkRoot((StgClosure *)run_queue_tl);
ASSERT(run_queue_tl != END_TSO_QUEUE);
evac((StgClosure **)&run_queue_hd);
evac((StgClosure **)&run_queue_tl);
}
if (blocked_queue_hd != END_TSO_QUEUE) {
ASSERT(blocked_queue_tl != END_TSO_QUEUE);
blocked_queue_hd = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hd);
blocked_queue_tl = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tl);
ASSERT(blocked_queue_tl != END_TSO_QUEUE);
evac((StgClosure **)&blocked_queue_hd);
evac((StgClosure **)&blocked_queue_tl);
}
if (sleeping_queue != END_TSO_QUEUE) {
sleeping_queue = (StgTSO *)MarkRoot((StgClosure *)sleeping_queue);
evac((StgClosure **)&sleeping_queue);
}
#endif
for (m = main_threads; m != NULL; m = m->link) {
m->tso = (StgTSO *)MarkRoot((StgClosure *)m->tso);
evac((StgClosure **)&m->tso);
}
if (suspended_ccalling_threads != END_TSO_QUEUE) {
evac((StgClosure **)&suspended_ccalling_threads);
}
if (suspended_ccalling_threads != END_TSO_QUEUE)
suspended_ccalling_threads =
(StgTSO *)MarkRoot((StgClosure *)suspended_ccalling_threads);
#if defined(SMP) || defined(PAR) || defined(GRAN)
markSparkQueue();
markSparkQueue(evac);
#endif
}
......@@ -2160,7 +2159,7 @@ static void GetRoots(void)
This needs to be protected by the GC condition variable above. KH.
-------------------------------------------------------------------------- */
void (*extra_roots)(void);
void (*extra_roots)(evac_fn);
void
performGC(void)
......@@ -2175,17 +2174,16 @@ performMajorGC(void)
}
static void
AllRoots(void)
AllRoots(evac_fn evac)
{
GetRoots(); /* the scheduler's roots */
extra_roots(); /* the user's roots */
GetRoots(evac); // the scheduler's roots
extra_roots(evac); // the user's roots
}
void
performGCWithRoots(void (*get_roots)(void))
performGCWithRoots(void (*get_roots)(evac_fn))
{
extra_roots = get_roots;
GarbageCollect(AllRoots,rtsFalse);
}
......@@ -2248,7 +2246,7 @@ threadStackOverflow(StgTSO *tso)
dest->stack_size = new_stack_size;
/* and relocate the update frame list */
relocate_TSO(tso, dest);
relocate_stack(dest, diff);
/* Mark the old TSO as relocated. We have to check for relocated
* TSOs in the garbage collector and any primops that deal with TSOs.
......
This diff is collapsed.
/* -----------------------------------------------------------------------------
* $Id: StablePriv.h,v 1.2 1999/02/05 16:02:56 simonm Exp $
* $Id: StablePriv.h,v 1.3 2001/07/23 17:23:20 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
......@@ -7,8 +7,11 @@
*
* ---------------------------------------------------------------------------*/
extern void initStablePtrTable(void);
extern void markStablePtrTable(rtsBool full);
extern void enlargeStablePtrTable(void);
extern void gcStablePtrTable(rtsBool full);
extern StgWord lookupStableName(StgPtr p);
extern void initStablePtrTable ( void );
extern void enlargeStablePtrTable ( void );
extern StgWord lookupStableName ( StgPtr p );
extern void markStablePtrTable ( evac_fn evac );
extern void threadStablePtrTable ( evac_fn evac );
extern void gcStablePtrTable ( void );
extern void updateStablePtrTable ( rtsBool full );
This diff is collapsed.
/* -----------------------------------------------------------------------------
* $Id: Stats.h,v 1.10 2000/12/19 14:30:39 simonmar Exp $
* $Id: Stats.h,v 1.11 2001/07/23 17:23:20 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
......@@ -22,8 +22,8 @@ extern void stat_workerStop(void);
extern void initStats(void);
extern void stat_describe_gens(void);
extern double mut_user_time_during_GC(void);
extern double mut_user_time(void);
extern void statDescribeGens( void );
extern HsInt getAllocations( void );
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment