From 8b460bc60f91860f9a78e571b55cc7df557e40e7 Mon Sep 17 00:00:00 2001 From: Kobe Housen Date: Fri, 10 Nov 2023 15:55:58 +0000 Subject: [PATCH] Use make size hint when copying channels in Nick() 70% faster when using a high number of channels Old performance ``` $ go test ./state -bench=. goos: linux goarch: amd64 pkg: github.com/fluffle/goirc/state cpu: AMD Ryzen Threadripper PRO 3945WX 12-Cores BenchmarkNickSingleChan-24 15465226 76.35 ns/op BenchmarkNickManyChan-24 5738 195721 ns/op PASS ok github.com/fluffle/goirc/state 2.433s ``` new performance ``` $ go test ./state -bench=. goos: linux goarch: amd64 pkg: github.com/fluffle/goirc/state cpu: AMD Ryzen Threadripper PRO 3945WX 12-Cores BenchmarkNickSingleChan-24 15022640 79.13 ns/op BenchmarkNickManyChan-24 10000 115104 ns/op PASS ok github.com/fluffle/goirc/state 2.456s ``` --- state/nick.go | 4 +++- state/nick_test.go | 32 +++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/state/nick.go b/state/nick.go index b29d98a..24a03bd 100644 --- a/state/nick.go +++ b/state/nick.go @@ -71,7 +71,7 @@ func (nk *nick) Nick() *Nick { Host: nk.host, Name: nk.name, Modes: nk.modes.Copy(), - Channels: make(map[string]*ChanPrivs), + Channels: make(map[string]*ChanPrivs, len(nk.chans)), } for c, cp := range nk.chans { n.Channels[c.name] = cp.Copy() @@ -157,6 +157,7 @@ func (nm *NickMode) Equals(other *NickMode) bool { } // Returns a string representing the nick. Looks like: +// // Nick: e.g. CowMaster // Hostmask: e.g. moo@cows.org // Real Name: e.g. Steve "CowMaster" Bush @@ -181,6 +182,7 @@ func (nk *nick) String() string { } // Returns a string representing the nick modes. Looks like: +// // +iwx func (nm *NickMode) String() string { if nm == nil { diff --git a/state/nick_test.go b/state/nick_test.go index 1344400..717c8a0 100644 --- a/state/nick_test.go +++ b/state/nick_test.go @@ -1,6 +1,9 @@ package state -import "testing" +import ( + "fmt" + "testing" +) func compareNick(t *testing.T, nk *nick) { n := nk.Nick() @@ -86,3 +89,30 @@ func TestNickParseModes(t *testing.T) { t.Errorf("Modes not flipped correctly by ParseModes.") } } + +func BenchmarkNickSingleChan(b *testing.B) { + nk := newNick("test1") + ch := newChannel("#test1") + cp := new(ChanPrivs) + nk.addChannel(ch, cp) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + nk.Nick() + } +} + +func BenchmarkNickManyChan(b *testing.B) { + const numChans = 1000 + nk := newNick("test1") + for i := 0; i < numChans; i++ { + ch := newChannel(fmt.Sprintf("#test%d", i)) + cp := new(ChanPrivs) + nk.addChannel(ch, cp) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + nk.Nick() + } +}