mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
Merge pull request #106432 from MikeSpreitzer/regularize-observers
Factored TimedObserver into less surprising pieces
This commit is contained in:
commit
2b3ff415ba
@ -61,13 +61,13 @@ func handleError(w http.ResponseWriter, r *http.Request, err error) {
|
|||||||
// requestWatermark is used to track maximal numbers of requests in a particular phase of handling
|
// requestWatermark is used to track maximal numbers of requests in a particular phase of handling
|
||||||
type requestWatermark struct {
|
type requestWatermark struct {
|
||||||
phase string
|
phase string
|
||||||
readOnlyObserver, mutatingObserver fcmetrics.TimedObserver
|
readOnlyObserver, mutatingObserver fcmetrics.RatioedChangeObserver
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
readOnlyWatermark, mutatingWatermark int
|
readOnlyWatermark, mutatingWatermark int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *requestWatermark) recordMutating(mutatingVal int) {
|
func (w *requestWatermark) recordMutating(mutatingVal int) {
|
||||||
w.mutatingObserver.Set(float64(mutatingVal))
|
w.mutatingObserver.Observe(float64(mutatingVal))
|
||||||
|
|
||||||
w.lock.Lock()
|
w.lock.Lock()
|
||||||
defer w.lock.Unlock()
|
defer w.lock.Unlock()
|
||||||
@ -78,7 +78,7 @@ func (w *requestWatermark) recordMutating(mutatingVal int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *requestWatermark) recordReadOnly(readOnlyVal int) {
|
func (w *requestWatermark) recordReadOnly(readOnlyVal int) {
|
||||||
w.readOnlyObserver.Set(float64(readOnlyVal))
|
w.readOnlyObserver.Observe(float64(readOnlyVal))
|
||||||
|
|
||||||
w.lock.Lock()
|
w.lock.Lock()
|
||||||
defer w.lock.Unlock()
|
defer w.lock.Unlock()
|
||||||
@ -132,11 +132,11 @@ func WithMaxInFlightLimit(
|
|||||||
var mutatingChan chan bool
|
var mutatingChan chan bool
|
||||||
if nonMutatingLimit != 0 {
|
if nonMutatingLimit != 0 {
|
||||||
nonMutatingChan = make(chan bool, nonMutatingLimit)
|
nonMutatingChan = make(chan bool, nonMutatingLimit)
|
||||||
watermark.readOnlyObserver.SetX1(float64(nonMutatingLimit))
|
watermark.readOnlyObserver.SetDenominator(float64(nonMutatingLimit))
|
||||||
}
|
}
|
||||||
if mutatingLimit != 0 {
|
if mutatingLimit != 0 {
|
||||||
mutatingChan = make(chan bool, mutatingLimit)
|
mutatingChan = make(chan bool, mutatingLimit)
|
||||||
watermark.mutatingObserver.SetX1(float64(mutatingLimit))
|
watermark.mutatingObserver.SetDenominator(float64(mutatingLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -102,8 +102,8 @@ type configController struct {
|
|||||||
name string // varies in tests of fighting controllers
|
name string // varies in tests of fighting controllers
|
||||||
clock clock.PassiveClock
|
clock clock.PassiveClock
|
||||||
queueSetFactory fq.QueueSetFactory
|
queueSetFactory fq.QueueSetFactory
|
||||||
reqsObsPairGenerator metrics.TimedObserverPairGenerator
|
reqsObsPairGenerator metrics.RatioedChangeObserverPairGenerator
|
||||||
execSeatsObsGenerator metrics.TimedObserverGenerator
|
execSeatsObsGenerator metrics.RatioedChangeObserverGenerator
|
||||||
|
|
||||||
// How this controller appears in an ObjectMeta ManagedFieldsEntry.Manager
|
// How this controller appears in an ObjectMeta ManagedFieldsEntry.Manager
|
||||||
asFieldManager string
|
asFieldManager string
|
||||||
@ -193,10 +193,10 @@ type priorityLevelState struct {
|
|||||||
numPending int
|
numPending int
|
||||||
|
|
||||||
// Observers tracking number of requests waiting, executing
|
// Observers tracking number of requests waiting, executing
|
||||||
reqsObsPair metrics.TimedObserverPair
|
reqsObsPair metrics.RatioedChangeObserverPair
|
||||||
|
|
||||||
// Observer of number of seats occupied throughout execution
|
// Observer of number of seats occupied throughout execution
|
||||||
execSeatsObs metrics.TimedObserver
|
execSeatsObs metrics.RatioedChangeObserver
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTestableController is extra flexible to facilitate testing
|
// NewTestableController is extra flexible to facilitate testing
|
||||||
@ -693,7 +693,7 @@ func (meal *cfgMeal) finishQueueSetReconfigsLocked() {
|
|||||||
// given priority level configuration. Returns nil if that config
|
// given priority level configuration. Returns nil if that config
|
||||||
// does not call for limiting. Returns nil and an error if the given
|
// does not call for limiting. Returns nil and an error if the given
|
||||||
// object is malformed in a way that is a problem for this package.
|
// object is malformed in a way that is a problem for this package.
|
||||||
func queueSetCompleterForPL(qsf fq.QueueSetFactory, queues fq.QueueSet, pl *flowcontrol.PriorityLevelConfiguration, requestWaitLimit time.Duration, reqsIntPair metrics.TimedObserverPair, execSeatsObs metrics.TimedObserver) (fq.QueueSetCompleter, error) {
|
func queueSetCompleterForPL(qsf fq.QueueSetFactory, queues fq.QueueSet, pl *flowcontrol.PriorityLevelConfiguration, requestWaitLimit time.Duration, reqsIntPair metrics.RatioedChangeObserverPair, execSeatsObs metrics.RatioedChangeObserver) (fq.QueueSetCompleter, error) {
|
||||||
if (pl.Spec.Type == flowcontrol.PriorityLevelEnablementExempt) != (pl.Spec.Limited == nil) {
|
if (pl.Spec.Type == flowcontrol.PriorityLevelEnablementExempt) != (pl.Spec.Limited == nil) {
|
||||||
return nil, errors.New("broken union structure at the top")
|
return nil, errors.New("broken union structure at the top")
|
||||||
}
|
}
|
||||||
|
@ -135,10 +135,10 @@ type TestableConfig struct {
|
|||||||
RequestWaitLimit time.Duration
|
RequestWaitLimit time.Duration
|
||||||
|
|
||||||
// ObsPairGenerator for metrics about requests
|
// ObsPairGenerator for metrics about requests
|
||||||
ReqsObsPairGenerator metrics.TimedObserverPairGenerator
|
ReqsObsPairGenerator metrics.RatioedChangeObserverPairGenerator
|
||||||
|
|
||||||
// TimedObserverPairGenerator for metrics about seats occupied by all phases of execution
|
// RatioedChangeObserverPairGenerator for metrics about seats occupied by all phases of execution
|
||||||
ExecSeatsObsGenerator metrics.TimedObserverGenerator
|
ExecSeatsObsGenerator metrics.RatioedChangeObserverGenerator
|
||||||
|
|
||||||
// QueueSetFactory for the queuing implementation
|
// QueueSetFactory for the queuing implementation
|
||||||
QueueSetFactory fq.QueueSetFactory
|
QueueSetFactory fq.QueueSetFactory
|
||||||
|
@ -105,7 +105,7 @@ type ctlrTestRequest struct {
|
|||||||
descr1, descr2 interface{}
|
descr1, descr2 interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cts *ctlrTestState) BeginConstruction(qc fq.QueuingConfig, rip metrics.TimedObserverPair, eso metrics.TimedObserver) (fq.QueueSetCompleter, error) {
|
func (cts *ctlrTestState) BeginConstruction(qc fq.QueuingConfig, rip metrics.RatioedChangeObserverPair, eso metrics.RatioedChangeObserver) (fq.QueueSetCompleter, error) {
|
||||||
return ctlrTestQueueSetCompleter{cts, nil, qc}, nil
|
return ctlrTestQueueSetCompleter{cts, nil, qc}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,10 +28,9 @@ import (
|
|||||||
// Integrator computes the moments of some variable X over time as
|
// Integrator computes the moments of some variable X over time as
|
||||||
// read from a particular clock. The integrals start when the
|
// read from a particular clock. The integrals start when the
|
||||||
// Integrator is created, and ends at the latest operation on the
|
// Integrator is created, and ends at the latest operation on the
|
||||||
// Integrator. As a `metrics.TimedObserver` this fixes X1=1 and
|
// Integrator.
|
||||||
// ignores attempts to change X1.
|
|
||||||
type Integrator interface {
|
type Integrator interface {
|
||||||
metrics.TimedObserver
|
metrics.ChangeObserver
|
||||||
|
|
||||||
GetResults() IntegratorResults
|
GetResults() IntegratorResults
|
||||||
|
|
||||||
@ -70,10 +69,7 @@ func NewIntegrator(clock clock.PassiveClock) Integrator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (igr *integrator) SetX1(x1 float64) {
|
func (igr *integrator) Observe(x float64) {
|
||||||
}
|
|
||||||
|
|
||||||
func (igr *integrator) Set(x float64) {
|
|
||||||
igr.Lock()
|
igr.Lock()
|
||||||
igr.setLocked(x)
|
igr.setLocked(x)
|
||||||
igr.Unlock()
|
igr.Unlock()
|
||||||
|
@ -38,7 +38,7 @@ func TestIntegrator(t *testing.T) {
|
|||||||
if !results.Equal(&rToo) {
|
if !results.Equal(&rToo) {
|
||||||
t.Errorf("expected %#+v, got %#+v", results, rToo)
|
t.Errorf("expected %#+v, got %#+v", results, rToo)
|
||||||
}
|
}
|
||||||
igr.Set(2)
|
igr.Observe(2)
|
||||||
results = igr.GetResults()
|
results = igr.GetResults()
|
||||||
if e := (IntegratorResults{Duration: 0, Average: math.NaN(), Deviation: math.NaN(), Min: 2, Max: 3}); !e.Equal(&results) {
|
if e := (IntegratorResults{Duration: 0, Average: math.NaN(), Deviation: math.NaN(), Min: 2, Max: 3}); !e.Equal(&results) {
|
||||||
t.Errorf("expected %#+v, got %#+v", e, results)
|
t.Errorf("expected %#+v, got %#+v", e, results)
|
||||||
|
@ -32,10 +32,10 @@ import (
|
|||||||
// before committing to a concurrency allotment for the second.
|
// before committing to a concurrency allotment for the second.
|
||||||
type QueueSetFactory interface {
|
type QueueSetFactory interface {
|
||||||
// BeginConstruction does the first phase of creating a QueueSet.
|
// BeginConstruction does the first phase of creating a QueueSet.
|
||||||
// The TimedObserverPair observes number of requests,
|
// The RatioedChangeObserverPair observes number of requests,
|
||||||
// execution covering just the regular phase.
|
// execution covering just the regular phase.
|
||||||
// The TimedObserver observes number of seats occupied through all phases of execution.
|
// The RatioedChangeObserver observes number of seats occupied through all phases of execution.
|
||||||
BeginConstruction(QueuingConfig, metrics.TimedObserverPair, metrics.TimedObserver) (QueueSetCompleter, error)
|
BeginConstruction(QueuingConfig, metrics.RatioedChangeObserverPair, metrics.RatioedChangeObserver) (QueueSetCompleter, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueueSetCompleter finishes the two-step process of creating or
|
// QueueSetCompleter finishes the two-step process of creating or
|
||||||
|
@ -61,8 +61,8 @@ type promiseFactoryFactory func(*queueSet) promiseFactory
|
|||||||
// the fields `factory` and `theSet` is non-nil.
|
// the fields `factory` and `theSet` is non-nil.
|
||||||
type queueSetCompleter struct {
|
type queueSetCompleter struct {
|
||||||
factory *queueSetFactory
|
factory *queueSetFactory
|
||||||
reqsObsPair metrics.TimedObserverPair
|
reqsObsPair metrics.RatioedChangeObserverPair
|
||||||
execSeatsObs metrics.TimedObserver
|
execSeatsObs metrics.RatioedChangeObserver
|
||||||
theSet *queueSet
|
theSet *queueSet
|
||||||
qCfg fq.QueuingConfig
|
qCfg fq.QueuingConfig
|
||||||
dealer *shufflesharding.Dealer
|
dealer *shufflesharding.Dealer
|
||||||
@ -81,9 +81,9 @@ type queueSet struct {
|
|||||||
clock eventclock.Interface
|
clock eventclock.Interface
|
||||||
estimatedServiceDuration time.Duration
|
estimatedServiceDuration time.Duration
|
||||||
|
|
||||||
reqsObsPair metrics.TimedObserverPair // .RequestsExecuting covers regular phase only
|
reqsObsPair metrics.RatioedChangeObserverPair // .RequestsExecuting covers regular phase only
|
||||||
|
|
||||||
execSeatsObs metrics.TimedObserver // for all phases of execution
|
execSeatsObs metrics.RatioedChangeObserver // for all phases of execution
|
||||||
|
|
||||||
promiseFactory promiseFactory
|
promiseFactory promiseFactory
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ func newTestableQueueSetFactory(c eventclock.Interface, promiseFactoryFactory pr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qsf *queueSetFactory) BeginConstruction(qCfg fq.QueuingConfig, reqsObsPair metrics.TimedObserverPair, execSeatsObs metrics.TimedObserver) (fq.QueueSetCompleter, error) {
|
func (qsf *queueSetFactory) BeginConstruction(qCfg fq.QueuingConfig, reqsObsPair metrics.RatioedChangeObserverPair, execSeatsObs metrics.RatioedChangeObserver) (fq.QueueSetCompleter, error) {
|
||||||
dealer, err := checkConfig(qCfg)
|
dealer, err := checkConfig(qCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -243,9 +243,9 @@ func (qs *queueSet) setConfiguration(ctx context.Context, qCfg fq.QueuingConfig,
|
|||||||
if qll < 1 {
|
if qll < 1 {
|
||||||
qll = 1
|
qll = 1
|
||||||
}
|
}
|
||||||
qs.reqsObsPair.RequestsWaiting.SetX1(float64(qll))
|
qs.reqsObsPair.RequestsWaiting.SetDenominator(float64(qll))
|
||||||
qs.reqsObsPair.RequestsExecuting.SetX1(float64(dCfg.ConcurrencyLimit))
|
qs.reqsObsPair.RequestsExecuting.SetDenominator(float64(dCfg.ConcurrencyLimit))
|
||||||
qs.execSeatsObs.SetX1(float64(dCfg.ConcurrencyLimit))
|
qs.execSeatsObs.SetDenominator(float64(dCfg.ConcurrencyLimit))
|
||||||
|
|
||||||
qs.dispatchAsMuchAsPossibleLocked()
|
qs.dispatchAsMuchAsPossibleLocked()
|
||||||
}
|
}
|
||||||
|
@ -1461,10 +1461,10 @@ func newFIFO(requests ...*request) fifo {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func newObserverPair(clk clock.PassiveClock) metrics.TimedObserverPair {
|
func newObserverPair(clk clock.PassiveClock) metrics.RatioedChangeObserverPair {
|
||||||
return metrics.PriorityLevelConcurrencyObserverPairGenerator.Generate(1, 1, []string{"test"})
|
return metrics.PriorityLevelConcurrencyObserverPairGenerator.Generate(1, 1, []string{"test"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func newExecSeatsObserver(clk clock.PassiveClock) metrics.TimedObserver {
|
func newExecSeatsObserver(clk clock.PassiveClock) metrics.RatioedChangeObserver {
|
||||||
return metrics.PriorityLevelExecutionSeatsObserverGenerator.Generate(1, 1, []string{"test"})
|
return metrics.PriorityLevelExecutionSeatsObserverGenerator.Generate(1, 1, []string{"test"})
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ type noRestraint struct{}
|
|||||||
|
|
||||||
type noRestraintRequest struct{}
|
type noRestraintRequest struct{}
|
||||||
|
|
||||||
func (noRestraintFactory) BeginConstruction(fq.QueuingConfig, metrics.TimedObserverPair, metrics.TimedObserver) (fq.QueueSetCompleter, error) {
|
func (noRestraintFactory) BeginConstruction(fq.QueuingConfig, metrics.RatioedChangeObserverPair, metrics.RatioedChangeObserver) (fq.QueueSetCompleter, error) {
|
||||||
return noRestraintCompleter{}, nil
|
return noRestraintCompleter{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 The Kubernetes 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
|
||||||
|
|
||||||
|
// Observer is something that can be given numeric observations.
|
||||||
|
type Observer interface {
|
||||||
|
// Observe takes an observation
|
||||||
|
Observe(float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeObserver extends Observer with the ability to take
|
||||||
|
// an observation that is relative to the previous observation.
|
||||||
|
type ChangeObserver interface {
|
||||||
|
Observer
|
||||||
|
|
||||||
|
// Observe a new value that differs by the given amount from the previous observation.
|
||||||
|
Add(float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RatioedChangeObserver tracks ratios.
|
||||||
|
// The numerator is set/changed through the ChangeObserver methods,
|
||||||
|
// and the denominator can be updated through the SetDenominator method.
|
||||||
|
// A ratio is tracked whenever the numerator is set/changed.
|
||||||
|
type RatioedChangeObserver interface {
|
||||||
|
ChangeObserver
|
||||||
|
|
||||||
|
// SetDenominator sets the denominator to use until it is changed again
|
||||||
|
SetDenominator(float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RatioedChangeObserverGenerator creates related observers that are
|
||||||
|
// differentiated by a series of label values
|
||||||
|
type RatioedChangeObserverGenerator interface {
|
||||||
|
Generate(initialNumerator, initialDenominator float64, labelValues []string) RatioedChangeObserver
|
||||||
|
}
|
||||||
|
|
||||||
|
// RatioedChangeObserverPair is a corresponding pair of observers, one for the
|
||||||
|
// number of requests waiting in queue(s) and one for the number of
|
||||||
|
// requests being executed
|
||||||
|
type RatioedChangeObserverPair struct {
|
||||||
|
// RequestsWaiting is given observations of the number of currently queued requests
|
||||||
|
RequestsWaiting RatioedChangeObserver
|
||||||
|
|
||||||
|
// RequestsExecuting is given observations of the number of requests currently executing
|
||||||
|
RequestsExecuting RatioedChangeObserver
|
||||||
|
}
|
||||||
|
|
||||||
|
// RatioedChangeObserverPairGenerator generates pairs
|
||||||
|
type RatioedChangeObserverPairGenerator interface {
|
||||||
|
Generate(initialWaitingDenominator, initialExecutingDenominator float64, labelValues []string) RatioedChangeObserverPair
|
||||||
|
}
|
@ -34,13 +34,13 @@ const (
|
|||||||
labelValueExecuting = "executing"
|
labelValueExecuting = "executing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SampleAndWaterMarkPairGenerator makes pairs of TimedObservers that
|
// SampleAndWaterMarkPairGenerator makes pairs of RatioedChangeObservers that
|
||||||
// track samples and watermarks.
|
// track samples and watermarks.
|
||||||
type SampleAndWaterMarkPairGenerator struct {
|
type SampleAndWaterMarkPairGenerator struct {
|
||||||
urGenerator SampleAndWaterMarkObserverGenerator
|
urGenerator SampleAndWaterMarkObserverGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ TimedObserverPairGenerator = SampleAndWaterMarkPairGenerator{}
|
var _ RatioedChangeObserverPairGenerator = SampleAndWaterMarkPairGenerator{}
|
||||||
|
|
||||||
// NewSampleAndWaterMarkHistogramsPairGenerator makes a new pair generator
|
// NewSampleAndWaterMarkHistogramsPairGenerator makes a new pair generator
|
||||||
func NewSampleAndWaterMarkHistogramsPairGenerator(clock clock.PassiveClock, samplePeriod time.Duration, sampleOpts, waterMarkOpts *compbasemetrics.HistogramOpts, labelNames []string) SampleAndWaterMarkPairGenerator {
|
func NewSampleAndWaterMarkHistogramsPairGenerator(clock clock.PassiveClock, samplePeriod time.Duration, sampleOpts, waterMarkOpts *compbasemetrics.HistogramOpts, labelNames []string) SampleAndWaterMarkPairGenerator {
|
||||||
@ -50,10 +50,10 @@ func NewSampleAndWaterMarkHistogramsPairGenerator(clock clock.PassiveClock, samp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate makes a new pair
|
// Generate makes a new pair
|
||||||
func (spg SampleAndWaterMarkPairGenerator) Generate(waiting1, executing1 float64, labelValues []string) TimedObserverPair {
|
func (spg SampleAndWaterMarkPairGenerator) Generate(initialWaitingDenominator, initialExecutingDenominator float64, labelValues []string) RatioedChangeObserverPair {
|
||||||
return TimedObserverPair{
|
return RatioedChangeObserverPair{
|
||||||
RequestsWaiting: spg.urGenerator.Generate(0, waiting1, append([]string{labelValueWaiting}, labelValues...)),
|
RequestsWaiting: spg.urGenerator.Generate(0, initialWaitingDenominator, append([]string{labelValueWaiting}, labelValues...)),
|
||||||
RequestsExecuting: spg.urGenerator.Generate(0, executing1, append([]string{labelValueExecuting}, labelValues...)),
|
RequestsExecuting: spg.urGenerator.Generate(0, initialExecutingDenominator, append([]string{labelValueExecuting}, labelValues...)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ func (spg SampleAndWaterMarkPairGenerator) metrics() Registerables {
|
|||||||
return spg.urGenerator.metrics()
|
return spg.urGenerator.metrics()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SampleAndWaterMarkObserverGenerator creates TimedObservers that
|
// SampleAndWaterMarkObserverGenerator creates RatioedChangeObservers that
|
||||||
// populate histograms of samples and low- and high-water-marks. The
|
// populate histograms of samples and low- and high-water-marks. The
|
||||||
// generator has a samplePeriod, and the histograms get an observation
|
// generator has a samplePeriod, and the histograms get an observation
|
||||||
// every samplePeriod. The sampling windows are quantized based on
|
// every samplePeriod. The sampling windows are quantized based on
|
||||||
@ -79,7 +79,7 @@ type sampleAndWaterMarkObserverGenerator struct {
|
|||||||
waterMarks *compbasemetrics.HistogramVec
|
waterMarks *compbasemetrics.HistogramVec
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ TimedObserverGenerator = SampleAndWaterMarkObserverGenerator{}
|
var _ RatioedChangeObserverGenerator = SampleAndWaterMarkObserverGenerator{}
|
||||||
|
|
||||||
// NewSampleAndWaterMarkHistogramsGenerator makes a new one
|
// NewSampleAndWaterMarkHistogramsGenerator makes a new one
|
||||||
func NewSampleAndWaterMarkHistogramsGenerator(clock clock.PassiveClock, samplePeriod time.Duration, sampleOpts, waterMarkOpts *compbasemetrics.HistogramOpts, labelNames []string) SampleAndWaterMarkObserverGenerator {
|
func NewSampleAndWaterMarkHistogramsGenerator(clock clock.PassiveClock, samplePeriod time.Duration, sampleOpts, waterMarkOpts *compbasemetrics.HistogramOpts, labelNames []string) SampleAndWaterMarkObserverGenerator {
|
||||||
@ -97,23 +97,23 @@ func (swg *sampleAndWaterMarkObserverGenerator) quantize(when time.Time) int64 {
|
|||||||
return int64(when.Sub(swg.t0) / swg.samplePeriod)
|
return int64(when.Sub(swg.t0) / swg.samplePeriod)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate makes a new TimedObserver
|
// Generate makes a new RatioedChangeObserver
|
||||||
func (swg *sampleAndWaterMarkObserverGenerator) Generate(x, x1 float64, labelValues []string) TimedObserver {
|
func (swg *sampleAndWaterMarkObserverGenerator) Generate(initialNumerator, initialDenominator float64, labelValues []string) RatioedChangeObserver {
|
||||||
relX := x / x1
|
ratio := initialNumerator / initialDenominator
|
||||||
when := swg.clock.Now()
|
when := swg.clock.Now()
|
||||||
return &sampleAndWaterMarkHistograms{
|
return &sampleAndWaterMarkHistograms{
|
||||||
sampleAndWaterMarkObserverGenerator: swg,
|
sampleAndWaterMarkObserverGenerator: swg,
|
||||||
labelValues: labelValues,
|
labelValues: labelValues,
|
||||||
loLabelValues: append([]string{labelValueLo}, labelValues...),
|
loLabelValues: append([]string{labelValueLo}, labelValues...),
|
||||||
hiLabelValues: append([]string{labelValueHi}, labelValues...),
|
hiLabelValues: append([]string{labelValueHi}, labelValues...),
|
||||||
x1: x1,
|
denominator: initialDenominator,
|
||||||
sampleAndWaterMarkAccumulator: sampleAndWaterMarkAccumulator{
|
sampleAndWaterMarkAccumulator: sampleAndWaterMarkAccumulator{
|
||||||
lastSet: when,
|
lastSet: when,
|
||||||
lastSetInt: swg.quantize(when),
|
lastSetInt: swg.quantize(when),
|
||||||
x: x,
|
numerator: initialNumerator,
|
||||||
relX: relX,
|
ratio: ratio,
|
||||||
loRelX: relX,
|
loRatio: ratio,
|
||||||
hiRelX: relX,
|
hiRatio: ratio,
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,39 +127,39 @@ type sampleAndWaterMarkHistograms struct {
|
|||||||
loLabelValues, hiLabelValues []string
|
loLabelValues, hiLabelValues []string
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
x1 float64
|
denominator float64
|
||||||
sampleAndWaterMarkAccumulator
|
sampleAndWaterMarkAccumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
type sampleAndWaterMarkAccumulator struct {
|
type sampleAndWaterMarkAccumulator struct {
|
||||||
lastSet time.Time
|
lastSet time.Time
|
||||||
lastSetInt int64 // lastSet / samplePeriod
|
lastSetInt int64 // lastSet / samplePeriod
|
||||||
x float64
|
numerator float64
|
||||||
relX float64 // x / x1
|
ratio float64 // numerator/denominator
|
||||||
loRelX, hiRelX float64
|
loRatio, hiRatio float64
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ TimedObserver = (*sampleAndWaterMarkHistograms)(nil)
|
var _ RatioedChangeObserver = (*sampleAndWaterMarkHistograms)(nil)
|
||||||
|
|
||||||
func (saw *sampleAndWaterMarkHistograms) Add(deltaX float64) {
|
func (saw *sampleAndWaterMarkHistograms) Add(deltaNumerator float64) {
|
||||||
saw.innerSet(func() {
|
saw.innerSet(func() {
|
||||||
saw.x += deltaX
|
saw.numerator += deltaNumerator
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (saw *sampleAndWaterMarkHistograms) Set(x float64) {
|
func (saw *sampleAndWaterMarkHistograms) Observe(numerator float64) {
|
||||||
saw.innerSet(func() {
|
saw.innerSet(func() {
|
||||||
saw.x = x
|
saw.numerator = numerator
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (saw *sampleAndWaterMarkHistograms) SetX1(x1 float64) {
|
func (saw *sampleAndWaterMarkHistograms) SetDenominator(denominator float64) {
|
||||||
saw.innerSet(func() {
|
saw.innerSet(func() {
|
||||||
saw.x1 = x1
|
saw.denominator = denominator
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (saw *sampleAndWaterMarkHistograms) innerSet(updateXOrX1 func()) {
|
func (saw *sampleAndWaterMarkHistograms) innerSet(updateNumeratorOrDenominator func()) {
|
||||||
when, whenInt, acc, wellOrdered := func() (time.Time, int64, sampleAndWaterMarkAccumulator, bool) {
|
when, whenInt, acc, wellOrdered := func() (time.Time, int64, sampleAndWaterMarkAccumulator, bool) {
|
||||||
saw.Lock()
|
saw.Lock()
|
||||||
defer saw.Unlock()
|
defer saw.Unlock()
|
||||||
@ -168,11 +168,11 @@ func (saw *sampleAndWaterMarkHistograms) innerSet(updateXOrX1 func()) {
|
|||||||
whenInt := saw.quantize(when)
|
whenInt := saw.quantize(when)
|
||||||
acc := saw.sampleAndWaterMarkAccumulator
|
acc := saw.sampleAndWaterMarkAccumulator
|
||||||
wellOrdered := !when.Before(acc.lastSet)
|
wellOrdered := !when.Before(acc.lastSet)
|
||||||
updateXOrX1()
|
updateNumeratorOrDenominator()
|
||||||
saw.relX = saw.x / saw.x1
|
saw.ratio = saw.numerator / saw.denominator
|
||||||
if wellOrdered {
|
if wellOrdered {
|
||||||
if acc.lastSetInt < whenInt {
|
if acc.lastSetInt < whenInt {
|
||||||
saw.loRelX, saw.hiRelX = acc.relX, acc.relX
|
saw.loRatio, saw.hiRatio = acc.ratio, acc.ratio
|
||||||
saw.lastSetInt = whenInt
|
saw.lastSetInt = whenInt
|
||||||
}
|
}
|
||||||
saw.lastSet = when
|
saw.lastSet = when
|
||||||
@ -187,10 +187,10 @@ func (saw *sampleAndWaterMarkHistograms) innerSet(updateXOrX1 func()) {
|
|||||||
// would be wrong to update `saw.lastSet` in this case because
|
// would be wrong to update `saw.lastSet` in this case because
|
||||||
// that plants a time bomb for future updates to
|
// that plants a time bomb for future updates to
|
||||||
// `saw.lastSetInt`.
|
// `saw.lastSetInt`.
|
||||||
if saw.relX < saw.loRelX {
|
if saw.ratio < saw.loRatio {
|
||||||
saw.loRelX = saw.relX
|
saw.loRatio = saw.ratio
|
||||||
} else if saw.relX > saw.hiRelX {
|
} else if saw.ratio > saw.hiRatio {
|
||||||
saw.hiRelX = saw.relX
|
saw.hiRatio = saw.ratio
|
||||||
}
|
}
|
||||||
return when, whenInt, acc, wellOrdered
|
return when, whenInt, acc, wellOrdered
|
||||||
}()
|
}()
|
||||||
@ -200,10 +200,10 @@ func (saw *sampleAndWaterMarkHistograms) innerSet(updateXOrX1 func()) {
|
|||||||
klog.Errorf("Time went backwards from %s to %s for labelValues=%#+v", lastSetS, whenS, saw.labelValues)
|
klog.Errorf("Time went backwards from %s to %s for labelValues=%#+v", lastSetS, whenS, saw.labelValues)
|
||||||
}
|
}
|
||||||
for acc.lastSetInt < whenInt {
|
for acc.lastSetInt < whenInt {
|
||||||
saw.samples.WithLabelValues(saw.labelValues...).Observe(acc.relX)
|
saw.samples.WithLabelValues(saw.labelValues...).Observe(acc.ratio)
|
||||||
saw.waterMarks.WithLabelValues(saw.loLabelValues...).Observe(acc.loRelX)
|
saw.waterMarks.WithLabelValues(saw.loLabelValues...).Observe(acc.loRatio)
|
||||||
saw.waterMarks.WithLabelValues(saw.hiLabelValues...).Observe(acc.hiRelX)
|
saw.waterMarks.WithLabelValues(saw.hiLabelValues...).Observe(acc.hiRatio)
|
||||||
acc.lastSetInt++
|
acc.lastSetInt++
|
||||||
acc.loRelX, acc.hiRelX = acc.relX, acc.relX
|
acc.loRatio, acc.hiRatio = acc.ratio, acc.ratio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ func TestSampler(t *testing.T) {
|
|||||||
dt = diff
|
dt = diff
|
||||||
}
|
}
|
||||||
clk.SetTime(t1)
|
clk.SetTime(t1)
|
||||||
saw.Set(1)
|
saw.Observe(1)
|
||||||
expectedCount := int64(dt / samplingPeriod)
|
expectedCount := int64(dt / samplingPeriod)
|
||||||
actualCount, err := getHistogramCount(regs, samplesHistName)
|
actualCount, err := getHistogramCount(regs, samplesHistName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 The Kubernetes 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
|
|
||||||
|
|
||||||
// TimedObserver gets informed about the values assigned to a variable
|
|
||||||
// `X float64` over time, and reports on the ratio `X/X1`.
|
|
||||||
type TimedObserver interface {
|
|
||||||
// Add notes a change to the variable
|
|
||||||
Add(deltaX float64)
|
|
||||||
|
|
||||||
// Set notes a setting of the variable
|
|
||||||
Set(x float64)
|
|
||||||
|
|
||||||
// SetX1 changes the value to use for X1
|
|
||||||
SetX1(x1 float64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimedObserverGenerator creates related observers that are
|
|
||||||
// differentiated by a series of label values
|
|
||||||
type TimedObserverGenerator interface {
|
|
||||||
Generate(x, x1 float64, labelValues []string) TimedObserver
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimedObserverPair is a corresponding pair of observers, one for the
|
|
||||||
// number of requests waiting in queue(s) and one for the number of
|
|
||||||
// requests being executed
|
|
||||||
type TimedObserverPair struct {
|
|
||||||
// RequestsWaiting is given observations of the number of currently queued requests
|
|
||||||
RequestsWaiting TimedObserver
|
|
||||||
|
|
||||||
// RequestsExecuting is given observations of the number of requests currently executing
|
|
||||||
RequestsExecuting TimedObserver
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimedObserverPairGenerator generates pairs
|
|
||||||
type TimedObserverPairGenerator interface {
|
|
||||||
Generate(waiting1, executing1 float64, labelValues []string) TimedObserverPair
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user