#ifndef RTS_STORAGE_MBLOCK_H
#define RTS_STORAGE_MBLOCK_H
+extern lnat peak_mblocks_allocated;
extern lnat mblocks_allocated;
extern void initMBlocks(void);
extern void * getMBlock(void);
extern void * getMBlocks(nat n);
+extern void freeMBlocks(void *addr, nat n);
extern void freeAllMBlocks(void);
-#ifdef DEBUG
extern void *getFirstMBlock(void);
extern void *getNextMBlock(void *mblock);
-#endif
#ifdef THREADED_RTS
// needed for HEAP_ALLOCED below
AvgResidency*sizeof(W_)/ResidencySamples,
MaxResidency*sizeof(W_),
ResidencySamples,
- (unsigned long)(mblocks_allocated * MBLOCK_SIZE / (1024L * 1024L)),
+ (unsigned long)(peak_mblocks_allocated * MBLOCK_SIZE / (1024L * 1024L)),
TICK_TO_DBL(InitUserTime), TICK_TO_DBL(InitElapsedTime),
TICK_TO_DBL(MutUserTime), TICK_TO_DBL(MutElapsedTime),
TICK_TO_DBL(GC_tot_time), TICK_TO_DBL(GCe_tot_time));
#include <mach/vm_map.h>
#endif
-/* keep track of maps returned by my_mmap */
-typedef struct _map_rec {
- char* base; /* base addr */
- int size; /* map size */
- struct _map_rec* next; /* next pointer */
-} map_rec;
-
-
static caddr_t next_request = 0;
-static map_rec* mmap_rec = NULL;
void osMemInit(void)
{
{
caddr_t ret;
lnat size = MBLOCK_SIZE * (lnat)n;
- map_rec* rec;
if (next_request == 0) {
// use gen_map_mblocks the first time.
ret = gen_map_mblocks(size);
}
}
- rec = (map_rec*)stgMallocBytes(sizeof(map_rec),"OSMem: osGetMBlocks");
- rec->size = size;
- rec->base = ret;
- rec->next = mmap_rec;
- mmap_rec = rec;
// Next time, we'll try to allocate right after the block we just got.
// ToDo: check that we haven't already grabbed the memory at next_request
next_request = ret + size;
return ret;
}
-void osFreeAllMBlocks(void)
+void osFreeMBlocks(char *addr, nat n)
{
- map_rec* tmp = mmap_rec;
- map_rec* next = NULL;
+ munmap(addr, n * MBLOCK_SIZE);
+}
- for(; tmp!=NULL;) {
- if(munmap(tmp->base,tmp->size))
- barf("osFreeAllMBlocks: munmap failed!");
+void osFreeAllMBlocks(void)
+{
+ void *mblock;
- next = tmp->next;
- stgFree(tmp);
- tmp = next;
+ for (mblock = getFirstMBlock();
+ mblock != NULL;
+ mblock = getNextMBlock(mblock)) {
+ munmap(mblock, MBLOCK_SIZE);
}
}
#include "Storage.h"
#include "RtsUtils.h"
#include "BlockAlloc.h"
+#include "OSMem.h"
#include <string.h>
return n;
}
+void returnMemoryToOS(nat n /* megablocks */)
+{
+ static bdescr *bd;
+ nat size;
+
+ bd = free_mblock_list;
+ while ((n > 0) && (bd != NULL)) {
+ size = BLOCKS_TO_MBLOCKS(bd->blocks);
+ if (size > n) {
+ nat newSize = size - n;
+ char *freeAddr = MBLOCK_ROUND_DOWN(bd->start);
+ freeAddr += newSize * MBLOCK_SIZE;
+ bd->blocks = MBLOCK_GROUP_BLOCKS(newSize);
+ freeMBlocks(freeAddr, n);
+ n = 0;
+ }
+ else {
+ char *freeAddr = MBLOCK_ROUND_DOWN(bd->start);
+ n -= size;
+ bd = bd->link;
+ freeMBlocks(freeAddr, size);
+ }
+ }
+ free_mblock_list = bd;
+
+ IF_DEBUG(gc,
+ if (n != 0) {
+ debugBelch("Wanted to free %d more MBlocks than are freeable\n",
+ n);
+ }
+ );
+}
+
/* -----------------------------------------------------------------------------
Debugging
-------------------------------------------------------------------------- */
extern nat countBlocks (bdescr *bd);
extern nat countAllocdBlocks (bdescr *bd);
+extern void returnMemoryToOS(nat n);
#ifdef DEBUG
void checkFreeListSanity(void);
scheduleFinalizers(cap, old_weak_ptr_list);
ACQUIRE_SM_LOCK;
+ if (major_gc) {
+ nat need, got;
+ need = BLOCKS_TO_MBLOCKS(n_alloc_blocks);
+ got = mblocks_allocated;
+ /* If the amount of data remains constant, next major GC we'll
+ require (F+1)*need. We leave (F+2)*need in order to reduce
+ repeated deallocation and reallocation. */
+ need = (RtsFlags.GcFlags.oldGenFactor + 2) * need;
+ if (got > need) {
+ returnMemoryToOS(got - need);
+ }
+ }
+
// check sanity after GC
IF_DEBUG(sanity, checkSanity(rtsTrue));
#include <string.h>
+lnat peak_mblocks_allocated = 0;
lnat mblocks_allocated = 0;
lnat mpc_misses = 0;
StgWord8 mblock_map[MBLOCK_MAP_SIZE]; // initially all zeros
static void
-markHeapAlloced(void *p)
+setHeapAlloced(void *p, StgWord8 i)
{
- mblock_map[MBLOCK_MAP_ENTRY(p)] = 1;
+ mblock_map[MBLOCK_MAP_ENTRY(p)] = i;
}
#elif SIZEOF_VOID_P == 8
}
static void
-markHeapAlloced(void *p)
+setHeapAlloced(void *p, StgWord8 i)
{
MBlockMap *map = findMBlockMap(p);
if(map == NULL)
map->addrHigh32 = (StgWord32) (((StgWord)p) >> 32);
}
- map->lines[MBLOCK_MAP_LINE(p)] = 1;
+ map->lines[MBLOCK_MAP_LINE(p)] = i;
{
StgWord mblock;
mblock = (StgWord)p >> MBLOCK_SHIFT;
entry_no = mblock & (MBC_ENTRIES-1);
- mblock_cache[entry_no] = (mblock << 1) + 1;
+ mblock_cache[entry_no] = (mblock << 1) + i;
}
}
#endif
-/* ----------------------------------------------------------------------------
- Debugging code for traversing the allocated MBlocks
-
- This is used for searching for lost blocks when a memory leak is
- detected; see Blocks.c:findUnmarkedBlock().
- ------------------------------------------------------------------------ */
+static void
+markHeapAlloced(void *p)
+{
+ setHeapAlloced(p, 1);
+}
-#ifdef DEBUG
+static void
+markHeapUnalloced(void *p)
+{
+ setHeapAlloced(p, 0);
+}
#if SIZEOF_VOID_P == 4
#endif // SIZEOF_VOID_P
-#endif // DEBUG
-
/* -----------------------------------------------------------------------------
Allocate new mblock(s)
-------------------------------------------------------------------------- */
}
mblocks_allocated += n;
+ peak_mblocks_allocated = stg_max(peak_mblocks_allocated, mblocks_allocated);
return ret;
}
void
+freeMBlocks(void *addr, nat n)
+{
+ nat i;
+
+ debugTrace(DEBUG_gc, "freeing %d megablock(s) at %p",n,addr);
+
+ mblocks_allocated -= n;
+
+ for (i = 0; i < n; i++) {
+ markHeapUnalloced( (StgWord8*)addr + i * MBLOCK_SIZE );
+ }
+
+ osFreeMBlocks(addr, n);
+}
+
+void
freeAllMBlocks(void)
{
+ debugTrace(DEBUG_gc, "freeing all megablocks");
osFreeAllMBlocks();
}
void osMemInit(void);
void *osGetMBlocks(nat n);
+void osFreeMBlocks(char *addr, nat n);
void osFreeAllMBlocks(void);
lnat getPageSize (void);
void setExecutable (void *p, lnat len, rtsBool exec);
return ret;
}
+void osFreeMBlocks(char *addr, nat n)
+{
+ alloc_rec *p;
+ lnat nBytes = (lnat)n * MBLOCK_SIZE;
+
+ insertFree(addr, nBytes);
+
+ p = allocs;
+ while ((p != NULL) && (addr >= (p->base + p->size))) {
+ p = p->next;
+ }
+ while (nBytes > 0) {
+ if ((p == NULL) || (p->base > addr)) {
+ errorBelch("Memory to be freed isn't allocated\n");
+ stg_exit(EXIT_FAILURE);
+ }
+ if (p->base + p->size >= addr + nBytes) {
+ if (!VirtualFree(addr, nBytes, MEM_DECOMMIT)) {
+ sysErrorBelch("osFreeMBlocks: VirtualFree MEM_DECOMMIT failed");
+ stg_exit(EXIT_FAILURE);
+ }
+ nBytes = 0;
+ }
+ else {
+ lnat bytesToFree = p->base + p->size - addr;
+ if (!VirtualFree(addr, bytesToFree, MEM_DECOMMIT)) {
+ sysErrorBelch("osFreeMBlocks: VirtualFree MEM_DECOMMIT failed");
+ stg_exit(EXIT_FAILURE);
+ }
+ addr += bytesToFree;
+ nBytes -= bytesToFree;
+ p = p->next;
+ }
+ }
+}
+
void
osFreeAllMBlocks(void)
{