From 13420ae2286a81a2c083dd31ab6e1e7dab60c877 Mon Sep 17 00:00:00 2001 From: Nicholas Lindsay Wilson Date: Sat, 17 Nov 2018 19:09:37 +0800 Subject: [PATCH] Modify gc_stats API to be able to select needed ones --- src/core/memory.d | 63 +++++++++++++++++++++++++++++++++-- src/gc/gcinterface.d | 2 +- src/gc/impl/conservative/gc.d | 46 ++++++++++++++----------- src/gc/impl/manual/gc.d | 2 +- src/gc/impl/proto/gc.d | 2 +- src/gc/proxy.d | 4 +-- 6 files changed, 92 insertions(+), 27 deletions(-) diff --git a/src/core/memory.d b/src/core/memory.d index 4e3ee5affb..56a60abce8 100644 --- a/src/core/memory.d +++ b/src/core/memory.d @@ -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; @@ -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 @@ -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); } /** @@ -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) + { + 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); +} diff --git a/src/gc/gcinterface.d b/src/gc/gcinterface.d index c162041994..063d7c7bf6 100644 --- a/src/gc/gcinterface.d +++ b/src/gc/gcinterface.d @@ -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 diff --git a/src/gc/impl/conservative/gc.d b/src/gc/impl/conservative/gc.d index fa1d900808..234d213360 100644 --- a/src/gc/impl/conservative/gc.d +++ b/src/gc/impl/conservative/gc.d @@ -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; } @@ -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; + } } } diff --git a/src/gc/impl/manual/gc.d b/src/gc/impl/manual/gc.d index 3bcde758e3..ce1176b33a 100644 --- a/src/gc/impl/manual/gc.d +++ b/src/gc/impl/manual/gc.d @@ -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; } diff --git a/src/gc/impl/proto/gc.d b/src/gc/impl/proto/gc.d index e23e38f7f9..16b8a1b230 100644 --- a/src/gc/impl/proto/gc.d +++ b/src/gc/impl/proto/gc.d @@ -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; } diff --git a/src/gc/proxy.d b/src/gc/proxy.d index fe74db8e09..53aefcb365 100644 --- a/src/gc/proxy.d +++ b/src/gc/proxy.d @@ -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