Skip to content

Commit 3a91c2e

Browse files
committed
Add concurrent city lookup benchmark
Add BenchmarkCityLookupConcurrent to demonstrate string cache performance improvements under concurrent load. Tests 1, 4, 16, and 64 goroutines performing realistic city lookups, providing clear metrics for concurrent scaling behavior.
1 parent 39ee35c commit 3a91c2e

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

reader_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/netip"
1010
"os"
1111
"path/filepath"
12+
"sync"
1213
"testing"
1314
"time"
1415

@@ -1007,6 +1008,61 @@ func BenchmarkDecodePathCountryCode(b *testing.B) {
10071008
require.NoError(b, db.Close(), "error on close")
10081009
}
10091010

1011+
// BenchmarkCityLookupConcurrent tests concurrent city lookups to demonstrate
1012+
// string cache performance under concurrent load.
1013+
func BenchmarkCityLookupConcurrent(b *testing.B) {
1014+
db, err := Open("GeoLite2-City.mmdb")
1015+
require.NoError(b, err)
1016+
defer func() {
1017+
require.NoError(b, db.Close(), "error on close")
1018+
}()
1019+
1020+
// Test with different numbers of concurrent goroutines
1021+
goroutineCounts := []int{1, 4, 16, 64}
1022+
1023+
for _, numGoroutines := range goroutineCounts {
1024+
b.Run(fmt.Sprintf("goroutines_%d", numGoroutines), func(b *testing.B) {
1025+
// Each goroutine performs 100 lookups
1026+
const lookupsPerGoroutine = 100
1027+
b.ResetTimer()
1028+
1029+
for range b.N {
1030+
var wg sync.WaitGroup
1031+
wg.Add(numGoroutines)
1032+
1033+
for range numGoroutines {
1034+
go func() {
1035+
defer wg.Done()
1036+
1037+
//nolint:gosec // this is a test
1038+
r := rand.New(rand.NewSource(time.Now().UnixNano()))
1039+
s := make(net.IP, 4)
1040+
var result fullCity
1041+
1042+
for range lookupsPerGoroutine {
1043+
ip := randomIPv4Address(r, s)
1044+
err := db.Lookup(ip).Decode(&result)
1045+
if err != nil {
1046+
b.Error(err)
1047+
return
1048+
}
1049+
// Access string fields to exercise the cache
1050+
_ = result.City.Names
1051+
_ = result.Country.Names
1052+
}
1053+
}()
1054+
}
1055+
1056+
wg.Wait()
1057+
}
1058+
1059+
// Report operations per second
1060+
totalOps := int64(b.N) * int64(numGoroutines) * int64(lookupsPerGoroutine)
1061+
b.ReportMetric(float64(totalOps)/b.Elapsed().Seconds(), "lookups/sec")
1062+
})
1063+
}
1064+
}
1065+
10101066
func randomIPv4Address(r *rand.Rand, ip []byte) netip.Addr {
10111067
num := r.Uint32()
10121068
ip[0] = byte(num >> 24)

0 commit comments

Comments
 (0)