From 036ce62a965fbd2c662b9fc8b5dbe329e73d1dc1 Mon Sep 17 00:00:00 2001 From: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> Date: Tue, 18 Feb 2025 09:05:26 +0200 Subject: [PATCH] Throttler: reduce regexp/string allocations by pre-computing pascal case Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com> --- .../tabletserver/throttle/base/metric_name.go | 11 +++++++++++ .../tabletserver/throttle/base/metric_name_test.go | 1 + .../tabletserver/throttle/base/metric_scope.go | 12 ++++++++++++ .../tabletserver/throttle/base/self_metric.go | 2 ++ go/vt/vttablet/tabletserver/throttle/check.go | 9 ++++----- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/go/vt/vttablet/tabletserver/throttle/base/metric_name.go b/go/vt/vttablet/tabletserver/throttle/base/metric_name.go index 43bd2d17a8c..978e4be2abd 100644 --- a/go/vt/vttablet/tabletserver/throttle/base/metric_name.go +++ b/go/vt/vttablet/tabletserver/throttle/base/metric_name.go @@ -20,6 +20,8 @@ import ( "fmt" "slices" "strings" + + "vitess.io/vitess/go/textutil" ) // MetricName is a formalized name for a metric, such as "lag" or "threads_running". A metric name @@ -77,6 +79,14 @@ func (metric MetricName) DefaultScope() Scope { return SelfScope } +// Pascal case representation of this name, e.g. "ThreadsRunning" +func (metric MetricName) Pascal() string { + if pascal, ok := pascalMetricNames[metric]; ok { + return pascal + } + return textutil.PascalCase(metric.String()) +} + func (metric MetricName) String() string { return string(metric) } @@ -113,6 +123,7 @@ var ( // - no textual parsing is needed in the critical path // - we can easily check if a metric name is valid aggregatedMetricNames = make(map[string]AggregatedMetricName) + pascalMetricNames = make(map[MetricName]string) ) // DisaggregateMetricName splits a metric name into its scope name and metric name diff --git a/go/vt/vttablet/tabletserver/throttle/base/metric_name_test.go b/go/vt/vttablet/tabletserver/throttle/base/metric_name_test.go index c2e2b44b36f..179bff918fc 100644 --- a/go/vt/vttablet/tabletserver/throttle/base/metric_name_test.go +++ b/go/vt/vttablet/tabletserver/throttle/base/metric_name_test.go @@ -261,6 +261,7 @@ func TestKnownMetricNamesPascalCase(t *testing.T) { t.Run(metricName.String(), func(t *testing.T) { expect, ok := expectCases[metricName] require.True(t, ok) + assert.Equal(t, expect, metricName.Pascal()) assert.Equal(t, expect, textutil.PascalCase(metricName.String())) }) } diff --git a/go/vt/vttablet/tabletserver/throttle/base/metric_scope.go b/go/vt/vttablet/tabletserver/throttle/base/metric_scope.go index 60d116861c3..5cd745cfcc6 100644 --- a/go/vt/vttablet/tabletserver/throttle/base/metric_scope.go +++ b/go/vt/vttablet/tabletserver/throttle/base/metric_scope.go @@ -30,6 +30,18 @@ const ( SelfScope Scope = "self" ) +var ( + pascalScopeNames = map[Scope]string{ + UndefinedScope: "", + ShardScope: "Shard", + SelfScope: "Self", + } +) + +func (s Scope) Pascal() string { + return pascalScopeNames[s] +} + func (s Scope) String() string { return string(s) } diff --git a/go/vt/vttablet/tabletserver/throttle/base/self_metric.go b/go/vt/vttablet/tabletserver/throttle/base/self_metric.go index 88fbe2bdd13..306eae734bc 100644 --- a/go/vt/vttablet/tabletserver/throttle/base/self_metric.go +++ b/go/vt/vttablet/tabletserver/throttle/base/self_metric.go @@ -21,6 +21,7 @@ import ( "fmt" "strconv" + "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" "vitess.io/vitess/go/vt/vttablet/tmclient" @@ -48,6 +49,7 @@ var ( func registerSelfMetric(selfMetric SelfMetric) SelfMetric { RegisteredSelfMetrics[selfMetric.Name()] = selfMetric KnownMetricNames = append(KnownMetricNames, selfMetric.Name()) + pascalMetricNames[selfMetric.Name()] = textutil.PascalCase(selfMetric.Name().String()) aggregatedMetricNames[selfMetric.Name().String()] = AggregatedMetricName{ Scope: selfMetric.DefaultScope(), Metric: selfMetric.Name(), diff --git a/go/vt/vttablet/tabletserver/throttle/check.go b/go/vt/vttablet/tabletserver/throttle/check.go index 888daeb5801..f8c08a7738f 100644 --- a/go/vt/vttablet/tabletserver/throttle/check.go +++ b/go/vt/vttablet/tabletserver/throttle/check.go @@ -47,7 +47,6 @@ import ( "time" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/base" "vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/throttlerapp" @@ -175,9 +174,9 @@ func (check *ThrottlerCheck) Check(ctx context.Context, appName string, scope ba // Out of abundance of caution, we will protect against such a scenario. return } - stats.GetOrNewCounter(fmt.Sprintf("ThrottlerCheck%s%sTotal", textutil.PascalCase(metricScope.String()), textutil.PascalCase(metricName.String())), "").Add(1) + stats.GetOrNewCounter(fmt.Sprintf("ThrottlerCheck%s%sTotal", metricScope.Pascal(), metricName.Pascal()), "").Add(1) if !metricCheckResult.IsOK() { - stats.GetOrNewCounter(fmt.Sprintf("ThrottlerCheck%s%sError", textutil.PascalCase(metricScope.String()), textutil.PascalCase(metricName.String())), "").Add(1) + stats.GetOrNewCounter(fmt.Sprintf("ThrottlerCheck%s%sError", metricScope.Pascal(), metricName.Pascal()), "").Add(1) } }(metricCheckResult) } @@ -232,7 +231,7 @@ func (check *ThrottlerCheck) localCheck(ctx context.Context, aggregatedMetricNam check.throttler.markMetricHealthy(aggregatedMetricName) } if timeSinceHealthy, found := check.throttler.timeSinceMetricHealthy(aggregatedMetricName); found { - go stats.GetOrNewGauge(fmt.Sprintf("ThrottlerCheck%sSecondsSinceHealthy", textutil.PascalCase(scope.String())), fmt.Sprintf("seconds since last healthy check for %v", scope)).Set(int64(timeSinceHealthy.Seconds())) + go stats.GetOrNewGauge(fmt.Sprintf("ThrottlerCheck%sSecondsSinceHealthy", scope.Pascal()), fmt.Sprintf("seconds since last healthy check for %v", scope)).Set(int64(timeSinceHealthy.Seconds())) } return checkResult @@ -244,7 +243,7 @@ func (check *ThrottlerCheck) reportAggregated(aggregatedMetricName string, metri return } if value, err := metricResult.Get(); err == nil { - stats.GetOrNewGaugeFloat64(fmt.Sprintf("ThrottlerAggregated%s%s", textutil.PascalCase(scope.String()), textutil.PascalCase(metricName.String())), fmt.Sprintf("aggregated value for %v", scope)).Set(value) + stats.GetOrNewGaugeFloat64(fmt.Sprintf("ThrottlerAggregated%s%s", scope.Pascal(), metricName.Pascal()), fmt.Sprintf("aggregated value for %v", scope)).Set(value) } }