Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e096dc1
refactor: block export
RodrigoVillar Dec 2, 2025
fa99ce5
chore: nits
RodrigoVillar Dec 3, 2025
a433a81
chore(reexecute/c): remove go bench from benchmark
RodrigoVillar Dec 2, 2025
c1203b1
chore: remove go bench in workflow
RodrigoVillar Dec 2, 2025
1935adf
chore: reduce diff
RodrigoVillar Dec 2, 2025
b508826
chore: use test context logger
RodrigoVillar Dec 4, 2025
953a76e
chore: clean up benchmarkTool
RodrigoVillar Dec 4, 2025
e6481ab
docs: benchmarking types
RodrigoVillar Dec 4, 2025
89abbde
refactor: use tc wherever convenient
RodrigoVillar Dec 4, 2025
5f55711
refactor: clean up result logging
RodrigoVillar Dec 4, 2025
afac7bc
fix: append unit to base name
RodrigoVillar Dec 4, 2025
a817e73
chore: remove unnecessary log
RodrigoVillar Dec 4, 2025
d0b95de
Merge branch 'master' into rodrigo/custom-benchmarks
RodrigoVillar Dec 9, 2025
828abe3
chore: nit
RodrigoVillar Dec 9, 2025
01f0663
chore: add back require
RodrigoVillar Dec 9, 2025
18b884d
chore: txt => json
RodrigoVillar Dec 9, 2025
d4639ff
docs: remove stale ref
RodrigoVillar Dec 9, 2025
718bc52
docs: nit
RodrigoVillar Dec 9, 2025
b26e8c4
chore: improve logResults()
RodrigoVillar Dec 9, 2025
3588978
chore: address PR review
RodrigoVillar Dec 9, 2025
9e7f54f
Merge branch 'master' into rodrigo/custom-benchmarks
RodrigoVillar Dec 10, 2025
bc78644
chore(reexecute/c): add back scraping of multiple metrics
RodrigoVillar Dec 10, 2025
29da042
Merge branch 'master' into rodrigo/add-back-multiple-metrics
RodrigoVillar Dec 16, 2025
7250778
chore: nit
RodrigoVillar Dec 16, 2025
43f9633
chore: nsPerMs => nanosecondsPerMillisecond
RodrigoVillar Dec 16, 2025
9a97ce8
chore: make clear that metric values are in terms of ns
RodrigoVillar Dec 16, 2025
4144d9e
refactor: move topLevelMetric def
RodrigoVillar Dec 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore(reexecute/c): remove go bench from benchmark
  • Loading branch information
RodrigoVillar committed Dec 3, 2025
commit a433a8154217797aed06d6774061e101c78bc9c7
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ tasks:
LABELS: '{{.LABELS | default ""}}'
BENCHMARK_OUTPUT_FILE: '{{.BENCHMARK_OUTPUT_FILE | default ""}}'
TIMESTAMP: '{{.TIMESTAMP | default (now | date "20060102-150405")}}'
EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR | default (printf "/tmp/%s-%s" .TASK_NAME .TIMESTAMP)}}'
EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR | default (printf "/tmp/%s-%s" .TASK .TIMESTAMP)}}'
cmd: |
CURRENT_STATE_DIR={{.CURRENT_STATE_DIR}} \
BLOCK_DIR={{.BLOCK_DIR}} \
Expand Down
9 changes: 3 additions & 6 deletions scripts/benchmark_cchain_range.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ set -euo pipefail
: "${START_BLOCK:?START_BLOCK must be set}"
: "${END_BLOCK:?END_BLOCK must be set}"

