Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #817 from rainers/gc_config
Browse files Browse the repository at this point in the history
make GC configurable through environment variable
  • Loading branch information
MartinNowak committed Oct 6, 2014
2 parents eb18ee3 + 3d9413a commit f400e66
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 33 deletions.
1 change: 1 addition & 0 deletions mak/MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ MANIFEST=\
src\gc\gc.d \
src\gc\os.d \
src\gc\bits.d \
src\gc\config.d \
src\gc\stats.d \
src\gc\proxy.d \
\
Expand Down
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ SRCS=\
src\gc\gc.d \
src\gc\os.d \
src\gc\bits.d \
src\gc\config.d \
src\gc\stats.d \
src\gc\proxy.d \
\
Expand Down
137 changes: 137 additions & 0 deletions src/gc/config.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* Contains the garbage collector configuration.
*
* Copyright: Copyright Digital Mars 2014
* License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
*/

module gc.config;

// to add the possiblity to configure the GC from the outside, add gc.config
// with one of these versions to the executable build command line, e.g.
// dmd -version=initGCFromEnvironment main.c /path/to/druntime/src/gc/config.d

//version = initGCFromEnvironment; // read settings from environment variable D_GC
version = initGCFromCommandLine; // read settings from command line argument "--DRT-gcopt=options"

version(initGCFromEnvironment)
version = configurable;
version(initGCFromCommandLine)
version = configurable;

import core.stdc.stdlib;
import core.stdc.stdio;
import core.stdc.ctype;
import core.stdc.string;
import core.vararg;

extern extern(C) string[] rt_args();

struct Config
{
bool disable; // start disabled
bool profile; // enable profiling with summary when terminating program
bool precise; // enable precise scanning
bool concurrent; // enable concurrent collection

size_t initReserve; // initial reserve (MB)
size_t minPoolSize = 1; // initial and minimum pool size (MB)
size_t maxPoolSize = 32; // maximum pool size (MB)
size_t incPoolSize = 3; // pool size increment (MB)

bool initialize(...) // avoid inlining
{
version(initGCFromEnvironment)
{
auto p = getenv("D_GC");
if (p)
if (!parseOptions(p[0 .. strlen(p)]))
return false;
}
version(initGCFromCommandLine)
{
foreach (a; rt_args)
{
if(a.length >= 12 && a[0..12] == "--DRT-gcopt=")
if (!parseOptions(a[12 .. $]))
return false;
}
}
return true;
}

version (configurable):

string help() @nogc
{
return "GC options are specified as white space separated assignments:
disable=0|1 - start disabled
profile=0|1 - enable profiling with summary when terminating program
precise=0|1 - enable precise scanning (not implemented yet)
concurrent=0|1 - enable concurrent collection (not implemented yet)
initReserve=N - initial memory to reserve (MB), default 0
minPoolSize=N - initial and minimum pool size (MB), default 1
maxPoolSize=N - maximum pool size (MB), default 32
incPoolSize=N - pool size increment (MB), defaut 3
";
}

bool parseOptions(const(char)[] opt) @nogc
{
size_t p = 0;
while(p < opt.length)
{
while (p < opt.length && isspace(opt[p]))
p++;
if (p >= opt.length)
break;
auto q = p;
while (q < opt.length && opt[q] != '=' && !isspace(opt[q]))
q++;

auto s = opt[p .. q];
if(s == "help")
{
printf("%s", help().ptr);
p = q;
}
else if (q < opt.length)
{
auto r = q + 1;
size_t v = 0;
for ( ; r < opt.length && isdigit(opt[r]); r++)
v = v * 10 + opt[r] - '0';

if(s == "disable")
disable = v != 0;
else if(s == "profile")
profile = v != 0;
else if(s == "precise")
precise = v != 0;
else if(s == "concurrent")
concurrent = v != 0;
else if(s == "initReserve")
initReserve = v;
else if(s == "minPoolSize")
minPoolSize = v;
else if(s == "maxPoolSize")
maxPoolSize = v;
else if(s == "incPoolSize")
incPoolSize = v;
else
{
printf("Unknown GC option \"%.*s\"\n", cast(int) s.length, s.ptr);
return false;
}
p = r;
}
else
{
printf("Incomplete GC option \"%.*s\"\n", cast(int) s.length, s.ptr);
return false;
}
}
return true;
}
}
72 changes: 46 additions & 26 deletions src/gc/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ module gc.gc;
//debug = SENTINEL; // add underrun/overrrun protection
//debug = PTRCHECK; // more pointer checking
//debug = PTRCHECK2; // thorough but slow pointer checking
//debug = PROFILING; // measure performance of various steps.
//debug = INVARIANT; // enable invariants
//debug = CACHE_HITRATE; // enable hit rate measure

