mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
334 lines
6.9 KiB
Go
334 lines
6.9 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package benchmarks
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/luxfi/crypto/hash"
|
|
"github.com/luxfi/database/memdb"
|
|
"github.com/luxfi/database/prefixdb"
|
|
"github.com/luxfi/database/versiondb"
|
|
"github.com/luxfi/ids"
|
|
)
|
|
|
|
// BenchmarkMemoryDatabase benchmarks in-memory database operations
|
|
func BenchmarkMemoryDatabase(b *testing.B) {
|
|
db := memdb.New()
|
|
defer db.Close()
|
|
|
|
key := []byte("test-key")
|
|
value := make([]byte, 1024) // 1KB value
|
|
for i := range value {
|
|
value[i] = byte(i % 256)
|
|
}
|
|
|
|
b.Run("Put", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
}
|
|
b.SetBytes(int64(len(value)))
|
|
})
|
|
|
|
b.Run("Get", func(b *testing.B) {
|
|
// Pre-populate database
|
|
for i := 0; i < 1000; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i%1000)...)
|
|
_, _ = db.Get(k)
|
|
}
|
|
})
|
|
|
|
b.Run("Delete", func(b *testing.B) {
|
|
// Pre-populate database
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-del-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-del-%d", i)...)
|
|
_ = db.Delete(k)
|
|
}
|
|
})
|
|
|
|
b.Run("Has", func(b *testing.B) {
|
|
// Pre-populate database
|
|
for i := 0; i < 1000; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i%1000)...)
|
|
_, _ = db.Has(k)
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkPrefixDatabase benchmarks prefix database operations
|
|
func BenchmarkPrefixDatabase(b *testing.B) {
|
|
baseDB := memdb.New()
|
|
defer baseDB.Close()
|
|
|
|
prefix := []byte("prefix")
|
|
db := prefixdb.New(prefix, baseDB)
|
|
|
|
key := []byte("test-key")
|
|
value := make([]byte, 256) // 256 bytes value
|
|
|
|
b.Run("Put", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
}
|
|
b.SetBytes(int64(len(value)))
|
|
})
|
|
|
|
b.Run("Get", func(b *testing.B) {
|
|
// Pre-populate
|
|
for i := 0; i < 100; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i%100)...)
|
|
_, _ = db.Get(k)
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkVersionDatabase benchmarks versioned database operations
|
|
func BenchmarkVersionDatabase(b *testing.B) {
|
|
baseDB := memdb.New()
|
|
defer baseDB.Close()
|
|
|
|
db := versiondb.New(baseDB)
|
|
|
|
key := []byte("test-key")
|
|
value := make([]byte, 256)
|
|
|
|
b.Run("Put", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
}
|
|
b.SetBytes(int64(len(value)))
|
|
})
|
|
|
|
b.Run("Commit", func(b *testing.B) {
|
|
// Add some data before each commit
|
|
for i := 0; i < 10; i++ {
|
|
k := append(key, fmt.Sprintf("-pre-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
_ = db.Commit()
|
|
}
|
|
})
|
|
|
|
b.Run("Abort", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
k := append(key, fmt.Sprintf("-%d", i)...)
|
|
_ = db.Put(k, value)
|
|
db.Abort()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkDatabaseBatch benchmarks batch database operations
|
|
func BenchmarkDatabaseBatch(b *testing.B) {
|
|
db := memdb.New()
|
|
defer db.Close()
|
|
|
|
b.Run("SmallBatch", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
batch := db.NewBatch()
|
|
for j := 0; j < 10; j++ {
|
|
key := []byte(fmt.Sprintf("key-%d-%d", i, j))
|
|
value := []byte(fmt.Sprintf("value-%d-%d", i, j))
|
|
_ = batch.Put(key, value)
|
|
}
|
|
_ = batch.Write()
|
|
}
|
|
})
|
|
|
|
b.Run("MediumBatch", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
batch := db.NewBatch()
|
|
for j := 0; j < 100; j++ {
|
|
key := []byte(fmt.Sprintf("key-%d-%d", i, j))
|
|
value := []byte(fmt.Sprintf("value-%d-%d", i, j))
|
|
_ = batch.Put(key, value)
|
|
}
|
|
_ = batch.Write()
|
|
}
|
|
})
|
|
|
|
b.Run("LargeBatch", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
batch := db.NewBatch()
|
|
for j := 0; j < 1000; j++ {
|
|
key := []byte(fmt.Sprintf("key-%d-%d", i, j))
|
|
value := []byte(fmt.Sprintf("value-%d-%d", i, j))
|
|
_ = batch.Put(key, value)
|
|
}
|
|
_ = batch.Write()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkDatabaseIterator benchmarks database iteration
|
|
func BenchmarkDatabaseIterator(b *testing.B) {
|
|
db := memdb.New()
|
|
defer db.Close()
|
|
|
|
// Pre-populate database
|
|
numEntries := 10000
|
|
for i := 0; i < numEntries; i++ {
|
|
key := []byte(fmt.Sprintf("key-%08d", i))
|
|
value := []byte(fmt.Sprintf("value-%d", i))
|
|
_ = db.Put(key, value)
|
|
}
|
|
|
|
b.Run("FullIteration", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
iter := db.NewIterator()
|
|
count := 0
|
|
for iter.Next() {
|
|
_ = iter.Key()
|
|
_ = iter.Value()
|
|
count++
|
|
}
|
|
iter.Release()
|
|
}
|
|
})
|
|
|
|
b.Run("PrefixIteration", func(b *testing.B) {
|
|
prefix := []byte("key-0000")
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
iter := db.NewIteratorWithPrefix(prefix)
|
|
count := 0
|
|
for iter.Next() {
|
|
_ = iter.Key()
|
|
_ = iter.Value()
|
|
count++
|
|
}
|
|
iter.Release()
|
|
}
|
|
})
|
|
|
|
b.Run("RangeIteration", func(b *testing.B) {
|
|
start := []byte("key-00001000")
|
|
end := []byte("key-00002000")
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
iter := db.NewIteratorWithStartAndPrefix(start, end)
|
|
count := 0
|
|
for iter.Next() {
|
|
_ = iter.Key()
|
|
_ = iter.Value()
|
|
count++
|
|
}
|
|
iter.Release()
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkDatabaseConcurrency benchmarks concurrent database access
|
|
func BenchmarkDatabaseConcurrency(b *testing.B) {
|
|
db := memdb.New()
|
|
defer db.Close()
|
|
|
|
// Pre-populate
|
|
for i := 0; i < 1000; i++ {
|
|
key := []byte(fmt.Sprintf("key-%d", i))
|
|
value := []byte(fmt.Sprintf("value-%d", i))
|
|
_ = db.Put(key, value)
|
|
}
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
i := 0
|
|
for pb.Next() {
|
|
key := []byte(fmt.Sprintf("key-%d", i%1000))
|
|
|
|
// Mix of operations
|
|
switch i % 3 {
|
|
case 0:
|
|
_, _ = db.Get(key)
|
|
case 1:
|
|
value := []byte(fmt.Sprintf("new-value-%d", i))
|
|
_ = db.Put(key, value)
|
|
case 2:
|
|
_, _ = db.Has(key)
|
|
}
|
|
i++
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkDatabaseKeyGeneration benchmarks different key generation strategies
|
|
func BenchmarkDatabaseKeyGeneration(b *testing.B) {
|
|
b.Run("Sequential", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = []byte(fmt.Sprintf("key-%d", i))
|
|
}
|
|
})
|
|
|
|
b.Run("Hash", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
data := fmt.Sprintf("key-%d", i)
|
|
_ = hash.ComputeHash256([]byte(data))
|
|
}
|
|
})
|
|
|
|
b.Run("ID", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
id := ids.GenerateTestID()
|
|
_ = id[:]
|
|
}
|
|
})
|
|
}
|