From d41dc5b8f0d22b6f59ba12c6242a643d7e0f85a3 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Mon, 23 Feb 2026 09:57:00 -0600 Subject: [PATCH 01/49] experiments with flatkv --- sei-db/state_db/bench/bench_sc_long_running_test.go | 3 +++ sei-db/state_db/bench/wrappers/db_implementations.go | 1 + 2 files changed, 4 insertions(+) diff --git a/sei-db/state_db/bench/bench_sc_long_running_test.go b/sei-db/state_db/bench/bench_sc_long_running_test.go index 028c91c39f..752aed5803 100644 --- a/sei-db/state_db/bench/bench_sc_long_running_test.go +++ b/sei-db/state_db/bench/bench_sc_long_running_test.go @@ -4,6 +4,8 @@ package bench import ( "testing" + + "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" ) func BenchmarkLongRunningWrite(b *testing.B) { @@ -12,6 +14,7 @@ func BenchmarkLongRunningWrite(b *testing.B) { NumBlocks: 1_000_000_000, TotalKeys: 1_000_000_000_000, DuplicateRatio: 0.5, + Backend: wrappers.FlatKV, } b.Run(scenario.Name, func(b *testing.B) { diff --git a/sei-db/state_db/bench/wrappers/db_implementations.go b/sei-db/state_db/bench/wrappers/db_implementations.go index 968094a5e4..eda99c96ae 100644 --- a/sei-db/state_db/bench/wrappers/db_implementations.go +++ b/sei-db/state_db/bench/wrappers/db_implementations.go @@ -46,6 +46,7 @@ func newFlatKVCommitStore(b *testing.B) DBWrapper { b.Helper() dir := b.TempDir() cfg := flatkv.DefaultConfig() + cfg.Fsync = false cs := flatkv.NewCommitStore(dir, logger.NewNopLogger(), cfg) _, err := cs.LoadVersion(0) From 44db682b139d85316847799d86aeaba57635757c Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Mon, 23 Feb 2026 11:34:23 -0600 Subject: [PATCH 02/49] Don't sync all DBs at commit time --- sei-db/state_db/sc/flatkv/store_write.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sei-db/state_db/sc/flatkv/store_write.go b/sei-db/state_db/sc/flatkv/store_write.go index 1f1f82b7c9..96f734e226 100644 --- a/sei-db/state_db/sc/flatkv/store_write.go +++ b/sei-db/state_db/sc/flatkv/store_write.go @@ -224,19 +224,12 @@ func (s *CommitStore) Commit() (int64, error) { s.committedVersion = version s.committedLtHash = s.workingLtHash.Clone() - // Step 4: Flush data DBs if not using fsync (ensures data is on disk before metaDB update) - if !s.config.Fsync { - if err := s.flushAllDBs(); err != nil { - return 0, fmt.Errorf("flush: %w", err) - } - } - - // Step 5: Persist global metadata to metadata DB (always every block) + // Step 4: Persist global metadata to metadata DB (always every block) if err := s.commitGlobalMetadata(version, s.committedLtHash); err != nil { return 0, fmt.Errorf("metadata DB commit: %w", err) } - // Step 6: Clear pending buffers + // Step 5: Clear pending buffers s.clearPendingWrites() s.log.Info("Committed version", "version", version) From 189bb31c8c3b54b3e4357b6880dde8164e51281d Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Mon, 23 Feb 2026 13:26:03 -0600 Subject: [PATCH 03/49] added some initial utilities --- sei-db/state_db/bench/cryptosim/README.md | 4 + .../bench/cryptosim/cryptosim_config.go | 56 ++++++++ .../state_db/bench/cryptosim/random_buffer.go | 127 ++++++++++++++++++ sei-db/state_db/bench/cryptosim/util.go | 38 ++++++ 4 files changed, 225 insertions(+) create mode 100644 sei-db/state_db/bench/cryptosim/README.md create mode 100644 sei-db/state_db/bench/cryptosim/cryptosim_config.go create mode 100644 sei-db/state_db/bench/cryptosim/random_buffer.go create mode 100644 sei-db/state_db/bench/cryptosim/util.go diff --git a/sei-db/state_db/bench/cryptosim/README.md b/sei-db/state_db/bench/cryptosim/README.md new file mode 100644 index 0000000000..8674372df7 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/README.md @@ -0,0 +1,4 @@ +The `cryptosim` benchmark simulates basic cryptocurrency transfer transactions. It's a benchmark designed to be +predictive of DB performance under a heavy crypto transfer load. + +TODO expand this doc \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go new file mode 100644 index 0000000000..087879a2f2 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -0,0 +1,56 @@ +package cryptosim + +// Defines the configuration for the cryptosim benchmark. +type CryptoSimConfig struct { + + // The minimum number of accounts that should be in the DB prior to the start of the benchmark. + // If there are fewer than this number of accounts, the benchmark will first create the necessary + // accounts before starting its regular operations. + MinimumAccountNumber int + + // When selecting an account for a transaction, the benchmark will select a hot account with this + // weight. The actual probability depends on the ratio of this weight to the other account weight configurations. + HotAccountWeight float64 + + // When selecting an account for a transaction, the benchmark will select a cold account with this + // weight. The actual probability depends on the ratio of this weight to the other account weight configurations. + ColdAccountWeight float64 + + // When selecting an account for a transaction, the benchmark will create a new account with this + // weight. The actual probability depends on the ratio of this weight to the other account weight configurations. + NewAccountWeight float64 + + // The number of hot accounts. + // + // Future work: add different distributions of hot account access. Currently, distribution is flat. + HotSetSize int + + // The number of bytes in the account key. + AccountKeySize int + + // Each account contains an integer value used to track a balance, plus a bunch of random + // bytes for padding. This is the total size of the account after padding is added. + PaddedAccountSize int + + // The number of transactions that will be processed in each "block". + TransactionsPerBlock int + + // The directory to store the benchmark data. If unspecified, the benchmark will use a temporary directory + // that is destroyed after the benchmark completes. + DataDir string +} + +// Returns the default configuration for the cryptosim benchmark. +func DefaultCryptoSimConfig() *CryptoSimConfig { + return &CryptoSimConfig{ + MinimumAccountNumber: 1000, + HotAccountWeight: 50, + ColdAccountWeight: 49, + NewAccountWeight: 1, + HotSetSize: 100, + AccountKeySize: 20, + PaddedAccountSize: 100, + TransactionsPerBlock: 100, + DataDir: "", + } +} diff --git a/sei-db/state_db/bench/cryptosim/random_buffer.go b/sei-db/state_db/bench/cryptosim/random_buffer.go new file mode 100644 index 0000000000..b7b57cf586 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/random_buffer.go @@ -0,0 +1,127 @@ +package cryptosim + +import ( + "encoding/binary" + "fmt" + "math/rand" +) + +// A utility that buffers randomness in a way that is highly performant for benchmarking. +// It contains a buffer of random bytes that it reuses to avoid generating lots of random numbers +// at runtime. +// +// The goal is to avoid accidentally creating CPU hotspots in the benchmark framework. We want +// to exercise the DB, not the code that feeds it randomness. +// +// This utility is not thread safe. +// +// In case it requires saying, this utility is NOT a suitable source cryptographically secure random numbers. +type RandomBuffer struct { + // Pre-generated buffer of random bytes. + buffer []byte + + // Controls the next index to read from the buffer. + index int64 +} + +// Creates a new random buffer. +func NewRandomBuffer( + // The size of the buffer to create. A slice of this size is instantiated, so avoid setting this too large. + // Do not set this too small though, as the buffer will panic if the requested number of bytes is greater + // than the buffer size. + bufferSize int, + // The seed to use to generate the random bytes. This utility provides deterministic random numbers + // given the same seed. + seed int64, +) *RandomBuffer { + + if bufferSize < 8 { + panic(fmt.Sprintf("buffer size must be at least 8 bytes, got %d", bufferSize)) + } + + // Adjust the buffer size so that (bufferSize % 8) == 1. This way when the index wraps around, it won't align + // perfectly with the buffer, giving us a longer runway before we repeat the exact same sequence of bytes. + // TODO verify that this logic works as intended. + bufferSize += (1 - (bufferSize % 8) + 8) % 8 + + source := rand.NewSource(seed) + rng := rand.New(source) + + buffer := make([]byte, bufferSize) + rng.Read(buffer) + + return &RandomBuffer{ + buffer: buffer, + index: 0, + } +} + +// Returns a slice of random bytes. +// +// Returned slice is NOT safe to modify. If modification is required, the caller should make a copy of the slice. +func (rb *RandomBuffer) Bytes(count int) []byte { + return rb.SeededBytes(count, rb.Int64()) +} + +// Returns a slice of random bytes from a given seed. Bytes are deterministic given the same seed. +// +// Returned slice is NOT safe to modify. If modification is required, the caller should make a copy of the slice. +func (rb *RandomBuffer) SeededBytes(count int, seed int64) []byte { + + if count < 0 { + panic(fmt.Sprintf("count must be non-negative, got %d", count)) + } + if count > len(rb.buffer) { + panic(fmt.Sprintf("count must be less than or equal to the buffer size, got %d", count)) + } else if count == len(rb.buffer) { + return rb.buffer + } + + startIndex := PositiveHash64(seed) % int64(len(rb.buffer)-count) + return rb.buffer[startIndex : startIndex+int64(count)] +} + +// Generate a random-ish int64. +func (rb *RandomBuffer) Int64() int64 { + bufLen := int64(len(rb.buffer)) + var buf [8]byte + for i := int64(0); i < 8; i++ { + buf[i] = rb.buffer[(rb.index+i)%bufLen] + } + base := binary.BigEndian.Uint64(buf[:]) + result := Hash64(int64(base) + rb.index) + + // Add 8 to the index to skip the 8 bytes we just read. + rb.index = (rb.index + 8) % bufLen + return result +} + +// Generate a random address suitable for use simulating an eth-style address. Given the same account ID, +// the address will be deterministic, and any two unique account IDs are guaranteed to generate unique addresses. +func (rb *RandomBuffer) Address( + addressSize int, + accountID int64, +) []byte { + + if addressSize < 8 { + panic(fmt.Sprintf("address size must be at least 8 bytes, got %d", addressSize)) + } + + address := make([]byte, addressSize) + baseBytes := rb.SeededBytes(addressSize, accountID) + + // Inject the account ID into the middle of the address to ensure uniqueness. + accountIDIndex := addressSize / 2 + if accountIDIndex+8 > addressSize { + // If we don't have enough space, put the account ID at the end. + accountIDIndex = addressSize - 8 + } + + // copy base bytes to the address + copy(address, baseBytes) + + // write the account ID to the address + binary.BigEndian.PutUint64(address[accountIDIndex:accountIDIndex+8], uint64(accountID)) + + return address +} diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go new file mode 100644 index 0000000000..9bc53fe0f6 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -0,0 +1,38 @@ +package cryptosim + +import "math" + +// Hash64 returns a well-distributed 64-bit hash of x. +// It implements the SplitMix64 finalizer, a fast non-cryptographic mixing +// function with excellent avalanche properties. It is suitable for hash tables, +// sharding, randomized iteration, and benchmarks, but it is NOT +// cryptographically secure. +// +// The function is a bijection over uint64 (no collisions as a mapping). +// +// References: +// - Steele, Lea, Flood. "Fast Splittable Pseudorandom Number Generators" +// (OOPSLA 2014): https://doi.org/10.1145/2660193.2660195 +// - Public domain reference implementation: +// http://xorshift.di.unimi.it/splitmix64.c +func Hash64(x int64) int64 { + z := uint64(x) + z += 0x9e3779b97f4a7c15 + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9 + z = (z ^ (z >> 27)) * 0x94d049bb133111eb + z = z ^ (z >> 31) + return int64(z) +} + +// PositiveHash64 returns the absolute value of Hash64(x). It never returns a negative value. +// When Hash64(x) is math.MinInt64, returns math.MaxInt64 since the true absolute value does not fit in int64. +func PositiveHash64(x int64) int64 { + result := Hash64(x) + if result == math.MinInt64 { + return math.MaxInt64 + } + if result < 0 { + return -result + } + return result +} From bd8c08f53a07c4043afc64a3b2d69a8a1843e2ca Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Mon, 23 Feb 2026 15:47:47 -0600 Subject: [PATCH 04/49] incremental progress --- sei-db/state_db/bench/cryptosim/cryptosim.go | 65 +++++++++++++++ .../bench/cryptosim/cryptosim_config.go | 11 +++ sei-db/state_db/bench/cryptosim/main/main.go | 10 +++ .../state_db/bench/cryptosim/random_buffer.go | 25 +++--- sei-db/state_db/bench/cryptosim/run.sh | 4 + sei-db/state_db/bench/cryptosim/util.go | 29 ++++++- sei-db/state_db/bench/helper.go | 9 ++- .../bench/wrappers/db_implementations.go | 81 +++++++++---------- sei-db/state_db/bench/wrappers/db_wrapper.go | 3 + .../state_db/bench/wrappers/flatkv_wrapper.go | 5 ++ .../bench/wrappers/memiavl_wrapper.go | 4 + 11 files changed, 191 insertions(+), 55 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/cryptosim.go create mode 100644 sei-db/state_db/bench/cryptosim/main/main.go create mode 100755 sei-db/state_db/bench/cryptosim/run.sh diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go new file mode 100644 index 0000000000..17d2f30e63 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -0,0 +1,65 @@ +package cryptosim + +import ( + "context" + "fmt" + + "github.com/sei-protocol/sei-chain/sei-db/common/evm" + "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" +) + +const ( + // Used to store the seed used for the current run. + seedKey = string(evm.EVMKeyNonce) + "seed" + // Used to store the next account ID to be used when creating a new account. + nonceKey = string(evm.EVMKeyNonce) + "nonce" +) + +// The test runner for the cryptosim benchmark. +type CryptoSim struct { + ctx context.Context + + // The configuration for the benchmark. + config *CryptoSimConfig + + // The database implementation to use for the benchmark. + db wrappers.DBWrapper + + // The source of randomness for the benchmark. + rand *RandomBuffer +} + +// Creates a new cryptosim benchmark runner. +func NewCryptoSim( + ctx context.Context, + config *CryptoSimConfig, +) (*CryptoSim, error) { + + dataDir, err := resolveAndCreateDataDir(config.DataDir) + if err != nil { + return nil, err + } + + db, err := wrappers.NewDBImpl(config.Backend, dataDir) + if err != nil { + return nil, fmt.Errorf("failed to create database: %w", err) + } + + c := &CryptoSim{ + ctx: ctx, + config: config, + db: db, + } + + c.setup() + c.start() + return c, nil +} + +func (c *CryptoSim) setup() { + // TODO +} + +func (c *CryptoSim) start() { + // TODO +} diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index 087879a2f2..1d0e52f801 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -1,5 +1,7 @@ package cryptosim +import "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" + // Defines the configuration for the cryptosim benchmark. type CryptoSimConfig struct { @@ -38,6 +40,13 @@ type CryptoSimConfig struct { // The directory to store the benchmark data. If unspecified, the benchmark will use a temporary directory // that is destroyed after the benchmark completes. DataDir string + + // The seed to use for the random number generator. If starting from a state on disk, this seed is ignored + // (the benchmark DB saves its own seed internally). + Seed int64 + + // The backend to use for the benchmark database. + Backend wrappers.DBType } // Returns the default configuration for the cryptosim benchmark. @@ -52,5 +61,7 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { PaddedAccountSize: 100, TransactionsPerBlock: 100, DataDir: "", + Seed: 0, + Backend: wrappers.FlatKV, } } diff --git a/sei-db/state_db/bench/cryptosim/main/main.go b/sei-db/state_db/bench/cryptosim/main/main.go new file mode 100644 index 0000000000..b4cb7850e5 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/main/main.go @@ -0,0 +1,10 @@ +package main + +import "fmt" + +// Run the cryptosim benchmark. +func main() { + // TODO + + fmt.Println("Hello, world!") +} diff --git a/sei-db/state_db/bench/cryptosim/random_buffer.go b/sei-db/state_db/bench/cryptosim/random_buffer.go index b7b57cf586..32acb4208a 100644 --- a/sei-db/state_db/bench/cryptosim/random_buffer.go +++ b/sei-db/state_db/bench/cryptosim/random_buffer.go @@ -99,7 +99,11 @@ func (rb *RandomBuffer) Int64() int64 { // Generate a random address suitable for use simulating an eth-style address. Given the same account ID, // the address will be deterministic, and any two unique account IDs are guaranteed to generate unique addresses. func (rb *RandomBuffer) Address( + // The prefix to use for the address. + keyPrefix []byte, + // The size of the address to generate, not including the key prefix. addressSize int, + // The account ID to use for the address. accountID int64, ) []byte { @@ -107,21 +111,20 @@ func (rb *RandomBuffer) Address( panic(fmt.Sprintf("address size must be at least 8 bytes, got %d", addressSize)) } - address := make([]byte, addressSize) + result := make([]byte, len(keyPrefix)+addressSize) + address := result[len(keyPrefix):] + copy(result, keyPrefix) + baseBytes := rb.SeededBytes(addressSize, accountID) - // Inject the account ID into the middle of the address to ensure uniqueness. - accountIDIndex := addressSize / 2 - if accountIDIndex+8 > addressSize { - // If we don't have enough space, put the account ID at the end. - accountIDIndex = addressSize - 8 + // Inject the account ID into the middle of the address span (excluding the prefix) to ensure uniqueness. + accountIDIndex := len(keyPrefix) + (addressSize / 2) + if accountIDIndex+8 > len(result) { + accountIDIndex = len(result) - 8 } - // copy base bytes to the address copy(address, baseBytes) + binary.BigEndian.PutUint64(result[accountIDIndex:accountIDIndex+8], uint64(accountID)) - // write the account ID to the address - binary.BigEndian.PutUint64(address[accountIDIndex:accountIDIndex+8], uint64(accountID)) - - return address + return result } diff --git a/sei-db/state_db/bench/cryptosim/run.sh b/sei-db/state_db/bench/cryptosim/run.sh new file mode 100755 index 0000000000..1833e95bf2 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/run.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# Run the cryptosim benchmark. +go run main/main.go \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go index 9bc53fe0f6..a639864006 100644 --- a/sei-db/state_db/bench/cryptosim/util.go +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -1,6 +1,12 @@ package cryptosim -import "math" +import ( + "fmt" + "math" + "os" + "path/filepath" + "strings" +) // Hash64 returns a well-distributed 64-bit hash of x. // It implements the SplitMix64 finalizer, a fast non-cryptographic mixing @@ -36,3 +42,24 @@ func PositiveHash64(x int64) int64 { } return result } + +// resolveAndCreateDataDir expands ~ to the home directory and creates the directory if it doesn't exist. +func resolveAndCreateDataDir(dataDir string) (string, error) { + if dataDir == "~" || strings.HasPrefix(dataDir, "~/") { + home, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("failed to get home directory: %w", err) + } + if dataDir == "~" { + dataDir = home + } else { + dataDir = filepath.Join(home, dataDir[2:]) + } + } + if dataDir != "" { + if err := os.MkdirAll(dataDir, 0755); err != nil { + return "", fmt.Errorf("failed to create data directory: %w", err) + } + } + return dataDir, nil +} diff --git a/sei-db/state_db/bench/helper.go b/sei-db/state_db/bench/helper.go index 37f1b5461c..94730cc169 100644 --- a/sei-db/state_db/bench/helper.go +++ b/sei-db/state_db/bench/helper.go @@ -264,7 +264,12 @@ func runBenchmark(b *testing.B, scenario TestScenario, withProgress bool) { for range b.N { func() { b.StopTimer() - cs := wrappers.NewDBImpl(b, scenario.Backend) + cs, err := wrappers.NewDBImpl(scenario.Backend, b.TempDir()) + defer func() { + err := cs.Close() + require.NoError(b, err) + }() + require.NoError(b, err) require.NotNil(b, cs) changesetChannel := startChangesetGenerator(scenario) @@ -291,7 +296,7 @@ func runBenchmark(b *testing.B, scenario TestScenario, withProgress bool) { progress.Add(len(changeset.Changeset.Pairs)) } } - err := cs.Close() // close to make sure all data got flushed + err = cs.Close() // close to make sure all data got flushed require.NoError(b, err) b.StopTimer() diff --git a/sei-db/state_db/bench/wrappers/db_implementations.go b/sei-db/state_db/bench/wrappers/db_implementations.go index eda99c96ae..b685d7e32a 100644 --- a/sei-db/state_db/bench/wrappers/db_implementations.go +++ b/sei-db/state_db/bench/wrappers/db_implementations.go @@ -1,14 +1,13 @@ package wrappers import ( - "testing" + "fmt" "github.com/sei-protocol/sei-chain/sei-db/common/logger" "github.com/sei-protocol/sei-chain/sei-db/config" "github.com/sei-protocol/sei-chain/sei-db/state_db/sc/composite" "github.com/sei-protocol/sei-chain/sei-db/state_db/sc/flatkv" "github.com/sei-protocol/sei-chain/sei-db/state_db/sc/memiavl" - "github.com/sei-protocol/sei-chain/sei-tendermint/libs/utils/require" ) const EVMStoreName = "evm" @@ -23,85 +22,85 @@ const ( CompositeCosmos DBType = "CompositeCosmos" ) -func newMemIAVLCommitStore(b *testing.B) DBWrapper { - b.Helper() - dir := b.TempDir() +func newMemIAVLCommitStore( + dataDir string, +) (DBWrapper, error) { + cfg := memiavl.DefaultConfig() cfg.AsyncCommitBuffer = 10 cfg.SnapshotInterval = 100 - cs := memiavl.NewCommitStore(dir, logger.NewNopLogger(), cfg) + cs := memiavl.NewCommitStore(dataDir, logger.NewNopLogger(), cfg) cs.Initialize([]string{EVMStoreName}) _, err := cs.LoadVersion(0, false) - require.NoError(b, err) - - b.Cleanup(func() { - _ = cs.Close() - }) + if err != nil { + cs.Close() + return nil, fmt.Errorf("failed to load version: %w", err) + } - return NewMemIAVLWrapper(cs) + return NewMemIAVLWrapper(cs), nil } -func newFlatKVCommitStore(b *testing.B) DBWrapper { - b.Helper() - dir := b.TempDir() +func newFlatKVCommitStore( + dataDir string, +) (DBWrapper, error) { + cfg := flatkv.DefaultConfig() cfg.Fsync = false - cs := flatkv.NewCommitStore(dir, logger.NewNopLogger(), cfg) + cs := flatkv.NewCommitStore(dataDir, logger.NewNopLogger(), cfg) _, err := cs.LoadVersion(0) - require.NoError(b, err) - - b.Cleanup(func() { - _ = cs.Close() - }) + if err != nil { + cs.Close() + return nil, fmt.Errorf("failed to load version: %w", err) + } - return NewFlatKVWrapper(cs) + return NewFlatKVWrapper(cs), nil } -func newCompositeCommitStore(b *testing.B, writeMode config.WriteMode) DBWrapper { - b.Helper() - dir := b.TempDir() +func newCompositeCommitStore( + dataDir string, + writeMode config.WriteMode, +) (DBWrapper, error) { + cfg := config.DefaultStateCommitConfig() cfg.WriteMode = writeMode cfg.MemIAVLConfig.AsyncCommitBuffer = 10 cfg.MemIAVLConfig.SnapshotInterval = 100 - cs := composite.NewCompositeCommitStore(dir, logger.NewNopLogger(), cfg) + cs := composite.NewCompositeCommitStore(dataDir, logger.NewNopLogger(), cfg) cs.Initialize([]string{EVMStoreName}) loaded, err := cs.LoadVersion(0, false) - require.NoError(b, err) + if err != nil { + cs.Close() + return nil, fmt.Errorf("failed to load version: %w", err) + } loadedStore := loaded.(*composite.CompositeCommitStore) - b.Cleanup(func() { - _ = loadedStore.Close() - }) - - return NewCompositeWrapper(loadedStore) + return NewCompositeWrapper(loadedStore), nil } // Instantiates a new DBWrapper based on the given DBType. func NewDBImpl( - b *testing.B, dbType DBType, -) DBWrapper { + dataDir string, +) (DBWrapper, error) { switch dbType { case MemIAVL: - return newMemIAVLCommitStore(b) + return newMemIAVLCommitStore(dataDir) case FlatKV: - return newFlatKVCommitStore(b) + return newFlatKVCommitStore(dataDir) case CompositeDual: - return newCompositeCommitStore(b, config.DualWrite) + return newCompositeCommitStore(dataDir, config.DualWrite) case CompositeSplit: - return newCompositeCommitStore(b, config.SplitWrite) + return newCompositeCommitStore(dataDir, config.SplitWrite) case CompositeCosmos: - return newCompositeCommitStore(b, config.CosmosOnlyWrite) + return newCompositeCommitStore(dataDir, config.CosmosOnlyWrite) default: - b.Fatalf("unsupported DB type: %s", dbType) - return nil + return nil, fmt.Errorf("unsupported DB type: %s", dbType) } } diff --git a/sei-db/state_db/bench/wrappers/db_wrapper.go b/sei-db/state_db/bench/wrappers/db_wrapper.go index 7695753b39..59161cce83 100644 --- a/sei-db/state_db/bench/wrappers/db_wrapper.go +++ b/sei-db/state_db/bench/wrappers/db_wrapper.go @@ -8,6 +8,9 @@ type DBWrapper interface { // Non-EVM modules are ignored. Call Commit to persist. ApplyChangeSets(cs []*proto.NamedChangeSet) error + // Read reads the value for the given key. + Read(key []byte) (data []byte, found bool, err error) + // Commit persists buffered writes and advances the version. Commit() (int64, error) diff --git a/sei-db/state_db/bench/wrappers/flatkv_wrapper.go b/sei-db/state_db/bench/wrappers/flatkv_wrapper.go index 115806bb2d..1437a2ee41 100644 --- a/sei-db/state_db/bench/wrappers/flatkv_wrapper.go +++ b/sei-db/state_db/bench/wrappers/flatkv_wrapper.go @@ -48,3 +48,8 @@ func (f *flatKVWrapper) Version() int64 { func (f *flatKVWrapper) Close() error { return f.base.Close() } + +func (f *flatKVWrapper) Read(key []byte) (data []byte, found bool, err error) { + data, found = f.base.Get(key) + return data, found, nil +} diff --git a/sei-db/state_db/bench/wrappers/memiavl_wrapper.go b/sei-db/state_db/bench/wrappers/memiavl_wrapper.go index 38f560a13c..7c029a7e0c 100644 --- a/sei-db/state_db/bench/wrappers/memiavl_wrapper.go +++ b/sei-db/state_db/bench/wrappers/memiavl_wrapper.go @@ -34,3 +34,7 @@ func (m *memIAVLWrapper) ApplyChangeSets(cs []*proto.NamedChangeSet) error { func (m *memIAVLWrapper) Close() error { return m.base.Close() } + +func (m *memIAVLWrapper) Read(key []byte) (data []byte, found bool, err error) { + // TODO: Implement this. +} From dec45bffc04c03ed7d31b912606b83e48ad3dc30 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Tue, 24 Feb 2026 10:35:00 -0600 Subject: [PATCH 05/49] incremental progress --- .gitignore | 3 + .../bench/cryptosim/config/basic-config.json | 4 + sei-db/state_db/bench/cryptosim/cryptosim.go | 116 +++++++++++++++++- .../bench/cryptosim/cryptosim_config.go | 67 +++++++--- sei-db/state_db/bench/cryptosim/main/main.go | 38 +++++- .../state_db/bench/cryptosim/random_buffer.go | 2 +- sei-db/state_db/bench/cryptosim/run.sh | 2 +- sei-db/state_db/bench/cryptosim/util.go | 6 +- .../bench/wrappers/composite_wrapper.go | 9 ++ .../bench/wrappers/memiavl_wrapper.go | 7 +- 10 files changed, 225 insertions(+), 29 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/config/basic-config.json diff --git a/.gitignore b/.gitignore index d3f4ccb98f..3684e41239 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,6 @@ contracts/artifacts # Integration tests build artifacts integration_test/dapp_tests/artifacts + +# DB benchmark data +sei-db/state_db/bench/cryptosim/data/** \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json new file mode 100644 index 0000000000..9bc5de4f15 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -0,0 +1,4 @@ +{ + "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", + "DataDir": "data/basic" +} \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 17d2f30e63..4e03a8defb 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -2,15 +2,16 @@ package cryptosim import ( "context" + "encoding/binary" "fmt" "github.com/sei-protocol/sei-chain/sei-db/common/evm" + "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) const ( - // Used to store the seed used for the current run. - seedKey = string(evm.EVMKeyNonce) + "seed" // Used to store the next account ID to be used when creating a new account. nonceKey = string(evm.EVMKeyNonce) + "nonce" ) @@ -27,6 +28,12 @@ type CryptoSim struct { // The source of randomness for the benchmark. rand *RandomBuffer + + // The next account ID to be used when creating a new account. + nextAccountID int64 + + // The current batch of changesets waiting to be committed. + batch []*proto.NamedChangeSet } // Creates a new cryptosim benchmark runner. @@ -35,31 +42,130 @@ func NewCryptoSim( config *CryptoSimConfig, ) (*CryptoSim, error) { + if config.DataDir == "" { + return nil, fmt.Errorf("data directory is required") + } + dataDir, err := resolveAndCreateDataDir(config.DataDir) if err != nil { return nil, err } + fmt.Printf("Running cryptosim benchmark from data directory: %s\n", dataDir) + db, err := wrappers.NewDBImpl(config.Backend, dataDir) if err != nil { return nil, fmt.Errorf("failed to create database: %w", err) } + fmt.Printf("Initializing random buffer\n") + rand := NewRandomBuffer(config.RandomBufferSize, config.Seed) + c := &CryptoSim{ ctx: ctx, config: config, db: db, + rand: rand, + batch: make([]*proto.NamedChangeSet, 0, config.TransactionsPerBlock), + } + + err = c.setup() + if err != nil { + return nil, fmt.Errorf("failed to setup benchmark: %w", err) } - c.setup() c.start() return c, nil } -func (c *CryptoSim) setup() { - // TODO +func (c *CryptoSim) setup() error { + + // Ensure that we at least have as many accounts as the hot set + 1. This simplifies logic elsewhere. + if c.config.MinimumNumberOfAccounts < c.config.HotSetSize+1 { + c.config.MinimumNumberOfAccounts = c.config.HotSetSize + 1 + } + + nextAccountID, found, err := c.db.Read([]byte(nonceKey)) + if err != nil { + return fmt.Errorf("failed to read nonce: %w", err) + } + if found { + c.nextAccountID = int64(binary.BigEndian.Uint64(nextAccountID)) + } + + fmt.Printf("There are currently %d keys in the database.\n", c.nextAccountID) + + if c.nextAccountID >= int64(c.config.MinimumNumberOfAccounts) { + return nil + } + + fmt.Printf("Benchmark is configured to run with a minimum of %d accounts. Creating %d new accounts.\n", + c.config.MinimumNumberOfAccounts, int64(c.config.MinimumNumberOfAccounts)-c.nextAccountID) + + for c.nextAccountID < int64(c.config.MinimumNumberOfAccounts) { + err := c.createNewAccount() + if err != nil { + return fmt.Errorf("failed to create new account: %w", err) + } + } + c.commitBatch() + + return nil } func (c *CryptoSim) start() { // TODO } + +// Creates a new account and writes it to the database. +func (c *CryptoSim) createNewAccount() error { + + accountID := c.nextAccountID + c.nextAccountID++ + + address := c.rand.Address(nonceKey, c.config.AccountKeySize, accountID) + balance := c.rand.Int64() + + accountData := make([]byte, c.config.PaddedAccountSize) + + // The first 8 bytes of the account data are the balance. For the sake of simplicity, + // For the sake of simplicity, we allow negative balances and don't care about overflow. + binary.BigEndian.PutUint64(accountData[:8], uint64(balance)) + + // The remaining bytes are random data for padding. + randomBytes := c.rand.Bytes(c.config.PaddedAccountSize - 8) + copy(accountData[8:], randomBytes) + + cs := &proto.NamedChangeSet{ + Name: wrappers.EVMStoreName, + Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ + {Key: address, Value: accountData}, + }}, + } + c.batch = append(c.batch, cs) + + c.maybeCommitBatch() + + return nil +} + +// Commit the current batch if it has reached the configured number of transactions. +func (c *CryptoSim) maybeCommitBatch() error { + if len(c.batch) >= c.config.TransactionsPerBlock { + return c.commitBatch() + } + return nil +} + +// Commit the current batch. +func (c *CryptoSim) commitBatch() error { + if len(c.batch) == 0 { + return nil + } + err := c.db.ApplyChangeSets(c.batch) + if err != nil { + return fmt.Errorf("failed to apply change sets: %w", err) + } + c.batch = make([]*proto.NamedChangeSet, 0, c.config.TransactionsPerBlock) + return nil +} diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index 1d0e52f801..58cb976d15 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -1,6 +1,12 @@ package cryptosim -import "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" +import ( + "encoding/json" + "fmt" + "os" + + "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" +) // Defines the configuration for the cryptosim benchmark. type CryptoSimConfig struct { @@ -8,7 +14,7 @@ type CryptoSimConfig struct { // The minimum number of accounts that should be in the DB prior to the start of the benchmark. // If there are fewer than this number of accounts, the benchmark will first create the necessary // accounts before starting its regular operations. - MinimumAccountNumber int + MinimumNumberOfAccounts int // When selecting an account for a transaction, the benchmark will select a hot account with this // weight. The actual probability depends on the ratio of this weight to the other account weight configurations. @@ -37,31 +43,58 @@ type CryptoSimConfig struct { // The number of transactions that will be processed in each "block". TransactionsPerBlock int - // The directory to store the benchmark data. If unspecified, the benchmark will use a temporary directory - // that is destroyed after the benchmark completes. + // The directory to store the benchmark data. DataDir string - // The seed to use for the random number generator. If starting from a state on disk, this seed is ignored - // (the benchmark DB saves its own seed internally). + // The seed to use for the random number generator. Altering this seed for a pre-existing DB will result + // in undefined behavior, don't change the seed unless you are starting a new run from scratch. Seed int64 + // The size of the buffer for random data. Similar to the seed, altering this size for a pre-existing DB will result + // in undefined behavior, don't change the size unless you are starting a new run from scratch. + RandomBufferSize int + // The backend to use for the benchmark database. Backend wrappers.DBType + + // This field is ignored, but allows for a comment to be added to the config file. + // Something, something, why in the name of all things holy doesn't json support comments? + Comment string } // Returns the default configuration for the cryptosim benchmark. func DefaultCryptoSimConfig() *CryptoSimConfig { return &CryptoSimConfig{ - MinimumAccountNumber: 1000, - HotAccountWeight: 50, - ColdAccountWeight: 49, - NewAccountWeight: 1, - HotSetSize: 100, - AccountKeySize: 20, - PaddedAccountSize: 100, - TransactionsPerBlock: 100, - DataDir: "", - Seed: 0, - Backend: wrappers.FlatKV, + MinimumNumberOfAccounts: 1000, + HotAccountWeight: 50, + ColdAccountWeight: 49, + NewAccountWeight: 1, + HotSetSize: 100, + AccountKeySize: 20, + PaddedAccountSize: 100, + TransactionsPerBlock: 100, + DataDir: "", + Seed: 1337, + RandomBufferSize: 1024 * 1024 * 1024, // 1GB + Backend: wrappers.FlatKV, + } +} + +// LoadConfigFromFile parses a JSON config file at the given path. +// Returns defaults with file values overlaid. Fails if the file contains +// unrecognized configuration keys. +func LoadConfigFromFile(path string) (*CryptoSimConfig, error) { + cfg := DefaultCryptoSimConfig() + f, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("open config file: %w", err) + } + defer f.Close() + + dec := json.NewDecoder(f) + dec.DisallowUnknownFields() + if err := dec.Decode(cfg); err != nil { + return nil, fmt.Errorf("decode config: %w", err) } + return cfg, nil } diff --git a/sei-db/state_db/bench/cryptosim/main/main.go b/sei-db/state_db/bench/cryptosim/main/main.go index b4cb7850e5..ab90c428df 100644 --- a/sei-db/state_db/bench/cryptosim/main/main.go +++ b/sei-db/state_db/bench/cryptosim/main/main.go @@ -1,10 +1,42 @@ package main -import "fmt" +import ( + "context" + "fmt" + "os" + "os/signal" + + "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/cryptosim" +) // Run the cryptosim benchmark. func main() { - // TODO + err := run() + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } +} + +func run() error { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) + os.Exit(1) + } + config, err := cryptosim.LoadConfigFromFile(os.Args[1]) + if err != nil { + return err + } + + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + defer stop() + + _, err = cryptosim.NewCryptoSim(ctx, config) + if err != nil { + return fmt.Errorf("failed to create cryptosim: %w", err) + } + + <-ctx.Done() - fmt.Println("Hello, world!") + return nil } diff --git a/sei-db/state_db/bench/cryptosim/random_buffer.go b/sei-db/state_db/bench/cryptosim/random_buffer.go index 32acb4208a..583fcb352c 100644 --- a/sei-db/state_db/bench/cryptosim/random_buffer.go +++ b/sei-db/state_db/bench/cryptosim/random_buffer.go @@ -100,7 +100,7 @@ func (rb *RandomBuffer) Int64() int64 { // the address will be deterministic, and any two unique account IDs are guaranteed to generate unique addresses. func (rb *RandomBuffer) Address( // The prefix to use for the address. - keyPrefix []byte, + keyPrefix string, // The size of the address to generate, not including the key prefix. addressSize int, // The account ID to use for the address. diff --git a/sei-db/state_db/bench/cryptosim/run.sh b/sei-db/state_db/bench/cryptosim/run.sh index 1833e95bf2..d546114644 100755 --- a/sei-db/state_db/bench/cryptosim/run.sh +++ b/sei-db/state_db/bench/cryptosim/run.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash # Run the cryptosim benchmark. -go run main/main.go \ No newline at end of file +go run main/main.go $@ \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go index a639864006..6674ad7a1b 100644 --- a/sei-db/state_db/bench/cryptosim/util.go +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -61,5 +61,9 @@ func resolveAndCreateDataDir(dataDir string) (string, error) { return "", fmt.Errorf("failed to create data directory: %w", err) } } - return dataDir, nil + abs, err := filepath.Abs(dataDir) + if err != nil { + return "", fmt.Errorf("failed to resolve absolute path: %w", err) + } + return abs, nil } diff --git a/sei-db/state_db/bench/wrappers/composite_wrapper.go b/sei-db/state_db/bench/wrappers/composite_wrapper.go index e849b12d5b..e8002df5d8 100644 --- a/sei-db/state_db/bench/wrappers/composite_wrapper.go +++ b/sei-db/state_db/bench/wrappers/composite_wrapper.go @@ -34,3 +34,12 @@ func (c *compositeWrapper) Version() int64 { func (c *compositeWrapper) Close() error { return c.base.Close() } + +func (c *compositeWrapper) Read(key []byte) (data []byte, found bool, err error) { + store := c.base.GetChildStoreByName(EVMStoreName) + if store == nil { + return nil, false, nil + } + data = store.Get(key) + return data, data != nil, nil +} diff --git a/sei-db/state_db/bench/wrappers/memiavl_wrapper.go b/sei-db/state_db/bench/wrappers/memiavl_wrapper.go index 7c029a7e0c..6ad7cfef84 100644 --- a/sei-db/state_db/bench/wrappers/memiavl_wrapper.go +++ b/sei-db/state_db/bench/wrappers/memiavl_wrapper.go @@ -36,5 +36,10 @@ func (m *memIAVLWrapper) Close() error { } func (m *memIAVLWrapper) Read(key []byte) (data []byte, found bool, err error) { - // TODO: Implement this. + store := m.base.GetChildStoreByName(EVMStoreName) + if store == nil { + return nil, false, nil + } + data = store.Get(key) + return data, data != nil, nil } From 0f253ecfe709d2527f41b34abffd958345c4569b Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Tue, 24 Feb 2026 11:03:42 -0600 Subject: [PATCH 06/49] incremental progress --- .../bench/cryptosim/config/basic-config.json | 3 +- sei-db/state_db/bench/cryptosim/cryptosim.go | 91 ++++++++++++++++--- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index 9bc5de4f15..db3d3b025e 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -1,4 +1,5 @@ { "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", - "DataDir": "data/basic" + "DataDir": "data/basic", + "MinimumNumberOfAccounts": 1000000 } \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 4e03a8defb..a540db0b75 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -33,7 +33,7 @@ type CryptoSim struct { nextAccountID int64 // The current batch of changesets waiting to be committed. - batch []*proto.NamedChangeSet + batch map[string]*proto.NamedChangeSet } // Creates a new cryptosim benchmark runner. @@ -66,7 +66,7 @@ func NewCryptoSim( config: config, db: db, rand: rand, - batch: make([]*proto.NamedChangeSet, 0, config.TransactionsPerBlock), + batch: make(map[string]*proto.NamedChangeSet, config.TransactionsPerBlock), } err = c.setup() @@ -107,8 +107,21 @@ func (c *CryptoSim) setup() error { if err != nil { return fmt.Errorf("failed to create new account: %w", err) } + err = c.maybeCommitBatch() + if err != nil { + return fmt.Errorf("failed to maybe commit batch: %w", err) + } + } + err = c.commitBatch() + if err != nil { + return fmt.Errorf("failed to commit batch: %w", err) + } + _, err = c.db.Commit() + if err != nil { + return fmt.Errorf("failed to commit database: %w", err) } - c.commitBatch() + + fmt.Printf("There are now %d accounts in the database.\n", c.nextAccountID) return nil } @@ -136,15 +149,10 @@ func (c *CryptoSim) createNewAccount() error { randomBytes := c.rand.Bytes(c.config.PaddedAccountSize - 8) copy(accountData[8:], randomBytes) - cs := &proto.NamedChangeSet{ - Name: wrappers.EVMStoreName, - Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ - {Key: address, Value: accountData}, - }}, + err := c.put(address, accountData) + if err != nil { + return fmt.Errorf("failed to put account: %w", err) } - c.batch = append(c.batch, cs) - - c.maybeCommitBatch() return nil } @@ -162,10 +170,67 @@ func (c *CryptoSim) commitBatch() error { if len(c.batch) == 0 { return nil } - err := c.db.ApplyChangeSets(c.batch) + + changeSets := make([]*proto.NamedChangeSet, 0, len(c.batch)+1) + for _, cs := range c.batch { + changeSets = append(changeSets, cs) + } + + // Within each batch, be sure to include the nonce key. + nonceKey := []byte(nonceKey) + nonceValue := make([]byte, 8) + binary.BigEndian.PutUint64(nonceValue, uint64(c.nextAccountID)) + changeSets = append(changeSets, &proto.NamedChangeSet{ + Name: wrappers.EVMStoreName, + Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ + {Key: nonceKey, Value: nonceValue}, + }}, + }) + + err := c.db.ApplyChangeSets(changeSets) if err != nil { return fmt.Errorf("failed to apply change sets: %w", err) } - c.batch = make([]*proto.NamedChangeSet, 0, c.config.TransactionsPerBlock) + c.batch = make(map[string]*proto.NamedChangeSet) return nil } + +// Insert a key-value pair into the database/cache. +func (c *CryptoSim) put(key []byte, value []byte) error { + stringKey := string(key) + + pending, found := c.batch[stringKey] + if found { + pending.Changeset.Pairs[0].Value = value + return nil + } + + c.batch[stringKey] = &proto.NamedChangeSet{ + Name: wrappers.EVMStoreName, + Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ + {Key: key, Value: value}, + }}, + } + + return nil +} + +// Retrieve a value from the database/cache. +func (c *CryptoSim) get(key []byte) ([]byte, bool, error) { + stringKey := string(key) + + pending, found := c.batch[stringKey] + if found { + return pending.Changeset.Pairs[0].Value, true, nil + } + + value, found, err := c.db.Read(key) + if err != nil { + return nil, false, fmt.Errorf("failed to read from database: %w", err) + } + if found { + return value, true, nil + } + + return nil, false, nil +} From 926f8284badd6c9874fd84db8b302f6dc7c800c3 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Tue, 24 Feb 2026 11:24:28 -0600 Subject: [PATCH 07/49] startup now working --- sei-db/state_db/bench/cryptosim/cryptosim.go | 71 +++++++++++++------ sei-db/state_db/bench/cryptosim/main/main.go | 8 ++- .../state_db/bench/cryptosim/random_buffer.go | 25 ++----- 3 files changed, 63 insertions(+), 41 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index a540db0b75..9b5959518c 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -11,11 +11,6 @@ import ( iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) -const ( - // Used to store the next account ID to be used when creating a new account. - nonceKey = string(evm.EVMKeyNonce) + "nonce" -) - // The test runner for the cryptosim benchmark. type CryptoSim struct { ctx context.Context @@ -34,6 +29,10 @@ type CryptoSim struct { // The current batch of changesets waiting to be committed. batch map[string]*proto.NamedChangeSet + + // Memiavl nonce key for the account ID counter (0x0a + reserved 20-byte addr). + // Uses non-zero sentinel address to avoid potential edge cases with all-zero key. + accountIDCounterKey []byte } // Creates a new cryptosim benchmark runner. @@ -61,12 +60,18 @@ func NewCryptoSim( fmt.Printf("Initializing random buffer\n") rand := NewRandomBuffer(config.RandomBufferSize, config.Seed) + // Reserved address for counter: 20 bytes of 0x01 (avoids all-zero key edge cases). + reservedAddr := make([]byte, 20) + for i := range reservedAddr { + reservedAddr[i] = 0x01 + } c := &CryptoSim{ - ctx: ctx, - config: config, - db: db, - rand: rand, - batch: make(map[string]*proto.NamedChangeSet, config.TransactionsPerBlock), + ctx: ctx, + config: config, + db: db, + rand: rand, + batch: make(map[string]*proto.NamedChangeSet, config.TransactionsPerBlock), + accountIDCounterKey: evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, reservedAddr), } err = c.setup() @@ -85,9 +90,9 @@ func (c *CryptoSim) setup() error { c.config.MinimumNumberOfAccounts = c.config.HotSetSize + 1 } - nextAccountID, found, err := c.db.Read([]byte(nonceKey)) + nextAccountID, found, err := c.db.Read(c.accountIDCounterKey) if err != nil { - return fmt.Errorf("failed to read nonce: %w", err) + return fmt.Errorf("failed to read account counter: %w", err) } if found { c.nextAccountID = int64(binary.BigEndian.Uint64(nextAccountID)) @@ -112,12 +117,10 @@ func (c *CryptoSim) setup() error { return fmt.Errorf("failed to maybe commit batch: %w", err) } } - err = c.commitBatch() - if err != nil { + if err := c.commitBatch(); err != nil { return fmt.Errorf("failed to commit batch: %w", err) } - _, err = c.db.Commit() - if err != nil { + if _, err := c.db.Commit(); err != nil { return fmt.Errorf("failed to commit database: %w", err) } @@ -136,7 +139,9 @@ func (c *CryptoSim) createNewAccount() error { accountID := c.nextAccountID c.nextAccountID++ - address := c.rand.Address(nonceKey, c.config.AccountKeySize, accountID) + // Use memiavl code key format (0x07 + addr) so FlatKV persists account data. + addr := c.rand.Address(c.config.AccountKeySize, accountID) + address := evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr) balance := c.rand.Int64() accountData := make([]byte, c.config.PaddedAccountSize) @@ -175,15 +180,13 @@ func (c *CryptoSim) commitBatch() error { for _, cs := range c.batch { changeSets = append(changeSets, cs) } - - // Within each batch, be sure to include the nonce key. - nonceKey := []byte(nonceKey) + // Persist the account ID counter in every batch. nonceValue := make([]byte, 8) binary.BigEndian.PutUint64(nonceValue, uint64(c.nextAccountID)) changeSets = append(changeSets, &proto.NamedChangeSet{ Name: wrappers.EVMStoreName, Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ - {Key: nonceKey, Value: nonceValue}, + {Key: c.accountIDCounterKey, Value: nonceValue}, }}, }) @@ -234,3 +237,29 @@ func (c *CryptoSim) get(key []byte) ([]byte, bool, error) { return nil, false, nil } + +// Shut down the benchmark and release any resources. +func (c *CryptoSim) Close() error { + + fmt.Printf("Committing final batch...\n") + + if err := c.commitBatch(); err != nil { + return fmt.Errorf("failed to commit batch: %w", err) + } + if _, err := c.db.Commit(); err != nil { + return fmt.Errorf("failed to commit database: %w", err) + } + + fmt.Printf("Closing database...\n") + err := c.db.Close() + if err != nil { + return fmt.Errorf("failed to close database: %w", err) + } + + fmt.Printf("benchmark terminated successfully\n") + + // Specifically release rand, since it's likely to hold a lot of memory. + c.rand = nil + + return nil +} diff --git a/sei-db/state_db/bench/cryptosim/main/main.go b/sei-db/state_db/bench/cryptosim/main/main.go index ab90c428df..2c1a8ceb50 100644 --- a/sei-db/state_db/bench/cryptosim/main/main.go +++ b/sei-db/state_db/bench/cryptosim/main/main.go @@ -31,10 +31,16 @@ func run() error { ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) defer stop() - _, err = cryptosim.NewCryptoSim(ctx, config) + cs, err := cryptosim.NewCryptoSim(ctx, config) if err != nil { return fmt.Errorf("failed to create cryptosim: %w", err) } + defer func() { + err := cs.Close() + if err != nil { + fmt.Fprintf(os.Stderr, "Error closing cryptosim: %v\n", err) + } + }() <-ctx.Done() diff --git a/sei-db/state_db/bench/cryptosim/random_buffer.go b/sei-db/state_db/bench/cryptosim/random_buffer.go index 583fcb352c..789b610e92 100644 --- a/sei-db/state_db/bench/cryptosim/random_buffer.go +++ b/sei-db/state_db/bench/cryptosim/random_buffer.go @@ -98,32 +98,19 @@ func (rb *RandomBuffer) Int64() int64 { // Generate a random address suitable for use simulating an eth-style address. Given the same account ID, // the address will be deterministic, and any two unique account IDs are guaranteed to generate unique addresses. -func (rb *RandomBuffer) Address( - // The prefix to use for the address. - keyPrefix string, - // The size of the address to generate, not including the key prefix. - addressSize int, - // The account ID to use for the address. - accountID int64, -) []byte { - +func (rb *RandomBuffer) Address(addressSize int, accountID int64) []byte { if addressSize < 8 { panic(fmt.Sprintf("address size must be at least 8 bytes, got %d", addressSize)) } - result := make([]byte, len(keyPrefix)+addressSize) - address := result[len(keyPrefix):] - copy(result, keyPrefix) - + result := make([]byte, addressSize) baseBytes := rb.SeededBytes(addressSize, accountID) - // Inject the account ID into the middle of the address span (excluding the prefix) to ensure uniqueness. - accountIDIndex := len(keyPrefix) + (addressSize / 2) - if accountIDIndex+8 > len(result) { - accountIDIndex = len(result) - 8 + accountIDIndex := addressSize / 2 + if accountIDIndex+8 > addressSize { + accountIDIndex = addressSize - 8 } - - copy(address, baseBytes) + copy(result, baseBytes) binary.BigEndian.PutUint64(result[accountIDIndex:accountIDIndex+8], uint64(accountID)) return result From 61b4e86b3b1395209d873ffc478d740153de0c9c Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Tue, 24 Feb 2026 12:11:45 -0600 Subject: [PATCH 08/49] incremental progress, code written for simulating transactions --- .../{random_buffer.go => canned_random.go} | 66 ++++-- sei-db/state_db/bench/cryptosim/cryptosim.go | 201 ++++++++++++++++-- .../bench/cryptosim/cryptosim_config.go | 51 ++--- 3 files changed, 256 insertions(+), 62 deletions(-) rename sei-db/state_db/bench/cryptosim/{random_buffer.go => canned_random.go} (65%) diff --git a/sei-db/state_db/bench/cryptosim/random_buffer.go b/sei-db/state_db/bench/cryptosim/canned_random.go similarity index 65% rename from sei-db/state_db/bench/cryptosim/random_buffer.go rename to sei-db/state_db/bench/cryptosim/canned_random.go index 789b610e92..771b344a2b 100644 --- a/sei-db/state_db/bench/cryptosim/random_buffer.go +++ b/sei-db/state_db/bench/cryptosim/canned_random.go @@ -3,10 +3,11 @@ package cryptosim import ( "encoding/binary" "fmt" + "math" "math/rand" ) -// A utility that buffers randomness in a way that is highly performant for benchmarking. +// CannedRandom provides pre-generated randomness for benchmarking. // It contains a buffer of random bytes that it reuses to avoid generating lots of random numbers // at runtime. // @@ -16,7 +17,7 @@ import ( // This utility is not thread safe. // // In case it requires saying, this utility is NOT a suitable source cryptographically secure random numbers. -type RandomBuffer struct { +type CannedRandom struct { // Pre-generated buffer of random bytes. buffer []byte @@ -24,8 +25,8 @@ type RandomBuffer struct { index int64 } -// Creates a new random buffer. -func NewRandomBuffer( +// NewCannedRandom creates a new CannedRandom. +func NewCannedRandom( // The size of the buffer to create. A slice of this size is instantiated, so avoid setting this too large. // Do not set this too small though, as the buffer will panic if the requested number of bytes is greater // than the buffer size. @@ -33,7 +34,7 @@ func NewRandomBuffer( // The seed to use to generate the random bytes. This utility provides deterministic random numbers // given the same seed. seed int64, -) *RandomBuffer { +) *CannedRandom { if bufferSize < 8 { panic(fmt.Sprintf("buffer size must be at least 8 bytes, got %d", bufferSize)) @@ -50,7 +51,7 @@ func NewRandomBuffer( buffer := make([]byte, bufferSize) rng.Read(buffer) - return &RandomBuffer{ + return &CannedRandom{ buffer: buffer, index: 0, } @@ -59,52 +60,75 @@ func NewRandomBuffer( // Returns a slice of random bytes. // // Returned slice is NOT safe to modify. If modification is required, the caller should make a copy of the slice. -func (rb *RandomBuffer) Bytes(count int) []byte { - return rb.SeededBytes(count, rb.Int64()) +func (cr *CannedRandom) Bytes(count int) []byte { + return cr.SeededBytes(count, cr.Int64()) } // Returns a slice of random bytes from a given seed. Bytes are deterministic given the same seed. // // Returned slice is NOT safe to modify. If modification is required, the caller should make a copy of the slice. -func (rb *RandomBuffer) SeededBytes(count int, seed int64) []byte { +func (cr *CannedRandom) SeededBytes(count int, seed int64) []byte { if count < 0 { panic(fmt.Sprintf("count must be non-negative, got %d", count)) } - if count > len(rb.buffer) { + if count > len(cr.buffer) { panic(fmt.Sprintf("count must be less than or equal to the buffer size, got %d", count)) - } else if count == len(rb.buffer) { - return rb.buffer + } else if count == len(cr.buffer) { + return cr.buffer } - startIndex := PositiveHash64(seed) % int64(len(rb.buffer)-count) - return rb.buffer[startIndex : startIndex+int64(count)] + startIndex := PositiveHash64(seed) % int64(len(cr.buffer)-count) + return cr.buffer[startIndex : startIndex+int64(count)] } // Generate a random-ish int64. -func (rb *RandomBuffer) Int64() int64 { - bufLen := int64(len(rb.buffer)) +func (cr *CannedRandom) Int64() int64 { + bufLen := int64(len(cr.buffer)) var buf [8]byte for i := int64(0); i < 8; i++ { - buf[i] = rb.buffer[(rb.index+i)%bufLen] + buf[i] = cr.buffer[(cr.index+i)%bufLen] } base := binary.BigEndian.Uint64(buf[:]) - result := Hash64(int64(base) + rb.index) + result := Hash64(int64(base) + cr.index) // Add 8 to the index to skip the 8 bytes we just read. - rb.index = (rb.index + 8) % bufLen + cr.index = (cr.index + 8) % bufLen return result } +// Int64Range returns a random int64 in [min, max). Min is inclusive, max is exclusive. +// If min == max, returns min. +func (cr *CannedRandom) Int64Range(min int64, max int64) int64 { + if min == max { + return min + } + if max < min { + panic(fmt.Sprintf("max must be >= min, got min=%d max=%d", min, max)) + } + return min + int64(uint64(cr.Int64())%uint64(max-min)) +} + +// Float64 returns a random float64 in the range [0.0, 1.0]. +// It uses Int64() internally and converts the result to the proper range. +func (cr *CannedRandom) Float64() float64 { + return float64(uint64(cr.Int64())) / float64(math.MaxUint64) +} + +// Bool returns a random boolean. +func (cr *CannedRandom) Bool() bool { + return cr.Int64()%2 == 0 +} + // Generate a random address suitable for use simulating an eth-style address. Given the same account ID, // the address will be deterministic, and any two unique account IDs are guaranteed to generate unique addresses. -func (rb *RandomBuffer) Address(addressSize int, accountID int64) []byte { +func (cr *CannedRandom) Address(addressSize int, accountID int64) []byte { if addressSize < 8 { panic(fmt.Sprintf("address size must be at least 8 bytes, got %d", addressSize)) } result := make([]byte, addressSize) - baseBytes := rb.SeededBytes(addressSize, accountID) + baseBytes := cr.SeededBytes(addressSize, accountID) accountIDIndex := addressSize / 2 if accountIDIndex+8 > addressSize { diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 9b5959518c..10fd6f72a4 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -4,6 +4,7 @@ import ( "context" "encoding/binary" "fmt" + "time" "github.com/sei-protocol/sei-chain/sei-db/common/evm" "github.com/sei-protocol/sei-chain/sei-db/proto" @@ -22,17 +23,33 @@ type CryptoSim struct { db wrappers.DBWrapper // The source of randomness for the benchmark. - rand *RandomBuffer + rand *CannedRandom // The next account ID to be used when creating a new account. nextAccountID int64 + // The total number of transactions executed by the benchmark since it last started. + transactionCount int64 + // The current batch of changesets waiting to be committed. batch map[string]*proto.NamedChangeSet // Memiavl nonce key for the account ID counter (0x0a + reserved 20-byte addr). // Uses non-zero sentinel address to avoid potential edge cases with all-zero key. accountIDCounterKey []byte + + // The address of the fee account (i.e. the account that collects gas fees). This is a special account + // and has account ID 0. Since we reuse this account very often, it is cached for performance. + feeCollectionAddress []byte + + // If this much time has passed since the last console update, the benchmark will print a report to the console. + consoleUpdatePeriod time.Duration + + // The time of the last console update. + lastConsoleUpdateTime time.Time + + // The number of transactions executed by the benchmark the last time the console was updated. + lastConsoleUpdateTransactionCount int64 } // Creates a new cryptosim benchmark runner. @@ -57,21 +74,30 @@ func NewCryptoSim( return nil, fmt.Errorf("failed to create database: %w", err) } - fmt.Printf("Initializing random buffer\n") - rand := NewRandomBuffer(config.RandomBufferSize, config.Seed) + fmt.Printf("Initializing canned random\n") + rand := NewCannedRandom(config.CannedRandomSize, config.Seed) + + feeCollectionAddress := evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, rand.Address(config.AccountKeySize, 0)) // Reserved address for counter: 20 bytes of 0x01 (avoids all-zero key edge cases). reservedAddr := make([]byte, 20) for i := range reservedAddr { reservedAddr[i] = 0x01 } + + consoleUpdatePeriod := time.Duration(config.ConsoleUpdateIntervalSeconds * float64(time.Second)) + c := &CryptoSim{ - ctx: ctx, - config: config, - db: db, - rand: rand, - batch: make(map[string]*proto.NamedChangeSet, config.TransactionsPerBlock), - accountIDCounterKey: evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, reservedAddr), + ctx: ctx, + config: config, + db: db, + rand: rand, + batch: make(map[string]*proto.NamedChangeSet, config.TransactionsPerBlock), + accountIDCounterKey: evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, reservedAddr), + feeCollectionAddress: feeCollectionAddress, + consoleUpdatePeriod: consoleUpdatePeriod, + lastConsoleUpdateTime: time.Now(), + lastConsoleUpdateTransactionCount: 0, } err = c.setup() @@ -79,10 +105,11 @@ func NewCryptoSim( return nil, fmt.Errorf("failed to setup benchmark: %w", err) } - c.start() + go c.run() return c, nil } +// Prepare the benchmark by pre-populating the database with the minimum number of accounts. func (c *CryptoSim) setup() error { // Ensure that we at least have as many accounts as the hot set + 1. This simplifies logic elsewhere. @@ -108,7 +135,7 @@ func (c *CryptoSim) setup() error { c.config.MinimumNumberOfAccounts, int64(c.config.MinimumNumberOfAccounts)-c.nextAccountID) for c.nextAccountID < int64(c.config.MinimumNumberOfAccounts) { - err := c.createNewAccount() + _, err := c.createNewAccount() if err != nil { return fmt.Errorf("failed to create new account: %w", err) } @@ -129,12 +156,152 @@ func (c *CryptoSim) setup() error { return nil } -func (c *CryptoSim) start() { - // TODO +// The main loop of the benchmark. +func (c *CryptoSim) run() { + for { + select { + case <-c.ctx.Done(): + return + default: + err := c.executeTransaction() + if err != nil { + fmt.Printf("failed to execute transaction: %v\n", err) + } + c.transactionCount++ + c.generateConsoleReport() + } + } } -// Creates a new account and writes it to the database. -func (c *CryptoSim) createNewAccount() error { +// Perform a single transaction. +func (c *CryptoSim) executeTransaction() error { + + // Determine which accounts will be involved in the transaction. + srcAccount, err := c.randomAccount() + if err != nil { + return fmt.Errorf("failed to select source account: %w", err) + } + dstAccount, err := c.randomAccount() + if err != nil { + return fmt.Errorf("failed to select destination account: %w", err) + } + + // Read the current balances of the accounts. + // TODO we should be able to parrelize these reads, do this as a follow up + srcValue, found, err := c.get(srcAccount) + if err != nil { + return fmt.Errorf("failed to get source account: %w", err) + } + if !found { + // return fmt.Errorf("source account not found") + panic(fmt.Sprintf("source account not found: %s", srcAccount)) // TODO + } + + dstValue, found, err := c.get(dstAccount) + if err != nil { + return fmt.Errorf("failed to get destination account: %w", err) + } + if !found { + return fmt.Errorf("destination account not found") + } + + feeValue, found, err := c.get(c.feeCollectionAddress) + if err != nil { + return fmt.Errorf("failed to get fee collection account: %w", err) + } + if !found { + return fmt.Errorf("fee collection account not found") + } + + // Generate new balances for the accounts. + // The "balance" is simulated as the first 8 bytes of the account data. + // We can just choose a new random balance, since we don't care about the actual balance. + + newSrcBalance := c.rand.Int64() + newDstBalance := c.rand.Int64() + newFeeBalance := c.rand.Int64() + + binary.BigEndian.PutUint64(srcValue[:8], uint64(newSrcBalance)) + binary.BigEndian.PutUint64(dstValue[:8], uint64(newDstBalance)) + binary.BigEndian.PutUint64(feeValue[:8], uint64(newFeeBalance)) + + // Write the new balances to the DB. + err = c.put(srcAccount, srcValue) + if err != nil { + return fmt.Errorf("failed to put source account: %w", err) + } + err = c.put(dstAccount, dstValue) + if err != nil { + return fmt.Errorf("failed to put destination account: %w", err) + } + err = c.put(c.feeCollectionAddress, feeValue) + if err != nil { + return fmt.Errorf("failed to put fee collection account: %w", err) + } + + return nil +} + +// Generates a human readable report of the benchmark's progress. +func (c *CryptoSim) generateConsoleReport() { + + // TODO measuring time each cycle is not efficient + + now := time.Now() + timeSinceLastUpdate := now.Sub(c.lastConsoleUpdateTime) + transactionsSinceLastUpdate := c.transactionCount - c.lastConsoleUpdateTransactionCount + + if timeSinceLastUpdate < c.consoleUpdatePeriod && + transactionsSinceLastUpdate < int64(c.config.ConsoleUpdateIntervalTransactions) { + + // Not yet time to update the console. + return + } + + c.lastConsoleUpdateTime = now + c.lastConsoleUpdateTransactionCount = c.transactionCount + + // Generate the report. + fmt.Printf("%d txns executed in %s (%.2f txns/sec), totall number of accounts: %d\n", + transactionsSinceLastUpdate, + timeSinceLastUpdate, + float64(transactionsSinceLastUpdate)/timeSinceLastUpdate.Seconds(), + c.nextAccountID) +} + +// Select a random account for a transaction. +func (c *CryptoSim) randomAccount() ([]byte, error) { + hot := c.rand.Float64() < c.config.HotAccountProbably + + if hot { + firstHotAccountID := 1 + lastHotAccountID := c.config.HotSetSize + accountID := c.rand.Int64Range(int64(firstHotAccountID), int64(lastHotAccountID+1)) + + fmt.Printf("selected hot account: %d\n", accountID) // TODO + return c.rand.Address(c.config.AccountKeySize, accountID), nil + } else { + + new := c.rand.Float64() < c.config.NewAccountProbably + if new { + fmt.Printf("creating new account, id: %d\n", c.nextAccountID) // TODO + account, err := c.createNewAccount() + if err != nil { + return nil, fmt.Errorf("failed to create new account: %w", err) + } + return account, nil + } + + firstNonHotAccountID := c.config.HotSetSize + 1 + accountID := c.rand.Int64Range(int64(firstNonHotAccountID), int64(c.nextAccountID)) + + fmt.Printf("selected cold account: %d\n", accountID) // TODO + return c.rand.Address(c.config.AccountKeySize, accountID), nil + } +} + +// Creates a new account and writes it to the database. Returns the address of the new account. +func (c *CryptoSim) createNewAccount() ([]byte, error) { accountID := c.nextAccountID c.nextAccountID++ @@ -156,10 +323,10 @@ func (c *CryptoSim) createNewAccount() error { err := c.put(address, accountData) if err != nil { - return fmt.Errorf("failed to put account: %w", err) + return nil, fmt.Errorf("failed to put account: %w", err) } - return nil + return address, nil } // Commit the current batch if it has reached the configured number of transactions. diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index 58cb976d15..ccb31c540f 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -16,17 +16,13 @@ type CryptoSimConfig struct { // accounts before starting its regular operations. MinimumNumberOfAccounts int - // When selecting an account for a transaction, the benchmark will select a hot account with this - // weight. The actual probability depends on the ratio of this weight to the other account weight configurations. - HotAccountWeight float64 + // When selecting an account for a transaction, select a hot account with this probability. Should be + // a value between 0.0 and 1.0. + HotAccountProbably float64 - // When selecting an account for a transaction, the benchmark will select a cold account with this - // weight. The actual probability depends on the ratio of this weight to the other account weight configurations. - ColdAccountWeight float64 - - // When selecting an account for a transaction, the benchmark will create a new account with this - // weight. The actual probability depends on the ratio of this weight to the other account weight configurations. - NewAccountWeight float64 + // When selecting a non-hot account for a transaction, the benchmark will create a new account with this + // probability. Should be a value between 0.0 and 1.0. + NewAccountProbably float64 // The number of hot accounts. // @@ -50,9 +46,9 @@ type CryptoSimConfig struct { // in undefined behavior, don't change the seed unless you are starting a new run from scratch. Seed int64 - // The size of the buffer for random data. Similar to the seed, altering this size for a pre-existing DB will result + // The size of the CannedRandom buffer. Similar to the seed, altering this size for a pre-existing DB will result // in undefined behavior, don't change the size unless you are starting a new run from scratch. - RandomBufferSize int + CannedRandomSize int // The backend to use for the benchmark database. Backend wrappers.DBType @@ -60,23 +56,30 @@ type CryptoSimConfig struct { // This field is ignored, but allows for a comment to be added to the config file. // Something, something, why in the name of all things holy doesn't json support comments? Comment string + + // If this many seconds go by without a console update, the benchmark will print a report to the console. + ConsoleUpdateIntervalSeconds float64 + + // If this many transactions are executed without a console update, the benchmark will print a report to the console. + ConsoleUpdateIntervalTransactions float64 } // Returns the default configuration for the cryptosim benchmark. func DefaultCryptoSimConfig() *CryptoSimConfig { return &CryptoSimConfig{ - MinimumNumberOfAccounts: 1000, - HotAccountWeight: 50, - ColdAccountWeight: 49, - NewAccountWeight: 1, - HotSetSize: 100, - AccountKeySize: 20, - PaddedAccountSize: 100, - TransactionsPerBlock: 100, - DataDir: "", - Seed: 1337, - RandomBufferSize: 1024 * 1024 * 1024, // 1GB - Backend: wrappers.FlatKV, + MinimumNumberOfAccounts: 1000, + HotAccountProbably: 0.5, + NewAccountProbably: 0.001, + HotSetSize: 100, + AccountKeySize: 20, + PaddedAccountSize: 100, + TransactionsPerBlock: 100, + DataDir: "", + Seed: 1337, + CannedRandomSize: 1024 * 1024 * 1024, // 1GB + Backend: wrappers.FlatKV, + ConsoleUpdateIntervalSeconds: 1, + ConsoleUpdateIntervalTransactions: 1_000_000, } } From 96f2c6681240907486b810e82ddc3b7f80b949b5 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Tue, 24 Feb 2026 13:08:22 -0600 Subject: [PATCH 09/49] basic benchmark is now functional --- .../bench/cryptosim/config/basic-config.json | 2 +- sei-db/state_db/bench/cryptosim/cryptosim.go | 117 +++++++++++++----- .../bench/cryptosim/cryptosim_config.go | 14 ++- sei-db/state_db/bench/cryptosim/kill-all.sh | 22 ++++ sei-db/state_db/bench/cryptosim/main/main.go | 1 + sei-db/state_db/bench/cryptosim/util.go | 65 ++++++++++ 6 files changed, 185 insertions(+), 36 deletions(-) create mode 100755 sei-db/state_db/bench/cryptosim/kill-all.sh diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index db3d3b025e..8a00255113 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -1,5 +1,5 @@ { "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", "DataDir": "data/basic", - "MinimumNumberOfAccounts": 1000000 + "MinimumNumberOfAccounts": 10000000 } \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 10fd6f72a4..3afdb1e1f1 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -14,7 +14,8 @@ import ( // The test runner for the cryptosim benchmark. type CryptoSim struct { - ctx context.Context + ctx context.Context + cancel context.CancelFunc // The configuration for the benchmark. config *CryptoSimConfig @@ -31,7 +32,11 @@ type CryptoSim struct { // The total number of transactions executed by the benchmark since it last started. transactionCount int64 - // The current batch of changesets waiting to be committed. + // The number of blocks that have been executed since the last commit. + uncommitedBlockCount int64 + + // The current batch of changesets waiting to be committed. Represents changes we are accumulating + // as part of a simulated "block". batch map[string]*proto.NamedChangeSet // Memiavl nonce key for the account ID counter (0x0a + reserved 20-byte addr). @@ -50,6 +55,12 @@ type CryptoSim struct { // The number of transactions executed by the benchmark the last time the console was updated. lastConsoleUpdateTransactionCount int64 + + // The time the benchmark started. + startTimestamp time.Time + + // The run channel sends a signal on this channel when it has halted. + runHaltedChan chan struct{} } // Creates a new cryptosim benchmark runner. @@ -67,14 +78,14 @@ func NewCryptoSim( return nil, err } - fmt.Printf("Running cryptosim benchmark from data directory: %s\n", dataDir) + fmt.Printf("running cryptosim benchmark from data directory: %s\n", dataDir) db, err := wrappers.NewDBImpl(config.Backend, dataDir) if err != nil { return nil, fmt.Errorf("failed to create database: %w", err) } - fmt.Printf("Initializing canned random\n") + fmt.Printf("initializing random number generator\n") rand := NewCannedRandom(config.CannedRandomSize, config.Seed) feeCollectionAddress := evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, rand.Address(config.AccountKeySize, 0)) @@ -87,8 +98,13 @@ func NewCryptoSim( consoleUpdatePeriod := time.Duration(config.ConsoleUpdateIntervalSeconds * float64(time.Second)) + start := time.Now() + + ctx, cancel := context.WithCancel(ctx) + c := &CryptoSim{ ctx: ctx, + cancel: cancel, config: config, db: db, rand: rand, @@ -96,8 +112,10 @@ func NewCryptoSim( accountIDCounterKey: evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, reservedAddr), feeCollectionAddress: feeCollectionAddress, consoleUpdatePeriod: consoleUpdatePeriod, - lastConsoleUpdateTime: time.Now(), + lastConsoleUpdateTime: start, lastConsoleUpdateTransactionCount: 0, + startTimestamp: start, + runHaltedChan: make(chan struct{}, 1), } err = c.setup() @@ -135,21 +153,34 @@ func (c *CryptoSim) setup() error { c.config.MinimumNumberOfAccounts, int64(c.config.MinimumNumberOfAccounts)-c.nextAccountID) for c.nextAccountID < int64(c.config.MinimumNumberOfAccounts) { + + if c.ctx.Err() != nil { + fmt.Printf("benchmark aborted during account creation\n") + break + } + _, err := c.createNewAccount() if err != nil { return fmt.Errorf("failed to create new account: %w", err) } - err = c.maybeCommitBatch() + err = c.maybeFinalizeBlock() if err != nil { return fmt.Errorf("failed to maybe commit batch: %w", err) } + + if c.nextAccountID%c.config.SetupUpdateIntervalCount == 0 { + fmt.Printf("created %s of %s accounts\r", + int64Commas(c.nextAccountID), int64Commas(int64(c.config.MinimumNumberOfAccounts))) + } } - if err := c.commitBatch(); err != nil { - return fmt.Errorf("failed to commit batch: %w", err) + fmt.Printf("created %d of %d accounts\n", c.nextAccountID, c.config.MinimumNumberOfAccounts) + if err := c.finalizeBlock(); err != nil { + return fmt.Errorf("failed to commit block: %w", err) } if _, err := c.db.Commit(); err != nil { return fmt.Errorf("failed to commit database: %w", err) } + c.uncommitedBlockCount = 0 fmt.Printf("There are now %d accounts in the database.\n", c.nextAccountID) @@ -158,9 +189,18 @@ func (c *CryptoSim) setup() error { // The main loop of the benchmark. func (c *CryptoSim) run() { + + defer func() { + c.runHaltedChan <- struct{}{} + }() + for { select { case <-c.ctx.Done(): + if c.transactionCount > 0 { + c.generateConsoleReport(true) + fmt.Printf("\ntransaction workload halted\n") + } return default: err := c.executeTransaction() @@ -168,7 +208,7 @@ func (c *CryptoSim) run() { fmt.Printf("failed to execute transaction: %v\n", err) } c.transactionCount++ - c.generateConsoleReport() + c.generateConsoleReport(false) } } } @@ -193,8 +233,7 @@ func (c *CryptoSim) executeTransaction() error { return fmt.Errorf("failed to get source account: %w", err) } if !found { - // return fmt.Errorf("source account not found") - panic(fmt.Sprintf("source account not found: %s", srcAccount)) // TODO + return fmt.Errorf("source account not found") } dstValue, found, err := c.get(dstAccount) @@ -243,7 +282,7 @@ func (c *CryptoSim) executeTransaction() error { } // Generates a human readable report of the benchmark's progress. -func (c *CryptoSim) generateConsoleReport() { +func (c *CryptoSim) generateConsoleReport(force bool) { // TODO measuring time each cycle is not efficient @@ -251,7 +290,8 @@ func (c *CryptoSim) generateConsoleReport() { timeSinceLastUpdate := now.Sub(c.lastConsoleUpdateTime) transactionsSinceLastUpdate := c.transactionCount - c.lastConsoleUpdateTransactionCount - if timeSinceLastUpdate < c.consoleUpdatePeriod && + if !force && + timeSinceLastUpdate < c.consoleUpdatePeriod && transactionsSinceLastUpdate < int64(c.config.ConsoleUpdateIntervalTransactions) { // Not yet time to update the console. @@ -261,12 +301,15 @@ func (c *CryptoSim) generateConsoleReport() { c.lastConsoleUpdateTime = now c.lastConsoleUpdateTransactionCount = c.transactionCount + totalElapsedTime := now.Sub(c.startTimestamp) + transactionsPerSecond := float64(c.transactionCount) / totalElapsedTime.Seconds() + // Generate the report. - fmt.Printf("%d txns executed in %s (%.2f txns/sec), totall number of accounts: %d\n", - transactionsSinceLastUpdate, - timeSinceLastUpdate, - float64(transactionsSinceLastUpdate)/timeSinceLastUpdate.Seconds(), - c.nextAccountID) + fmt.Printf("%s txns executed in %v (%s txns/sec), total number of accounts: %s\r", + int64Commas(c.transactionCount), + totalElapsedTime, + formatNumberFloat64(transactionsPerSecond, 2), + int64Commas(c.nextAccountID)) } // Select a random account for a transaction. @@ -277,14 +320,12 @@ func (c *CryptoSim) randomAccount() ([]byte, error) { firstHotAccountID := 1 lastHotAccountID := c.config.HotSetSize accountID := c.rand.Int64Range(int64(firstHotAccountID), int64(lastHotAccountID+1)) - - fmt.Printf("selected hot account: %d\n", accountID) // TODO - return c.rand.Address(c.config.AccountKeySize, accountID), nil + addr := c.rand.Address(c.config.AccountKeySize, accountID) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } else { new := c.rand.Float64() < c.config.NewAccountProbably if new { - fmt.Printf("creating new account, id: %d\n", c.nextAccountID) // TODO account, err := c.createNewAccount() if err != nil { return nil, fmt.Errorf("failed to create new account: %w", err) @@ -294,9 +335,8 @@ func (c *CryptoSim) randomAccount() ([]byte, error) { firstNonHotAccountID := c.config.HotSetSize + 1 accountID := c.rand.Int64Range(int64(firstNonHotAccountID), int64(c.nextAccountID)) - - fmt.Printf("selected cold account: %d\n", accountID) // TODO - return c.rand.Address(c.config.AccountKeySize, accountID), nil + addr := c.rand.Address(c.config.AccountKeySize, accountID) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } } @@ -330,15 +370,15 @@ func (c *CryptoSim) createNewAccount() ([]byte, error) { } // Commit the current batch if it has reached the configured number of transactions. -func (c *CryptoSim) maybeCommitBatch() error { +func (c *CryptoSim) maybeFinalizeBlock() error { if len(c.batch) >= c.config.TransactionsPerBlock { - return c.commitBatch() + return c.finalizeBlock() } return nil } -// Commit the current batch. -func (c *CryptoSim) commitBatch() error { +// Push the current block out to the database. +func (c *CryptoSim) finalizeBlock() error { if len(c.batch) == 0 { return nil } @@ -362,6 +402,17 @@ func (c *CryptoSim) commitBatch() error { return fmt.Errorf("failed to apply change sets: %w", err) } c.batch = make(map[string]*proto.NamedChangeSet) + + // Periodically commit the changes to the database. + c.uncommitedBlockCount++ + if c.uncommitedBlockCount >= int64(c.config.BlocksPerCommit) { + _, err := c.db.Commit() + if err != nil { + return fmt.Errorf("failed to commit: %w", err) + } + c.uncommitedBlockCount = 0 + } + return nil } @@ -407,17 +458,19 @@ func (c *CryptoSim) get(key []byte) ([]byte, bool, error) { // Shut down the benchmark and release any resources. func (c *CryptoSim) Close() error { + c.cancel() + <-c.runHaltedChan - fmt.Printf("Committing final batch...\n") + fmt.Printf("committing final batch\n") - if err := c.commitBatch(); err != nil { + if err := c.finalizeBlock(); err != nil { return fmt.Errorf("failed to commit batch: %w", err) } if _, err := c.db.Commit(); err != nil { return fmt.Errorf("failed to commit database: %w", err) } - fmt.Printf("Closing database...\n") + fmt.Printf("closing database\n") err := c.db.Close() if err != nil { return fmt.Errorf("failed to close database: %w", err) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index ccb31c540f..d9158ec905 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -39,6 +39,9 @@ type CryptoSimConfig struct { // The number of transactions that will be processed in each "block". TransactionsPerBlock int + // Commit is called on the database after this many blocks have been processed. + BlocksPerCommit int + // The directory to store the benchmark data. DataDir string @@ -62,24 +65,29 @@ type CryptoSimConfig struct { // If this many transactions are executed without a console update, the benchmark will print a report to the console. ConsoleUpdateIntervalTransactions float64 + + // When setting up the benchmark, print a console update after adding this many accounts to the DB. + SetupUpdateIntervalCount int64 } // Returns the default configuration for the cryptosim benchmark. func DefaultCryptoSimConfig() *CryptoSimConfig { return &CryptoSimConfig{ - MinimumNumberOfAccounts: 1000, + MinimumNumberOfAccounts: 1_000_000, HotAccountProbably: 0.5, NewAccountProbably: 0.001, HotSetSize: 100, AccountKeySize: 20, - PaddedAccountSize: 100, - TransactionsPerBlock: 100, + PaddedAccountSize: 69, // Not a joke, this is the actual size + TransactionsPerBlock: 1024, + BlocksPerCommit: 32, DataDir: "", Seed: 1337, CannedRandomSize: 1024 * 1024 * 1024, // 1GB Backend: wrappers.FlatKV, ConsoleUpdateIntervalSeconds: 1, ConsoleUpdateIntervalTransactions: 1_000_000, + SetupUpdateIntervalCount: 100_000, } } diff --git a/sei-db/state_db/bench/cryptosim/kill-all.sh b/sei-db/state_db/bench/cryptosim/kill-all.sh new file mode 100755 index 0000000000..47e1823840 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/kill-all.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# Kill all cryptosim benchmark processes. +# Targets: run.sh, go run main/main.go, and the compiled main binary. + +BENCH_PATH="sei-db/state_db/bench/cryptosim" + +pids=$(pgrep -f "$BENCH_PATH" 2>/dev/null || true) +pids="$pids $(pgrep -f 'cryptosim/run\.sh' 2>/dev/null || true)" +pids="$pids $(pgrep -f 'cryptosim.*main/main\.go' 2>/dev/null || true)" + +# Dedupe and kill +killed=0 +for pid in $(echo "$pids" | tr ' ' '\n' | sort -un); do + [ -n "$pid" ] && [ "$pid" -gt 0 ] 2>/dev/null || continue + if kill -9 "$pid" 2>/dev/null; then + echo "Killed PID $pid" + killed=$((killed + 1)) + fi +done + +[ "$killed" -eq 0 ] && echo "No cryptosim benchmark processes found." diff --git a/sei-db/state_db/bench/cryptosim/main/main.go b/sei-db/state_db/bench/cryptosim/main/main.go index 2c1a8ceb50..ca741e9dc3 100644 --- a/sei-db/state_db/bench/cryptosim/main/main.go +++ b/sei-db/state_db/bench/cryptosim/main/main.go @@ -36,6 +36,7 @@ func run() error { return fmt.Errorf("failed to create cryptosim: %w", err) } defer func() { + fmt.Printf("initiating teardown\n") err := cs.Close() if err != nil { fmt.Fprintf(os.Stderr, "Error closing cryptosim: %v\n", err) diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go index 6674ad7a1b..ea762bcadb 100644 --- a/sei-db/state_db/bench/cryptosim/util.go +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -5,6 +5,7 @@ import ( "math" "os" "path/filepath" + "strconv" "strings" ) @@ -67,3 +68,67 @@ func resolveAndCreateDataDir(dataDir string) (string, error) { } return abs, nil } + +// int64Commas formats n with commas as thousands separators (e.g., 1000000 -> "1,000,000"). +func int64Commas(n int64) string { + abs := n + if n < 0 { + abs = -n + } + s := strconv.FormatInt(abs, 10) + if len(s) <= 3 { + if n < 0 { + return "-" + s + } + return s + } + firstGroupLen := len(s) % 3 + if firstGroupLen == 0 { + firstGroupLen = 3 + } + var b strings.Builder + if n < 0 { + b.WriteByte('-') + } + b.WriteString(s[:firstGroupLen]) + for i := firstGroupLen; i < len(s); i += 3 { + b.WriteByte(',') + b.WriteString(s[i : i+3]) + } + return b.String() +} + +// formatNumberFloat64 formats f with commas in the integer part and the given number of decimal places. +// Special values (NaN, Inf) are formatted as strconv.FormatFloat would. +func formatNumberFloat64(f float64, decimals int) string { + switch { + case math.IsNaN(f): + return "NaN" + case math.IsInf(f, 1): + return "+Inf" + case math.IsInf(f, -1): + return "-Inf" + } + format := fmt.Sprintf("%%.%df", decimals) + s := fmt.Sprintf(format, f) + // Handle negative sign - we'll need to format the abs and prepend minus + neg := strings.HasPrefix(s, "-") + if neg { + s = s[1:] + } + parts := strings.SplitN(s, ".", 2) + integerPart, _ := strconv.ParseInt(parts[0], 10, 64) + if neg { + integerPart = -integerPart + } + var b strings.Builder + if neg && integerPart == 0 { + b.WriteString("-") + } + b.WriteString(int64Commas(integerPart)) + if len(parts) == 2 { + b.WriteByte('.') + b.WriteString(parts[1]) + } + return b.String() +} From acd6cb87a80ff7d1337f862e8bab9d19ce7d129a Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Tue, 24 Feb 2026 17:47:24 -0600 Subject: [PATCH 10/49] cleanup --- .../state_db/bench/cryptosim/config/basic-config.json | 2 +- sei-db/state_db/bench/cryptosim/cryptosim.go | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index 8a00255113..a1e838883d 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -1,5 +1,5 @@ { "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", "DataDir": "data/basic", - "MinimumNumberOfAccounts": 10000000 + "MinimumNumberOfAccounts": 100000000 } \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 3afdb1e1f1..c59c3538fc 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -114,7 +114,6 @@ func NewCryptoSim( consoleUpdatePeriod: consoleUpdatePeriod, lastConsoleUpdateTime: start, lastConsoleUpdateTransactionCount: 0, - startTimestamp: start, runHaltedChan: make(chan struct{}, 1), } @@ -123,6 +122,8 @@ func NewCryptoSim( return nil, fmt.Errorf("failed to setup benchmark: %w", err) } + c.startTimestamp = time.Now() + go c.run() return c, nil } @@ -143,14 +144,15 @@ func (c *CryptoSim) setup() error { c.nextAccountID = int64(binary.BigEndian.Uint64(nextAccountID)) } - fmt.Printf("There are currently %d keys in the database.\n", c.nextAccountID) + fmt.Printf("There are currently %s keys in the database.\n", int64Commas(c.nextAccountID)) if c.nextAccountID >= int64(c.config.MinimumNumberOfAccounts) { return nil } - fmt.Printf("Benchmark is configured to run with a minimum of %d accounts. Creating %d new accounts.\n", - c.config.MinimumNumberOfAccounts, int64(c.config.MinimumNumberOfAccounts)-c.nextAccountID) + fmt.Printf("Benchmark is configured to run with a minimum of %s accounts. Creating %s new accounts.\n", + int64Commas(int64(c.config.MinimumNumberOfAccounts)), + int64Commas(int64(c.config.MinimumNumberOfAccounts)-c.nextAccountID)) for c.nextAccountID < int64(c.config.MinimumNumberOfAccounts) { From 7238fa6715c6ab54d5856b195338fe9858a1cedb Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 13:32:56 -0600 Subject: [PATCH 11/49] Update model for more realistic simulation --- .gitignore | 2 +- sei-db/state_db/bench/cryptosim/README.md | 50 ++- .../state_db/bench/cryptosim/canned_random.go | 42 +- .../bench/cryptosim/config/basic-config.json | 5 +- sei-db/state_db/bench/cryptosim/cryptosim.go | 375 +++++++++++++++--- .../bench/cryptosim/cryptosim_config.go | 46 ++- sei-db/state_db/bench/cryptosim/kill-all.sh | 22 - sei-db/state_db/bench/cryptosim/main/main.go | 2 +- sei-db/state_db/bench/cryptosim/run.sh | 2 +- sei-db/state_db/bench/helper.go | 4 +- 10 files changed, 432 insertions(+), 118 deletions(-) delete mode 100755 sei-db/state_db/bench/cryptosim/kill-all.sh diff --git a/.gitignore b/.gitignore index 3684e41239..881a462cc3 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,4 @@ contracts/artifacts integration_test/dapp_tests/artifacts # DB benchmark data -sei-db/state_db/bench/cryptosim/data/** \ No newline at end of file +sei-db/state_db/bench/cryptosim/data/** diff --git a/sei-db/state_db/bench/cryptosim/README.md b/sei-db/state_db/bench/cryptosim/README.md index 8674372df7..f9cfd8af8b 100644 --- a/sei-db/state_db/bench/cryptosim/README.md +++ b/sei-db/state_db/bench/cryptosim/README.md @@ -1,4 +1,52 @@ The `cryptosim` benchmark simulates basic cryptocurrency transfer transactions. It's a benchmark designed to be predictive of DB performance under a heavy crypto transfer load. -TODO expand this doc \ No newline at end of file +# Running Cryptosim + +To run this benchmark, execute the following from within the cryptosim directory: + +``` +./run.sh ./config/basic-config.json +``` + +# Configuring Cryptosim + +You can modify or provide a different config file for this benchmark. Available configuration options and their +defaults are defined in the [cryptosim config struct](./cryptosim_config.go). Fields in the json file should +mirror struct field names exactly. + +# Data Persistence + +The cryptosim benchmark writes database files. If provided with those database files at startup time, the cryptosim +benchmark can continue running with that database. This may be useful when operating on large data sets that require +significant setup time. + +Note that if continuing from an earlier run, you may not alter the `Seed`, `CannedRandomSize`, or +`AccountKeySize` parameters, since keys are deterministically derived from these configuration values. + +# Transaciton Model + +The goal of this benchmark is to generate database load similar to that generated by processing ERC20 transactions. + +Each "transaction" performs the following operations (in no particular order): + +- Randomly select a source and a destination account. For both: + - Performs an account read + write (native balance, nonce, codehash) + - Performs a read + write on a storage slot +- Randomly selects a simulated ERC20 contract and reads it +- Performs a read+write on an account that "collects gas fees" + +# Future Work + +The following features might be useful to add to this benchmark: + +- Metrics collection + - Measurements of size of data on disk vs. keys in the database + - Detailed latency breakdown + - Measurements of variance (e.g. p99 vs. just average) + - Memory utilization + - Raw disk IO utilization + - Compaction overhead + - Metrics exported by the underlying DB +- Prometheus/Grafana dashboards to visualize metrics +- More exotic key access patterns diff --git a/sei-db/state_db/bench/cryptosim/canned_random.go b/sei-db/state_db/bench/cryptosim/canned_random.go index 771b344a2b..e82bd7b48c 100644 --- a/sei-db/state_db/bench/cryptosim/canned_random.go +++ b/sei-db/state_db/bench/cryptosim/canned_random.go @@ -42,7 +42,7 @@ func NewCannedRandom( // Adjust the buffer size so that (bufferSize % 8) == 1. This way when the index wraps around, it won't align // perfectly with the buffer, giving us a longer runway before we repeat the exact same sequence of bytes. - // TODO verify that this logic works as intended. + // The expression maps (bufferSize%8) -> add: 0->1, 1->0, 2->7, 3->6, 4->5, 5->4, 6->3, 7->2. bufferSize += (1 - (bufferSize % 8) + 8) % 8 source := rand.NewSource(seed) @@ -68,7 +68,6 @@ func (cr *CannedRandom) Bytes(count int) []byte { // // Returned slice is NOT safe to modify. If modification is required, the caller should make a copy of the slice. func (cr *CannedRandom) SeededBytes(count int, seed int64) []byte { - if count < 0 { panic(fmt.Sprintf("count must be non-negative, got %d", count)) } @@ -120,22 +119,35 @@ func (cr *CannedRandom) Bool() bool { return cr.Int64()%2 == 0 } -// Generate a random address suitable for use simulating an eth-style address. Given the same account ID, -// the address will be deterministic, and any two unique account IDs are guaranteed to generate unique addresses. -func (cr *CannedRandom) Address(addressSize int, accountID int64) []byte { - if addressSize < 8 { - panic(fmt.Sprintf("address size must be at least 8 bytes, got %d", addressSize)) - } +// Generate a random 20 byte address suitable for use simulating an eth-style address. +// For the same input arguments, a canned random generator with the same seed and size will produce +// deterministic results addresses. +// +// Addresses have the following shape: +// +// 1 byte addressType +// 8 bytes of random data +// 8 bytes containing the ID +// 3 bytes of random data (to bring the total to 20 bytes) +// +// The ID is not included in the begining so that adjacent IDs will not appear close to each other if addresses +// are sorted in lexicographic order. +func (cr *CannedRandom) Address( + // A one-char byte descriptor. Allows for keys for different types of things to have different values + // even if they have the same ID. + addressType uint8, + // A unique ID for the key. + id int64, - result := make([]byte, addressSize) - baseBytes := cr.SeededBytes(addressSize, accountID) +) []byte { - accountIDIndex := addressSize / 2 - if accountIDIndex+8 > addressSize { - accountIDIndex = addressSize - 8 - } + result := make([]byte, 20) + + baseBytes := cr.SeededBytes(20, id) copy(result, baseBytes) - binary.BigEndian.PutUint64(result[accountIDIndex:accountIDIndex+8], uint64(accountID)) + + result[0] = addressType + binary.BigEndian.PutUint64(result[9:], uint64(id)) return result } diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index a1e838883d..f16c1668ed 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -1,5 +1,6 @@ { "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", "DataDir": "data/basic", - "MinimumNumberOfAccounts": 100000000 -} \ No newline at end of file + "MinimumNumberOfAccounts": 100000 +} + diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index c59c3538fc..37e660044b 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -12,6 +12,17 @@ import ( iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) +const ( + // Used to store the next account ID in the database. + accountIdCounterKey = "accountIdCounterKey" + // Used to store the next ERC20 contract ID in the database. + erc20IdCounterKey = "erc20IdCounterKey" + + accountPrefix = 'a' + contractPrefix = 'c' + ethStoragePrefix = 's' +) + // The test runner for the cryptosim benchmark. type CryptoSim struct { ctx context.Context @@ -29,20 +40,25 @@ type CryptoSim struct { // The next account ID to be used when creating a new account. nextAccountID int64 + // Key for the account ID counter in the database. + accountIDCounterKey []byte + + // The next ERC20 contract ID to be used when creating a new ERC20 contract. + nextErc20ContractID int64 + + // Key for the ERC20 contract ID counter in the database. + erc20IDCounterKey []byte + // The total number of transactions executed by the benchmark since it last started. transactionCount int64 // The number of blocks that have been executed since the last commit. - uncommitedBlockCount int64 + uncommittedBlockCount int64 // The current batch of changesets waiting to be committed. Represents changes we are accumulating // as part of a simulated "block". batch map[string]*proto.NamedChangeSet - // Memiavl nonce key for the account ID counter (0x0a + reserved 20-byte addr). - // Uses non-zero sentinel address to avoid potential edge cases with all-zero key. - accountIDCounterKey []byte - // The address of the fee account (i.e. the account that collects gas fees). This is a special account // and has account ID 0. Since we reuse this account very often, it is cached for performance. feeCollectionAddress []byte @@ -63,6 +79,20 @@ type CryptoSim struct { runHaltedChan chan struct{} } +// The keys that a transaction will read and write. +type transactionKeys struct { + // The simualted ERC20 contract that will be interacted with. This value is read. + erc20Contract []byte + // The source account that will be interacted with. This value is read and written. + srcAccount []byte + // The destination account that will be interacted with. This value is read and written. + dstAccount []byte + // The source account's storage slot that will be interacted with. This value is read and written. + srcAccountSlot []byte + // The destination account's storage slot that will be interacted with. This value is read and written. + dstAccountSlot []byte +} + // Creates a new cryptosim benchmark runner. func NewCryptoSim( ctx context.Context, @@ -88,13 +118,18 @@ func NewCryptoSim( fmt.Printf("initializing random number generator\n") rand := NewCannedRandom(config.CannedRandomSize, config.Seed) - feeCollectionAddress := evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, rand.Address(config.AccountKeySize, 0)) + feeCollectionAddress := evm.BuildMemIAVLEVMKey( + evm.EVMKeyCode, + rand.Address(accountPrefix, 0), + ) - // Reserved address for counter: 20 bytes of 0x01 (avoids all-zero key edge cases). - reservedAddr := make([]byte, 20) - for i := range reservedAddr { - reservedAddr[i] = 0x01 - } + accountIdCounterBytes := make([]byte, 20) + copy(accountIdCounterBytes, []byte(accountIdCounterKey)) + accountIDCounterKey := evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, accountIdCounterBytes) + + erc20IdCounterBytes := make([]byte, 20) + copy(erc20IdCounterBytes, []byte(erc20IdCounterKey)) + erc20IDCounterKey := evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, erc20IdCounterBytes) consoleUpdatePeriod := time.Duration(config.ConsoleUpdateIntervalSeconds * float64(time.Second)) @@ -109,7 +144,8 @@ func NewCryptoSim( db: db, rand: rand, batch: make(map[string]*proto.NamedChangeSet, config.TransactionsPerBlock), - accountIDCounterKey: evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, reservedAddr), + accountIDCounterKey: accountIDCounterKey, + erc20IDCounterKey: erc20IDCounterKey, feeCollectionAddress: feeCollectionAddress, consoleUpdatePeriod: consoleUpdatePeriod, lastConsoleUpdateTime: start, @@ -130,10 +166,21 @@ func NewCryptoSim( // Prepare the benchmark by pre-populating the database with the minimum number of accounts. func (c *CryptoSim) setup() error { + err := c.setupAccounts() + if err != nil { + return fmt.Errorf("failed to setup accounts: %w", err) + } + err = c.setupErc20Contracts() + if err != nil { + return fmt.Errorf("failed to setup ERC20 contracts: %w", err) + } + return nil +} - // Ensure that we at least have as many accounts as the hot set + 1. This simplifies logic elsewhere. - if c.config.MinimumNumberOfAccounts < c.config.HotSetSize+1 { - c.config.MinimumNumberOfAccounts = c.config.HotSetSize + 1 +func (c *CryptoSim) setupAccounts() error { + // Ensure that we at least have as many accounts as the hot set + 2. This simplifies logic elsewhere. + if c.config.MinimumNumberOfAccounts < c.config.HotAccountSetSize+2 { + c.config.MinimumNumberOfAccounts = c.config.HotAccountSetSize + 2 } nextAccountID, found, err := c.db.Read(c.accountIDCounterKey) @@ -155,13 +202,12 @@ func (c *CryptoSim) setup() error { int64Commas(int64(c.config.MinimumNumberOfAccounts)-c.nextAccountID)) for c.nextAccountID < int64(c.config.MinimumNumberOfAccounts) { - if c.ctx.Err() != nil { fmt.Printf("benchmark aborted during account creation\n") break } - _, err := c.createNewAccount() + _, _, err := c.createNewAccount() if err != nil { return fmt.Errorf("failed to create new account: %w", err) } @@ -175,20 +221,98 @@ func (c *CryptoSim) setup() error { int64Commas(c.nextAccountID), int64Commas(int64(c.config.MinimumNumberOfAccounts))) } } - fmt.Printf("created %d of %d accounts\n", c.nextAccountID, c.config.MinimumNumberOfAccounts) + if c.nextAccountID >= c.config.SetupUpdateIntervalCount { + fmt.Printf("\n") + } + fmt.Printf("Created %s of %s accounts.\n", + int64Commas(c.nextAccountID), int64Commas(int64(c.config.MinimumNumberOfAccounts))) if err := c.finalizeBlock(); err != nil { return fmt.Errorf("failed to commit block: %w", err) } if _, err := c.db.Commit(); err != nil { return fmt.Errorf("failed to commit database: %w", err) } - c.uncommitedBlockCount = 0 + c.uncommittedBlockCount = 0 fmt.Printf("There are now %d accounts in the database.\n", c.nextAccountID) return nil } +func (c *CryptoSim) setupErc20Contracts() error { + + // Ensure that we at least have as many ERC20 contracts as the hot set + 1. This simplifies logic elsewhere. + if c.config.MinimumNumberOfErc20Contracts < c.config.HotErc20ContractSetSize+1 { + c.config.MinimumNumberOfErc20Contracts = c.config.HotErc20ContractSetSize + 1 + } + + nextErc20ContractID, found, err := c.db.Read(c.erc20IDCounterKey) + if err != nil { + return fmt.Errorf("failed to read ERC20 contract counter: %w", err) + } + if found { + c.nextErc20ContractID = int64(binary.BigEndian.Uint64(nextErc20ContractID)) + } + + fmt.Printf("There are currently %s simulated ERC20 contracts in the database.\n", + int64Commas(c.nextErc20ContractID)) + + if c.nextErc20ContractID >= int64(c.config.MinimumNumberOfErc20Contracts) { + return nil + } + + fmt.Printf("Benchmark is configured to run with a minimum of %s simulated ERC20 contracts. "+ + "Creating %s new ERC20 contracts.\n", + int64Commas(int64(c.config.MinimumNumberOfErc20Contracts)), + int64Commas(int64(c.config.MinimumNumberOfErc20Contracts)-c.nextErc20ContractID)) + + for c.nextErc20ContractID < int64(c.config.MinimumNumberOfErc20Contracts) { + if c.ctx.Err() != nil { + fmt.Printf("benchmark aborted during ERC20 contract creation\n") + break + } + + _, err := c.createNewErc20Contract() + if err != nil { + return fmt.Errorf("failed to create new ERC20 contract: %w", err) + } + err = c.maybeFinalizeBlock() + if err != nil { + return fmt.Errorf("failed to maybe commit batch: %w", err) + } + + if c.nextErc20ContractID%c.config.SetupUpdateIntervalCount == 0 { + fmt.Printf("created %s of %s simulated ERC20 contracts\r", + int64Commas(c.nextErc20ContractID), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) + } + } + + // As a final step, write the ERC20 contract ID counter to the database. + data := make([]byte, 8) + binary.BigEndian.PutUint64(data, uint64(c.nextErc20ContractID)) + err = c.put(c.erc20IDCounterKey, data) + if err != nil { + return fmt.Errorf("failed to put ERC20 contract ID counter: %w", err) + } + + if c.nextErc20ContractID >= c.config.SetupUpdateIntervalCount { + fmt.Printf("\n") + } + fmt.Printf("Created %s of %s simulated ERC20 contracts.\n", + int64Commas(c.nextErc20ContractID), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) + if err := c.finalizeBlock(); err != nil { + return fmt.Errorf("failed to commit block: %w", err) + } + if _, err := c.db.Commit(); err != nil { + return fmt.Errorf("failed to commit database: %w", err) + } + c.uncommittedBlockCount = 0 + + fmt.Printf("There are now %d simulated ERC20 contracts in the database.\n", c.nextErc20ContractID) + + return nil +} + // The main loop of the benchmark. func (c *CryptoSim) run() { @@ -201,7 +325,7 @@ func (c *CryptoSim) run() { case <-c.ctx.Done(): if c.transactionCount > 0 { c.generateConsoleReport(true) - fmt.Printf("\ntransaction workload halted\n") + fmt.Printf("\nTransaction workload halted.\n") } return default: @@ -215,22 +339,66 @@ func (c *CryptoSim) run() { } } +// Selects the keys that a transaction will read and write. +func (c *CryptoSim) selectTransactionKeys() (*transactionKeys, error) { + srcAccountID, srcAccountAddress, err := c.randomAccount() + if err != nil { + return nil, fmt.Errorf("failed to select source account: %w", err) + } + dstAccountID, dstAccountAddress, err := c.randomAccount() + if err != nil { + return nil, fmt.Errorf("failed to select destination account: %w", err) + } + + srcAccountSlot, err := c.randomAccountSlot(srcAccountID) + if err != nil { + return nil, fmt.Errorf("failed to select source account slot: %w", err) + } + dstAccountSlot, err := c.randomAccountSlot(dstAccountID) + if err != nil { + return nil, fmt.Errorf("failed to select destination account slot: %w", err) + } + erc20Contract, err := c.randomErc20Contract() + if err != nil { + return nil, fmt.Errorf("failed to select ERC20 contract: %w", err) + } + + return &transactionKeys{ + srcAccount: srcAccountAddress, + dstAccount: dstAccountAddress, + srcAccountSlot: srcAccountSlot, + dstAccountSlot: dstAccountSlot, + erc20Contract: erc20Contract, + }, nil +} + // Perform a single transaction. func (c *CryptoSim) executeTransaction() error { - // Determine which accounts will be involved in the transaction. - srcAccount, err := c.randomAccount() + // Determine which accounts and ERC20 contract will be involved in the transaction. + keys, err := c.selectTransactionKeys() if err != nil { - return fmt.Errorf("failed to select source account: %w", err) + return fmt.Errorf("failed to select transaction keys: %w", err) } - dstAccount, err := c.randomAccount() + + // Read the simulated ERC20 contract. + _, found, err := c.get(keys.erc20Contract) if err != nil { - return fmt.Errorf("failed to select destination account: %w", err) + return fmt.Errorf("failed to get ERC20 contract: %w", err) } + if !found { + return fmt.Errorf("ERC20 contract not found") + } + + // Read the following: + // - the sender's native balance / nonce / codehash + // - the receiver's native balance + // - the sender's storage slot for the ERC20 contract + // - the receiver's storage slot for the ERC20 contract + // - the fee collection account's native balance - // Read the current balances of the accounts. - // TODO we should be able to parrelize these reads, do this as a follow up - srcValue, found, err := c.get(srcAccount) + // Read the sender's native balance / nonce / codehash. + srcAccountValue, found, err := c.get(keys.srcAccount) if err != nil { return fmt.Errorf("failed to get source account: %w", err) } @@ -238,7 +406,8 @@ func (c *CryptoSim) executeTransaction() error { return fmt.Errorf("source account not found") } - dstValue, found, err := c.get(dstAccount) + // Read the receiver's native balance. + dstAccountValue, found, err := c.get(keys.dstAccount) if err != nil { return fmt.Errorf("failed to get destination account: %w", err) } @@ -246,6 +415,21 @@ func (c *CryptoSim) executeTransaction() error { return fmt.Errorf("destination account not found") } + // Read the sender's storage slot for the ERC20 contract. + // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. + _, _, err = c.get(keys.srcAccountSlot) + if err != nil { + return fmt.Errorf("failed to get source account slot: %w", err) + } + + // Read the receiver's storage slot for the ERC20 contract. + // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. + _, _, err = c.get(keys.dstAccountSlot) + if err != nil { + return fmt.Errorf("failed to get destination account slot: %w", err) + } + + // Read the fee collection account's native balance. feeValue, found, err := c.get(c.feeCollectionAddress) if err != nil { return fmt.Errorf("failed to get fee collection account: %w", err) @@ -254,27 +438,52 @@ func (c *CryptoSim) executeTransaction() error { return fmt.Errorf("fee collection account not found") } - // Generate new balances for the accounts. - // The "balance" is simulated as the first 8 bytes of the account data. - // We can just choose a new random balance, since we don't care about the actual balance. + // Generate new data for the sender and reciver's native balance / nonce / codehash, as well + // as the sender and receiver's storage slot for the ERC20 contract. newSrcBalance := c.rand.Int64() newDstBalance := c.rand.Int64() newFeeBalance := c.rand.Int64() - binary.BigEndian.PutUint64(srcValue[:8], uint64(newSrcBalance)) - binary.BigEndian.PutUint64(dstValue[:8], uint64(newDstBalance)) + binary.BigEndian.PutUint64(srcAccountValue[:8], uint64(newSrcBalance)) + binary.BigEndian.PutUint64(dstAccountValue[:8], uint64(newDstBalance)) binary.BigEndian.PutUint64(feeValue[:8], uint64(newFeeBalance)) - // Write the new balances to the DB. - err = c.put(srcAccount, srcValue) + newSrcAccountSlotValue := c.rand.Bytes(c.config.Erc20StorageSlotSize) + newDstAccountSlotValue := c.rand.Bytes(c.config.Erc20StorageSlotSize) + + // Write the following: + // - the sender's native balance / nonce / codehash + // - the receiver's native balance + // - the sender's storage slot for the ERC20 contract + // - the receiver's storage slot for the ERC20 contract + // - the fee collection account's native balance + + // Write the sender's account data. + err = c.put(keys.srcAccount, srcAccountValue) if err != nil { return fmt.Errorf("failed to put source account: %w", err) } - err = c.put(dstAccount, dstValue) + + // Write the receiver's account data. + err = c.put(keys.dstAccount, dstAccountValue) if err != nil { return fmt.Errorf("failed to put destination account: %w", err) } + + // Write the sender's storage slot for the ERC20 contract. + err = c.put(keys.srcAccountSlot, newSrcAccountSlotValue) + if err != nil { + return fmt.Errorf("failed to put source account slot: %w", err) + } + + // Write the receiver's storage slot for the ERC20 contract. + err = c.put(keys.dstAccountSlot, newDstAccountSlotValue) + if err != nil { + return fmt.Errorf("failed to put destination account slot: %w", err) + } + + // Write the fee collection account's native balance. err = c.put(c.feeCollectionAddress, feeValue) if err != nil { return fmt.Errorf("failed to put fee collection account: %w", err) @@ -286,7 +495,7 @@ func (c *CryptoSim) executeTransaction() error { // Generates a human readable report of the benchmark's progress. func (c *CryptoSim) generateConsoleReport(force bool) { - // TODO measuring time each cycle is not efficient + // Future work: determine overhead of measuring time each cycle and change accordingly. now := time.Now() timeSinceLastUpdate := now.Sub(c.lastConsoleUpdateTime) @@ -315,57 +524,99 @@ func (c *CryptoSim) generateConsoleReport(force bool) { } // Select a random account for a transaction. -func (c *CryptoSim) randomAccount() ([]byte, error) { - hot := c.rand.Float64() < c.config.HotAccountProbably +func (c *CryptoSim) randomAccount() (id int64, address []byte, err error) { + hot := c.rand.Float64() < c.config.HotAccountProbability if hot { firstHotAccountID := 1 - lastHotAccountID := c.config.HotSetSize + lastHotAccountID := c.config.HotAccountSetSize accountID := c.rand.Int64Range(int64(firstHotAccountID), int64(lastHotAccountID+1)) - addr := c.rand.Address(c.config.AccountKeySize, accountID) - return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil + addr := c.rand.Address(accountPrefix, accountID) + return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } else { - new := c.rand.Float64() < c.config.NewAccountProbably + new := c.rand.Float64() < c.config.NewAccountProbability if new { - account, err := c.createNewAccount() + id, address, err := c.createNewAccount() if err != nil { - return nil, fmt.Errorf("failed to create new account: %w", err) + return 0, nil, fmt.Errorf("failed to create new account: %w", err) } - return account, nil + return id, address, nil } - firstNonHotAccountID := c.config.HotSetSize + 1 + firstNonHotAccountID := c.config.HotAccountSetSize + 1 accountID := c.rand.Int64Range(int64(firstNonHotAccountID), int64(c.nextAccountID)) - addr := c.rand.Address(c.config.AccountKeySize, accountID) + addr := c.rand.Address(accountPrefix, accountID) + return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil + } +} + +// Selects a random account slot for a transaction. +func (c *CryptoSim) randomAccountSlot(accountID int64) ([]byte, error) { + slotNumber := c.rand.Int64Range(0, int64(c.config.Erc20InteractionsPerAccount)) + slotID := accountID*int64(c.config.Erc20InteractionsPerAccount) + slotNumber + + addr := c.rand.Address(ethStoragePrefix, slotID) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil +} + +// Selects a random ERC20 contract for a transaction. +func (c *CryptoSim) randomErc20Contract() ([]byte, error) { + + hot := c.rand.Float64() < c.config.HotErc20ContractProbability + + if hot { + erc20ContractID := c.rand.Int64Range(0, int64(c.config.HotErc20ContractSetSize)) + addr := c.rand.Address(contractPrefix, erc20ContractID) return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } + + // Otherwise, select a cold ERC20 contract at random. + + erc20ContractID := c.rand.Int64Range(int64(c.config.HotErc20ContractSetSize), int64(c.nextErc20ContractID)) + addr := c.rand.Address(contractPrefix, erc20ContractID) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } // Creates a new account and writes it to the database. Returns the address of the new account. -func (c *CryptoSim) createNewAccount() ([]byte, error) { +func (c *CryptoSim) createNewAccount() (id int64, address []byte, err error) { accountID := c.nextAccountID c.nextAccountID++ // Use memiavl code key format (0x07 + addr) so FlatKV persists account data. - addr := c.rand.Address(c.config.AccountKeySize, accountID) - address := evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr) + addr := c.rand.Address(accountPrefix, accountID) + address = evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr) balance := c.rand.Int64() accountData := make([]byte, c.config.PaddedAccountSize) - // The first 8 bytes of the account data are the balance. For the sake of simplicity, - // For the sake of simplicity, we allow negative balances and don't care about overflow. binary.BigEndian.PutUint64(accountData[:8], uint64(balance)) // The remaining bytes are random data for padding. randomBytes := c.rand.Bytes(c.config.PaddedAccountSize - 8) copy(accountData[8:], randomBytes) - err := c.put(address, accountData) + err = c.put(address, accountData) + if err != nil { + return 0, nil, fmt.Errorf("failed to put account: %w", err) + } + + return accountID, address, nil +} + +// Creates a new ERC20 contract and writes it to the database. Returns the address of the new ERC20 contract. +func (c *CryptoSim) createNewErc20Contract() ([]byte, error) { + erc20ContractID := c.nextErc20ContractID + c.nextErc20ContractID++ + + erc20Address := c.rand.Address(contractPrefix, erc20ContractID) + address := evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, erc20Address) + + erc20Data := c.rand.Bytes(c.config.Erc20ContractSize) + err := c.put(address, erc20Data) if err != nil { - return nil, fmt.Errorf("failed to put account: %w", err) + return nil, fmt.Errorf("failed to put ERC20 contract: %w", err) } return address, nil @@ -406,13 +657,13 @@ func (c *CryptoSim) finalizeBlock() error { c.batch = make(map[string]*proto.NamedChangeSet) // Periodically commit the changes to the database. - c.uncommitedBlockCount++ - if c.uncommitedBlockCount >= int64(c.config.BlocksPerCommit) { + c.uncommittedBlockCount++ + if c.uncommittedBlockCount >= int64(c.config.BlocksPerCommit) { _, err := c.db.Commit() if err != nil { return fmt.Errorf("failed to commit: %w", err) } - c.uncommitedBlockCount = 0 + c.uncommittedBlockCount = 0 } return nil @@ -463,7 +714,7 @@ func (c *CryptoSim) Close() error { c.cancel() <-c.runHaltedChan - fmt.Printf("committing final batch\n") + fmt.Printf("Committing final batch.\n") if err := c.finalizeBlock(); err != nil { return fmt.Errorf("failed to commit batch: %w", err) @@ -472,13 +723,13 @@ func (c *CryptoSim) Close() error { return fmt.Errorf("failed to commit database: %w", err) } - fmt.Printf("closing database\n") + fmt.Printf("Closing database.\n") err := c.db.Close() if err != nil { return fmt.Errorf("failed to close database: %w", err) } - fmt.Printf("benchmark terminated successfully\n") + fmt.Printf("Benchmark terminated successfully.\n") // Specifically release rand, since it's likely to hold a lot of memory. c.rand = nil diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index d9158ec905..a6335cf50e 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -18,24 +18,44 @@ type CryptoSimConfig struct { // When selecting an account for a transaction, select a hot account with this probability. Should be // a value between 0.0 and 1.0. - HotAccountProbably float64 + HotAccountProbability float64 // When selecting a non-hot account for a transaction, the benchmark will create a new account with this // probability. Should be a value between 0.0 and 1.0. - NewAccountProbably float64 + NewAccountProbability float64 // The number of hot accounts. // // Future work: add different distributions of hot account access. Currently, distribution is flat. - HotSetSize int - - // The number of bytes in the account key. - AccountKeySize int + HotAccountSetSize int // Each account contains an integer value used to track a balance, plus a bunch of random // bytes for padding. This is the total size of the account after padding is added. PaddedAccountSize int + // The minimum number of ERC20 contracts that should be in the DB prior to the start of the benchmark. + // If there are fewer than this number of contracts, the benchmark will first create the necessary + // contracts before starting its regular operations. + MinimumNumberOfErc20Contracts int + + // When selecting an ERC20 contract for a transaction, select a hot ERC20 contract with this probability. + // Should be a value between 0.0 and 1.0. + HotErc20ContractProbability float64 + + // The number of hot ERC20 contracts. + HotErc20ContractSetSize int + + // The size of the a simulated ERC20 contract, in bytes. + Erc20ContractSize int + + // The size of a simulated ERC20 storage slot, in bytes. + Erc20StorageSlotSize int + + // The number of of ERC20 tokens that each account will interact with. + // Each account will have an eth storage slot for tracking the balance of each ERC20 token it owns. + // It is not legal to modify this value after the benchmark has started. + Erc20InteractionsPerAccount int + // The number of transactions that will be processed in each "block". TransactionsPerBlock int @@ -74,14 +94,18 @@ type CryptoSimConfig struct { func DefaultCryptoSimConfig() *CryptoSimConfig { return &CryptoSimConfig{ MinimumNumberOfAccounts: 1_000_000, - HotAccountProbably: 0.5, - NewAccountProbably: 0.001, - HotSetSize: 100, - AccountKeySize: 20, + HotAccountProbability: 0.5, + NewAccountProbability: 0.001, + HotAccountSetSize: 100, PaddedAccountSize: 69, // Not a joke, this is the actual size + MinimumNumberOfErc20Contracts: 10_000, + HotErc20ContractProbability: 0.5, + HotErc20ContractSetSize: 100, + Erc20ContractSize: 1024 * 2, // 2kb + Erc20StorageSlotSize: 32, + Erc20InteractionsPerAccount: 10, TransactionsPerBlock: 1024, BlocksPerCommit: 32, - DataDir: "", Seed: 1337, CannedRandomSize: 1024 * 1024 * 1024, // 1GB Backend: wrappers.FlatKV, diff --git a/sei-db/state_db/bench/cryptosim/kill-all.sh b/sei-db/state_db/bench/cryptosim/kill-all.sh deleted file mode 100755 index 47e1823840..0000000000 --- a/sei-db/state_db/bench/cryptosim/kill-all.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -# Kill all cryptosim benchmark processes. -# Targets: run.sh, go run main/main.go, and the compiled main binary. - -BENCH_PATH="sei-db/state_db/bench/cryptosim" - -pids=$(pgrep -f "$BENCH_PATH" 2>/dev/null || true) -pids="$pids $(pgrep -f 'cryptosim/run\.sh' 2>/dev/null || true)" -pids="$pids $(pgrep -f 'cryptosim.*main/main\.go' 2>/dev/null || true)" - -# Dedupe and kill -killed=0 -for pid in $(echo "$pids" | tr ' ' '\n' | sort -un); do - [ -n "$pid" ] && [ "$pid" -gt 0 ] 2>/dev/null || continue - if kill -9 "$pid" 2>/dev/null; then - echo "Killed PID $pid" - killed=$((killed + 1)) - fi -done - -[ "$killed" -eq 0 ] && echo "No cryptosim benchmark processes found." diff --git a/sei-db/state_db/bench/cryptosim/main/main.go b/sei-db/state_db/bench/cryptosim/main/main.go index ca741e9dc3..c1a80a319f 100644 --- a/sei-db/state_db/bench/cryptosim/main/main.go +++ b/sei-db/state_db/bench/cryptosim/main/main.go @@ -36,7 +36,7 @@ func run() error { return fmt.Errorf("failed to create cryptosim: %w", err) } defer func() { - fmt.Printf("initiating teardown\n") + fmt.Printf("Initiating teardown.\n") err := cs.Close() if err != nil { fmt.Fprintf(os.Stderr, "Error closing cryptosim: %v\n", err) diff --git a/sei-db/state_db/bench/cryptosim/run.sh b/sei-db/state_db/bench/cryptosim/run.sh index d546114644..7fc988cf3d 100755 --- a/sei-db/state_db/bench/cryptosim/run.sh +++ b/sei-db/state_db/bench/cryptosim/run.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash # Run the cryptosim benchmark. -go run main/main.go $@ \ No newline at end of file +go run main/main.go $@ diff --git a/sei-db/state_db/bench/helper.go b/sei-db/state_db/bench/helper.go index 94730cc169..421b9c0b14 100644 --- a/sei-db/state_db/bench/helper.go +++ b/sei-db/state_db/bench/helper.go @@ -265,12 +265,12 @@ func runBenchmark(b *testing.B, scenario TestScenario, withProgress bool) { func() { b.StopTimer() cs, err := wrappers.NewDBImpl(scenario.Backend, b.TempDir()) + require.NoError(b, err) + require.NotNil(b, cs) defer func() { err := cs.Close() require.NoError(b, err) }() - require.NoError(b, err) - require.NotNil(b, cs) changesetChannel := startChangesetGenerator(scenario) var progress *ProgressReporter From ed52867c7d50d4bb7798556eee87abda7ad9e270 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 13:37:22 -0600 Subject: [PATCH 12/49] bugfixes --- sei-db/state_db/bench/cryptosim/config/basic-config.json | 2 +- sei-db/state_db/bench/cryptosim/config/medium.json | 6 ++++++ sei-db/state_db/bench/cryptosim/cryptosim.go | 8 ++++---- 3 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/config/medium.json diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index f16c1668ed..001849740d 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -1,6 +1,6 @@ { "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", - "DataDir": "data/basic", + "DataDir": "data", "MinimumNumberOfAccounts": 100000 } diff --git a/sei-db/state_db/bench/cryptosim/config/medium.json b/sei-db/state_db/bench/cryptosim/config/medium.json new file mode 100644 index 0000000000..67307ef1d0 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/config/medium.json @@ -0,0 +1,6 @@ +{ + "Comment": "A medium-sized simulation. Takes a few minutes to set up, but is not extremely onerous to set up.", + "DataDir": "data", + "MinimumNumberOfAccounts": 10000000 +} + diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 37e660044b..f67cda2be2 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -108,14 +108,14 @@ func NewCryptoSim( return nil, err } - fmt.Printf("running cryptosim benchmark from data directory: %s\n", dataDir) + fmt.Printf("Running cryptosim benchmark from data directory: %s\n", dataDir) db, err := wrappers.NewDBImpl(config.Backend, dataDir) if err != nil { return nil, fmt.Errorf("failed to create database: %w", err) } - fmt.Printf("initializing random number generator\n") + fmt.Printf("Initializing random number generator.\n") rand := NewCannedRandom(config.CannedRandomSize, config.Seed) feeCollectionAddress := evm.BuildMemIAVLEVMKey( @@ -217,7 +217,7 @@ func (c *CryptoSim) setupAccounts() error { } if c.nextAccountID%c.config.SetupUpdateIntervalCount == 0 { - fmt.Printf("created %s of %s accounts\r", + fmt.Printf("Created %s of %s accounts.\r", int64Commas(c.nextAccountID), int64Commas(int64(c.config.MinimumNumberOfAccounts))) } } @@ -282,7 +282,7 @@ func (c *CryptoSim) setupErc20Contracts() error { } if c.nextErc20ContractID%c.config.SetupUpdateIntervalCount == 0 { - fmt.Printf("created %s of %s simulated ERC20 contracts\r", + fmt.Printf("Created %s of %s simulated ERC20 contracts.\r", int64Commas(c.nextErc20ContractID), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) } } From 16be236691754a48e13a046a8ba62c020896e5a9 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 15:01:33 -0600 Subject: [PATCH 13/49] code organization, bugfixes --- sei-db/state_db/bench/cryptosim/cryptosim.go | 247 ++++-------------- .../bench/cryptosim/cryptosim_config.go | 9 + sei-db/state_db/bench/cryptosim/main/main.go | 2 +- sei-db/state_db/bench/cryptosim/sync_map.go | 45 ++++ .../state_db/bench/cryptosim/transaciton.go | 224 ++++++++++++++++ .../bench/cryptosim/transaction_executor.go | 22 ++ 6 files changed, 359 insertions(+), 190 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/sync_map.go create mode 100644 sei-db/state_db/bench/cryptosim/transaciton.go create mode 100644 sei-db/state_db/bench/cryptosim/transaction_executor.go diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index f67cda2be2..c75c1b522f 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -57,7 +57,10 @@ type CryptoSim struct { // The current batch of changesets waiting to be committed. Represents changes we are accumulating // as part of a simulated "block". - batch map[string]*proto.NamedChangeSet + batch *SyncMap[string, *proto.NamedChangeSet] + + // A count of the number of transactions in the current batch. + transactionsInCurrentBlock int64 // The address of the fee account (i.e. the account that collects gas fees). This is a special account // and has account ID 0. Since we reuse this account very often, it is cached for performance. @@ -79,20 +82,6 @@ type CryptoSim struct { runHaltedChan chan struct{} } -// The keys that a transaction will read and write. -type transactionKeys struct { - // The simualted ERC20 contract that will be interacted with. This value is read. - erc20Contract []byte - // The source account that will be interacted with. This value is read and written. - srcAccount []byte - // The destination account that will be interacted with. This value is read and written. - dstAccount []byte - // The source account's storage slot that will be interacted with. This value is read and written. - srcAccountSlot []byte - // The destination account's storage slot that will be interacted with. This value is read and written. - dstAccountSlot []byte -} - // Creates a new cryptosim benchmark runner. func NewCryptoSim( ctx context.Context, @@ -143,7 +132,7 @@ func NewCryptoSim( config: config, db: db, rand: rand, - batch: make(map[string]*proto.NamedChangeSet, config.TransactionsPerBlock), + batch: NewSyncMap[string, *proto.NamedChangeSet](), accountIDCounterKey: accountIDCounterKey, erc20IDCounterKey: erc20IDCounterKey, feeCollectionAddress: feeCollectionAddress, @@ -207,10 +196,11 @@ func (c *CryptoSim) setupAccounts() error { break } - _, _, err := c.createNewAccount() + _, _, err := c.createNewAccount(true) if err != nil { return fmt.Errorf("failed to create new account: %w", err) } + c.transactionsInCurrentBlock++ err = c.maybeFinalizeBlock() if err != nil { return fmt.Errorf("failed to maybe commit batch: %w", err) @@ -272,6 +262,8 @@ func (c *CryptoSim) setupErc20Contracts() error { break } + c.transactionsInCurrentBlock++ + _, err := c.createNewErc20Contract() if err != nil { return fmt.Errorf("failed to create new ERC20 contract: %w", err) @@ -329,167 +321,30 @@ func (c *CryptoSim) run() { } return default: - err := c.executeTransaction() + + txn, err := BuildTransaction(c) if err != nil { - fmt.Printf("failed to execute transaction: %v\n", err) + fmt.Printf("\nfailed to build transaction: %v\n", err) + continue } - c.transactionCount++ - c.generateConsoleReport(false) - } - } -} - -// Selects the keys that a transaction will read and write. -func (c *CryptoSim) selectTransactionKeys() (*transactionKeys, error) { - srcAccountID, srcAccountAddress, err := c.randomAccount() - if err != nil { - return nil, fmt.Errorf("failed to select source account: %w", err) - } - dstAccountID, dstAccountAddress, err := c.randomAccount() - if err != nil { - return nil, fmt.Errorf("failed to select destination account: %w", err) - } - - srcAccountSlot, err := c.randomAccountSlot(srcAccountID) - if err != nil { - return nil, fmt.Errorf("failed to select source account slot: %w", err) - } - dstAccountSlot, err := c.randomAccountSlot(dstAccountID) - if err != nil { - return nil, fmt.Errorf("failed to select destination account slot: %w", err) - } - erc20Contract, err := c.randomErc20Contract() - if err != nil { - return nil, fmt.Errorf("failed to select ERC20 contract: %w", err) - } - - return &transactionKeys{ - srcAccount: srcAccountAddress, - dstAccount: dstAccountAddress, - srcAccountSlot: srcAccountSlot, - dstAccountSlot: dstAccountSlot, - erc20Contract: erc20Contract, - }, nil -} - -// Perform a single transaction. -func (c *CryptoSim) executeTransaction() error { - - // Determine which accounts and ERC20 contract will be involved in the transaction. - keys, err := c.selectTransactionKeys() - if err != nil { - return fmt.Errorf("failed to select transaction keys: %w", err) - } - - // Read the simulated ERC20 contract. - _, found, err := c.get(keys.erc20Contract) - if err != nil { - return fmt.Errorf("failed to get ERC20 contract: %w", err) - } - if !found { - return fmt.Errorf("ERC20 contract not found") - } - // Read the following: - // - the sender's native balance / nonce / codehash - // - the receiver's native balance - // - the sender's storage slot for the ERC20 contract - // - the receiver's storage slot for the ERC20 contract - // - the fee collection account's native balance - - // Read the sender's native balance / nonce / codehash. - srcAccountValue, found, err := c.get(keys.srcAccount) - if err != nil { - return fmt.Errorf("failed to get source account: %w", err) - } - if !found { - return fmt.Errorf("source account not found") - } - - // Read the receiver's native balance. - dstAccountValue, found, err := c.get(keys.dstAccount) - if err != nil { - return fmt.Errorf("failed to get destination account: %w", err) - } - if !found { - return fmt.Errorf("destination account not found") - } - - // Read the sender's storage slot for the ERC20 contract. - // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. - _, _, err = c.get(keys.srcAccountSlot) - if err != nil { - return fmt.Errorf("failed to get source account slot: %w", err) - } - - // Read the receiver's storage slot for the ERC20 contract. - // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. - _, _, err = c.get(keys.dstAccountSlot) - if err != nil { - return fmt.Errorf("failed to get destination account slot: %w", err) - } - - // Read the fee collection account's native balance. - feeValue, found, err := c.get(c.feeCollectionAddress) - if err != nil { - return fmt.Errorf("failed to get fee collection account: %w", err) - } - if !found { - return fmt.Errorf("fee collection account not found") - } - - // Generate new data for the sender and reciver's native balance / nonce / codehash, as well - // as the sender and receiver's storage slot for the ERC20 contract. - - newSrcBalance := c.rand.Int64() - newDstBalance := c.rand.Int64() - newFeeBalance := c.rand.Int64() - - binary.BigEndian.PutUint64(srcAccountValue[:8], uint64(newSrcBalance)) - binary.BigEndian.PutUint64(dstAccountValue[:8], uint64(newDstBalance)) - binary.BigEndian.PutUint64(feeValue[:8], uint64(newFeeBalance)) - - newSrcAccountSlotValue := c.rand.Bytes(c.config.Erc20StorageSlotSize) - newDstAccountSlotValue := c.rand.Bytes(c.config.Erc20StorageSlotSize) - - // Write the following: - // - the sender's native balance / nonce / codehash - // - the receiver's native balance - // - the sender's storage slot for the ERC20 contract - // - the receiver's storage slot for the ERC20 contract - // - the fee collection account's native balance - - // Write the sender's account data. - err = c.put(keys.srcAccount, srcAccountValue) - if err != nil { - return fmt.Errorf("failed to put source account: %w", err) - } - - // Write the receiver's account data. - err = c.put(keys.dstAccount, dstAccountValue) - if err != nil { - return fmt.Errorf("failed to put destination account: %w", err) - } - - // Write the sender's storage slot for the ERC20 contract. - err = c.put(keys.srcAccountSlot, newSrcAccountSlotValue) - if err != nil { - return fmt.Errorf("failed to put source account slot: %w", err) - } + err = txn.Execute(c) + if err != nil { + fmt.Printf("\nfailed to execute transaction: %v\n", err) + continue + } - // Write the receiver's storage slot for the ERC20 contract. - err = c.put(keys.dstAccountSlot, newDstAccountSlotValue) - if err != nil { - return fmt.Errorf("failed to put destination account slot: %w", err) - } + err = c.maybeFinalizeBlock() + if err != nil { + fmt.Printf("error finalizing block: %v\n", err) + continue + } - // Write the fee collection account's native balance. - err = c.put(c.feeCollectionAddress, feeValue) - if err != nil { - return fmt.Errorf("failed to put fee collection account: %w", err) + c.transactionCount++ + c.transactionsInCurrentBlock++ + c.generateConsoleReport(false) + } } - - return nil } // Generates a human readable report of the benchmark's progress. @@ -524,7 +379,7 @@ func (c *CryptoSim) generateConsoleReport(force bool) { } // Select a random account for a transaction. -func (c *CryptoSim) randomAccount() (id int64, address []byte, err error) { +func (c *CryptoSim) randomAccount() (id int64, address []byte, isNew bool, err error) { hot := c.rand.Float64() < c.config.HotAccountProbability if hot { @@ -532,22 +387,22 @@ func (c *CryptoSim) randomAccount() (id int64, address []byte, err error) { lastHotAccountID := c.config.HotAccountSetSize accountID := c.rand.Int64Range(int64(firstHotAccountID), int64(lastHotAccountID+1)) addr := c.rand.Address(accountPrefix, accountID) - return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil + return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil } else { new := c.rand.Float64() < c.config.NewAccountProbability if new { - id, address, err := c.createNewAccount() + id, address, err := c.createNewAccount(false) if err != nil { - return 0, nil, fmt.Errorf("failed to create new account: %w", err) + return 0, nil, false, fmt.Errorf("failed to create new account: %w", err) } - return id, address, nil + return id, address, true, nil } firstNonHotAccountID := c.config.HotAccountSetSize + 1 accountID := c.rand.Int64Range(int64(firstNonHotAccountID), int64(c.nextAccountID)) addr := c.rand.Address(accountPrefix, accountID) - return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil + return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil } } @@ -578,8 +433,8 @@ func (c *CryptoSim) randomErc20Contract() ([]byte, error) { return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } -// Creates a new account and writes it to the database. Returns the address of the new account. -func (c *CryptoSim) createNewAccount() (id int64, address []byte, err error) { +// Creates a new account and optinally writes it to the database. Returns the address of the new account. +func (c *CryptoSim) createNewAccount(write bool) (id int64, address []byte, err error) { accountID := c.nextAccountID c.nextAccountID++ @@ -587,6 +442,11 @@ func (c *CryptoSim) createNewAccount() (id int64, address []byte, err error) { // Use memiavl code key format (0x07 + addr) so FlatKV persists account data. addr := c.rand.Address(accountPrefix, accountID) address = evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr) + + if !write { + return accountID, address, nil + } + balance := c.rand.Int64() accountData := make([]byte, c.config.PaddedAccountSize) @@ -624,7 +484,7 @@ func (c *CryptoSim) createNewErc20Contract() ([]byte, error) { // Commit the current batch if it has reached the configured number of transactions. func (c *CryptoSim) maybeFinalizeBlock() error { - if len(c.batch) >= c.config.TransactionsPerBlock { + if c.transactionsInCurrentBlock >= int64(c.config.TransactionsPerBlock) { return c.finalizeBlock() } return nil @@ -632,14 +492,18 @@ func (c *CryptoSim) maybeFinalizeBlock() error { // Push the current block out to the database. func (c *CryptoSim) finalizeBlock() error { - if len(c.batch) == 0 { + if c.transactionsInCurrentBlock == 0 { return nil } - changeSets := make([]*proto.NamedChangeSet, 0, len(c.batch)+1) - for _, cs := range c.batch { + c.transactionsInCurrentBlock = 0 + + changeSets := make([]*proto.NamedChangeSet, 0, c.transactionsInCurrentBlock+1) + for _, cs := range c.batch.Iterator() { changeSets = append(changeSets, cs) } + c.batch.Clear() + // Persist the account ID counter in every batch. nonceValue := make([]byte, 8) binary.BigEndian.PutUint64(nonceValue, uint64(c.nextAccountID)) @@ -654,7 +518,6 @@ func (c *CryptoSim) finalizeBlock() error { if err != nil { return fmt.Errorf("failed to apply change sets: %w", err) } - c.batch = make(map[string]*proto.NamedChangeSet) // Periodically commit the changes to the database. c.uncommittedBlockCount++ @@ -670,30 +533,36 @@ func (c *CryptoSim) finalizeBlock() error { } // Insert a key-value pair into the database/cache. +// +// This method is safe to call concurrently with other calls to put() and get(). Is not thread +// safe with finalizeBlock(). func (c *CryptoSim) put(key []byte, value []byte) error { stringKey := string(key) - pending, found := c.batch[stringKey] + pending, found := c.batch.Get(stringKey) if found { pending.Changeset.Pairs[0].Value = value return nil } - c.batch[stringKey] = &proto.NamedChangeSet{ + c.batch.Put(stringKey, &proto.NamedChangeSet{ Name: wrappers.EVMStoreName, Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ {Key: key, Value: value}, }}, - } + }) return nil } // Retrieve a value from the database/cache. +// +// This method is safe to call concurrently with other calls to put() and get(). Is not thread +// safe with finalizeBlock(). func (c *CryptoSim) get(key []byte) ([]byte, bool, error) { stringKey := string(key) - pending, found := c.batch[stringKey] + pending, found := c.batch.Get(stringKey) if found { return pending.Changeset.Pairs[0].Value, true, nil } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index a6335cf50e..7cbaba8fa8 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -88,6 +88,13 @@ type CryptoSimConfig struct { // When setting up the benchmark, print a console update after adding this many accounts to the DB. SetupUpdateIntervalCount int64 + + // Run a number of threads equal to the number of cores on the host machine, multiplied by this value. + ThreadsPerCore float64 + + // Increase or decrease the thread count by this many threads. Total thread count is a function of + // ThreadsPerCore and ConstantThreadCount. + ConstantThreadCount int } // Returns the default configuration for the cryptosim benchmark. @@ -112,6 +119,8 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { ConsoleUpdateIntervalSeconds: 1, ConsoleUpdateIntervalTransactions: 1_000_000, SetupUpdateIntervalCount: 100_000, + ThreadsPerCore: 1.0, + ConstantThreadCount: 0, } } diff --git a/sei-db/state_db/bench/cryptosim/main/main.go b/sei-db/state_db/bench/cryptosim/main/main.go index c1a80a319f..efb6365067 100644 --- a/sei-db/state_db/bench/cryptosim/main/main.go +++ b/sei-db/state_db/bench/cryptosim/main/main.go @@ -36,7 +36,7 @@ func run() error { return fmt.Errorf("failed to create cryptosim: %w", err) } defer func() { - fmt.Printf("Initiating teardown.\n") + fmt.Printf("\nInitiating teardown.\n") err := cs.Close() if err != nil { fmt.Fprintf(os.Stderr, "Error closing cryptosim: %v\n", err) diff --git a/sei-db/state_db/bench/cryptosim/sync_map.go b/sei-db/state_db/bench/cryptosim/sync_map.go new file mode 100644 index 0000000000..d97d283637 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/sync_map.go @@ -0,0 +1,45 @@ +package cryptosim + +import ( + "iter" + "sync" +) + +// A thread safe map-like data structure. Unlike sync.Map, supports generics. +type SyncMap[K comparable, V any] struct { + base sync.Map +} + +// NewSyncMap returns a new empty SyncMap. +func NewSyncMap[K comparable, V any]() *SyncMap[K, V] { + return &SyncMap[K, V]{} +} + +// Put stores the key-value pair in the map. +func (m *SyncMap[K, V]) Put(key K, value V) { + m.base.Store(key, value) +} + +// Clear removes all key-value pairs from the map. +func (m *SyncMap[K, V]) Clear() { + m.base.Clear() +} + +// Get returns the value for key and true if present, or the zero value of V and false otherwise. +func (m *SyncMap[K, V]) Get(key K) (V, bool) { + val, ok := m.base.Load(key) + if !ok { + var zero V + return zero, false + } + return val.(V), true +} + +// All returns an iterator over the map's key-value pairs for use with range. +func (m *SyncMap[K, V]) Iterator() iter.Seq2[K, V] { + return func(yield func(K, V) bool) { + m.base.Range(func(key, value any) bool { + return yield(key.(K), value.(V)) + }) + } +} diff --git a/sei-db/state_db/bench/cryptosim/transaciton.go b/sei-db/state_db/bench/cryptosim/transaciton.go new file mode 100644 index 0000000000..0fc108191a --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/transaciton.go @@ -0,0 +1,224 @@ +package cryptosim + +import ( + "encoding/binary" + "fmt" +) + +// The data needed to execute a transaction. +type transaction struct { + // The simualted ERC20 contract that will be interacted with. This value is read. + erc20Contract []byte + + // The source account that will be interacted with. This value is read and written. + srcAccount []byte + // If true, the source account is new and needs to be created. + isSrcNew bool + // If the source account is new, this is the data that will be written to the account. + // If not new, this will be nil. + newSrcData []byte + + // The destination account that will be interacted with. This value is read and written. + dstAccount []byte + // If true, the destination account is new and needs to be created. + isDstNew bool + // If the destination account is new, this is the data that will be written to the account. + // If not new, this will be nil. + newDstData []byte + + // The source account's storage slot that will be interacted with. This value is read and written. + srcAccountSlot []byte + // The destination account's storage slot that will be interacted with. This value is read and written. + dstAccountSlot []byte + + // Pre-generated random value for the source account's new native balance. + newSrcBalance int64 + // Pre-generated random value for the destination account's new native balance. + newDstBalance int64 + // Pre-generated random value for the fee collection account's new native balance. + newFeeBalance int64 + // Pre-generated random value for the source account's ERC20 storage slot. + newSrcAccountSlot []byte + // Pre-generated random value for the destination account's ERC20 storage slot. + newDstAccountSlot []byte +} + +// Generate all data needed to execute a transaction. +// +// This method is not thread safe to call concurrently with other calls to BuildTransaction(). +func BuildTransaction(cryptosim *CryptoSim) (*transaction, error) { + srcAccountID, srcAccountAddress, isSrcNew, err := cryptosim.randomAccount() + if err != nil { + return nil, fmt.Errorf("failed to select source account: %w", err) + } + dstAccountID, dstAccountAddress, isDstNew, err := cryptosim.randomAccount() + if err != nil { + return nil, fmt.Errorf("failed to select destination account: %w", err) + } + + srcAccountSlot, err := cryptosim.randomAccountSlot(srcAccountID) + if err != nil { + return nil, fmt.Errorf("failed to select source account slot: %w", err) + } + dstAccountSlot, err := cryptosim.randomAccountSlot(dstAccountID) + if err != nil { + return nil, fmt.Errorf("failed to select destination account slot: %w", err) + } + erc20Contract, err := cryptosim.randomErc20Contract() + if err != nil { + return nil, fmt.Errorf("failed to select ERC20 contract: %w", err) + } + + var newSrcData []byte + if isSrcNew { + newSrcData = cryptosim.rand.Bytes(cryptosim.config.PaddedAccountSize) + } + var newDstData []byte + if isDstNew { + newDstData = cryptosim.rand.Bytes(cryptosim.config.PaddedAccountSize) + } + + return &transaction{ + srcAccount: srcAccountAddress, + isSrcNew: isSrcNew, + newSrcData: newSrcData, + dstAccount: dstAccountAddress, + isDstNew: isDstNew, + newDstData: newDstData, + srcAccountSlot: srcAccountSlot, + dstAccountSlot: dstAccountSlot, + erc20Contract: erc20Contract, + newSrcBalance: cryptosim.rand.Int64(), + newDstBalance: cryptosim.rand.Int64(), + newFeeBalance: cryptosim.rand.Int64(), + newSrcAccountSlot: cryptosim.rand.Bytes(cryptosim.config.Erc20StorageSlotSize), + newDstAccountSlot: cryptosim.rand.Bytes(cryptosim.config.Erc20StorageSlotSize), + }, nil +} + +// Execute the transaction. +// +// This method is thread safe with other calls to Execute(), +// but must not be called concurrently with CryptoSim.finalizeBlock(). +func (txn *transaction) Execute(cryptosim *CryptoSim) error { + + // Read the simulated ERC20 contract. + _, found, err := cryptosim.get(txn.erc20Contract) + if err != nil { + return fmt.Errorf("failed to get ERC20 contract: %w", err) + } + if !found { + return fmt.Errorf("ERC20 contract not found") + } + + // Read the following: + // - the sender's native balance / nonce / codehash + // - the receiver's native balance + // - the sender's storage slot for the ERC20 contract + // - the receiver's storage slot for the ERC20 contract + // - the fee collection account's native balance + + // Read the sender's native balance / nonce / codehash. + srcAccountValue, found, err := cryptosim.get(txn.srcAccount) + if err != nil { + return fmt.Errorf("failed to get source account: %w", err) + } + + if txn.isSrcNew { + // This is a new account, so we should not find it in the DB. + if found { + return fmt.Errorf("should not find source account in DB, account should be new") + } + srcAccountValue = txn.newSrcData + } else { + // This is an existing account, so we should find it in the DB. + if !found { + return fmt.Errorf("source account not found") + } + } + + // Read the receiver's native balance. + dstAccountValue, found, err := cryptosim.get(txn.dstAccount) + if err != nil { + return fmt.Errorf("failed to get destination account: %w", err) + } + if txn.isDstNew { + // This is a new account, so we should not find it in the DB. + if found { + return fmt.Errorf("should not find destination account in DB, account should be new") + } + dstAccountValue = txn.newDstData + } else { + // This is an existing account, so we should find it in the DB. + if !found { + return fmt.Errorf("destination account not found") + } + } + + // Read the sender's storage slot for the ERC20 contract. + // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. + _, _, err = cryptosim.get(txn.srcAccountSlot) + if err != nil { + return fmt.Errorf("failed to get source account slot: %w", err) + } + + // Read the receiver's storage slot for the ERC20 contract. + // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. + _, _, err = cryptosim.get(txn.dstAccountSlot) + if err != nil { + return fmt.Errorf("failed to get destination account slot: %w", err) + } + + // Read the fee collection account's native balance. + feeValue, found, err := cryptosim.get(cryptosim.feeCollectionAddress) + if err != nil { + return fmt.Errorf("failed to get fee collection account: %w", err) + } + if !found { + return fmt.Errorf("fee collection account not found") + } + + // Apply the random values from the transaction to the account and slot data. + binary.BigEndian.PutUint64(srcAccountValue[:8], uint64(txn.newSrcBalance)) + binary.BigEndian.PutUint64(dstAccountValue[:8], uint64(txn.newDstBalance)) + binary.BigEndian.PutUint64(feeValue[:8], uint64(txn.newFeeBalance)) + + // Write the following: + // - the sender's native balance / nonce / codehash + // - the receiver's native balance + // - the sender's storage slot for the ERC20 contract + // - the receiver's storage slot for the ERC20 contract + // - the fee collection account's native balance + + // Write the sender's account data. + err = cryptosim.put(txn.srcAccount, srcAccountValue) + if err != nil { + return fmt.Errorf("failed to put source account: %w", err) + } + + // Write the receiver's account data. + err = cryptosim.put(txn.dstAccount, dstAccountValue) + if err != nil { + return fmt.Errorf("failed to put destination account: %w", err) + } + + // Write the sender's storage slot for the ERC20 contract. + err = cryptosim.put(txn.srcAccountSlot, txn.newSrcAccountSlot) + if err != nil { + return fmt.Errorf("failed to put source account slot: %w", err) + } + + // Write the receiver's storage slot for the ERC20 contract. + err = cryptosim.put(txn.dstAccountSlot, txn.newDstAccountSlot) + if err != nil { + return fmt.Errorf("failed to put destination account slot: %w", err) + } + + // Write the fee collection account's native balance. + err = cryptosim.put(cryptosim.feeCollectionAddress, feeValue) + if err != nil { + return fmt.Errorf("failed to put fee collection account: %w", err) + } + + return nil +} diff --git a/sei-db/state_db/bench/cryptosim/transaction_executor.go b/sei-db/state_db/bench/cryptosim/transaction_executor.go new file mode 100644 index 0000000000..0c4d34db80 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/transaction_executor.go @@ -0,0 +1,22 @@ +package cryptosim + +type TransactionExecutor struct { + // The CryptoSim benchmark runner. + cryptoSim *CryptoSim + + // The Incoming transactions to be executed. + workChan chan *any +} + +// A single threaded transaction executor. +func NewTransactionExecutor( + cryptosim *CryptoSim, + queueSize int, +) *TransactionExecutor { + return &TransactionExecutor{ + cryptoSim: cryptosim, + workChan: make(chan *any, queueSize), + } +} + +// TODO From e662b332eba9034475608f5174de8e381cd6cb6b Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 15:51:17 -0600 Subject: [PATCH 14/49] reorganized code, introduced bugs --- sei-db/state_db/bench/cryptosim/cryptosim.go | 170 +++++------------- .../bench/cryptosim/data_generator.go | 152 ++++++++++++++++ .../{transaciton.go => transaction.go} | 14 +- 3 files changed, 207 insertions(+), 129 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/data_generator.go rename sei-db/state_db/bench/cryptosim/{transaciton.go => transaction.go} (95%) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index c75c1b522f..bdd1d51374 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -13,11 +13,6 @@ import ( ) const ( - // Used to store the next account ID in the database. - accountIdCounterKey = "accountIdCounterKey" - // Used to store the next ERC20 contract ID in the database. - erc20IdCounterKey = "erc20IdCounterKey" - accountPrefix = 'a' contractPrefix = 'c' ethStoragePrefix = 's' @@ -37,18 +32,6 @@ type CryptoSim struct { // The source of randomness for the benchmark. rand *CannedRandom - // The next account ID to be used when creating a new account. - nextAccountID int64 - - // Key for the account ID counter in the database. - accountIDCounterKey []byte - - // The next ERC20 contract ID to be used when creating a new ERC20 contract. - nextErc20ContractID int64 - - // Key for the ERC20 contract ID counter in the database. - erc20IDCounterKey []byte - // The total number of transactions executed by the benchmark since it last started. transactionCount int64 @@ -80,6 +63,9 @@ type CryptoSim struct { // The run channel sends a signal on this channel when it has halted. runHaltedChan chan struct{} + + // The data generator for the benchmark. + dataGenerator *DataGenerator } // Creates a new cryptosim benchmark runner. @@ -112,20 +98,19 @@ func NewCryptoSim( rand.Address(accountPrefix, 0), ) - accountIdCounterBytes := make([]byte, 20) - copy(accountIdCounterBytes, []byte(accountIdCounterKey)) - accountIDCounterKey := evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, accountIdCounterBytes) - - erc20IdCounterBytes := make([]byte, 20) - copy(erc20IdCounterBytes, []byte(erc20IdCounterKey)) - erc20IDCounterKey := evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, erc20IdCounterBytes) - consoleUpdatePeriod := time.Duration(config.ConsoleUpdateIntervalSeconds * float64(time.Second)) start := time.Now() ctx, cancel := context.WithCancel(ctx) + dataGenerator, err := NewDataGenerator(db, rand) + if err != nil { + cancel() + db.Close() + return nil, fmt.Errorf("failed to create data generator: %w", err) + } + c := &CryptoSim{ ctx: ctx, cancel: cancel, @@ -133,13 +118,12 @@ func NewCryptoSim( db: db, rand: rand, batch: NewSyncMap[string, *proto.NamedChangeSet](), - accountIDCounterKey: accountIDCounterKey, - erc20IDCounterKey: erc20IDCounterKey, feeCollectionAddress: feeCollectionAddress, consoleUpdatePeriod: consoleUpdatePeriod, lastConsoleUpdateTime: start, lastConsoleUpdateTransactionCount: 0, runHaltedChan: make(chan struct{}, 1), + dataGenerator: dataGenerator, } err = c.setup() @@ -172,31 +156,21 @@ func (c *CryptoSim) setupAccounts() error { c.config.MinimumNumberOfAccounts = c.config.HotAccountSetSize + 2 } - nextAccountID, found, err := c.db.Read(c.accountIDCounterKey) - if err != nil { - return fmt.Errorf("failed to read account counter: %w", err) - } - if found { - c.nextAccountID = int64(binary.BigEndian.Uint64(nextAccountID)) - } - - fmt.Printf("There are currently %s keys in the database.\n", int64Commas(c.nextAccountID)) - - if c.nextAccountID >= int64(c.config.MinimumNumberOfAccounts) { + if c.dataGenerator.NextAccountID() >= int64(c.config.MinimumNumberOfAccounts) { return nil } fmt.Printf("Benchmark is configured to run with a minimum of %s accounts. Creating %s new accounts.\n", int64Commas(int64(c.config.MinimumNumberOfAccounts)), - int64Commas(int64(c.config.MinimumNumberOfAccounts)-c.nextAccountID)) + int64Commas(int64(c.config.MinimumNumberOfAccounts)-c.dataGenerator.NextAccountID())) - for c.nextAccountID < int64(c.config.MinimumNumberOfAccounts) { + for c.dataGenerator.NextAccountID() < int64(c.config.MinimumNumberOfAccounts) { if c.ctx.Err() != nil { fmt.Printf("benchmark aborted during account creation\n") break } - _, _, err := c.createNewAccount(true) + _, _, err := c.dataGenerator.CreateNewAccount(c, c.config.PaddedAccountSize, true) if err != nil { return fmt.Errorf("failed to create new account: %w", err) } @@ -206,16 +180,16 @@ func (c *CryptoSim) setupAccounts() error { return fmt.Errorf("failed to maybe commit batch: %w", err) } - if c.nextAccountID%c.config.SetupUpdateIntervalCount == 0 { + if c.dataGenerator.NextAccountID()%c.config.SetupUpdateIntervalCount == 0 { fmt.Printf("Created %s of %s accounts.\r", - int64Commas(c.nextAccountID), int64Commas(int64(c.config.MinimumNumberOfAccounts))) + int64Commas(c.dataGenerator.NextAccountID()), int64Commas(int64(c.config.MinimumNumberOfAccounts))) } } - if c.nextAccountID >= c.config.SetupUpdateIntervalCount { + if c.dataGenerator.NextAccountID() >= c.config.SetupUpdateIntervalCount { fmt.Printf("\n") } fmt.Printf("Created %s of %s accounts.\n", - int64Commas(c.nextAccountID), int64Commas(int64(c.config.MinimumNumberOfAccounts))) + int64Commas(c.dataGenerator.NextAccountID()), int64Commas(int64(c.config.MinimumNumberOfAccounts))) if err := c.finalizeBlock(); err != nil { return fmt.Errorf("failed to commit block: %w", err) } @@ -224,7 +198,7 @@ func (c *CryptoSim) setupAccounts() error { } c.uncommittedBlockCount = 0 - fmt.Printf("There are now %d accounts in the database.\n", c.nextAccountID) + fmt.Printf("There are now %d accounts in the database.\n", c.dataGenerator.NextAccountID()) return nil } @@ -236,27 +210,16 @@ func (c *CryptoSim) setupErc20Contracts() error { c.config.MinimumNumberOfErc20Contracts = c.config.HotErc20ContractSetSize + 1 } - nextErc20ContractID, found, err := c.db.Read(c.erc20IDCounterKey) - if err != nil { - return fmt.Errorf("failed to read ERC20 contract counter: %w", err) - } - if found { - c.nextErc20ContractID = int64(binary.BigEndian.Uint64(nextErc20ContractID)) - } - - fmt.Printf("There are currently %s simulated ERC20 contracts in the database.\n", - int64Commas(c.nextErc20ContractID)) - - if c.nextErc20ContractID >= int64(c.config.MinimumNumberOfErc20Contracts) { + if c.dataGenerator.NextErc20ContractID() >= int64(c.config.MinimumNumberOfErc20Contracts) { return nil } fmt.Printf("Benchmark is configured to run with a minimum of %s simulated ERC20 contracts. "+ "Creating %s new ERC20 contracts.\n", int64Commas(int64(c.config.MinimumNumberOfErc20Contracts)), - int64Commas(int64(c.config.MinimumNumberOfErc20Contracts)-c.nextErc20ContractID)) + int64Commas(int64(c.config.MinimumNumberOfErc20Contracts)-c.dataGenerator.NextErc20ContractID())) - for c.nextErc20ContractID < int64(c.config.MinimumNumberOfErc20Contracts) { + for c.dataGenerator.NextErc20ContractID() < int64(c.config.MinimumNumberOfErc20Contracts) { if c.ctx.Err() != nil { fmt.Printf("benchmark aborted during ERC20 contract creation\n") break @@ -264,7 +227,7 @@ func (c *CryptoSim) setupErc20Contracts() error { c.transactionsInCurrentBlock++ - _, err := c.createNewErc20Contract() + _, _, err := c.dataGenerator.CreateNewErc20Contract(c, c.config.Erc20ContractSize, true) if err != nil { return fmt.Errorf("failed to create new ERC20 contract: %w", err) } @@ -273,25 +236,26 @@ func (c *CryptoSim) setupErc20Contracts() error { return fmt.Errorf("failed to maybe commit batch: %w", err) } - if c.nextErc20ContractID%c.config.SetupUpdateIntervalCount == 0 { + if c.dataGenerator.NextErc20ContractID()%c.config.SetupUpdateIntervalCount == 0 { fmt.Printf("Created %s of %s simulated ERC20 contracts.\r", - int64Commas(c.nextErc20ContractID), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) + int64Commas(c.dataGenerator.NextErc20ContractID()), + int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) } } // As a final step, write the ERC20 contract ID counter to the database. data := make([]byte, 8) - binary.BigEndian.PutUint64(data, uint64(c.nextErc20ContractID)) - err = c.put(c.erc20IDCounterKey, data) + binary.BigEndian.PutUint64(data, uint64(c.dataGenerator.NextErc20ContractID())) + err := c.put(Erc20IDCounterKey(), data) if err != nil { return fmt.Errorf("failed to put ERC20 contract ID counter: %w", err) } - if c.nextErc20ContractID >= c.config.SetupUpdateIntervalCount { + if c.dataGenerator.NextErc20ContractID() >= c.config.SetupUpdateIntervalCount { fmt.Printf("\n") } fmt.Printf("Created %s of %s simulated ERC20 contracts.\n", - int64Commas(c.nextErc20ContractID), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) + int64Commas(c.dataGenerator.NextErc20ContractID()), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) if err := c.finalizeBlock(); err != nil { return fmt.Errorf("failed to commit block: %w", err) } @@ -300,7 +264,7 @@ func (c *CryptoSim) setupErc20Contracts() error { } c.uncommittedBlockCount = 0 - fmt.Printf("There are now %d simulated ERC20 contracts in the database.\n", c.nextErc20ContractID) + fmt.Printf("There are now %d simulated ERC20 contracts in the database.\n", c.dataGenerator.NextErc20ContractID()) return nil } @@ -322,7 +286,7 @@ func (c *CryptoSim) run() { return default: - txn, err := BuildTransaction(c) + txn, err := BuildTransaction(c, c.dataGenerator) if err != nil { fmt.Printf("\nfailed to build transaction: %v\n", err) continue @@ -375,11 +339,12 @@ func (c *CryptoSim) generateConsoleReport(force bool) { int64Commas(c.transactionCount), totalElapsedTime, formatNumberFloat64(transactionsPerSecond, 2), - int64Commas(c.nextAccountID)) + int64Commas(c.dataGenerator.NextAccountID())) } -// Select a random account for a transaction. -func (c *CryptoSim) randomAccount() (id int64, address []byte, isNew bool, err error) { +// Select a random account for a transaction. If an existing account is selected then its ID is guaranteed to be +// less or equal to maxAccountID. If a new account is created, it may have an ID greater than maxAccountID. +func (c *CryptoSim) randomAccount(maxAccountID int64) (id int64, address []byte, isNew bool, err error) { hot := c.rand.Float64() < c.config.HotAccountProbability if hot { @@ -392,15 +357,17 @@ func (c *CryptoSim) randomAccount() (id int64, address []byte, isNew bool, err e new := c.rand.Float64() < c.config.NewAccountProbability if new { - id, address, err := c.createNewAccount(false) + id, address, err := c.dataGenerator.CreateNewAccount(c, c.config.PaddedAccountSize, false) if err != nil { return 0, nil, false, fmt.Errorf("failed to create new account: %w", err) } return id, address, true, nil } + // select an existing account at random + firstNonHotAccountID := c.config.HotAccountSetSize + 1 - accountID := c.rand.Int64Range(int64(firstNonHotAccountID), int64(c.nextAccountID)) + accountID := c.rand.Int64Range(int64(firstNonHotAccountID), maxAccountID+1) addr := c.rand.Address(accountPrefix, accountID) return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil } @@ -428,60 +395,11 @@ func (c *CryptoSim) randomErc20Contract() ([]byte, error) { // Otherwise, select a cold ERC20 contract at random. - erc20ContractID := c.rand.Int64Range(int64(c.config.HotErc20ContractSetSize), int64(c.nextErc20ContractID)) + erc20ContractID := c.rand.Int64Range(int64(c.config.HotErc20ContractSetSize), int64(c.dataGenerator.NextErc20ContractID())) addr := c.rand.Address(contractPrefix, erc20ContractID) return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } -// Creates a new account and optinally writes it to the database. Returns the address of the new account. -func (c *CryptoSim) createNewAccount(write bool) (id int64, address []byte, err error) { - - accountID := c.nextAccountID - c.nextAccountID++ - - // Use memiavl code key format (0x07 + addr) so FlatKV persists account data. - addr := c.rand.Address(accountPrefix, accountID) - address = evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr) - - if !write { - return accountID, address, nil - } - - balance := c.rand.Int64() - - accountData := make([]byte, c.config.PaddedAccountSize) - - binary.BigEndian.PutUint64(accountData[:8], uint64(balance)) - - // The remaining bytes are random data for padding. - randomBytes := c.rand.Bytes(c.config.PaddedAccountSize - 8) - copy(accountData[8:], randomBytes) - - err = c.put(address, accountData) - if err != nil { - return 0, nil, fmt.Errorf("failed to put account: %w", err) - } - - return accountID, address, nil -} - -// Creates a new ERC20 contract and writes it to the database. Returns the address of the new ERC20 contract. -func (c *CryptoSim) createNewErc20Contract() ([]byte, error) { - erc20ContractID := c.nextErc20ContractID - c.nextErc20ContractID++ - - erc20Address := c.rand.Address(contractPrefix, erc20ContractID) - address := evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, erc20Address) - - erc20Data := c.rand.Bytes(c.config.Erc20ContractSize) - err := c.put(address, erc20Data) - if err != nil { - return nil, fmt.Errorf("failed to put ERC20 contract: %w", err) - } - - return address, nil -} - // Commit the current batch if it has reached the configured number of transactions. func (c *CryptoSim) maybeFinalizeBlock() error { if c.transactionsInCurrentBlock >= int64(c.config.TransactionsPerBlock) { @@ -506,11 +424,11 @@ func (c *CryptoSim) finalizeBlock() error { // Persist the account ID counter in every batch. nonceValue := make([]byte, 8) - binary.BigEndian.PutUint64(nonceValue, uint64(c.nextAccountID)) + binary.BigEndian.PutUint64(nonceValue, uint64(c.dataGenerator.NextAccountID())) changeSets = append(changeSets, &proto.NamedChangeSet{ Name: wrappers.EVMStoreName, Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ - {Key: c.accountIDCounterKey, Value: nonceValue}, + {Key: AccountIDCounterKey(), Value: nonceValue}, }}, }) diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go new file mode 100644 index 0000000000..86e9cecca3 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/data_generator.go @@ -0,0 +1,152 @@ +package cryptosim + +import ( + "encoding/binary" + "fmt" + + "github.com/sei-protocol/sei-chain/sei-db/common/evm" + "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" +) + +const ( + // Used to store the next account ID in the database. + accountIdCounterKey = "accountIdCounterKey" + // Used to store the next ERC20 contract ID in the database. + erc20IdCounterKey = "erc20IdCounterKey" +) + +// Generates random data for the benchmark. This is not a thread safe utility. +type DataGenerator struct { + nextAccountID int64 + nextErc20ContractID int64 + + rand *CannedRandom +} + +// Creates a new data generator. +func NewDataGenerator( + db wrappers.DBWrapper, + rand *CannedRandom) (*DataGenerator, error) { + + nextAccountIDBinary, found, err := db.Read(AccountIDCounterKey()) + if err != nil { + return nil, fmt.Errorf("failed to read account counter: %w", err) + } + var nextAccountID int64 + if found { + nextAccountID = int64(binary.BigEndian.Uint64(nextAccountIDBinary)) + } + + fmt.Printf("There are currently %s keys in the database.\n", int64Commas(nextAccountID)) + + // erc20IdCounterBytes := make([]byte, 20) + // copy(erc20IdCounterBytes, []byte(erc20IdCounterKey)) + // erc20IDCounterKey := evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, erc20IdCounterBytes) + + nextErc20ContractIDBinary, found, err := db.Read(Erc20IDCounterKey()) + if err != nil { + return nil, fmt.Errorf("failed to read ERC20 contract counter: %w", err) + } + var nextErc20ContractID int64 + if found { + nextErc20ContractID = int64(binary.BigEndian.Uint64(nextErc20ContractIDBinary)) + } + + fmt.Printf("There are currently %s ERC20 contracts in the database.\n", int64Commas(nextErc20ContractID)) + + return &DataGenerator{ + nextAccountID: nextAccountID, + nextErc20ContractID: nextErc20ContractID, + rand: rand, + }, nil +} + +// Get the key for the account ID counter in the database. +func AccountIDCounterKey() []byte { + return evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, []byte(accountIdCounterKey)) +} + +// Get the key for the ERC20 contract ID counter in the database. +func Erc20IDCounterKey() []byte { + return evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, []byte(erc20IdCounterKey)) +} + +// Get the next account ID to be used when creating a new account. This is also the total number of accounts +// currently in the database. +func (d *DataGenerator) NextAccountID() int64 { + return d.nextAccountID +} + +// Get the next ERC20 contract ID to be used when creating a new ERC20 contract. This is also the total number of +// ERC20 contracts currently in the database. +func (d *DataGenerator) NextErc20ContractID() int64 { + return d.nextErc20ContractID +} + +// Creates a new account and optionally writes it to the database. Returns the address of the new account. +func (d *DataGenerator) CreateNewAccount( + cryptosim *CryptoSim, + // The number of bytes to allocate for the account data. + accountSize int, + // If true, the account will be immediately written to the database. + write bool, +) (id int64, address []byte, err error) { + + accountID := d.nextAccountID + d.nextAccountID++ + + // Use memiavl code key format (0x07 + addr) so FlatKV persists account data. + addr := d.rand.Address(accountPrefix, accountID) + address = evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr) + + if !write { + return accountID, address, nil + } + + balance := d.rand.Int64() + + accountData := make([]byte, accountSize) + + binary.BigEndian.PutUint64(accountData[:8], uint64(balance)) + + // The remaining bytes are random data for padding. + randomBytes := d.rand.Bytes(accountSize - 8) + copy(accountData[8:], randomBytes) + + err = cryptosim.put(address, accountData) + if err != nil { + return 0, nil, fmt.Errorf("failed to put account: %w", err) + } + + return accountID, address, nil +} + +// Creates a new ERC20 contract and optionally writes it to the database. Returns the address of the new ERC20 contract. +func (d *DataGenerator) CreateNewErc20Contract( + cryptosim *CryptoSim, + // The number of bytes to allocate for the ERC20 contract data. + erc20ContractSize int, + // If true, the ERC20 contract will be immediately written to the database. + write bool, +) (id int64, address []byte, err error) { + erc20ContractID := d.nextErc20ContractID + d.nextErc20ContractID++ + + erc20Address := d.rand.Address(contractPrefix, erc20ContractID) + address = evm.BuildMemIAVLEVMKey(evm.EVMKeyStorage, erc20Address) + + if !write { + return erc20ContractID, address, nil + } + + erc20Data := make([]byte, erc20ContractSize) + randomBytes := d.rand.Bytes(erc20ContractSize) + copy(erc20Data, randomBytes) + + err = cryptosim.put(address, erc20Data) + if err != nil { + return 0, nil, fmt.Errorf("failed to put ERC20 contract: %w", err) + } + + return erc20ContractID, address, nil +} diff --git a/sei-db/state_db/bench/cryptosim/transaciton.go b/sei-db/state_db/bench/cryptosim/transaction.go similarity index 95% rename from sei-db/state_db/bench/cryptosim/transaciton.go rename to sei-db/state_db/bench/cryptosim/transaction.go index 0fc108191a..e37bc7e902 100644 --- a/sei-db/state_db/bench/cryptosim/transaciton.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -46,12 +46,20 @@ type transaction struct { // Generate all data needed to execute a transaction. // // This method is not thread safe to call concurrently with other calls to BuildTransaction(). -func BuildTransaction(cryptosim *CryptoSim) (*transaction, error) { - srcAccountID, srcAccountAddress, isSrcNew, err := cryptosim.randomAccount() +func BuildTransaction( + cryptosim *CryptoSim, + dataGenerator *DataGenerator, +) (*transaction, error) { + + // The maximum account ID for existing transactions. If random account returns a new account ID, + // that ID may be greater than this value. + maxAccountID := dataGenerator.NextAccountID() - 1 + + srcAccountID, srcAccountAddress, isSrcNew, err := cryptosim.randomAccount(maxAccountID) if err != nil { return nil, fmt.Errorf("failed to select source account: %w", err) } - dstAccountID, dstAccountAddress, isDstNew, err := cryptosim.randomAccount() + dstAccountID, dstAccountAddress, isDstNew, err := cryptosim.randomAccount(maxAccountID) if err != nil { return nil, fmt.Errorf("failed to select destination account: %w", err) } From aa45ea3c3d6c984509518e14d18e142a6f5f828d Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 16:30:56 -0600 Subject: [PATCH 15/49] More changes, more bugs --- sei-db/state_db/bench/cryptosim/cryptosim.go | 270 ++---------------- .../bench/cryptosim/data_generator.go | 132 +++++++-- sei-db/state_db/bench/cryptosim/database.go | 184 ++++++++++++ .../state_db/bench/cryptosim/transaction.go | 52 ++-- sei-db/state_db/bench/cryptosim/util.go | 12 + 5 files changed, 359 insertions(+), 291 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/database.go diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index bdd1d51374..4df1bd6131 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -2,14 +2,10 @@ package cryptosim import ( "context" - "encoding/binary" "fmt" "time" - "github.com/sei-protocol/sei-chain/sei-db/common/evm" - "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" - iavl "github.com/sei-protocol/sei-chain/sei-iavl" ) const ( @@ -26,29 +22,6 @@ type CryptoSim struct { // The configuration for the benchmark. config *CryptoSimConfig - // The database implementation to use for the benchmark. - db wrappers.DBWrapper - - // The source of randomness for the benchmark. - rand *CannedRandom - - // The total number of transactions executed by the benchmark since it last started. - transactionCount int64 - - // The number of blocks that have been executed since the last commit. - uncommittedBlockCount int64 - - // The current batch of changesets waiting to be committed. Represents changes we are accumulating - // as part of a simulated "block". - batch *SyncMap[string, *proto.NamedChangeSet] - - // A count of the number of transactions in the current batch. - transactionsInCurrentBlock int64 - - // The address of the fee account (i.e. the account that collects gas fees). This is a special account - // and has account ID 0. Since we reuse this account very often, it is cached for performance. - feeCollectionAddress []byte - // If this much time has passed since the last console update, the benchmark will print a report to the console. consoleUpdatePeriod time.Duration @@ -66,6 +39,9 @@ type CryptoSim struct { // The data generator for the benchmark. dataGenerator *DataGenerator + + // The database for the benchmark. + database *Database } // Creates a new cryptosim benchmark runner. @@ -93,18 +69,15 @@ func NewCryptoSim( fmt.Printf("Initializing random number generator.\n") rand := NewCannedRandom(config.CannedRandomSize, config.Seed) - feeCollectionAddress := evm.BuildMemIAVLEVMKey( - evm.EVMKeyCode, - rand.Address(accountPrefix, 0), - ) - consoleUpdatePeriod := time.Duration(config.ConsoleUpdateIntervalSeconds * float64(time.Second)) start := time.Now() ctx, cancel := context.WithCancel(ctx) - dataGenerator, err := NewDataGenerator(db, rand) + database := NewDatabase(config, db) + + dataGenerator, err := NewDataGenerator(config, database, rand) if err != nil { cancel() db.Close() @@ -115,15 +88,12 @@ func NewCryptoSim( ctx: ctx, cancel: cancel, config: config, - db: db, - rand: rand, - batch: NewSyncMap[string, *proto.NamedChangeSet](), - feeCollectionAddress: feeCollectionAddress, consoleUpdatePeriod: consoleUpdatePeriod, lastConsoleUpdateTime: start, lastConsoleUpdateTransactionCount: 0, runHaltedChan: make(chan struct{}, 1), dataGenerator: dataGenerator, + database: database, } err = c.setup() @@ -170,12 +140,12 @@ func (c *CryptoSim) setupAccounts() error { break } - _, _, err := c.dataGenerator.CreateNewAccount(c, c.config.PaddedAccountSize, true) + _, _, err := c.dataGenerator.CreateNewAccount(c.config.PaddedAccountSize, true) if err != nil { return fmt.Errorf("failed to create new account: %w", err) } - c.transactionsInCurrentBlock++ - err = c.maybeFinalizeBlock() + c.database.IncrementTransactionCount() + err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { return fmt.Errorf("failed to maybe commit batch: %w", err) } @@ -190,13 +160,10 @@ func (c *CryptoSim) setupAccounts() error { } fmt.Printf("Created %s of %s accounts.\n", int64Commas(c.dataGenerator.NextAccountID()), int64Commas(int64(c.config.MinimumNumberOfAccounts))) - if err := c.finalizeBlock(); err != nil { - return fmt.Errorf("failed to commit block: %w", err) - } - if _, err := c.db.Commit(); err != nil { - return fmt.Errorf("failed to commit database: %w", err) + err := c.database.FinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID(), true) + if err != nil { + return fmt.Errorf("failed to finalize block: %w", err) } - c.uncommittedBlockCount = 0 fmt.Printf("There are now %d accounts in the database.\n", c.dataGenerator.NextAccountID()) @@ -225,13 +192,13 @@ func (c *CryptoSim) setupErc20Contracts() error { break } - c.transactionsInCurrentBlock++ + c.database.IncrementTransactionCount() _, _, err := c.dataGenerator.CreateNewErc20Contract(c, c.config.Erc20ContractSize, true) if err != nil { return fmt.Errorf("failed to create new ERC20 contract: %w", err) } - err = c.maybeFinalizeBlock() + err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { return fmt.Errorf("failed to maybe commit batch: %w", err) } @@ -243,26 +210,15 @@ func (c *CryptoSim) setupErc20Contracts() error { } } - // As a final step, write the ERC20 contract ID counter to the database. - data := make([]byte, 8) - binary.BigEndian.PutUint64(data, uint64(c.dataGenerator.NextErc20ContractID())) - err := c.put(Erc20IDCounterKey(), data) - if err != nil { - return fmt.Errorf("failed to put ERC20 contract ID counter: %w", err) - } - if c.dataGenerator.NextErc20ContractID() >= c.config.SetupUpdateIntervalCount { fmt.Printf("\n") } fmt.Printf("Created %s of %s simulated ERC20 contracts.\n", int64Commas(c.dataGenerator.NextErc20ContractID()), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) - if err := c.finalizeBlock(); err != nil { - return fmt.Errorf("failed to commit block: %w", err) - } - if _, err := c.db.Commit(); err != nil { - return fmt.Errorf("failed to commit database: %w", err) + err := c.database.FinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID(), true) + if err != nil { + return fmt.Errorf("failed to finalize block: %w", err) } - c.uncommittedBlockCount = 0 fmt.Printf("There are now %d simulated ERC20 contracts in the database.\n", c.dataGenerator.NextErc20ContractID()) @@ -279,33 +235,32 @@ func (c *CryptoSim) run() { for { select { case <-c.ctx.Done(): - if c.transactionCount > 0 { + if c.database.TransactionCount() > 0 { c.generateConsoleReport(true) fmt.Printf("\nTransaction workload halted.\n") } return default: - txn, err := BuildTransaction(c, c.dataGenerator) + txn, err := BuildTransaction(c.dataGenerator) if err != nil { fmt.Printf("\nfailed to build transaction: %v\n", err) continue } - err = txn.Execute(c) + err = txn.Execute(c.database, c.dataGenerator.FeeCollectionAddress()) if err != nil { fmt.Printf("\nfailed to execute transaction: %v\n", err) continue } - err = c.maybeFinalizeBlock() + err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { fmt.Printf("error finalizing block: %v\n", err) continue } - c.transactionCount++ - c.transactionsInCurrentBlock++ + c.database.IncrementTransactionCount() c.generateConsoleReport(false) } } @@ -318,7 +273,7 @@ func (c *CryptoSim) generateConsoleReport(force bool) { now := time.Now() timeSinceLastUpdate := now.Sub(c.lastConsoleUpdateTime) - transactionsSinceLastUpdate := c.transactionCount - c.lastConsoleUpdateTransactionCount + transactionsSinceLastUpdate := c.database.TransactionCount() - c.lastConsoleUpdateTransactionCount if !force && timeSinceLastUpdate < c.consoleUpdatePeriod && @@ -329,197 +284,32 @@ func (c *CryptoSim) generateConsoleReport(force bool) { } c.lastConsoleUpdateTime = now - c.lastConsoleUpdateTransactionCount = c.transactionCount + c.lastConsoleUpdateTransactionCount = c.database.TransactionCount() totalElapsedTime := now.Sub(c.startTimestamp) - transactionsPerSecond := float64(c.transactionCount) / totalElapsedTime.Seconds() + transactionsPerSecond := float64(c.database.TransactionCount()) / totalElapsedTime.Seconds() // Generate the report. fmt.Printf("%s txns executed in %v (%s txns/sec), total number of accounts: %s\r", - int64Commas(c.transactionCount), + int64Commas(c.database.TransactionCount()), totalElapsedTime, formatNumberFloat64(transactionsPerSecond, 2), int64Commas(c.dataGenerator.NextAccountID())) } -// Select a random account for a transaction. If an existing account is selected then its ID is guaranteed to be -// less or equal to maxAccountID. If a new account is created, it may have an ID greater than maxAccountID. -func (c *CryptoSim) randomAccount(maxAccountID int64) (id int64, address []byte, isNew bool, err error) { - hot := c.rand.Float64() < c.config.HotAccountProbability - - if hot { - firstHotAccountID := 1 - lastHotAccountID := c.config.HotAccountSetSize - accountID := c.rand.Int64Range(int64(firstHotAccountID), int64(lastHotAccountID+1)) - addr := c.rand.Address(accountPrefix, accountID) - return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil - } else { - - new := c.rand.Float64() < c.config.NewAccountProbability - if new { - id, address, err := c.dataGenerator.CreateNewAccount(c, c.config.PaddedAccountSize, false) - if err != nil { - return 0, nil, false, fmt.Errorf("failed to create new account: %w", err) - } - return id, address, true, nil - } - - // select an existing account at random - - firstNonHotAccountID := c.config.HotAccountSetSize + 1 - accountID := c.rand.Int64Range(int64(firstNonHotAccountID), maxAccountID+1) - addr := c.rand.Address(accountPrefix, accountID) - return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil - } -} - -// Selects a random account slot for a transaction. -func (c *CryptoSim) randomAccountSlot(accountID int64) ([]byte, error) { - slotNumber := c.rand.Int64Range(0, int64(c.config.Erc20InteractionsPerAccount)) - slotID := accountID*int64(c.config.Erc20InteractionsPerAccount) + slotNumber - - addr := c.rand.Address(ethStoragePrefix, slotID) - return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil -} - -// Selects a random ERC20 contract for a transaction. -func (c *CryptoSim) randomErc20Contract() ([]byte, error) { - - hot := c.rand.Float64() < c.config.HotErc20ContractProbability - - if hot { - erc20ContractID := c.rand.Int64Range(0, int64(c.config.HotErc20ContractSetSize)) - addr := c.rand.Address(contractPrefix, erc20ContractID) - return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil - } - - // Otherwise, select a cold ERC20 contract at random. - - erc20ContractID := c.rand.Int64Range(int64(c.config.HotErc20ContractSetSize), int64(c.dataGenerator.NextErc20ContractID())) - addr := c.rand.Address(contractPrefix, erc20ContractID) - return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil -} - -// Commit the current batch if it has reached the configured number of transactions. -func (c *CryptoSim) maybeFinalizeBlock() error { - if c.transactionsInCurrentBlock >= int64(c.config.TransactionsPerBlock) { - return c.finalizeBlock() - } - return nil -} - -// Push the current block out to the database. -func (c *CryptoSim) finalizeBlock() error { - if c.transactionsInCurrentBlock == 0 { - return nil - } - - c.transactionsInCurrentBlock = 0 - - changeSets := make([]*proto.NamedChangeSet, 0, c.transactionsInCurrentBlock+1) - for _, cs := range c.batch.Iterator() { - changeSets = append(changeSets, cs) - } - c.batch.Clear() - - // Persist the account ID counter in every batch. - nonceValue := make([]byte, 8) - binary.BigEndian.PutUint64(nonceValue, uint64(c.dataGenerator.NextAccountID())) - changeSets = append(changeSets, &proto.NamedChangeSet{ - Name: wrappers.EVMStoreName, - Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ - {Key: AccountIDCounterKey(), Value: nonceValue}, - }}, - }) - - err := c.db.ApplyChangeSets(changeSets) - if err != nil { - return fmt.Errorf("failed to apply change sets: %w", err) - } - - // Periodically commit the changes to the database. - c.uncommittedBlockCount++ - if c.uncommittedBlockCount >= int64(c.config.BlocksPerCommit) { - _, err := c.db.Commit() - if err != nil { - return fmt.Errorf("failed to commit: %w", err) - } - c.uncommittedBlockCount = 0 - } - - return nil -} - -// Insert a key-value pair into the database/cache. -// -// This method is safe to call concurrently with other calls to put() and get(). Is not thread -// safe with finalizeBlock(). -func (c *CryptoSim) put(key []byte, value []byte) error { - stringKey := string(key) - - pending, found := c.batch.Get(stringKey) - if found { - pending.Changeset.Pairs[0].Value = value - return nil - } - - c.batch.Put(stringKey, &proto.NamedChangeSet{ - Name: wrappers.EVMStoreName, - Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ - {Key: key, Value: value}, - }}, - }) - - return nil -} - -// Retrieve a value from the database/cache. -// -// This method is safe to call concurrently with other calls to put() and get(). Is not thread -// safe with finalizeBlock(). -func (c *CryptoSim) get(key []byte) ([]byte, bool, error) { - stringKey := string(key) - - pending, found := c.batch.Get(stringKey) - if found { - return pending.Changeset.Pairs[0].Value, true, nil - } - - value, found, err := c.db.Read(key) - if err != nil { - return nil, false, fmt.Errorf("failed to read from database: %w", err) - } - if found { - return value, true, nil - } - - return nil, false, nil -} - // Shut down the benchmark and release any resources. func (c *CryptoSim) Close() error { c.cancel() <-c.runHaltedChan - fmt.Printf("Committing final batch.\n") - - if err := c.finalizeBlock(); err != nil { - return fmt.Errorf("failed to commit batch: %w", err) - } - if _, err := c.db.Commit(); err != nil { - return fmt.Errorf("failed to commit database: %w", err) - } - - fmt.Printf("Closing database.\n") - err := c.db.Close() + err := c.database.Close(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { return fmt.Errorf("failed to close database: %w", err) } - fmt.Printf("Benchmark terminated successfully.\n") + c.dataGenerator.Close() - // Specifically release rand, since it's likely to hold a lot of memory. - c.rand = nil + fmt.Printf("Benchmark terminated successfully.\n") return nil } diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go index 86e9cecca3..e1bc052b38 100644 --- a/sei-db/state_db/bench/cryptosim/data_generator.go +++ b/sei-db/state_db/bench/cryptosim/data_generator.go @@ -5,7 +5,6 @@ import ( "fmt" "github.com/sei-protocol/sei-chain/sei-db/common/evm" - "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" ) const ( @@ -17,18 +16,33 @@ const ( // Generates random data for the benchmark. This is not a thread safe utility. type DataGenerator struct { - nextAccountID int64 + config *CryptoSimConfig + + // The next account ID to be used when creating a new account. + nextAccountID int64 + + // The next ERC20 contract ID to be used when creating a new ERC20 contract. nextErc20ContractID int64 + // The random number generator. rand *CannedRandom + + // The address of the fee account (i.e. the account that collects gas fees). This is a special account + // and has account ID 0. Since we reuse this account very often, it is cached for performance. + feeCollectionAddress []byte + + // The database for the benchmark. + database *Database } // Creates a new data generator. func NewDataGenerator( - db wrappers.DBWrapper, - rand *CannedRandom) (*DataGenerator, error) { + config *CryptoSimConfig, + database *Database, + rand *CannedRandom, +) (*DataGenerator, error) { - nextAccountIDBinary, found, err := db.Read(AccountIDCounterKey()) + nextAccountIDBinary, found, err := database.Get(AccountIDCounterKey()) if err != nil { return nil, fmt.Errorf("failed to read account counter: %w", err) } @@ -39,11 +53,7 @@ func NewDataGenerator( fmt.Printf("There are currently %s keys in the database.\n", int64Commas(nextAccountID)) - // erc20IdCounterBytes := make([]byte, 20) - // copy(erc20IdCounterBytes, []byte(erc20IdCounterKey)) - // erc20IDCounterKey := evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, erc20IdCounterBytes) - - nextErc20ContractIDBinary, found, err := db.Read(Erc20IDCounterKey()) + nextErc20ContractIDBinary, found, err := database.Get(Erc20IDCounterKey()) if err != nil { return nil, fmt.Errorf("failed to read ERC20 contract counter: %w", err) } @@ -54,23 +64,21 @@ func NewDataGenerator( fmt.Printf("There are currently %s ERC20 contracts in the database.\n", int64Commas(nextErc20ContractID)) + feeCollectionAddress := evm.BuildMemIAVLEVMKey( + evm.EVMKeyCode, + rand.Address(accountPrefix, 0), + ) + return &DataGenerator{ - nextAccountID: nextAccountID, - nextErc20ContractID: nextErc20ContractID, - rand: rand, + config: config, + nextAccountID: nextAccountID, + nextErc20ContractID: nextErc20ContractID, + rand: rand, + feeCollectionAddress: feeCollectionAddress, + database: database, }, nil } -// Get the key for the account ID counter in the database. -func AccountIDCounterKey() []byte { - return evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, []byte(accountIdCounterKey)) -} - -// Get the key for the ERC20 contract ID counter in the database. -func Erc20IDCounterKey() []byte { - return evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, []byte(erc20IdCounterKey)) -} - // Get the next account ID to be used when creating a new account. This is also the total number of accounts // currently in the database. func (d *DataGenerator) NextAccountID() int64 { @@ -85,7 +93,6 @@ func (d *DataGenerator) NextErc20ContractID() int64 { // Creates a new account and optionally writes it to the database. Returns the address of the new account. func (d *DataGenerator) CreateNewAccount( - cryptosim *CryptoSim, // The number of bytes to allocate for the account data. accountSize int, // If true, the account will be immediately written to the database. @@ -113,7 +120,7 @@ func (d *DataGenerator) CreateNewAccount( randomBytes := d.rand.Bytes(accountSize - 8) copy(accountData[8:], randomBytes) - err = cryptosim.put(address, accountData) + err = d.database.Put(address, accountData) if err != nil { return 0, nil, fmt.Errorf("failed to put account: %w", err) } @@ -143,10 +150,83 @@ func (d *DataGenerator) CreateNewErc20Contract( randomBytes := d.rand.Bytes(erc20ContractSize) copy(erc20Data, randomBytes) - err = cryptosim.put(address, erc20Data) + err = d.database.Put(address, erc20Data) if err != nil { return 0, nil, fmt.Errorf("failed to put ERC20 contract: %w", err) } return erc20ContractID, address, nil } + +// Select a random account for a transaction. If an existing account is selected then its ID is guaranteed to be +// less or equal to maxAccountID. If a new account is created, it may have an ID greater than maxAccountID. +func (d *DataGenerator) RandomAccount(maxAccountID int64) (id int64, address []byte, isNew bool, err error) { + + hot := d.rand.Float64() < d.config.HotAccountProbability + + if hot { + firstHotAccountID := 1 + lastHotAccountID := d.config.HotAccountSetSize + accountID := d.rand.Int64Range(int64(firstHotAccountID), int64(lastHotAccountID+1)) + addr := d.rand.Address(accountPrefix, accountID) + return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil + } else { + + new := d.rand.Float64() < d.config.NewAccountProbability + if new { + // create a new account + id, address, err := d.CreateNewAccount(d.config.PaddedAccountSize, false) + if err != nil { + return 0, nil, false, fmt.Errorf("failed to create new account: %w", err) + } + return id, address, true, nil + } + + // select an existing account at random + + firstNonHotAccountID := d.config.HotAccountSetSize + 1 + accountID := d.rand.Int64Range(int64(firstNonHotAccountID), maxAccountID+1) + addr := d.rand.Address(accountPrefix, accountID) + return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil + } +} + +// Selects a random account slot for a transaction. +func (d *DataGenerator) randomAccountSlot(accountID int64) ([]byte, error) { + slotNumber := d.rand.Int64Range(0, int64(d.config.Erc20InteractionsPerAccount)) + slotID := accountID*int64(d.config.Erc20InteractionsPerAccount) + slotNumber + + addr := d.rand.Address(ethStoragePrefix, slotID) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil +} + +// Selects a random ERC20 contract for a transaction. +func (d *DataGenerator) randomErc20Contract() ([]byte, error) { + + hot := d.rand.Float64() < d.config.HotErc20ContractProbability + + if hot { + erc20ContractID := d.rand.Int64Range(0, int64(d.config.HotErc20ContractSetSize)) + addr := d.rand.Address(contractPrefix, erc20ContractID) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil + } + + // Otherwise, select a cold ERC20 contract at random. + + erc20ContractID := d.rand.Int64Range( + int64(d.config.HotErc20ContractSetSize), + int64(d.nextAccountID)) + addr := d.rand.Address(contractPrefix, erc20ContractID) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil +} + +// Close the data generator and release any resources. +func (d *DataGenerator) Close() { + // Specifically release rand, since it's likely to hold a lot of memory. + d.rand = nil +} + +// Get the address of the fee collection account. +func (d *DataGenerator) FeeCollectionAddress() []byte { + return d.feeCollectionAddress +} diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go new file mode 100644 index 0000000000..864c209f00 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -0,0 +1,184 @@ +package cryptosim + +import ( + "encoding/binary" + "fmt" + + "github.com/sei-protocol/sei-chain/sei-db/proto" + "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" + iavl "github.com/sei-protocol/sei-chain/sei-iavl" +) + +// Encapsulates the database for the cryptosim benchmark. +type Database struct { + // The configuration for the benchmark. + config *CryptoSimConfig + + // The database implementation to use for the benchmark. + db wrappers.DBWrapper + + // The total number of transactions executed by the benchmark since it last started. + transactionCount int64 + + // A count of the number of transactions in the current batch. + transactionsInCurrentBlock int64 + + // The number of blocks that have been executed since the last commit. + uncommittedBlockCount int64 + + // The current batch of changesets waiting to be committed. Represents changes we are accumulating + // as part of a simulated "block". + batch *SyncMap[string, *proto.NamedChangeSet] +} + +// Creates a new database for the cryptosim benchmark. +func NewDatabase( + config *CryptoSimConfig, + db wrappers.DBWrapper, +) *Database { + return &Database{ + config: config, + db: db, + batch: NewSyncMap[string, *proto.NamedChangeSet](), + } +} + +// Insert a key-value pair into the database/cache. +// +// This method is safe to call concurrently with other calls to Put() and Get(). Is not thread +// safe with finalizeBlock(). +func (d *Database) Put(key []byte, value []byte) error { + stringKey := string(key) + + pending, found := d.batch.Get(stringKey) + if found { + pending.Changeset.Pairs[0].Value = value + return nil + } + + d.batch.Put(stringKey, &proto.NamedChangeSet{ + Name: wrappers.EVMStoreName, + Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ + {Key: key, Value: value}, + }}, + }) + + return nil +} + +// Retrieve a value from the database/cache. +// +// This method is safe to call concurrently with other calls to put() and get(). Is not thread +// safe with finalizeBlock(). +func (d *Database) Get(key []byte) ([]byte, bool, error) { + stringKey := string(key) + + pending, found := d.batch.Get(stringKey) + if found { + return pending.Changeset.Pairs[0].Value, true, nil + } + + value, found, err := d.db.Read(key) + if err != nil { + return nil, false, fmt.Errorf("failed to read from database: %w", err) + } + if found { + return value, true, nil + } + + return nil, false, nil +} + +// Signal that a transaction has been executed. +func (d *Database) IncrementTransactionCount() { + d.transactionCount++ +} + +// Get the total number of transactions executed by the benchmark since it last started. +func (d *Database) TransactionCount() int64 { + return d.transactionCount +} + +// Commit the current batch if it has reached the configured number of transactions. +func (d *Database) MaybeFinalizeBlock( + nextAccountID int64, + nextErc20ContractID int64, +) error { + if d.transactionsInCurrentBlock >= int64(d.config.TransactionsPerBlock) { + return d.FinalizeBlock(nextAccountID, nextErc20ContractID, false) + } + return nil +} + +// Push the current block out to the database. +func (d *Database) FinalizeBlock( + nextAccountID int64, + nextErc20ContractID int64, + forceCommit bool, +) error { + if d.transactionsInCurrentBlock == 0 { + return nil + } + + d.transactionsInCurrentBlock = 0 + + changeSets := make([]*proto.NamedChangeSet, 0, d.transactionsInCurrentBlock+2) + for _, cs := range d.batch.Iterator() { + changeSets = append(changeSets, cs) + } + d.batch.Clear() + + // Persist the account ID counter in every batch. + nonceValue := make([]byte, 8) + binary.BigEndian.PutUint64(nonceValue, uint64(nextAccountID)) + changeSets = append(changeSets, &proto.NamedChangeSet{ + Name: wrappers.EVMStoreName, + Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ + {Key: AccountIDCounterKey(), Value: nonceValue}, + }}, + }) + + err := d.db.ApplyChangeSets(changeSets) + if err != nil { + return fmt.Errorf("failed to apply change sets: %w", err) + } + + // Persist the ERC20 contract ID counter in every batch. + erc20ContractIDValue := make([]byte, 8) + binary.BigEndian.PutUint64(erc20ContractIDValue, uint64(nextErc20ContractID)) + changeSets = append(changeSets, &proto.NamedChangeSet{ + Name: wrappers.EVMStoreName, + Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ + {Key: Erc20IDCounterKey(), Value: erc20ContractIDValue}, + }}, + }) + + // Periodically commit the changes to the database. + d.uncommittedBlockCount++ + if forceCommit || d.uncommittedBlockCount >= int64(d.config.BlocksPerCommit) { + _, err := d.db.Commit() + if err != nil { + return fmt.Errorf("failed to commit: %w", err) + } + d.uncommittedBlockCount = 0 + } + + return nil +} + +// Close the database and release any resources. +func (d *Database) Close(nextAccountID int64, nextErc20ContractID int64) error { + fmt.Printf("Committing final batch.\n") + + if err := d.FinalizeBlock(nextAccountID, nextErc20ContractID, true); err != nil { + return fmt.Errorf("failed to commit batch: %w", err) + } + + fmt.Printf("Closing database.\n") + err := d.db.Close() + if err != nil { + return fmt.Errorf("failed to close database: %w", err) + } + + return nil +} diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index e37bc7e902..bcfbe72c88 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -47,7 +47,6 @@ type transaction struct { // // This method is not thread safe to call concurrently with other calls to BuildTransaction(). func BuildTransaction( - cryptosim *CryptoSim, dataGenerator *DataGenerator, ) (*transaction, error) { @@ -55,35 +54,35 @@ func BuildTransaction( // that ID may be greater than this value. maxAccountID := dataGenerator.NextAccountID() - 1 - srcAccountID, srcAccountAddress, isSrcNew, err := cryptosim.randomAccount(maxAccountID) + srcAccountID, srcAccountAddress, isSrcNew, err := dataGenerator.RandomAccount(maxAccountID) if err != nil { return nil, fmt.Errorf("failed to select source account: %w", err) } - dstAccountID, dstAccountAddress, isDstNew, err := cryptosim.randomAccount(maxAccountID) + dstAccountID, dstAccountAddress, isDstNew, err := dataGenerator.RandomAccount(maxAccountID) if err != nil { return nil, fmt.Errorf("failed to select destination account: %w", err) } - srcAccountSlot, err := cryptosim.randomAccountSlot(srcAccountID) + srcAccountSlot, err := dataGenerator.randomAccountSlot(srcAccountID) if err != nil { return nil, fmt.Errorf("failed to select source account slot: %w", err) } - dstAccountSlot, err := cryptosim.randomAccountSlot(dstAccountID) + dstAccountSlot, err := dataGenerator.randomAccountSlot(dstAccountID) if err != nil { return nil, fmt.Errorf("failed to select destination account slot: %w", err) } - erc20Contract, err := cryptosim.randomErc20Contract() + erc20Contract, err := dataGenerator.randomErc20Contract() if err != nil { return nil, fmt.Errorf("failed to select ERC20 contract: %w", err) } var newSrcData []byte if isSrcNew { - newSrcData = cryptosim.rand.Bytes(cryptosim.config.PaddedAccountSize) + newSrcData = dataGenerator.rand.Bytes(dataGenerator.config.PaddedAccountSize) } var newDstData []byte if isDstNew { - newDstData = cryptosim.rand.Bytes(cryptosim.config.PaddedAccountSize) + newDstData = dataGenerator.rand.Bytes(dataGenerator.config.PaddedAccountSize) } return &transaction{ @@ -96,11 +95,11 @@ func BuildTransaction( srcAccountSlot: srcAccountSlot, dstAccountSlot: dstAccountSlot, erc20Contract: erc20Contract, - newSrcBalance: cryptosim.rand.Int64(), - newDstBalance: cryptosim.rand.Int64(), - newFeeBalance: cryptosim.rand.Int64(), - newSrcAccountSlot: cryptosim.rand.Bytes(cryptosim.config.Erc20StorageSlotSize), - newDstAccountSlot: cryptosim.rand.Bytes(cryptosim.config.Erc20StorageSlotSize), + newSrcBalance: dataGenerator.rand.Int64(), + newDstBalance: dataGenerator.rand.Int64(), + newFeeBalance: dataGenerator.rand.Int64(), + newSrcAccountSlot: dataGenerator.rand.Bytes(dataGenerator.config.Erc20StorageSlotSize), + newDstAccountSlot: dataGenerator.rand.Bytes(dataGenerator.config.Erc20StorageSlotSize), }, nil } @@ -108,10 +107,13 @@ func BuildTransaction( // // This method is thread safe with other calls to Execute(), // but must not be called concurrently with CryptoSim.finalizeBlock(). -func (txn *transaction) Execute(cryptosim *CryptoSim) error { +func (txn *transaction) Execute( + database *Database, + feeCollectionAddress []byte, +) error { // Read the simulated ERC20 contract. - _, found, err := cryptosim.get(txn.erc20Contract) + _, found, err := database.Get(txn.erc20Contract) if err != nil { return fmt.Errorf("failed to get ERC20 contract: %w", err) } @@ -127,7 +129,7 @@ func (txn *transaction) Execute(cryptosim *CryptoSim) error { // - the fee collection account's native balance // Read the sender's native balance / nonce / codehash. - srcAccountValue, found, err := cryptosim.get(txn.srcAccount) + srcAccountValue, found, err := database.Get(txn.srcAccount) if err != nil { return fmt.Errorf("failed to get source account: %w", err) } @@ -146,7 +148,7 @@ func (txn *transaction) Execute(cryptosim *CryptoSim) error { } // Read the receiver's native balance. - dstAccountValue, found, err := cryptosim.get(txn.dstAccount) + dstAccountValue, found, err := database.Get(txn.dstAccount) if err != nil { return fmt.Errorf("failed to get destination account: %w", err) } @@ -165,20 +167,20 @@ func (txn *transaction) Execute(cryptosim *CryptoSim) error { // Read the sender's storage slot for the ERC20 contract. // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. - _, _, err = cryptosim.get(txn.srcAccountSlot) + _, _, err = database.Get(txn.srcAccountSlot) if err != nil { return fmt.Errorf("failed to get source account slot: %w", err) } // Read the receiver's storage slot for the ERC20 contract. // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. - _, _, err = cryptosim.get(txn.dstAccountSlot) + _, _, err = database.Get(txn.dstAccountSlot) if err != nil { return fmt.Errorf("failed to get destination account slot: %w", err) } // Read the fee collection account's native balance. - feeValue, found, err := cryptosim.get(cryptosim.feeCollectionAddress) + feeValue, found, err := database.Get(feeCollectionAddress) if err != nil { return fmt.Errorf("failed to get fee collection account: %w", err) } @@ -199,31 +201,31 @@ func (txn *transaction) Execute(cryptosim *CryptoSim) error { // - the fee collection account's native balance // Write the sender's account data. - err = cryptosim.put(txn.srcAccount, srcAccountValue) + err = database.Put(txn.srcAccount, srcAccountValue) if err != nil { return fmt.Errorf("failed to put source account: %w", err) } // Write the receiver's account data. - err = cryptosim.put(txn.dstAccount, dstAccountValue) + err = database.Put(txn.dstAccount, dstAccountValue) if err != nil { return fmt.Errorf("failed to put destination account: %w", err) } // Write the sender's storage slot for the ERC20 contract. - err = cryptosim.put(txn.srcAccountSlot, txn.newSrcAccountSlot) + err = database.Put(txn.srcAccountSlot, txn.newSrcAccountSlot) if err != nil { return fmt.Errorf("failed to put source account slot: %w", err) } // Write the receiver's storage slot for the ERC20 contract. - err = cryptosim.put(txn.dstAccountSlot, txn.newDstAccountSlot) + err = database.Put(txn.dstAccountSlot, txn.newDstAccountSlot) if err != nil { return fmt.Errorf("failed to put destination account slot: %w", err) } // Write the fee collection account's native balance. - err = cryptosim.put(cryptosim.feeCollectionAddress, feeValue) + err = database.Put(feeCollectionAddress, feeValue) if err != nil { return fmt.Errorf("failed to put fee collection account: %w", err) } diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go index ea762bcadb..3fa63f09df 100644 --- a/sei-db/state_db/bench/cryptosim/util.go +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -7,8 +7,20 @@ import ( "path/filepath" "strconv" "strings" + + "github.com/sei-protocol/sei-chain/sei-db/common/evm" ) +// Get the key for the account ID counter in the database. +func AccountIDCounterKey() []byte { + return evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, []byte(accountIdCounterKey)) +} + +// Get the key for the ERC20 contract ID counter in the database. +func Erc20IDCounterKey() []byte { + return evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, []byte(erc20IdCounterKey)) +} + // Hash64 returns a well-distributed 64-bit hash of x. // It implements the SplitMix64 finalizer, a fast non-cryptographic mixing // function with excellent avalanche properties. It is suitable for hash tables, From 847324dd96b01b9f11d7745573eb87a858781687 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 16:48:28 -0600 Subject: [PATCH 16/49] bugfixes --- .../state_db/bench/cryptosim/canned_random.go | 35 ++++++++++--------- sei-db/state_db/bench/cryptosim/cryptosim.go | 19 ++++++++-- .../bench/cryptosim/data_generator.go | 26 +++++++------- sei-db/state_db/bench/cryptosim/database.go | 1 + sei-db/state_db/bench/cryptosim/util.go | 13 +++++-- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/canned_random.go b/sei-db/state_db/bench/cryptosim/canned_random.go index e82bd7b48c..eb9895b4c3 100644 --- a/sei-db/state_db/bench/cryptosim/canned_random.go +++ b/sei-db/state_db/bench/cryptosim/canned_random.go @@ -119,33 +119,36 @@ func (cr *CannedRandom) Bool() bool { return cr.Int64()%2 == 0 } -// Generate a random 20 byte address suitable for use simulating an eth-style address. -// For the same input arguments, a canned random generator with the same seed and size will produce -// deterministic results addresses. +// Address generates a deterministic byte sequence suitable for simulating keys. +// For the same input arguments, a canned random generator with the same seed and buffer size +// will produce the same output. // -// Addresses have the following shape: +// The first AddressLen bytes have the following shape (eth-style address): // -// 1 byte addressType -// 8 bytes of random data -// 8 bytes containing the ID -// 3 bytes of random data (to bring the total to 20 bytes) +// 1 byte addressType +// 8 bytes of random data +// 8 bytes containing the ID +// the remainder is filled with random data // -// The ID is not included in the begining so that adjacent IDs will not appear close to each other if addresses -// are sorted in lexicographic order. +// The ID is not at the beginning so that adjacent IDs will not appear close to each other +// if keys are sorted lexicographically. If size > AddressLen, the remainder is filled with +// additional deterministic random bytes seeded by id. func (cr *CannedRandom) Address( - // A one-char byte descriptor. Allows for keys for different types of things to have different values + // A one-char byte descriptor. Allows keys for different types to have different values // even if they have the same ID. addressType uint8, // A unique ID for the key. id int64, - + // Total size in bytes. Must be at least AddressLen. + size int, ) []byte { + if size < AddressLen { + panic(fmt.Sprintf("size must be at least %d, got %d", AddressLen, size)) + } - result := make([]byte, 20) - - baseBytes := cr.SeededBytes(20, id) + result := make([]byte, size) + baseBytes := cr.SeededBytes(AddressLen, id) copy(result, baseBytes) - result[0] = addressType binary.BigEndian.PutUint64(result[9:], uint64(id)) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 4df1bd6131..13f4252c58 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -3,6 +3,7 @@ package cryptosim import ( "context" "fmt" + "os" "time" "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" @@ -14,6 +15,13 @@ const ( ethStoragePrefix = 's' ) +// EVM key sizes (matches sei-db/common/evm). +const ( + AddressLen = 20 // EVM address length + SlotLen = 32 // EVM storage slot length + StorageKeyLen = AddressLen + SlotLen +) + // The test runner for the cryptosim benchmark. type CryptoSim struct { ctx context.Context @@ -120,6 +128,7 @@ func (c *CryptoSim) setup() error { return nil } +// Prepopulate the database with the minimum number of accounts. func (c *CryptoSim) setupAccounts() error { // Ensure that we at least have as many accounts as the hot set + 2. This simplifies logic elsewhere. if c.config.MinimumNumberOfAccounts < c.config.HotAccountSetSize+2 { @@ -160,6 +169,7 @@ func (c *CryptoSim) setupAccounts() error { } fmt.Printf("Created %s of %s accounts.\n", int64Commas(c.dataGenerator.NextAccountID()), int64Commas(int64(c.config.MinimumNumberOfAccounts))) + err := c.database.FinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID(), true) if err != nil { return fmt.Errorf("failed to finalize block: %w", err) @@ -170,6 +180,7 @@ func (c *CryptoSim) setupAccounts() error { return nil } +// Prepopulate the database with the minimum number of ERC20 contracts. func (c *CryptoSim) setupErc20Contracts() error { // Ensure that we at least have as many ERC20 contracts as the hot set + 1. This simplifies logic elsewhere. @@ -213,8 +224,10 @@ func (c *CryptoSim) setupErc20Contracts() error { if c.dataGenerator.NextErc20ContractID() >= c.config.SetupUpdateIntervalCount { fmt.Printf("\n") } + fmt.Printf("Created %s of %s simulated ERC20 contracts.\n", int64Commas(c.dataGenerator.NextErc20ContractID()), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) + err := c.database.FinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID(), true) if err != nil { return fmt.Errorf("failed to finalize block: %w", err) @@ -245,19 +258,19 @@ func (c *CryptoSim) run() { txn, err := BuildTransaction(c.dataGenerator) if err != nil { fmt.Printf("\nfailed to build transaction: %v\n", err) - continue + os.Exit(1) // TODO use more elegant teardown mechanism } err = txn.Execute(c.database, c.dataGenerator.FeeCollectionAddress()) if err != nil { fmt.Printf("\nfailed to execute transaction: %v\n", err) - continue + os.Exit(1) } err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { fmt.Printf("error finalizing block: %v\n", err) - continue + os.Exit(1) } c.database.IncrementTransactionCount() diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go index e1bc052b38..3c34babf68 100644 --- a/sei-db/state_db/bench/cryptosim/data_generator.go +++ b/sei-db/state_db/bench/cryptosim/data_generator.go @@ -64,9 +64,10 @@ func NewDataGenerator( fmt.Printf("There are currently %s ERC20 contracts in the database.\n", int64Commas(nextErc20ContractID)) + // Use EVMKeyCode for account data; EVMKeyNonce only accepts 8-byte values. feeCollectionAddress := evm.BuildMemIAVLEVMKey( evm.EVMKeyCode, - rand.Address(accountPrefix, 0), + rand.Address(accountPrefix, 0, AddressLen), ) return &DataGenerator{ @@ -102,8 +103,8 @@ func (d *DataGenerator) CreateNewAccount( accountID := d.nextAccountID d.nextAccountID++ - // Use memiavl code key format (0x07 + addr) so FlatKV persists account data. - addr := d.rand.Address(accountPrefix, accountID) + // Use EVMKeyCode for account data (balance+padding); EVMKeyNonce only accepts 8-byte values. + addr := d.rand.Address(accountPrefix, accountID, AddressLen) address = evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr) if !write { @@ -139,8 +140,8 @@ func (d *DataGenerator) CreateNewErc20Contract( erc20ContractID := d.nextErc20ContractID d.nextErc20ContractID++ - erc20Address := d.rand.Address(contractPrefix, erc20ContractID) - address = evm.BuildMemIAVLEVMKey(evm.EVMKeyStorage, erc20Address) + erc20Address := d.rand.Address(contractPrefix, erc20ContractID, AddressLen) + address = evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, erc20Address) if !write { return erc20ContractID, address, nil @@ -168,7 +169,7 @@ func (d *DataGenerator) RandomAccount(maxAccountID int64) (id int64, address []b firstHotAccountID := 1 lastHotAccountID := d.config.HotAccountSetSize accountID := d.rand.Int64Range(int64(firstHotAccountID), int64(lastHotAccountID+1)) - addr := d.rand.Address(accountPrefix, accountID) + addr := d.rand.Address(accountPrefix, accountID, AddressLen) return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil } else { @@ -186,18 +187,19 @@ func (d *DataGenerator) RandomAccount(maxAccountID int64) (id int64, address []b firstNonHotAccountID := d.config.HotAccountSetSize + 1 accountID := d.rand.Int64Range(int64(firstNonHotAccountID), maxAccountID+1) - addr := d.rand.Address(accountPrefix, accountID) + addr := d.rand.Address(accountPrefix, accountID, AddressLen) return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil } } // Selects a random account slot for a transaction. +// Uses EVMKeyStorage with addr||slot (AddressLen+SlotLen bytes) for proper storage slot format. func (d *DataGenerator) randomAccountSlot(accountID int64) ([]byte, error) { slotNumber := d.rand.Int64Range(0, int64(d.config.Erc20InteractionsPerAccount)) slotID := accountID*int64(d.config.Erc20InteractionsPerAccount) + slotNumber - addr := d.rand.Address(ethStoragePrefix, slotID) - return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil + storageKeyBytes := d.rand.Address(ethStoragePrefix, slotID, StorageKeyLen) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyStorage, storageKeyBytes), nil } // Selects a random ERC20 contract for a transaction. @@ -207,7 +209,7 @@ func (d *DataGenerator) randomErc20Contract() ([]byte, error) { if hot { erc20ContractID := d.rand.Int64Range(0, int64(d.config.HotErc20ContractSetSize)) - addr := d.rand.Address(contractPrefix, erc20ContractID) + addr := d.rand.Address(contractPrefix, erc20ContractID, AddressLen) return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } @@ -215,8 +217,8 @@ func (d *DataGenerator) randomErc20Contract() ([]byte, error) { erc20ContractID := d.rand.Int64Range( int64(d.config.HotErc20ContractSetSize), - int64(d.nextAccountID)) - addr := d.rand.Address(contractPrefix, erc20ContractID) + d.nextErc20ContractID) + addr := d.rand.Address(contractPrefix, erc20ContractID, AddressLen) return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 864c209f00..73172cb1f5 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -92,6 +92,7 @@ func (d *Database) Get(key []byte) ([]byte, bool, error) { // Signal that a transaction has been executed. func (d *Database) IncrementTransactionCount() { d.transactionCount++ + d.transactionsInCurrentBlock++ } // Get the total number of transactions executed by the benchmark since it last started. diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go index 3fa63f09df..41a0d3c144 100644 --- a/sei-db/state_db/bench/cryptosim/util.go +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -12,13 +12,22 @@ import ( ) // Get the key for the account ID counter in the database. +// Uses EVMKeyCode with padded keyBytes; EVMKeyNonce requires 20-byte addresses and +// non-standard lengths are routed to EVMKeyLegacy which FlatKV ignores. func AccountIDCounterKey() []byte { - return evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, []byte(accountIdCounterKey)) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, paddedCounterKey(accountIdCounterKey)) } // Get the key for the ERC20 contract ID counter in the database. func Erc20IDCounterKey() []byte { - return evm.BuildMemIAVLEVMKey(evm.EVMKeyNonce, []byte(erc20IdCounterKey)) + return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, paddedCounterKey(erc20IdCounterKey)) +} + +// paddedCounterKey pads the string to AddressLen bytes for use with EVM key builders. +func paddedCounterKey(s string) []byte { + b := make([]byte, AddressLen) + copy(b, s) + return b } // Hash64 returns a well-distributed 64-bit hash of x. From e81e42a0c9d129714649d14a5b7e127bd67dc0bb Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 16:51:31 -0600 Subject: [PATCH 17/49] bugfixes --- sei-db/state_db/bench/cryptosim/cryptosim.go | 1 + sei-db/state_db/bench/cryptosim/database.go | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 13f4252c58..094133afb5 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -109,6 +109,7 @@ func NewCryptoSim( return nil, fmt.Errorf("failed to setup benchmark: %w", err) } + c.database.ResetTransactionCount() c.startTimestamp = time.Now() go c.run() diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 73172cb1f5..e492901428 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -95,6 +95,12 @@ func (d *Database) IncrementTransactionCount() { d.transactionsInCurrentBlock++ } +// Reset the transaction count. Useful for when changing test phases. +func (d *Database) ResetTransactionCount() { + d.transactionCount = 0 + d.transactionsInCurrentBlock = 0 +} + // Get the total number of transactions executed by the benchmark since it last started. func (d *Database) TransactionCount() int64 { return d.transactionCount From 589baec45343b32d948a64804ed83608835f75e0 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 17:29:02 -0600 Subject: [PATCH 18/49] bugfixes --- sei-db/state_db/bench/cryptosim/cryptosim.go | 6 +++--- sei-db/state_db/bench/cryptosim/transaction.go | 10 ++++++---- sei-db/state_db/bench/cryptosim/util.go | 6 ++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 094133afb5..9b2e770152 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -176,7 +176,7 @@ func (c *CryptoSim) setupAccounts() error { return fmt.Errorf("failed to finalize block: %w", err) } - fmt.Printf("There are now %d accounts in the database.\n", c.dataGenerator.NextAccountID()) + fmt.Printf("There are now %s accounts in the database.\n", int64Commas(c.dataGenerator.NextAccountID())) return nil } @@ -259,7 +259,7 @@ func (c *CryptoSim) run() { txn, err := BuildTransaction(c.dataGenerator) if err != nil { fmt.Printf("\nfailed to build transaction: %v\n", err) - os.Exit(1) // TODO use more elegant teardown mechanism + // os.Exit(1) // TODO use more elegant teardown mechanism } err = txn.Execute(c.database, c.dataGenerator.FeeCollectionAddress()) @@ -271,7 +271,7 @@ func (c *CryptoSim) run() { err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { fmt.Printf("error finalizing block: %v\n", err) - os.Exit(1) + // os.Exit(1) } c.database.IncrementTransactionCount() diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index bcfbe72c88..b9f64c2bb4 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -78,11 +78,13 @@ func BuildTransaction( var newSrcData []byte if isSrcNew { - newSrcData = dataGenerator.rand.Bytes(dataGenerator.config.PaddedAccountSize) + b := dataGenerator.rand.Bytes(dataGenerator.config.PaddedAccountSize) + newSrcData = append([]byte(nil), b...) } var newDstData []byte if isDstNew { - newDstData = dataGenerator.rand.Bytes(dataGenerator.config.PaddedAccountSize) + b := dataGenerator.rand.Bytes(dataGenerator.config.PaddedAccountSize) + newDstData = append([]byte(nil), b...) } return &transaction{ @@ -98,8 +100,8 @@ func BuildTransaction( newSrcBalance: dataGenerator.rand.Int64(), newDstBalance: dataGenerator.rand.Int64(), newFeeBalance: dataGenerator.rand.Int64(), - newSrcAccountSlot: dataGenerator.rand.Bytes(dataGenerator.config.Erc20StorageSlotSize), - newDstAccountSlot: dataGenerator.rand.Bytes(dataGenerator.config.Erc20StorageSlotSize), + newSrcAccountSlot: append([]byte(nil), dataGenerator.rand.Bytes(dataGenerator.config.Erc20StorageSlotSize)...), + newDstAccountSlot: append([]byte(nil), dataGenerator.rand.Bytes(dataGenerator.config.Erc20StorageSlotSize)...), }, nil } diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go index 41a0d3c144..1debe38b15 100644 --- a/sei-db/state_db/bench/cryptosim/util.go +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -1,6 +1,7 @@ package cryptosim import ( + "encoding/hex" "fmt" "math" "os" @@ -11,6 +12,11 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/common/evm" ) +// BytesToHex returns a lowercase hex string with 0x prefix, suitable for printing binary keys or addresses. +func BytesToHex(b []byte) string { + return "0x" + hex.EncodeToString(b) +} + // Get the key for the account ID counter in the database. // Uses EVMKeyCode with padded keyBytes; EVMKeyNonce requires 20-byte addresses and // non-standard lengths are routed to EVMKeyLegacy which FlatKV ignores. From 0be6002aa584782936f3ff0024e055d9e9fd1bc4 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 17:48:55 -0600 Subject: [PATCH 19/49] Add threading --- sei-db/state_db/bench/cryptosim/cryptosim.go | 37 +++++++-- .../bench/cryptosim/cryptosim_config.go | 4 + sei-db/state_db/bench/cryptosim/database.go | 14 ++++ .../bench/cryptosim/transaction_executor.go | 75 +++++++++++++++++-- 4 files changed, 116 insertions(+), 14 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 9b2e770152..380c3a1b58 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -3,7 +3,7 @@ package cryptosim import ( "context" "fmt" - "os" + "runtime" "time" "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" @@ -50,6 +50,12 @@ type CryptoSim struct { // The database for the benchmark. database *Database + + // The transaction executors for the benchmark. Transactions are distributed round-robin to the executors. + executors []*TransactionExecutor + + // The index of the next executor to receive a transaction. + nextExecutorIndex int } // Creates a new cryptosim benchmark runner. @@ -92,6 +98,18 @@ func NewCryptoSim( return nil, fmt.Errorf("failed to create data generator: %w", err) } + threadCount := int(config.ThreadsPerCore)*runtime.NumCPU() + config.ConstantThreadCount + if threadCount < 1 { + threadCount = 1 + } + fmt.Printf("Running benchmark with %d threads.\n", threadCount) + + executors := make([]*TransactionExecutor, threadCount) + for i := range threadCount { + executors[i] = NewTransactionExecutor( + ctx, database, dataGenerator.FeeCollectionAddress(), config.ExecutorQueueSize) + } + c := &CryptoSim{ ctx: ctx, cancel: cancel, @@ -102,8 +120,11 @@ func NewCryptoSim( runHaltedChan: make(chan struct{}, 1), dataGenerator: dataGenerator, database: database, + executors: executors, } + database.SetFlushFunc(c.flushExecutors) + err = c.setup() if err != nil { return nil, fmt.Errorf("failed to setup benchmark: %w", err) @@ -262,11 +283,8 @@ func (c *CryptoSim) run() { // os.Exit(1) // TODO use more elegant teardown mechanism } - err = txn.Execute(c.database, c.dataGenerator.FeeCollectionAddress()) - if err != nil { - fmt.Printf("\nfailed to execute transaction: %v\n", err) - os.Exit(1) - } + c.executors[c.nextExecutorIndex].ScheduleForExecution(txn) + c.nextExecutorIndex = (c.nextExecutorIndex + 1) % len(c.executors) err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { @@ -327,3 +345,10 @@ func (c *CryptoSim) Close() error { return nil } + +// Blocks until all pending transactions sent to the executors have been executed. +func (c *CryptoSim) flushExecutors() { + for _, executor := range c.executors { + executor.Flush() + } +} diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index 7cbaba8fa8..a60c618c87 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -95,6 +95,9 @@ type CryptoSimConfig struct { // Increase or decrease the thread count by this many threads. Total thread count is a function of // ThreadsPerCore and ConstantThreadCount. ConstantThreadCount int + + // The size of the queue for each transaction executor. + ExecutorQueueSize int } // Returns the default configuration for the cryptosim benchmark. @@ -121,6 +124,7 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { SetupUpdateIntervalCount: 100_000, ThreadsPerCore: 1.0, ConstantThreadCount: 0, + ExecutorQueueSize: 64, } } diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index e492901428..d9ba871a72 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -29,6 +29,9 @@ type Database struct { // The current batch of changesets waiting to be committed. Represents changes we are accumulating // as part of a simulated "block". batch *SyncMap[string, *proto.NamedChangeSet] + + // A method that flushes the executors. + flushFunc func() } // Creates a new database for the cryptosim benchmark. @@ -123,6 +126,12 @@ func (d *Database) FinalizeBlock( nextErc20ContractID int64, forceCommit bool, ) error { + + // Wait for all transactions in the current block to be executed. + if d.flushFunc != nil { + d.flushFunc() + } + if d.transactionsInCurrentBlock == 0 { return nil } @@ -189,3 +198,8 @@ func (d *Database) Close(nextAccountID int64, nextErc20ContractID int64) error { return nil } + +// Set the function that flushes the executors. This setter is required to break a circular dependency. +func (d *Database) SetFlushFunc(flushFunc func()) { + d.flushFunc = flushFunc +} diff --git a/sei-db/state_db/bench/cryptosim/transaction_executor.go b/sei-db/state_db/bench/cryptosim/transaction_executor.go index 0c4d34db80..65caa6a5bf 100644 --- a/sei-db/state_db/bench/cryptosim/transaction_executor.go +++ b/sei-db/state_db/bench/cryptosim/transaction_executor.go @@ -1,22 +1,81 @@ package cryptosim +import "context" + type TransactionExecutor struct { - // The CryptoSim benchmark runner. - cryptoSim *CryptoSim + ctx context.Context + + // The database for the benchmark. + database *Database + + // The address of the fee collection account. + feeCollectionAddress []byte // The Incoming transactions to be executed. - workChan chan *any + workChan chan any +} + +// A request to flush the transaction executor. +type flushRequest struct { + doneChan chan struct{} } // A single threaded transaction executor. func NewTransactionExecutor( - cryptosim *CryptoSim, + ctx context.Context, + database *Database, + feeCollectionAddress []byte, queueSize int, ) *TransactionExecutor { - return &TransactionExecutor{ - cryptoSim: cryptosim, - workChan: make(chan *any, queueSize), + e := &TransactionExecutor{ + ctx: ctx, + database: database, + feeCollectionAddress: feeCollectionAddress, + workChan: make(chan any, queueSize), + } + + go e.mainLoop() + + return e +} + +// Schedule a transaction for execution. +func (e *TransactionExecutor) ScheduleForExecution(txn *transaction) { + select { + case <-e.ctx.Done(): + case e.workChan <- txn: } } -// TODO +// Blocks until all currently queued transactions have been executed. +func (e *TransactionExecutor) Flush() { + + request := flushRequest{doneChan: make(chan struct{}, 1)} + + select { + case <-e.ctx.Done(): + case e.workChan <- request: + } + + select { + case <-request.doneChan: + case <-e.ctx.Done(): + } +} + +func (e *TransactionExecutor) mainLoop() { + + for { + select { + case <-e.ctx.Done(): + return + case request := <-e.workChan: + switch request := request.(type) { + case *transaction: + request.Execute(e.database, e.feeCollectionAddress) + case flushRequest: + request.doneChan <- struct{}{} + } + } + } +} From 38ba919e8cfc1219ef1427bb28713e061a9a05b3 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Wed, 25 Feb 2026 17:49:54 -0600 Subject: [PATCH 20/49] cleanup --- sei-db/state_db/bench/cryptosim/cryptosim.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 380c3a1b58..5a559e76af 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -280,7 +280,6 @@ func (c *CryptoSim) run() { txn, err := BuildTransaction(c.dataGenerator) if err != nil { fmt.Printf("\nfailed to build transaction: %v\n", err) - // os.Exit(1) // TODO use more elegant teardown mechanism } c.executors[c.nextExecutorIndex].ScheduleForExecution(txn) @@ -289,7 +288,6 @@ func (c *CryptoSim) run() { err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { fmt.Printf("error finalizing block: %v\n", err) - // os.Exit(1) } c.database.IncrementTransactionCount() From d23cd806168947a2b71b9fac0713f48a6262a49b Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 09:01:20 -0600 Subject: [PATCH 21/49] Fixes suggested during AI code review --- sei-db/state_db/bench/cryptosim/cryptosim.go | 8 +-- .../bench/cryptosim/cryptosim_config.go | 59 ++++++++++++++++++- .../bench/cryptosim/data_generator.go | 14 ++++- sei-db/state_db/bench/cryptosim/database.go | 16 ++--- .../state_db/bench/cryptosim/transaction.go | 6 +- .../bench/cryptosim/transaction_executor.go | 9 ++- 6 files changed, 94 insertions(+), 18 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 5a559e76af..6d97fc0cf4 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -64,8 +64,8 @@ func NewCryptoSim( config *CryptoSimConfig, ) (*CryptoSim, error) { - if config.DataDir == "" { - return nil, fmt.Errorf("data directory is required") + if err := config.Validate(); err != nil { + return nil, fmt.Errorf("invalid config: %w", err) } dataDir, err := resolveAndCreateDataDir(config.DataDir) @@ -105,7 +105,7 @@ func NewCryptoSim( fmt.Printf("Running benchmark with %d threads.\n", threadCount) executors := make([]*TransactionExecutor, threadCount) - for i := range threadCount { + for i := 0; i < threadCount; i++ { executors[i] = NewTransactionExecutor( ctx, database, dataGenerator.FeeCollectionAddress(), config.ExecutorQueueSize) } @@ -255,7 +255,7 @@ func (c *CryptoSim) setupErc20Contracts() error { return fmt.Errorf("failed to finalize block: %w", err) } - fmt.Printf("There are now %d simulated ERC20 contracts in the database.\n", c.dataGenerator.NextErc20ContractID()) + fmt.Printf("There are now %s simulated ERC20 contracts in the database.\n", int64Commas(c.dataGenerator.NextErc20ContractID())) return nil } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index a60c618c87..c230581dec 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -8,6 +8,12 @@ import ( "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" ) +const ( + minPaddedAccountSize = 8 + minErc20StorageSlotSize = 32 + minErc20InteractionsPerAcct = 1 +) + // Defines the configuration for the cryptosim benchmark. type CryptoSimConfig struct { @@ -51,7 +57,7 @@ type CryptoSimConfig struct { // The size of a simulated ERC20 storage slot, in bytes. Erc20StorageSlotSize int - // The number of of ERC20 tokens that each account will interact with. + // The number of ERC20 tokens that each account will interact with. // Each account will have an eth storage slot for tracking the balance of each ERC20 token it owns. // It is not legal to modify this value after the benchmark has started. Erc20InteractionsPerAccount int @@ -100,6 +106,54 @@ type CryptoSimConfig struct { ExecutorQueueSize int } +// Validate checks that the configuration is sane and returns an error if not. +func (c *CryptoSimConfig) Validate() error { + if c.DataDir == "" { + return fmt.Errorf("DataDir is required") + } + if c.PaddedAccountSize < minPaddedAccountSize { + return fmt.Errorf("PaddedAccountSize must be at least %d (got %d)", minPaddedAccountSize, c.PaddedAccountSize) + } + if c.MinimumNumberOfAccounts < c.HotAccountSetSize+2 { + return fmt.Errorf("MinimumNumberOfAccounts must be at least HotAccountSetSize+2 (%d)", c.HotAccountSetSize+2) + } + if c.MinimumNumberOfErc20Contracts < c.HotErc20ContractSetSize+1 { + return fmt.Errorf("MinimumNumberOfErc20Contracts must be at least HotErc20ContractSetSize+1 (%d)", + c.HotErc20ContractSetSize+1) + } + if c.HotAccountProbability < 0 || c.HotAccountProbability > 1 { + return fmt.Errorf("HotAccountProbability must be in [0, 1] (got %f)", c.HotAccountProbability) + } + if c.NewAccountProbability < 0 || c.NewAccountProbability > 1 { + return fmt.Errorf("NewAccountProbability must be in [0, 1] (got %f)", c.NewAccountProbability) + } + if c.HotErc20ContractProbability < 0 || c.HotErc20ContractProbability > 1 { + return fmt.Errorf("HotErc20ContractProbability must be in [0, 1] (got %f)", c.HotErc20ContractProbability) + } + if c.Erc20StorageSlotSize < minErc20StorageSlotSize { + return fmt.Errorf("Erc20StorageSlotSize must be at least %d (got %d)", minErc20StorageSlotSize, c.Erc20StorageSlotSize) + } + if c.Erc20InteractionsPerAccount < minErc20InteractionsPerAcct { + return fmt.Errorf("Erc20InteractionsPerAccount must be at least %d (got %d)", minErc20InteractionsPerAcct, c.Erc20InteractionsPerAccount) + } + if c.TransactionsPerBlock < 1 { + return fmt.Errorf("TransactionsPerBlock must be at least 1 (got %d)", c.TransactionsPerBlock) + } + if c.BlocksPerCommit < 1 { + return fmt.Errorf("BlocksPerCommit must be at least 1 (got %d)", c.BlocksPerCommit) + } + if c.CannedRandomSize < 8 { + return fmt.Errorf("CannedRandomSize must be at least 8 (got %d)", c.CannedRandomSize) + } + if c.ExecutorQueueSize < 1 { + return fmt.Errorf("ExecutorQueueSize must be at least 1 (got %d)", c.ExecutorQueueSize) + } + if c.SetupUpdateIntervalCount < 1 { + return fmt.Errorf("SetupUpdateIntervalCount must be at least 1 (got %d)", c.SetupUpdateIntervalCount) + } + return nil +} + // Returns the default configuration for the cryptosim benchmark. func DefaultCryptoSimConfig() *CryptoSimConfig { return &CryptoSimConfig{ @@ -144,5 +198,8 @@ func LoadConfigFromFile(path string) (*CryptoSimConfig, error) { if err := dec.Decode(cfg); err != nil { return nil, fmt.Errorf("decode config: %w", err) } + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("invalid config: %w", err) + } return cfg, nil } diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go index 3c34babf68..60c253f89a 100644 --- a/sei-db/state_db/bench/cryptosim/data_generator.go +++ b/sei-db/state_db/bench/cryptosim/data_generator.go @@ -208,13 +208,23 @@ func (d *DataGenerator) randomErc20Contract() ([]byte, error) { hot := d.rand.Float64() < d.config.HotErc20ContractProbability if hot { - erc20ContractID := d.rand.Int64Range(0, int64(d.config.HotErc20ContractSetSize)) + hotMax := int64(d.config.HotErc20ContractSetSize) + if d.nextErc20ContractID < hotMax { + hotMax = d.nextErc20ContractID + } + if hotMax <= 0 { + return nil, fmt.Errorf("no ERC20 contracts available for hot selection") + } + erc20ContractID := d.rand.Int64Range(0, hotMax) addr := d.rand.Address(contractPrefix, erc20ContractID, AddressLen) return evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), nil } // Otherwise, select a cold ERC20 contract at random. - + if d.nextErc20ContractID <= int64(d.config.HotErc20ContractSetSize) { + return nil, fmt.Errorf("no cold ERC20 contracts available (have %d, hot set size %d)", + d.nextErc20ContractID, d.config.HotErc20ContractSetSize) + } erc20ContractID := d.rand.Int64Range( int64(d.config.HotErc20ContractSetSize), d.nextErc20ContractID) diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index d9ba871a72..98a408efe0 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -49,7 +49,7 @@ func NewDatabase( // Insert a key-value pair into the database/cache. // // This method is safe to call concurrently with other calls to Put() and Get(). Is not thread -// safe with finalizeBlock(). +// safe with FinalizeBlock(). func (d *Database) Put(key []byte, value []byte) error { stringKey := string(key) @@ -71,8 +71,8 @@ func (d *Database) Put(key []byte, value []byte) error { // Retrieve a value from the database/cache. // -// This method is safe to call concurrently with other calls to put() and get(). Is not thread -// safe with finalizeBlock(). +// This method is safe to call concurrently with other calls to Put() and Get(). Is not thread +// safe with FinalizeBlock(). func (d *Database) Get(key []byte) ([]byte, bool, error) { stringKey := string(key) @@ -154,11 +154,6 @@ func (d *Database) FinalizeBlock( }}, }) - err := d.db.ApplyChangeSets(changeSets) - if err != nil { - return fmt.Errorf("failed to apply change sets: %w", err) - } - // Persist the ERC20 contract ID counter in every batch. erc20ContractIDValue := make([]byte, 8) binary.BigEndian.PutUint64(erc20ContractIDValue, uint64(nextErc20ContractID)) @@ -169,6 +164,11 @@ func (d *Database) FinalizeBlock( }}, }) + err := d.db.ApplyChangeSets(changeSets) + if err != nil { + return fmt.Errorf("failed to apply change sets: %w", err) + } + // Periodically commit the changes to the database. d.uncommittedBlockCount++ if forceCommit || d.uncommittedBlockCount >= int64(d.config.BlocksPerCommit) { diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index b9f64c2bb4..ea3efd78fd 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -7,7 +7,7 @@ import ( // The data needed to execute a transaction. type transaction struct { - // The simualted ERC20 contract that will be interacted with. This value is read. + // The simulated ERC20 contract that will be interacted with. This value is read. erc20Contract []byte // The source account that will be interacted with. This value is read and written. @@ -191,6 +191,10 @@ func (txn *transaction) Execute( } // Apply the random values from the transaction to the account and slot data. + const minAccountBytes = 8 // balance at offset 0 + if len(srcAccountValue) < minAccountBytes || len(dstAccountValue) < minAccountBytes || len(feeValue) < minAccountBytes { + return fmt.Errorf("account value too short for balance update (need %d bytes)", minAccountBytes) + } binary.BigEndian.PutUint64(srcAccountValue[:8], uint64(txn.newSrcBalance)) binary.BigEndian.PutUint64(dstAccountValue[:8], uint64(txn.newDstBalance)) binary.BigEndian.PutUint64(feeValue[:8], uint64(txn.newFeeBalance)) diff --git a/sei-db/state_db/bench/cryptosim/transaction_executor.go b/sei-db/state_db/bench/cryptosim/transaction_executor.go index 65caa6a5bf..27478de53a 100644 --- a/sei-db/state_db/bench/cryptosim/transaction_executor.go +++ b/sei-db/state_db/bench/cryptosim/transaction_executor.go @@ -1,6 +1,9 @@ package cryptosim -import "context" +import ( + "context" + "log" +) type TransactionExecutor struct { ctx context.Context @@ -72,7 +75,9 @@ func (e *TransactionExecutor) mainLoop() { case request := <-e.workChan: switch request := request.(type) { case *transaction: - request.Execute(e.database, e.feeCollectionAddress) + if err := request.Execute(e.database, e.feeCollectionAddress); err != nil { + log.Printf("transaction execution error: %v", err) + } case flushRequest: request.doneChan <- struct{}{} } From ae91b2808a7710142d68f70fe0b0c4fbb6ae230d Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 09:59:34 -0600 Subject: [PATCH 22/49] fix rare race condition --- sei-db/state_db/bench/cryptosim/cryptosim.go | 27 +++++++++++++---- .../bench/cryptosim/cryptosim_config.go | 10 ++++--- .../bench/cryptosim/data_generator.go | 29 +++++++++++++----- sei-db/state_db/bench/cryptosim/database.go | 11 +++++-- .../state_db/bench/cryptosim/transaction.go | 8 ++--- sei-db/state_db/bench/cryptosim/util.go | 30 +++++++++++++++++++ 6 files changed, 88 insertions(+), 27 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 6d97fc0cf4..31b4d9613b 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -176,10 +176,14 @@ func (c *CryptoSim) setupAccounts() error { return fmt.Errorf("failed to create new account: %w", err) } c.database.IncrementTransactionCount() - err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) + finalized, err := c.database.MaybeFinalizeBlock( + c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { return fmt.Errorf("failed to maybe commit batch: %w", err) } + if finalized { + c.dataGenerator.ReportFinalizeBlock() + } if c.dataGenerator.NextAccountID()%c.config.SetupUpdateIntervalCount == 0 { fmt.Printf("Created %s of %s accounts.\r", @@ -196,6 +200,7 @@ func (c *CryptoSim) setupAccounts() error { if err != nil { return fmt.Errorf("failed to finalize block: %w", err) } + c.dataGenerator.ReportFinalizeBlock() fmt.Printf("There are now %s accounts in the database.\n", int64Commas(c.dataGenerator.NextAccountID())) @@ -231,10 +236,14 @@ func (c *CryptoSim) setupErc20Contracts() error { if err != nil { return fmt.Errorf("failed to create new ERC20 contract: %w", err) } - err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) + finalized, err := c.database.MaybeFinalizeBlock( + c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { return fmt.Errorf("failed to maybe commit batch: %w", err) } + if finalized { + c.dataGenerator.ReportFinalizeBlock() + } if c.dataGenerator.NextErc20ContractID()%c.config.SetupUpdateIntervalCount == 0 { fmt.Printf("Created %s of %s simulated ERC20 contracts.\r", @@ -254,8 +263,10 @@ func (c *CryptoSim) setupErc20Contracts() error { if err != nil { return fmt.Errorf("failed to finalize block: %w", err) } + c.dataGenerator.ReportFinalizeBlock() - fmt.Printf("There are now %s simulated ERC20 contracts in the database.\n", int64Commas(c.dataGenerator.NextErc20ContractID())) + fmt.Printf("There are now %s simulated ERC20 contracts in the database.\n", + int64Commas(c.dataGenerator.NextErc20ContractID())) return nil } @@ -285,10 +296,14 @@ func (c *CryptoSim) run() { c.executors[c.nextExecutorIndex].ScheduleForExecution(txn) c.nextExecutorIndex = (c.nextExecutorIndex + 1) % len(c.executors) - err = c.database.MaybeFinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) + finalized, err := c.database.MaybeFinalizeBlock( + c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { fmt.Printf("error finalizing block: %v\n", err) } + if finalized { + c.dataGenerator.ReportFinalizeBlock() + } c.database.IncrementTransactionCount() c.generateConsoleReport(false) @@ -320,9 +335,9 @@ func (c *CryptoSim) generateConsoleReport(force bool) { transactionsPerSecond := float64(c.database.TransactionCount()) / totalElapsedTime.Seconds() // Generate the report. - fmt.Printf("%s txns executed in %v (%s txns/sec), total number of accounts: %s\r", + fmt.Printf("%s txns executed in %s (%s txns/sec), total number of accounts: %s\r", int64Commas(c.database.TransactionCount()), - totalElapsedTime, + formatDuration(totalElapsedTime, 1), formatNumberFloat64(transactionsPerSecond, 2), int64Commas(c.dataGenerator.NextAccountID())) } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index c230581dec..b2e0776803 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -131,10 +131,12 @@ func (c *CryptoSimConfig) Validate() error { return fmt.Errorf("HotErc20ContractProbability must be in [0, 1] (got %f)", c.HotErc20ContractProbability) } if c.Erc20StorageSlotSize < minErc20StorageSlotSize { - return fmt.Errorf("Erc20StorageSlotSize must be at least %d (got %d)", minErc20StorageSlotSize, c.Erc20StorageSlotSize) + return fmt.Errorf("Erc20StorageSlotSize must be at least %d (got %d)", + minErc20StorageSlotSize, c.Erc20StorageSlotSize) } if c.Erc20InteractionsPerAccount < minErc20InteractionsPerAcct { - return fmt.Errorf("Erc20InteractionsPerAccount must be at least %d (got %d)", minErc20InteractionsPerAcct, c.Erc20InteractionsPerAccount) + return fmt.Errorf("Erc20InteractionsPerAccount must be at least %d (got %d)", + minErc20InteractionsPerAcct, c.Erc20InteractionsPerAccount) } if c.TransactionsPerBlock < 1 { return fmt.Errorf("TransactionsPerBlock must be at least 1 (got %d)", c.TransactionsPerBlock) @@ -158,7 +160,7 @@ func (c *CryptoSimConfig) Validate() error { func DefaultCryptoSimConfig() *CryptoSimConfig { return &CryptoSimConfig{ MinimumNumberOfAccounts: 1_000_000, - HotAccountProbability: 0.5, + HotAccountProbability: 0.1, NewAccountProbability: 0.001, HotAccountSetSize: 100, PaddedAccountSize: 69, // Not a joke, this is the actual size @@ -176,7 +178,7 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { ConsoleUpdateIntervalSeconds: 1, ConsoleUpdateIntervalTransactions: 1_000_000, SetupUpdateIntervalCount: 100_000, - ThreadsPerCore: 1.0, + ThreadsPerCore: 2.0, ConstantThreadCount: 0, ExecutorQueueSize: 64, } diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go index 60c253f89a..5635acd976 100644 --- a/sei-db/state_db/bench/cryptosim/data_generator.go +++ b/sei-db/state_db/bench/cryptosim/data_generator.go @@ -33,6 +33,13 @@ type DataGenerator struct { // The database for the benchmark. database *Database + + // The highest account ID that has been read in the current block. + // Since there are multiple threads of execution, it's possible that one executor may create a new account, + // and another may attempt to read/write it before the account is actually created. To avoid this, we will only + // choose read/write targets from acccounts that were created before the current block. This field tracks the + // highest account ID that was created before the current block. + highestSafeAccountIDInBlock int64 } // Creates a new data generator. @@ -71,12 +78,13 @@ func NewDataGenerator( ) return &DataGenerator{ - config: config, - nextAccountID: nextAccountID, - nextErc20ContractID: nextErc20ContractID, - rand: rand, - feeCollectionAddress: feeCollectionAddress, - database: database, + config: config, + nextAccountID: nextAccountID, + nextErc20ContractID: nextErc20ContractID, + rand: rand, + feeCollectionAddress: feeCollectionAddress, + database: database, + highestSafeAccountIDInBlock: nextAccountID - 1, }, nil } @@ -161,7 +169,7 @@ func (d *DataGenerator) CreateNewErc20Contract( // Select a random account for a transaction. If an existing account is selected then its ID is guaranteed to be // less or equal to maxAccountID. If a new account is created, it may have an ID greater than maxAccountID. -func (d *DataGenerator) RandomAccount(maxAccountID int64) (id int64, address []byte, isNew bool, err error) { +func (d *DataGenerator) RandomAccount() (id int64, address []byte, isNew bool, err error) { hot := d.rand.Float64() < d.config.HotAccountProbability @@ -186,7 +194,7 @@ func (d *DataGenerator) RandomAccount(maxAccountID int64) (id int64, address []b // select an existing account at random firstNonHotAccountID := d.config.HotAccountSetSize + 1 - accountID := d.rand.Int64Range(int64(firstNonHotAccountID), maxAccountID+1) + accountID := d.rand.Int64Range(int64(firstNonHotAccountID), d.highestSafeAccountIDInBlock+1) addr := d.rand.Address(accountPrefix, accountID, AddressLen) return accountID, evm.BuildMemIAVLEVMKey(evm.EVMKeyCode, addr), false, nil } @@ -242,3 +250,8 @@ func (d *DataGenerator) Close() { func (d *DataGenerator) FeeCollectionAddress() []byte { return d.feeCollectionAddress } + +// This method should be called after a block is finalized. +func (d *DataGenerator) ReportFinalizeBlock() { + d.highestSafeAccountIDInBlock = d.nextAccountID - 1 +} diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 98a408efe0..03fc9a02e5 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -110,14 +110,19 @@ func (d *Database) TransactionCount() int64 { } // Commit the current batch if it has reached the configured number of transactions. +// Returns true if the batch was finalized, false if not. func (d *Database) MaybeFinalizeBlock( nextAccountID int64, nextErc20ContractID int64, -) error { +) (bool, error) { if d.transactionsInCurrentBlock >= int64(d.config.TransactionsPerBlock) { - return d.FinalizeBlock(nextAccountID, nextErc20ContractID, false) + err := d.FinalizeBlock(nextAccountID, nextErc20ContractID, false) + if err != nil { + return false, fmt.Errorf("failed to finalize block: %w", err) + } + return true, nil } - return nil + return false, nil } // Push the current block out to the database. diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index ea3efd78fd..4a8e613513 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -50,15 +50,11 @@ func BuildTransaction( dataGenerator *DataGenerator, ) (*transaction, error) { - // The maximum account ID for existing transactions. If random account returns a new account ID, - // that ID may be greater than this value. - maxAccountID := dataGenerator.NextAccountID() - 1 - - srcAccountID, srcAccountAddress, isSrcNew, err := dataGenerator.RandomAccount(maxAccountID) + srcAccountID, srcAccountAddress, isSrcNew, err := dataGenerator.RandomAccount() if err != nil { return nil, fmt.Errorf("failed to select source account: %w", err) } - dstAccountID, dstAccountAddress, isDstNew, err := dataGenerator.RandomAccount(maxAccountID) + dstAccountID, dstAccountAddress, isDstNew, err := dataGenerator.RandomAccount() if err != nil { return nil, fmt.Errorf("failed to select destination account: %w", err) } diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go index 1debe38b15..355e1829e5 100644 --- a/sei-db/state_db/bench/cryptosim/util.go +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strconv" "strings" + "time" "github.com/sei-protocol/sei-chain/sei-db/common/evm" ) @@ -159,3 +160,32 @@ func formatNumberFloat64(f float64, decimals int) string { } return b.String() } + +// formatDuration formats d using the most appropriate unit (days, hours, minutes, seconds, ms, µs, ns). +func formatDuration(d time.Duration, decimals int) string { + if decimals < 0 { + decimals = 0 + } + format := fmt.Sprintf("%%.%df%%s", decimals) + ns := d.Nanoseconds() + abs := int64(ns) + if abs < 0 { + abs = -abs + } + switch { + case abs >= int64(24*time.Hour): + return fmt.Sprintf(format, float64(ns)/float64(time.Hour)/24, "d") + case abs >= int64(time.Hour): + return fmt.Sprintf(format, float64(ns)/float64(time.Hour), "h") + case abs >= int64(time.Minute): + return fmt.Sprintf(format, float64(ns)/float64(time.Minute), "m") + case abs >= int64(time.Second): + return fmt.Sprintf(format, float64(ns)/float64(time.Second), "s") + case abs >= int64(time.Millisecond): + return fmt.Sprintf(format, float64(ns)/float64(time.Millisecond), "ms") + case abs >= int64(time.Microsecond): + return fmt.Sprintf(format, float64(ns)/float64(time.Microsecond), "µs") + default: + return fmt.Sprintf(format, float64(ns), "ns") + } +} From 0c344029eef995acc0c57d52e447153fff7d5fc1 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 12:42:33 -0600 Subject: [PATCH 23/49] made suggested changes --- .../bench/cryptosim/config/basic-config.json | 28 ++++++-- sei-db/state_db/bench/cryptosim/cryptosim.go | 10 +-- .../bench/cryptosim/cryptosim_config.go | 68 ++++++++++--------- sei-db/state_db/bench/cryptosim/database.go | 38 ++++------- 4 files changed, 77 insertions(+), 67 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index 001849740d..bc8eca2430 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -1,6 +1,26 @@ { - "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", - "DataDir": "data", - "MinimumNumberOfAccounts": 100000 + "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", + "Backend": "FlatKV", + "BlocksPerCommit": 32, + "CannedRandomSize": 1073741824, + "ConstantThreadCount": 0, + "ConsoleUpdateIntervalSeconds": 1, + "ConsoleUpdateIntervalTransactions": 1000000, + "DataDir": "data", + "Erc20ContractSize": 2048, + "Erc20InteractionsPerAccount": 10, + "Erc20StorageSlotSize": 32, + "ExecutorQueueSize": 64, + "HotAccountProbability": 0.1, + "HotAccountSetSize": 100, + "HotErc20ContractProbability": 0.5, + "HotErc20ContractSetSize": 100, + "MinimumNumberOfAccounts": 1000000, + "MinimumNumberOfErc20Contracts": 10000, + "NewAccountProbability": 0.001, + "PaddedAccountSize": 69, + "Seed": 1337, + "SetupUpdateIntervalCount": 100000, + "ThreadsPerCore": 2.0, + "TransactionsPerBlock": 1024 } - diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 31b4d9613b..222b41695d 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -186,14 +186,14 @@ func (c *CryptoSim) setupAccounts() error { } if c.dataGenerator.NextAccountID()%c.config.SetupUpdateIntervalCount == 0 { - fmt.Printf("Created %s of %s accounts.\r", + fmt.Printf("Created %s of %s accounts. \r", int64Commas(c.dataGenerator.NextAccountID()), int64Commas(int64(c.config.MinimumNumberOfAccounts))) } } if c.dataGenerator.NextAccountID() >= c.config.SetupUpdateIntervalCount { fmt.Printf("\n") } - fmt.Printf("Created %s of %s accounts.\n", + fmt.Printf("Created %s of %s accounts. \n", int64Commas(c.dataGenerator.NextAccountID()), int64Commas(int64(c.config.MinimumNumberOfAccounts))) err := c.database.FinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID(), true) @@ -246,7 +246,7 @@ func (c *CryptoSim) setupErc20Contracts() error { } if c.dataGenerator.NextErc20ContractID()%c.config.SetupUpdateIntervalCount == 0 { - fmt.Printf("Created %s of %s simulated ERC20 contracts.\r", + fmt.Printf("Created %s of %s simulated ERC20 contracts. \r", int64Commas(c.dataGenerator.NextErc20ContractID()), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) } @@ -256,7 +256,7 @@ func (c *CryptoSim) setupErc20Contracts() error { fmt.Printf("\n") } - fmt.Printf("Created %s of %s simulated ERC20 contracts.\n", + fmt.Printf("Created %s of %s simulated ERC20 contracts. \n", int64Commas(c.dataGenerator.NextErc20ContractID()), int64Commas(int64(c.config.MinimumNumberOfErc20Contracts))) err := c.database.FinalizeBlock(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID(), true) @@ -335,7 +335,7 @@ func (c *CryptoSim) generateConsoleReport(force bool) { transactionsPerSecond := float64(c.database.TransactionCount()) / totalElapsedTime.Seconds() // Generate the report. - fmt.Printf("%s txns executed in %s (%s txns/sec), total number of accounts: %s\r", + fmt.Printf("%s txns executed in %s (%s txns/sec), total number of accounts: %s \r", int64Commas(c.database.TransactionCount()), formatDuration(totalElapsedTime, 1), formatNumberFloat64(transactionsPerSecond, 2), diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index b2e0776803..5c9967459e 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -106,6 +106,38 @@ type CryptoSimConfig struct { ExecutorQueueSize int } +// Returns the default configuration for the cryptosim benchmark. +func DefaultCryptoSimConfig() *CryptoSimConfig { + + // Note: if you add new fields or modify default values, be sure to keep config/basic-config.json in sync. + // That file should conatain every available config set to its default value, as a reference. + + return &CryptoSimConfig{ + MinimumNumberOfAccounts: 1_000_000, + HotAccountProbability: 0.1, + NewAccountProbability: 0.001, + HotAccountSetSize: 100, + PaddedAccountSize: 69, // Not a joke, this is the actual size + MinimumNumberOfErc20Contracts: 10_000, + HotErc20ContractProbability: 0.5, + HotErc20ContractSetSize: 100, + Erc20ContractSize: 1024 * 2, // 2kb + Erc20StorageSlotSize: 32, + Erc20InteractionsPerAccount: 10, + TransactionsPerBlock: 1024, + BlocksPerCommit: 32, + Seed: 1337, + CannedRandomSize: 1024 * 1024 * 1024, // 1GB + Backend: wrappers.FlatKV, + ConsoleUpdateIntervalSeconds: 1, + ConsoleUpdateIntervalTransactions: 1_000_000, + SetupUpdateIntervalCount: 100_000, + ThreadsPerCore: 2.0, + ConstantThreadCount: 0, + ExecutorQueueSize: 64, + } +} + // Validate checks that the configuration is sane and returns an error if not. func (c *CryptoSimConfig) Validate() error { if c.DataDir == "" { @@ -131,12 +163,12 @@ func (c *CryptoSimConfig) Validate() error { return fmt.Errorf("HotErc20ContractProbability must be in [0, 1] (got %f)", c.HotErc20ContractProbability) } if c.Erc20StorageSlotSize < minErc20StorageSlotSize { - return fmt.Errorf("Erc20StorageSlotSize must be at least %d (got %d)", - minErc20StorageSlotSize, c.Erc20StorageSlotSize) + return fmt.Errorf("Erc20StorageSlotSize must be at least %d (got %d)", + minErc20StorageSlotSize, c.Erc20StorageSlotSize) } if c.Erc20InteractionsPerAccount < minErc20InteractionsPerAcct { - return fmt.Errorf("Erc20InteractionsPerAccount must be at least %d (got %d)", - minErc20InteractionsPerAcct, c.Erc20InteractionsPerAccount) + return fmt.Errorf("Erc20InteractionsPerAccount must be at least %d (got %d)", + minErc20InteractionsPerAcct, c.Erc20InteractionsPerAccount) } if c.TransactionsPerBlock < 1 { return fmt.Errorf("TransactionsPerBlock must be at least 1 (got %d)", c.TransactionsPerBlock) @@ -156,34 +188,6 @@ func (c *CryptoSimConfig) Validate() error { return nil } -// Returns the default configuration for the cryptosim benchmark. -func DefaultCryptoSimConfig() *CryptoSimConfig { - return &CryptoSimConfig{ - MinimumNumberOfAccounts: 1_000_000, - HotAccountProbability: 0.1, - NewAccountProbability: 0.001, - HotAccountSetSize: 100, - PaddedAccountSize: 69, // Not a joke, this is the actual size - MinimumNumberOfErc20Contracts: 10_000, - HotErc20ContractProbability: 0.5, - HotErc20ContractSetSize: 100, - Erc20ContractSize: 1024 * 2, // 2kb - Erc20StorageSlotSize: 32, - Erc20InteractionsPerAccount: 10, - TransactionsPerBlock: 1024, - BlocksPerCommit: 32, - Seed: 1337, - CannedRandomSize: 1024 * 1024 * 1024, // 1GB - Backend: wrappers.FlatKV, - ConsoleUpdateIntervalSeconds: 1, - ConsoleUpdateIntervalTransactions: 1_000_000, - SetupUpdateIntervalCount: 100_000, - ThreadsPerCore: 2.0, - ConstantThreadCount: 0, - ExecutorQueueSize: 64, - } -} - // LoadConfigFromFile parses a JSON config file at the given path. // Returns defaults with file values overlaid. Fails if the file contains // unrecognized configuration keys. diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 03fc9a02e5..b80b089b4a 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -26,9 +26,9 @@ type Database struct { // The number of blocks that have been executed since the last commit. uncommittedBlockCount int64 - // The current batch of changesets waiting to be committed. Represents changes we are accumulating - // as part of a simulated "block". - batch *SyncMap[string, *proto.NamedChangeSet] + // The current batch of key-value pairs waiting to be committed. Represents changes we are accumulating + // as part of a simulated "block". Stored as value []byte; converted to NamedChangeSet when applied to the DB. + batch *SyncMap[string, []byte] // A method that flushes the executors. flushFunc func() @@ -42,7 +42,7 @@ func NewDatabase( return &Database{ config: config, db: db, - batch: NewSyncMap[string, *proto.NamedChangeSet](), + batch: NewSyncMap[string, []byte](), } } @@ -51,21 +51,7 @@ func NewDatabase( // This method is safe to call concurrently with other calls to Put() and Get(). Is not thread // safe with FinalizeBlock(). func (d *Database) Put(key []byte, value []byte) error { - stringKey := string(key) - - pending, found := d.batch.Get(stringKey) - if found { - pending.Changeset.Pairs[0].Value = value - return nil - } - - d.batch.Put(stringKey, &proto.NamedChangeSet{ - Name: wrappers.EVMStoreName, - Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{ - {Key: key, Value: value}, - }}, - }) - + d.batch.Put(string(key), value) return nil } @@ -74,11 +60,8 @@ func (d *Database) Put(key []byte, value []byte) error { // This method is safe to call concurrently with other calls to Put() and Get(). Is not thread // safe with FinalizeBlock(). func (d *Database) Get(key []byte) ([]byte, bool, error) { - stringKey := string(key) - - pending, found := d.batch.Get(stringKey) - if found { - return pending.Changeset.Pairs[0].Value, true, nil + if value, found := d.batch.Get(string(key)); found { + return value, true, nil } value, found, err := d.db.Read(key) @@ -144,8 +127,11 @@ func (d *Database) FinalizeBlock( d.transactionsInCurrentBlock = 0 changeSets := make([]*proto.NamedChangeSet, 0, d.transactionsInCurrentBlock+2) - for _, cs := range d.batch.Iterator() { - changeSets = append(changeSets, cs) + for key, value := range d.batch.Iterator() { + changeSets = append(changeSets, &proto.NamedChangeSet{ + Name: wrappers.EVMStoreName, + Changeset: iavl.ChangeSet{Pairs: []*iavl.KVPair{{Key: []byte(key), Value: value}}}, + }) } d.batch.Clear() From ab92fce33787973e4cad1731f6cdf62865952284 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 13:17:02 -0600 Subject: [PATCH 24/49] added first metric --- .../bench/cryptosim/config/basic-config.json | 2 + sei-db/state_db/bench/cryptosim/cryptosim.go | 11 ++- .../bench/cryptosim/cryptosim_config.go | 4 + .../bench/cryptosim/cryptosim_metrics.go | 73 +++++++++++++++++++ sei-db/state_db/bench/cryptosim/database.go | 19 ++++- 5 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/cryptosim_metrics.go diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index bc8eca2430..1537613c93 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -16,6 +16,8 @@ "HotErc20ContractProbability": 0.5, "HotErc20ContractSetSize": 100, "MinimumNumberOfAccounts": 1000000, + "MetricsAddr": ":9090", + "MinimumNumberOfAccounts": 1000000, "MinimumNumberOfErc20Contracts": 10000, "NewAccountProbability": 0.001, "PaddedAccountSize": 69, diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 222b41695d..90ea9b1ed1 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -56,6 +56,9 @@ type CryptoSim struct { // The index of the next executor to receive a transaction. nextExecutorIndex int + + // The metrics for the benchmark. + metrics *CryptosimMetrics } // Creates a new cryptosim benchmark runner. @@ -68,6 +71,9 @@ func NewCryptoSim( return nil, fmt.Errorf("invalid config: %w", err) } + ctx, cancel := context.WithCancel(ctx) + metrics := NewCryptosimMetrics(ctx, config.MetricsAddr) + dataDir, err := resolveAndCreateDataDir(config.DataDir) if err != nil { return nil, err @@ -87,9 +93,7 @@ func NewCryptoSim( start := time.Now() - ctx, cancel := context.WithCancel(ctx) - - database := NewDatabase(config, db) + database := NewDatabase(config, db, metrics) dataGenerator, err := NewDataGenerator(config, database, rand) if err != nil { @@ -121,6 +125,7 @@ func NewCryptoSim( dataGenerator: dataGenerator, database: database, executors: executors, + metrics: metrics, } database.SetFlushFunc(c.flushExecutors) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index 5c9967459e..d299fdd9b6 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -104,6 +104,9 @@ type CryptoSimConfig struct { // The size of the queue for each transaction executor. ExecutorQueueSize int + + // Address for the Prometheus metrics HTTP server (e.g. ":9090"). If empty, metrics are disabled. + MetricsAddr string } // Returns the default configuration for the cryptosim benchmark. @@ -135,6 +138,7 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { ThreadsPerCore: 2.0, ConstantThreadCount: 0, ExecutorQueueSize: 64, + MetricsAddr: ":9090", } } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go new file mode 100644 index 0000000000..7ded14a4ea --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -0,0 +1,73 @@ +package cryptosim + +import ( + "context" + "net/http" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +// CryptosimMetrics holds Prometheus metrics for the cryptosim benchmark. +type CryptosimMetrics struct { + blocksFinalizedTotal prometheus.Counter + blockFinalizationLatency prometheus.Observer +} + +// NewCryptosimMetrics creates metrics for the cryptosim benchmark. A dedicated +// registry is created internally. When ctx is cancelled, the metrics HTTP server +// (if started) is shut down gracefully. +func NewCryptosimMetrics( + ctx context.Context, + metricsAddr string, +) *CryptosimMetrics { + reg := prometheus.NewRegistry() + + blocksFinalizedTotal := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "cryptosim_blocks_finalized_total", + Help: "Total number of blocks finalized", + }) + blockFinalizationLatency := prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "cryptosim_block_finalization_latency_seconds", + Help: "Time to finalize a block in seconds", + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), + }) + + reg.MustRegister(blocksFinalizedTotal, blockFinalizationLatency) + + if metricsAddr != "" { + startMetricsServer(ctx, reg, metricsAddr) + } + + return &CryptosimMetrics{ + blocksFinalizedTotal: blocksFinalizedTotal, + blockFinalizationLatency: blockFinalizationLatency, + } +} + +// startMetricsServer starts an HTTP server serving /metrics from reg. When ctx is +// cancelled, the server is shut down gracefully. +func startMetricsServer(ctx context.Context, reg *prometheus.Registry, addr string) { + mux := http.NewServeMux() + mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{})) + srv := &http.Server{Addr: addr, Handler: mux} + go func() { + _ = srv.ListenAndServe() + }() + go func() { + <-ctx.Done() + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + _ = srv.Shutdown(shutdownCtx) + }() +} + +// ReportBlockFinalized records that a block was finalized and the latency. +func (m *CryptosimMetrics) ReportBlockFinalized(latency time.Duration) { + if m == nil { + return + } + m.blocksFinalizedTotal.Inc() + m.blockFinalizationLatency.Observe(latency.Seconds()) +} diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index b80b089b4a..2d4f734920 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -3,6 +3,7 @@ package cryptosim import ( "encoding/binary" "fmt" + "time" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" @@ -32,17 +33,22 @@ type Database struct { // A method that flushes the executors. flushFunc func() + + // The metrics for the benchmark. + metrics *CryptosimMetrics } // Creates a new database for the cryptosim benchmark. func NewDatabase( config *CryptoSimConfig, db wrappers.DBWrapper, + metrics *CryptosimMetrics, ) *Database { return &Database{ - config: config, - db: db, - batch: NewSyncMap[string, []byte](), + config: config, + db: db, + batch: NewSyncMap[string, []byte](), + metrics: metrics, } } @@ -124,6 +130,8 @@ func (d *Database) FinalizeBlock( return nil } + finalizationStart := time.Now() + d.transactionsInCurrentBlock = 0 changeSets := make([]*proto.NamedChangeSet, 0, d.transactionsInCurrentBlock+2) @@ -160,6 +168,9 @@ func (d *Database) FinalizeBlock( return fmt.Errorf("failed to apply change sets: %w", err) } + finalizationFinish := time.Now() + d.metrics.ReportBlockFinalized(finalizationFinish.Sub(finalizationStart)) + // Periodically commit the changes to the database. d.uncommittedBlockCount++ if forceCommit || d.uncommittedBlockCount >= int64(d.config.BlocksPerCommit) { @@ -168,6 +179,8 @@ func (d *Database) FinalizeBlock( return fmt.Errorf("failed to commit: %w", err) } d.uncommittedBlockCount = 0 + + // commitFinish := time.Now() // TODO } return nil From 0acc8a27d1f5daeec48ad5094dcc208581fc367c Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 13:29:40 -0600 Subject: [PATCH 25/49] Basic tooling for starting grafana/prometheus, added first metric --- .../provisioning/datasources/prometheus.yaml | 8 ++ .../tools/prometheus-config/prometheus.yml | 9 ++ .../bench/cryptosim/tools/start-grafana.sh | 84 +++++++++++++++++++ .../bench/cryptosim/tools/start-prometheus.sh | 78 +++++++++++++++++ .../bench/cryptosim/tools/stop-grafana.sh | 33 ++++++++ .../bench/cryptosim/tools/stop-prometheus.sh | 33 ++++++++ 6 files changed, 245 insertions(+) create mode 100644 sei-db/state_db/bench/cryptosim/tools/grafana-config/provisioning/datasources/prometheus.yaml create mode 100644 sei-db/state_db/bench/cryptosim/tools/prometheus-config/prometheus.yml create mode 100755 sei-db/state_db/bench/cryptosim/tools/start-grafana.sh create mode 100755 sei-db/state_db/bench/cryptosim/tools/start-prometheus.sh create mode 100755 sei-db/state_db/bench/cryptosim/tools/stop-grafana.sh create mode 100755 sei-db/state_db/bench/cryptosim/tools/stop-prometheus.sh diff --git a/sei-db/state_db/bench/cryptosim/tools/grafana-config/provisioning/datasources/prometheus.yaml b/sei-db/state_db/bench/cryptosim/tools/grafana-config/provisioning/datasources/prometheus.yaml new file mode 100644 index 0000000000..49c5cb5b58 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/tools/grafana-config/provisioning/datasources/prometheus.yaml @@ -0,0 +1,8 @@ +apiVersion: 1 +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://host.docker.internal:9091 + isDefault: true + editable: false diff --git a/sei-db/state_db/bench/cryptosim/tools/prometheus-config/prometheus.yml b/sei-db/state_db/bench/cryptosim/tools/prometheus-config/prometheus.yml new file mode 100644 index 0000000000..e8c478f098 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/tools/prometheus-config/prometheus.yml @@ -0,0 +1,9 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: 'cryptosim' + static_configs: + - targets: ['host.docker.internal:9090'] + scrape_interval: 5s diff --git a/sei-db/state_db/bench/cryptosim/tools/start-grafana.sh b/sei-db/state_db/bench/cryptosim/tools/start-grafana.sh new file mode 100755 index 0000000000..5f6462e74c --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/tools/start-grafana.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# +# Starts the local Grafana server, preconfigured with Prometheus as a data source. +# Prometheus must be running (see start-prometheus.sh). +# +# Usage: ./start-grafana.sh +# +# Requirements: Docker must be installed and running. +# Compatible with macOS and Linux. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +GRAFANA_DIR="${SCRIPT_DIR}/grafana-config" +DATASOURCES_DIR="${GRAFANA_DIR}/provisioning/datasources" +DATASOURCE_CONFIG="${DATASOURCES_DIR}/prometheus.yaml" +CONTAINER_NAME="cryptosim-grafana" +GRAFANA_PORT=3000 +PROMETHEUS_UI_PORT=9091 + +# Check for Docker +if ! command -v docker &>/dev/null; then + echo "Error: docker is not installed or not in PATH" >&2 + exit 1 +fi + +# Check that Docker daemon is reachable +if ! docker info &>/dev/null; then + echo "Error: Docker daemon is not running or not accessible. Start Docker and try again." >&2 + exit 1 +fi + +# Check that datasource config exists +if [[ ! -f "${DATASOURCE_CONFIG}" ]]; then + echo "Error: Grafana datasource config not found at ${DATASOURCE_CONFIG}" >&2 + exit 1 +fi + +# If container exists and is running, we're done +if docker ps -q -f "name=^${CONTAINER_NAME}$" | grep -q .; then + echo "Grafana is already running." + echo " UI: http://localhost:${GRAFANA_PORT}" + echo " Default login: admin / admin" + exit 0 +fi + +# If container exists but is stopped, start it +if docker ps -aq -f "name=^${CONTAINER_NAME}$" | grep -q .; then + echo "Starting existing Grafana container..." + docker start "$CONTAINER_NAME" + echo "" + echo "Grafana is running." + echo " UI: http://localhost:${GRAFANA_PORT}" + echo " Default login: admin / admin" + exit 0 +fi + +# Container doesn't exist – create and run (first-time setup) +# Grafana needs to reach Prometheus on the host; use host.docker.internal. +case "$(uname -s)" in + Linux*) ADD_HOST_FLAG="--add-host=host.docker.internal:host-gateway" ;; + *) ADD_HOST_FLAG="" ;; +esac + +echo "Creating and starting Grafana container..." +docker run -d \ + --name "$CONTAINER_NAME" \ + ${ADD_HOST_FLAG:+"$ADD_HOST_FLAG"} \ + -p "${GRAFANA_PORT}:3000" \ + -v "${GRAFANA_DIR}/provisioning:/etc/grafana/provisioning:ro" \ + -e "GF_SECURITY_ADMIN_USER=admin" \ + -e "GF_SECURITY_ADMIN_PASSWORD=admin" \ + -e "GF_USERS_ALLOW_SIGN_UP=false" \ + grafana/grafana:latest + +echo "" +echo "Grafana is running." +echo " UI: http://localhost:${GRAFANA_PORT}" +echo " Login: admin / admin" +echo " Data source: Prometheus (provisioned from ${DATASOURCE_CONFIG})" +echo "" +echo "To stop: ./stop-grafana.sh" +echo "" +echo "Note: Start Prometheus first (./start-prometheus.sh) to have data to visualize." diff --git a/sei-db/state_db/bench/cryptosim/tools/start-prometheus.sh b/sei-db/state_db/bench/cryptosim/tools/start-prometheus.sh new file mode 100755 index 0000000000..3d1369f217 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/tools/start-prometheus.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# +# Starts the local Prometheus server. If the container already exists, it is +# started; otherwise it is created and run (first-time setup). +# +# Usage: ./start-prometheus.sh +# +# Requirements: Docker must be installed and running. +# Compatible with macOS and Linux. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROMETHEUS_DIR="${SCRIPT_DIR}/prometheus-config" +PROMETHEUS_CONFIG="${PROMETHEUS_DIR}/prometheus.yml" +CONTAINER_NAME="cryptosim-prometheus" +PROMETHEUS_UI_PORT=9091 +CRYPTOSIM_METRICS_PORT=9090 + +# Check for Docker +if ! command -v docker &>/dev/null; then + echo "Error: docker is not installed or not in PATH" >&2 + exit 1 +fi + +# Check that Docker daemon is reachable +if ! docker info &>/dev/null; then + echo "Error: Docker daemon is not running or not accessible. Start Docker and try again." >&2 + exit 1 +fi + +# Check that config exists +if [[ ! -f "${PROMETHEUS_CONFIG}" ]]; then + echo "Error: Prometheus config not found at ${PROMETHEUS_CONFIG}" >&2 + exit 1 +fi + +# If container exists and is running, we're done +if docker ps -q -f "name=^${CONTAINER_NAME}$" | grep -q .; then + echo "Prometheus is already running." + echo " UI: http://localhost:${PROMETHEUS_UI_PORT}" + exit 0 +fi + +# If container exists but is stopped, start it +if docker ps -aq -f "name=^${CONTAINER_NAME}$" | grep -q .; then + echo "Starting existing Prometheus container..." + docker start "$CONTAINER_NAME" + echo "" + echo "Prometheus is running." + echo " UI: http://localhost:${PROMETHEUS_UI_PORT}" + exit 0 +fi + +# Container doesn't exist – create and run (first-time setup) +# host.docker.internal works on Docker Desktop (macOS/Windows). On Linux we add it via --add-host. +case "$(uname -s)" in + Linux*) ADD_HOST_FLAG="--add-host=host.docker.internal:host-gateway" ;; + *) ADD_HOST_FLAG="" ;; +esac + +echo "Creating and starting Prometheus container..." +docker run -d \ + --name "$CONTAINER_NAME" \ + ${ADD_HOST_FLAG:+"$ADD_HOST_FLAG"} \ + -p "${PROMETHEUS_UI_PORT}:9090" \ + -v "${PROMETHEUS_CONFIG}:/etc/prometheus/prometheus.yml:ro" \ + prom/prometheus:latest \ + --config.file=/etc/prometheus/prometheus.yml \ + --storage.tsdb.path=/prometheus \ + --web.enable-lifecycle + +echo "" +echo "Prometheus is running." +echo " UI: http://localhost:${PROMETHEUS_UI_PORT}" +echo " Config: ${PROMETHEUS_CONFIG}" +echo "" +echo "To stop: ./stop-prometheus.sh" diff --git a/sei-db/state_db/bench/cryptosim/tools/stop-grafana.sh b/sei-db/state_db/bench/cryptosim/tools/stop-grafana.sh new file mode 100755 index 0000000000..1d8c401769 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/tools/stop-grafana.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# +# Stops the local Grafana server. The container is stopped but not removed; +# use start-grafana.sh to start it again. +# +# Usage: ./stop-grafana.sh +# +# Requirements: Docker must be installed and running. +# Compatible with macOS and Linux. + +set -euo pipefail + +CONTAINER_NAME="cryptosim-grafana" + +# Check for Docker +if ! command -v docker &>/dev/null; then + echo "Error: docker is not installed or not in PATH" >&2 + exit 1 +fi + +# Check that Docker daemon is reachable +if ! docker info &>/dev/null; then + echo "Error: Docker daemon is not running or not accessible. Start Docker and try again." >&2 + exit 1 +fi + +if docker ps -q -f "name=^${CONTAINER_NAME}$" | grep -q .; then + echo "Stopping Grafana container..." + docker stop "$CONTAINER_NAME" + echo "Grafana stopped." +else + echo "Grafana is not running." +fi diff --git a/sei-db/state_db/bench/cryptosim/tools/stop-prometheus.sh b/sei-db/state_db/bench/cryptosim/tools/stop-prometheus.sh new file mode 100755 index 0000000000..3e91242799 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/tools/stop-prometheus.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# +# Stops the local Prometheus server. The container is stopped but not removed; +# use start-prometheus.sh to start it again. +# +# Usage: ./stop-prometheus.sh +# +# Requirements: Docker must be installed and running. +# Compatible with macOS and Linux. + +set -euo pipefail + +CONTAINER_NAME="cryptosim-prometheus" + +# Check for Docker +if ! command -v docker &>/dev/null; then + echo "Error: docker is not installed or not in PATH" >&2 + exit 1 +fi + +# Check that Docker daemon is reachable +if ! docker info &>/dev/null; then + echo "Error: Docker daemon is not running or not accessible. Start Docker and try again." >&2 + exit 1 +fi + +if docker ps -q -f "name=^${CONTAINER_NAME}$" | grep -q .; then + echo "Stopping Prometheus container..." + docker stop "$CONTAINER_NAME" + echo "Prometheus stopped." +else + echo "Prometheus is not running." +fi From ee71e87ba7f2d181d2fb12b2131d875df80e92bd Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 13:54:07 -0600 Subject: [PATCH 26/49] Add basic dashboard. --- .../bench/cryptosim/cryptosim_metrics.go | 24 +- sei-db/state_db/bench/cryptosim/database.go | 3 +- .../bench/cryptosim/metrics/dashboard.json | 500 ++++++++++++++++++ .../prometheus.yaml => metrics/grafana.yaml} | 0 .../prometheus.yaml} | 0 .../{tools => metrics}/start-grafana.sh | 6 +- .../{tools => metrics}/start-prometheus.sh | 3 +- .../{tools => metrics}/stop-grafana.sh | 0 .../{tools => metrics}/stop-prometheus.sh | 0 9 files changed, 527 insertions(+), 9 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/metrics/dashboard.json rename sei-db/state_db/bench/cryptosim/{tools/grafana-config/provisioning/datasources/prometheus.yaml => metrics/grafana.yaml} (100%) rename sei-db/state_db/bench/cryptosim/{tools/prometheus-config/prometheus.yml => metrics/prometheus.yaml} (100%) rename sei-db/state_db/bench/cryptosim/{tools => metrics}/start-grafana.sh (91%) rename sei-db/state_db/bench/cryptosim/{tools => metrics}/start-prometheus.sh (95%) rename sei-db/state_db/bench/cryptosim/{tools => metrics}/stop-grafana.sh (100%) rename sei-db/state_db/bench/cryptosim/{tools => metrics}/stop-prometheus.sh (100%) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index 7ded14a4ea..cf15dd3d92 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -13,6 +13,8 @@ import ( type CryptosimMetrics struct { blocksFinalizedTotal prometheus.Counter blockFinalizationLatency prometheus.Observer + dbCommitsTotal prometheus.Counter + dbCommitLatency prometheus.Observer } // NewCryptosimMetrics creates metrics for the cryptosim benchmark. A dedicated @@ -33,8 +35,17 @@ func NewCryptosimMetrics( Help: "Time to finalize a block in seconds", Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), }) + dbCommitsTotal := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "cryptosim_db_commits_total", + Help: "Total number of database commits", + }) + dbCommitLatency := prometheus.NewHistogram(prometheus.HistogramOpts{ + Name: "cryptosim_db_commit_latency_seconds", + Help: "Time to commit to the database in seconds", + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), + }) - reg.MustRegister(blocksFinalizedTotal, blockFinalizationLatency) + reg.MustRegister(blocksFinalizedTotal, blockFinalizationLatency, dbCommitsTotal, dbCommitLatency) if metricsAddr != "" { startMetricsServer(ctx, reg, metricsAddr) @@ -43,6 +54,8 @@ func NewCryptosimMetrics( return &CryptosimMetrics{ blocksFinalizedTotal: blocksFinalizedTotal, blockFinalizationLatency: blockFinalizationLatency, + dbCommitsTotal: dbCommitsTotal, + dbCommitLatency: dbCommitLatency, } } @@ -71,3 +84,12 @@ func (m *CryptosimMetrics) ReportBlockFinalized(latency time.Duration) { m.blocksFinalizedTotal.Inc() m.blockFinalizationLatency.Observe(latency.Seconds()) } + +// ReportDBCommit records that a database commit completed and the latency. +func (m *CryptosimMetrics) ReportDBCommit(latency time.Duration) { + if m == nil { + return + } + m.dbCommitsTotal.Inc() + m.dbCommitLatency.Observe(latency.Seconds()) +} diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 2d4f734920..18fad51a93 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -178,9 +178,8 @@ func (d *Database) FinalizeBlock( if err != nil { return fmt.Errorf("failed to commit: %w", err) } + d.metrics.ReportDBCommit(time.Since(finalizationFinish)) d.uncommittedBlockCount = 0 - - // commitFinish := time.Now() // TODO } return nil diff --git a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json new file mode 100644 index 0000000000..4bb26a643d --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -0,0 +1,500 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A DB microbenchmark, workload is a simulation of ERC20 crypto-transfer traffic.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_blocks_finalized_total[5m])", + "legendFormat": "Blocks / Second", + "range": true, + "refId": "A" + } + ], + "title": "Blocks / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(cryptosim_block_finalization_latency_seconds_bucket[5m]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(cryptosim_block_finalization_latency_seconds_bucket[5m]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(cryptosim_block_finalization_latency_seconds_bucket[5m]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_block_finalization_latency_seconds_sum[5m]) / rate(cryptosim_block_finalization_latency_seconds_count[5m])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Block Finalization Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_db_commits_total[5m])", + "legendFormat": "Blocks / Second", + "range": true, + "refId": "A" + } + ], + "title": "Commits / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(cryptosim_db_commit_latency_seconds_bucket[5m]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(cryptosim_db_commit_latency_seconds_bucket[5m]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(cryptosim_db_commit_latency_seconds_bucket[5m]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_db_commit_latency_seconds_sum[5m]) / rate(cryptosim_db_commit_latency_seconds_count[5m])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "DB Commit Time", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "5s", + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "CryptoSim", + "uid": "adnqfm4", + "version": 3, + "weekStart": "" + } \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/tools/grafana-config/provisioning/datasources/prometheus.yaml b/sei-db/state_db/bench/cryptosim/metrics/grafana.yaml similarity index 100% rename from sei-db/state_db/bench/cryptosim/tools/grafana-config/provisioning/datasources/prometheus.yaml rename to sei-db/state_db/bench/cryptosim/metrics/grafana.yaml diff --git a/sei-db/state_db/bench/cryptosim/tools/prometheus-config/prometheus.yml b/sei-db/state_db/bench/cryptosim/metrics/prometheus.yaml similarity index 100% rename from sei-db/state_db/bench/cryptosim/tools/prometheus-config/prometheus.yml rename to sei-db/state_db/bench/cryptosim/metrics/prometheus.yaml diff --git a/sei-db/state_db/bench/cryptosim/tools/start-grafana.sh b/sei-db/state_db/bench/cryptosim/metrics/start-grafana.sh similarity index 91% rename from sei-db/state_db/bench/cryptosim/tools/start-grafana.sh rename to sei-db/state_db/bench/cryptosim/metrics/start-grafana.sh index 5f6462e74c..b59962b414 100755 --- a/sei-db/state_db/bench/cryptosim/tools/start-grafana.sh +++ b/sei-db/state_db/bench/cryptosim/metrics/start-grafana.sh @@ -11,9 +11,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -GRAFANA_DIR="${SCRIPT_DIR}/grafana-config" -DATASOURCES_DIR="${GRAFANA_DIR}/provisioning/datasources" -DATASOURCE_CONFIG="${DATASOURCES_DIR}/prometheus.yaml" +DATASOURCE_CONFIG="${SCRIPT_DIR}/grafana.yaml" CONTAINER_NAME="cryptosim-grafana" GRAFANA_PORT=3000 PROMETHEUS_UI_PORT=9091 @@ -67,7 +65,7 @@ docker run -d \ --name "$CONTAINER_NAME" \ ${ADD_HOST_FLAG:+"$ADD_HOST_FLAG"} \ -p "${GRAFANA_PORT}:3000" \ - -v "${GRAFANA_DIR}/provisioning:/etc/grafana/provisioning:ro" \ + -v "${DATASOURCE_CONFIG}:/etc/grafana/provisioning/datasources/grafana.yaml:ro" \ -e "GF_SECURITY_ADMIN_USER=admin" \ -e "GF_SECURITY_ADMIN_PASSWORD=admin" \ -e "GF_USERS_ALLOW_SIGN_UP=false" \ diff --git a/sei-db/state_db/bench/cryptosim/tools/start-prometheus.sh b/sei-db/state_db/bench/cryptosim/metrics/start-prometheus.sh similarity index 95% rename from sei-db/state_db/bench/cryptosim/tools/start-prometheus.sh rename to sei-db/state_db/bench/cryptosim/metrics/start-prometheus.sh index 3d1369f217..aab63bdded 100755 --- a/sei-db/state_db/bench/cryptosim/tools/start-prometheus.sh +++ b/sei-db/state_db/bench/cryptosim/metrics/start-prometheus.sh @@ -11,8 +11,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROMETHEUS_DIR="${SCRIPT_DIR}/prometheus-config" -PROMETHEUS_CONFIG="${PROMETHEUS_DIR}/prometheus.yml" +PROMETHEUS_CONFIG="${SCRIPT_DIR}/prometheus.yaml" CONTAINER_NAME="cryptosim-prometheus" PROMETHEUS_UI_PORT=9091 CRYPTOSIM_METRICS_PORT=9090 diff --git a/sei-db/state_db/bench/cryptosim/tools/stop-grafana.sh b/sei-db/state_db/bench/cryptosim/metrics/stop-grafana.sh similarity index 100% rename from sei-db/state_db/bench/cryptosim/tools/stop-grafana.sh rename to sei-db/state_db/bench/cryptosim/metrics/stop-grafana.sh diff --git a/sei-db/state_db/bench/cryptosim/tools/stop-prometheus.sh b/sei-db/state_db/bench/cryptosim/metrics/stop-prometheus.sh similarity index 100% rename from sei-db/state_db/bench/cryptosim/tools/stop-prometheus.sh rename to sei-db/state_db/bench/cryptosim/metrics/stop-prometheus.sh From 859feb72e75a48fe9f2333f4975080662abc4b17 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 14:36:20 -0600 Subject: [PATCH 27/49] more metrics --- sei-db/state_db/bench/cryptosim/cryptosim.go | 9 +- .../bench/cryptosim/cryptosim_metrics.go | 92 ++- .../bench/cryptosim/data_generator.go | 8 + sei-db/state_db/bench/cryptosim/database.go | 5 +- .../bench/cryptosim/metrics/dashboard.json | 577 +++++++++++++++++- 5 files changed, 647 insertions(+), 44 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 90ea9b1ed1..2721c60590 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -73,6 +73,8 @@ func NewCryptoSim( ctx, cancel := context.WithCancel(ctx) metrics := NewCryptosimMetrics(ctx, config.MetricsAddr) + // Server start deferred until after DataGenerator loads DB state and sets gauges, + // avoiding rate() spikes when restarting with a preserved DB. dataDir, err := resolveAndCreateDataDir(config.DataDir) if err != nil { @@ -95,12 +97,13 @@ func NewCryptoSim( database := NewDatabase(config, db, metrics) - dataGenerator, err := NewDataGenerator(config, database, rand) + dataGenerator, err := NewDataGenerator(config, database, rand, metrics) if err != nil { cancel() db.Close() return nil, fmt.Errorf("failed to create data generator: %w", err) } + metrics.StartServer(config.MetricsAddr) threadCount := int(config.ThreadsPerCore)*runtime.NumCPU() + config.ConstantThreadCount if threadCount < 1 { @@ -187,6 +190,7 @@ func (c *CryptoSim) setupAccounts() error { return fmt.Errorf("failed to maybe commit batch: %w", err) } if finalized { + c.metrics.SetTotalNumberOfAccounts(c.dataGenerator.NextAccountID()) c.dataGenerator.ReportFinalizeBlock() } @@ -205,6 +209,7 @@ func (c *CryptoSim) setupAccounts() error { if err != nil { return fmt.Errorf("failed to finalize block: %w", err) } + c.metrics.SetTotalNumberOfAccounts(c.dataGenerator.NextAccountID()) c.dataGenerator.ReportFinalizeBlock() fmt.Printf("There are now %s accounts in the database.\n", int64Commas(c.dataGenerator.NextAccountID())) @@ -248,6 +253,7 @@ func (c *CryptoSim) setupErc20Contracts() error { } if finalized { c.dataGenerator.ReportFinalizeBlock() + c.metrics.SetTotalNumberOfERC20Contracts(c.dataGenerator.NextErc20ContractID()) } if c.dataGenerator.NextErc20ContractID()%c.config.SetupUpdateIntervalCount == 0 { @@ -269,6 +275,7 @@ func (c *CryptoSim) setupErc20Contracts() error { return fmt.Errorf("failed to finalize block: %w", err) } c.dataGenerator.ReportFinalizeBlock() + c.metrics.SetTotalNumberOfERC20Contracts(c.dataGenerator.NextErc20ContractID()) fmt.Printf("There are now %s simulated ERC20 contracts in the database.\n", int64Commas(c.dataGenerator.NextErc20ContractID())) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index cf15dd3d92..d6b022ce77 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -11,10 +11,15 @@ import ( // CryptosimMetrics holds Prometheus metrics for the cryptosim benchmark. type CryptosimMetrics struct { - blocksFinalizedTotal prometheus.Counter - blockFinalizationLatency prometheus.Observer - dbCommitsTotal prometheus.Counter - dbCommitLatency prometheus.Observer + reg *prometheus.Registry + ctx context.Context + blocksFinalizedTotal prometheus.Counter + blockFinalizationLatency prometheus.Observer + transactionsProcessedTotal prometheus.Counter + totalAccounts prometheus.Gauge + totalErc20Contracts prometheus.Gauge + dbCommitsTotal prometheus.Counter + dbCommitLatency prometheus.Observer } // NewCryptosimMetrics creates metrics for the cryptosim benchmark. A dedicated @@ -35,6 +40,18 @@ func NewCryptosimMetrics( Help: "Time to finalize a block in seconds", Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), }) + transactionsProcessedTotal := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "cryptosim_transactions_processed_total", + Help: "Total number of transactions processed", + }) + totalAccounts := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "cryptosim_accounts_total", + Help: "Total number of accounts", + }) + totalErc20Contracts := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "cryptosim_erc20_contracts_total", + Help: "Total number of ERC20 contracts", + }) dbCommitsTotal := prometheus.NewCounter(prometheus.CounterOpts{ Name: "cryptosim_db_commits_total", Help: "Total number of database commits", @@ -45,18 +62,37 @@ func NewCryptosimMetrics( Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), }) - reg.MustRegister(blocksFinalizedTotal, blockFinalizationLatency, dbCommitsTotal, dbCommitLatency) + reg.MustRegister( + blocksFinalizedTotal, + blockFinalizationLatency, + transactionsProcessedTotal, + totalAccounts, + totalErc20Contracts, + dbCommitsTotal, + dbCommitLatency, + ) - if metricsAddr != "" { - startMetricsServer(ctx, reg, metricsAddr) + return &CryptosimMetrics{ + reg: reg, + ctx: ctx, + blocksFinalizedTotal: blocksFinalizedTotal, + blockFinalizationLatency: blockFinalizationLatency, + transactionsProcessedTotal: transactionsProcessedTotal, + totalAccounts: totalAccounts, + totalErc20Contracts: totalErc20Contracts, + dbCommitsTotal: dbCommitsTotal, + dbCommitLatency: dbCommitLatency, } +} - return &CryptosimMetrics{ - blocksFinalizedTotal: blocksFinalizedTotal, - blockFinalizationLatency: blockFinalizationLatency, - dbCommitsTotal: dbCommitsTotal, - dbCommitLatency: dbCommitLatency, +// StartServer starts the metrics HTTP server. Call this after loading initial +// state and setting gauges (e.g., SetTotalNumberOfAccounts) to avoid spurious +// rate spikes on restart. If addr is empty, no server is started. +func (m *CryptosimMetrics) StartServer(addr string) { + if m == nil || addr == "" { + return } + startMetricsServer(m.ctx, m.reg, addr) } // startMetricsServer starts an HTTP server serving /metrics from reg. When ctx is @@ -76,12 +112,14 @@ func startMetricsServer(ctx context.Context, reg *prometheus.Registry, addr stri }() } -// ReportBlockFinalized records that a block was finalized and the latency. -func (m *CryptosimMetrics) ReportBlockFinalized(latency time.Duration) { +// ReportBlockFinalized records that a block was finalized, the number of +// transactions in that block, and the finalization latency. +func (m *CryptosimMetrics) ReportBlockFinalized(latency time.Duration, transactionCount int64) { if m == nil { return } m.blocksFinalizedTotal.Inc() + m.transactionsProcessedTotal.Add(float64(transactionCount)) m.blockFinalizationLatency.Observe(latency.Seconds()) } @@ -93,3 +131,29 @@ func (m *CryptosimMetrics) ReportDBCommit(latency time.Duration) { m.dbCommitsTotal.Inc() m.dbCommitLatency.Observe(latency.Seconds()) } + +// SetTotalNumberOfAccounts sets the total number of accounts (e.g., when loading +// from existing data). +func (m *CryptosimMetrics) SetTotalNumberOfAccounts(total int64) { + if m == nil { + return + } + m.totalAccounts.Set(float64(total)) +} + +// IncrementTotalNumberOfAccounts records that a new account was created. +func (m *CryptosimMetrics) IncrementTotalNumberOfAccounts() { + if m == nil { + return + } + m.totalAccounts.Inc() +} + +// SetTotalNumberOfERC20Contracts sets the total number of ERC20 contracts (e.g., +// when loading from existing data). +func (m *CryptosimMetrics) SetTotalNumberOfERC20Contracts(total int64) { + if m == nil { + return + } + m.totalErc20Contracts.Set(float64(total)) +} diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go index 5635acd976..38b213ebfb 100644 --- a/sei-db/state_db/bench/cryptosim/data_generator.go +++ b/sei-db/state_db/bench/cryptosim/data_generator.go @@ -40,6 +40,9 @@ type DataGenerator struct { // choose read/write targets from acccounts that were created before the current block. This field tracks the // highest account ID that was created before the current block. highestSafeAccountIDInBlock int64 + + // The metrics for the benchmark. + metrics *CryptosimMetrics } // Creates a new data generator. @@ -47,6 +50,7 @@ func NewDataGenerator( config *CryptoSimConfig, database *Database, rand *CannedRandom, + metrics *CryptosimMetrics, ) (*DataGenerator, error) { nextAccountIDBinary, found, err := database.Get(AccountIDCounterKey()) @@ -59,6 +63,7 @@ func NewDataGenerator( } fmt.Printf("There are currently %s keys in the database.\n", int64Commas(nextAccountID)) + metrics.SetTotalNumberOfAccounts(nextAccountID) nextErc20ContractIDBinary, found, err := database.Get(Erc20IDCounterKey()) if err != nil { @@ -70,6 +75,7 @@ func NewDataGenerator( } fmt.Printf("There are currently %s ERC20 contracts in the database.\n", int64Commas(nextErc20ContractID)) + metrics.SetTotalNumberOfERC20Contracts(nextErc20ContractID) // Use EVMKeyCode for account data; EVMKeyNonce only accepts 8-byte values. feeCollectionAddress := evm.BuildMemIAVLEVMKey( @@ -85,6 +91,7 @@ func NewDataGenerator( feeCollectionAddress: feeCollectionAddress, database: database, highestSafeAccountIDInBlock: nextAccountID - 1, + metrics: metrics, }, nil } @@ -188,6 +195,7 @@ func (d *DataGenerator) RandomAccount() (id int64, address []byte, isNew bool, e if err != nil { return 0, nil, false, fmt.Errorf("failed to create new account: %w", err) } + d.metrics.IncrementTotalNumberOfAccounts() return id, address, true, nil } diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 18fad51a93..9c6ef964b9 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -132,8 +132,6 @@ func (d *Database) FinalizeBlock( finalizationStart := time.Now() - d.transactionsInCurrentBlock = 0 - changeSets := make([]*proto.NamedChangeSet, 0, d.transactionsInCurrentBlock+2) for key, value := range d.batch.Iterator() { changeSets = append(changeSets, &proto.NamedChangeSet{ @@ -169,7 +167,8 @@ func (d *Database) FinalizeBlock( } finalizationFinish := time.Now() - d.metrics.ReportBlockFinalized(finalizationFinish.Sub(finalizationStart)) + d.metrics.ReportBlockFinalized(finalizationFinish.Sub(finalizationStart), d.transactionsInCurrentBlock) + d.transactionsInCurrentBlock = 0 // Periodically commit the changes to the database. d.uncommittedBlockCount++ diff --git a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json index 4bb26a643d..7aa307ede8 100644 --- a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -21,6 +21,127 @@ "graphTooltip": 0, "links": [], "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 13, + "panels": [], + "title": "Transactions", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_transactions_processed_total[5m])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transactions / Second", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 12, + "panels": [], + "title": "Commit", + "type": "row" + }, { "datasource": { "type": "prometheus", @@ -86,15 +207,15 @@ "h": 8, "w": 12, "x": 0, - "y": 0 + "y": 10 }, - "id": 1, + "id": 3, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": true + "showLegend": false }, "tooltip": { "hideZeros": false, @@ -110,13 +231,13 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_blocks_finalized_total[5m])", + "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", "legendFormat": "Blocks / Second", "range": true, "refId": "A" } ], - "title": "Blocks / Second", + "title": "Commits / Second", "type": "timeseries" }, { @@ -185,9 +306,9 @@ "h": 8, "w": 12, "x": 12, - "y": 0 + "y": 10 }, - "id": 2, + "id": 4, "options": { "legend": { "calcs": [], @@ -205,7 +326,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(cryptosim_block_finalization_latency_seconds_bucket[5m]))", + "expr": "histogram_quantile(0.99, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -216,7 +337,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(cryptosim_block_finalization_latency_seconds_bucket[5m]))", + "expr": "histogram_quantile(0.95, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -228,7 +349,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(cryptosim_block_finalization_latency_seconds_bucket[5m]))", + "expr": "histogram_quantile(0.50, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -240,16 +361,29 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_block_finalization_latency_seconds_sum[5m]) / rate(cryptosim_block_finalization_latency_seconds_count[5m])", + "expr": "rate(cryptosim_db_commit_latency_seconds_sum[$__rate_interval]) / rate(cryptosim_db_commit_latency_seconds_count[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Block Finalization Time", + "title": "DB Commit Time", "type": "timeseries" }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 8, + "panels": [], + "title": "Blocks", + "type": "row" + }, { "datasource": { "type": "prometheus", @@ -315,15 +449,15 @@ "h": 8, "w": 12, "x": 0, - "y": 8 + "y": 19 }, - "id": 3, + "id": 1, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": true + "showLegend": false }, "tooltip": { "hideZeros": false, @@ -339,13 +473,13 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_db_commits_total[5m])", + "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", "legendFormat": "Blocks / Second", "range": true, "refId": "A" } ], - "title": "Commits / Second", + "title": "Blocks / Second", "type": "timeseries" }, { @@ -414,9 +548,9 @@ "h": 8, "w": 12, "x": 12, - "y": 8 + "y": 19 }, - "id": 4, + "id": 2, "options": { "legend": { "calcs": [], @@ -434,7 +568,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(cryptosim_db_commit_latency_seconds_bucket[5m]))", + "expr": "histogram_quantile(0.99, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -445,7 +579,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(cryptosim_db_commit_latency_seconds_bucket[5m]))", + "expr": "histogram_quantile(0.95, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -457,7 +591,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(cryptosim_db_commit_latency_seconds_bucket[5m]))", + "expr": "histogram_quantile(0.50, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -469,14 +603,405 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_db_commit_latency_seconds_sum[5m]) / rate(cryptosim_db_commit_latency_seconds_count[5m])", + "expr": "rate(cryptosim_block_finalization_latency_seconds_sum[$__rate_interval]) / rate(cryptosim_block_finalization_latency_seconds_count[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "DB Commit Time", + "title": "Block Finalization Time", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 9, + "panels": [], + "title": "State Size", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_accounts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of Accounts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_accounts_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Accounts Created / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_erc20_contracts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of ERC20 Contracts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "ERC20 Contracts Created / Second", "type": "timeseries" } ], @@ -488,13 +1013,13 @@ "list": [] }, "time": { - "from": "now-15m", + "from": "now-5m", "to": "now" }, "timepicker": {}, "timezone": "browser", "title": "CryptoSim", "uid": "adnqfm4", - "version": 3, + "version": 5, "weekStart": "" } \ No newline at end of file From 54e0b3c1817bf99b484c191a589a8c50a9b16b97 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 15:01:33 -0600 Subject: [PATCH 28/49] pie chart --- sei-db/state_db/bench/cryptosim/cryptosim.go | 2 + .../bench/cryptosim/cryptosim_metrics.go | 42 + sei-db/state_db/bench/cryptosim/database.go | 4 + .../bench/cryptosim/metrics/dashboard.json | 2046 +++++++++-------- 4 files changed, 1156 insertions(+), 938 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 2721c60590..bd0cbec555 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -290,6 +290,8 @@ func (c *CryptoSim) run() { c.runHaltedChan <- struct{}{} }() + c.metrics.SetPhase(PhaseExecuting) + for { select { case <-c.ctx.Done(): diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index d6b022ce77..9e9a65f44b 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -9,6 +9,15 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" ) +// Phase identifies where the main thread is spending its time. +type Phase string + +const ( + PhaseExecuting Phase = "executing" + PhaseFinalizing Phase = "finalizing" + PhaseCommitting Phase = "committing" +) + // CryptosimMetrics holds Prometheus metrics for the cryptosim benchmark. type CryptosimMetrics struct { reg *prometheus.Registry @@ -20,6 +29,10 @@ type CryptosimMetrics struct { totalErc20Contracts prometheus.Gauge dbCommitsTotal prometheus.Counter dbCommitLatency prometheus.Observer + phaseDurationTotal *prometheus.CounterVec + phaseDurationCount *prometheus.CounterVec + lastPhase Phase + lastPhaseChangeTime time.Time } // NewCryptosimMetrics creates metrics for the cryptosim benchmark. A dedicated @@ -61,6 +74,14 @@ func NewCryptosimMetrics( Help: "Time to commit to the database in seconds", Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), }) + phaseDurationTotal := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "cryptosim_phase_duration_seconds_total", + Help: "Total seconds spent in each phase (executing, finalizing, committing, etc.)", + }, []string{"phase"}) + phaseDurationCount := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "cryptosim_phase_duration_count_total", + Help: "Total number of times each phase was reported", + }, []string{"phase"}) reg.MustRegister( blocksFinalizedTotal, @@ -70,6 +91,8 @@ func NewCryptosimMetrics( totalErc20Contracts, dbCommitsTotal, dbCommitLatency, + phaseDurationTotal, + phaseDurationCount, ) return &CryptosimMetrics{ @@ -82,6 +105,8 @@ func NewCryptosimMetrics( totalErc20Contracts: totalErc20Contracts, dbCommitsTotal: dbCommitsTotal, dbCommitLatency: dbCommitLatency, + phaseDurationTotal: phaseDurationTotal, + phaseDurationCount: phaseDurationCount, } } @@ -157,3 +182,20 @@ func (m *CryptosimMetrics) SetTotalNumberOfERC20Contracts(total int64) { } m.totalErc20Contracts.Set(float64(total)) } + +// SetPhase records a transition of the main thread to a new phase. +// +// SetPhase is not safe for concurrent use. +func (m *CryptosimMetrics) SetPhase(phase Phase) { + if m == nil || phase == "" { + return + } + now := time.Now() + if m.lastPhase != "" { + latency := now.Sub(m.lastPhaseChangeTime) + m.phaseDurationTotal.WithLabelValues(string(m.lastPhase)).Add(latency.Seconds()) + m.phaseDurationCount.WithLabelValues(string(m.lastPhase)).Inc() + } + m.lastPhase = phase + m.lastPhaseChangeTime = now +} diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 9c6ef964b9..17ea214dab 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -131,6 +131,7 @@ func (d *Database) FinalizeBlock( } finalizationStart := time.Now() + d.metrics.SetPhase(PhaseFinalizing) changeSets := make([]*proto.NamedChangeSet, 0, d.transactionsInCurrentBlock+2) for key, value := range d.batch.Iterator() { @@ -173,6 +174,7 @@ func (d *Database) FinalizeBlock( // Periodically commit the changes to the database. d.uncommittedBlockCount++ if forceCommit || d.uncommittedBlockCount >= int64(d.config.BlocksPerCommit) { + d.metrics.SetPhase(PhaseCommitting) _, err := d.db.Commit() if err != nil { return fmt.Errorf("failed to commit: %w", err) @@ -181,6 +183,8 @@ func (d *Database) FinalizeBlock( d.uncommittedBlockCount = 0 } + d.metrics.SetPhase(PhaseExecuting) + return nil } diff --git a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json index 7aa307ede8..9a9190f897 100644 --- a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -1,1025 +1,1195 @@ { - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "description": "A DB microbenchmark, workload is a simulation of ERC20 crypto-transfer traffic.", - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "links": [], - "panels": [ + "annotations": { + "list": [ { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" }, - "id": 13, - "panels": [], - "title": "Transactions", - "type": "row" + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A DB microbenchmark, workload is a simulation of ERC20 crypto-transfer traffic.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "id": 17, + "panels": [], + "title": "Key Metrics", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 14, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "increase(cryptosim_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Time Spent", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" }, - "unit": "locale" + "thresholdsStyle": { + "mode": "off" + } }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 1 - }, - "id": 5, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } + "unit": "s" }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(cryptosim_transactions_processed_total[5m])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Transactions / Second", - "type": "timeseries" + "overrides": [] }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 9 - }, - "id": 12, - "panels": [], - "title": "Commit", - "type": "row" + "gridPos": { + "h": 16, + "w": 12, + "x": 12, + "y": 1 }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Time Spent", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 13, + "panels": [], + "title": "Transactions", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 10 - }, - "id": 3, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } + "unit": "locale" }, - "pluginVersion": "12.4.0", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", - "legendFormat": "Blocks / Second", - "range": true, - "refId": "A" - } - ], - "title": "Commits / Second", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_transactions_processed_total[5m])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transactions / Second", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 12, + "panels": [], + "title": "Commit", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" }, - "unit": "s" + "thresholdsStyle": { + "mode": "off" + } }, - "overrides": [] + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 10 + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "id": 4, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" + "editorMode": "code", + "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", + "legendFormat": "Blocks / Second", + "range": true, + "refId": "A" + } + ], + "title": "Commits / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" }, - "editorMode": "code", - "expr": "rate(cryptosim_db_commit_latency_seconds_sum[$__rate_interval]) / rate(cryptosim_db_commit_latency_seconds_count[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "DB Commit Time", - "type": "timeseries" + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 18 + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "id": 8, - "panels": [], - "title": "Blocks", - "type": "row" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "overrides": [] + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 19 - }, - "id": 1, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" }, - "pluginVersion": "12.4.0", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", - "legendFormat": "Blocks / Second", - "range": true, - "refId": "A" - } - ], - "title": "Blocks / Second", - "type": "timeseries" + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_db_commit_latency_seconds_sum[$__rate_interval]) / rate(cryptosim_db_commit_latency_seconds_count[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "DB Commit Time", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "id": 8, + "panels": [], + "title": "Blocks", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" }, - "unit": "s" + "thresholdsStyle": { + "mode": "off" + } }, - "overrides": [] + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 19 + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "id": 2, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" + "editorMode": "code", + "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", + "legendFormat": "Blocks / Second", + "range": true, + "refId": "A" + } + ], + "title": "Blocks / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" }, - "editorMode": "code", - "expr": "rate(cryptosim_block_finalization_latency_seconds_sum[$__rate_interval]) / rate(cryptosim_block_finalization_latency_seconds_count[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Block Finalization Time", - "type": "timeseries" + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 27 + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "id": 9, - "panels": [], - "title": "State Size", - "type": "row" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 28 + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" }, - "id": 6, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "cryptosim_accounts_total", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Number of Accounts", - "type": "timeseries" + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_block_finalization_latency_seconds_sum[$__rate_interval]) / rate(cryptosim_block_finalization_latency_seconds_count[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Block Finalization Time", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 44 }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "id": 9, + "panels": [], + "title": "State Size", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 28 - }, - "id": 7, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } + "unit": "locale" }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(cryptosim_accounts_total[$__rate_interval])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Accounts Created / Second", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_accounts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of Accounts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 36 - }, - "id": 10, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false + "thresholdsStyle": { + "mode": "off" + } }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] } }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "cryptosim_erc20_contracts_total", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Number of ERC20 Contracts", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_accounts_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Accounts Created / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 36 + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "id": 11, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_erc20_contracts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of ERC20 Contracts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] } }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "ERC20 Contracts Created / Second", - "type": "timeseries" - } - ], - "preload": false, - "refresh": "5s", - "schemaVersion": 42, - "tags": [], - "templating": { - "list": [] - }, - "time": { - "from": "now-5m", - "to": "now" - }, - "timepicker": {}, - "timezone": "browser", - "title": "CryptoSim", - "uid": "adnqfm4", - "version": 5, - "weekStart": "" - } \ No newline at end of file + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "ERC20 Contracts Created / Second", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "5s", + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "CryptoSim", + "uid": "adnqfm4", + "version": 6, + "weekStart": "" +} \ No newline at end of file From 3090ff146947ffbf50f0d965350d3aea0dc46afd Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 15:30:59 -0600 Subject: [PATCH 29/49] incremental improvements --- .../bench/cryptosim/config/basic-config.json | 3 +- sei-db/state_db/bench/cryptosim/cryptosim.go | 2 +- .../bench/cryptosim/cryptosim_config.go | 7 + .../bench/cryptosim/cryptosim_metrics.go | 43 +--- sei-db/state_db/bench/cryptosim/database.go | 6 +- .../bench/cryptosim/metrics/dashboard.json | 226 ++++++++++++++---- .../state_db/bench/cryptosim/phase_timer.go | 85 +++++++ .../state_db/bench/cryptosim/transaction.go | 20 +- 8 files changed, 302 insertions(+), 90 deletions(-) create mode 100644 sei-db/state_db/bench/cryptosim/phase_timer.go diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index 1537613c93..2e3d2b054d 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -24,5 +24,6 @@ "Seed": 1337, "SetupUpdateIntervalCount": 100000, "ThreadsPerCore": 2.0, - "TransactionsPerBlock": 1024 + "TransactionsPerBlock": 1024, + "TransactionMetricsSampleRate": 0.001 } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index bd0cbec555..839db9c4f9 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -290,7 +290,7 @@ func (c *CryptoSim) run() { c.runHaltedChan <- struct{}{} }() - c.metrics.SetPhase(PhaseExecuting) + c.metrics.SetMainThreadPhase("executing") for { select { diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index d299fdd9b6..753c491d95 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -107,6 +107,9 @@ type CryptoSimConfig struct { // Address for the Prometheus metrics HTTP server (e.g. ":9090"). If empty, metrics are disabled. MetricsAddr string + + // The probability of capturing detailed metrics about a transaction. Should be a value between 0.0 and 1.0. + TransactionMetricsSampleRate float64 } // Returns the default configuration for the cryptosim benchmark. @@ -139,6 +142,7 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { ConstantThreadCount: 0, ExecutorQueueSize: 64, MetricsAddr: ":9090", + TransactionMetricsSampleRate: 0.001, } } @@ -189,6 +193,9 @@ func (c *CryptoSimConfig) Validate() error { if c.SetupUpdateIntervalCount < 1 { return fmt.Errorf("SetupUpdateIntervalCount must be at least 1 (got %d)", c.SetupUpdateIntervalCount) } + if c.TransactionMetricsSampleRate < 0 || c.TransactionMetricsSampleRate > 1 { + return fmt.Errorf("TransactionMetricsSampleRate must be in [0, 1] (got %f)", c.TransactionMetricsSampleRate) + } return nil } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index 9e9a65f44b..0abb72b267 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -9,15 +9,6 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" ) -// Phase identifies where the main thread is spending its time. -type Phase string - -const ( - PhaseExecuting Phase = "executing" - PhaseFinalizing Phase = "finalizing" - PhaseCommitting Phase = "committing" -) - // CryptosimMetrics holds Prometheus metrics for the cryptosim benchmark. type CryptosimMetrics struct { reg *prometheus.Registry @@ -29,10 +20,7 @@ type CryptosimMetrics struct { totalErc20Contracts prometheus.Gauge dbCommitsTotal prometheus.Counter dbCommitLatency prometheus.Observer - phaseDurationTotal *prometheus.CounterVec - phaseDurationCount *prometheus.CounterVec - lastPhase Phase - lastPhaseChangeTime time.Time + mainThreadPhase *PhaseTimer } // NewCryptosimMetrics creates metrics for the cryptosim benchmark. A dedicated @@ -74,14 +62,7 @@ func NewCryptosimMetrics( Help: "Time to commit to the database in seconds", Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), }) - phaseDurationTotal := prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "cryptosim_phase_duration_seconds_total", - Help: "Total seconds spent in each phase (executing, finalizing, committing, etc.)", - }, []string{"phase"}) - phaseDurationCount := prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "cryptosim_phase_duration_count_total", - Help: "Total number of times each phase was reported", - }, []string{"phase"}) + mainThreadPhase := NewPhaseTimer(reg, "main_thread") reg.MustRegister( blocksFinalizedTotal, @@ -91,8 +72,6 @@ func NewCryptosimMetrics( totalErc20Contracts, dbCommitsTotal, dbCommitLatency, - phaseDurationTotal, - phaseDurationCount, ) return &CryptosimMetrics{ @@ -105,8 +84,7 @@ func NewCryptosimMetrics( totalErc20Contracts: totalErc20Contracts, dbCommitsTotal: dbCommitsTotal, dbCommitLatency: dbCommitLatency, - phaseDurationTotal: phaseDurationTotal, - phaseDurationCount: phaseDurationCount, + mainThreadPhase: mainThreadPhase, } } @@ -184,18 +162,9 @@ func (m *CryptosimMetrics) SetTotalNumberOfERC20Contracts(total int64) { } // SetPhase records a transition of the main thread to a new phase. -// -// SetPhase is not safe for concurrent use. -func (m *CryptosimMetrics) SetPhase(phase Phase) { - if m == nil || phase == "" { +func (m *CryptosimMetrics) SetMainThreadPhase(phase string) { + if m == nil { return } - now := time.Now() - if m.lastPhase != "" { - latency := now.Sub(m.lastPhaseChangeTime) - m.phaseDurationTotal.WithLabelValues(string(m.lastPhase)).Add(latency.Seconds()) - m.phaseDurationCount.WithLabelValues(string(m.lastPhase)).Inc() - } - m.lastPhase = phase - m.lastPhaseChangeTime = now + m.mainThreadPhase.SetPhase(phase) } diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 17ea214dab..ec4f7aa9f6 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -131,7 +131,7 @@ func (d *Database) FinalizeBlock( } finalizationStart := time.Now() - d.metrics.SetPhase(PhaseFinalizing) + d.metrics.SetMainThreadPhase("finalizing") changeSets := make([]*proto.NamedChangeSet, 0, d.transactionsInCurrentBlock+2) for key, value := range d.batch.Iterator() { @@ -174,7 +174,7 @@ func (d *Database) FinalizeBlock( // Periodically commit the changes to the database. d.uncommittedBlockCount++ if forceCommit || d.uncommittedBlockCount >= int64(d.config.BlocksPerCommit) { - d.metrics.SetPhase(PhaseCommitting) + d.metrics.SetMainThreadPhase("committing") _, err := d.db.Commit() if err != nil { return fmt.Errorf("failed to commit: %w", err) @@ -183,7 +183,7 @@ func (d *Database) FinalizeBlock( d.uncommittedBlockCount = 0 } - d.metrics.SetPhase(PhaseExecuting) + d.metrics.SetMainThreadPhase("executing") return nil } diff --git a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json index 9a9190f897..1ed4041940 100644 --- a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -31,7 +31,7 @@ }, "id": 17, "panels": [], - "title": "Key Metrics", + "title": "Overview", "type": "row" }, { @@ -51,7 +51,8 @@ "viz": false } }, - "mappings": [] + "mappings": [], + "unit": "s" }, "overrides": [] }, @@ -87,7 +88,7 @@ "targets": [ { "editorMode": "code", - "expr": "increase(cryptosim_phase_duration_seconds_total[$__rate_interval])", + "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", "legendFormat": "{{phase}}", "range": true, "refId": "A" @@ -182,7 +183,7 @@ "targets": [ { "editorMode": "code", - "expr": "rate(cryptosim_phase_duration_seconds_total[$__rate_interval])", + "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", "legendFormat": "{{phase}}", "range": true, "refId": "A" @@ -191,17 +192,112 @@ "title": "Time Spent", "type": "timeseries" }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_transactions_processed_total[5m])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transactions / Second", + "type": "timeseries" + }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 17 + "y": 25 }, "id": 13, "panels": [], - "title": "Transactions", + "title": "Execution", "type": "row" }, { @@ -262,7 +358,7 @@ } ] }, - "unit": "locale" + "unit": "s" }, "overrides": [] }, @@ -270,15 +366,15 @@ "h": 8, "w": 12, "x": 0, - "y": 18 + "y": 26 }, - "id": 16, + "id": 19, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": false + "showLegend": true }, "tooltip": { "hideZeros": false, @@ -290,13 +386,49 @@ "targets": [ { "editorMode": "code", - "expr": "rate(cryptosim_transactions_processed_total[5m])", - "legendFormat": "__auto", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "legendFormat": "p99", "range": true, "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"executing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"executing\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" } ], - "title": "Transactions / Second", + "title": "Block Execution Time", "type": "timeseries" }, { @@ -305,11 +437,11 @@ "h": 1, "w": 24, "x": 0, - "y": 26 + "y": 34 }, - "id": 12, + "id": 8, "panels": [], - "title": "Commit", + "title": "Blocks", "type": "row" }, { @@ -377,9 +509,9 @@ "h": 8, "w": 12, "x": 0, - "y": 27 + "y": 35 }, - "id": 3, + "id": 1, "options": { "legend": { "calcs": [], @@ -401,13 +533,13 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", + "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", "legendFormat": "Blocks / Second", "range": true, "refId": "A" } ], - "title": "Commits / Second", + "title": "Blocks / Second", "type": "timeseries" }, { @@ -476,9 +608,9 @@ "h": 8, "w": 12, "x": 12, - "y": 27 + "y": 35 }, - "id": 4, + "id": 18, "options": { "legend": { "calcs": [], @@ -496,7 +628,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -507,7 +639,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -519,7 +651,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(cryptosim_db_commit_latency_seconds_bucket[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -531,14 +663,14 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_db_commit_latency_seconds_sum[$__rate_interval]) / rate(cryptosim_db_commit_latency_seconds_count[$__rate_interval])", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"finalizing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"finalizing\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "DB Commit Time", + "title": "Block Finalization Time", "type": "timeseries" }, { @@ -547,11 +679,11 @@ "h": 1, "w": 24, "x": 0, - "y": 35 + "y": 43 }, - "id": 8, + "id": 12, "panels": [], - "title": "Blocks", + "title": "Commit", "type": "row" }, { @@ -619,9 +751,9 @@ "h": 8, "w": 12, "x": 0, - "y": 36 + "y": 44 }, - "id": 1, + "id": 3, "options": { "legend": { "calcs": [], @@ -643,13 +775,13 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", + "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", "legendFormat": "Blocks / Second", "range": true, "refId": "A" } ], - "title": "Blocks / Second", + "title": "Commits / Second", "type": "timeseries" }, { @@ -718,9 +850,9 @@ "h": 8, "w": 12, "x": 12, - "y": 36 + "y": 44 }, - "id": 2, + "id": 4, "options": { "legend": { "calcs": [], @@ -738,7 +870,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -749,7 +881,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -761,7 +893,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(cryptosim_block_finalization_latency_seconds_bucket[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -773,14 +905,14 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_block_finalization_latency_seconds_sum[$__rate_interval]) / rate(cryptosim_block_finalization_latency_seconds_count[$__rate_interval])", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"committing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"committing\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Block Finalization Time", + "title": "DB Commit Time", "type": "timeseries" }, { @@ -789,7 +921,7 @@ "h": 1, "w": 24, "x": 0, - "y": 44 + "y": 52 }, "id": 9, "panels": [], @@ -862,7 +994,7 @@ "h": 8, "w": 12, "x": 0, - "y": 45 + "y": 53 }, "id": 6, "options": { @@ -956,7 +1088,7 @@ "h": 8, "w": 12, "x": 12, - "y": 45 + "y": 53 }, "id": 7, "options": { @@ -1051,7 +1183,7 @@ "h": 8, "w": 12, "x": 0, - "y": 53 + "y": 61 }, "id": 10, "options": { @@ -1145,7 +1277,7 @@ "h": 8, "w": 12, "x": 12, - "y": 53 + "y": 61 }, "id": 11, "options": { @@ -1190,6 +1322,6 @@ "timezone": "browser", "title": "CryptoSim", "uid": "adnqfm4", - "version": 6, + "version": 7, "weekStart": "" } \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/phase_timer.go b/sei-db/state_db/bench/cryptosim/phase_timer.go new file mode 100644 index 0000000000..0c863181cd --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/phase_timer.go @@ -0,0 +1,85 @@ +package cryptosim + +import ( + "fmt" + "time" + + "github.com/prometheus/client_golang/prometheus" +) + +// PhaseTimer records time spent in phases (e.g., "executing", "finalizing"). +// Call SetPhase when transitioning to a new phase; latency is calculated from the +// previous transition. Not safe for concurrent use. +// +// Grafana queries (substitute PREFIX with the name passed to NewPhaseTimer): +// +// Rate, for pie chart or stacked timeseries (seconds per second): +// +// rate(PREFIX_phase_duration_seconds_total[$__rate_interval]) +// +// Average latency: +// +// rate(PREFIX_phase_latency_seconds_sum[$__rate_interval]) / +// rate(PREFIX_phase_latency_seconds_count[$__rate_interval]) +// +// Latency percentiles (p99, p95, p50). The phase label (executing, finalizing, +// etc.) distinguishes series; add {phase="executing"} to filter: +// +// histogram_quantile(0.99, rate(PREFIX_phase_latency_seconds_bucket[$__rate_interval])) +// histogram_quantile(0.95, rate(PREFIX_phase_latency_seconds_bucket[$__rate_interval])) +// histogram_quantile(0.50, rate(PREFIX_phase_latency_seconds_bucket[$__rate_interval])) +type PhaseTimer struct { + phaseDurationTotal *prometheus.CounterVec + phaseLatency *prometheus.HistogramVec + lastPhase string + lastPhaseChangeTime time.Time +} + +// NewPhaseTimer creates a PhaseTimer that registers metrics with the given name +// prefix (e.g., "cryptosim" produces cryptosim_phase_duration_seconds_total). +func NewPhaseTimer(reg *prometheus.Registry, name string) *PhaseTimer { + phaseDurationTotal := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: fmt.Sprintf("%s_phase_duration_seconds_total", name), + Help: "Total seconds spent in each phase", + }, []string{"phase"}) + phaseLatency := prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: fmt.Sprintf("%s_phase_latency_seconds", name), + Help: "Latency per phase (seconds); use for p99, p95, etc.", + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), + }, []string{"phase"}) + reg.MustRegister(phaseDurationTotal, phaseLatency) + return &PhaseTimer{ + phaseDurationTotal: phaseDurationTotal, + phaseLatency: phaseLatency, + } +} + +// SetPhase records a transition to a new phase. +func (p *PhaseTimer) SetPhase(phase string) { + if p == nil || phase == "" { + return + } + now := time.Now() + if p.lastPhase != "" { + latency := now.Sub(p.lastPhaseChangeTime) + seconds := latency.Seconds() + p.phaseDurationTotal.WithLabelValues(p.lastPhase).Add(seconds) + p.phaseLatency.WithLabelValues(p.lastPhase).Observe(seconds) + } + p.lastPhase = phase + p.lastPhaseChangeTime = now +} + +// Reset ends the current phase (capturing its metrics) and clears the phase state. +func (p *PhaseTimer) Reset() { + if p == nil { + return + } + if p.lastPhase != "" { + latency := time.Since(p.lastPhaseChangeTime) + seconds := latency.Seconds() + p.phaseDurationTotal.WithLabelValues(p.lastPhase).Add(seconds) + p.phaseLatency.WithLabelValues(p.lastPhase).Observe(seconds) + } + p.lastPhase = "" +} diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index 4a8e613513..9315a37f47 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -3,6 +3,7 @@ package cryptosim import ( "encoding/binary" "fmt" + "time" ) // The data needed to execute a transaction. @@ -41,6 +42,10 @@ type transaction struct { newSrcAccountSlot []byte // Pre-generated random value for the destination account's ERC20 storage slot. newDstAccountSlot []byte + + // If true, capture detailed (and potentially expensive) metrics about this transaction. + // We may only sample a small percentage of transactions with this flag set to true. + captureMetrics bool } // Generate all data needed to execute a transaction. @@ -83,6 +88,8 @@ func BuildTransaction( newDstData = append([]byte(nil), b...) } + captureMetrics := dataGenerator.rand.Float64() < dataGenerator.config.TransactionMetricsSampleRate + return &transaction{ srcAccount: srcAccountAddress, isSrcNew: isSrcNew, @@ -98,6 +105,7 @@ func BuildTransaction( newFeeBalance: dataGenerator.rand.Int64(), newSrcAccountSlot: append([]byte(nil), dataGenerator.rand.Bytes(dataGenerator.config.Erc20StorageSlotSize)...), newDstAccountSlot: append([]byte(nil), dataGenerator.rand.Bytes(dataGenerator.config.Erc20StorageSlotSize)...), + captureMetrics: captureMetrics, }, nil } @@ -188,7 +196,9 @@ func (txn *transaction) Execute( // Apply the random values from the transaction to the account and slot data. const minAccountBytes = 8 // balance at offset 0 - if len(srcAccountValue) < minAccountBytes || len(dstAccountValue) < minAccountBytes || len(feeValue) < minAccountBytes { + if len(srcAccountValue) < minAccountBytes || + len(dstAccountValue) < minAccountBytes || + len(feeValue) < minAccountBytes { return fmt.Errorf("account value too short for balance update (need %d bytes)", minAccountBytes) } binary.BigEndian.PutUint64(srcAccountValue[:8], uint64(txn.newSrcBalance)) @@ -234,3 +244,11 @@ func (txn *transaction) Execute( return nil } + +// Returns the current time if captureMetrics is true, otherwise returns a zero time. +func (txn *transaction) now() time.Time { // TODO + if txn.captureMetrics { + return time.Now() + } + return time.Time{} +} From e1e62d67f5bcb23606f71c4b0dbc732f429bb6f9 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Thu, 26 Feb 2026 15:58:42 -0600 Subject: [PATCH 30/49] More metrics --- sei-db/state_db/bench/cryptosim/cryptosim.go | 2 +- .../bench/cryptosim/cryptosim_metrics.go | 45 +- sei-db/state_db/bench/cryptosim/database.go | 7 +- .../bench/cryptosim/metrics/dashboard.json | 1115 ++++++++++++++++- .../state_db/bench/cryptosim/phase_timer.go | 66 +- .../state_db/bench/cryptosim/transaction.go | 27 +- .../bench/cryptosim/transaction_executor.go | 13 +- 7 files changed, 1195 insertions(+), 80 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 839db9c4f9..88256102af 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -114,7 +114,7 @@ func NewCryptoSim( executors := make([]*TransactionExecutor, threadCount) for i := 0; i < threadCount; i++ { executors[i] = NewTransactionExecutor( - ctx, database, dataGenerator.FeeCollectionAddress(), config.ExecutorQueueSize) + ctx, database, dataGenerator.FeeCollectionAddress(), config.ExecutorQueueSize, metrics) } c := &CryptoSim{ diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index 0abb72b267..c06358f697 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -14,13 +14,12 @@ type CryptosimMetrics struct { reg *prometheus.Registry ctx context.Context blocksFinalizedTotal prometheus.Counter - blockFinalizationLatency prometheus.Observer transactionsProcessedTotal prometheus.Counter totalAccounts prometheus.Gauge totalErc20Contracts prometheus.Gauge - dbCommitsTotal prometheus.Counter - dbCommitLatency prometheus.Observer - mainThreadPhase *PhaseTimer + dbCommitsTotal prometheus.Counter + mainThreadPhase *PhaseTimer + transactionPhaseTimerFactory *PhaseTimerFactory } // NewCryptosimMetrics creates metrics for the cryptosim benchmark. A dedicated @@ -36,11 +35,6 @@ func NewCryptosimMetrics( Name: "cryptosim_blocks_finalized_total", Help: "Total number of blocks finalized", }) - blockFinalizationLatency := prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "cryptosim_block_finalization_latency_seconds", - Help: "Time to finalize a block in seconds", - Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), - }) transactionsProcessedTotal := prometheus.NewCounter(prometheus.CounterOpts{ Name: "cryptosim_transactions_processed_total", Help: "Total number of transactions processed", @@ -57,34 +51,27 @@ func NewCryptosimMetrics( Name: "cryptosim_db_commits_total", Help: "Total number of database commits", }) - dbCommitLatency := prometheus.NewHistogram(prometheus.HistogramOpts{ - Name: "cryptosim_db_commit_latency_seconds", - Help: "Time to commit to the database in seconds", - Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), - }) mainThreadPhase := NewPhaseTimer(reg, "main_thread") + transactionPhaseTimerFactory := NewPhaseTimerFactory(reg, "transaction") reg.MustRegister( blocksFinalizedTotal, - blockFinalizationLatency, transactionsProcessedTotal, totalAccounts, totalErc20Contracts, dbCommitsTotal, - dbCommitLatency, ) return &CryptosimMetrics{ reg: reg, ctx: ctx, blocksFinalizedTotal: blocksFinalizedTotal, - blockFinalizationLatency: blockFinalizationLatency, transactionsProcessedTotal: transactionsProcessedTotal, totalAccounts: totalAccounts, totalErc20Contracts: totalErc20Contracts, - dbCommitsTotal: dbCommitsTotal, - dbCommitLatency: dbCommitLatency, - mainThreadPhase: mainThreadPhase, + dbCommitsTotal: dbCommitsTotal, + mainThreadPhase: mainThreadPhase, + transactionPhaseTimerFactory: transactionPhaseTimerFactory, } } @@ -117,22 +104,20 @@ func startMetricsServer(ctx context.Context, reg *prometheus.Registry, addr stri // ReportBlockFinalized records that a block was finalized, the number of // transactions in that block, and the finalization latency. -func (m *CryptosimMetrics) ReportBlockFinalized(latency time.Duration, transactionCount int64) { +func (m *CryptosimMetrics) ReportBlockFinalized(transactionCount int64) { if m == nil { return } m.blocksFinalizedTotal.Inc() m.transactionsProcessedTotal.Add(float64(transactionCount)) - m.blockFinalizationLatency.Observe(latency.Seconds()) } // ReportDBCommit records that a database commit completed and the latency. -func (m *CryptosimMetrics) ReportDBCommit(latency time.Duration) { +func (m *CryptosimMetrics) ReportDBCommit() { if m == nil { return } m.dbCommitsTotal.Inc() - m.dbCommitLatency.Observe(latency.Seconds()) } // SetTotalNumberOfAccounts sets the total number of accounts (e.g., when loading @@ -161,7 +146,17 @@ func (m *CryptosimMetrics) SetTotalNumberOfERC20Contracts(total int64) { m.totalErc20Contracts.Set(float64(total)) } -// SetPhase records a transition of the main thread to a new phase. +// GetTransactionPhaseTimerInstance returns a new PhaseTimer from the transaction +// phase timer factory. Each call returns an independent timer; use one per +// transaction executor or thread. +func (m *CryptosimMetrics) GetTransactionPhaseTimerInstance() *PhaseTimer { + if m == nil || m.transactionPhaseTimerFactory == nil { + return nil + } + return m.transactionPhaseTimerFactory.Build() +} + +// SetMainThreadPhase records a transition of the main thread to a new phase. func (m *CryptosimMetrics) SetMainThreadPhase(phase string) { if m == nil { return diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index ec4f7aa9f6..3993c7e04f 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -3,7 +3,6 @@ package cryptosim import ( "encoding/binary" "fmt" - "time" "github.com/sei-protocol/sei-chain/sei-db/proto" "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" @@ -130,7 +129,6 @@ func (d *Database) FinalizeBlock( return nil } - finalizationStart := time.Now() d.metrics.SetMainThreadPhase("finalizing") changeSets := make([]*proto.NamedChangeSet, 0, d.transactionsInCurrentBlock+2) @@ -167,8 +165,7 @@ func (d *Database) FinalizeBlock( return fmt.Errorf("failed to apply change sets: %w", err) } - finalizationFinish := time.Now() - d.metrics.ReportBlockFinalized(finalizationFinish.Sub(finalizationStart), d.transactionsInCurrentBlock) + d.metrics.ReportBlockFinalized(d.transactionsInCurrentBlock) d.transactionsInCurrentBlock = 0 // Periodically commit the changes to the database. @@ -179,7 +176,7 @@ func (d *Database) FinalizeBlock( if err != nil { return fmt.Errorf("failed to commit: %w", err) } - d.metrics.ReportDBCommit(time.Since(finalizationFinish)) + d.metrics.ReportDBCommit() d.uncommittedBlockCount = 0 } diff --git a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json index 1ed4041940..38b7c63c2e 100644 --- a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -160,7 +160,7 @@ "overrides": [] }, "gridPos": { - "h": 16, + "h": 8, "w": 12, "x": 12, "y": 1 @@ -257,8 +257,8 @@ "gridPos": { "h": 8, "w": 12, - "x": 0, - "y": 17 + "x": 12, + "y": 9 }, "id": 16, "options": { @@ -293,13 +293,76 @@ "h": 1, "w": 24, "x": 0, - "y": 25 + "y": 17 }, "id": 13, "panels": [], "title": "Execution", "type": "row" }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 20, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Transaction Time", + "type": "piechart" + }, { "datasource": { "type": "prometheus", @@ -365,8 +428,8 @@ "gridPos": { "h": 8, "w": 12, - "x": 0, - "y": 26 + "x": 12, + "y": 18 }, "id": 19, "options": { @@ -432,13 +495,1025 @@ "type": "timeseries" }, { - "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, "gridPos": { - "h": 1, - "w": 24, + "h": 8, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Transaction Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, "x": 0, "y": 34 }, + "id": 22, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_erc20\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_erc20\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read ERC20 Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 34 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Source Account Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 42 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Destination Account Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 42 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account_slot\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Source Slot Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 50 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account_slot\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Destination Slot Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 50 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_fee_collection_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_fee_collection_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Fee Collection Account Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 58 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"update_balances\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"update_balances\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Update Balances Time", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 66 + }, "id": 8, "panels": [], "title": "Blocks", @@ -509,7 +1584,7 @@ "h": 8, "w": 12, "x": 0, - "y": 35 + "y": 67 }, "id": 1, "options": { @@ -608,7 +1683,7 @@ "h": 8, "w": 12, "x": 12, - "y": 35 + "y": 67 }, "id": 18, "options": { @@ -679,7 +1754,7 @@ "h": 1, "w": 24, "x": 0, - "y": 43 + "y": 75 }, "id": 12, "panels": [], @@ -751,7 +1826,7 @@ "h": 8, "w": 12, "x": 0, - "y": 44 + "y": 76 }, "id": 3, "options": { @@ -850,7 +1925,7 @@ "h": 8, "w": 12, "x": 12, - "y": 44 + "y": 76 }, "id": 4, "options": { @@ -921,7 +1996,7 @@ "h": 1, "w": 24, "x": 0, - "y": 52 + "y": 84 }, "id": 9, "panels": [], @@ -994,7 +2069,7 @@ "h": 8, "w": 12, "x": 0, - "y": 53 + "y": 85 }, "id": 6, "options": { @@ -1088,7 +2163,7 @@ "h": 8, "w": 12, "x": 12, - "y": 53 + "y": 85 }, "id": 7, "options": { @@ -1183,7 +2258,7 @@ "h": 8, "w": 12, "x": 0, - "y": 61 + "y": 93 }, "id": 10, "options": { @@ -1277,7 +2352,7 @@ "h": 8, "w": 12, "x": 12, - "y": 61 + "y": 93 }, "id": 11, "options": { @@ -1322,6 +2397,6 @@ "timezone": "browser", "title": "CryptoSim", "uid": "adnqfm4", - "version": 7, + "version": 9, "weekStart": "" } \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/phase_timer.go b/sei-db/state_db/bench/cryptosim/phase_timer.go index 0c863181cd..9389f8c56f 100644 --- a/sei-db/state_db/bench/cryptosim/phase_timer.go +++ b/sei-db/state_db/bench/cryptosim/phase_timer.go @@ -7,11 +7,54 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +// PhaseTimerFactory constructs shared Prometheus metrics and builds independent +// PhaseTimer instances. Use Build() to create a timer for each thread. +type PhaseTimerFactory struct { + phaseDurationTotal *prometheus.CounterVec + phaseLatency *prometheus.HistogramVec +} + +// NewPhaseTimerFactory creates a factory that registers metrics with the given +// name prefix (e.g., "main_thread" produces main_thread_phase_duration_seconds_total). +func NewPhaseTimerFactory(reg *prometheus.Registry, name string) *PhaseTimerFactory { + phaseDurationTotal := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: fmt.Sprintf("%s_phase_duration_seconds_total", name), + Help: "Total seconds spent in each phase", + }, []string{"phase"}) + phaseLatency := prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Name: fmt.Sprintf("%s_phase_latency_seconds", name), + Help: "Latency per phase (seconds); use for p99, p95, etc.", + Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), + }, []string{"phase"}) + reg.MustRegister(phaseDurationTotal, phaseLatency) + return &PhaseTimerFactory{ + phaseDurationTotal: phaseDurationTotal, + phaseLatency: phaseLatency, + } +} + +// NewPhaseTimer creates a factory and builds a single PhaseTimer. Convenient when +// only one timer is needed (e.g., for a single-threaded main loop). +func NewPhaseTimer(reg *prometheus.Registry, name string) *PhaseTimer { + return NewPhaseTimerFactory(reg, name).Build() +} + +// Build returns a new PhaseTimer that records to this factory's metrics. +// Each timer has independent phase state; safe for use by different threads. +func (f *PhaseTimerFactory) Build() *PhaseTimer { + return &PhaseTimer{ + phaseDurationTotal: f.phaseDurationTotal, + phaseLatency: f.phaseLatency, + lastPhase: "", + lastPhaseChangeTime: time.Time{}, + } +} + // PhaseTimer records time spent in phases (e.g., "executing", "finalizing"). // Call SetPhase when transitioning to a new phase; latency is calculated from the -// previous transition. Not safe for concurrent use. +// previous transition. Not safe for concurrent use on a single instance. // -// Grafana queries (substitute PREFIX with the name passed to NewPhaseTimer): +// Grafana queries (substitute PREFIX with the name passed to NewPhaseTimer or NewPhaseTimerFactory): // // Rate, for pie chart or stacked timeseries (seconds per second): // @@ -35,25 +78,6 @@ type PhaseTimer struct { lastPhaseChangeTime time.Time } -// NewPhaseTimer creates a PhaseTimer that registers metrics with the given name -// prefix (e.g., "cryptosim" produces cryptosim_phase_duration_seconds_total). -func NewPhaseTimer(reg *prometheus.Registry, name string) *PhaseTimer { - phaseDurationTotal := prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: fmt.Sprintf("%s_phase_duration_seconds_total", name), - Help: "Total seconds spent in each phase", - }, []string{"phase"}) - phaseLatency := prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Name: fmt.Sprintf("%s_phase_latency_seconds", name), - Help: "Latency per phase (seconds); use for p99, p95, etc.", - Buckets: prometheus.ExponentialBucketsRange(0.001, 10, 12), - }, []string{"phase"}) - reg.MustRegister(phaseDurationTotal, phaseLatency) - return &PhaseTimer{ - phaseDurationTotal: phaseDurationTotal, - phaseLatency: phaseLatency, - } -} - // SetPhase records a transition to a new phase. func (p *PhaseTimer) SetPhase(phase string) { if p == nil || phase == "" { diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index 9315a37f47..e139c156b5 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -3,7 +3,6 @@ package cryptosim import ( "encoding/binary" "fmt" - "time" ) // The data needed to execute a transaction. @@ -116,8 +115,11 @@ func BuildTransaction( func (txn *transaction) Execute( database *Database, feeCollectionAddress []byte, + phaseTimer *PhaseTimer, ) error { + phaseTimer.SetPhase("read_erc20") + // Read the simulated ERC20 contract. _, found, err := database.Get(txn.erc20Contract) if err != nil { @@ -134,6 +136,8 @@ func (txn *transaction) Execute( // - the receiver's storage slot for the ERC20 contract // - the fee collection account's native balance + phaseTimer.SetPhase("read_src_account") + // Read the sender's native balance / nonce / codehash. srcAccountValue, found, err := database.Get(txn.srcAccount) if err != nil { @@ -153,6 +157,8 @@ func (txn *transaction) Execute( } } + phaseTimer.SetPhase("read_dst_account") + // Read the receiver's native balance. dstAccountValue, found, err := database.Get(txn.dstAccount) if err != nil { @@ -171,6 +177,8 @@ func (txn *transaction) Execute( } } + phaseTimer.SetPhase("read_src_account_slot") + // Read the sender's storage slot for the ERC20 contract. // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. _, _, err = database.Get(txn.srcAccountSlot) @@ -178,6 +186,8 @@ func (txn *transaction) Execute( return fmt.Errorf("failed to get source account slot: %w", err) } + phaseTimer.SetPhase("read_dst_account_slot") + // Read the receiver's storage slot for the ERC20 contract. // We don't care if the value isn't in the DB yet, since we don't pre-populate the database with storage slots. _, _, err = database.Get(txn.dstAccountSlot) @@ -185,6 +195,8 @@ func (txn *transaction) Execute( return fmt.Errorf("failed to get destination account slot: %w", err) } + phaseTimer.SetPhase("read_fee_collection_account") + // Read the fee collection account's native balance. feeValue, found, err := database.Get(feeCollectionAddress) if err != nil { @@ -194,6 +206,8 @@ func (txn *transaction) Execute( return fmt.Errorf("fee collection account not found") } + phaseTimer.SetPhase("update_balances") + // Apply the random values from the transaction to the account and slot data. const minAccountBytes = 8 // balance at offset 0 if len(srcAccountValue) < minAccountBytes || @@ -242,13 +256,12 @@ func (txn *transaction) Execute( return fmt.Errorf("failed to put fee collection account: %w", err) } + phaseTimer.Reset() + return nil } -// Returns the current time if captureMetrics is true, otherwise returns a zero time. -func (txn *transaction) now() time.Time { // TODO - if txn.captureMetrics { - return time.Now() - } - return time.Time{} +// Returns true if metrics should be captured for this transaction. +func (txn *transaction) ShouldCaptureMetrics() bool { + return txn.captureMetrics } diff --git a/sei-db/state_db/bench/cryptosim/transaction_executor.go b/sei-db/state_db/bench/cryptosim/transaction_executor.go index 27478de53a..5cd90a52ec 100644 --- a/sei-db/state_db/bench/cryptosim/transaction_executor.go +++ b/sei-db/state_db/bench/cryptosim/transaction_executor.go @@ -16,6 +16,9 @@ type TransactionExecutor struct { // The Incoming transactions to be executed. workChan chan any + + // Used to time the execution of transactions. + phaseTimer *PhaseTimer } // A request to flush the transaction executor. @@ -29,12 +32,14 @@ func NewTransactionExecutor( database *Database, feeCollectionAddress []byte, queueSize int, + metrics *CryptosimMetrics, ) *TransactionExecutor { e := &TransactionExecutor{ ctx: ctx, database: database, feeCollectionAddress: feeCollectionAddress, workChan: make(chan any, queueSize), + phaseTimer: metrics.GetTransactionPhaseTimerInstance(), } go e.mainLoop() @@ -75,7 +80,13 @@ func (e *TransactionExecutor) mainLoop() { case request := <-e.workChan: switch request := request.(type) { case *transaction: - if err := request.Execute(e.database, e.feeCollectionAddress); err != nil { + + var phaseTimer *PhaseTimer + if request.ShouldCaptureMetrics() { + phaseTimer = e.phaseTimer + } + + if err := request.Execute(e.database, e.feeCollectionAddress, phaseTimer); err != nil { log.Printf("transaction execution error: %v", err) } case flushRequest: From 6a8613feada5a96f0c8b68fd33a759627ad35164 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 08:28:43 -0600 Subject: [PATCH 31/49] several TODOs --- sei-db/state_db/bench/cryptosim/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sei-db/state_db/bench/cryptosim/README.md b/sei-db/state_db/bench/cryptosim/README.md index f9cfd8af8b..ee7f17865e 100644 --- a/sei-db/state_db/bench/cryptosim/README.md +++ b/sei-db/state_db/bench/cryptosim/README.md @@ -50,3 +50,14 @@ The following features might be useful to add to this benchmark: - Metrics exported by the underlying DB - Prometheus/Grafana dashboards to visualize metrics - More exotic key access patterns + + +# Setting Up Prometheus / Grafana + +TODO + +Other TODOs: + +- system metrics (e.g. memory, cpu, thread count, IO info if it's available) +- disk utilization +- disk utilizaiton per account (good for detecting disk leaks) From ec119a3c4d21a989f58d6aed23660b376f99962f Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 09:06:45 -0600 Subject: [PATCH 32/49] made suggested changes --- .../bench/cryptosim/config/basic-config.json | 3 +- sei-db/state_db/bench/cryptosim/cryptosim.go | 49 +++++++++++++------ .../bench/cryptosim/cryptosim_config.go | 19 ++++++- .../bench/cryptosim/data_generator.go | 1 - sei-db/state_db/bench/cryptosim/database.go | 2 +- sei-db/state_db/bench/cryptosim/main/main.go | 9 +++- 6 files changed, 63 insertions(+), 20 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index bc8eca2430..b1e177bc1d 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -22,5 +22,6 @@ "Seed": 1337, "SetupUpdateIntervalCount": 100000, "ThreadsPerCore": 2.0, - "TransactionsPerBlock": 1024 + "TransactionsPerBlock": 1024, + "MaxRuntimeSeconds": 60 } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 222b41695d..8c9a89f4f5 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -42,8 +42,8 @@ type CryptoSim struct { // The time the benchmark started. startTimestamp time.Time - // The run channel sends a signal on this channel when it has halted. - runHaltedChan chan struct{} + // A message is sent on this channel when the benchmark is fully stopped and all resources have been released. + closeChan chan struct{} // The data generator for the benchmark. dataGenerator *DataGenerator @@ -117,7 +117,7 @@ func NewCryptoSim( consoleUpdatePeriod: consoleUpdatePeriod, lastConsoleUpdateTime: start, lastConsoleUpdateTransactionCount: 0, - runHaltedChan: make(chan struct{}, 1), + closeChan: make(chan struct{}, 1), dataGenerator: dataGenerator, database: database, executors: executors, @@ -232,7 +232,7 @@ func (c *CryptoSim) setupErc20Contracts() error { c.database.IncrementTransactionCount() - _, _, err := c.dataGenerator.CreateNewErc20Contract(c, c.config.Erc20ContractSize, true) + _, _, err := c.dataGenerator.CreateNewErc20Contract(c.config.Erc20ContractSize, true) if err != nil { return fmt.Errorf("failed to create new ERC20 contract: %w", err) } @@ -274,9 +274,9 @@ func (c *CryptoSim) setupErc20Contracts() error { // The main loop of the benchmark. func (c *CryptoSim) run() { - defer func() { - c.runHaltedChan <- struct{}{} - }() + defer c.teardown() + + haltTime := time.Now().Add(time.Duration(c.config.MaxRuntimeSeconds * time.Second)) for { select { @@ -291,6 +291,7 @@ func (c *CryptoSim) run() { txn, err := BuildTransaction(c.dataGenerator) if err != nil { fmt.Printf("\nfailed to build transaction: %v\n", err) + continue } c.executors[c.nextExecutorIndex].ScheduleForExecution(txn) @@ -303,6 +304,10 @@ func (c *CryptoSim) run() { } if finalized { c.dataGenerator.ReportFinalizeBlock() + + if c.config.MaxRuntimeSeconds > 0 && time.Now().After(haltTime) { + c.cancel() + } } c.database.IncrementTransactionCount() @@ -311,6 +316,18 @@ func (c *CryptoSim) run() { } } +// Clean up the benchmark and release any resources. +func (c *CryptoSim) teardown() { + err := c.database.Close(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) + if err != nil { + fmt.Printf("failed to close database: %v\n", err) + } + + c.dataGenerator.Close() + + c.closeChan <- struct{}{} +} + // Generates a human readable report of the benchmark's progress. func (c *CryptoSim) generateConsoleReport(force bool) { @@ -345,14 +362,10 @@ func (c *CryptoSim) generateConsoleReport(force bool) { // Shut down the benchmark and release any resources. func (c *CryptoSim) Close() error { c.cancel() - <-c.runHaltedChan + <-c.closeChan - err := c.database.Close(c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) - if err != nil { - return fmt.Errorf("failed to close database: %w", err) - } - - c.dataGenerator.Close() + // "reload" closeChan in case other goroutines are waiting on it. + c.closeChan <- struct{}{} fmt.Printf("Benchmark terminated successfully.\n") @@ -365,3 +378,11 @@ func (c *CryptoSim) flushExecutors() { executor.Flush() } } + +// Blocks until the benchmark has halted. +func (c *CryptoSim) BlockUntilHalted() { + <-c.closeChan + + // "reload" closeChan in case other goroutines are waiting on it. + c.closeChan <- struct{}{} +} diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index 5c9967459e..986902579b 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "os" + "time" "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" ) @@ -104,13 +105,16 @@ type CryptoSimConfig struct { // The size of the queue for each transaction executor. ExecutorQueueSize int + + // The amount of time to run the benchmark for. If 0, the benchmark will run until it is stopped. + MaxRuntimeSeconds time.Duration } // Returns the default configuration for the cryptosim benchmark. func DefaultCryptoSimConfig() *CryptoSimConfig { // Note: if you add new fields or modify default values, be sure to keep config/basic-config.json in sync. - // That file should conatain every available config set to its default value, as a reference. + // That file should contain every available config set to its default value, as a reference. return &CryptoSimConfig{ MinimumNumberOfAccounts: 1_000_000, @@ -135,7 +139,17 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { ThreadsPerCore: 2.0, ConstantThreadCount: 0, ExecutorQueueSize: 64, + MaxRuntimeSeconds: 0, + } +} + +// StringifiedConfig returns the config as human-readable, multi-line JSON. +func (c *CryptoSimConfig) StringifiedConfig() (string, error) { + b, err := json.MarshalIndent(c, "", " ") + if err != nil { + return "", err } + return string(b), nil } // Validate checks that the configuration is sane and returns an error if not. @@ -185,6 +199,9 @@ func (c *CryptoSimConfig) Validate() error { if c.SetupUpdateIntervalCount < 1 { return fmt.Errorf("SetupUpdateIntervalCount must be at least 1 (got %d)", c.SetupUpdateIntervalCount) } + if c.MaxRuntimeSeconds < 0 { + return fmt.Errorf("MaxRuntimeSeconds must be at least 0 (got %d)", c.MaxRuntimeSeconds) + } return nil } diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go index 5635acd976..ac1fd14c4b 100644 --- a/sei-db/state_db/bench/cryptosim/data_generator.go +++ b/sei-db/state_db/bench/cryptosim/data_generator.go @@ -139,7 +139,6 @@ func (d *DataGenerator) CreateNewAccount( // Creates a new ERC20 contract and optionally writes it to the database. Returns the address of the new ERC20 contract. func (d *DataGenerator) CreateNewErc20Contract( - cryptosim *CryptoSim, // The number of bytes to allocate for the ERC20 contract data. erc20ContractSize int, // If true, the ERC20 contract will be immediately written to the database. diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index b80b089b4a..383694fd65 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -49,7 +49,7 @@ func NewDatabase( // Insert a key-value pair into the database/cache. // // This method is safe to call concurrently with other calls to Put() and Get(). Is not thread -// safe with FinalizeBlock(). +// safe with FinalizeBlock(). It is not thread safe to modify the returned value (make a copy first). func (d *Database) Put(key []byte, value []byte) error { d.batch.Put(string(key), value) return nil diff --git a/sei-db/state_db/bench/cryptosim/main/main.go b/sei-db/state_db/bench/cryptosim/main/main.go index efb6365067..5afb758bd0 100644 --- a/sei-db/state_db/bench/cryptosim/main/main.go +++ b/sei-db/state_db/bench/cryptosim/main/main.go @@ -28,6 +28,12 @@ func run() error { return err } + configString, err := config.StringifiedConfig() + if err != nil { + return fmt.Errorf("failed to stringify config: %w", err) + } + fmt.Printf("%s\n", configString) + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) defer stop() @@ -36,14 +42,13 @@ func run() error { return fmt.Errorf("failed to create cryptosim: %w", err) } defer func() { - fmt.Printf("\nInitiating teardown.\n") err := cs.Close() if err != nil { fmt.Fprintf(os.Stderr, "Error closing cryptosim: %v\n", err) } }() - <-ctx.Done() + cs.BlockUntilHalted() return nil } From 27dc9ecda44abdf01071fec8f413ec7cf87d14eb Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 09:07:27 -0600 Subject: [PATCH 33/49] fix default value --- sei-db/state_db/bench/cryptosim/config/basic-config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index b1e177bc1d..f7576d849d 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -23,5 +23,5 @@ "SetupUpdateIntervalCount": 100000, "ThreadsPerCore": 2.0, "TransactionsPerBlock": 1024, - "MaxRuntimeSeconds": 60 + "MaxRuntimeSeconds": 0 } From 5aacc23c38c5cc18d247e5d00b8e05aa5954065f Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 09:21:33 -0600 Subject: [PATCH 34/49] halt on errors --- sei-db/state_db/bench/cryptosim/cryptosim.go | 5 ++++- sei-db/state_db/bench/cryptosim/transaction_executor.go | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 45c8bf88e2..5058b0b51e 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -114,7 +114,7 @@ func NewCryptoSim( executors := make([]*TransactionExecutor, threadCount) for i := 0; i < threadCount; i++ { executors[i] = NewTransactionExecutor( - ctx, database, dataGenerator.FeeCollectionAddress(), config.ExecutorQueueSize, metrics) + ctx, cancel, database, dataGenerator.FeeCollectionAddress(), config.ExecutorQueueSize, metrics) } c := &CryptoSim{ @@ -305,6 +305,7 @@ func (c *CryptoSim) run() { txn, err := BuildTransaction(c.dataGenerator) if err != nil { fmt.Printf("\nfailed to build transaction: %v\n", err) + c.cancel() continue } @@ -315,6 +316,8 @@ func (c *CryptoSim) run() { c.dataGenerator.NextAccountID(), c.dataGenerator.NextErc20ContractID()) if err != nil { fmt.Printf("error finalizing block: %v\n", err) + c.cancel() + continue } if finalized { c.dataGenerator.ReportFinalizeBlock() diff --git a/sei-db/state_db/bench/cryptosim/transaction_executor.go b/sei-db/state_db/bench/cryptosim/transaction_executor.go index 5cd90a52ec..fb35350026 100644 --- a/sei-db/state_db/bench/cryptosim/transaction_executor.go +++ b/sei-db/state_db/bench/cryptosim/transaction_executor.go @@ -6,7 +6,8 @@ import ( ) type TransactionExecutor struct { - ctx context.Context + ctx context.Context + cancel context.CancelFunc // The database for the benchmark. database *Database @@ -29,6 +30,7 @@ type flushRequest struct { // A single threaded transaction executor. func NewTransactionExecutor( ctx context.Context, + cancel context.CancelFunc, database *Database, feeCollectionAddress []byte, queueSize int, @@ -88,6 +90,7 @@ func (e *TransactionExecutor) mainLoop() { if err := request.Execute(e.database, e.feeCollectionAddress, phaseTimer); err != nil { log.Printf("transaction execution error: %v", err) + e.cancel() } case flushRequest: request.doneChan <- struct{}{} From 53249902480d0efa1b23a8d80f3b9cf9b9b1c8d0 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 09:58:06 -0600 Subject: [PATCH 35/49] lint --- sei-db/state_db/bench/cryptosim/canned_random.go | 8 +++++++- sei-db/state_db/bench/cryptosim/cryptosim.go | 6 ++++-- sei-db/state_db/bench/cryptosim/cryptosim_config.go | 13 +++++++++---- sei-db/state_db/bench/cryptosim/data_generator.go | 3 +++ sei-db/state_db/bench/cryptosim/database.go | 2 ++ sei-db/state_db/bench/cryptosim/transaction.go | 6 +++--- sei-db/state_db/bench/cryptosim/util.go | 7 ++++--- sei-db/state_db/bench/wrappers/composite_wrapper.go | 3 --- .../state_db/bench/wrappers/db_implementations.go | 12 +++++++++--- sei-db/state_db/bench/wrappers/memiavl_wrapper.go | 3 --- 10 files changed, 41 insertions(+), 22 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/canned_random.go b/sei-db/state_db/bench/cryptosim/canned_random.go index eb9895b4c3..d4f1368b29 100644 --- a/sei-db/state_db/bench/cryptosim/canned_random.go +++ b/sei-db/state_db/bench/cryptosim/canned_random.go @@ -49,7 +49,9 @@ func NewCannedRandom( rng := rand.New(source) buffer := make([]byte, bufferSize) - rng.Read(buffer) + if _, err := rng.Read(buffer); err != nil { + panic(fmt.Sprintf("failed to read random bytes: %v", err)) + } return &CannedRandom{ buffer: buffer, @@ -89,6 +91,7 @@ func (cr *CannedRandom) Int64() int64 { buf[i] = cr.buffer[(cr.index+i)%bufLen] } base := binary.BigEndian.Uint64(buf[:]) + //nolint:gosec // G115 - benchmark uses deterministic non-crypto randomness, overflow acceptable result := Hash64(int64(base) + cr.index) // Add 8 to the index to skip the 8 bytes we just read. @@ -105,12 +108,14 @@ func (cr *CannedRandom) Int64Range(min int64, max int64) int64 { if max < min { panic(fmt.Sprintf("max must be >= min, got min=%d max=%d", min, max)) } + //nolint:gosec // G115 - benchmark uses deterministic non-crypto randomness, overflow acceptable return min + int64(uint64(cr.Int64())%uint64(max-min)) } // Float64 returns a random float64 in the range [0.0, 1.0]. // It uses Int64() internally and converts the result to the proper range. func (cr *CannedRandom) Float64() float64 { + //nolint:gosec // G115 - benchmark uses deterministic non-crypto randomness, overflow acceptable return float64(uint64(cr.Int64())) / float64(math.MaxUint64) } @@ -150,6 +155,7 @@ func (cr *CannedRandom) Address( baseBytes := cr.SeededBytes(AddressLen, id) copy(result, baseBytes) result[0] = addressType + //nolint:gosec // G115 - id is from benchmark data, overflow acceptable for address generation binary.BigEndian.PutUint64(result[9:], uint64(id)) return result diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 8c9a89f4f5..ba03e4026f 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -94,7 +94,9 @@ func NewCryptoSim( dataGenerator, err := NewDataGenerator(config, database, rand) if err != nil { cancel() - db.Close() + if closeErr := db.Close(); closeErr != nil { + fmt.Printf("failed to close database during error recovery: %v\n", closeErr) + } return nil, fmt.Errorf("failed to create data generator: %w", err) } @@ -276,7 +278,7 @@ func (c *CryptoSim) run() { defer c.teardown() - haltTime := time.Now().Add(time.Duration(c.config.MaxRuntimeSeconds * time.Second)) + haltTime := time.Now().Add(time.Duration(c.config.MaxRuntimeSeconds) * time.Second) for { select { diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index 986902579b..ff69b8c42e 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" "os" - "time" + "path/filepath" "github.com/sei-protocol/sei-chain/sei-db/state_db/bench/wrappers" ) @@ -107,7 +107,7 @@ type CryptoSimConfig struct { ExecutorQueueSize int // The amount of time to run the benchmark for. If 0, the benchmark will run until it is stopped. - MaxRuntimeSeconds time.Duration + MaxRuntimeSeconds int } // Returns the default configuration for the cryptosim benchmark. @@ -210,11 +210,16 @@ func (c *CryptoSimConfig) Validate() error { // unrecognized configuration keys. func LoadConfigFromFile(path string) (*CryptoSimConfig, error) { cfg := DefaultCryptoSimConfig() - f, err := os.Open(path) + //nolint:gosec // G304 - path comes from config file, filepath.Clean used to mitigate traversal + f, err := os.Open(filepath.Clean(path)) if err != nil { return nil, fmt.Errorf("open config file: %w", err) } - defer f.Close() + defer func() { + if err := f.Close(); err != nil { + fmt.Printf("failed to close config file: %v\n", err) + } + }() dec := json.NewDecoder(f) dec.DisallowUnknownFields() diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go index ac1fd14c4b..e09bb438e6 100644 --- a/sei-db/state_db/bench/cryptosim/data_generator.go +++ b/sei-db/state_db/bench/cryptosim/data_generator.go @@ -55,6 +55,7 @@ func NewDataGenerator( } var nextAccountID int64 if found { + //nolint:gosec // G115 - persisted counter value, overflow acceptable nextAccountID = int64(binary.BigEndian.Uint64(nextAccountIDBinary)) } @@ -66,6 +67,7 @@ func NewDataGenerator( } var nextErc20ContractID int64 if found { + //nolint:gosec // G115 - persisted counter value, overflow acceptable nextErc20ContractID = int64(binary.BigEndian.Uint64(nextErc20ContractIDBinary)) } @@ -123,6 +125,7 @@ func (d *DataGenerator) CreateNewAccount( accountData := make([]byte, accountSize) + //nolint:gosec // G115 - balance is benchmark simulation value, overflow acceptable binary.BigEndian.PutUint64(accountData[:8], uint64(balance)) // The remaining bytes are random data for padding. diff --git a/sei-db/state_db/bench/cryptosim/database.go b/sei-db/state_db/bench/cryptosim/database.go index 383694fd65..c685187d59 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -137,6 +137,7 @@ func (d *Database) FinalizeBlock( // Persist the account ID counter in every batch. nonceValue := make([]byte, 8) + //nolint:gosec // G115 - nextAccountID is benchmark counter, overflow acceptable binary.BigEndian.PutUint64(nonceValue, uint64(nextAccountID)) changeSets = append(changeSets, &proto.NamedChangeSet{ Name: wrappers.EVMStoreName, @@ -147,6 +148,7 @@ func (d *Database) FinalizeBlock( // Persist the ERC20 contract ID counter in every batch. erc20ContractIDValue := make([]byte, 8) + //nolint:gosec // G115 - nextErc20ContractID is benchmark counter, overflow acceptable binary.BigEndian.PutUint64(erc20ContractIDValue, uint64(nextErc20ContractID)) changeSets = append(changeSets, &proto.NamedChangeSet{ Name: wrappers.EVMStoreName, diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index 4a8e613513..ffcd57fcdb 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -191,9 +191,9 @@ func (txn *transaction) Execute( if len(srcAccountValue) < minAccountBytes || len(dstAccountValue) < minAccountBytes || len(feeValue) < minAccountBytes { return fmt.Errorf("account value too short for balance update (need %d bytes)", minAccountBytes) } - binary.BigEndian.PutUint64(srcAccountValue[:8], uint64(txn.newSrcBalance)) - binary.BigEndian.PutUint64(dstAccountValue[:8], uint64(txn.newDstBalance)) - binary.BigEndian.PutUint64(feeValue[:8], uint64(txn.newFeeBalance)) + binary.BigEndian.PutUint64(srcAccountValue[:8], uint64(txn.newSrcBalance)) //nolint:gosec + binary.BigEndian.PutUint64(dstAccountValue[:8], uint64(txn.newDstBalance)) //nolint:gosec + binary.BigEndian.PutUint64(feeValue[:8], uint64(txn.newFeeBalance)) //nolint:gosec // Write the following: // - the sender's native balance / nonce / codehash diff --git a/sei-db/state_db/bench/cryptosim/util.go b/sei-db/state_db/bench/cryptosim/util.go index 355e1829e5..0cc4453e82 100644 --- a/sei-db/state_db/bench/cryptosim/util.go +++ b/sei-db/state_db/bench/cryptosim/util.go @@ -51,11 +51,12 @@ func paddedCounterKey(s string) []byte { // - Public domain reference implementation: // http://xorshift.di.unimi.it/splitmix64.c func Hash64(x int64) int64 { - z := uint64(x) + z := uint64(x) //nolint:gosec // G115 - hash function, int64->uint64 conversion intentional z += 0x9e3779b97f4a7c15 z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9 z = (z ^ (z >> 27)) * 0x94d049bb133111eb z = z ^ (z >> 31) + //nolint:gosec // G115 - hash function converts uint64 to int64, overflow intentional return int64(z) } @@ -86,7 +87,7 @@ func resolveAndCreateDataDir(dataDir string) (string, error) { } } if dataDir != "" { - if err := os.MkdirAll(dataDir, 0755); err != nil { + if err := os.MkdirAll(dataDir, 0o750); err != nil { return "", fmt.Errorf("failed to create data directory: %w", err) } } @@ -168,7 +169,7 @@ func formatDuration(d time.Duration, decimals int) string { } format := fmt.Sprintf("%%.%df%%s", decimals) ns := d.Nanoseconds() - abs := int64(ns) + abs := ns if abs < 0 { abs = -abs } diff --git a/sei-db/state_db/bench/wrappers/composite_wrapper.go b/sei-db/state_db/bench/wrappers/composite_wrapper.go index 863facd1f6..05bdf10afc 100644 --- a/sei-db/state_db/bench/wrappers/composite_wrapper.go +++ b/sei-db/state_db/bench/wrappers/composite_wrapper.go @@ -47,9 +47,6 @@ func (c *compositeWrapper) Close() error { func (c *compositeWrapper) Read(key []byte) (data []byte, found bool, err error) { store := c.base.GetChildStoreByName(EVMStoreName) - if store == nil { - return nil, false, nil - } data = store.Get(key) return data, data != nil, nil } diff --git a/sei-db/state_db/bench/wrappers/db_implementations.go b/sei-db/state_db/bench/wrappers/db_implementations.go index 4a1868c80c..1901fdc18c 100644 --- a/sei-db/state_db/bench/wrappers/db_implementations.go +++ b/sei-db/state_db/bench/wrappers/db_implementations.go @@ -31,7 +31,9 @@ func newMemIAVLCommitStore(dbDir string) (DBWrapper, error) { cs.Initialize([]string{EVMStoreName}) _, err := cs.LoadVersion(0, false) if err != nil { - cs.Close() + if closeErr := cs.Close(); closeErr != nil { + fmt.Printf("failed to close commit store during error recovery: %v\n", closeErr) + } return nil, fmt.Errorf("failed to load version: %w", err) } return NewMemIAVLWrapper(cs), nil @@ -44,7 +46,9 @@ func newFlatKVCommitStore(dbDir string) (DBWrapper, error) { cs := flatkv.NewCommitStore(dbDir, logger.NewNopLogger(), cfg) _, err := cs.LoadVersion(0) if err != nil { - cs.Close() + if closeErr := cs.Close(); closeErr != nil { + fmt.Printf("failed to close commit store during error recovery: %v\n", closeErr) + } return nil, fmt.Errorf("failed to load version: %w", err) } return NewFlatKVWrapper(cs), nil @@ -61,7 +65,9 @@ func newCompositeCommitStore(dbDir string, writeMode config.WriteMode) (DBWrappe loaded, err := cs.LoadVersion(0, false) if err != nil { - cs.Close() + if closeErr := cs.Close(); closeErr != nil { + fmt.Printf("failed to close commit store during error recovery: %v\n", closeErr) + } return nil, fmt.Errorf("failed to load version: %w", err) } diff --git a/sei-db/state_db/bench/wrappers/memiavl_wrapper.go b/sei-db/state_db/bench/wrappers/memiavl_wrapper.go index d7637acb0e..09a8fc186a 100644 --- a/sei-db/state_db/bench/wrappers/memiavl_wrapper.go +++ b/sei-db/state_db/bench/wrappers/memiavl_wrapper.go @@ -51,9 +51,6 @@ func (m *memIAVLWrapper) Close() error { func (m *memIAVLWrapper) Read(key []byte) (data []byte, found bool, err error) { store := m.base.GetChildStoreByName(EVMStoreName) - if store == nil { - return nil, false, nil - } data = store.Get(key) return data, data != nil, nil } From 9a19fd889bdee8717f419b89c24ed16a744fc154 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 10:03:26 -0600 Subject: [PATCH 36/49] made suggested changes --- sei-db/state_db/bench/cryptosim/README.md | 2 +- sei-db/state_db/bench/helper.go | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/README.md b/sei-db/state_db/bench/cryptosim/README.md index f9cfd8af8b..3fe791a79e 100644 --- a/sei-db/state_db/bench/cryptosim/README.md +++ b/sei-db/state_db/bench/cryptosim/README.md @@ -24,7 +24,7 @@ significant setup time. Note that if continuing from an earlier run, you may not alter the `Seed`, `CannedRandomSize`, or `AccountKeySize` parameters, since keys are deterministically derived from these configuration values. -# Transaciton Model +# Transaction Model The goal of this benchmark is to generate database load similar to that generated by processing ERC20 transactions. diff --git a/sei-db/state_db/bench/helper.go b/sei-db/state_db/bench/helper.go index ef53f17f81..4303f0f47d 100644 --- a/sei-db/state_db/bench/helper.go +++ b/sei-db/state_db/bench/helper.go @@ -397,10 +397,6 @@ func runBenchmark(b *testing.B, scenario TestScenario, withProgress bool) { b.StopTimer() cs, err := wrappers.NewDBImpl(scenario.Backend, dbDir) require.NoError(b, err) - defer func() { - err := cs.Close() - require.NoError(b, err) - }() // Load snapshot if available if scenario.SnapshotPath != "" { From cc7be77cbf498b6e7915da1f4daf19310e61d61a Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 10:32:40 -0600 Subject: [PATCH 37/49] system metrics --- .../bench/cryptosim/cryptosim_metrics.go | 31 +- .../bench/cryptosim/metrics/dashboard.json | 3834 ++++++++++------- 2 files changed, 2290 insertions(+), 1575 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index c06358f697..e4c1efe28c 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -6,17 +6,18 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" ) // CryptosimMetrics holds Prometheus metrics for the cryptosim benchmark. type CryptosimMetrics struct { - reg *prometheus.Registry - ctx context.Context - blocksFinalizedTotal prometheus.Counter - transactionsProcessedTotal prometheus.Counter - totalAccounts prometheus.Gauge - totalErc20Contracts prometheus.Gauge + reg *prometheus.Registry + ctx context.Context + blocksFinalizedTotal prometheus.Counter + transactionsProcessedTotal prometheus.Counter + totalAccounts prometheus.Gauge + totalErc20Contracts prometheus.Gauge dbCommitsTotal prometheus.Counter mainThreadPhase *PhaseTimer transactionPhaseTimerFactory *PhaseTimerFactory @@ -31,6 +32,12 @@ func NewCryptosimMetrics( ) *CryptosimMetrics { reg := prometheus.NewRegistry() + // Register automatic process and Go runtime metrics (CPU, memory, goroutines, etc.) + reg.MustRegister( + collectors.NewGoCollector(), + collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}), + ) + blocksFinalizedTotal := prometheus.NewCounter(prometheus.CounterOpts{ Name: "cryptosim_blocks_finalized_total", Help: "Total number of blocks finalized", @@ -63,12 +70,12 @@ func NewCryptosimMetrics( ) return &CryptosimMetrics{ - reg: reg, - ctx: ctx, - blocksFinalizedTotal: blocksFinalizedTotal, - transactionsProcessedTotal: transactionsProcessedTotal, - totalAccounts: totalAccounts, - totalErc20Contracts: totalErc20Contracts, + reg: reg, + ctx: ctx, + blocksFinalizedTotal: blocksFinalizedTotal, + transactionsProcessedTotal: transactionsProcessedTotal, + totalAccounts: totalAccounts, + totalErc20Contracts: totalErc20Contracts, dbCommitsTotal: dbCommitsTotal, mainThreadPhase: mainThreadPhase, transactionPhaseTimerFactory: transactionPhaseTimerFactory, diff --git a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json index 38b7c63c2e..2944b1c6e2 100644 --- a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -22,1489 +22,2369 @@ "links": [], "panels": [ { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 17, - "panels": [], - "title": "Overview", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - } - }, - "mappings": [], - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 12, - "x": 0, - "y": 1 - }, - "id": 14, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "pieType": "pie", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "sort": "desc", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", - "range": true, - "refId": "A" - } - ], - "title": "Time Spent", - "type": "piechart" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 1 - }, - "id": 15, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", - "range": true, - "refId": "A" - } - ], - "title": "Time Spent", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 9 - }, - "id": 16, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(cryptosim_transactions_processed_total[5m])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Transactions / Second", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 17 - }, - "id": 13, - "panels": [], - "title": "Execution", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - } - }, - "mappings": [], - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 12, - "x": 0, - "y": 18 - }, - "id": 20, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "pieType": "pie", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "sort": "desc", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", - "range": true, - "refId": "A" - } - ], - "title": "Transaction Time", - "type": "piechart" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 18 - }, - "id": 19, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"executing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"executing\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Block Execution Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 26 - }, - "id": 21, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", - "range": true, - "refId": "A" - } - ], - "title": "Transaction Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 34 - }, - "id": 22, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, + "id": 17, + "panels": [ { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_erc20\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_erc20\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read ERC20 Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "s" }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 12, + "x": 0, + "y": 114 + }, + "id": 14, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "thresholdsStyle": { - "mode": "off" + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 34 - }, - "id": 23, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Time Spent", + "type": "piechart" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 114 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Time Spent", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 122 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_transactions_processed_total[5m])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transactions / Second", + "type": "timeseries" } ], - "title": "Read Source Account Time", - "type": "timeseries" + "title": "Overview", + "type": "row" }, { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "id": 13, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "s" }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 12, + "x": 0, + "y": 122 + }, + "id": 20, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "thresholdsStyle": { - "mode": "off" + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 42 - }, - "id": 24, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Transaction Time", + "type": "piechart" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 122 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"executing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"executing\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Block Execution Time", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 146 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Transaction Time", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read Destination Account Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 154 + }, + "id": 22, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "thresholdsStyle": { - "mode": "off" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 42 - }, - "id": 25, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_erc20\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_erc20\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read ERC20 Time", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 154 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Source Account Time", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 162 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Destination Account Time", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account_slot\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read Source Slot Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 162 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "thresholdsStyle": { - "mode": "off" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 50 - }, - "id": 26, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account_slot\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Source Slot Time", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 170 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account_slot\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Destination Slot Time", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 170 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_fee_collection_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_fee_collection_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Fee Collection Account Time", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account_slot\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 178 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"update_balances\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"update_balances\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Update Balances Time", + "type": "timeseries" } ], - "title": "Read Destination Slot Time", - "type": "timeseries" + "title": "Execution", + "type": "row" }, { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 2 }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "id": 8, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 123 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "thresholdsStyle": { - "mode": "off" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 + "pluginVersion": "12.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 50 - }, - "id": 27, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" + "editorMode": "code", + "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", + "legendFormat": "Blocks / Second", + "range": true, + "refId": "A" + } + ], + "title": "Blocks / Second", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 123 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"finalizing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"finalizing\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Block Finalization Time", + "type": "timeseries" + } + ], + "title": "Blocks", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 12, + "panels": [ { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 124 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", + "legendFormat": "Blocks / Second", + "range": true, + "refId": "A" + } + ], + "title": "Commits / Second", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_fee_collection_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_fee_collection_account\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read Fee Collection Account Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 124 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "thresholdsStyle": { - "mode": "off" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 58 - }, - "id": 28, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"committing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"committing\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "DB Commit Time", + "type": "timeseries" } + ], + "title": "Commit", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 4 }, - "pluginVersion": "12.4.0", - "targets": [ + "id": 9, + "panels": [ { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_accounts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of Accounts", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_accounts_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Accounts Created / Second", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_erc20_contracts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of ERC20 Contracts", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"update_balances\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"update_balances\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "ERC20 Contracts Created / Second", + "type": "timeseries" } ], - "title": "Update Balances Time", - "type": "timeseries" + "title": "State Size", + "type": "row" }, { "collapsed": false, @@ -1512,11 +2392,11 @@ "h": 1, "w": 24, "x": 0, - "y": 66 + "y": 5 }, - "id": 8, + "id": 29, "panels": [], - "title": "Blocks", + "title": "Memory", "type": "row" }, { @@ -1576,7 +2456,8 @@ "value": 80 } ] - } + }, + "unit": "bytes" }, "overrides": [] }, @@ -1584,9 +2465,9 @@ "h": 8, "w": 12, "x": 0, - "y": 67 + "y": 6 }, - "id": 1, + "id": 31, "options": { "legend": { "calcs": [], @@ -1603,18 +2484,14 @@ "pluginVersion": "12.4.0", "targets": [ { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, "editorMode": "code", - "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", - "legendFormat": "Blocks / Second", + "expr": "process_resident_memory_bytes", + "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Blocks / Second", + "title": "Resident Memory", "type": "timeseries" }, { @@ -1675,7 +2552,7 @@ } ] }, - "unit": "s" + "unit": "bytes" }, "overrides": [] }, @@ -1683,152 +2560,9 @@ "h": 8, "w": 12, "x": 12, - "y": 67 - }, - "id": 18, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"finalizing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"finalizing\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Block Finalization Time", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 75 - }, - "id": 12, - "panels": [], - "title": "Commit", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 76 + "y": 6 }, - "id": 3, + "id": 36, "options": { "legend": { "calcs": [], @@ -1845,18 +2579,14 @@ "pluginVersion": "12.4.0", "targets": [ { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, "editorMode": "code", - "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", - "legendFormat": "Blocks / Second", + "expr": "go_memstats_alloc_bytes", + "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Commits / Second", + "title": "Heap Size", "type": "timeseries" }, { @@ -1924,16 +2654,16 @@ "gridPos": { "h": 8, "w": 12, - "x": 12, - "y": 76 + "x": 0, + "y": 14 }, - "id": 4, + "id": 38, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": true + "showLegend": false }, "tooltip": { "hideZeros": false, @@ -1945,49 +2675,13 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "legendFormat": "p99", + "expr": "rate(go_gc_duration_seconds_sum[$__rate_interval]) / rate(go_gc_duration_seconds_count[$__rate_interval])", + "legendFormat": "__auto", "range": true, "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"committing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"committing\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" } ], - "title": "DB Commit Time", + "title": "Average GC Pause", "type": "timeseries" }, { @@ -1996,11 +2690,11 @@ "h": 1, "w": 24, "x": 0, - "y": 84 + "y": 22 }, - "id": 9, + "id": 35, "panels": [], - "title": "State Size", + "title": "CPU", "type": "row" }, { @@ -2060,8 +2754,7 @@ "value": 80 } ] - }, - "unit": "locale" + } }, "overrides": [] }, @@ -2069,9 +2762,9 @@ "h": 8, "w": 12, "x": 0, - "y": 85 + "y": 23 }, - "id": 6, + "id": 30, "options": { "legend": { "calcs": [], @@ -2089,13 +2782,13 @@ "targets": [ { "editorMode": "code", - "expr": "cryptosim_accounts_total", + "expr": "rate(process_cpu_seconds_total[$__rate_interval])", "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Number of Accounts", + "title": "CPU Seconds", "type": "timeseries" }, { @@ -2155,7 +2848,8 @@ "value": 80 } ] - } + }, + "unit": "locale" }, "overrides": [] }, @@ -2163,9 +2857,9 @@ "h": 8, "w": 12, "x": 12, - "y": 85 + "y": 23 }, - "id": 7, + "id": 33, "options": { "legend": { "calcs": [], @@ -2183,13 +2877,13 @@ "targets": [ { "editorMode": "code", - "expr": "rate(cryptosim_accounts_total[$__rate_interval])", + "expr": "go_goroutines", "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Accounts Created / Second", + "title": "Goroutines", "type": "timeseries" }, { @@ -2258,9 +2952,9 @@ "h": 8, "w": 12, "x": 0, - "y": 93 + "y": 31 }, - "id": 10, + "id": 34, "options": { "legend": { "calcs": [], @@ -2278,15 +2972,28 @@ "targets": [ { "editorMode": "code", - "expr": "cryptosim_erc20_contracts_total", + "expr": "go_threads", "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Number of ERC20 Contracts", + "title": "Threads", "type": "timeseries" }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 37, + "panels": [], + "title": "File System", + "type": "row" + }, { "datasource": { "type": "prometheus", @@ -2344,17 +3051,18 @@ "value": 80 } ] - } + }, + "unit": "locale" }, "overrides": [] }, "gridPos": { "h": 8, "w": 12, - "x": 12, - "y": 93 + "x": 0, + "y": 40 }, - "id": 11, + "id": 32, "options": { "legend": { "calcs": [], @@ -2372,13 +3080,13 @@ "targets": [ { "editorMode": "code", - "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", + "expr": "process_open_fds", "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "ERC20 Contracts Created / Second", + "title": "Open File Descriptors", "type": "timeseries" } ], @@ -2390,13 +3098,13 @@ "list": [] }, "time": { - "from": "now-5m", + "from": "now-15m", "to": "now" }, "timepicker": {}, "timezone": "browser", "title": "CryptoSim", "uid": "adnqfm4", - "version": 9, + "version": 10, "weekStart": "" } \ No newline at end of file From 40503cbeb76a00ca923e911a4ea671974ef16dfa Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 10:45:23 -0600 Subject: [PATCH 38/49] Metrics for data size on disk --- .../bench/cryptosim/config/basic-config.json | 6 +- sei-db/state_db/bench/cryptosim/cryptosim.go | 2 +- .../bench/cryptosim/cryptosim_config.go | 7 ++ .../bench/cryptosim/cryptosim_metrics.go | 67 ++++++++++++++++++- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index c2ffaeb53d..1f5ea21038 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -2,7 +2,7 @@ "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", "Backend": "FlatKV", "BlocksPerCommit": 32, - "CannedRandomSize": 1073741824, + "CannedRandomSize": 1073741824, "ConstantThreadCount": 0, "ConsoleUpdateIntervalSeconds": 1, "ConsoleUpdateIntervalTransactions": 1000000, @@ -17,7 +17,6 @@ "HotErc20ContractSetSize": 100, "MinimumNumberOfAccounts": 1000000, "MetricsAddr": ":9090", - "MinimumNumberOfAccounts": 1000000, "MinimumNumberOfErc20Contracts": 10000, "NewAccountProbability": 0.001, "PaddedAccountSize": 69, @@ -26,5 +25,6 @@ "ThreadsPerCore": 2.0, "TransactionsPerBlock": 1024, "MaxRuntimeSeconds": 0, - "TransactionMetricsSampleRate": 0.001 + "TransactionMetricsSampleRate": 0.001, + "DataDirSizeIntervalSeconds": 60 } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 66a8a1eb3c..836d90bea7 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -72,7 +72,7 @@ func NewCryptoSim( } ctx, cancel := context.WithCancel(ctx) - metrics := NewCryptosimMetrics(ctx, config.MetricsAddr) + metrics := NewCryptosimMetrics(ctx, config) // Server start deferred until after DataGenerator loads DB state and sets gauges, // avoiding rate() spikes when restarting with a preserved DB. diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index a782ee3005..dfa85dd212 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -114,6 +114,9 @@ type CryptoSimConfig struct { // The probability of capturing detailed metrics about a transaction. Should be a value between 0.0 and 1.0. TransactionMetricsSampleRate float64 + + // How often (in seconds) to measure and export the data directory size. If 0, size sampling is disabled. + DataDirSizeIntervalSeconds int } // Returns the default configuration for the cryptosim benchmark. @@ -148,6 +151,7 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { MaxRuntimeSeconds: 0, MetricsAddr: ":9090", TransactionMetricsSampleRate: 0.001, + DataDirSizeIntervalSeconds: 60, } } @@ -213,6 +217,9 @@ func (c *CryptoSimConfig) Validate() error { if c.TransactionMetricsSampleRate < 0 || c.TransactionMetricsSampleRate > 1 { return fmt.Errorf("TransactionMetricsSampleRate must be in [0, 1] (got %f)", c.TransactionMetricsSampleRate) } + if c.DataDirSizeIntervalSeconds < 0 { + return fmt.Errorf("DataDirSizeIntervalSeconds must be non-negative (got %d)", c.DataDirSizeIntervalSeconds) + } return nil } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index e4c1efe28c..cccdbb534b 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -2,7 +2,9 @@ package cryptosim import ( "context" + "io/fs" "net/http" + "path/filepath" "time" "github.com/prometheus/client_golang/prometheus" @@ -19,16 +21,18 @@ type CryptosimMetrics struct { totalAccounts prometheus.Gauge totalErc20Contracts prometheus.Gauge dbCommitsTotal prometheus.Counter + dataDirSizeBytes prometheus.Gauge mainThreadPhase *PhaseTimer transactionPhaseTimerFactory *PhaseTimerFactory } // NewCryptosimMetrics creates metrics for the cryptosim benchmark. A dedicated // registry is created internally. When ctx is cancelled, the metrics HTTP server -// (if started) is shut down gracefully. +// (if started) is shut down gracefully. Data directory size sampling is started +// automatically when DataDirSizeIntervalSeconds > 0. func NewCryptosimMetrics( ctx context.Context, - metricsAddr string, + config *CryptoSimConfig, ) *CryptosimMetrics { reg := prometheus.NewRegistry() @@ -58,6 +62,10 @@ func NewCryptosimMetrics( Name: "cryptosim_db_commits_total", Help: "Total number of database commits", }) + dataDirSizeBytes := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "cryptosim_data_dir_size_bytes", + Help: "Approximate size in bytes of the benchmark data directory", + }) mainThreadPhase := NewPhaseTimer(reg, "main_thread") transactionPhaseTimerFactory := NewPhaseTimerFactory(reg, "transaction") @@ -67,9 +75,10 @@ func NewCryptosimMetrics( totalAccounts, totalErc20Contracts, dbCommitsTotal, + dataDirSizeBytes, ) - return &CryptosimMetrics{ + m := &CryptosimMetrics{ reg: reg, ctx: ctx, blocksFinalizedTotal: blocksFinalizedTotal, @@ -77,9 +86,16 @@ func NewCryptosimMetrics( totalAccounts: totalAccounts, totalErc20Contracts: totalErc20Contracts, dbCommitsTotal: dbCommitsTotal, + dataDirSizeBytes: dataDirSizeBytes, mainThreadPhase: mainThreadPhase, transactionPhaseTimerFactory: transactionPhaseTimerFactory, } + if config != nil && config.DataDirSizeIntervalSeconds > 0 && config.DataDir != "" { + if dataDir, err := resolveAndCreateDataDir(config.DataDir); err == nil { + m.startDataDirSizeSampling(dataDir, config.DataDirSizeIntervalSeconds) + } + } + return m } // StartServer starts the metrics HTTP server. Call this after loading initial @@ -92,6 +108,51 @@ func (m *CryptosimMetrics) StartServer(addr string) { startMetricsServer(m.ctx, m.reg, addr) } +// startDataDirSizeSampling starts a goroutine that periodically measures the +// size of dataDir and exports it to cryptosim_data_dir_size_bytes. The first +// measurement runs immediately so the gauge is never left at 0 for Prometheus scrapes. +func (m *CryptosimMetrics) startDataDirSizeSampling(dataDir string, intervalSeconds int) { + if m == nil || intervalSeconds <= 0 || dataDir == "" { + return + } + interval := time.Duration(intervalSeconds) * time.Second + go func() { + ticker := time.NewTicker(interval) + defer ticker.Stop() + // Measure immediately, then on each tick. + m.dataDirSizeBytes.Set(float64(measureDataDirSize(dataDir))) + for { + select { + case <-m.ctx.Done(): + return + case <-ticker.C: + m.dataDirSizeBytes.Set(float64(measureDataDirSize(dataDir))) + } + } + }() +} + +// measureDataDirSize walks the directory tree and sums file sizes. +// Ignores errors from individual entries (e.g., removed or inaccessible files). +func measureDataDirSize(dataDir string) int64 { + var total int64 + _ = filepath.WalkDir(dataDir, func(path string, entry fs.DirEntry, err error) error { + if err != nil { + return nil // Skip problematic entries, continue with partial result. + } + if entry.IsDir() { + return nil + } + info, err := entry.Info() + if err != nil { + return nil + } + total += info.Size() + return nil + }) + return total +} + // startMetricsServer starts an HTTP server serving /metrics from reg. When ctx is // cancelled, the server is shut down gracefully. func startMetricsServer(ctx context.Context, reg *prometheus.Registry, addr string) { From 0ee484442a71ddd021df16878679e5c28d0523d2 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 10:49:24 -0600 Subject: [PATCH 39/49] Capture available disk space --- .../bench/cryptosim/cryptosim_metrics.go | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index cccdbb534b..b6bb1528e6 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -10,6 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" + "golang.org/x/sys/unix" ) // CryptosimMetrics holds Prometheus metrics for the cryptosim benchmark. @@ -22,6 +23,7 @@ type CryptosimMetrics struct { totalErc20Contracts prometheus.Gauge dbCommitsTotal prometheus.Counter dataDirSizeBytes prometheus.Gauge + dataDirAvailableBytes prometheus.Gauge mainThreadPhase *PhaseTimer transactionPhaseTimerFactory *PhaseTimerFactory } @@ -66,6 +68,10 @@ func NewCryptosimMetrics( Name: "cryptosim_data_dir_size_bytes", Help: "Approximate size in bytes of the benchmark data directory", }) + dataDirAvailableBytes := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "cryptosim_data_dir_available_bytes", + Help: "Available disk space in bytes on the filesystem containing the data directory", + }) mainThreadPhase := NewPhaseTimer(reg, "main_thread") transactionPhaseTimerFactory := NewPhaseTimerFactory(reg, "transaction") @@ -76,6 +82,7 @@ func NewCryptosimMetrics( totalErc20Contracts, dbCommitsTotal, dataDirSizeBytes, + dataDirAvailableBytes, ) m := &CryptosimMetrics{ @@ -87,6 +94,7 @@ func NewCryptosimMetrics( totalErc20Contracts: totalErc20Contracts, dbCommitsTotal: dbCommitsTotal, dataDirSizeBytes: dataDirSizeBytes, + dataDirAvailableBytes: dataDirAvailableBytes, mainThreadPhase: mainThreadPhase, transactionPhaseTimerFactory: transactionPhaseTimerFactory, } @@ -109,8 +117,8 @@ func (m *CryptosimMetrics) StartServer(addr string) { } // startDataDirSizeSampling starts a goroutine that periodically measures the -// size of dataDir and exports it to cryptosim_data_dir_size_bytes. The first -// measurement runs immediately so the gauge is never left at 0 for Prometheus scrapes. +// size and available disk space of dataDir and exports them. The first +// measurement runs immediately so the gauges are never left at 0 for Prometheus scrapes. func (m *CryptosimMetrics) startDataDirSizeSampling(dataDir string, intervalSeconds int) { if m == nil || intervalSeconds <= 0 || dataDir == "" { return @@ -119,19 +127,32 @@ func (m *CryptosimMetrics) startDataDirSizeSampling(dataDir string, intervalSeco go func() { ticker := time.NewTicker(interval) defer ticker.Stop() - // Measure immediately, then on each tick. - m.dataDirSizeBytes.Set(float64(measureDataDirSize(dataDir))) + sample := func() { + m.dataDirSizeBytes.Set(float64(measureDataDirSize(dataDir))) + m.dataDirAvailableBytes.Set(float64(measureDataDirAvailableBytes(dataDir))) + } + sample() for { select { case <-m.ctx.Done(): return case <-ticker.C: - m.dataDirSizeBytes.Set(float64(measureDataDirSize(dataDir))) + sample() } } }() } +// measureDataDirAvailableBytes returns the available disk space in bytes for the +// filesystem containing dataDir. Returns 0 on error or unsupported platforms. +func measureDataDirAvailableBytes(dataDir string) int64 { + var stat unix.Statfs_t + if err := unix.Statfs(dataDir, &stat); err != nil { + return 0 + } + return int64(stat.Bavail) * int64(stat.Bsize) +} + // measureDataDirSize walks the directory tree and sums file sizes. // Ignores errors from individual entries (e.g., removed or inaccessible files). func measureDataDirSize(dataDir string) int64 { From 11315093ebeeeca4838efcef7adfe38e7b1f4a0a Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 10:52:59 -0600 Subject: [PATCH 40/49] more dashboards --- .../bench/cryptosim/config/basic-config.json | 3520 ++++++++++++++++- 1 file changed, 3491 insertions(+), 29 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index 1f5ea21038..d92820d16b 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -1,30 +1,3492 @@ { - "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", - "Backend": "FlatKV", - "BlocksPerCommit": 32, - "CannedRandomSize": 1073741824, - "ConstantThreadCount": 0, - "ConsoleUpdateIntervalSeconds": 1, - "ConsoleUpdateIntervalTransactions": 1000000, - "DataDir": "data", - "Erc20ContractSize": 2048, - "Erc20InteractionsPerAccount": 10, - "Erc20StorageSlotSize": 32, - "ExecutorQueueSize": 64, - "HotAccountProbability": 0.1, - "HotAccountSetSize": 100, - "HotErc20ContractProbability": 0.5, - "HotErc20ContractSetSize": 100, - "MinimumNumberOfAccounts": 1000000, - "MetricsAddr": ":9090", - "MinimumNumberOfErc20Contracts": 10000, - "NewAccountProbability": 0.001, - "PaddedAccountSize": 69, - "Seed": 1337, - "SetupUpdateIntervalCount": 100000, - "ThreadsPerCore": 2.0, - "TransactionsPerBlock": 1024, - "MaxRuntimeSeconds": 0, - "TransactionMetricsSampleRate": 0.001, - "DataDirSizeIntervalSeconds": 60 -} + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A DB microbenchmark, workload is a simulation of ERC20 crypto-transfer traffic.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 17, + "panels": [], + "title": "Overview", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 14, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Time Spent", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Time Spent", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_transactions_processed_total[5m])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transactions / Second", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 13, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 20, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Transaction Time", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"executing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"executing\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Block Execution Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Transaction Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 34 + }, + "id": 22, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_erc20\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_erc20\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read ERC20 Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 34 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Source Account Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 42 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Destination Account Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 42 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account_slot\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Source Slot Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 50 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account_slot\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Destination Slot Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 50 + }, + "id": 27, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_fee_collection_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_fee_collection_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Read Fee Collection Account Time", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 58 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"update_balances\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"update_balances\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Update Balances Time", + "type": "timeseries" + } + ], + "title": "Execution", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 8, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 67 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", + "legendFormat": "Blocks / Second", + "range": true, + "refId": "A" + } + ], + "title": "Blocks / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 67 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"finalizing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"finalizing\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Block Finalization Time", + "type": "timeseries" + } + ], + "title": "Blocks", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 12, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 76 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", + "legendFormat": "Blocks / Second", + "range": true, + "refId": "A" + } + ], + "title": "Commits / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 76 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", + "legendFormat": "p99", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"committing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"committing\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "DB Commit Time", + "type": "timeseries" + } + ], + "title": "Commit", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 9, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 85 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_accounts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of Accounts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 85 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_accounts_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Accounts Created / Second", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 93 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_erc20_contracts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Number of ERC20 Contracts", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 93 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "ERC20 Contracts Created / Second", + "type": "timeseries" + } + ], + "title": "State Size", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 29, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 102 + }, + "id": 31, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "process_resident_memory_bytes", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Resident Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 102 + }, + "id": 36, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "go_memstats_alloc_bytes", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Heap Size", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 110 + }, + "id": 38, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(go_gc_duration_seconds_sum[$__rate_interval]) / rate(go_gc_duration_seconds_count[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Average GC Pause", + "type": "timeseries" + } + ], + "title": "Memory", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 35, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 119 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(process_cpu_seconds_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "CPU Seconds", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 119 + }, + "id": 33, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "go_goroutines", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Goroutines", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 127 + }, + "id": 34, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "go_threads", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Threads", + "type": "timeseries" + } + ], + "title": "CPU", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 37, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 136 + }, + "id": 39, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_data_dir_size_bytes", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Data On Disk", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 136 + }, + "id": 40, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "deriv(cryptosim_data_dir_size_bytes[5m])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Data Growth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 144 + }, + "id": 41, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_data_dir_available_bytes", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Available Disk Space", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 144 + }, + "id": 42, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_data_dir_size_bytes / cryptosim_accounts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Bytes Per Account", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 152 + }, + "id": 32, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "process_open_fds", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Open File Descriptors", + "type": "timeseries" + } + ], + "title": "File System", + "type": "row" + } + ], + "preload": false, + "refresh": "5s", + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "CryptoSim", + "uid": "adnqfm4", + "version": 11, + "weekStart": "" +} \ No newline at end of file From 485b98a49531fa1db38fe7aeac97745184775dcb Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 11:23:28 -0600 Subject: [PATCH 41/49] fix bug --- sei-db/state_db/bench/cryptosim/transaction.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index cb2e6dfea0..3582f965de 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -143,6 +143,9 @@ func (txn *transaction) Execute( if err != nil { return fmt.Errorf("failed to get source account: %w", err) } + srcAccountValueCopy := make([]byte, len(srcAccountValue)) + copy(srcAccountValueCopy, srcAccountValue) + srcAccountValue = srcAccountValueCopy if txn.isSrcNew { // This is a new account, so we should not find it in the DB. @@ -176,6 +179,9 @@ func (txn *transaction) Execute( return fmt.Errorf("destination account not found") } } + dstAccountValueCopy := make([]byte, len(dstAccountValue)) + copy(dstAccountValueCopy, dstAccountValue) + dstAccountValue = dstAccountValueCopy phaseTimer.SetPhase("read_src_account_slot") @@ -205,6 +211,9 @@ func (txn *transaction) Execute( if !found { return fmt.Errorf("fee collection account not found") } + feeValueCopy := make([]byte, len(feeValue)) + copy(feeValueCopy, feeValue) + feeValue = feeValueCopy phaseTimer.SetPhase("update_balances") From f6f61d16c42147a6ad85f1106b5a7f9386deb7e9 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 12:30:36 -0600 Subject: [PATCH 42/49] more metrics --- go.mod | 1 + go.sum | 1 + .../bench/cryptosim/config/basic-config.json | 3520 +---------------- sei-db/state_db/bench/cryptosim/cryptosim.go | 3 +- .../bench/cryptosim/cryptosim_config.go | 11 +- .../bench/cryptosim/cryptosim_metrics.go | 132 +- .../bench/cryptosim/metrics/dashboard.json | 2425 +++++++----- .../bench/cryptosim/transaction_executor.go | 1 + 8 files changed, 1626 insertions(+), 4468 deletions(-) diff --git a/go.mod b/go.mod index 8ca2814fe7..35420d16f2 100644 --- a/go.mod +++ b/go.mod @@ -334,6 +334,7 @@ require ( github.com/securego/gosec/v2 v2.13.1 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/shirou/gopsutil/v3 v3.23.2 github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.2 // indirect github.com/sivchari/nosnakecase v1.7.0 // indirect diff --git a/go.sum b/go.sum index 7aae2ae68e..ac7f48c35c 100644 --- a/go.sum +++ b/go.sum @@ -2048,6 +2048,7 @@ github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAx github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU= github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= diff --git a/sei-db/state_db/bench/cryptosim/config/basic-config.json b/sei-db/state_db/bench/cryptosim/config/basic-config.json index d92820d16b..15d172acac 100644 --- a/sei-db/state_db/bench/cryptosim/config/basic-config.json +++ b/sei-db/state_db/bench/cryptosim/config/basic-config.json @@ -1,3492 +1,30 @@ { - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "description": "A DB microbenchmark, workload is a simulation of ERC20 crypto-transfer traffic.", - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "links": [], - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 17, - "panels": [], - "title": "Overview", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - } - }, - "mappings": [], - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 12, - "x": 0, - "y": 1 - }, - "id": 14, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "pieType": "pie", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "sort": "desc", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", - "range": true, - "refId": "A" - } - ], - "title": "Time Spent", - "type": "piechart" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 1 - }, - "id": 15, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", - "range": true, - "refId": "A" - } - ], - "title": "Time Spent", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 9 - }, - "id": 16, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(cryptosim_transactions_processed_total[5m])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Transactions / Second", - "type": "timeseries" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 17 - }, - "id": 13, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - } - }, - "mappings": [], - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 12, - "x": 0, - "y": 18 - }, - "id": 20, - "options": { - "legend": { - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "pieType": "pie", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "sort": "desc", - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", - "range": true, - "refId": "A" - } - ], - "title": "Transaction Time", - "type": "piechart" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 18 - }, - "id": 19, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"executing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"executing\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Block Execution Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 100, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 26 - }, - "id": 21, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", - "range": true, - "refId": "A" - } - ], - "title": "Transaction Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 34 - }, - "id": 22, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_erc20\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_erc20\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read ERC20 Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 34 - }, - "id": 23, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read Source Account Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 42 - }, - "id": 24, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read Destination Account Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 42 - }, - "id": 25, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account_slot\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read Source Slot Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 50 - }, - "id": 26, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account_slot\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read Destination Slot Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 50 - }, - "id": 27, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_fee_collection_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_fee_collection_account\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Read Fee Collection Account Time", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 58 - }, - "id": 28, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"update_balances\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"update_balances\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Update Balances Time", - "type": "timeseries" - } - ], - "title": "Execution", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 18 - }, - "id": 8, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 67 - }, - "id": 1, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", - "legendFormat": "Blocks / Second", - "range": true, - "refId": "A" - } - ], - "title": "Blocks / Second", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 67 - }, - "id": 18, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"finalizing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"finalizing\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "Block Finalization Time", - "type": "timeseries" - } - ], - "title": "Blocks", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 19 - }, - "id": 12, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 76 - }, - "id": 3, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", - "legendFormat": "Blocks / Second", - "range": true, - "refId": "A" - } - ], - "title": "Commits / Second", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 76 - }, - "id": 4, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"committing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"committing\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" - } - ], - "title": "DB Commit Time", - "type": "timeseries" - } - ], - "title": "Commit", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 20 - }, - "id": 9, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 85 - }, - "id": 6, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "cryptosim_accounts_total", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Number of Accounts", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 85 - }, - "id": 7, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(cryptosim_accounts_total[$__rate_interval])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Accounts Created / Second", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 93 - }, - "id": 10, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "cryptosim_erc20_contracts_total", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Number of ERC20 Contracts", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 93 - }, - "id": 11, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "ERC20 Contracts Created / Second", - "type": "timeseries" - } - ], - "title": "State Size", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 21 - }, - "id": 29, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 102 - }, - "id": 31, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "process_resident_memory_bytes", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Resident Memory", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 102 - }, - "id": 36, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "go_memstats_alloc_bytes", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Heap Size", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 110 - }, - "id": 38, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(go_gc_duration_seconds_sum[$__rate_interval]) / rate(go_gc_duration_seconds_count[$__rate_interval])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Average GC Pause", - "type": "timeseries" - } - ], - "title": "Memory", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 22 - }, - "id": 35, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 119 - }, - "id": 30, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(process_cpu_seconds_total[$__rate_interval])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "CPU Seconds", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 119 - }, - "id": 33, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "go_goroutines", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Goroutines", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 127 - }, - "id": 34, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "go_threads", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Threads", - "type": "timeseries" - } - ], - "title": "CPU", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 23 - }, - "id": 37, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 136 - }, - "id": 39, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "cryptosim_data_dir_size_bytes", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Data On Disk", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "binBps" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 136 - }, - "id": 40, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "deriv(cryptosim_data_dir_size_bytes[5m])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Data Growth", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 144 - }, - "id": 41, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "cryptosim_data_dir_available_bytes", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Available Disk Space", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 144 - }, - "id": 42, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "cryptosim_data_dir_size_bytes / cryptosim_accounts_total", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Bytes Per Account", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 152 - }, - "id": 32, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "process_open_fds", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Open File Descriptors", - "type": "timeseries" - } - ], - "title": "File System", - "type": "row" - } - ], - "preload": false, - "refresh": "5s", - "schemaVersion": 42, - "tags": [], - "templating": { - "list": [] - }, - "time": { - "from": "now-15m", - "to": "now" - }, - "timepicker": {}, - "timezone": "browser", - "title": "CryptoSim", - "uid": "adnqfm4", - "version": 11, - "weekStart": "" -} \ No newline at end of file + "Comment": "Basic configuration for the cryptosim benchmark. Intended for basic correctness/sanity testing.", + "Backend": "FlatKV", + "BlocksPerCommit": 32, + "CannedRandomSize": 1073741824, + "ConstantThreadCount": 0, + "ConsoleUpdateIntervalSeconds": 1, + "ConsoleUpdateIntervalTransactions": 1000000, + "DataDir": "data", + "Erc20ContractSize": 2048, + "Erc20InteractionsPerAccount": 10, + "Erc20StorageSlotSize": 32, + "ExecutorQueueSize": 64, + "HotAccountProbability": 0.1, + "HotAccountSetSize": 100, + "HotErc20ContractProbability": 0.5, + "HotErc20ContractSetSize": 100, + "MinimumNumberOfAccounts": 1000000, + "MetricsAddr": ":9090", + "MinimumNumberOfErc20Contracts": 10000, + "NewAccountProbability": 0.001, + "PaddedAccountSize": 69, + "Seed": 1337, + "SetupUpdateIntervalCount": 100000, + "ThreadsPerCore": 2.0, + "TransactionsPerBlock": 1024, + "MaxRuntimeSeconds": 0, + "TransactionMetricsSampleRate": 0.001, + "BackgroundMetricsScrapeInterval": 60 +} diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 836d90bea7..1055958d71 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -105,8 +105,6 @@ func NewCryptoSim( } return nil, fmt.Errorf("failed to create data generator: %w", err) } - metrics.StartServer(config.MetricsAddr) - threadCount := int(config.ThreadsPerCore)*runtime.NumCPU() + config.ConstantThreadCount if threadCount < 1 { threadCount = 1 @@ -142,6 +140,7 @@ func NewCryptoSim( c.database.ResetTransactionCount() c.startTimestamp = time.Now() + c.metrics.StartServer(config.MetricsAddr) go c.run() return c, nil diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index dfa85dd212..4089641814 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -115,8 +115,9 @@ type CryptoSimConfig struct { // The probability of capturing detailed metrics about a transaction. Should be a value between 0.0 and 1.0. TransactionMetricsSampleRate float64 - // How often (in seconds) to measure and export the data directory size. If 0, size sampling is disabled. - DataDirSizeIntervalSeconds int + // How often (in seconds) to scrape background metrics (data dir size, process I/O). + // If 0, background metrics are disabled. + BackgroundMetricsScrapeInterval int } // Returns the default configuration for the cryptosim benchmark. @@ -151,7 +152,7 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { MaxRuntimeSeconds: 0, MetricsAddr: ":9090", TransactionMetricsSampleRate: 0.001, - DataDirSizeIntervalSeconds: 60, + BackgroundMetricsScrapeInterval: 60, } } @@ -217,8 +218,8 @@ func (c *CryptoSimConfig) Validate() error { if c.TransactionMetricsSampleRate < 0 || c.TransactionMetricsSampleRate > 1 { return fmt.Errorf("TransactionMetricsSampleRate must be in [0, 1] (got %f)", c.TransactionMetricsSampleRate) } - if c.DataDirSizeIntervalSeconds < 0 { - return fmt.Errorf("DataDirSizeIntervalSeconds must be non-negative (got %d)", c.DataDirSizeIntervalSeconds) + if c.BackgroundMetricsScrapeInterval < 0 { + return fmt.Errorf("BackgroundMetricsScrapeInterval must be non-negative (got %d)", c.BackgroundMetricsScrapeInterval) } return nil diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index b6bb1528e6..ef1ba70bc5 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -4,12 +4,15 @@ import ( "context" "io/fs" "net/http" + "os" "path/filepath" + "runtime" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/shirou/gopsutil/v3/process" "golang.org/x/sys/unix" ) @@ -24,6 +27,11 @@ type CryptosimMetrics struct { dbCommitsTotal prometheus.Counter dataDirSizeBytes prometheus.Gauge dataDirAvailableBytes prometheus.Gauge + processReadBytesTotal prometheus.Counter + processWriteBytesTotal prometheus.Counter + processReadCountTotal prometheus.Counter + processWriteCountTotal prometheus.Counter + uptimeSeconds prometheus.Gauge mainThreadPhase *PhaseTimer transactionPhaseTimerFactory *PhaseTimerFactory } @@ -31,7 +39,7 @@ type CryptosimMetrics struct { // NewCryptosimMetrics creates metrics for the cryptosim benchmark. A dedicated // registry is created internally. When ctx is cancelled, the metrics HTTP server // (if started) is shut down gracefully. Data directory size sampling is started -// automatically when DataDirSizeIntervalSeconds > 0. +// automatically when BackgroundMetricsScrapeInterval > 0. func NewCryptosimMetrics( ctx context.Context, config *CryptoSimConfig, @@ -72,6 +80,28 @@ func NewCryptosimMetrics( Name: "cryptosim_data_dir_available_bytes", Help: "Available disk space in bytes on the filesystem containing the data directory", }) + processReadBytesTotal := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "cryptosim_process_read_bytes_total", + Help: "Bytes read from storage by benchmark. Use rate() for throughput. " + + "Linux only (ErrNotImplemented on darwin).", + }) + processWriteBytesTotal := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "cryptosim_process_write_bytes_total", + Help: "Bytes written to storage by benchmark. Use rate() for throughput. " + + "Linux only (ErrNotImplemented on darwin).", + }) + processReadCountTotal := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "cryptosim_process_read_count_total", + Help: "Read I/O ops by benchmark. Use rate() for read IOPS. Linux only (ErrNotImplemented on darwin).", + }) + processWriteCountTotal := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "cryptosim_process_write_count_total", + Help: "Write I/O ops by benchmark. Use rate() for write IOPS. Linux only (ErrNotImplemented on darwin).", + }) + uptimeSeconds := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "cryptosim_uptime_seconds", + Help: "Seconds since benchmark started. Resets to 0 on restart.", + }) mainThreadPhase := NewPhaseTimer(reg, "main_thread") transactionPhaseTimerFactory := NewPhaseTimerFactory(reg, "transaction") @@ -83,6 +113,11 @@ func NewCryptosimMetrics( dbCommitsTotal, dataDirSizeBytes, dataDirAvailableBytes, + processReadBytesTotal, + processWriteBytesTotal, + processReadCountTotal, + processWriteCountTotal, + uptimeSeconds, ) m := &CryptosimMetrics{ @@ -95,13 +130,19 @@ func NewCryptosimMetrics( dbCommitsTotal: dbCommitsTotal, dataDirSizeBytes: dataDirSizeBytes, dataDirAvailableBytes: dataDirAvailableBytes, + processReadBytesTotal: processReadBytesTotal, + processWriteBytesTotal: processWriteBytesTotal, + processReadCountTotal: processReadCountTotal, + processWriteCountTotal: processWriteCountTotal, + uptimeSeconds: uptimeSeconds, mainThreadPhase: mainThreadPhase, transactionPhaseTimerFactory: transactionPhaseTimerFactory, } - if config != nil && config.DataDirSizeIntervalSeconds > 0 && config.DataDir != "" { + if config != nil && config.BackgroundMetricsScrapeInterval > 0 && config.DataDir != "" { if dataDir, err := resolveAndCreateDataDir(config.DataDir); err == nil { - m.startDataDirSizeSampling(dataDir, config.DataDirSizeIntervalSeconds) + m.startDataDirSizeSampling(dataDir, config.BackgroundMetricsScrapeInterval) } + m.startProcessIOSampling(config.BackgroundMetricsScrapeInterval) } return m } @@ -113,9 +154,94 @@ func (m *CryptosimMetrics) StartServer(addr string) { if m == nil || addr == "" { return } + m.startUptimeSampling(time.Now()) startMetricsServer(m.ctx, m.reg, addr) } +// startUptimeSampling updates the uptime gauge every second from startTime. +func (m *CryptosimMetrics) startUptimeSampling(startTime time.Time) { + if m == nil { + return + } + go func() { + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + for { + select { + case <-m.ctx.Done(): + return + case <-ticker.C: + m.uptimeSeconds.Set(time.Since(startTime).Seconds()) + } + } + }() +} + +// startProcessIOSampling starts a goroutine that periodically samples process +// I/O counters (read/write bytes and operation counts) via gopsutil and adds +// deltas to Prometheus counters. Use rate() on these counters for throughput +// and IOPS. Runs when BackgroundMetricsScrapeInterval > 0. +// +// Skipped on darwin: gopsutil does not implement process.IOCounters on macOS; +// the kernel does not expose per-process disk I/O via public APIs. These metrics +// will remain at zero on darwin. +func (m *CryptosimMetrics) startProcessIOSampling(intervalSeconds int) { + if m == nil || intervalSeconds <= 0 { + return + } + if runtime.GOOS == "darwin" { + // OSX does not support process I/O stats. + return + } + proc, err := process.NewProcess(int32(os.Getpid())) + if err != nil { + return + } + interval := time.Duration(intervalSeconds) * time.Second + var prevReadBytes, prevWriteBytes, prevReadCount, prevWriteCount uint64 + var initialized bool + go func() { + ticker := time.NewTicker(interval) + defer ticker.Stop() + sample := func() { + io, err := proc.IOCounters() + if err != nil || io == nil { + return + } + curRead := io.ReadBytes + curWrite := io.WriteBytes + curReadCount := io.ReadCount + curWriteCount := io.WriteCount + if initialized { + if curRead >= prevReadBytes { + m.processReadBytesTotal.Add(float64(curRead - prevReadBytes)) + } + if curWrite >= prevWriteBytes { + m.processWriteBytesTotal.Add(float64(curWrite - prevWriteBytes)) + } + if curReadCount >= prevReadCount { + m.processReadCountTotal.Add(float64(curReadCount - prevReadCount)) + } + if curWriteCount >= prevWriteCount { + m.processWriteCountTotal.Add(float64(curWriteCount - prevWriteCount)) + } + } + prevReadBytes, prevWriteBytes = curRead, curWrite + prevReadCount, prevWriteCount = curReadCount, curWriteCount + initialized = true + } + sample() + for { + select { + case <-m.ctx.Done(): + return + case <-ticker.C: + sample() + } + } + }() +} + // startDataDirSizeSampling starts a goroutine that periodically measures the // size and available disk space of dataDir and exports them. The first // measurement runs immediately so the gauges are never left at 0 for Prometheus scrapes. diff --git a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json index 2944b1c6e2..108cfbe626 100644 --- a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -22,7 +22,7 @@ "links": [], "panels": [ { - "collapsed": true, + "collapsed": false, "gridPos": { "h": 1, "w": 24, @@ -30,6 +30,272 @@ "y": 0 }, "id": 17, + "panels": [], + "title": "Overview", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 16, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 14, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "sort": "desc", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Time Spent", + "type": "piechart" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", + "legendFormat": "{{phase}}", + "range": true, + "refId": "A" + } + ], + "title": "Time Spent", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(cryptosim_transactions_processed_total[5m])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Transactions / Second", + "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 13, "panels": [ { "datasource": { @@ -57,9 +323,9 @@ "h": 16, "w": 12, "x": 0, - "y": 114 + "y": 18 }, - "id": 14, + "id": 20, "options": { "legend": { "displayMode": "list", @@ -85,13 +351,13 @@ "targets": [ { "editorMode": "code", - "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", + "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", "legendFormat": "{{phase}}", "range": true, "refId": "A" } ], - "title": "Time Spent", + "title": "Transaction Time", "type": "piechart" }, { @@ -113,7 +379,7 @@ "barAlignment": 0, "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 100, + "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, @@ -132,7 +398,7 @@ "spanNulls": false, "stacking": { "group": "A", - "mode": "normal" + "mode": "none" }, "thresholdsStyle": { "mode": "off" @@ -160,9 +426,9 @@ "h": 8, "w": 12, "x": 12, - "y": 114 + "y": 18 }, - "id": 15, + "id": 19, "options": { "legend": { "calcs": [], @@ -180,14 +446,50 @@ "targets": [ { "editorMode": "code", - "expr": "rate(main_thread_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "legendFormat": "p99", "range": true, "refId": "A" - } - ], - "title": "Time Spent", - "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"executing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"executing\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" + } + ], + "title": "Block Execution Time", + "type": "timeseries" }, { "datasource": { @@ -208,7 +510,7 @@ "barAlignment": 0, "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 0, + "fillOpacity": 100, "gradientMode": "none", "hideFrom": { "legend": false, @@ -227,7 +529,7 @@ "spanNulls": false, "stacking": { "group": "A", - "mode": "none" + "mode": "normal" }, "thresholdsStyle": { "mode": "off" @@ -247,7 +549,7 @@ } ] }, - "unit": "locale" + "unit": "s" }, "overrides": [] }, @@ -255,93 +557,16 @@ "h": 8, "w": 12, "x": 12, - "y": 122 + "y": 42 }, - "id": 16, + "id": 21, "options": { "legend": { "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(cryptosim_transactions_processed_total[5m])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Transactions / Second", - "type": "timeseries" - } - ], - "title": "Overview", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 1 - }, - "id": 13, - "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - } - }, - "mappings": [], - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 16, - "w": 12, - "x": 0, - "y": 122 - }, - "id": 20, - "options": { - "legend": { "displayMode": "list", "placement": "bottom", "showLegend": true }, - "pieType": "pie", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "sort": "desc", "tooltip": { "hideZeros": false, "mode": "single", @@ -359,7 +584,7 @@ } ], "title": "Transaction Time", - "type": "piechart" + "type": "timeseries" }, { "datasource": { @@ -426,10 +651,10 @@ "gridPos": { "h": 8, "w": 12, - "x": 12, - "y": 122 + "x": 0, + "y": 50 }, - "id": 19, + "id": 22, "options": { "legend": { "calcs": [], @@ -447,7 +672,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -458,7 +683,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -470,7 +695,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"executing\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -482,14 +707,14 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"executing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"executing\"}[$__rate_interval])", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_erc20\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_erc20\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Block Execution Time", + "title": "Read ERC20 Time", "type": "timeseries" }, { @@ -511,7 +736,7 @@ "barAlignment": 0, "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 100, + "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, @@ -530,7 +755,7 @@ "spanNulls": false, "stacking": { "group": "A", - "mode": "normal" + "mode": "none" }, "thresholdsStyle": { "mode": "off" @@ -558,9 +783,9 @@ "h": 8, "w": 12, "x": 12, - "y": 146 + "y": 50 }, - "id": 21, + "id": 23, "options": { "legend": { "calcs": [], @@ -578,13 +803,49 @@ "targets": [ { "editorMode": "code", - "expr": "rate(transaction_phase_duration_seconds_total[$__rate_interval])", - "legendFormat": "{{phase}}", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "legendFormat": "p99", "range": true, "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p95", + "range": true, + "refId": "B" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "p50", + "range": true, + "refId": "C" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "editorMode": "code", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account\"}[$__rate_interval])", + "instant": false, + "legendFormat": "average", + "range": true, + "refId": "D" } ], - "title": "Transaction Time", + "title": "Read Source Account Time", "type": "timeseries" }, { @@ -653,9 +914,9 @@ "h": 8, "w": 12, "x": 0, - "y": 154 + "y": 58 }, - "id": 22, + "id": 24, "options": { "legend": { "calcs": [], @@ -673,7 +934,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -684,7 +945,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -696,7 +957,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_erc20\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -708,14 +969,14 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_erc20\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_erc20\"}[$__rate_interval])", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Read ERC20 Time", + "title": "Read Destination Account Time", "type": "timeseries" }, { @@ -784,9 +1045,9 @@ "h": 8, "w": 12, "x": 12, - "y": 154 + "y": 58 }, - "id": 23, + "id": 25, "options": { "legend": { "calcs": [], @@ -804,7 +1065,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -815,7 +1076,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -827,7 +1088,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -839,14 +1100,14 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account\"}[$__rate_interval])", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account_slot\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Read Source Account Time", + "title": "Read Source Slot Time", "type": "timeseries" }, { @@ -915,9 +1176,9 @@ "h": 8, "w": 12, "x": 0, - "y": 162 + "y": 66 }, - "id": 24, + "id": 26, "options": { "legend": { "calcs": [], @@ -935,7 +1196,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -946,7 +1207,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -958,7 +1219,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -970,14 +1231,14 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account\"}[$__rate_interval])", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account_slot\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Read Destination Account Time", + "title": "Read Destination Slot Time", "type": "timeseries" }, { @@ -1046,9 +1307,9 @@ "h": 8, "w": 12, "x": 12, - "y": 162 + "y": 66 }, - "id": 25, + "id": 27, "options": { "legend": { "calcs": [], @@ -1066,7 +1327,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -1077,7 +1338,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -1089,7 +1350,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_src_account_slot\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -1101,14 +1362,14 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_src_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_src_account_slot\"}[$__rate_interval])", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_fee_collection_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_fee_collection_account\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Read Source Slot Time", + "title": "Read Fee Collection Account Time", "type": "timeseries" }, { @@ -1177,9 +1438,9 @@ "h": 8, "w": 12, "x": 0, - "y": 170 + "y": 74 }, - "id": 26, + "id": 28, "options": { "legend": { "calcs": [], @@ -1197,7 +1458,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -1208,7 +1469,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -1220,7 +1481,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_dst_account_slot\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -1232,26 +1493,40 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_dst_account_slot\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_dst_account_slot\"}[$__rate_interval])", + "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"update_balances\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"update_balances\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Read Destination Slot Time", + "title": "Update Balances Time", "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, + } + ], + "title": "Execution", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 8, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, @@ -1299,24 +1574,23 @@ "value": 80 } ] - }, - "unit": "s" + } }, "overrides": [] }, "gridPos": { "h": 8, "w": 12, - "x": 12, - "y": 170 + "x": 0, + "y": 195 }, - "id": 27, + "id": 1, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": true + "showLegend": false }, "tooltip": { "hideZeros": false, @@ -1326,51 +1600,19 @@ }, "pluginVersion": "12.4.0", "targets": [ - { - "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "legendFormat": "p99", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"read_fee_collection_account\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, { "datasource": { "type": "prometheus", "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"read_fee_collection_account\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"read_fee_collection_account\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", + "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", + "legendFormat": "Blocks / Second", "range": true, - "refId": "D" + "refId": "A" } ], - "title": "Read Fee Collection Account Time", + "title": "Blocks / Second", "type": "timeseries" }, { @@ -1438,10 +1680,10 @@ "gridPos": { "h": 8, "w": 12, - "x": 0, - "y": 178 + "x": 12, + "y": 195 }, - "id": 28, + "id": 18, "options": { "legend": { "calcs": [], @@ -1459,7 +1701,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -1470,7 +1712,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -1482,7 +1724,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(transaction_phase_latency_seconds_bucket{phase=\"update_balances\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -1494,18 +1736,18 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(transaction_phase_latency_seconds_sum{phase=\"update_balances\"}[$__rate_interval]) / rate(transaction_phase_latency_seconds_count{phase=\"update_balances\"}[$__rate_interval])", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"finalizing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"finalizing\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Update Balances Time", + "title": "Block Finalization Time", "type": "timeseries" } ], - "title": "Execution", + "title": "Blocks", "type": "row" }, { @@ -1514,9 +1756,9 @@ "h": 1, "w": 24, "x": 0, - "y": 2 + "y": 19 }, - "id": 8, + "id": 12, "panels": [ { "datasource": { @@ -1583,9 +1825,9 @@ "h": 8, "w": 12, "x": 0, - "y": 123 + "y": 196 }, - "id": 1, + "id": 3, "options": { "legend": { "calcs": [], @@ -1607,13 +1849,13 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(cryptosim_blocks_finalized_total[$__rate_interval ])", + "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", "legendFormat": "Blocks / Second", "range": true, "refId": "A" } ], - "title": "Blocks / Second", + "title": "Commits / Second", "type": "timeseries" }, { @@ -1682,9 +1924,9 @@ "h": 8, "w": 12, "x": 12, - "y": 123 + "y": 196 }, - "id": 18, + "id": 4, "options": { "legend": { "calcs": [], @@ -1702,7 +1944,7 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", "legendFormat": "p99", "range": true, "refId": "A" @@ -1713,7 +1955,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", "instant": false, "legendFormat": "p95", "range": true, @@ -1725,7 +1967,7 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"finalizing\"}[$__rate_interval]))", + "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", "instant": false, "legendFormat": "p50", "range": true, @@ -1737,18 +1979,18 @@ "uid": "PBFA97CFB590B2093" }, "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"finalizing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"finalizing\"}[$__rate_interval])", + "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"committing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"committing\"}[$__rate_interval])", "instant": false, "legendFormat": "average", "range": true, "refId": "D" } ], - "title": "Block Finalization Time", + "title": "DB Commit Time", "type": "timeseries" } ], - "title": "Blocks", + "title": "Commit", "type": "row" }, { @@ -1757,9 +1999,9 @@ "h": 1, "w": 24, "x": 0, - "y": 3 + "y": 20 }, - "id": 12, + "id": 9, "panels": [ { "datasource": { @@ -1818,7 +2060,8 @@ "value": 80 } ] - } + }, + "unit": "locale" }, "overrides": [] }, @@ -1826,9 +2069,9 @@ "h": 8, "w": 12, "x": 0, - "y": 124 + "y": 197 }, - "id": 3, + "id": 6, "options": { "legend": { "calcs": [], @@ -1845,18 +2088,14 @@ "pluginVersion": "12.4.0", "targets": [ { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, "editorMode": "code", - "expr": "rate(cryptosim_db_commits_total[$__rate_interval])", - "legendFormat": "Blocks / Second", + "expr": "cryptosim_accounts_total", + "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Commits / Second", + "title": "Number of Accounts", "type": "timeseries" }, { @@ -1916,8 +2155,7 @@ "value": 80 } ] - }, - "unit": "s" + } }, "overrides": [] }, @@ -1925,15 +2163,15 @@ "h": 8, "w": 12, "x": 12, - "y": 124 + "y": 197 }, - "id": 4, + "id": 7, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": true + "showLegend": false }, "tooltip": { "hideZeros": false, @@ -1945,65 +2183,15 @@ "targets": [ { "editorMode": "code", - "expr": "histogram_quantile(0.99, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "legendFormat": "p99", + "expr": "rate(cryptosim_accounts_total[$__rate_interval])", + "legendFormat": "__auto", "range": true, "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.95, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p95", - "range": true, - "refId": "B" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "histogram_quantile(0.50, rate(main_thread_phase_latency_seconds_bucket{phase=\"committing\"}[$__rate_interval]))", - "instant": false, - "legendFormat": "p50", - "range": true, - "refId": "C" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "editorMode": "code", - "expr": "rate(main_thread_phase_latency_seconds_sum{phase=\"committing\"}[$__rate_interval]) / rate(main_thread_phase_latency_seconds_count{phase=\"committing\"}[$__rate_interval])", - "instant": false, - "legendFormat": "average", - "range": true, - "refId": "D" } ], - "title": "DB Commit Time", + "title": "Accounts Created / Second", "type": "timeseries" - } - ], - "title": "Commit", - "type": "row" - }, - { - "collapsed": true, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 4 - }, - "id": 9, - "panels": [ + }, { "datasource": { "type": "prometheus", @@ -2070,9 +2258,9 @@ "h": 8, "w": 12, "x": 0, - "y": 5 + "y": 269 }, - "id": 6, + "id": 10, "options": { "legend": { "calcs": [], @@ -2090,13 +2278,13 @@ "targets": [ { "editorMode": "code", - "expr": "cryptosim_accounts_total", + "expr": "cryptosim_erc20_contracts_total", "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Number of Accounts", + "title": "Number of ERC20 Contracts", "type": "timeseries" }, { @@ -2164,9 +2352,9 @@ "h": 8, "w": 12, "x": 12, - "y": 5 + "y": 269 }, - "id": 7, + "id": 11, "options": { "legend": { "calcs": [], @@ -2184,15 +2372,29 @@ "targets": [ { "editorMode": "code", - "expr": "rate(cryptosim_accounts_total[$__rate_interval])", + "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Accounts Created / Second", + "title": "ERC20 Contracts Created / Second", "type": "timeseries" - }, + } + ], + "title": "State Size", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 29, + "panels": [ { "datasource": { "type": "prometheus", @@ -2251,7 +2453,7 @@ } ] }, - "unit": "locale" + "unit": "bytes" }, "overrides": [] }, @@ -2259,9 +2461,9 @@ "h": 8, "w": 12, "x": 0, - "y": 13 + "y": 278 }, - "id": 10, + "id": 31, "options": { "legend": { "calcs": [], @@ -2279,13 +2481,13 @@ "targets": [ { "editorMode": "code", - "expr": "cryptosim_erc20_contracts_total", + "expr": "process_resident_memory_bytes", "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "Number of ERC20 Contracts", + "title": "Resident Memory", "type": "timeseries" }, { @@ -2345,7 +2547,8 @@ "value": 80 } ] - } + }, + "unit": "bytes" }, "overrides": [] }, @@ -2353,9 +2556,9 @@ "h": 8, "w": 12, "x": 12, - "y": 13 + "y": 278 }, - "id": 11, + "id": 36, "options": { "legend": { "calcs": [], @@ -2373,721 +2576,1009 @@ "targets": [ { "editorMode": "code", - "expr": "rate(cryptosim_erc20_contracts_total[$__rate_interval])", + "expr": "go_memstats_alloc_bytes", "legendFormat": "__auto", "range": true, "refId": "A" } ], - "title": "ERC20 Contracts Created / Second", + "title": "Heap Size", "type": "timeseries" - } - ], - "title": "State Size", - "type": "row" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 5 - }, - "id": 29, - "panels": [], - "title": "Memory", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 6 - }, - "id": 31, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ { - "editorMode": "code", - "expr": "process_resident_memory_bytes", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Resident Memory", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 286 + }, + "id": 38, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "thresholdsStyle": { - "mode": "off" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 6 - }, - "id": 36, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "go_memstats_alloc_bytes", - "legendFormat": "__auto", - "range": true, - "refId": "A" + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(go_gc_duration_seconds_sum[$__rate_interval]) / rate(go_gc_duration_seconds_count[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Average GC Pause", + "type": "timeseries" } ], - "title": "Heap Size", - "type": "timeseries" + "title": "Memory", + "type": "row" }, { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "id": 35, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "color": "red", - "value": 80 + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] } - ] + }, + "overrides": [] }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 14 - }, - "id": 38, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "rate(go_gc_duration_seconds_sum[$__rate_interval]) / rate(go_gc_duration_seconds_count[$__rate_interval])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Average GC Pause", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 22 - }, - "id": 35, - "panels": [], - "title": "CPU", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 23 }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "thresholdsStyle": { - "mode": "off" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 23 - }, - "id": 30, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "rate(process_cpu_seconds_total[$__rate_interval])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "CPU Seconds", + "type": "timeseries" }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ { - "editorMode": "code", - "expr": "rate(process_cpu_seconds_total[$__rate_interval])", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "CPU Seconds", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 33, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "thresholdsStyle": { - "mode": "off" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "go_goroutines", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Goroutines", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" }, - { - "color": "red", - "value": 80 - } - ] + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" + }, + "overrides": [] }, - "unit": "locale" - }, - "overrides": [] - }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 31 + }, + "id": 34, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "go_threads", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Threads", + "type": "timeseries" + } + ], + "title": "CPU", + "type": "row" + }, + { + "collapsed": true, "gridPos": { - "h": 8, - "w": 12, - "x": 12, + "h": 1, + "w": 24, + "x": 0, "y": 23 }, - "id": 33, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ + "id": 37, + "panels": [ { - "editorMode": "code", - "expr": "go_goroutines", - "legendFormat": "__auto", - "range": true, - "refId": "A" - } - ], - "title": "Goroutines", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 200 + }, + "id": 39, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_data_dir_size_bytes", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Data On Disk", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "binBps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 200 + }, + "id": 40, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "deriv(cryptosim_data_dir_size_bytes[5m])", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Data Growth", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 208 + }, + "id": 41, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_data_dir_available_bytes", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Available Disk Space", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 208 + }, + "id": 42, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_data_dir_size_bytes / cryptosim_accounts_total", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Bytes Per Account", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "locale" }, - "thresholdsStyle": { - "mode": "off" - } + "overrides": [] }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 216 }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 31 - }, - "id": 34, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "go_threads", - "legendFormat": "__auto", - "range": true, - "refId": "A" + "id": 32, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "process_open_fds", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Open File Descriptors", + "type": "timeseries" } ], - "title": "Threads", - "type": "timeseries" + "title": "File System", + "type": "row" }, { - "collapsed": false, + "collapsed": true, "gridPos": { "h": 1, "w": 24, "x": 0, - "y": 39 - }, - "id": 37, - "panels": [], - "title": "File System", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" + "y": 24 }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "id": 44, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PBFA97CFB590B2093" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" }, - "showPoints": "auto", - "showValues": false, - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 233 + }, + "id": 43, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, - "thresholdsStyle": { - "mode": "off" + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" } }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": 0 - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "locale" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 40 - }, - "id": 32, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": false - }, - "tooltip": { - "hideZeros": false, - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "12.4.0", - "targets": [ - { - "editorMode": "code", - "expr": "process_open_fds", - "legendFormat": "__auto", - "range": true, - "refId": "A" + "pluginVersion": "12.4.0", + "targets": [ + { + "editorMode": "code", + "expr": "cryptosim_uptime_seconds", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Uptime", + "type": "timeseries" } ], - "title": "Open File Descriptors", - "type": "timeseries" + "title": "Misc", + "type": "row" } ], "preload": false, @@ -3105,6 +3596,6 @@ "timezone": "browser", "title": "CryptoSim", "uid": "adnqfm4", - "version": 10, + "version": 13, "weekStart": "" } \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/transaction_executor.go b/sei-db/state_db/bench/cryptosim/transaction_executor.go index fb35350026..c00f4e63d7 100644 --- a/sei-db/state_db/bench/cryptosim/transaction_executor.go +++ b/sei-db/state_db/bench/cryptosim/transaction_executor.go @@ -38,6 +38,7 @@ func NewTransactionExecutor( ) *TransactionExecutor { e := &TransactionExecutor{ ctx: ctx, + cancel: cancel, database: database, feeCollectionAddress: feeCollectionAddress, workChan: make(chan any, queueSize), From ddac4f9483afd4c000401840a4249d970af06508 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 12:55:57 -0600 Subject: [PATCH 43/49] Added script to set up ubuntu --- sei-db/state_db/bench/cryptosim/README.md | 22 ++++- .../bench/cryptosim/tools/setup-ubuntu.sh | 99 +++++++++++++++++++ 2 files changed, 116 insertions(+), 5 deletions(-) create mode 100755 sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh diff --git a/sei-db/state_db/bench/cryptosim/README.md b/sei-db/state_db/bench/cryptosim/README.md index 06ff353850..35fbf6bb72 100644 --- a/sei-db/state_db/bench/cryptosim/README.md +++ b/sei-db/state_db/bench/cryptosim/README.md @@ -54,10 +54,22 @@ The following features might be useful to add to this benchmark: # Setting Up Prometheus / Grafana -TODO +To set up local prometheus/grafana instances, run the following. You must have docker installed. -Other TODOs: +``` +./metrics/start-prometheus.sh +./metrics/start-grafana.sh +``` + +Then, navigate to http://localhost:3000/ in a web browser to reach the grafana UI. Username and password are "admin". + +There is a pre-built dashboard containing visualizations for benchmark metrics in `metrics/dashboard.json` that +you can import into grafana. -- system metrics (e.g. memory, cpu, thread count, IO info if it's available) -- disk utilization -- disk utilizaiton per account (good for detecting disk leaks) + +You can stop these services by killing their containers, or by running the following: + +``` +./metrics/stop-prometheus.sh +./metrics/stop-grafana.sh +``` diff --git a/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh b/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh new file mode 100755 index 0000000000..12a7337fe9 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# +# Sets up a clean Ubuntu install for compiling and running the cryptosim benchmark. +# +# Usage: Run as root or with sudo +# sudo ./setup-ubuntu.sh +# +# Installs: +# - build-essential, git (for building) +# - Go (from official tarball) +# - nano, tree, htop, iotop, tmux, sl (dev/admin tools) +# - Docker (optional, for Prometheus/Grafana metrics) +# +set -euo pipefail + +if [[ $EUID -ne 0 ]]; then + echo "Error: This script must be run as root (use sudo)" >&2 + exit 1 +fi + +# Detect architecture for Go tarball +ARCH=$(uname -m) +case "$ARCH" in + x86_64) GO_ARCH="amd64" ;; + aarch64|arm64) GO_ARCH="arm64" ;; + *) echo "Error: Unsupported architecture: $ARCH" >&2; exit 1 ;; +esac + +GO_VERSION="1.26.0" +GO_TAR="go${GO_VERSION}.linux-${GO_ARCH}.tar.gz" +GO_URL="https://go.dev/dl/${GO_TAR}" + +echo "=== Updating package lists ===" +apt-get update + +echo "" +echo "=== Installing build dependencies (build-essential, git) ===" +apt-get install -y build-essential git + +echo "" +echo "=== Installing dev/admin tools (nano, tree, htop, iotop, tmux, sl) ===" +apt-get install -y nano tree htop iotop tmux sl + +echo "" +echo "=== Installing Go ${GO_VERSION} ===" +if command -v go &>/dev/null; then + INSTALLED=$(go version 2>/dev/null || true) + echo "Go already installed: $INSTALLED" + echo "Skipping Go installation. Remove existing Go and re-run if you need a different version." +else + TMPDIR=$(mktemp -d) + trap "rm -rf $TMPDIR" EXIT + cd "$TMPDIR" + wget -q --show-progress "$GO_URL" -O "$GO_TAR" + rm -rf /usr/local/go + tar -C /usr/local -xzf "$GO_TAR" + cd - >/dev/null + + # Add Go to PATH for all users + if ! grep -q '/usr/local/go/bin' /etc/profile.d/go.sh 2>/dev/null; then + echo 'export PATH=$PATH:/usr/local/go/bin' > /etc/profile.d/go.sh + chmod 644 /etc/profile.d/go.sh + fi + export PATH=$PATH:/usr/local/go/bin + echo "Go ${GO_VERSION} installed to /usr/local/go" +fi + +echo "" +echo "=== Installing Docker (for Prometheus/Grafana metrics; optional) ===" +if command -v docker &>/dev/null; then + echo "Docker already installed: $(docker --version)" +else + apt-get install -y ca-certificates curl + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc + chmod a+r /etc/apt/keyrings/docker.asc + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \ + > /etc/apt/sources.list.d/docker.list + apt-get update + apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + echo "Docker installed. Add users to the 'docker' group for non-root access: usermod -aG docker " +fi + +echo "" +echo "=== Setup complete ===" +echo "" +echo "To use Go in the current shell, run:" +echo " export PATH=\$PATH:/usr/local/go/bin" +echo " (or log out and back in, or start a new tmux session)" +echo "" +echo "To run the cryptosim benchmark:" +echo " 1. Clone the sei-chain repo (or copy it to the machine)" +echo " 2. cd /sei-db/state_db/bench/cryptosim" +echo " 3. ./run.sh ./config/basic-config.json" +echo "" +echo "For Prometheus/Grafana metrics:" +echo " ./metrics/start-prometheus.sh" +echo " ./metrics/start-grafana.sh" +echo "" From 97920c2107ff6dbb94e2b1107e8a9bd0f4bcd7a0 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 13:11:34 -0600 Subject: [PATCH 44/49] Properly set up docker --- sei-db/state_db/bench/cryptosim/README.md | 34 +++++++++++++++++++ .../bench/cryptosim/tools/setup-ubuntu.sh | 29 ++++++++-------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/README.md b/sei-db/state_db/bench/cryptosim/README.md index 35fbf6bb72..4049f6eeed 100644 --- a/sei-db/state_db/bench/cryptosim/README.md +++ b/sei-db/state_db/bench/cryptosim/README.md @@ -73,3 +73,37 @@ You can stop these services by killing their containers, or by running the follo ./metrics/stop-prometheus.sh ./metrics/stop-grafana.sh ``` + +# Running in AWS + +To set up this benchmark on an AWS machine, perform the following steps: + +1. Clone the repo + +``` +git clone https://github.com/sei-protocol/sei-chain.git +``` + +2. Install dependencies + +``` +cd ./sei-chain/sei-db/state_db/bench/cryptosim +./tools/setup-ubuntu.sh +``` + +3: Start Prometheus Server (optional) + +``` +cd ./sei-chain/sei-db/state_db/bench/cryptosim +./metrics/start-prometheus.sh +``` + +3. Start the Benchmark + +Optional: start a tmux session (the install script installs tmux). This will allow the benchmark to run +even if your connection is interrupted. + +``` +cd sei-chain/sei-db/state_db/bench/cryptosim +./run.sh ./config/basic-config.json +``` \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh b/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh index 12a7337fe9..bdad69cdf1 100755 --- a/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh +++ b/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh @@ -66,7 +66,7 @@ else fi echo "" -echo "=== Installing Docker (for Prometheus/Grafana metrics; optional) ===" +echo "=== Installing Docker (for Prometheus/Grafana metrics) ===" if command -v docker &>/dev/null; then echo "Docker already installed: $(docker --version)" else @@ -78,22 +78,21 @@ else > /etc/apt/sources.list.d/docker.list apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - echo "Docker installed. Add users to the 'docker' group for non-root access: usermod -aG docker " + echo "Docker installed." +fi + +# Start Docker daemon and enable on boot (handles both fresh install and existing install) +echo "Starting and enabling Docker daemon..." +systemctl start docker +systemctl enable docker + +# Add sudo user to docker group for non-root access (requires new login to take effect) +if [[ -n "${SUDO_USER:-}" ]] && [[ "$SUDO_USER" != "root" ]]; then + usermod -aG docker "$SUDO_USER" + echo "Added $SUDO_USER to docker group. Log out and back in (or run 'newgrp docker') for non-root access." fi echo "" echo "=== Setup complete ===" echo "" -echo "To use Go in the current shell, run:" -echo " export PATH=\$PATH:/usr/local/go/bin" -echo " (or log out and back in, or start a new tmux session)" -echo "" -echo "To run the cryptosim benchmark:" -echo " 1. Clone the sei-chain repo (or copy it to the machine)" -echo " 2. cd /sei-db/state_db/bench/cryptosim" -echo " 3. ./run.sh ./config/basic-config.json" -echo "" -echo "For Prometheus/Grafana metrics:" -echo " ./metrics/start-prometheus.sh" -echo " ./metrics/start-grafana.sh" -echo "" + From 2b7c9dac94e2aea17b85fd5c23270ddce35b6388 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 13:27:46 -0600 Subject: [PATCH 45/49] Updated readme instructions --- sei-db/state_db/bench/cryptosim/README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sei-db/state_db/bench/cryptosim/README.md b/sei-db/state_db/bench/cryptosim/README.md index 4049f6eeed..3dcbe201be 100644 --- a/sei-db/state_db/bench/cryptosim/README.md +++ b/sei-db/state_db/bench/cryptosim/README.md @@ -106,4 +106,21 @@ even if your connection is interrupted. ``` cd sei-chain/sei-db/state_db/bench/cryptosim ./run.sh ./config/basic-config.json -``` \ No newline at end of file +``` + +4: Connect Local Grafana to Remote Prometheus (optional) + +Before taking this step, you will need to set up SSH access to the remote VM. The easiest way to do this is to +copy your public ssh key into the remote machine's `~/.ssh/authorized_keys` file. + +You will want the prometheus container running on your remote machine, and the grafana container running locally. +Make sure you don't have a local prometheus container running. + +Then, initiate an ssh connection with the remote machine using this command: + +``` +ssh -L 9091:localhost:9091 user@remote-host +``` + +As long as this connection remains open, your local grafana instance will be able to talk to the remote prometheus +instance over the SSH tunnel. From 98f49f61fe7ab7363e8de921fcc4cc2e7ede013e Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 13:40:00 -0600 Subject: [PATCH 46/49] lint --- go.mod | 5 +++++ go.sum | 2 ++ sei-db/state_db/bench/cryptosim/cryptosim.go | 4 +++- .../bench/cryptosim/cryptosim_metrics.go | 19 ++++++++++++++++--- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 35420d16f2..da7b7bf309 100644 --- a/go.mod +++ b/go.mod @@ -117,6 +117,11 @@ require ( pgregory.net/rapid v1.2.0 ) +require ( + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect +) + require ( github.com/quasilyte/go-ruleguard v0.3.18 // indirect github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f // indirect diff --git a/go.sum b/go.sum index ac7f48c35c..4b5d350e54 100644 --- a/go.sum +++ b/go.sum @@ -1637,6 +1637,7 @@ github.com/linxGnu/grocksdb v1.8.11/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXk github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= @@ -1905,6 +1906,7 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/polyfloyd/go-errorlint v1.0.5 h1:AHB5JRCjlmelh9RrLxT9sgzpalIwwq4hqE8EkwIwKdY= github.com/polyfloyd/go-errorlint v1.0.5/go.mod h1:APVvOesVSAnne5SClsPxPdfvZTVDojXh1/G3qb5wjGI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index 1055958d71..86f3e14f24 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim.go @@ -78,13 +78,15 @@ func NewCryptoSim( dataDir, err := resolveAndCreateDataDir(config.DataDir) if err != nil { - return nil, err + cancel() + return nil, fmt.Errorf("failed to resolve and create data directory: %w", err) } fmt.Printf("Running cryptosim benchmark from data directory: %s\n", dataDir) db, err := wrappers.NewDBImpl(config.Backend, dataDir) if err != nil { + cancel() return nil, fmt.Errorf("failed to create database: %w", err) } diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index ef1ba70bc5..a6a03f41b2 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -3,6 +3,7 @@ package cryptosim import ( "context" "io/fs" + "math" "net/http" "os" "path/filepath" @@ -193,7 +194,11 @@ func (m *CryptosimMetrics) startProcessIOSampling(intervalSeconds int) { // OSX does not support process I/O stats. return } - proc, err := process.NewProcess(int32(os.Getpid())) + pid := os.Getpid() + if pid < 0 || pid > math.MaxInt32 { + return + } + proc, err := process.NewProcess(int32(pid)) if err != nil { return } @@ -276,7 +281,11 @@ func measureDataDirAvailableBytes(dataDir string) int64 { if err := unix.Statfs(dataDir, &stat); err != nil { return 0 } - return int64(stat.Bavail) * int64(stat.Bsize) + result := stat.Bavail * uint64(stat.Bsize) + if result > math.MaxInt64 { + return math.MaxInt64 + } + return int64(result) } // measureDataDirSize walks the directory tree and sums file sizes. @@ -305,7 +314,11 @@ func measureDataDirSize(dataDir string) int64 { func startMetricsServer(ctx context.Context, reg *prometheus.Registry, addr string) { mux := http.NewServeMux() mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{})) - srv := &http.Server{Addr: addr, Handler: mux} + srv := &http.Server{ + Addr: addr, + Handler: mux, + ReadHeaderTimeout: 10 * time.Second, + } go func() { _ = srv.ListenAndServe() }() From 126e43c522d1a552a9bcc9bdaa04c43a36f3254d Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 13:41:19 -0600 Subject: [PATCH 47/49] dashboard tweaks --- .../bench/cryptosim/metrics/dashboard.json | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json index 108cfbe626..7b2426620c 100644 --- a/sei-db/state_db/bench/cryptosim/metrics/dashboard.json +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -557,7 +557,7 @@ "h": 8, "w": 12, "x": 12, - "y": 42 + "y": 138 }, "id": 21, "options": { @@ -652,7 +652,7 @@ "h": 8, "w": 12, "x": 0, - "y": 50 + "y": 146 }, "id": 22, "options": { @@ -783,7 +783,7 @@ "h": 8, "w": 12, "x": 12, - "y": 50 + "y": 146 }, "id": 23, "options": { @@ -914,7 +914,7 @@ "h": 8, "w": 12, "x": 0, - "y": 58 + "y": 154 }, "id": 24, "options": { @@ -1045,7 +1045,7 @@ "h": 8, "w": 12, "x": 12, - "y": 58 + "y": 154 }, "id": 25, "options": { @@ -1176,7 +1176,7 @@ "h": 8, "w": 12, "x": 0, - "y": 66 + "y": 162 }, "id": 26, "options": { @@ -1307,7 +1307,7 @@ "h": 8, "w": 12, "x": 12, - "y": 66 + "y": 162 }, "id": 27, "options": { @@ -1438,7 +1438,7 @@ "h": 8, "w": 12, "x": 0, - "y": 74 + "y": 170 }, "id": 28, "options": { @@ -1582,7 +1582,7 @@ "h": 8, "w": 12, "x": 0, - "y": 195 + "y": 179 }, "id": 1, "options": { @@ -1681,7 +1681,7 @@ "h": 8, "w": 12, "x": 12, - "y": 195 + "y": 179 }, "id": 18, "options": { @@ -1825,7 +1825,7 @@ "h": 8, "w": 12, "x": 0, - "y": 196 + "y": 188 }, "id": 3, "options": { @@ -1924,7 +1924,7 @@ "h": 8, "w": 12, "x": 12, - "y": 196 + "y": 188 }, "id": 4, "options": { @@ -2258,7 +2258,7 @@ "h": 8, "w": 12, "x": 0, - "y": 269 + "y": 205 }, "id": 10, "options": { @@ -2352,7 +2352,7 @@ "h": 8, "w": 12, "x": 12, - "y": 269 + "y": 205 }, "id": 11, "options": { @@ -2461,7 +2461,7 @@ "h": 8, "w": 12, "x": 0, - "y": 278 + "y": 214 }, "id": 31, "options": { @@ -2556,7 +2556,7 @@ "h": 8, "w": 12, "x": 12, - "y": 278 + "y": 214 }, "id": 36, "options": { @@ -2651,7 +2651,7 @@ "h": 8, "w": 12, "x": 0, - "y": 286 + "y": 222 }, "id": 38, "options": { @@ -2949,7 +2949,7 @@ "h": 8, "w": 12, "x": 0, - "y": 31 + "y": 63 }, "id": 34, "options": { @@ -3058,7 +3058,7 @@ "h": 8, "w": 12, "x": 0, - "y": 200 + "y": 24 }, "id": 39, "options": { @@ -3153,7 +3153,7 @@ "h": 8, "w": 12, "x": 12, - "y": 200 + "y": 24 }, "id": 40, "options": { @@ -3248,7 +3248,7 @@ "h": 8, "w": 12, "x": 0, - "y": 208 + "y": 32 }, "id": 41, "options": { @@ -3343,7 +3343,7 @@ "h": 8, "w": 12, "x": 12, - "y": 208 + "y": 32 }, "id": 42, "options": { @@ -3438,7 +3438,7 @@ "h": 8, "w": 12, "x": 0, - "y": 216 + "y": 40 }, "id": 32, "options": { @@ -3547,7 +3547,7 @@ "h": 8, "w": 12, "x": 0, - "y": 233 + "y": 49 }, "id": 43, "options": { From 155b6ba2efaf724f74215a2ef21e2a5d36866ec8 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 13:53:12 -0600 Subject: [PATCH 48/49] Add new config --- sei-db/state_db/bench/cryptosim/config/large.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 sei-db/state_db/bench/cryptosim/config/large.json diff --git a/sei-db/state_db/bench/cryptosim/config/large.json b/sei-db/state_db/bench/cryptosim/config/large.json new file mode 100644 index 0000000000..358c7ac47c --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/config/large.json @@ -0,0 +1,6 @@ +{ + "Comment": "A large simulation. This is the largest sane simulation for local testing.", + "DataDir": "data", + "MinimumNumberOfAccounts": 100000000 +} + From fa554e8c33596cda2cbe3585897ddf81f4cdd178 Mon Sep 17 00:00:00 2001 From: Cody Littley Date: Fri, 27 Feb 2026 14:09:21 -0600 Subject: [PATCH 49/49] lint --- sei-db/state_db/bench/cryptosim/cryptosim_metrics.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go index a6a03f41b2..bbd085e4b3 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -281,7 +281,7 @@ func measureDataDirAvailableBytes(dataDir string) int64 { if err := unix.Statfs(dataDir, &stat); err != nil { return 0 } - result := stat.Bavail * uint64(stat.Bsize) + result := stat.Bavail * uint64(stat.Bsize) //nolint:gosec if result > math.MaxInt64 { return math.MaxInt64 }