Expand All @@ -40,6 +39,7 @@ version = STACKGROWSDOWN; // growing the stack means subtracting from the
import gc.bits;
import gc.stats;
import gc.os;
import gc.config;

import rt.util.container.treap;

Expand Down Expand Up @@ -93,16 +93,14 @@ debug(PRINTF) void printFreeInfo(Pool* pool) nothrow
printf("Pool %p: %d really free, %d supposedly free\n", pool, nReallyFree, pool.freepages);
}

debug(PROFILING)
{
// Track total time spent preparing for GC,
// marking, sweeping and recovering pages.
import core.stdc.stdio, core.stdc.time;
__gshared long prepTime;
__gshared long markTime;
__gshared long sweepTime;
__gshared long recoverTime;
}
// Track total time spent preparing for GC,
// marking, sweeping and recovering pages.
import core.stdc.stdio, core.stdc.time;
__gshared long prepTime;
__gshared long markTime;
__gshared long sweepTime;
__gshared long recoverTime;
__gshared size_t maxPoolMemory;

private
{
Expand Down Expand Up @@ -265,15 +263,24 @@ class GC
__gshared GCMutex gcLock; // global lock
__gshared byte[__traits(classInstanceSize, GCMutex)] mutexStorage;

__gshared Config config;

void initialize()
{
config.initialize();

mutexStorage[] = typeid(GCMutex).init[];
gcLock = cast(GCMutex) mutexStorage.ptr;
gcLock.__ctor();
gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof);
if (!gcx)
onOutOfMemoryError();
gcx.initialize();

if (config.initReserve)
gcx.reserve(config.initReserve << 20);
if (config.disable)
gcx.disabled++;
}


Expand Down Expand Up @@ -1435,7 +1442,7 @@ struct Gcx

void Dtor()
{
debug(PROFILING)
if (GC.config.profile)
{
printf("\tTotal GC prep time: %d milliseconds\n",
prepTime * 1000 / CLOCKS_PER_SEC);
Expand All @@ -1445,9 +1452,11 @@ struct Gcx
sweepTime * 1000 / CLOCKS_PER_SEC);
printf("\tTotal page recovery time: %d milliseconds\n",
recoverTime * 1000 / CLOCKS_PER_SEC);
long pauseTime = recoverTime + sweepTime + markTime + prepTime;
printf("\tGrand total GC time: %d milliseconds\n",
1000 * (recoverTime + sweepTime + markTime + prepTime)
/ CLOCKS_PER_SEC);
pauseTime * 1000 / CLOCKS_PER_SEC);
printf("maxPoolMemory = %lld MB, pause time = %lld ms\n",
cast(long) maxPoolMemory >> 20, 1000 * pauseTime / CLOCKS_PER_SEC);
}

debug(CACHE_HITRATE)
Expand Down Expand Up @@ -2213,9 +2222,10 @@ struct Gcx
//debug(PRINTF) printf("************Gcx::newPool(npages = %d)****************\n", npages);

