Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Closed
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
5 changes: 5 additions & 0 deletions changelog/collect-stats.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
`GC.Stats` provide new metric, total collected memory.

Result struct of `core.memory.GC.stats()` method now provides additional field,
`totalCollected`, which is set to total amount of bytes reclaimed by GC during
collection cycles since the program start.
1 change: 1 addition & 0 deletions src/core/internal/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,4 @@ template hasElaborateCopyConstructor(T...)
else
enum bool hasElaborateCopyConstructor = false;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra newline

7 changes: 5 additions & 2 deletions src/core/memory.d
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,12 @@ struct GC
static struct Stats
{
/// number of used bytes on the GC heap (might only get updated after a collection)
size_t usedSize;
ulong usedSize;
/// number of free bytes on the GC heap (might only get updated after a collection)
size_t freeSize;
ulong freeSize;
/// number of bytes freed during collections through program lifetime so
/// far (will count same memory multiple times if re-used)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of keeping track of this? It should be mentioned at least in the commit message, but probably also in the changelog and the code docs.

ulong totalCollected;
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/gc/gcinterface.d
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ static import core.memory;
alias BlkAttr = core.memory.GC.BlkAttr;
alias BlkInfo = core.memory.GC.BlkInfo;

static import core.sync.mutex;

alias RootIterator = int delegate(scope int delegate(ref Root) nothrow dg);
alias RangeIterator = int delegate(scope int delegate(ref Range) nothrow dg);

Expand Down Expand Up @@ -187,4 +189,7 @@ interface GC
*
*/
bool inFinalizer() nothrow;

void enableProfiling() nothrow @nogc;
shared(core.sync.mutex.Mutex) profilerLock() nothrow @nogc;
}
32 changes: 31 additions & 1 deletion src/gc/impl/conservative/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
import core.stdc.string : memcpy, memset, memmove;
import core.bitop;
import core.thread;
import core.sync.mutex;
static import core.memory;

version (GNU) import gcc.builtins;
Expand Down Expand Up @@ -115,6 +116,7 @@ __gshared long numFrees;
__gshared long numReallocs;
__gshared long numExtends;
__gshared long numOthers;
__gshared long totalCollectedPages;
__gshared long mallocTime; // using ticks instead of MonoTime for better performance
__gshared long freeTime;
__gshared long reallocTime;
Expand Down Expand Up @@ -251,6 +253,10 @@ debug (LOGGING)

class ConservativeGC : GC
{
bool profiling_enabled;
shared Mutex profiler_lock;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why creating this new mutex instead of using the pre-existing GC global lock for everything?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currenty main GC implementation uses non re-entrant spinlock. Anyway, all lock/sync hacking is more of proof of concept to see if I can make it work that way (have failed so far).

shared void[__traits(classInstanceSize, Mutex)] profiler_lock_bytes;

// For passing to debug code (not thread safe)
__gshared size_t line;
__gshared char* file;
Expand Down Expand Up @@ -315,6 +321,10 @@ class ConservativeGC : GC
gcx.reserve(config.initReserve << 20);
if (config.disable)
gcx.disabled++;

this.profiler_lock_bytes[0..$] = typeid(Mutex).initializer[];
this.profiler_lock = cast(shared(Mutex)) this.profiler_lock_bytes.ptr;
this.profiler_lock.__ctor();
}


Expand Down Expand Up @@ -358,6 +368,13 @@ class ConservativeGC : GC

auto runLocked(alias func, Args...)(auto ref Args args)
{
if (this.profiling_enabled)
{
this.profiler_lock.lock_nothrow();
scope(exit)
this.profiler_lock.unlock_nothrow();
}

debug(PROFILE_API) immutable tm = (config.profile > 1 ? currTime.ticks : 0);
lockNR();
scope (failure) gcLock.unlock();
Expand Down Expand Up @@ -1227,6 +1244,17 @@ class ConservativeGC : GC

stats.usedSize -= freeListSize;
stats.freeSize += freeListSize;
stats.totalCollected = .totalCollectedPages * PAGESIZE;
}

