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
```
This commit is contained in:
Kobe Housen 2023-11-10 15:55:58 +00:00 committed by Alex Bee
parent 2b7abdce8f
commit 8b460bc60f
2 changed files with 34 additions and 2 deletions

View File

@ -71,7 +71,7 @@ func (nk *nick) Nick() *Nick {
Host: nk.host, Host: nk.host,
Name: nk.name, Name: nk.name,
Modes: nk.modes.Copy(), Modes: nk.modes.Copy(),
Channels: make(map[string]*ChanPrivs), Channels: make(map[string]*ChanPrivs, len(nk.chans)),
} }
for c, cp := range nk.chans { for c, cp := range nk.chans {
n.Channels[c.name] = cp.Copy() 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: // Returns a string representing the nick. Looks like:
//
// Nick: <nick name> e.g. CowMaster // Nick: <nick name> e.g. CowMaster
// Hostmask: <ident@host> e.g. moo@cows.org // Hostmask: <ident@host> e.g. moo@cows.org
// Real Name: <real name> e.g. Steve "CowMaster" Bush // Real Name: <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: // Returns a string representing the nick modes. Looks like:
//
// +iwx // +iwx
func (nm *NickMode) String() string { func (nm *NickMode) String() string {
if nm == nil { if nm == nil {

View File

@ -1,6 +1,9 @@
package state package state
import "testing" import (
"fmt"
"testing"
)
func compareNick(t *testing.T, nk *nick) { func compareNick(t *testing.T, nk *nick) {
n := nk.Nick() n := nk.Nick()
@ -86,3 +89,30 @@ func TestNickParseModes(t *testing.T) {
t.Errorf("Modes not flipped correctly by ParseModes.") 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()
}
}