/**************************************************************************** ** ** This file is part of GAP, a system for computational discrete algebra. ** ** Copyright of GAP belongs to its developers, whose names are too numerous ** to list here. Please refer to the COPYRIGHT file for details. ** ** SPDX-License-Identifier: GPL-2.0-or-later ** ** This file implements functions and variables related to memory management, ** for use by GASMAN. **
*/
/**************************************************************************** ** *F SyMsgsBags( <full>, <phase>, <nr> ) . . . . . . . display Gasman messages ** ** 'SyMsgsBags' is the function that is used by Gasman to display messages ** during garbage collections.
*/
Int SyGasmanNumbers[2][9];
void SyMsgsBags (
UInt full,
UInt phase, Int nr )
{ Char cmd [3]; // command string buffer Char str [32]; // string buffer Char ch; // leading character
UInt i; // loop variable Int copynr; // copy of <nr>
UInt shifted; // non-zero if nr > 10^6 and so has to be shifted down static UInt tstart = 0;
// remember the numbers if (phase > 0)
{
SyGasmanNumbers[full][phase] = nr;
// in a full GC clear the partial numbers if (full)
SyGasmanNumbers[0][phase] = 0;
} else
{
SyGasmanNumbers[full][0]++;
tstart = SyTime();
} if (phase == 6)
{
UInt x = SyTime() - tstart;
SyGasmanNumbers[full][7] = x;
SyGasmanNumbers[full][8] += x;
}
// convert <nr> into a string with leading blanks
copynr = nr;
ch = '0'; str[7] = '\0';
shifted = (nr >= ((phase % 2) ? 10000000 : 1000000)) ? 1 : 0; if (shifted)
{
nr /= 1024;
} if ((phase % 2) == 1 && shifted && nr > 1000000)
{
shifted++;
nr /= 1024;
}
for ( i = ((phase % 2) == 1 && shifted) ? 6 : 7 ;
i != 0; i-- ) { if ( 0 < nr ) { str[i-1] = '0' + ( nr) % 10; ch = ' '; } elseif ( nr < 0 ) { str[i-1] = '0' + (-nr) % 10; ch = '-'; } else { str[i-1] = ch; ch = ' '; }
nr = nr / 10;
}
nr = copynr;
/**************************************************************************** ** *f SyAllocBags( <size>, <need> ) ** ** For UNIX, 'SyAllocBags' calls 'sbrk', which will work on most systems. ** ** Note that it may happen that another function has called 'sbrk' ** between two calls to 'SyAllocBags', so that the next allocation will ** not be immediately adjacent to the last one. In this case 'SyAllocBags' ** returns the area to the operating system, and either returns 0 if <need> ** was 0 or aborts GAP if <need> was 1. 'SyAllocBags' will refuse to extend ** the workspace beyond 'SyStorMax' or to reduce it below 'SyStorMin'.
*/
static UInt pagesize = 4096; // Will be initialised if SyAllocPool > 0
staticinline UInt SyRoundUpToPagesize(UInt x)
{
UInt r;
r = x % pagesize; return r == 0 ? x : x - r + pagesize;
}
/*************************************************************** * GAP_MEM_CHECK * * The following code is used by GAP_MEM_CHECK support, which is * documented in gasman.c
*/
#if !defined(HAVE_MADVISE) || !defined(SYS_IS_64_BIT) #error GAP_MEM_CHECK requires MADVISE and 64-bit OS #endif
if (fd < 0) {
Panic("Fatal error setting up multiheap");
}
if (ftruncate(fd, size) < 0) {
Panic("Fatal error setting up multiheap!");
}
for (int i = 0; i < membufcount; ++i) {
membufs[i] =
mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (membufs[i] == MAP_FAILED) {
Panic("Fatal error setting up multiheap!!");
}
}
// Sort the membufs, so membufs[0] is the first in memory. // We will always refer to the copy of the master pointers in // membufs[0].
qsort(membufs, membufcount, sizeof(void *), order_pointers); return membufs[0];
}
staticvoid *SyMMapStart = NULL; // Start of mmap'ed region for POOL staticvoid *SyMMapEnd; // End of mmap'ed region for POOL staticvoid *SyMMapAdvised; // We have already advised about non-usage // up to here.
void SyMAdviseFree(void)
{
size_t size; void *from; if (!SyMMapStart) return;
from = EndOfWorkspace();
from = (void *)SyRoundUpToPagesize((UInt) from); if (from > SyMMapAdvised) {
SyMMapAdvised = from; return;
} if (from < SyMMapStart || from >= SyMMapEnd || from >= SyMMapAdvised) return;
size = (char *)SyMMapAdvised - (char *)from; #ifdefined(MADV_FREE)
madvise(from, size, MADV_FREE); #elifdefined(MADV_DONTNEED)
madvise(from, size, MADV_DONTNEED); #endif
SyMMapAdvised = from; /* On Darwin, MADV_FREE and MADV_DONTNEED will not actually update * a process's resident memory until those pages are explicitly * unmapped or needed elsewhere. * * The following code accomplishes this, but is not portable and * potentially not safe, since the POSIX standard does not make * any sufficiently strong promises with regard to the use of * MAP_FIXED. * * We probably don't want to do this and just live with pages * remaining with a process until reused even if that appears to * inflate the resident set size. * * Maybe we do want to do this until it breaks to avoid questions * by users...
*/ #if !defined(NO_DIRTY_OSX_MMAP_TRICK) && defined(__APPLE__) if (mmap(from, size, PROT_NONE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) != from) {
Panic("macOS trick to free pages did not work!");
} if (mmap(from, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) != from) {
Panic("macOS trick to free pages did not work!!");
} #endif
}
staticvoid * SyAnonMMap(size_t size)
{ void *result;
size = SyRoundUpToPagesize(size); #ifdef SYS_IS_64_BIT // The following is at 16 Terabyte:
result = mmap((void *) (16L*1024*1024*1024*1024), size,
PROT_READ|PROT_WRITE, GAP_MMAP_FLAGS, -1, 0); if (result == MAP_FAILED) {
result = mmap(NULL, size, PROT_READ|PROT_WRITE,
GAP_MMAP_FLAGS, -1, 0);
} #else
result = mmap(NULL, size, PROT_READ|PROT_WRITE,
GAP_MMAP_FLAGS, -1, 0); #endif if (result == MAP_FAILED)
result = NULL;
SyMMapStart = result;
SyMMapEnd = (char *)result + size;
SyMMapAdvised = (char *)result + size; return result;
}
// This tries to increase the pool size by a factor of 3/2, if this // worked, then 0 is returned, otherwise -1. staticint SyTryToIncreasePool(void)
{ void *result;
size_t size;
size_t newchunk;
staticvoid SyInitialAllocPool(void)
{ #ifdef HAVE_SYSCONF
pagesize = sysconf(_SC_PAGESIZE); #endif // Otherwise we take the default of 4k as pagesize.
do { // Always round up to pagesize:
SyAllocPool = SyRoundUpToPagesize(SyAllocPool); #ifdef HAVE_MADVISE
POOL = SyAnonMMap(SyAllocPool+pagesize); // For alignment #else
POOL = calloc(SyAllocPool+pagesize,1); // For alignment #endif if (POOL != NULL) { // fprintf(stderr,"Pool size is %lx.\n",SyAllocPool); break;
}
SyAllocPool = SyAllocPool / 2; if (SyDebugLoading) fputs("gap: halving pool size.\n", stderr); if (SyAllocPool < 16*1024*1024) {
Panic("cannot allocate initial memory");
}
} while (1); // Is left by break
// ensure alignment of start address
syWorkspace = (UInt***)(SyRoundUpToPagesize((UInt) POOL)); // Now both syWorkspace and SyAllocPool are aligned to pagesize
}
// get the storage, but only if we stay within the bounds while ((syWorksize + size) * 1024 > SyAllocPool) { if (SyTryToIncreasePool()) return INVALID_PTR;
}
UInt *** ret = EndOfWorkspace();
syWorksize += size; return ret;
}
// force alignment on first call if (syWorkspace == 0) {
UInt align = (UInt)sbrk(0) % sizeof(UInt); if (align != 0)
syWorkspace = (UInt***)sbrk(sizeof(UInt) - align);
syWorkspace = (UInt***)sbrk( 0 );
}
// get the storage #ifndef SYS_IS_64_BIT
UInt adjust = 0; // on 32bit systems, call sbrk with at most 1 GB at a time, // to avoid integer overflow while (size >= 1024*1024) {
ret = SyAllocBagHelper(1024); if (ret == INVALID_PTR) break;
size -= 1024*1024;
syWorksize += 1024*1024;
adjust++;
} // try to allocate the rest, if any if (size < 1024*1024)
ret = SyAllocBagHelper(size); if (ret != INVALID_PTR) { while (adjust--)
ret = (UInt ***)(((Char *)ret) - 1024 * 1024 * 1024);
} #else // allocate all at once
ret = SyAllocBagHelper(size); #endif
if (ret != INVALID_PTR) { // update the size info
syWorksize += size;
}
// check that <size> is divisible by <vm_page_size> if ( size*1024 % vm_page_size != 0 ) {
Panic("memory block size is not a multiple of vm_page_size");
}
// allocate memory anywhere on first call elseif ( 0 < size && syBase == 0 ) {
GAP_ASSERT(syWorksize == 0); if ( vm_allocate(mach_task_self(),&syBase,size*1024,TRUE) == KERN_SUCCESS ) {
ret = (UInt***) syBase;
}
}
// get more memory from system else {
vm_address_t adr;
adr = (vm_address_t)( (char*) syBase + syWorksize*1024 ); if ( vm_allocate(mach_task_self(),&adr,size*1024,FALSE) == KERN_SUCCESS ) {
ret = (UInt***) ( (char*) syBase + syWorksize*1024 );
}
}
if (ret != INVALID_PTR) { // update the size info
syWorksize += size;
}
// check that <size> is divisible by <vm_page_size> if ( size*1024 % vm_page_size != 0 ) {
Panic("memory block size is not a multiple of vm_page_size");
}
// check that we don't try to shrink uninitialized memory elseif ( syBase == 0 ) {
Panic("trying to shrink uninitialized vm memory");
}
// don't shrink memory but mark it as deactivated elseif (syWorksize >= size && syWorksize - size >= SyStorMin) {
vm_address_t adr;
adr = (vm_address_t)( (char*) syBase + (syWorksize-size)*1024 ); if ( vm_deallocate(mach_task_self(),adr,size*1024) == KERN_SUCCESS ) {
ret = (UInt***)( (char*) syBase + syWorksize*1024 );
// first check if we would get above SyStorKill, if yes exit! if (SyStorKill != 0 && SyStorKill < syWorksize + size) { if (need) {
Panic("will not extend workspace above -K limit!");
} return 0;
} elseif (SyAllocPool > 0) { // initialize allocation pool if necessary; this aborts if it fails if (POOL == NULL)
SyInitialAllocPool();
ret = SyAllocBagsFromPool(size);
} else { #ifdefined(HAVE_SBRK) || defined(HAVE_VM_ALLOCATE)
ret = SyAllocBags_(size); #else
Panic("running without allocation pool not supported on this architecture"); #endif
}
// handle allocation failures if (ret == INVALID_PTR) { if (need) {
Panic("cannot extend the workspace any more!");
} return 0;
}
// set the overrun flag if we became larger than SyStorMax if (SyStorMax != 0 && syWorksize > SyStorMax) {
SyStorOverrun = SY_STOR_OVERRUN_TO_REPORT;
SyStorMax = syWorksize * 2; // new maximum
InterruptExecStat(); // interrupt at the next possible point
}
return ret;
}
Int SyFreeBags(Int size)
{
GAP_ASSERT(size > 0);
if (SyAllocPool > 0) { return SyFreeBagsFromPool(size);
} else { #ifdefined(HAVE_SBRK) || defined(HAVE_VM_ALLOCATE) return SyFreeBags_(size) != INVALID_PTR; #else
Panic("running without allocation pool not supported on this architecture"); #endif
}
}
void SyFreeAllBags(void)
{ // for now, do nothing
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.21Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.