Files
VictoriaMetrics/lib/stringsutil/stringsutil_timing_test.go
Vadim Alekseev de3690671b lib/stringsutil: optimize AppendLowercase
The optimization includes the following improvements:
- Implementation of a function that processes 8 bytes per loop iteration to locate ASCII characters using bitwise manipulations.
- Implementation of the ToLowercaseFunc function that prevents string copying if the string is already in lowercase.
- Use of a lookup table for converting ASCII characters to lowercase, with logic copied from the VictoriaLogs repository.
2026-04-16 02:22:45 +04:00

133 lines
5.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package stringsutil
import (
"sync/atomic"
"testing"
)
func BenchmarkAppendLowercase(b *testing.B) {
b.Run("ascii-full-lowercase", func(b *testing.B) {
data := `started kubernetes log collector for node "gke-sandbox-e2-standard-8-20250715071-5b0a2ce9-vyko"`
benchmarkToLower(b, data)
})
b.Run("ascii-partial-lowercase", func(b *testing.B) {
data := `started Kubernetes log collector for Node "gke-sandbox-e2-standard-8-20250715071-5b0a2ce9-vyko"`
benchmarkToLower(b, data)
})
b.Run("ascii-full-uppercase", func(b *testing.B) {
data := `STARTED KUBERNETES LOG COLLECTOR FOR NODE "GKE-SANDBOX-E2-STANDARD-8-20250715071-5B0A2CE9-VYKO"`
benchmarkToLower(b, data)
})
b.Run("ascii-partial-uppercase", func(b *testing.B) {
data := `started KUBERNETES log collector FOR NODE "gke-sandbox-e2-standard-8-20250715071-5b0a2ce9-vyko"`
benchmarkToLower(b, data)
})
b.Run("ascii-full-title", func(b *testing.B) {
data := `Started Kubernetes Log Collector For Node "Gke-Sandbox-E2-Standard-8-20250715071-5b0a2ce9-Vyko"`
benchmarkToLower(b, data)
})
b.Run("ascii-partial-title", func(b *testing.B) {
data := `started Kubernetes log Collector for Node "gke-sandbox-e2-standard-8-20250715071-5b0a2ce9-vyko"`
benchmarkToLower(b, data)
})
b.Run("ascii-mixcase", func(b *testing.B) {
data := `Started Kubernetes log COLLECTOR for nodE "GKE-Sandbox-E2-Standard-8-20250715071-5b0a2ce9-VYKO"`
benchmarkToLower(b, data)
})
b.Run("unicode-full-lowercase", func(b *testing.B) {
data := `запущен кубернетес лог коллектор на ноде гке-сендбокс-е2-стандарт-8-20250715071-5в0а2се9-вико`
benchmarkToLower(b, data)
})
b.Run("unicode-partial-lowercase", func(b *testing.B) {
data := `запущен КубернеТЕС лОг кОллектор нА НодЕ гке-сендбокс-е2-стандарт-8-20250715071-5в0а2се9-вико`
benchmarkToLower(b, data)
})
b.Run("unicode-full-uppercase", func(b *testing.B) {
data := `ЗАПУЩЕН КУБЕРНЕТЕС ЛОГ КОЛЛЕКТОР НА НОДЕ ГКЕ-СЕНДБОКС-Е2-СТАНДАРТ-8-20250715071-5В0А2СЕ9-ВИКО`
benchmarkToLower(b, data)
})
b.Run("unicode-partial-uppercase", func(b *testing.B) {
data := `запущен КУБЕРНЕТЕС лог коллектор НА НОДЕ гке-сендбокс-е2-стандарт-8-20250715071-5в0а2се9-вико`
benchmarkToLower(b, data)
})
b.Run("unicode-full-title", func(b *testing.B) {
data := `Запущен Кубернетес Лог Коллектор На Ноде Гке-Сендбокс-Е2-Стандарт-8-20250715071-5В0а2се9-Вико`
benchmarkToLower(b, data)
})
b.Run("unicode-partial-title", func(b *testing.B) {
data := `запущен Кубернетес лог Коллектор на Ноде гке-сендбокс-е2-стандарт-8-20250715071-5в0а2се9-вико`
benchmarkToLower(b, data)
})
b.Run("unicode-mixcase", func(b *testing.B) {
data := `Запущен Кубернетес лог КОЛЛЕКТОР на нодЕ гке-Сендбокс-Е2-Стандарт-8-20250715071-5В0а2се9-ВИКО`
benchmarkToLower(b, data)
})
}
func benchmarkToLower(b *testing.B, s string) {
b.Helper()
b.ReportAllocs()
b.SetBytes(int64(len(s)))
b.RunParallel(func(pb *testing.PB) {
var buf []byte
for pb.Next() {
buf = AppendLowercase(buf[:0], s)
}
GlobalSink.Add(uint64(len(buf)))
})
}
var GlobalSink atomic.Uint64
func BenchmarkIsLowercase(b *testing.B) {
b.Run("ascii-mismatch", func(b *testing.B) {
data := `started kubernetes log collector for node "gke-sandbox-e2-standard-8-20250715071-5b0a2ce9-vyko"`
benchmarkIsLowercase(b, data, true)
})
b.Run("ascii-match-start", func(b *testing.B) {
data := `started Kubernetes log collector for Node "gke-sandbox-e2-standard-8-20250715071-5b0a2ce9-vyko"`
benchmarkIsLowercase(b, data, false)
})
b.Run("ascii-match-middle", func(b *testing.B) {
data := `started kubernetes log collector for Node "gke-sandbox-e2-standard-8-20250715071-5b0a2ce9-vyko"`
benchmarkIsLowercase(b, data, false)
})
b.Run("ascii-match-end", func(b *testing.B) {
data := `started kubernetes log collector for node "gke-sandbox-e2-standard-8-20250715071-5b0a2ce9-vyKo"`
benchmarkIsLowercase(b, data, false)
})
b.Run("unicode-mismatch", func(b *testing.B) {
data := `запущен кубернетес лог коллектор на ноде гке-сендбокс-е2-стандарт-8-20250715071-5в0а2се9-вико`
benchmarkIsLowercase(b, data, true)
})
b.Run("unicode-match-start", func(b *testing.B) {
data := `запущен Кубернетес лог коллектор на ноде гке-сендбокс-е2-стандарт-8-20250715071-5в0а2се9-вико`
benchmarkIsLowercase(b, data, false)
})
b.Run("unicode-match-middle", func(b *testing.B) {
data := `запущен кубернетес лог коллектор на Ноде гке-сендбокс-е2-стандарт-8-20250715071-5в0а2се9-вико`
benchmarkIsLowercase(b, data, false)
})
b.Run("unicode-match-end", func(b *testing.B) {
data := `запущен кубернетес лог коллектор на ноде гке-сендбокс-е2-стандарт-8-20250715071-5в0а2се9-виКо`
benchmarkIsLowercase(b, data, false)
})
}
func benchmarkIsLowercase(b *testing.B, s string, expected bool) {
b.Helper()
b.ReportAllocs()
b.SetBytes(int64(len(s)))
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if IsLowercase(s) != expected {
b.Fatalf("expected IsLower(%q) to return %v", s, expected)
}
}
})
}