void enableProfiling() nothrow @nogc
{
this.profiling_enabled = true;
}

shared(Mutex) profilerLock() nothrow @nogc
{
return this.profiler_lock;
}
}

Expand Down Expand Up @@ -2434,7 +2462,9 @@ struct Gcx

updateCollectThresholds();

return freedLargePages + freedSmallPages;
auto total = freedLargePages + freedSmallPages;
totalCollectedPages += total;
return total;
}

/**
Expand Down
10 changes: 10 additions & 0 deletions src/gc/impl/manual/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import gc.gcinterface;
import rt.util.container.array;

import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
import core.sync.mutex;
static import core.memory;

extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */
Expand Down Expand Up @@ -271,4 +272,13 @@ class ManualGC : GC
{
return false;
}

void enableProfiling() nothrow @nogc
{
}

shared(Mutex) profilerLock() nothrow @nogc
{
return null;
}
}
42 changes: 25 additions & 17 deletions src/rt/profilegc.d
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import core.stdc.string;

import core.exception : onOutOfMemoryError;

struct Entry { size_t count, size; }
struct Entry { ulong count, size; }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is changing size_t to ulong is necessary or better? Needs clarification in the commit message at least, but maybe even here too, so nobody is tempted to change it back.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was trying to fix differences in stats between 32-bit and 64-bit builds, stupid idea that will need to be reverted (I have later switched to using two different log files to compare against in test runner).


char[] buffer;
Entry[string] newCounts;
Expand All @@ -41,12 +41,15 @@ __gshared

extern (C) void profilegc_setlogfilename(string name)
{
import gc.proxy : gc_getProxy;
gc_getProxy().enableProfiling();
logfilename = name;
}



public void accumulate(string file, uint line, string funcname, string type, size_t sz)
public void accumulate(string file, uint line, string funcname, string type,
ulong sz)
{
char[3 * line.sizeof + 1] buf;
auto buflen = snprintf(buf.ptr, buf.length, "%u", line);
Expand Down Expand Up @@ -85,23 +88,23 @@ public void accumulate(string file, uint line, string funcname, string type, siz
// Merge thread local newCounts into globalNewCounts
static ~this()
{
import gc.proxy : gc_getProxy;
auto mtx = gc_getProxy().profilerLock();

if (newCounts.length)
{
synchronized
mtx.lock();
scope(exit) mtx.unlock();

foreach (name, entry; newCounts)
{
if (globalNewCounts.length)
{
// Merge
foreach (name, entry; newCounts)
{
globalNewCounts[name].count += entry.count;
globalNewCounts[name].size += entry.size;
}
}
else
// Assign
globalNewCounts = newCounts;
if (!(name in globalNewCounts))
globalNewCounts[name] = Entry.init;

globalNewCounts[name].count += entry.count;
globalNewCounts[name].size += entry.size;
}

newCounts = null;
}
free(buffer.ptr);
Expand All @@ -121,10 +124,15 @@ shared static ~this()
{
auto result1 = cast(Result*)r1;
auto result2 = cast(Result*)r2;
ptrdiff_t cmp = result2.entry.size - result1.entry.size;
auto totalSize1 = result1.entry.size * result1.entry.count;
auto totalSize2 = result2.entry.size * result2.entry.count;
long cmp = totalSize2 - totalSize1;
if (cmp) return cmp < 0 ? -1 : 1;
cmp = result2.entry.size - result1.entry.size;
if (cmp) return cmp < 0 ? -1 : 1;
cmp = result2.entry.count - result1.entry.count;
return cmp < 0 ? -1 : (cmp > 0 ? 1 : 0);
if (cmp) return cmp < 0 ? -1 : 1;
return result2.name < result1.name;
}
}

Expand Down
Loading