diff --git a/go.mod b/go.mod index 8ca2814fe7..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 @@ -334,6 +339,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..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= @@ -2048,6 +2050,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/README.md b/sei-db/state_db/bench/cryptosim/README.md index 3fe791a79e..3dcbe201be 100644 --- a/sei-db/state_db/bench/cryptosim/README.md +++ b/sei-db/state_db/bench/cryptosim/README.md @@ -50,3 +50,77 @@ 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 + +To set up local prometheus/grafana instances, run the following. You must have docker installed. + +``` +./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. + + +You can stop these services by killing their containers, or by running the following: + +``` +./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 +``` + +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. 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 f7576d849d..15d172acac 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, @@ -16,6 +16,7 @@ "HotErc20ContractProbability": 0.5, "HotErc20ContractSetSize": 100, "MinimumNumberOfAccounts": 1000000, + "MetricsAddr": ":9090", "MinimumNumberOfErc20Contracts": 10000, "NewAccountProbability": 0.001, "PaddedAccountSize": 69, @@ -23,5 +24,7 @@ "SetupUpdateIntervalCount": 100000, "ThreadsPerCore": 2.0, "TransactionsPerBlock": 1024, - "MaxRuntimeSeconds": 0 + "MaxRuntimeSeconds": 0, + "TransactionMetricsSampleRate": 0.001, + "BackgroundMetricsScrapeInterval": 60 } 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 +} + diff --git a/sei-db/state_db/bench/cryptosim/cryptosim.go b/sei-db/state_db/bench/cryptosim/cryptosim.go index ba03e4026f..86f3e14f24 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,15 +71,22 @@ func NewCryptoSim( return nil, fmt.Errorf("invalid config: %w", err) } + ctx, cancel := context.WithCancel(ctx) + 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. + 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) } @@ -87,11 +97,9 @@ 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) + dataGenerator, err := NewDataGenerator(config, database, rand, metrics) if err != nil { cancel() if closeErr := db.Close(); closeErr != nil { @@ -99,7 +107,6 @@ 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 @@ -109,7 +116,7 @@ func NewCryptoSim( executors := make([]*TransactionExecutor, threadCount) for i := 0; i < threadCount; i++ { executors[i] = NewTransactionExecutor( - ctx, database, dataGenerator.FeeCollectionAddress(), config.ExecutorQueueSize) + ctx, cancel, database, dataGenerator.FeeCollectionAddress(), config.ExecutorQueueSize, metrics) } c := &CryptoSim{ @@ -123,6 +130,7 @@ func NewCryptoSim( dataGenerator: dataGenerator, database: database, executors: executors, + metrics: metrics, } database.SetFlushFunc(c.flushExecutors) @@ -134,6 +142,7 @@ func NewCryptoSim( c.database.ResetTransactionCount() c.startTimestamp = time.Now() + c.metrics.StartServer(config.MetricsAddr) go c.run() return c, nil @@ -184,6 +193,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() } @@ -202,6 +212,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())) @@ -245,6 +256,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 { @@ -266,6 +278,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())) @@ -280,6 +293,8 @@ func (c *CryptoSim) run() { haltTime := time.Now().Add(time.Duration(c.config.MaxRuntimeSeconds) * time.Second) + c.metrics.SetMainThreadPhase("executing") + for { select { case <-c.ctx.Done(): @@ -293,6 +308,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 } @@ -303,6 +319,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/cryptosim_config.go b/sei-db/state_db/bench/cryptosim/cryptosim_config.go index ff69b8c42e..4089641814 100644 --- a/sei-db/state_db/bench/cryptosim/cryptosim_config.go +++ b/sei-db/state_db/bench/cryptosim/cryptosim_config.go @@ -108,6 +108,16 @@ type CryptoSimConfig struct { // The amount of time to run the benchmark for. If 0, the benchmark will run until it is stopped. MaxRuntimeSeconds int + + // 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 + + // 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. @@ -140,6 +150,9 @@ func DefaultCryptoSimConfig() *CryptoSimConfig { ConstantThreadCount: 0, ExecutorQueueSize: 64, MaxRuntimeSeconds: 0, + MetricsAddr: ":9090", + TransactionMetricsSampleRate: 0.001, + BackgroundMetricsScrapeInterval: 60, } } @@ -202,6 +215,13 @@ func (c *CryptoSimConfig) Validate() error { if c.MaxRuntimeSeconds < 0 { return fmt.Errorf("MaxRuntimeSeconds must be at least 0 (got %d)", c.MaxRuntimeSeconds) } + if c.TransactionMetricsSampleRate < 0 || c.TransactionMetricsSampleRate > 1 { + return fmt.Errorf("TransactionMetricsSampleRate must be in [0, 1] (got %f)", c.TransactionMetricsSampleRate) + } + 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 new file mode 100644 index 0000000000..bbd085e4b3 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/cryptosim_metrics.go @@ -0,0 +1,393 @@ +package cryptosim + +import ( + "context" + "io/fs" + "math" + "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" +) + +// 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 + 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 +} + +// 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 BackgroundMetricsScrapeInterval > 0. +func NewCryptosimMetrics( + ctx context.Context, + config *CryptoSimConfig, +) *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", + }) + 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", + }) + dataDirSizeBytes := prometheus.NewGauge(prometheus.GaugeOpts{ + 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", + }) + 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") + + reg.MustRegister( + blocksFinalizedTotal, + transactionsProcessedTotal, + totalAccounts, + totalErc20Contracts, + dbCommitsTotal, + dataDirSizeBytes, + dataDirAvailableBytes, + processReadBytesTotal, + processWriteBytesTotal, + processReadCountTotal, + processWriteCountTotal, + uptimeSeconds, + ) + + m := &CryptosimMetrics{ + reg: reg, + ctx: ctx, + blocksFinalizedTotal: blocksFinalizedTotal, + transactionsProcessedTotal: transactionsProcessedTotal, + totalAccounts: totalAccounts, + totalErc20Contracts: totalErc20Contracts, + dbCommitsTotal: dbCommitsTotal, + dataDirSizeBytes: dataDirSizeBytes, + dataDirAvailableBytes: dataDirAvailableBytes, + processReadBytesTotal: processReadBytesTotal, + processWriteBytesTotal: processWriteBytesTotal, + processReadCountTotal: processReadCountTotal, + processWriteCountTotal: processWriteCountTotal, + uptimeSeconds: uptimeSeconds, + mainThreadPhase: mainThreadPhase, + transactionPhaseTimerFactory: transactionPhaseTimerFactory, + } + if config != nil && config.BackgroundMetricsScrapeInterval > 0 && config.DataDir != "" { + if dataDir, err := resolveAndCreateDataDir(config.DataDir); err == nil { + m.startDataDirSizeSampling(dataDir, config.BackgroundMetricsScrapeInterval) + } + m.startProcessIOSampling(config.BackgroundMetricsScrapeInterval) + } + return m +} + +// 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 + } + 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 + } + pid := os.Getpid() + if pid < 0 || pid > math.MaxInt32 { + return + } + proc, err := process.NewProcess(int32(pid)) + 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. +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() + 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: + 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 + } + result := stat.Bavail * uint64(stat.Bsize) //nolint:gosec + if result > math.MaxInt64 { + return math.MaxInt64 + } + return int64(result) +} + +// 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) { + mux := http.NewServeMux() + mux.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{})) + srv := &http.Server{ + Addr: addr, + Handler: mux, + ReadHeaderTimeout: 10 * time.Second, + } + 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, the number of +// transactions in that block, and the finalization latency. +func (m *CryptosimMetrics) ReportBlockFinalized(transactionCount int64) { + if m == nil { + return + } + m.blocksFinalizedTotal.Inc() + m.transactionsProcessedTotal.Add(float64(transactionCount)) +} + +// ReportDBCommit records that a database commit completed and the latency. +func (m *CryptosimMetrics) ReportDBCommit() { + if m == nil { + return + } + m.dbCommitsTotal.Inc() +} + +// 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)) +} + +// 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 + } + m.mainThreadPhase.SetPhase(phase) +} diff --git a/sei-db/state_db/bench/cryptosim/data_generator.go b/sei-db/state_db/bench/cryptosim/data_generator.go index e09bb438e6..4a2b70bd41 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()) @@ -60,6 +64,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 { @@ -72,6 +77,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( @@ -87,6 +93,7 @@ func NewDataGenerator( feeCollectionAddress: feeCollectionAddress, database: database, highestSafeAccountIDInBlock: nextAccountID - 1, + metrics: metrics, }, nil } @@ -190,6 +197,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 c685187d59..2b723fbdbc 100644 --- a/sei-db/state_db/bench/cryptosim/database.go +++ b/sei-db/state_db/bench/cryptosim/database.go @@ -32,17 +32,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,7 +129,7 @@ func (d *Database) FinalizeBlock( return nil } - d.transactionsInCurrentBlock = 0 + d.metrics.SetMainThreadPhase("finalizing") changeSets := make([]*proto.NamedChangeSet, 0, d.transactionsInCurrentBlock+2) for key, value := range d.batch.Iterator() { @@ -162,16 +167,23 @@ func (d *Database) FinalizeBlock( return fmt.Errorf("failed to apply change sets: %w", err) } + d.metrics.ReportBlockFinalized(d.transactionsInCurrentBlock) + d.transactionsInCurrentBlock = 0 + // Periodically commit the changes to the database. d.uncommittedBlockCount++ if forceCommit || d.uncommittedBlockCount >= int64(d.config.BlocksPerCommit) { + d.metrics.SetMainThreadPhase("committing") _, err := d.db.Commit() if err != nil { return fmt.Errorf("failed to commit: %w", err) } + d.metrics.ReportDBCommit() d.uncommittedBlockCount = 0 } + 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 new file mode 100644 index 0000000000..7b2426620c --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/metrics/dashboard.json @@ -0,0 +1,3601 @@ +{ + "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": 138 + }, + "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": 146 + }, + "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": 146 + }, + "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": 154 + }, + "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": 154 + }, + "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": 162 + }, + "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": 162 + }, + "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": 170 + }, + "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": 179 + }, + "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": 179 + }, + "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": 188 + }, + "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": 188 + }, + "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": 197 + }, + "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": 197 + }, + "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": 205 + }, + "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": 205 + }, + "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": 214 + }, + "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": 214 + }, + "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": 222 + }, + "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": 23 + }, + "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": 23 + }, + "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": 63 + }, + "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": 24 + }, + "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": 24 + }, + "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": 32 + }, + "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": 32 + }, + "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": 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" + } + ], + "title": "Open File Descriptors", + "type": "timeseries" + } + ], + "title": "File System", + "type": "row" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 44, + "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": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 49 + }, + "id": 43, + "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_uptime_seconds", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Uptime", + "type": "timeseries" + } + ], + "title": "Misc", + "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": 13, + "weekStart": "" +} \ No newline at end of file diff --git a/sei-db/state_db/bench/cryptosim/metrics/grafana.yaml b/sei-db/state_db/bench/cryptosim/metrics/grafana.yaml new file mode 100644 index 0000000000..49c5cb5b58 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/metrics/grafana.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/metrics/prometheus.yaml b/sei-db/state_db/bench/cryptosim/metrics/prometheus.yaml new file mode 100644 index 0000000000..e8c478f098 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/metrics/prometheus.yaml @@ -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/metrics/start-grafana.sh b/sei-db/state_db/bench/cryptosim/metrics/start-grafana.sh new file mode 100755 index 0000000000..b59962b414 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/metrics/start-grafana.sh @@ -0,0 +1,82 @@ +#!/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)" +DATASOURCE_CONFIG="${SCRIPT_DIR}/grafana.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 "${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" \ + 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/metrics/start-prometheus.sh b/sei-db/state_db/bench/cryptosim/metrics/start-prometheus.sh new file mode 100755 index 0000000000..aab63bdded --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/metrics/start-prometheus.sh @@ -0,0 +1,77 @@ +#!/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_CONFIG="${SCRIPT_DIR}/prometheus.yaml" +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/metrics/stop-grafana.sh b/sei-db/state_db/bench/cryptosim/metrics/stop-grafana.sh new file mode 100755 index 0000000000..1d8c401769 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/metrics/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/metrics/stop-prometheus.sh b/sei-db/state_db/bench/cryptosim/metrics/stop-prometheus.sh new file mode 100755 index 0000000000..3e91242799 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/metrics/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 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..9389f8c56f --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/phase_timer.go @@ -0,0 +1,109 @@ +package cryptosim + +import ( + "fmt" + "time" + + "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 on a single instance. +// +// Grafana queries (substitute PREFIX with the name passed to NewPhaseTimer or NewPhaseTimerFactory): +// +// 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 +} + +// 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/tools/setup-ubuntu.sh b/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh new file mode 100755 index 0000000000..bdad69cdf1 --- /dev/null +++ b/sei-db/state_db/bench/cryptosim/tools/setup-ubuntu.sh @@ -0,0 +1,98 @@ +#!/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) ===" +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." +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 "" + diff --git a/sei-db/state_db/bench/cryptosim/transaction.go b/sei-db/state_db/bench/cryptosim/transaction.go index ffcd57fcdb..3582f965de 100644 --- a/sei-db/state_db/bench/cryptosim/transaction.go +++ b/sei-db/state_db/bench/cryptosim/transaction.go @@ -41,6 +41,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 +87,8 @@ func BuildTransaction( newDstData = append([]byte(nil), b...) } + captureMetrics := dataGenerator.rand.Float64() < dataGenerator.config.TransactionMetricsSampleRate + return &transaction{ srcAccount: srcAccountAddress, isSrcNew: isSrcNew, @@ -98,6 +104,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 } @@ -108,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 { @@ -126,11 +136,16 @@ 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 { 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. @@ -145,6 +160,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 { @@ -162,6 +179,11 @@ 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") // 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. @@ -170,6 +192,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) @@ -177,6 +201,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 { @@ -185,10 +211,17 @@ 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") // 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)) //nolint:gosec @@ -232,5 +265,12 @@ func (txn *transaction) Execute( return fmt.Errorf("failed to put fee collection account: %w", err) } + phaseTimer.Reset() + return nil } + +// 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..c00f4e63d7 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 @@ -16,6 +17,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. @@ -26,15 +30,19 @@ type flushRequest struct { // A single threaded transaction executor. func NewTransactionExecutor( ctx context.Context, + cancel context.CancelFunc, database *Database, feeCollectionAddress []byte, queueSize int, + metrics *CryptosimMetrics, ) *TransactionExecutor { e := &TransactionExecutor{ ctx: ctx, + cancel: cancel, database: database, feeCollectionAddress: feeCollectionAddress, workChan: make(chan any, queueSize), + phaseTimer: metrics.GetTransactionPhaseTimerInstance(), } go e.mainLoop() @@ -75,8 +83,15 @@ 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) + e.cancel() } case flushRequest: request.doneChan <- struct{}{}