diff --git a/builder/sizes_test.go b/builder/sizes_test.go index 639c32b5c..0117065b6 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) { // This is a small number of very diverse targets that we want to test. tests := []sizeTest{ // microcontrollers - {"hifive1b", "examples/echo", 4313, 323, 0, 2260}, - {"microbit", "examples/serial", 2838, 382, 8, 2256}, - {"wioterminal", "examples/pininterrupt", 8027, 1665, 132, 7488}, + {"hifive1b", "examples/echo", 4321, 323, 0, 2268}, + {"microbit", "examples/serial", 2842, 382, 8, 2264}, + {"wioterminal", "examples/pininterrupt", 8039, 1665, 132, 7496}, // TODO: also check wasm. Right now this is difficult, because // wasm binaries are run through wasm-opt and therefore the diff --git a/src/runtime/gc_blocks.go b/src/runtime/gc_blocks.go index 78387cb31..3afed0a3e 100644 --- a/src/runtime/gc_blocks.go +++ b/src/runtime/gc_blocks.go @@ -56,6 +56,7 @@ var ( endBlock gcBlock // the block just past the end of the available space gcTotalAlloc uint64 // total number of bytes allocated gcMallocs uint64 // total number of allocations + gcNumGC uint32 // total number of completed collection cycles gcLock task.PMutex // lock to avoid race conditions on multicore systems ) @@ -610,6 +611,11 @@ func runGC() (freeBytes uintptr) { dumpHeap() } + // The cycle is complete. Counted here rather than in GC() so that + // collections triggered by an allocation are counted too. Every caller + // holds gcLock, the same lock ReadMemStats reads it under. + gcNumGC++ + return } @@ -850,6 +856,9 @@ func ReadMemStats(m *MemStats) { // Record the total allocated bytes. m.TotalAlloc = gcTotalAlloc + // Record the number of completed collection cycles. + m.NumGC = gcNumGC + gcLock.Unlock() } diff --git a/src/runtime/gc_boehm.go b/src/runtime/gc_boehm.go index e0fc16a67..66a78697f 100644 --- a/src/runtime/gc_boehm.go +++ b/src/runtime/gc_boehm.go @@ -129,6 +129,7 @@ func ReadMemStats(m *MemStats) { m.Mallocs = 0 // not provided by bdwgc m.Frees = 0 // not provided by bdwgc m.Sys = uint64(gcMemStats.obtained_from_os_bytes) + m.NumGC = uint32(gcMemStats.gc_no) gcLock.Unlock() } diff --git a/src/runtime/gc_leaking.go b/src/runtime/gc_leaking.go index 3f1595ff6..839acd8d9 100644 --- a/src/runtime/gc_leaking.go +++ b/src/runtime/gc_leaking.go @@ -109,6 +109,7 @@ func ReadMemStats(m *MemStats) { m.HeapAlloc = gcTotalAlloc m.HeapObjects = gcMallocs m.Alloc = m.HeapAlloc + m.NumGC = 0 // this GC never collects, so no cycle ever completes gcLock.Unlock() } diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go index 987e17c30..4271bab9a 100644 --- a/src/runtime/mstats.go +++ b/src/runtime/mstats.go @@ -82,4 +82,9 @@ type MemStats struct { // GCSys is bytes of memory in garbage collection metadata. GCSys uint64 + + // NumGC is the number of completed GC cycles. + // + // The leaking collector never collects, so it always reports 0. + NumGC uint32 }