aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2020-04-14 21:06:26 +0000
committerMichael Knyszek <mknyszek@google.com>2020-10-26 18:28:09 +0000
commit2159c26ceb32bbfa86036431750c0752fca84ef6 (patch)
treedded56a567edd1e695475b32d6ee80e0fc804447
parentc02134abb01e019683daf051029d66b15dd11213 (diff)
downloadgo-2159c26ceb32bbfa86036431750c0752fca84ef6.tar.gz
go-2159c26ceb32bbfa86036431750c0752fca84ef6.zip
runtime/metrics: add package interface
This change creates the runtime/metrics package and adds the initial interface as laid out in the design document. For #37112. Change-Id: I202dcee08ab008dd63bf96f7a4162f5b5f813637 Reviewed-on: https://go-review.googlesource.com/c/go/+/247040 Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Michael Knyszek <mknyszek@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
-rw-r--r--src/go/build/deps_test.go3
-rw-r--r--src/runtime/metrics/description.go52
-rw-r--r--src/runtime/metrics/doc.go49
-rw-r--r--src/runtime/metrics/histogram.go30
-rw-r--r--src/runtime/metrics/sample.go29
-rw-r--r--src/runtime/metrics/value.go69
6 files changed, 232 insertions, 0 deletions
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index ba7a76318f..b26b2bd199 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -138,6 +138,9 @@ var depsRules = `
MATH
< math/rand;
+ MATH
+ < runtime/metrics;
+
MATH, unicode/utf8
< strconv;
diff --git a/src/runtime/metrics/description.go b/src/runtime/metrics/description.go
new file mode 100644
index 0000000000..32bb950a72
--- /dev/null
+++ b/src/runtime/metrics/description.go
@@ -0,0 +1,52 @@
+// 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
+
+// Description describes a runtime metric.
+type Description struct {
+ // Name is the full name of the metric which includes the unit.
+ //
+ // The format of the metric may be described by the following regular expression.
+ //
+ // ^(?P<name>/[^:]+):(?P<unit>[^:*\/]+(?:[*\/][^:*\/]+)*)$
+ //
+ // The format splits the name into two components, separated by a colon: a path which always
+ // starts with a /, and a machine-parseable unit. The name may contain any valid Unicode
+ // codepoint in between / characters, but by convention will try to stick to lowercase
+ // characters and hyphens. An example of such a path might be "/memory/heap/free".
+ //
+ // The unit is by convention a series of lowercase English unit names (singular or plural)
+ // without prefixes delimited by '*' or '/'. The unit names may contain any valid Unicode
+ // codepoint that is not a delimiter.
+ // Examples of units might be "seconds", "bytes", "bytes/second", "cpu-seconds",
+ // "byte*cpu-seconds", and "bytes/second/second".
+ //
+ // A complete name might look like "/memory/heap/free:bytes".
+ Name string
+
+ // Kind is the kind of value for this metric.
+ //
+ // The purpose of this field is to allow users to filter out metrics whose values are
+ // types which their application may not understand.
+ Kind ValueKind
+
+ // Cumulative is whether or not the metric is cumulative. If a cumulative metric is just
+ // a single number, then it increases monotonically. If the metric is a distribution,
+ // then each bucket count increases monotonically.
+ //
+ // This flag thus indicates whether or not it's useful to compute a rate from this value.
+ Cumulative bool
+
+ // StopTheWorld is whether or not the metric requires a stop-the-world
+ // event in order to collect it.
+ StopTheWorld bool
+}
+
+var allDesc = []Description{}
+
+// All returns a slice of containing metric descriptions for all supported metrics.
+func All() []Description {
+ return allDesc
+}
diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go
new file mode 100644
index 0000000000..b48c22ba30
--- /dev/null
+++ b/src/runtime/metrics/doc.go
@@ -0,0 +1,49 @@
+// 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 provides a stable interface to access implementation-defined
+metrics exported by the Go runtime. This package is similar to existing functions
+like runtime.ReadMemStats and debug.ReadGCStats, but significantly more general.
+
+The set of metrics defined by this package may evolve as the runtime itself
+evolves, and also enables variation across Go implementations, whose relevant
+metric sets may not intersect.
+
+Interface
+
+Metrics are designated by a string key, rather than, for example, a field name in
+a struct. The full list of supported metrics is always available in the slice of
+Descriptions returned by All. Each Description also includes useful information
+about the metric, such as how to display it (e.g. gauge vs. counter) and how difficult
+or disruptive it is to obtain it (e.g. do you need to stop the world?).
+
+Thus, users of this API are encouraged to sample supported metrics defined by the
+slice returned by All to remain compatible across Go versions. Of course, situations
+arise where reading specific metrics is critical. For these cases, users are
+encouranged to use build tags, and although metrics may be deprecated and removed,
+users should consider this to be an exceptional and rare event, coinciding with a
+very large change in a particular Go implementation.
+
+Each metric key also has a "kind" that describes the format of the metric's value.
+In the interest of not breaking users of this package, the "kind" for a given metric
+is guaranteed not to change. If it must change, then a new metric will be introduced
+with a new key and a new "kind."
+
+Metric key format
+
+As mentioned earlier, metric keys are strings. Their format is simple and well-defined,
+designed to be both human and machine readable. It is split into two components,
+separated by a colon: a rooted path and a unit. The choice to include the unit in
+the key is motivated by compatibility: if a metric's unit changes, its semantics likely
+did also, and a new key should be introduced.
+
+For more details on the precise definition of the metric key's path and unit formats, see
+the documentation of the Name field of the Description struct.
+
+Supported metrics
+
+TODO(mknyszek): List them here as they're added.
+*/
+package metrics
diff --git a/src/runtime/metrics/histogram.go b/src/runtime/metrics/histogram.go
new file mode 100644
index 0000000000..e1364e1e26
--- /dev/null
+++ b/src/runtime/metrics/histogram.go
@@ -0,0 +1,30 @@
+// 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
+
+// Float64Histogram represents a distribution of float64 values.
+type Float64Histogram struct {
+ // Counts contains the weights for each histogram bucket. The length of
+ // Counts is equal to the length of Buckets (in the metric description)
+ // plus one to account for the implicit minimum bucket.
+ //
+ // Given N buckets, the following is the mathematical relationship between
+ // Counts and Buckets.
+ // count[0] is the weight of the range (-inf, bucket[0])
+ // count[n] is the weight of the range [bucket[n], bucket[n+1]), for 0 < n < N-1
+ // count[N-1] is the weight of the range [bucket[N-1], inf)
+ Counts []uint64
+
+ // Buckets contains the boundaries between histogram buckets, in increasing order.
+ //
+ // Because this slice contains boundaries, there are len(Buckets)+1 counts:
+ // a count for all values less than the first boundary, a count covering each
+ // [slice[i], slice[i+1]) interval, and a count for all values greater than or
+ // equal to the last boundary.
+ //
+ // For a given metric name, the value of Buckets is guaranteed not to change
+ // between calls until program exit.
+ Buckets []float64
+}
diff --git a/src/runtime/metrics/sample.go b/src/runtime/metrics/sample.go
new file mode 100644
index 0000000000..c7a3fc424a
--- /dev/null
+++ b/src/runtime/metrics/sample.go
@@ -0,0 +1,29 @@
+// 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
+
+// Sample captures a single metric sample.
+type Sample struct {
+ // Name is the name of the metric sampled.
+ //
+ // It must correspond to a name in one of the metric descriptions
+ // returned by Descriptions.
+ Name string
+
+ // Value is the value of the metric sample.
+ Value Value
+}
+
+// Read populates each Value field in the given slice of metric samples.
+//
+// Desired metrics should be present in the slice with the appropriate name.
+// The user of this API is encouraged to re-use the same slice between calls.
+//
+// Metric values with names not appearing in the value returned by Descriptions
+// will have the value populated as KindBad to indicate that the name is
+// unknown.
+func Read(m []Sample) {
+ panic("unimplemented")
+}
diff --git a/src/runtime/metrics/value.go b/src/runtime/metrics/value.go
new file mode 100644
index 0000000000..0b056b4ea8
--- /dev/null
+++ b/src/runtime/metrics/value.go
@@ -0,0 +1,69 @@
+// 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
+
+import (
+ "math"
+ "unsafe"
+)
+
+// ValueKind is a tag for a metric Value which indicates its type.
+type ValueKind int
+
+const (
+ // KindBad indicates that the Value has no type and should not be used.
+ KindBad ValueKind = iota
+
+ // KindUint64 indicates that the type of the Value is a uint64.
+ KindUint64
+
+ // KindFloat64 indicates that the type of the Value is a float64.
+ KindFloat64
+
+ // KindFloat64Histogram indicates that the type of the Value is a *Float64Histogram.
+ KindFloat64Histogram
+)
+
+// Value represents a metric value returned by the runtime.
+type Value struct {
+ kind ValueKind
+ scalar uint64 // contains scalar values for scalar Kinds.
+ pointer unsafe.Pointer // contains non-scalar values.
+}
+
+// Kind returns the a tag representing the kind of value this is.
+func (v Value) Kind() ValueKind {
+ return v.kind
+}
+
+// Uint64 returns the internal uint64 value for the metric.
+//
+// If v.Kind() != KindUint64, this method panics.
+func (v Value) Uint64() uint64 {
+ if v.kind != KindUint64 {
+ panic("called Uint64 on non-uint64 metric value")
+ }
+ return v.scalar
+}
+
+// Float64 returns the internal float64 value for the metric.
+//
+// If v.Kind() != KindFloat64, this method panics.
+func (v Value) Float64() float64 {
+ if v.kind != KindFloat64 {
+ panic("called Float64 on non-float64 metric value")
+ }
+ return math.Float64frombits(v.scalar)
+}
+
+// Float64Histogram returns the internal *Float64Histogram value for the metric.
+//
+// If v.Kind() != KindFloat64Histogram, this method panics.
+func (v Value) Float64Histogram() *Float64Histogram {
+ if v.kind != KindFloat64Histogram {
+ panic("called Float64 on non-float64 metric value")
+ }
+ return (*Float64Histogram)(v.pointer)
+}