From: Austin Clements Date: Fri, 24 Feb 2017 02:40:55 +0000 (-0500) Subject: runtime: make TestMemStats failure messages useful X-Git-Tag: go1.9beta1~895 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=bda74b0e4a8eb1acae8c202efd62d298ec3268f0;p=gostls13.git 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 --- 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+