Skip to content

Avoid slice allocation in ValidateEndpointHost - #705

Open
joshuapare wants to merge 1 commit into
aws:mainfrom
joshuapare:optimize-host-validation-allocations
Open

Avoid slice allocation in ValidateEndpointHost#705
joshuapare wants to merge 1 commit into
aws:mainfrom
joshuapare:optimize-host-validation-allocations

Conversation

@joshuapare

@joshuapare joshuapare commented Sep 5, 2026

Copy link
Copy Markdown

Description of changes:

Replaced strings.Split with index-based scanning over the hostname so label extraction no longer allocates a []string, while preserving the existing trailing-dot (FQDN) handling and validation semantics. Roughly 43%-56% single core perf improvement, up to 81% under 18 concurrent goroutines. Also considered an LRU or sync.Map cache to avoid the validation entirely but the mutex and map hash cost exceeds the computation cost with the risk of unbounded map growth, so not worth it to try to short circuit the check.

Benchmarked locally with temporary benchmark cases, can add to commit if necessary. Results are as follows:

Machine:

goos: darwin
goarch: arm64
cpu: Apple M5 Max (18 cores)
go version go1.26.1 darwin/arm64
macOS 26.5.2 (25F84)

Single

                          │   before    │           after            │
                          │   sec/op    │   sec/op     vs base       │
ValidateEndpointHost/short   31.37n ± 2%   11.79n ± 1%  -62.39% (p=0.000 n=10)
ValidateEndpointHost/service 55.38n ± 1%   25.78n ± 3%  -53.45% (p=0.000 n=10)
ValidateEndpointHost/fqdn    64.25n ± 1%   28.39n ± 2%  -55.81% (p=0.000 n=10)
ValidateEndpointHost/with_port 66.12n ± 1% 34.97n ± 1%  -47.12% (p=0.000 n=10)
ValidateEndpointHost/long   107.35n ± 1%   56.29n ± 2%  -47.57% (p=0.000 n=10)

Concurrent (4 to 18)

                                        │  before   │            after            │
                                        │  sec/op   │   sec/op     vs base        │
ValidateEndpointHostParallel/service       56.49n     26.32n ± 2%  -53.40% (p=0.000 n=10)   (GOMAXPROCS=1)
ValidateEndpointHostParallel/service-4     19.52n      6.55n ± 2%  -66.44% (p=0.000 n=10)   (GOMAXPROCS=4)
ValidateEndpointHostParallel/service-18    20.53n      2.07n ± 3%  -89.90% (p=0.000 n=10)   (GOMAXPROCS=18)

Benchmark cases:

var benchmarkHosts = map[string]string{
	"short":     "example.com",
	"service":   "s3.us-west-2.amazonaws.com",
	"fqdn":      "s3.us-west-2.amazonaws.com.",
	"with port": "s3.us-west-2.amazonaws.com:8443",
	"long":      "my-very-long-bucket-name.s3-accesspoint.dualstack.us-west-2.amazonaws.com",
}

func BenchmarkValidateEndpointHost(b *testing.B) {
	for name, host := range benchmarkHosts {
		b.Run(name, func(b *testing.B) {
			b.ReportAllocs()
			for i := 0; i < b.N; i++ {
				if err := ValidateEndpointHost(host); err != nil {
					b.Fatalf("expect no error, got %v", err)
				}
			}
		})
	}
}

func BenchmarkValidateEndpointHostParallel(b *testing.B) {
	for name, host := range benchmarkHosts {
		b.Run(name, func(b *testing.B) {
			b.ReportAllocs()
			b.RunParallel(func(pb *testing.PB) {
				for pb.Next() {
					if err := ValidateEndpointHost(host); err != nil {
						b.Fatalf("expect no error, got %v", err)
					}
				}
			})
		})
	}
}

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Replace strings.Split with index-based scanning over the hostname so
label extraction no longer allocates a []string, while preserving the
existing trailing-dot (FQDN) handling and validation semantics.
@joshuapare
joshuapare requested review from a team as code owners September 5, 2026 02:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant