mirror of https://github.com/knative/pkg.git
Expose Go memstats as metrics. (#711)
This exposes metrics for the properties available through [here](https://godoc.org/runtime#MemStats) so that we can get some better visibility into things like GC pressure.
This commit is contained in:
parent
1ba51667e8
commit
2e019c8a87
|
|
@ -25,7 +25,9 @@ import (
|
|||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/stats/view"
|
||||
"golang.org/x/sync/errgroup"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
|
|
@ -113,6 +115,14 @@ func MainWithConfig(ctx context.Context, component string, cfg *rest.Config, cto
|
|||
log.Printf("Registering %d informers", len(injection.Default.GetInformers()))
|
||||
log.Printf("Registering %d controllers", len(ctors))
|
||||
|
||||
// Report stats on Go memory usage every 30 seconds.
|
||||
msp := metrics.NewMemStatsAll()
|
||||
msp.Start(ctx, 30*time.Second)
|
||||
|
||||
if err := view.Register(msp.DefaultViews()...); err != nil {
|
||||
log.Fatalf("Error exporting go memstats view: %v", err)
|
||||
}
|
||||
|
||||
// Adjust our client's rate limits based on the number of controller's we are running.
|
||||
cfg.QPS = float32(len(ctors)) * rest.DefaultQPS
|
||||
cfg.Burst = len(ctors) * rest.DefaultBurst
|
||||
|
|
|
|||
|
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
Copyright 2019 The Knative Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/stats/view"
|
||||
)
|
||||
|
||||
// NewMemStatsAll creates a new MemStatsProvider with stats for all of the
|
||||
// supported Go runtime.MemStat fields.
|
||||
func NewMemStatsAll() *MemStatsProvider {
|
||||
return &MemStatsProvider{
|
||||
Alloc: stats.Int64(
|
||||
"go_alloc",
|
||||
"The number of bytes of allocated heap objects.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
TotalAlloc: stats.Int64(
|
||||
"go_total_alloc",
|
||||
"The cumulative bytes allocated for heap objects.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
Sys: stats.Int64(
|
||||
"go_sys",
|
||||
"The total bytes of memory obtained from the OS.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
Lookups: stats.Int64(
|
||||
"go_lookups",
|
||||
"The number of pointer lookups performed by the runtime.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
Mallocs: stats.Int64(
|
||||
"go_mallocs",
|
||||
"The cumulative count of heap objects allocated.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
Frees: stats.Int64(
|
||||
"go_frees",
|
||||
"The cumulative count of heap objects freed.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
HeapAlloc: stats.Int64(
|
||||
"go_heap_alloc",
|
||||
"The number of bytes of allocated heap objects.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
HeapSys: stats.Int64(
|
||||
"go_heap_sys",
|
||||
"The number of bytes of heap memory obtained from the OS.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
HeapIdle: stats.Int64(
|
||||
"go_heap_idle",
|
||||
"The number of bytes in idle (unused) spans.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
HeapInuse: stats.Int64(
|
||||
"go_heap_in_use",
|
||||
"The number of bytes in in-use spans.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
HeapReleased: stats.Int64(
|
||||
"go_heap_released",
|
||||
"The number of bytes of physical memory returned to the OS.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
HeapObjects: stats.Int64(
|
||||
"go_heap_objects",
|
||||
"The number of allocated heap objects.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
StackInuse: stats.Int64(
|
||||
"go_stack_in_use",
|
||||
"The number of bytes in stack spans.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
StackSys: stats.Int64(
|
||||
"go_stack_sys",
|
||||
"The number of bytes of stack memory obtained from the OS.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
MSpanInuse: stats.Int64(
|
||||
"go_mspan_in_use",
|
||||
"The number of bytes of allocated mspan structures.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
MSpanSys: stats.Int64(
|
||||
"go_mspan_sys",
|
||||
"The number of bytes of memory obtained from the OS for mspan structures.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
MCacheInuse: stats.Int64(
|
||||
"go_mcache_in_use",
|
||||
"The number of bytes of allocated mcache structures.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
MCacheSys: stats.Int64(
|
||||
"go_mcache_sys",
|
||||
"The number of bytes of memory obtained from the OS for mcache structures.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
BuckHashSys: stats.Int64(
|
||||
"go_bucket_hash_sys",
|
||||
"The number of bytes of memory in profiling bucket hash tables.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
GCSys: stats.Int64(
|
||||
"go_gc_sys",
|
||||
"The number of bytes of memory in garbage collection metadata.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
OtherSys: stats.Int64(
|
||||
"go_other_sys",
|
||||
"The number of bytes of memory in miscellaneous off-heap runtime allocations.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
NextGC: stats.Int64(
|
||||
"go_next_gc",
|
||||
"The target heap size of the next GC cycle.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
LastGC: stats.Int64(
|
||||
"go_last_gc",
|
||||
"The time the last garbage collection finished, as nanoseconds since 1970 (the UNIX epoch).",
|
||||
"ns",
|
||||
),
|
||||
PauseTotalNs: stats.Int64(
|
||||
"go_total_gc_pause_ns",
|
||||
"The cumulative nanoseconds in GC stop-the-world pauses since the program started.",
|
||||
"ns",
|
||||
),
|
||||
NumGC: stats.Int64(
|
||||
"go_num_gc",
|
||||
"The number of completed GC cycles.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
NumForcedGC: stats.Int64(
|
||||
"go_num_forced_gc",
|
||||
"The number of GC cycles that were forced by the application calling the GC function.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
GCCPUFraction: stats.Float64(
|
||||
"go_gc_cpu_fraction",
|
||||
"The fraction of this program's available CPU time used by the GC since the program started.",
|
||||
stats.UnitNone,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// MemStatsProvider is used to expose metrics based on Go's runtime.MemStats.
|
||||
// The fields below (and their comments) are a filtered list taken from
|
||||
// Go's runtime.MemStats.
|
||||
type MemStatsProvider struct {
|
||||
// Alloc is bytes of allocated heap objects.
|
||||
//
|
||||
// This is the same as HeapAlloc (see below).
|
||||
Alloc *stats.Int64Measure
|
||||
|
||||
// TotalAlloc is cumulative bytes allocated for heap objects.
|
||||
//
|
||||
// TotalAlloc increases as heap objects are allocated, but
|
||||
// unlike Alloc and HeapAlloc, it does not decrease when
|
||||
// objects are freed.
|
||||
TotalAlloc *stats.Int64Measure
|
||||
|
||||
// Sys is the total bytes of memory obtained from the OS.
|
||||
//
|
||||
// Sys is the sum of the XSys fields below. Sys measures the
|
||||
// virtual address space reserved by the Go runtime for the
|
||||
// heap, stacks, and other internal data structures. It's
|
||||
// likely that not all of the virtual address space is backed
|
||||
// by physical memory at any given moment, though in general
|
||||
// it all was at some point.
|
||||
Sys *stats.Int64Measure
|
||||
|
||||
// Lookups is the number of pointer lookups performed by the
|
||||
// runtime.
|
||||
//
|
||||
// This is primarily useful for debugging runtime internals.
|
||||
Lookups *stats.Int64Measure
|
||||
|
||||
// Mallocs is the cumulative count of heap objects allocated.
|
||||
// The number of live objects is Mallocs - Frees.
|
||||
Mallocs *stats.Int64Measure
|
||||
|
||||
// Frees is the cumulative count of heap objects freed.
|
||||
Frees *stats.Int64Measure
|
||||
|
||||
// HeapAlloc is bytes of allocated heap objects.
|
||||
//
|
||||
// "Allocated" heap objects include all reachable objects, as
|
||||
// well as unreachable objects that the garbage collector has
|
||||
// not yet freed. Specifically, HeapAlloc increases as heap
|
||||
// objects are allocated and decreases as the heap is swept
|
||||
// and unreachable objects are freed. Sweeping occurs
|
||||
// incrementally between GC cycles, so these two processes
|
||||
// occur simultaneously, and as a result HeapAlloc tends to
|
||||
// change smoothly (in contrast with the sawtooth that is
|
||||
// typical of stop-the-world garbage collectors).
|
||||
HeapAlloc *stats.Int64Measure
|
||||
|
||||
// HeapSys is bytes of heap memory obtained from the OS.
|
||||
//
|
||||
// HeapSys measures the amount of virtual address space
|
||||
// reserved for the heap. This includes virtual address space
|
||||
// that has been reserved but not yet used, which consumes no
|
||||
// physical memory, but tends to be small, as well as virtual
|
||||
// address space for which the physical memory has been
|
||||
// returned to the OS after it became unused (see HeapReleased
|
||||
// for a measure of the latter).
|
||||
//
|
||||
// HeapSys estimates the largest size the heap has had.
|
||||
HeapSys *stats.Int64Measure
|
||||
|
||||
// HeapIdle is bytes in idle (unused) spans.
|
||||
//
|
||||
// Idle spans have no objects in them. These spans could be
|
||||
// (and may already have been) returned to the OS, or they can
|
||||
// be reused for heap allocations, or they can be reused as
|
||||
// stack memory.
|
||||
//
|
||||
// HeapIdle minus HeapReleased estimates the amount of memory
|
||||
// that could be returned to the OS, but is being retained by
|
||||
// the runtime so it can grow the heap without requesting more
|
||||
// memory from the OS. If this difference is significantly
|
||||
// larger than the heap size, it indicates there was a recent
|
||||
// transient spike in live heap size.
|
||||
HeapIdle *stats.Int64Measure
|
||||
|
||||
// HeapInuse is bytes in in-use spans.
|
||||
//
|
||||
// In-use spans have at least one object in them. These spans
|
||||
// can only be used for other objects of roughly the same
|
||||
// size.
|
||||
//
|
||||
// HeapInuse minus HeapAlloc estimates the amount of memory
|
||||
// that has been dedicated to particular size classes, but is
|
||||
// not currently being used. This is an upper bound on
|
||||
// fragmentation, but in general this memory can be reused
|
||||
// efficiently.
|
||||
HeapInuse *stats.Int64Measure
|
||||
|
||||
// HeapReleased is bytes of physical memory returned to the OS.
|
||||
//
|
||||
// This counts heap memory from idle spans that was returned
|
||||
// to the OS and has not yet been reacquired for the heap.
|
||||
HeapReleased *stats.Int64Measure
|
||||
|
||||
// HeapObjects is the number of allocated heap objects.
|
||||
//
|
||||
// Like HeapAlloc, this increases as objects are allocated and
|
||||
// decreases as the heap is swept and unreachable objects are
|
||||
// freed.
|
||||
HeapObjects *stats.Int64Measure
|
||||
|
||||
// StackInuse is bytes in stack spans.
|
||||
//
|
||||
// In-use stack spans have at least one stack in them. These
|
||||
// spans can only be used for other stacks of the same size.
|
||||
//
|
||||
// There is no StackIdle because unused stack spans are
|
||||
// returned to the heap (and hence counted toward HeapIdle).
|
||||
StackInuse *stats.Int64Measure
|
||||
|
||||
// StackSys is bytes of stack memory obtained from the OS.
|
||||
//
|
||||
// StackSys is StackInuse, plus any memory obtained directly
|
||||
// from the OS for OS thread stacks (which should be minimal).
|
||||
StackSys *stats.Int64Measure
|
||||
|
||||
// MSpanInuse is bytes of allocated mspan structures.
|
||||
MSpanInuse *stats.Int64Measure
|
||||
|
||||
// MSpanSys is bytes of memory obtained from the OS for mspan
|
||||
// structures.
|
||||
MSpanSys *stats.Int64Measure
|
||||
|
||||
// MCacheInuse is bytes of allocated mcache structures.
|
||||
MCacheInuse *stats.Int64Measure
|
||||
|
||||
// MCacheSys is bytes of memory obtained from the OS for
|
||||
// mcache structures.
|
||||
MCacheSys *stats.Int64Measure
|
||||
|
||||
// BuckHashSys is bytes of memory in profiling bucket hash tables.
|
||||
BuckHashSys *stats.Int64Measure
|
||||
|
||||
// GCSys is bytes of memory in garbage collection metadata.
|
||||
GCSys *stats.Int64Measure
|
||||
|
||||
// OtherSys is bytes of memory in miscellaneous off-heap
|
||||
// runtime allocations.
|
||||
OtherSys *stats.Int64Measure
|
||||
|
||||
// NextGC is the target heap size of the next GC cycle.
|
||||
//
|
||||
// The garbage collector's goal is to keep HeapAlloc ≤ NextGC.
|
||||
// At the end of each GC cycle, the target for the next cycle
|
||||
// is computed based on the amount of reachable data and the
|
||||
// value of GOGC.
|
||||
NextGC *stats.Int64Measure
|
||||
|
||||
// LastGC is the time the last garbage collection finished, as
|
||||
// nanoseconds since 1970 (the UNIX epoch).
|
||||
LastGC *stats.Int64Measure
|
||||
|
||||
// PauseTotalNs is the cumulative nanoseconds in GC
|
||||
// stop-the-world pauses since the program started.
|
||||
//
|
||||
// During a stop-the-world pause, all goroutines are paused
|
||||
// and only the garbage collector can run.
|
||||
PauseTotalNs *stats.Int64Measure
|
||||
|
||||
// NumGC is the number of completed GC cycles.
|
||||
NumGC *stats.Int64Measure
|
||||
|
||||
// NumForcedGC is the number of GC cycles that were forced by
|
||||
// the application calling the GC function.
|
||||
NumForcedGC *stats.Int64Measure
|
||||
|
||||
// GCCPUFraction is the fraction of this program's available
|
||||
// CPU time used by the GC since the program started.
|
||||
//
|
||||
// GCCPUFraction is expressed as a number between 0 and 1,
|
||||
// where 0 means GC has consumed none of this program's CPU. A
|
||||
// program's available CPU time is defined as the integral of
|
||||
// GOMAXPROCS since the program started. That is, if
|
||||
// GOMAXPROCS is 2 and a program has been running for 10
|
||||
// seconds, its "available CPU" is 20 seconds. GCCPUFraction
|
||||
// does not include CPU time used for write barrier activity.
|
||||
//
|
||||
// This is the same as the fraction of CPU reported by
|
||||
// GODEBUG=gctrace=1.
|
||||
GCCPUFraction *stats.Float64Measure
|
||||
}
|
||||
|
||||
// Start initiates a Go routine that starts pushing metrics into
|
||||
// the provided measures.
|
||||
func (msp *MemStatsProvider) Start(ctx context.Context, period time.Duration) {
|
||||
go func() {
|
||||
ticker := time.NewTicker(period)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
ms := runtime.MemStats{}
|
||||
runtime.ReadMemStats(&ms)
|
||||
if msp.Alloc != nil {
|
||||
Record(ctx, msp.Alloc.M(int64(ms.Alloc)))
|
||||
}
|
||||
if msp.TotalAlloc != nil {
|
||||
Record(ctx, msp.TotalAlloc.M(int64(ms.TotalAlloc)))
|
||||
}
|
||||
if msp.Sys != nil {
|
||||
Record(ctx, msp.Sys.M(int64(ms.Sys)))
|
||||
}
|
||||
if msp.Lookups != nil {
|
||||
Record(ctx, msp.Lookups.M(int64(ms.Lookups)))
|
||||
}
|
||||
if msp.Mallocs != nil {
|
||||
Record(ctx, msp.Mallocs.M(int64(ms.Mallocs)))
|
||||
}
|
||||
if msp.Frees != nil {
|
||||
Record(ctx, msp.Frees.M(int64(ms.Frees)))
|
||||
}
|
||||
if msp.HeapAlloc != nil {
|
||||
Record(ctx, msp.HeapAlloc.M(int64(ms.HeapAlloc)))
|
||||
}
|
||||
if msp.HeapSys != nil {
|
||||
Record(ctx, msp.HeapSys.M(int64(ms.HeapSys)))
|
||||
}
|
||||
if msp.HeapIdle != nil {
|
||||
Record(ctx, msp.HeapIdle.M(int64(ms.HeapIdle)))
|
||||
}
|
||||
if msp.HeapInuse != nil {
|
||||
Record(ctx, msp.HeapInuse.M(int64(ms.HeapInuse)))
|
||||
}
|
||||
if msp.HeapReleased != nil {
|
||||
Record(ctx, msp.HeapReleased.M(int64(ms.HeapReleased)))
|
||||
}
|
||||
if msp.HeapObjects != nil {
|
||||
Record(ctx, msp.HeapObjects.M(int64(ms.HeapObjects)))
|
||||
}
|
||||
if msp.StackInuse != nil {
|
||||
Record(ctx, msp.StackInuse.M(int64(ms.StackInuse)))
|
||||
}
|
||||
if msp.StackSys != nil {
|
||||
Record(ctx, msp.StackSys.M(int64(ms.StackSys)))
|
||||
}
|
||||
if msp.MSpanInuse != nil {
|
||||
Record(ctx, msp.MSpanInuse.M(int64(ms.MSpanInuse)))
|
||||
}
|
||||
if msp.MSpanSys != nil {
|
||||
Record(ctx, msp.MSpanSys.M(int64(ms.MSpanSys)))
|
||||
}
|
||||
if msp.MCacheInuse != nil {
|
||||
Record(ctx, msp.MCacheInuse.M(int64(ms.MCacheInuse)))
|
||||
}
|
||||
if msp.MCacheSys != nil {
|
||||
Record(ctx, msp.MCacheSys.M(int64(ms.MCacheSys)))
|
||||
}
|
||||
if msp.BuckHashSys != nil {
|
||||
Record(ctx, msp.BuckHashSys.M(int64(ms.BuckHashSys)))
|
||||
}
|
||||
if msp.GCSys != nil {
|
||||
Record(ctx, msp.GCSys.M(int64(ms.GCSys)))
|
||||
}
|
||||
if msp.OtherSys != nil {
|
||||
Record(ctx, msp.OtherSys.M(int64(ms.OtherSys)))
|
||||
}
|
||||
if msp.NextGC != nil {
|
||||
Record(ctx, msp.NextGC.M(int64(ms.NextGC)))
|
||||
}
|
||||
if msp.LastGC != nil {
|
||||
Record(ctx, msp.LastGC.M(int64(ms.LastGC)))
|
||||
}
|
||||
if msp.PauseTotalNs != nil {
|
||||
Record(ctx, msp.PauseTotalNs.M(int64(ms.PauseTotalNs)))
|
||||
}
|
||||
if msp.NumGC != nil {
|
||||
Record(ctx, msp.NumGC.M(int64(ms.NumGC)))
|
||||
}
|
||||
if msp.NumForcedGC != nil {
|
||||
Record(ctx, msp.NumForcedGC.M(int64(ms.NumForcedGC)))
|
||||
}
|
||||
if msp.GCCPUFraction != nil {
|
||||
Record(ctx, msp.GCCPUFraction.M(ms.GCCPUFraction))
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// DefaultViews returns a list of views suitable for passing to view.Register
|
||||
func (msp *MemStatsProvider) DefaultViews() (views []*view.View) {
|
||||
if m := msp.Alloc; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.TotalAlloc; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.Sys; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.Lookups; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.Mallocs; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.Frees; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.HeapAlloc; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.HeapSys; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.HeapIdle; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.HeapInuse; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.HeapReleased; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.HeapObjects; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.StackInuse; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.StackSys; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.MSpanInuse; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.MSpanSys; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.MCacheInuse; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.MCacheSys; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.BuckHashSys; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.GCSys; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.OtherSys; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.NextGC; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.LastGC; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.PauseTotalNs; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.NumGC; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.NumForcedGC; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
if m := msp.GCCPUFraction; m != nil {
|
||||
views = append(views, measureView(m, view.LastValue()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Copyright 2019 The Knative Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/stats/view"
|
||||
|
||||
"knative.dev/pkg/metrics/metricstest"
|
||||
)
|
||||
|
||||
func TestMemStatsMetrics(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
period := 200 * time.Millisecond
|
||||
|
||||
msp := NewMemStatsAll()
|
||||
msp.Start(ctx, period)
|
||||
|
||||
// Reset the metrics configuration to avoid leaked state from other tests.
|
||||
setCurMetricsConfig(nil)
|
||||
|
||||
views := msp.DefaultViews()
|
||||
if got, want := len(views), 27; got != want {
|
||||
t.Errorf("len(DefaultViews()) = %d, want %d", got, want)
|
||||
}
|
||||
if err := view.Register(views...); err != nil {
|
||||
t.Errorf("view.Register() = %v", err)
|
||||
}
|
||||
defer view.Unregister(views...)
|
||||
|
||||
metricstest.CheckStatsNotReported(t,
|
||||
"go_alloc",
|
||||
"go_total_alloc",
|
||||
"go_sys",
|
||||
"go_lookups",
|
||||
"go_mallocs",
|
||||
"go_frees",
|
||||
"go_heap_alloc",
|
||||
"go_heap_sys",
|
||||
"go_heap_idle",
|
||||
"go_heap_in_use",
|
||||
"go_heap_released",
|
||||
"go_heap_objects",
|
||||
"go_stack_in_use",
|
||||
"go_stack_sys",
|
||||
"go_mspan_in_use",
|
||||
"go_mspan_sys",
|
||||
"go_mcache_in_use",
|
||||
"go_mcache_sys",
|
||||
"go_bucket_hash_sys",
|
||||
"go_gc_sys",
|
||||
"go_other_sys",
|
||||
"go_next_gc",
|
||||
"go_last_gc",
|
||||
"go_total_gc_pause_ns",
|
||||
"go_num_gc",
|
||||
"go_num_forced_gc",
|
||||
"go_gc_cpu_fraction",
|
||||
)
|
||||
|
||||
time.Sleep(period + 100*time.Millisecond)
|
||||
|
||||
metricstest.CheckStatsReported(t,
|
||||
"go_alloc",
|
||||
"go_total_alloc",
|
||||
"go_sys",
|
||||
"go_lookups",
|
||||
"go_mallocs",
|
||||
"go_frees",
|
||||
"go_heap_alloc",
|
||||
"go_heap_sys",
|
||||
"go_heap_idle",
|
||||
"go_heap_in_use",
|
||||
"go_heap_released",
|
||||
"go_heap_objects",
|
||||
"go_stack_in_use",
|
||||
"go_stack_sys",
|
||||
"go_mspan_in_use",
|
||||
"go_mspan_sys",
|
||||
"go_mcache_in_use",
|
||||
"go_mcache_sys",
|
||||
"go_bucket_hash_sys",
|
||||
"go_gc_sys",
|
||||
"go_other_sys",
|
||||
"go_next_gc",
|
||||
"go_last_gc",
|
||||
"go_total_gc_pause_ns",
|
||||
"go_num_gc",
|
||||
"go_num_forced_gc",
|
||||
"go_gc_cpu_fraction",
|
||||
)
|
||||
|
||||
// We have seen zero forced GCs.
|
||||
metricstest.CheckLastValueData(t, "go_num_forced_gc", map[string]string{}, 0)
|
||||
|
||||
// Force a GC, and wait for the reporting period.
|
||||
runtime.GC()
|
||||
time.Sleep(period + 100*time.Millisecond)
|
||||
|
||||
// Now we should report a single forced GC.
|
||||
metricstest.CheckLastValueData(t, "go_num_forced_gc", map[string]string{}, 1)
|
||||
|
||||
// Repeat, and we should see two.
|
||||
runtime.GC()
|
||||
time.Sleep(period + 100*time.Millisecond)
|
||||
metricstest.CheckLastValueData(t, "go_num_forced_gc", map[string]string{}, 2)
|
||||
|
||||
// After we cancel the context, it should kill the go routine and any additional GCs
|
||||
// should not be reported.
|
||||
cancel()
|
||||
runtime.GC()
|
||||
time.Sleep(period + 100*time.Millisecond)
|
||||
metricstest.CheckLastValueData(t, "go_num_forced_gc", map[string]string{}, 2)
|
||||
}
|
||||
Loading…
Reference in New Issue