// Minimum of POOLSIZE
if (npages < POOLSIZE/PAGESIZE)
npages = POOLSIZE/PAGESIZE;
else if (npages > POOLSIZE/PAGESIZE)
size_t minPages = (GC.config.minPoolSize << 20) / PAGESIZE;
if (npages < minPages)
npages = minPages;
else if (npages > minPages)
{ // Give us 150% of requested size, so there's room to extend
auto n = npages + (npages >> 1);
if (n < size_t.max/PAGESIZE)
Expand All @@ -2226,9 +2236,10 @@ struct Gcx
if (npools)
{ size_t n;

n = npools * 3;

n *= (POOLSIZE / PAGESIZE);
n = GC.config.minPoolSize + GC.config.incPoolSize * npools;
if (n > GC.config.maxPoolSize)
n = GC.config.maxPoolSize; // cap pool size
n *= (1 << 20) / PAGESIZE; // convert MB to pages
if (npages < n)
npages = n;
}
Expand Down Expand Up @@ -2262,6 +2273,15 @@ struct Gcx
minAddr = pooltable[0].baseAddr;
maxAddr = pooltable[npools - 1].topAddr;
}

if (GC.config.profile)
{
size_t gcmem = 0;
for(i = 0; i < npools; i++)
gcmem += pooltable[i].topAddr - pooltable[i].baseAddr;
if(gcmem > maxPoolMemory)
maxPoolMemory = gcmem;
}
return pool;

Lerr:
Expand Down Expand Up @@ -2445,10 +2465,10 @@ struct Gcx
{
size_t n;
Pool* pool;
clock_t start, stop;

debug(PROFILING)
if (GC.config.profile)
{
clock_t start, stop;
start = clock();
}

Expand Down Expand Up @@ -2495,7 +2515,7 @@ struct Gcx
}
}

debug(PROFILING)
if (GC.config.profile)
{
stop = clock();
prepTime += (stop - start);
Expand Down Expand Up @@ -2590,7 +2610,7 @@ struct Gcx
thread_processGCMarks(&isMarked);
thread_resumeAll();

debug(PROFILING)
if (GC.config.profile)
{
stop = clock();
markTime += (stop - start);
Expand Down Expand Up @@ -2711,7 +2731,7 @@ struct Gcx
}
}

debug(PROFILING)
if (GC.config.profile)
{
stop = clock();
sweepTime += (stop - start);
Expand Down Expand Up @@ -2772,7 +2792,7 @@ struct Gcx
}
}

debug(PROFILING)
if (GC.config.profile)
{
stop = clock();
recoverTime += (stop - start);
Expand Down
22 changes: 15 additions & 7 deletions src/rt/dmain2.d
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ extern (C) string[] rt_args()
return _d_args;
}

// make arguments passed to main available for being filtered by runtime initializers
extern(C) __gshared char[][] _d_main_args = null;

// This variable is only ever set by a debugger on initialization so it should
// be fine to leave it as __gshared.
extern (C) __gshared bool rt_trapExceptions = true;
Expand Down Expand Up @@ -353,21 +356,26 @@ extern (C) int _d_run_main(int argc, char **argv, MainFunc mainFunc)
else
static assert(0);

/* Create a copy of args[] on the stack, and set the global _d_args to refer to it.
* Why a copy instead of just using args[] is unclear.
* This also means that when this function returns, _d_args will refer to garbage.
/* Create a copy of args[] on the stack to be used for main, so that rt_args()
* cannot be modified by the user.
* Note that when this function returns, _d_args will refer to garbage.
*/
{
_d_args = cast(string[]) args;
auto buff = cast(char[]*) alloca(args.length * (char[]).sizeof + totalArgsLength);

char[][] argsCopy = buff[0 .. args.length];
auto argBuff = cast(char*) (buff + args.length);
foreach(i, arg; args)
size_t j = 0;
foreach(arg; args)
{
argsCopy[i] = (argBuff[0 .. arg.length] = arg[]);
argBuff += arg.length;
if (arg.length < 6 || arg[0..6] != "--DRT-") // skip D runtime options
{
argsCopy[j++] = (argBuff[0 .. arg.length] = arg[]);
argBuff += arg.length;
}
}
_d_args = cast(string[]) argsCopy;
args = argsCopy[0..j];
}

bool trapExceptions = rt_trapExceptions;
Expand Down

0 comments on commit f400e66

Please sign in to comment.