mirror of
https://github.com/luxfi/node.git
synced 2026-10-30 15:24:05 +00:00
go list ./... returned nothing, so no package here could be built or tested and the failure was invisible: one directory held a Go test beside fifteen .cpp files, which makes it a Go package the toolchain then refuses. The generator moves to the golden/ subdirectory the other two C++ chains already use. That silence was hiding a package that does not compile. host/ calls EnsureIdentity and identity.go defines LoadIdentity — a rename that happened on one side — and it has no importers, because the Go host is cmd/luxd now. Deleted rather than repaired: the thing it was a stand-in for arrived. The operator tools came across too (backup, blscheck, ceremony, config, genesishash, keytoaddr, pqkeygen, repair-proposervm, wire) plus benchmarks and examples, so the package set now differs from the retired repo by exactly one name: main/ is cmd/luxd. Two tests were right and are now satisfied rather than silenced. The purity test looked for ./main; it looks where the daemon lives. The chain-address test found conformance/dex spelling /v1/chain by hand — but that is its own module on purpose, since it links an EVM ABI and a signer the node must not carry, so it cannot call Chain. The rule is about this module, and the walk now says so.
377 lines
7.3 KiB
Go
377 lines
7.3 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package benchmarks
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"encoding/binary"
|
|
"testing"
|
|
|
|
compression "github.com/luxfi/compress"
|
|
"github.com/luxfi/ids"
|
|
)
|
|
|
|
// BenchmarkMessageCompression benchmarks message compression
|
|
func BenchmarkMessageCompression(b *testing.B) {
|
|
// Create sample message data
|
|
data := make([]byte, 4096) // 4KB message
|
|
for i := range data {
|
|
// Create somewhat compressible data
|
|
data[i] = byte(i % 64)
|
|
}
|
|
|
|
b.Run("Gzip", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(data)))
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
var buf bytes.Buffer
|
|
w := gzip.NewWriter(&buf)
|
|
_, _ = w.Write(data)
|
|
_ = w.Close()
|
|
}
|
|
})
|
|
|
|
b.Run("Zstd", func(b *testing.B) {
|
|
compressor, err := compression.NewZstdCompressor(10 * 1024 * 1024) // 10MB max
|
|
if err != nil {
|
|
}
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(data)))
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_, _ = compressor.Compress(data)
|
|
}
|
|
})
|
|
|
|
b.Run("NoCompression", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(data)))
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
dst := make([]byte, len(data))
|
|
copy(dst, data)
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkMessageDecompression benchmarks message decompression
|
|
func BenchmarkMessageDecompression(b *testing.B) {
|
|
data := make([]byte, 4096)
|
|
for i := range data {
|
|
data[i] = byte(i % 64)
|
|
}
|
|
|
|
// Pre-compress data
|
|
var gzipBuf bytes.Buffer
|
|
w := gzip.NewWriter(&gzipBuf)
|
|
_, _ = w.Write(data)
|
|
_ = w.Close()
|
|
gzipData := gzipBuf.Bytes()
|
|
|
|
compressor, _ := compression.NewZstdCompressor(10 * 1024 * 1024) // 10MB max
|
|
zstdData, _ := compressor.Compress(data)
|
|
|
|
b.Run("Gzip", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(data)))
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
r, _ := gzip.NewReader(bytes.NewReader(gzipData))
|
|
var buf bytes.Buffer
|
|
_, _ = buf.ReadFrom(r)
|
|
_ = r.Close()
|
|
}
|
|
})
|
|
|
|
b.Run("Zstd", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(len(data)))
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_, _ = compressor.Decompress(zstdData)
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkMessageSerialization benchmarks message serialization
|
|
func BenchmarkNetworkMessageSerialization(b *testing.B) {
|
|
type networkMessage struct {
|
|
ChainID ids.ID
|
|
RequestID uint32
|
|
NodeID ids.NodeID
|
|
Data []byte
|
|
}
|
|
|
|
msg := networkMessage{
|
|
ChainID: ids.GenerateTestID(),
|
|
RequestID: 12345,
|
|
NodeID: ids.GenerateTestNodeID(),
|
|
Data: make([]byte, 256),
|
|
}
|
|
|
|
b.Run("Manual", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
buf := make([]byte, 0, 32+4+32+256)
|
|
buf = append(buf, msg.ChainID[:]...)
|
|
reqIDBytes := make([]byte, 4)
|
|
binary.BigEndian.PutUint32(reqIDBytes, msg.RequestID)
|
|
buf = append(buf, reqIDBytes...)
|
|
buf = append(buf, msg.NodeID[:]...)
|
|
buf = append(buf, msg.Data...)
|
|
}
|
|
})
|
|
|
|
b.Run("Buffer", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
var buf bytes.Buffer
|
|
buf.Write(msg.ChainID[:])
|
|
binary.Write(&buf, binary.BigEndian, msg.RequestID)
|
|
buf.Write(msg.NodeID[:])
|
|
buf.Write(msg.Data)
|
|
_ = buf.Bytes()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkNodeIDOperations benchmarks NodeID operations
|
|
func BenchmarkNodeIDOperations(b *testing.B) {
|
|
nodeID1 := ids.GenerateTestNodeID()
|
|
nodeID2 := ids.GenerateTestNodeID()
|
|
|
|
b.Run("Compare", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = bytes.Compare(nodeID1[:], nodeID2[:])
|
|
}
|
|
})
|
|
|
|
b.Run("String", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = nodeID1.String()
|
|
}
|
|
})
|
|
|
|
b.Run("MarshalJSON", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
_, _ = nodeID1.MarshalJSON()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkPeerSet benchmarks peer set operations
|
|
func BenchmarkPeerSet(b *testing.B) {
|
|
peers := make(map[ids.NodeID]struct{})
|
|
nodeIDs := make([]ids.NodeID, 100)
|
|
for i := range nodeIDs {
|
|
nodeIDs[i] = ids.GenerateTestNodeID()
|
|
}
|
|
|
|
b.Run("Add", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
peers[nodeIDs[i%100]] = struct{}{}
|
|
}
|
|
})
|
|
|
|
b.Run("Contains", func(b *testing.B) {
|
|
// Pre-populate
|
|
for _, id := range nodeIDs {
|
|
peers[id] = struct{}{}
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_, ok := peers[nodeIDs[i%100]]
|
|
_ = ok
|
|
}
|
|
})
|
|
|
|
b.Run("Remove", func(b *testing.B) {
|
|
// Pre-populate
|
|
for _, id := range nodeIDs {
|
|
peers[id] = struct{}{}
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
delete(peers, nodeIDs[i%100])
|
|
peers[nodeIDs[i%100]] = struct{}{} // Add it back
|
|
}
|
|
})
|
|
|
|
b.Run("Iterate", func(b *testing.B) {
|
|
// Pre-populate
|
|
for _, id := range nodeIDs {
|
|
peers[id] = struct{}{}
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
count := 0
|
|
for range peers {
|
|
count++
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkMessageQueue benchmarks message queue operations
|
|
func BenchmarkMessageQueue(b *testing.B) {
|
|
type message struct {
|
|
ID ids.ID
|
|
Data []byte
|
|
}
|
|
|
|
b.Run("Channel", func(b *testing.B) {
|
|
ch := make(chan message, 100)
|
|
msg := message{
|
|
ID: ids.GenerateTestID(),
|
|
Data: make([]byte, 256),
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
select {
|
|
case ch <- msg:
|
|
default:
|
|
<-ch
|
|
ch <- msg
|
|
}
|
|
}
|
|
})
|
|
|
|
b.Run("BufferedChannel", func(b *testing.B) {
|
|
ch := make(chan message, 1000)
|
|
msg := message{
|
|
ID: ids.GenerateTestID(),
|
|
Data: make([]byte, 256),
|
|
}
|
|
|
|
// Pre-fill to 50%
|
|
for i := 0; i < 500; i++ {
|
|
ch <- msg
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
select {
|
|
case ch <- msg:
|
|
<-ch // Keep it balanced
|
|
default:
|
|
}
|
|
}
|
|
})
|
|
|
|
b.Run("Slice", func(b *testing.B) {
|
|
queue := make([]message, 0, 1000)
|
|
msg := message{
|
|
ID: ids.GenerateTestID(),
|
|
Data: make([]byte, 256),
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
if len(queue) < cap(queue) {
|
|
queue = append(queue, msg)
|
|
} else {
|
|
// Remove first element and append
|
|
queue = queue[1:]
|
|
queue = append(queue, msg)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkConnectionPool benchmarks connection pool operations
|
|
func BenchmarkConnectionPool(b *testing.B) {
|
|
type connection struct {
|
|
nodeID ids.NodeID
|
|
connected bool
|
|
data []byte
|
|
}
|
|
|
|
pool := make(map[ids.NodeID]*connection)
|
|
nodeIDs := make([]ids.NodeID, 100)
|
|
for i := range nodeIDs {
|
|
nodeIDs[i] = ids.GenerateTestNodeID()
|
|
}
|
|
|
|
b.Run("Get", func(b *testing.B) {
|
|
// Pre-populate
|
|
for _, id := range nodeIDs {
|
|
pool[id] = &connection{
|
|
nodeID: id,
|
|
connected: true,
|
|
data: make([]byte, 256),
|
|
}
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
conn := pool[nodeIDs[i%100]]
|
|
_ = conn
|
|
}
|
|
})
|
|
|
|
b.Run("Add", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
pool[nodeIDs[i%100]] = &connection{
|
|
nodeID: nodeIDs[i%100],
|
|
connected: true,
|
|
data: make([]byte, 256),
|
|
}
|
|
}
|
|
})
|
|
|
|
b.Run("Remove", func(b *testing.B) {
|
|
// Pre-populate
|
|
for _, id := range nodeIDs {
|
|
pool[id] = &connection{
|
|
nodeID: id,
|
|
connected: true,
|
|
data: make([]byte, 256),
|
|
}
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
id := nodeIDs[i%100]
|
|
delete(pool, id)
|
|
// Add it back
|
|
pool[id] = &connection{
|
|
nodeID: id,
|
|
connected: true,
|
|
data: make([]byte, 256),
|
|
}
|
|
}
|
|
})
|
|
}
|