From b08dfbaa439e4e396b979e02ea2e7d36972e8b7a Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Wed, 1 Jul 2020 16:02:42 +0000 Subject: runtime,runtime/metrics: add memory metrics This change adds support for a variety of runtime memory metrics and contains the base implementation of Read for the runtime/metrics package, which lives in the runtime. It also adds testing infrastructure for the metrics package, and a bunch of format and documentation tests. For #37112. Change-Id: I16a2c4781eeeb2de0abcb045c15105f1210e2d8a Reviewed-on: https://go-review.googlesource.com/c/go/+/247041 Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Reviewed-by: Michael Pratt Trust: Michael Knyszek --- src/runtime/metrics/description_test.go | 125 ++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/runtime/metrics/description_test.go (limited to 'src/runtime/metrics/description_test.go') diff --git a/src/runtime/metrics/description_test.go b/src/runtime/metrics/description_test.go new file mode 100644 index 0000000000..e966a281a1 --- /dev/null +++ b/src/runtime/metrics/description_test.go @@ -0,0 +1,125 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package metrics_test + +import ( + "bufio" + "os" + "path/filepath" + "regexp" + "runtime" + "runtime/metrics" + "strings" + "testing" +) + +func TestDescriptionNameFormat(t *testing.T) { + r := regexp.MustCompile("^(?P/[^:]+):(?P[^:*/]+(?:[*/][^:*/]+)*)$") + descriptions := metrics.All() + for _, desc := range descriptions { + if !r.MatchString(desc.Name) { + t.Errorf("metrics %q does not match regexp %s", desc.Name, r) + } + } +} + +func extractMetricDocs(t *testing.T) map[string]string { + if runtime.GOOS == "android" { + t.Skip("no access to Go source on android") + } + + // Get doc.go. + _, filename, _, _ := runtime.Caller(0) + filename = filepath.Join(filepath.Dir(filename), "doc.go") + + f, err := os.Open(filename) + if err != nil { + t.Fatal(err) + } + const ( + stateSearch = iota // look for list of metrics + stateNextMetric // look for next metric + stateNextDescription // build description + ) + state := stateSearch + s := bufio.NewScanner(f) + result := make(map[string]string) + var metric string + var prevMetric string + var desc strings.Builder + for s.Scan() { + line := strings.TrimSpace(s.Text()) + switch state { + case stateSearch: + if line == "Supported metrics" { + state = stateNextMetric + } + case stateNextMetric: + // Ignore empty lines until we find a non-empty + // one. This will be our metric name. + if len(line) != 0 { + prevMetric = metric + metric = line + if prevMetric > metric { + t.Errorf("metrics %s and %s are out of lexicographical order", prevMetric, metric) + } + state = stateNextDescription + } + case stateNextDescription: + if len(line) == 0 || line == `*/` { + // An empty line means we're done. + // Write down the description and look + // for a new metric. + result[metric] = desc.String() + desc.Reset() + state = stateNextMetric + } else { + // As long as we're seeing data, assume that's + // part of the description and append it. + if desc.Len() != 0 { + // Turn previous newlines into spaces. + desc.WriteString(" ") + } + desc.WriteString(line) + } + } + if line == `*/` { + break + } + } + if state == stateSearch { + t.Fatalf("failed to find supported metrics docs in %s", filename) + } + return result +} + +func TestDescriptionDocs(t *testing.T) { + docs := extractMetricDocs(t) + descriptions := metrics.All() + for _, d := range descriptions { + want := d.Description + got, ok := docs[d.Name] + if !ok { + t.Errorf("no docs found for metric %s", d.Name) + continue + } + if got != want { + t.Errorf("mismatched description and docs for metric %s", d.Name) + t.Errorf("want: %q, got %q", want, got) + continue + } + } + if len(docs) > len(descriptions) { + docsLoop: + for name, _ := range docs { + for _, d := range descriptions { + if name == d.Name { + continue docsLoop + } + } + t.Errorf("stale documentation for non-existent metric: %s", name) + } + } +} -- cgit v1.3 From 5627a4dc3013fed02c4b8097413643b682cac276 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Tue, 8 Dec 2020 19:44:33 -0500 Subject: runtime/metrics: simplify test to support more environments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit go test sets the working directory to that of the package being tested, so opening one of the package source files can be done in a simpler way. This also allows the test to run in more environments, for example when GOROOT_FINAL¹ is set. Also remove the testenv.HasSrc-like check for Go source. The doc.go file is a part of the package being built and tested, so it's expected to be available. If it's important for this test to handle when a test binary is built with go test -c and executed elsewhere without package source files, something more than testenv.HasSrc would be needed. ¹ https://golang.org/cmd/go/#hdr-Environment_variables Fixes #43085. Change-Id: Ie6ade395a8fc7beebdadbad6f4873800138dfc26 Reviewed-on: https://go-review.googlesource.com/c/go/+/276452 Reviewed-by: Bryan C. Mills Reviewed-by: Michael Knyszek Trust: Dmitri Shuralyov --- src/runtime/metrics/description_test.go | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'src/runtime/metrics/description_test.go') diff --git a/src/runtime/metrics/description_test.go b/src/runtime/metrics/description_test.go index e966a281a1..448639ee77 100644 --- a/src/runtime/metrics/description_test.go +++ b/src/runtime/metrics/description_test.go @@ -7,9 +7,7 @@ package metrics_test import ( "bufio" "os" - "path/filepath" "regexp" - "runtime" "runtime/metrics" "strings" "testing" @@ -26,17 +24,9 @@ func TestDescriptionNameFormat(t *testing.T) { } func extractMetricDocs(t *testing.T) map[string]string { - if runtime.GOOS == "android" { - t.Skip("no access to Go source on android") - } - - // Get doc.go. - _, filename, _, _ := runtime.Caller(0) - filename = filepath.Join(filepath.Dir(filename), "doc.go") - - f, err := os.Open(filename) + f, err := os.Open("doc.go") if err != nil { - t.Fatal(err) + t.Fatalf("failed to open doc.go in runtime/metrics package: %v", err) } const ( stateSearch = iota // look for list of metrics @@ -90,7 +80,7 @@ func extractMetricDocs(t *testing.T) map[string]string { } } if state == stateSearch { - t.Fatalf("failed to find supported metrics docs in %s", filename) + t.Fatalf("failed to find supported metrics docs in %s", f.Name()) } return result } -- cgit v1.3 From d0f40d29223a2aef58475f81a559b2d27396134a Mon Sep 17 00:00:00 2001 From: Michael Anthony Knyszek Date: Fri, 4 Dec 2020 16:04:53 +0000 Subject: runtime/metrics: add ordering line to supported metrics docs This change adds an additional line explaining the ordering of the supported metrics list. It's also necessary to ensure "Supported metrics" is displayed by godoc as a proper header. This modification does mean the description test, that ensures descriptions line up with documentation, needs to change slightly so it it doesn't read this new line as documentation. Make this new line the line the test uses to decide when to begin. Change-Id: I654c1c20e97a80ea79c8eb864445153ce91950bf Reviewed-on: https://go-review.googlesource.com/c/go/+/275852 Run-TryBot: Michael Knyszek TryBot-Result: Go Bot Trust: Michael Knyszek Reviewed-by: Michael Pratt --- src/runtime/metrics/description_test.go | 2 +- src/runtime/metrics/doc.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/runtime/metrics/description_test.go') diff --git a/src/runtime/metrics/description_test.go b/src/runtime/metrics/description_test.go index 448639ee77..fd1fd46efc 100644 --- a/src/runtime/metrics/description_test.go +++ b/src/runtime/metrics/description_test.go @@ -43,7 +43,7 @@ func extractMetricDocs(t *testing.T) map[string]string { line := strings.TrimSpace(s.Text()) switch state { case stateSearch: - if line == "Supported metrics" { + if line == "Below is the full list of supported metrics, ordered lexicographically." { state = stateNextMetric } case stateNextMetric: diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go index 42b5bc3724..05a887e4f4 100644 --- a/src/runtime/metrics/doc.go +++ b/src/runtime/metrics/doc.go @@ -44,6 +44,8 @@ the documentation of the Name field of the Description struct. Supported metrics +Below is the full list of supported metrics, ordered lexicographically. + /gc/cycles/automatic:gc-cycles Count of completed GC cycles generated by the Go runtime. -- cgit v1.3