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

Modify GC.stats to allow requesting specific stats #2193

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 60 additions & 3 deletions src/core/memory.d
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ private
}

extern (C) BlkInfo_ gc_query( void* p ) pure nothrow;
extern (C) GC.Stats gc_stats ( ) nothrow @nogc;
extern (C) GC.Stats gc_stats ( ulong fields ) nothrow @nogc;

extern (C) void gc_addRoot( in void* p ) nothrow @nogc;
extern (C) void gc_addRange( in void* p, size_t sz, const TypeInfo ti = null ) nothrow @nogc;
Expand Down Expand Up @@ -170,6 +170,12 @@ struct GC
size_t freeSize;
}

/**
* Auto-generated bitflag enum with values of identical names as `Stats`
* struct. Optionally used to specify exact stats to calculate.
*/
mixin(generateFieldEnum!Stats);

/**
* Enables automatic garbage collection behavior if collections have
* previously been suspended by a call to disable. This function is
Expand Down Expand Up @@ -674,10 +680,16 @@ struct GC
/**
* Returns runtime stats for currently active GC implementation
* See `core.memory.GC.Stats` for list of available metrics.
*
* Params:
* fields = optional bit flag argument which specifies which stats need
* to be calculated. By default equals to "all fields". If some field
* was not requested via bit flag, its value in returned `Stats` struct
* will be undefined.
*/
static Stats stats() nothrow
static Stats stats(ulong fields = ulong.max) nothrow
{
return gc_stats();
return gc_stats(fields);
}

/**
Expand Down Expand Up @@ -1184,4 +1196,49 @@ unittest
assert(GC.addrOf(y.ptr) == null);
}

/**
For a given struct `S` generated bitflag enum with a value for each of
struct fields.
*/
private string generateFieldEnum(alias S)()
{
import core.internal.string;

string code = "enum " ~ __traits(identifier, S) ~ "Fields\n{\n";
ulong shift = 0;
char[3] buf;

foreach (idx, _; S.init.tupleof)
thewilsonator marked this conversation as resolved.
Show resolved Hide resolved
{
auto init = "1UL << " ~ unsignedToTempString(shift, buf);
code ~= __traits(identifier, S.tupleof[idx]) ~ " = " ~ init ~ ",\n";
++shift;
}

code ~= "}";

return code;
}

unittest
{
static struct Dummy
{
int a, b, c;
}

enum code = generateFieldEnum!Dummy();

static assert (code == "enum DummyFields
{
a = 1UL << 0,
b = 1UL << 1,
c = 1UL << 2,
}");

mixin(code);

assert(DummyFields.a == 1);
assert(DummyFields.b == 2);
assert(DummyFields.c == 4);
}
2 changes: 1 addition & 1 deletion src/gc/gcinterface.d
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ interface GC
* Retrieve statistics about garbage collection.
* Useful for debugging and tuning.
*/
core.memory.GC.Stats stats() nothrow;
core.memory.GC.Stats stats(ulong fields) nothrow;

/**
* add p to list of roots
Expand Down
46 changes: 27 additions & 19 deletions src/gc/impl/conservative/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -1191,11 +1191,11 @@ class ConservativeGC : GC
}


core.memory.GC.Stats stats() nothrow
core.memory.GC.Stats stats(ulong fields) nothrow
{
typeof(return) ret;

runLocked!(getStatsNoSync, otherTime, numOthers)(ret);
runLocked!(getStatsNoSync, otherTime, numOthers)(ret, fields);

return ret;
}
Expand All @@ -1204,29 +1204,37 @@ class ConservativeGC : GC
//
//
//
private void getStatsNoSync(out core.memory.GC.Stats stats) nothrow
private void getStatsNoSync(out core.memory.GC.Stats stats, ulong fields) nothrow
{
foreach (pool; gcx.pooltable[0 .. gcx.npools])
alias Flags = core.memory.GC.StatsFields;

if ((fields & Flags.usedSize) || (fields & Flags.freeSize))
{
foreach (bin; pool.pagetable[0 .. pool.npages])
// calculates both if any is requested as it is part of the same
// iteration process

foreach (pool; gcx.pooltable[0 .. gcx.npools])
{
if (bin == B_FREE)
stats.freeSize += PAGESIZE;
else
stats.usedSize += PAGESIZE;
foreach (bin; pool.pagetable[0 .. pool.npages])
{
if (bin == B_FREE)
stats.freeSize += PAGESIZE;
else
stats.usedSize += PAGESIZE;
}
}
}

size_t freeListSize;
foreach (n; 0 .. B_PAGE)
{
immutable sz = binsize[n];
for (List *list = gcx.bucket[n]; list; list = list.next)
freeListSize += sz;
}
size_t freeListSize;
foreach (n; 0 .. B_PAGE)
{
immutable sz = binsize[n];
for (List *list = gcx.bucket[n]; list; list = list.next)
freeListSize += sz;
}

stats.usedSize -= freeListSize;
stats.freeSize += freeListSize;
stats.usedSize -= freeListSize;
stats.freeSize += freeListSize;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/gc/impl/manual/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ class ManualGC : GC
return BlkInfo.init;
}

core.memory.GC.Stats stats() nothrow
core.memory.GC.Stats stats(ulong fields) nothrow
{
return typeof(return).init;
}
Expand Down
2 changes: 1 addition & 1 deletion src/gc/impl/proto/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class ProtoGC : GC
return BlkInfo.init;
}

core.memory.GC.Stats stats() nothrow
core.memory.GC.Stats stats(ulong fields) nothrow
{
return typeof(return).init;
}
Expand Down
4 changes: 2 additions & 2 deletions src/gc/proxy.d
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,9 @@ extern (C)
return instance.query( p );
}

core.memory.GC.Stats gc_stats() nothrow
core.memory.GC.Stats gc_stats(ulong fields) nothrow
{
return instance.stats();
return instance.stats(fields);
}

void gc_addRoot( void* p ) nothrow @nogc
Expand Down