From bda74b0e4a8eb1acae8c202efd62d298ec3268f0 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 23 Feb 2017 21:40:55 -0500 Subject: [PATCH] runtime: make TestMemStats failure messages useful Currently most TestMemStats failures dump the whole MemStats object if anything is amiss without telling you what is amiss, or even which field is wrong. This makes it hard to figure out what the actual problem is. Replace this with a reflection walk over MemStats and a map of predicates to check. If one fails, we can construct a detailed and descriptive error message. The predicates are a direct translation of the current tests. Change-Id: I5a7cafb8e6a1eeab653d2e18bb74e2245eaa5444 Reviewed-on: https://go-review.googlesource.com/37512 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Rick Hudson --- src/runtime/malloc_test.go | 60 ++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/runtime/malloc_test.go b/src/runtime/malloc_test.go index 0cf9cfbf42..596501f7d5 100644 --- a/src/runtime/malloc_test.go +++ b/src/runtime/malloc_test.go @@ -6,6 +6,8 @@ package runtime_test import ( "flag" + "fmt" + "reflect" . "runtime" "testing" "time" @@ -20,24 +22,50 @@ func TestMemStats(t *testing.T) { st := new(MemStats) ReadMemStats(st) - // Everything except HeapReleased, HeapIdle, and NumGC, - // because they indeed can be 0. - if st.Alloc == 0 || st.TotalAlloc == 0 || st.Sys == 0 || st.Lookups == 0 || - st.Mallocs == 0 || st.Frees == 0 || st.HeapAlloc == 0 || st.HeapSys == 0 || - st.HeapInuse == 0 || st.HeapObjects == 0 || st.StackInuse == 0 || - st.StackSys == 0 || st.MSpanInuse == 0 || st.MSpanSys == 0 || st.MCacheInuse == 0 || - st.MCacheSys == 0 || st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 || - st.NextGC == 0 || st.NumForcedGC == 0 { - t.Fatalf("Zero value: %+v", *st) + nz := func(x interface{}) error { + if x != reflect.Zero(reflect.TypeOf(x)).Interface() { + return nil + } + return fmt.Errorf("zero value") + } + le := func(thresh uint64) func(interface{}) error { + return func(x interface{}) error { + if reflect.ValueOf(x).Uint() < thresh { + return nil + } + return fmt.Errorf("insanely high value (overflow?); want <= %d", thresh) + } + } + // Of the uint fields, HeapReleased, HeapIdle, PauseTotalNs, and NumGC can be 0. + fields := map[string][]func(interface{}) error{ + "Alloc": {nz, le(1e10)}, "TotalAlloc": {nz, le(1e11)}, "Sys": {nz, le(1e10)}, + "Lookups": {nz, le(1e10)}, "Mallocs": {nz, le(1e10)}, "Frees": {nz, le(1e10)}, + "HeapAlloc": {nz, le(1e10)}, "HeapSys": {nz, le(1e10)}, "HeapIdle": {le(1e10)}, + "HeapInuse": {nz, le(1e10)}, "HeapReleased": nil, "HeapObjects": {nz, le(1e10)}, + "StackInuse": {nz, le(1e10)}, "StackSys": {nz, le(1e10)}, + "MSpanInuse": {nz, le(1e10)}, "MSpanSys": {nz, le(1e10)}, + "MCacheInuse": {nz, le(1e10)}, "MCacheSys": {nz, le(1e10)}, + "BuckHashSys": {nz, le(1e10)}, "GCSys": {nz, le(1e10)}, "OtherSys": {nz, le(1e10)}, + "NextGC": {nz, le(1e10)}, "LastGC": nil, + "PauseTotalNs": {le(1e11)}, "PauseNs": nil, "PauseEnd": nil, + "NumGC": {le(1e9)}, "NumForcedGC": {nz, le(1e9)}, + "GCCPUFraction": nil, "EnableGC": nil, "DebugGC": nil, + "BySize": nil, } - if st.Alloc > 1e10 || st.TotalAlloc > 1e11 || st.Sys > 1e10 || st.Lookups > 1e10 || - st.Mallocs > 1e10 || st.Frees > 1e10 || st.HeapAlloc > 1e10 || st.HeapSys > 1e10 || - st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 || - st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 || - st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 || - st.NextGC > 1e10 || st.NumGC > 1e9 || st.NumForcedGC > 1e9 || st.PauseTotalNs > 1e11 { - t.Fatalf("Insanely high value (overflow?): %+v", *st) + rst := reflect.ValueOf(st).Elem() + for i := 0; i < rst.Type().NumField(); i++ { + name, val := rst.Type().Field(i).Name, rst.Field(i).Interface() + checks, ok := fields[name] + if !ok { + t.Errorf("unknown MemStats field %s", name) + continue + } + for _, check := range checks { + if err := check(val); err != nil { + t.Errorf("%s = %v: %s", name, val, err) + } + } } if st.Sys != st.HeapSys+st.StackSys+st.MSpanSys+st.MCacheSys+ -- 2.48.1