diff --git a/changelog/core-memory-gc-profile-stats.dd b/changelog/core-memory-gc-profile-stats.dd new file mode 100644 index 0000000000..e84c6092e9 --- /dev/null +++ b/changelog/core-memory-gc-profile-stats.dd @@ -0,0 +1,4 @@ +Added `GC.profileStats()` to `core.memory` + +Allows access to current GC profiling information. +See $(REF GC.ProfileStats, core,memory) for a list of profile stats. diff --git a/mak/COPY b/mak/COPY index 65297a94c9..5186d83086 100644 --- a/mak/COPY +++ b/mak/COPY @@ -81,18 +81,18 @@ COPY=\ \ $(IMPDIR)\core\sys\freebsd\netinet\in_.d \ \ - $(IMPDIR)\core\sys\freebsd\sys\cdefs.d \ $(IMPDIR)\core\sys\freebsd\pthread_np.d \ $(IMPDIR)\core\sys\freebsd\sys\_bitset.d \ $(IMPDIR)\core\sys\freebsd\sys\_cpuset.d \ + $(IMPDIR)\core\sys\freebsd\sys\cdefs.d \ + $(IMPDIR)\core\sys\freebsd\sys\elf_common.d \ $(IMPDIR)\core\sys\freebsd\sys\elf.d \ $(IMPDIR)\core\sys\freebsd\sys\elf32.d \ $(IMPDIR)\core\sys\freebsd\sys\elf64.d \ - $(IMPDIR)\core\sys\freebsd\sys\elf_common.d \ $(IMPDIR)\core\sys\freebsd\sys\event.d \ $(IMPDIR)\core\sys\freebsd\sys\link_elf.d \ - $(IMPDIR)\core\sys\freebsd\sys\mount.d \ $(IMPDIR)\core\sys\freebsd\sys\mman.d \ + $(IMPDIR)\core\sys\freebsd\sys\mount.d \ $(IMPDIR)\core\sys\freebsd\time.d \ $(IMPDIR)\core\sys\freebsd\unistd.d \ \ @@ -101,14 +101,14 @@ COPY=\ \ $(IMPDIR)\core\sys\dragonflybsd\netinet\in_.d \ \ - $(IMPDIR)\core\sys\dragonflybsd\sys\cdefs.d \ $(IMPDIR)\core\sys\dragonflybsd\pthread_np.d \ $(IMPDIR)\core\sys\dragonflybsd\sys\_bitset.d \ $(IMPDIR)\core\sys\dragonflybsd\sys\_cpuset.d \ + $(IMPDIR)\core\sys\dragonflybsd\sys\cdefs.d \ + $(IMPDIR)\core\sys\dragonflybsd\sys\elf_common.d \ $(IMPDIR)\core\sys\dragonflybsd\sys\elf.d \ $(IMPDIR)\core\sys\dragonflybsd\sys\elf32.d \ $(IMPDIR)\core\sys\dragonflybsd\sys\elf64.d \ - $(IMPDIR)\core\sys\dragonflybsd\sys\elf_common.d \ $(IMPDIR)\core\sys\dragonflybsd\sys\event.d \ $(IMPDIR)\core\sys\dragonflybsd\sys\link_elf.d \ $(IMPDIR)\core\sys\dragonflybsd\sys\mman.d \ @@ -197,8 +197,8 @@ COPY=\ $(IMPDIR)\core\sys\posix\sys\types.d \ $(IMPDIR)\core\sys\posix\sys\uio.d \ $(IMPDIR)\core\sys\posix\sys\un.d \ - $(IMPDIR)\core\sys\posix\sys\wait.d \ $(IMPDIR)\core\sys\posix\sys\utsname.d \ + $(IMPDIR)\core\sys\posix\sys\wait.d \ \ $(IMPDIR)\core\sys\solaris\dlfcn.d \ $(IMPDIR)\core\sys\solaris\elf.d \ @@ -213,9 +213,9 @@ COPY=\ $(IMPDIR)\core\sys\solaris\sys\elf_SPARC.d \ $(IMPDIR)\core\sys\solaris\sys\elftypes.d \ $(IMPDIR)\core\sys\solaris\sys\link.d \ + $(IMPDIR)\core\sys\solaris\sys\priocntl.d \ $(IMPDIR)\core\sys\solaris\sys\procset.d \ $(IMPDIR)\core\sys\solaris\sys\types.d \ - $(IMPDIR)\core\sys\solaris\sys\priocntl.d \ \ $(IMPDIR)\core\sys\windows\accctrl.d \ $(IMPDIR)\core\sys\windows\aclapi.d \ diff --git a/mak/SRCS b/mak/SRCS index de4d232e0d..7ee1907d56 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -45,8 +45,10 @@ SRCS=\ src\core\stdc\stdio.d \ src\core\stdc\stdlib.d \ src\core\stdc\string.d \ + src\core\stdc\tgmath.d \ src\core\stdc\time.d \ src\core\stdc\wchar_.d \ + src\core\stdc\wctype.d \ \ src\core\stdcpp\array.d \ src\core\stdcpp\string_view.d \ @@ -74,9 +76,14 @@ SRCS=\ src\core\sys\darwin\mach\thread_act.d \ src\core\sys\darwin\netinet\in_.d \ \ + src\core\sys\darwin\sys\cdefs.d \ + src\core\sys\darwin\sys\event.d \ + src\core\sys\darwin\sys\mman.d \ + \ src\core\sys\freebsd\dlfcn.d \ src\core\sys\freebsd\execinfo.d \ src\core\sys\freebsd\netinet\in_.d \ + src\core\sys\freebsd\pthread_np.d \ src\core\sys\freebsd\sys\_bitset.d \ src\core\sys\freebsd\sys\_cpuset.d \ src\core\sys\freebsd\sys\cdefs.d \ @@ -94,6 +101,7 @@ SRCS=\ src\core\sys\dragonflybsd\dlfcn.d \ src\core\sys\dragonflybsd\execinfo.d \ src\core\sys\dragonflybsd\netinet\in_.d \ + src\core\sys\dragonflybsd\pthread_np.d \ src\core\sys\dragonflybsd\sys\_bitset.d \ src\core\sys\dragonflybsd\sys\_cpuset.d \ src\core\sys\dragonflybsd\sys\cdefs.d \ @@ -106,25 +114,75 @@ SRCS=\ src\core\sys\dragonflybsd\sys\mman.d \ src\core\sys\dragonflybsd\time.d \ \ + src\core\sys\linux\config.d \ + src\core\sys\linux\dlfcn.d \ + src\core\sys\linux\elf.d \ + src\core\sys\linux\epoll.d \ + src\core\sys\linux\errno.d \ + src\core\sys\linux\execinfo.d \ + src\core\sys\linux\fcntl.d \ + src\core\sys\linux\ifaddrs.d \ + src\core\sys\linux\link.d \ + src\core\sys\linux\sched.d \ + src\core\sys\linux\termios.d \ + src\core\sys\linux\time.d \ + src\core\sys\linux\timerfd.d \ + src\core\sys\linux\tipc.d \ + src\core\sys\linux\unistd.d \ + \ src\core\sys\linux\netinet\in_.d \ src\core\sys\linux\netinet\tcp.d \ - src\core\sys\linux\stdio.d \ - src\core\sys\linux\tipc.d \ + src\core\sys\linux\sys\netinet\tcp.d \ + \ + src\core\sys\linux\sys\auxv.d \ + src\core\sys\linux\sys\eventfd.d \ + src\core\sys\linux\sys\file.d \ src\core\sys\linux\sys\inotify.d \ src\core\sys\linux\sys\mman.d \ src\core\sys\linux\sys\signalfd.d \ src\core\sys\linux\sys\socket.d \ src\core\sys\linux\sys\sysinfo.d \ - src\core\sys\linux\sys\time.d \ src\core\sys\linux\sys\xattr.d \ + src\core\sys\linux\sys\time.d \ + src\core\sys\linux\sys\prctl.d \ + \ + src\core\sys\openbsd\dlfcn.d \ \ + src\core\sys\posix\arpa\inet.d \ + src\core\sys\posix\aio.d \ + src\core\sys\posix\config.d \ src\core\sys\posix\dirent.d \ + src\core\sys\posix\dlfcn.d \ + src\core\sys\posix\fcntl.d \ + src\core\sys\posix\grp.d \ + src\core\sys\posix\iconv.d \ + src\core\sys\posix\inttypes.d \ + src\core\sys\posix\libgen.d \ + src\core\sys\posix\netdb.d \ + src\core\sys\posix\poll.d \ + src\core\sys\posix\pthread.d \ + src\core\sys\posix\pwd.d \ + src\core\sys\posix\sched.d \ + src\core\sys\posix\semaphore.d \ + src\core\sys\posix\setjmp.d \ src\core\sys\posix\signal.d \ src\core\sys\posix\spawn.d \ - src\core\sys\posix\netdb.d \ + src\core\sys\posix\stdio.d \ + src\core\sys\posix\stdlib.d \ + src\core\sys\posix\syslog.d \ + src\core\sys\posix\termios.d \ + src\core\sys\posix\time.d \ + src\core\sys\posix\ucontext.d \ + src\core\sys\posix\unistd.d \ + src\core\sys\posix\utime.d \ + \ + src\core\sys\posix\net\if_.d \ + \ src\core\sys\posix\netinet\in_.d \ - src\core\sys\posix\arpa\inet.d \ + src\core\sys\posix\netinet\tcp.d \ \ + src\core\sys\posix\sys\filio.d \ + src\core\sys\posix\sys\ioccom.d \ src\core\sys\posix\sys\ioctl.d \ src\core\sys\posix\sys\ipc.d \ src\core\sys\posix\sys\mman.d \ @@ -135,15 +193,29 @@ SRCS=\ src\core\sys\posix\sys\stat.d \ src\core\sys\posix\sys\statvfs.d \ src\core\sys\posix\sys\time.d \ + src\core\sys\posix\sys\ttycom.d \ src\core\sys\posix\sys\types.d \ src\core\sys\posix\sys\uio.d \ src\core\sys\posix\sys\un.d \ src\core\sys\posix\sys\utsname.d \ src\core\sys\posix\sys\wait.d \ \ + src\core\sys\solaris\dlfcn.d \ + src\core\sys\solaris\elf.d \ + src\core\sys\solaris\execinfo.d \ + src\core\sys\solaris\libelf.d \ + src\core\sys\solaris\link.d \ + src\core\sys\solaris\time.d \ + src\core\sys\solaris\sys\elf.d \ + src\core\sys\solaris\sys\elf_386.d \ + src\core\sys\solaris\sys\elf_amd64.d \ + src\core\sys\solaris\sys\elf_notes.d \ + src\core\sys\solaris\sys\elf_SPARC.d \ + src\core\sys\solaris\sys\elftypes.d \ + src\core\sys\solaris\sys\link.d \ src\core\sys\solaris\sys\priocntl.d \ - src\core\sys\solaris\sys\types.d \ src\core\sys\solaris\sys\procset.d \ + src\core\sys\solaris\sys\types.d \ \ src\core\sys\windows\accctrl.d \ src\core\sys\windows\aclapi.d \ diff --git a/src/core/memory.d b/src/core/memory.d index da283017e8..08872df9e3 100644 --- a/src/core/memory.d +++ b/src/core/memory.d @@ -139,6 +139,7 @@ private extern (C) BlkInfo_ gc_query( void* p ) pure nothrow; extern (C) GC.Stats gc_stats ( ) nothrow @nogc; + extern (C) GC.ProfileStats gc_profileStats ( ) nothrow @nogc @safe; 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 +171,24 @@ struct GC size_t freeSize; } + /** + * Aggregation of current profile information + */ + static struct ProfileStats + { + import core.time : Duration; + /// total number of GC cycles + size_t numCollections; + /// total time spent doing GC + Duration totalCollectionTime; + /// total time threads were paused doing GC + Duration totalPauseTime; + /// largest time threads were paused during one GC cycle + Duration maxPauseTime; + /// largest time spent doing one GC cycle + Duration maxCollectionTime; + } + /** * Enables automatic garbage collection behavior if collections have * previously been suspended by a call to disable. This function is @@ -689,6 +708,15 @@ struct GC return gc_stats(); } + /** + * Returns runtime profile stats for currently active GC implementation + * See `core.memory.GC.ProfileStats` for list of available metrics. + */ + static ProfileStats profileStats() nothrow @nogc @safe + { + return gc_profileStats(); + } + /** * Adds an internal root pointing to the GC memory block referenced by p. * As a result, the block referenced by p itself and any blocks accessible @@ -1265,3 +1293,12 @@ unittest void* p = GC.malloc(100); assert(GC.realloc(&p, 50) == null); // non-GC pointer } + +// test GC.profileStats +unittest +{ + auto stats = GC.profileStats(); + GC.collect(); + auto nstats = GC.profileStats(); + assert(nstats.numCollections > stats.numCollections); +} diff --git a/src/core/sys/freebsd/pthread_np.d b/src/core/sys/freebsd/pthread_np.d index 9e674b6c24..02b6fda910 100644 --- a/src/core/sys/freebsd/pthread_np.d +++ b/src/core/sys/freebsd/pthread_np.d @@ -3,7 +3,7 @@ * * Authors: Martin Nowak */ -module core.sys.freebsd.pthread; +module core.sys.freebsd.pthread_np; version (FreeBSD): extern (C) nothrow @nogc: diff --git a/src/gc/gcinterface.d b/src/gc/gcinterface.d index c162041994..5c24173191 100644 --- a/src/gc/gcinterface.d +++ b/src/gc/gcinterface.d @@ -148,6 +148,12 @@ interface GC */ core.memory.GC.Stats stats() nothrow; + /** + * Retrieve profile statistics about garbage collection. + * Useful for debugging and tuning. + */ + core.memory.GC.ProfileStats profileStats() nothrow; + /** * add p to list of roots */ diff --git a/src/gc/impl/conservative/gc.d b/src/gc/impl/conservative/gc.d index 9d00e260bd..04d0887ab7 100644 --- a/src/gc/impl/conservative/gc.d +++ b/src/gc/impl/conservative/gc.d @@ -100,7 +100,9 @@ __gshared Duration prepTime; __gshared Duration markTime; __gshared Duration sweepTime; __gshared Duration recoverTime; +__gshared Duration pauseTime; __gshared Duration maxPauseTime; +__gshared Duration maxCollectionTime; __gshared size_t numCollections; __gshared size_t maxPoolMemory; @@ -1184,6 +1186,19 @@ class ConservativeGC : GC } + core.memory.GC.ProfileStats profileStats() nothrow + { + typeof(return) ret; + + ret.numCollections = numCollections; + ret.totalCollectionTime = prepTime + markTime + sweepTime + recoverTime; + ret.totalPauseTime = pauseTime; + ret.maxCollectionTime = maxCollectionTime; + ret.maxPauseTime = maxPauseTime; + + return ret; + } + // // // @@ -2405,12 +2420,9 @@ struct Gcx prepare(); - if (config.profile) - { - stop = currTime; - prepTime += (stop - start); - start = stop; - } + stop = currTime; + prepTime += (stop - start); + start = stop; markAll(nostack); @@ -2418,15 +2430,13 @@ struct Gcx thread_resumeAll(); } - if (config.profile) - { - stop = currTime; - markTime += (stop - start); - Duration pause = stop - begin; - if (pause > maxPauseTime) - maxPauseTime = pause; - start = stop; - } + stop = currTime; + markTime += (stop - start); + Duration pause = stop - begin; + if (pause > maxPauseTime) + maxPauseTime = pause; + pauseTime += pause; + start = stop; ConservativeGC._inFinalizer = true; size_t freedLargePages=void; @@ -2436,21 +2446,19 @@ struct Gcx ConservativeGC._inFinalizer = false; } - if (config.profile) - { - stop = currTime; - sweepTime += (stop - start); - start = stop; - } + stop = currTime; + sweepTime += (stop - start); + start = stop; immutable freedSmallPages = recover(); - if (config.profile) - { - stop = currTime; - recoverTime += (stop - start); - ++numCollections; - } + stop = currTime; + recoverTime += (stop - start); + Duration collectionTime = stop - begin; + if (collectionTime > maxCollectionTime) + maxCollectionTime = collectionTime; + + ++numCollections; updateCollectThresholds(); diff --git a/src/gc/impl/manual/gc.d b/src/gc/impl/manual/gc.d index 3bcde758e3..61902ba88e 100644 --- a/src/gc/impl/manual/gc.d +++ b/src/gc/impl/manual/gc.d @@ -195,6 +195,11 @@ class ManualGC : GC return typeof(return).init; } + core.memory.GC.ProfileStats profileStats() nothrow + { + return typeof(return).init; + } + void addRoot(void* p) nothrow @nogc { roots.insertBack(Root(p)); diff --git a/src/gc/impl/proto/gc.d b/src/gc/impl/proto/gc.d index e23e38f7f9..047f7a8b4a 100644 --- a/src/gc/impl/proto/gc.d +++ b/src/gc/impl/proto/gc.d @@ -161,6 +161,12 @@ class ProtoGC : GC } + core.memory.GC.ProfileStats profileStats() nothrow + { + return typeof(return).init; + } + + void addRoot(void* p) nothrow @nogc { roots.insertBack(Root(p)); diff --git a/src/gc/proxy.d b/src/gc/proxy.d index fe74db8e09..b6a9595ef8 100644 --- a/src/gc/proxy.d +++ b/src/gc/proxy.d @@ -189,6 +189,11 @@ extern (C) return instance.stats(); } + core.memory.GC.ProfileStats gc_profileStats() nothrow + { + return instance.profileStats(); + } + void gc_addRoot( void* p ) nothrow @nogc { return instance.addRoot( p );