From 45d85bb46ca9aeecd62ee35dbfa540012450a56d Mon Sep 17 00:00:00 2001 From: yingjinhui Date: Tue, 29 Nov 2022 19:28:15 +0800 Subject: [PATCH] add metrics for pool Signed-off-by: yingjinhui --- cmd/agent/app/agent.go | 1 + .../app/controllermanager.go | 1 + pkg/metrics/pool.go | 48 +++++++++ pkg/metrics/pool_test.go | 100 ++++++++++++++++++ .../configurableinterpreter/luavm/lua.go | 1 + pkg/util/fixedpool/fixedpool.go | 10 +- 6 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 pkg/metrics/pool.go create mode 100644 pkg/metrics/pool_test.go diff --git a/cmd/agent/app/agent.go b/cmd/agent/app/agent.go index 7dc50b2b9..b5eb69b2c 100644 --- a/cmd/agent/app/agent.go +++ b/cmd/agent/app/agent.go @@ -214,6 +214,7 @@ func run(ctx context.Context, opts *options.Options) error { crtlmetrics.Registry.MustRegister(metrics.ClusterCollectors()...) crtlmetrics.Registry.MustRegister(metrics.ResourceCollectorsForAgent()...) + crtlmetrics.Registry.MustRegister(metrics.PoolCollectors()...) if err = setupControllers(controllerManager, opts, ctx.Done()); err != nil { return err diff --git a/cmd/controller-manager/app/controllermanager.go b/cmd/controller-manager/app/controllermanager.go index 03e929c82..0bdfeee64 100644 --- a/cmd/controller-manager/app/controllermanager.go +++ b/cmd/controller-manager/app/controllermanager.go @@ -158,6 +158,7 @@ func Run(ctx context.Context, opts *options.Options) error { crtlmetrics.Registry.MustRegister(metrics.ClusterCollectors()...) crtlmetrics.Registry.MustRegister(metrics.ResourceCollectors()...) + crtlmetrics.Registry.MustRegister(metrics.PoolCollectors()...) setupControllers(controllerManager, opts, ctx.Done()) diff --git a/pkg/metrics/pool.go b/pkg/metrics/pool.go new file mode 100644 index 000000000..f6d8b6495 --- /dev/null +++ b/pkg/metrics/pool.go @@ -0,0 +1,48 @@ +package metrics + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +const ( + poolGetCounterMetricsName = "pool_get_operation_total" + poolPutCounterMetricsName = "pool_put_operation_total" +) + +var ( + poolGetCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: poolGetCounterMetricsName, + Help: "Total times of getting from pool", + }, []string{"name", "from"}) + + poolPutCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: poolPutCounterMetricsName, + Help: "Total times of putting from pool", + }, []string{"name", "to"}) +) + +// RecordPoolGet records the times of getting from pool +func RecordPoolGet(name string, created bool) { + from := "pool" + if created { + from = "new" + } + poolGetCounter.WithLabelValues(name, from).Inc() +} + +// RecordPoolPut records the times of putting from pool +func RecordPoolPut(name string, destroyed bool) { + to := "pool" + if destroyed { + to = "destroyed" + } + poolPutCounter.WithLabelValues(name, to).Inc() +} + +// PoolCollectors returns the collectors about pool. +func PoolCollectors() []prometheus.Collector { + return []prometheus.Collector{ + poolGetCounter, + poolPutCounter, + } +} diff --git a/pkg/metrics/pool_test.go b/pkg/metrics/pool_test.go new file mode 100644 index 000000000..4ad6552e6 --- /dev/null +++ b/pkg/metrics/pool_test.go @@ -0,0 +1,100 @@ +package metrics + +import ( + "strings" + "testing" + + "github.com/prometheus/client_golang/prometheus/testutil" +) + +func TestRecordPoolGet(t *testing.T) { + type args struct { + name string + created bool + } + tests := []struct { + name string + args args + want string + }{ + { + name: "get from pool", + args: args{ + name: "foo", + created: false, + }, + want: ` +# HELP pool_get_operation_total Total times of getting from pool +# TYPE pool_get_operation_total counter +pool_get_operation_total{from="pool",name="foo"} 1 +`, + }, + { + name: "get from new", + args: args{ + name: "foo", + created: true, + }, + want: ` +# HELP pool_get_operation_total Total times of getting from pool +# TYPE pool_get_operation_total counter +pool_get_operation_total{from="new",name="foo"} 1 +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + poolGetCounter.Reset() + RecordPoolGet(tt.args.name, tt.args.created) + if err := testutil.CollectAndCompare(poolGetCounter, strings.NewReader(tt.want), poolGetCounterMetricsName); err != nil { + t.Errorf("unexpected collecting result:\n%s", err) + } + }) + } +} + +func TestRecordPoolPut(t *testing.T) { + type args struct { + name string + destroyed bool + } + tests := []struct { + name string + args args + want string + }{ + { + name: "put to pool", + args: args{ + name: "foo", + destroyed: false, + }, + want: ` +# HELP pool_put_operation_total Total times of putting from pool +# TYPE pool_put_operation_total counter +pool_put_operation_total{name="foo",to="pool"} 1 +`, + }, + { + name: "put to destroyed", + args: args{ + name: "foo", + destroyed: true, + }, + want: ` +# HELP pool_put_operation_total Total times of putting from pool +# TYPE pool_put_operation_total counter +pool_put_operation_total{name="foo",to="destroyed"} 1 +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + poolPutCounter.Reset() + RecordPoolPut(tt.args.name, tt.args.destroyed) + if err := testutil.CollectAndCompare(poolPutCounter, strings.NewReader(tt.want), poolPutCounterMetricsName); err != nil { + t.Errorf("unexpected collecting result:\n%s", err) + } + }) + } +} diff --git a/pkg/resourceinterpreter/configurableinterpreter/luavm/lua.go b/pkg/resourceinterpreter/configurableinterpreter/luavm/lua.go index 5b90db2a0..a0d70428d 100644 --- a/pkg/resourceinterpreter/configurableinterpreter/luavm/lua.go +++ b/pkg/resourceinterpreter/configurableinterpreter/luavm/lua.go @@ -32,6 +32,7 @@ func New(useOpenLibs bool, poolSize int) *VM { UseOpenLibs: useOpenLibs, } vm.Pool = fixedpool.New( + "luavm", func() (any, error) { return vm.NewLuaState() }, func(a any) { a.(*lua.LState).Close() }, poolSize) diff --git a/pkg/util/fixedpool/fixedpool.go b/pkg/util/fixedpool/fixedpool.go index cf2d96635..b7ef23ef6 100644 --- a/pkg/util/fixedpool/fixedpool.go +++ b/pkg/util/fixedpool/fixedpool.go @@ -2,11 +2,14 @@ package fixedpool import ( "sync" + + "github.com/karmada-io/karmada/pkg/metrics" ) // A FixedPool like sync.Pool. But it's limited capacity. // When pool is full, Put will abandon and call destroyFunc to destroy the object. type FixedPool struct { + name string lock sync.Mutex pool []any capacity int @@ -16,8 +19,9 @@ type FixedPool struct { } // New return a FixedPool -func New(newFunc func() (any, error), destroyFunc func(any), capacity int) *FixedPool { +func New(name string, newFunc func() (any, error), destroyFunc func(any), capacity int) *FixedPool { return &FixedPool{ + name: name, pool: make([]any, 0, capacity), capacity: capacity, newFunc: newFunc, @@ -35,9 +39,11 @@ func New(newFunc func() (any, error), destroyFunc func(any), capacity int) *Fixe func (p *FixedPool) Get() (any, error) { o, ok := p.pop() if ok { + metrics.RecordPoolGet(p.name, false) return o, nil } + metrics.RecordPoolGet(p.name, true) return p.newFunc() } @@ -45,8 +51,10 @@ func (p *FixedPool) Get() (any, error) { // and it's destroy function will be called. func (p *FixedPool) Put(x any) { if p.push(x) { + metrics.RecordPoolPut(p.name, false) return } + metrics.RecordPoolPut(p.name, true) p.destroyFunc(x) }