util/fastuuid: add a more efficient uuid generator

This still generates github.com/google/uuid UUID objects, but does so
using a ChaCha8 CSPRNG from the stdlib rand/v2 package. The public API
is backed by a sync.Pool to provide good performance in highly
concurrent operation.

Under high load the read API produces a lot of extra garbage and
overhead by way of temporaries and syscalls. This implementation reduces
both to minimal levels, and avoids any long held global lock by
utilizing sync.Pool.

Updates tailscale/corp#18266
Updates tailscale/corp#19054

Signed-off-by: James Tucker <james@tailscale.com>
This commit is contained in:
James Tucker
2024-04-09 13:02:18 -07:00
committed by James Tucker
parent db760d0bac
commit d0f3fa7d7e
2 changed files with 128 additions and 0 deletions

View File

@ -0,0 +1,72 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package fastuuid
import (
"testing"
"github.com/google/uuid"
)
func TestNewUUID(t *testing.T) {
g := pool.Get().(*generator)
defer pool.Put(g)
u := g.newUUID()
if u[6] != (u[6]&0x0f)|0x40 {
t.Errorf("version bits are incorrect")
}
if u[8] != (u[8]&0x3f)|0x80 {
t.Errorf("variant bits are incorrect")
}
}
func BenchmarkBasic(b *testing.B) {
b.Run("NewUUID", func(b *testing.B) {
for i := 0; i < b.N; i++ {
NewUUID()
}
})
b.Run("uuid.New-unpooled", func(b *testing.B) {
uuid.DisableRandPool()
for i := 0; i < b.N; i++ {
uuid.New()
}
})
b.Run("uuid.New-pooled", func(b *testing.B) {
uuid.EnableRandPool()
for i := 0; i < b.N; i++ {
uuid.New()
}
})
}
func BenchmarkParallel(b *testing.B) {
b.Run("NewUUID", func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
NewUUID()
}
})
})
b.Run("uuid.New-unpooled", func(b *testing.B) {
uuid.DisableRandPool()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
uuid.New()
}
})
})
b.Run("uuid.New-pooled", func(b *testing.B) {
uuid.EnableRandPool()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
uuid.New()
}
})
})
}