You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by xu...@apache.org on 2026/06/12 03:28:50 UTC

(dubbo-go) branch develop updated: Feat: add benchmarks for common.URL (#3399)

This is an automated email from the ASF dual-hosted git repository.

Alanxtl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/develop by this push:
     new 1ce8314a0 Feat: add benchmarks for common.URL (#3399)
1ce8314a0 is described below

commit 1ce8314a06eb9a51c3d9befc5878e23dd15b62e7
Author: wm_03 <31...@qq.com>
AuthorDate: Fri Jun 12 11:28:45 2026 +0800

    Feat: add benchmarks for common.URL (#3399)
    
    * test: add benchmarks for common.URL.
    
    * test: keep full identity params across URL benchmark tiers
    
    * test: add URL filter benchmarks with nested sub-URLs
---
 common/url_benchmark_test.go | 320 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 320 insertions(+)

diff --git a/common/url_benchmark_test.go b/common/url_benchmark_test.go
new file mode 100644
index 000000000..1e904957a
--- /dev/null
+++ b/common/url_benchmark_test.go
@@ -0,0 +1,320 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 common
+
+import (
+	"fmt"
+	"net/url"
+	"testing"
+)
+
+import (
+	gxset "github.com/dubbogo/gost/container/set"
+)
+
+import (
+	"dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+const (
+	benchmarkURLProtocol  = "dubbo"
+	benchmarkURLIP        = "127.0.0.1"
+	benchmarkURLPort      = "20000"
+	benchmarkURLInterface = "com.test.BenchmarkService"
+	benchmarkURLGroup     = "benchmark"
+	benchmarkURLVersion   = "1.0.0"
+	benchmarkURLTimestamp = "1234567890"
+	benchmarkURLMeshID    = "benchmark-mesh"
+)
+
+var (
+	benchmarkURLParamSizes = []int{1, 32, 256, 1024}
+
+	benchmarkURLStringSink string
+	benchmarkURLSink       *URL
+	benchmarkURLParamsSink url.Values
+	benchmarkURLMapSink    map[string]string
+	benchmarkURLBoolSink   bool
+)
+
+func BenchmarkURLString(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLStringSink = u.String()
+	})
+}
+
+func BenchmarkURLKey(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLStringSink = u.Key()
+	})
+}
+
+func BenchmarkURLGetCacheInvokerMapKey(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLStringSink = u.GetCacheInvokerMapKey()
+	})
+}
+
+func BenchmarkURLServiceKey(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLStringSink = u.ServiceKey()
+	})
+}
+
+func BenchmarkURLCopyParams(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLParamsSink = u.CopyParams()
+	})
+}
+
+func BenchmarkURLGetParams(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLParamsSink = u.GetParams()
+	})
+}
+
+func BenchmarkURLClone(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLSink = u.Clone()
+	})
+
+	for _, paramCount := range benchmarkURLParamSizes {
+		paramCount := paramCount
+		b.Run(fmt.Sprintf("params_%d_with_suburl", paramCount), func(b *testing.B) {
+			u := makeBenchmarkURLWithSubURL(paramCount)
+			b.ReportAllocs()
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				benchmarkURLSink = u.Clone()
+			}
+		})
+	}
+}
+
+func BenchmarkURLCloneWithFilter(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLSink = u.CloneWithFilter(nil, nil)
+	})
+
+	for _, paramCount := range benchmarkURLParamSizes {
+		paramCount := paramCount
+		b.Run(fmt.Sprintf("params_%d_exclude_20_percent", paramCount), func(b *testing.B) {
+			u := makeBenchmarkURL(paramCount)
+			excludeParams := makeBenchmarkExcludeSet(paramCount)
+			b.ReportAllocs()
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				benchmarkURLSink = u.CloneWithFilter(excludeParams, nil)
+			}
+		})
+	}
+
+	for _, paramCount := range benchmarkURLParamSizes {
+		paramCount := paramCount
+		b.Run(fmt.Sprintf("params_%d_exclude_20_percent_with_suburl", paramCount), func(b *testing.B) {
+			u := makeBenchmarkURLWithSubURL(paramCount)
+			excludeParams := makeBenchmarkExcludeSet(paramCount)
+			b.ReportAllocs()
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				benchmarkURLSink = u.CloneWithFilter(excludeParams, nil)
+			}
+		})
+	}
+
+	for _, paramCount := range benchmarkURLParamSizes {
+		paramCount := paramCount
+		b.Run(fmt.Sprintf("params_%d_reserve_20_percent", paramCount), func(b *testing.B) {
+			u := makeBenchmarkURL(paramCount)
+			reserveParams := makeBenchmarkReserveKeys(paramCount)
+			b.ReportAllocs()
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				benchmarkURLSink = u.CloneWithFilter(nil, reserveParams)
+			}
+		})
+	}
+
+	for _, paramCount := range benchmarkURLParamSizes {
+		paramCount := paramCount
+		b.Run(fmt.Sprintf("params_%d_reserve_20_percent_with_suburl", paramCount), func(b *testing.B) {
+			u := makeBenchmarkURLWithSubURL(paramCount)
+			reserveParams := makeBenchmarkReserveKeys(paramCount)
+			b.ReportAllocs()
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				benchmarkURLSink = u.CloneWithFilter(nil, reserveParams)
+			}
+		})
+	}
+}
+
+func BenchmarkURLMergeURL(b *testing.B) {
+	for _, paramCount := range benchmarkURLParamSizes {
+		paramCount := paramCount
+		b.Run(fmt.Sprintf("params_%d_with_method_params", paramCount), func(b *testing.B) {
+			left, right := makeBenchmarkMergeHalfOverlapPair(paramCount)
+			addBenchmarkMethodParams(right)
+			b.ReportAllocs()
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				benchmarkURLSink = left.MergeURL(right)
+			}
+		})
+	}
+}
+
+func BenchmarkURLToMap(b *testing.B) {
+	runBenchmarkURLByParamSize(b, func(u *URL) {
+		benchmarkURLMapSink = u.ToMap()
+	})
+}
+
+func BenchmarkURLIsEquals(b *testing.B) {
+	for _, paramCount := range benchmarkURLParamSizes {
+		paramCount := paramCount
+		b.Run(fmt.Sprintf("params_%d", paramCount), func(b *testing.B) {
+			left := makeBenchmarkURL(paramCount)
+			right := makeBenchmarkURL(paramCount)
+			b.ReportAllocs()
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				benchmarkURLBoolSink = IsEquals(left, right)
+			}
+		})
+	}
+}
+
+func runBenchmarkURLByParamSize(b *testing.B, run func(*URL)) {
+	b.Helper()
+	for _, paramCount := range benchmarkURLParamSizes {
+		paramCount := paramCount
+		b.Run(fmt.Sprintf("params_%d", paramCount), func(b *testing.B) {
+			u := makeBenchmarkURL(paramCount)
+			b.ReportAllocs()
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				run(u)
+			}
+		})
+	}
+}
+
+func makeBenchmarkURL(paramCount int) *URL {
+	return makeBenchmarkURLWithParamStart(paramCount, 0)
+}
+
+func makeBenchmarkURLWithSubURL(paramCount int) *URL {
+	u := makeBenchmarkURL(paramCount)
+	u.SubURL = makeBenchmarkURL(paramCount)
+	return u
+}
+
+func makeBenchmarkURLWithParamStart(paramCount, genericStart int) *URL {
+	u := NewURLWithOptions(
+		WithProtocol(benchmarkURLProtocol),
+		WithIp(benchmarkURLIP),
+		WithPort(benchmarkURLPort),
+		WithPath(benchmarkURLInterface),
+		WithMethods(makeBenchmarkMethods()),
+		WithParams(makeBenchmarkParams(paramCount, genericStart)),
+	)
+	u.primitiveTS = u.GetParam(constant.TimestampKey, "")
+	return u
+}
+
+func makeBenchmarkMergeHalfOverlapPair(paramCount int) (*URL, *URL) {
+	return makeBenchmarkURL(paramCount), makeBenchmarkURLWithParamStart(paramCount, paramCount/2)
+}
+
+func makeBenchmarkParams(paramCount, genericStart int) url.Values {
+	params := make(url.Values, len(benchmarkURLIdentityParams)+paramCount)
+	for _, param := range benchmarkURLIdentityParams {
+		params.Set(param.key, param.value)
+	}
+	for i := 0; i < paramCount; i++ {
+		genericIndex := genericStart + i
+		params.Set(fmt.Sprintf("key%d", genericIndex), fmt.Sprintf("value%d", genericIndex))
+	}
+	return params
+}
+
+func makeBenchmarkParamKeys(paramCount int) []string {
+	keys := make([]string, 0, len(benchmarkURLIdentityParams)+paramCount)
+	for _, param := range benchmarkURLIdentityParams {
+		keys = append(keys, param.key)
+	}
+	for i := 0; i < paramCount; i++ {
+		keys = append(keys, fmt.Sprintf("key%d", i))
+	}
+	return keys
+}
+
+func makeBenchmarkExcludeSet(paramCount int) *gxset.HashSet {
+	keys := makeBenchmarkFilterKeys(paramCount)
+	values := make([]any, 0, len(keys))
+	for _, key := range keys {
+		values = append(values, key)
+	}
+	return gxset.NewSet(values...)
+}
+
+func makeBenchmarkReserveKeys(paramCount int) []string {
+	return makeBenchmarkFilterKeys(paramCount)
+}
+
+func makeBenchmarkFilterKeys(paramCount int) []string {
+	keys := makeBenchmarkParamKeys(paramCount)
+	filterCount := len(keys) / 5
+	if filterCount < 1 {
+		filterCount = 1
+	}
+	if filterCount > len(keys) {
+		filterCount = len(keys)
+	}
+	return keys[:filterCount]
+}
+
+func makeBenchmarkMethods() []string {
+	return []string{"method0", "method1", "method2"}
+}
+
+func addBenchmarkMethodParams(u *URL) {
+	u.Methods = makeBenchmarkMethods()
+	u.SetParam(constant.LoadbalanceKey, "random")
+	u.SetParam(constant.ClusterKey, "failover")
+	u.SetParam(constant.RetriesKey, "2")
+	u.SetParam(constant.TimeoutKey, "3000")
+	for _, method := range u.Methods {
+		u.SetParam("methods."+method+"."+constant.LoadbalanceKey, "roundrobin")
+		u.SetParam("methods."+method+"."+constant.ClusterKey, "failfast")
+		u.SetParam("methods."+method+"."+constant.RetriesKey, "1")
+		u.SetParam("methods."+method+"."+constant.TimeoutKey, "1000")
+	}
+}
+
+var benchmarkURLIdentityParams = []struct {
+	key   string
+	value string
+}{
+	{constant.InterfaceKey, benchmarkURLInterface},
+	{constant.GroupKey, benchmarkURLGroup},
+	{constant.VersionKey, benchmarkURLVersion},
+	{constant.TimestampKey, benchmarkURLTimestamp},
+	{constant.MeshClusterIDKey, benchmarkURLMeshID},
+}