From 8972aa1318745a20b55dce35d614a0f480377e50 Mon Sep 17 00:00:00 2001 From: Mihails Strasuns Date: Mon, 16 Apr 2018 20:35:00 +0300 Subject: [PATCH] Calculate GC.stats on the fly --- mak/SRCS | 1 + src/gc/impl/conservative/gc.d | 56 +++++++++++++-------------- src/gc/stats.d | 73 +++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 28 deletions(-) mode change 100644 => 100755 mak/SRCS mode change 100644 => 100755 src/gc/impl/conservative/gc.d create mode 100755 src/gc/stats.d diff --git a/mak/SRCS b/mak/SRCS old mode 100644 new mode 100755 index d7f74b919d..42028b671f --- a/mak/SRCS +++ b/mak/SRCS @@ -296,6 +296,7 @@ SRCS=\ src\gc\os.d \ src\gc\pooltable.d \ src\gc\proxy.d \ + src\gc\stats.d \ src\gc\impl\conservative\gc.d \ src\gc\impl\manual\gc.d \ src\gc\impl\proto\gc.d \ diff --git a/src/gc/impl/conservative/gc.d b/src/gc/impl/conservative/gc.d old mode 100644 new mode 100755 index d9b51004a7..209f16cd61 --- a/src/gc/impl/conservative/gc.d +++ b/src/gc/impl/conservative/gc.d @@ -42,6 +42,7 @@ import gc.bits; import gc.os; import gc.config; import gc.gcinterface; +import gc.stats; import rt.util.container.treap; @@ -110,6 +111,8 @@ __gshared Duration maxPauseTime; __gshared size_t numCollections; __gshared size_t maxPoolMemory; +__gshared GCStatsTracker statsTracker; + __gshared long numMallocs; __gshared long numFrees; __gshared long numReallocs; @@ -596,7 +599,8 @@ class ConservativeGC : GC { if (!size) { if (p) - { freeNoSync(p); + { + freeNoSync(p); p = null; } alloc_size = 0; @@ -693,6 +697,8 @@ class ConservativeGC : GC pool.setBits(biti, bits); } alloc_size = newsz * PAGESIZE; + statsTracker.freed(psize); + statsTracker.allocated(alloc_size); return p; } @@ -721,6 +727,9 @@ class ConservativeGC : GC //debug(PRINTF) printf("\tcopying %d bytes\n",size); memcpy(p2, p, size); p = p2; + + statsTracker.freed(psize); + statsTracker.allocated(size); } else alloc_size = psize; @@ -787,6 +796,7 @@ class ConservativeGC : GC lpool.updateOffsets(pagenum); lpool.freepages -= sz; gcx.usedLargePages += sz; + statsTracker.allocated(sz * PAGESIZE); return (psz + sz) * PAGESIZE; } } @@ -873,6 +883,7 @@ class ConservativeGC : GC size_t npages = lpool.bPageOffsets[pagenum]; debug (MEMSTOMP) memset(p, 0xF2, npages * PAGESIZE); lpool.freePages(pagenum, npages); + statsTracker.freed(npages * PAGESIZE); } else { // Add to free list @@ -1200,33 +1211,9 @@ class ConservativeGC : GC return ret; } - - // - // - // private void getStatsNoSync(out core.memory.GC.Stats stats) nothrow { - foreach (pool; gcx.pooltable[0 .. gcx.npools]) - { - 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; - } - - stats.usedSize -= freeListSize; - stats.freeSize += freeListSize; + stats = statsTracker.stats; } } @@ -1380,6 +1367,7 @@ struct Gcx roots.removeAll(); ranges.removeAll(); toscan.reset(); + statsTracker.reset(); } @@ -1659,6 +1647,7 @@ struct Gcx { debug(PRINTF) printFreeInfo(pool); mappedPages -= pool.npages; + statsTracker.removed(pool.npages * PAGESIZE); pool.Dtor(); cstdlib.free(pool); } @@ -1673,8 +1662,12 @@ struct Gcx void* alloc(size_t size, ref size_t alloc_size, uint bits) nothrow { - return size <= 2048 ? smallAlloc(binTable[size], alloc_size, bits) + auto p = size <= 2048 ? smallAlloc(binTable[size], alloc_size, bits) : bigAlloc(size, alloc_size, bits); + + statsTracker.allocated(alloc_size); + + return p; } void* smallAlloc(Bins bin, ref size_t alloc_size, uint bits) nothrow @@ -1859,6 +1852,7 @@ struct Gcx } mappedPages += npages; + statsTracker.added(npages * PAGESIZE); if (config.profile) { @@ -2306,6 +2300,10 @@ struct Gcx assert(freedLargePages <= usedLargePages); usedLargePages -= freedLargePages; debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedLargePages, npools); + + statsTracker.freed(freed); + statsTracker.freed(freedLargePages); + return freedLargePages; } @@ -2456,7 +2454,8 @@ struct Gcx updateCollectThresholds(); - return freedLargePages + freedSmallPages; + size_t freed = freedLargePages + freedSmallPages; + return freed; } /** @@ -3107,6 +3106,7 @@ struct LargeObjectPool break; debug (MEMSTOMP) memset(baseAddr + pn * PAGESIZE, 0xF3, n * PAGESIZE); freePages(pn, n); + statsTracker.freed(n * PAGESIZE); } } } diff --git a/src/gc/stats.d b/src/gc/stats.d new file mode 100755 index 0000000000..203396d988 --- /dev/null +++ b/src/gc/stats.d @@ -0,0 +1,73 @@ +/** + * Utility to simplify calculating `core.memory.GC.Stats` + * + * Copyright: D Language Foundation, 2018 + * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). + * Source: $(DRUNTIMESRC gc/stats.d) + */ +module gc.stats; + +/** + Embeds `GC.Stats` instance and adds few simple wrapper methods + to maniplate it while doing some sanity checks. + */ +package(gc) struct GCStatsTracker +{ + @nogc nothrow @safe pure: + + import core.memory; + GC.Stats stats; + + /** + Record new memory added to the GC pool from OS + Params: + bytes = amount of memory + */ + void added(size_t bytes) + { + this.stats.freeSize += bytes; + } + + /** + Record memory returned from the GC pool to OS + Params: + bytes = amount of memory + */ + void removed(size_t bytes) + { + assert(this.stats.freeSize >= bytes); + this.stats.freeSize -= bytes; + } + + /** + Record new chunk of allocations from the GC pool + Params: + bytes = amount of memory + */ + void allocated(size_t bytes) + { + assert(this.stats.freeSize >= bytes); + this.stats.freeSize -= bytes; + this.stats.usedSize += bytes; + } + + /** + Record return of allocated memory to the GC pool + Params: + bytes = amount of memory + */ + void freed(size_t bytes) + { + assert(this.stats.usedSize >= bytes); + this.stats.freeSize += bytes; + this.stats.usedSize -= bytes; + } + + /** + Reset stored GC stats + */ + void reset() + { + this.stats = this.stats.init; + } +}