cmd="go test -timeout=0 -v -benchtime=1x -bench=BenchmarkReexecuteRange -run=^$ github.com/ava-labs/avalanchego/tests/reexecute/c \
cmd="go run github.com/ava-labs/avalanchego/tests/reexecute/c \
--benchmark-output-file=\"${BENCHMARK_OUTPUT_FILE}\" \
--block-dir=\"${BLOCK_DIR}\" \
--current-state-dir=\"${CURRENT_STATE_DIR}\" \
${RUNNER_NAME:+--runner=\"${RUNNER_NAME}\"} \
Expand All @@ -31,8 +32,4 @@ cmd="go test -timeout=0 -v -benchtime=1x -bench=BenchmarkReexecuteRange -run=^$
${METRICS_SERVER_PORT:+--metrics-server-port=\"${METRICS_SERVER_PORT}\"} \
${METRICS_COLLECTOR_ENABLED:+--metrics-collector-enabled=\"${METRICS_COLLECTOR_ENABLED}\"}"

if [ -n "${BENCHMARK_OUTPUT_FILE:-}" ]; then
eval "$cmd" | tee "${BENCHMARK_OUTPUT_FILE}"
else
eval "$cmd"
fi
eval "$cmd"
1 change: 0 additions & 1 deletion tests/reexecute/blockexport/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ func main() {
startBlockArg,
endBlockArg,
chanSizeArg,
tc.DeferCleanup,
)
r.NoError(err)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package vm
package main

import (
"context"
"encoding/json"
"flag"
"fmt"
"maps"
Expand All @@ -13,7 +14,6 @@ import (
"slices"
"strconv"
"strings"
"testing"
"time"

"github.com/google/uuid"
Expand Down Expand Up @@ -41,6 +41,7 @@ import (
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/crypto/bls/signer/localsigner"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/perms"
"github.com/ava-labs/avalanchego/utils/timer"
"github.com/ava-labs/avalanchego/vms/metervm"
"github.com/ava-labs/avalanchego/vms/platformvm/warp"
Expand Down Expand Up @@ -97,9 +98,11 @@ var (
configNameArg string
runnerNameArg string
configBytesArg []byte

benchmarkOutputFileArg string
)

func TestMain(m *testing.M) {
func init() {
evm.RegisterAllLibEVMExtras()

flag.StringVar(&blockDirArg, "block-dir", blockDirArg, "Block DB directory to read from during re-execution.")
Expand All @@ -119,6 +122,8 @@ func TestMain(m *testing.M) {
flag.StringVar(&configNameArg, configKey, defaultConfigKey, fmt.Sprintf("Specifies the predefined config to use for the VM. Options include %s.", predefinedConfigOptionsStr))
flag.StringVar(&runnerNameArg, "runner", "dev", "Name of the runner executing this test. Added as a metric label and to the sub-benchmark's name to differentiate results on the runner key.")

flag.StringVar(&benchmarkOutputFileArg, "benchmark-output-file", benchmarkOutputFileArg, "The filepath where benchmark results should be written to.")

flag.Parse()

if metricsCollectorEnabledArg {
Expand All @@ -143,30 +148,40 @@ func TestMain(m *testing.M) {

// Set the runner name label on the metrics.
labels["runner"] = runnerNameArg

m.Run()
}

func BenchmarkReexecuteRange(b *testing.B) {
require.Equalf(b, 1, b.N, "BenchmarkReexecuteRange expects to run a single iteration because it overwrites the input current-state, but found (b.N=%d)", b.N)
b.Run(fmt.Sprintf("[%d,%d]-Config-%s-Runner-%s", startBlockArg, endBlockArg, configNameArg, runnerNameArg), func(b *testing.B) {
benchmarkReexecuteRange(
b,
blockDirArg,
currentStateDirArg,
configBytesArg,
startBlockArg,
endBlockArg,
chanSizeArg,
metricsServerEnabledArg,
metricsServerPortArg,
metricsCollectorEnabledArg,
)
})
func main() {
tc := tests.NewTestContext(tests.NewDefaultLogger("c-chain-reexecution"))
tc.SetDefaultContextParent(context.Background())
defer tc.RecoverAndExit()

benchmarkName := fmt.Sprintf(
"BenchmarkReexecuteRange/[%d,%d]-Config-%s-Runner-%s",
startBlockArg,
endBlockArg,
configNameArg,
runnerNameArg,
)

benchmarkReexecuteRange(
tc,
benchmarkName,
blockDirArg,
currentStateDirArg,
configBytesArg,
startBlockArg,
endBlockArg,
chanSizeArg,
metricsServerEnabledArg,
metricsServerPortArg,
metricsCollectorEnabledArg,
benchmarkOutputFileArg,
)
}

func benchmarkReexecuteRange(
b *testing.B,
tc tests.TestContext,
benchmarkName string,
blockDir string,
currentStateDir string,
configBytes []byte,
Expand All @@ -176,9 +191,10 @@ func benchmarkReexecuteRange(
metricsServerEnabled bool,
metricsPort uint64,
metricsCollectorEnabled bool,
benchmarkOutputFile string,
) {
r := require.New(b)
ctx := b.Context()
r := require.New(tc)
ctx := tc.GetDefaultContextParent()

// Create the prefix gatherer passed to the VM and register it with the top-level,
// labeled gatherer.
Expand All @@ -198,10 +214,10 @@ func benchmarkReexecuteRange(
log := tests.NewDefaultLogger("c-chain-reexecution")

if metricsServerEnabled {
serverAddr := startServer(b, log, prefixGatherer, metricsPort)
serverAddr := startServer(tc, log, prefixGatherer, metricsPort)

if metricsCollectorEnabled {
startCollector(b, log, "c-chain-reexecution", labels, serverAddr)
startCollector(tc, log, "c-chain-reexecution", labels, serverAddr)
}
}

Expand All @@ -225,7 +241,7 @@ func benchmarkReexecuteRange(
zap.Int("chan-size", chanSize),
)

blockChan, err := reexecute.CreateBlockChanFromLevelDB(b, blockDir, startBlock, endBlock, chanSize, b.Cleanup)
blockChan, err := reexecute.CreateBlockChanFromLevelDB(tc, blockDir, startBlock, endBlock, chanSize)
r.NoError(err)

dbLogger := tests.NewDefaultLogger("db")
Expand Down Expand Up @@ -265,8 +281,11 @@ func benchmarkReexecuteRange(
r.NoError(executor.executeSequence(ctx, blockChan))
elapsed := time.Since(start)

b.ReportMetric(0, "ns/op") // Set default ns/op to 0 to hide from the output
getTopLevelMetrics(b, prefixGatherer, elapsed) // Report the desired top-level metrics
benchmarkTool := newBenchmarkTool(benchmarkName)
getTopLevelMetrics(tc, benchmarkTool, prefixGatherer, elapsed) // Report the desired top-level metrics
if len(benchmarkOutputFile) != 0 {
r.NoError(benchmarkTool.saveToFile(benchmarkOutputFile))
}
}

func newMainnetCChainVM(
Expand Down Expand Up @@ -496,12 +515,12 @@ func newConsensusMetrics(registry prometheus.Registerer) (*consensusMetrics, err
// startServer starts a Prometheus server for the provided gatherer and returns
// the server address.
func startServer(
tb testing.TB,
tc tests.TestContext,
log logging.Logger,
gatherer prometheus.Gatherer,
port uint64,
) string {
r := require.New(tb)
r := require.New(tc)

server, err := tests.NewPrometheusServerWithPort(gatherer, port)
r.NoError(err)
Expand All @@ -510,7 +529,7 @@ func startServer(
zap.String("url", fmt.Sprintf("http://%s/ext/metrics", server.Address())),
)

tb.Cleanup(func() {
tc.DeferCleanup(func() {
r.NoError(server.Stop())
})

Expand All @@ -520,17 +539,17 @@ func startServer(
// startCollector starts a Prometheus collector configured to scrape the server
// listening on serverAddr. startCollector also attaches the provided labels +
// Github labels if available to the collected metrics.
func startCollector(tb testing.TB, log logging.Logger, name string, labels map[string]string, serverAddr string) {
r := require.New(tb)
func startCollector(tc tests.TestContext, log logging.Logger, name string, labels map[string]string, serverAddr string) {
r := require.New(tc)

startPromCtx, cancel := context.WithTimeout(tb.Context(), tests.DefaultTimeout)
startPromCtx, cancel := context.WithTimeout(tc.GetDefaultContextParent(), tests.DefaultTimeout)
defer cancel()

logger := tests.NewDefaultLogger("prometheus")
r.NoError(tmpnet.StartPrometheus(startPromCtx, logger))

var sdConfigFilePath string
tb.Cleanup(func() {
tc.DeferCleanup(func() {
// Ensure a final metrics scrape.
// This default delay is set above the default scrape interval used by StartPrometheus.
time.Sleep(tmpnet.NetworkShutdownDelay)
Expand All @@ -543,10 +562,7 @@ func startCollector(tb testing.TB, log logging.Logger, name string, labels map[s
}(),
)

//nolint:usetesting // t.Context() is already canceled inside the cleanup function
checkMetricsCtx, cancel := context.WithTimeout(context.Background(), tests.DefaultTimeout)
defer cancel()
r.NoError(tmpnet.CheckMetricsExist(checkMetricsCtx, logger, networkUUID))
r.NoError(tmpnet.CheckMetricsExist(tc.DefaultContext(), logger, networkUUID))
})

sdConfigFilePath, err := tmpnet.WritePrometheusSDConfig(name, tmpnet.SDConfig{
Expand All @@ -569,6 +585,42 @@ func startCollector(tb testing.TB, log logging.Logger, name string, labels map[s
)
}

type benchmarkResult struct {
Name string `json:"name"`
Value string `json:"value"`
Unit string `json:"unit"`
}

type benchmarkTool struct {
name string
benchmarkResults []benchmarkResult
}

func newBenchmarkTool(name string) *benchmarkTool {
return &benchmarkTool{
name: name,
benchmarkResults: make([]benchmarkResult, 0),
}
}

func (b *benchmarkTool) addResult(value float64, unit string) {
result := benchmarkResult{
Name: b.name,
Value: strconv.FormatFloat(value, 'f', -1, 64),
Unit: unit,
}
b.benchmarkResults = append(b.benchmarkResults, result)
}

func (b *benchmarkTool) saveToFile(filePath string) error {
output, err := json.MarshalIndent(b.benchmarkResults, "", " ")
if err != nil {
return err
}

return os.WriteFile(filePath, output, perms.ReadWrite)
}

// parseCustomLabels parses a comma-separated list of key-value pairs into a map
// of custom labels.
func parseCustomLabels(labelsStr string) (map[string]string, error) {
Expand All @@ -586,13 +638,15 @@ func parseCustomLabels(labelsStr string) (map[string]string, error) {
return labels, nil
}

func getTopLevelMetrics(b *testing.B, registry prometheus.Gatherer, elapsed time.Duration) {
r := require.New(b)
func getTopLevelMetrics(tc tests.TestContext, tool *benchmarkTool, registry prometheus.Gatherer, elapsed time.Duration) {
r := require.New(tc)

gasUsed, err := getCounterMetricValue(registry, "avalanche_evm_eth_chain_block_gas_used_processed")
r.NoError(err)
mgasPerSecond := gasUsed / 1_000_000 / elapsed.Seconds()
b.ReportMetric(mgasPerSecond, "mgas/s")

tool.addResult(mgasPerSecond, "mgas/s")
tc.Log().Info("block processing", zap.Float64("mgas/s", mgasPerSecond))
}

func getCounterMetricValue(registry prometheus.Gatherer, query string) (float64, error) {
Expand Down
9 changes: 4 additions & 5 deletions tests/reexecute/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import (
"fmt"

"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require"

"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/database/leveldb"
"github.com/ava-labs/avalanchego/tests"
"github.com/ava-labs/avalanchego/utils/logging"
)

Expand All @@ -28,16 +28,15 @@ type BlockResult struct {
// Blocks are read sequentially and sent to the returned channel as BlockResult values.
//
// Any validation errors or iteration errors are sent as BlockResult with Err set, then the channel is closed.
func CreateBlockChanFromLevelDB(t require.TestingT, sourceDir string, startBlock, endBlock uint64, chanSize int, cleanup func(func())) (<-chan BlockResult, error) {
r := require.New(t)
func CreateBlockChanFromLevelDB(tc tests.TestContext, sourceDir string, startBlock, endBlock uint64, chanSize int) (<-chan BlockResult, error) {
ch := make(chan BlockResult, chanSize)

db, err := leveldb.New(sourceDir, nil, logging.NoLog{}, prometheus.NewRegistry())
if err != nil {
return nil, fmt.Errorf("failed to create leveldb database from %q: %w", sourceDir, err)
}
cleanup(func() {
r.NoError(db.Close())
tc.DeferCleanup(func() {
db.Close()
})

go func() {
Expand Down