diff --git a/tests/reexecute/c/metrics.go b/tests/reexecute/c/metrics.go new file mode 100644 index 000000000000..94906761f152 --- /dev/null +++ b/tests/reexecute/c/metrics.go @@ -0,0 +1,105 @@ +// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package vm + +import ( + "fmt" + "testing" + "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" +) + +type metricKind uint + +const ( + counter metricKind = iota + 1 + gauge +) + +var ( + gasMetric = topLevelMetric{ + name: "gas", + query: "avalanche_evm_eth_chain_block_gas_used_processed", + kind: counter, + } + meterVMMetrics = []topLevelMetric{ + { + name: "block_parse", + query: "avalanche_meterchainvm_parse_block_sum", + kind: gauge, + }, + { + name: "block_verify", + query: "avalanche_meterchainvm_verify_sum", + kind: gauge, + }, + { + name: "block_accept", + query: "avalanche_meterchainvm_accept_sum", + kind: gauge, + }, + } +) + +func getMetricValue(registry prometheus.Gatherer, metric topLevelMetric) (float64, error) { + metricFamilies, err := registry.Gather() + if err != nil { + return 0, fmt.Errorf("failed to gather metrics: %w", err) + } + + query := metric.query + for _, mf := range metricFamilies { + switch metric.kind { + case counter: + if mf.GetName() == query { + return mf.GetMetric()[0].Counter.GetValue(), nil + } + case gauge: + if mf.GetName() == query { + return mf.GetMetric()[0].Gauge.GetValue(), nil + } + default: + return 0, fmt.Errorf("metric type unknown: %d", metric.kind) + } + } + + return 0, fmt.Errorf("metric %s not found", query) +} + +type topLevelMetric struct { + name string + query string + kind metricKind +} + +func getTopLevelMetrics(b *testing.B, registry prometheus.Gatherer, elapsed time.Duration) { + r := require.New(b) + + totalGas, err := getMetricValue(registry, gasMetric) + r.NoError(err) + r.NotZero(totalGas, "denominator metric %q has value 0", gasMetric.name) + + var ( + mgas float64 = 1_000_000 + ggas float64 = 1_000_000_000 + nsPerMs float64 = 1_000_000 + ) + + mgasPerSecond := (totalGas / mgas) / elapsed.Seconds() + b.ReportMetric(mgasPerSecond, "mgas/s") + + totalGGas := totalGas / ggas + msPerGGas := (float64(elapsed) / nsPerMs) / totalGGas + b.ReportMetric(msPerGGas, "ms/ggas") + + for _, metric := range meterVMMetrics { + metricVal, err := getMetricValue(registry, metric) + r.NoError(err) + + metricValMS := (metricVal / nsPerMs) / totalGGas + b.ReportMetric(metricValMS, metric.name+"_ms/ggas") + } +} diff --git a/tests/reexecute/c/vm_reexecute_test.go b/tests/reexecute/c/vm_reexecute_test.go index 9738c1bc38aa..e64835c70eca 100644 --- a/tests/reexecute/c/vm_reexecute_test.go +++ b/tests/reexecute/c/vm_reexecute_test.go @@ -42,6 +42,7 @@ import ( "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/timer" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/metervm" "github.com/ava-labs/avalanchego/vms/platformvm/warp" ) @@ -171,6 +172,9 @@ func benchmarkReexecuteRange( vmMultiGatherer := metrics.NewPrefixGatherer() r.NoError(prefixGatherer.Register("avalanche_evm", vmMultiGatherer)) + meterVMRegistry := prometheus.NewRegistry() + r.NoError(prefixGatherer.Register("avalanche_meterchainvm", meterVMRegistry)) + // consensusRegistry includes the chain="C" label and the prefix "avalanche_snowman". // The consensus registry is passed to the executor to mimic a subset of consensus metrics. consensusRegistry := prometheus.NewRegistry() @@ -214,6 +218,7 @@ func benchmarkReexecuteRange( chainDataDir, configBytes, vmMultiGatherer, + meterVMRegistry, ) r.NoError(err) defer func() { @@ -244,7 +249,8 @@ func newMainnetCChainVM( vmAndSharedMemoryDB database.Database, chainDataDir string, configBytes []byte, - metricsGatherer metrics.MultiGatherer, + vmMultiGatherer metrics.MultiGatherer, + meterVMRegistry prometheus.Registerer, ) (block.ChainVM, error) { factory := factory.Factory{} vmIntf, err := factory.New(logging.NoLog{}) @@ -272,6 +278,8 @@ func newMainnetCChainVM( ids.Empty: constants.PrimaryNetworkID, } + vm = metervm.NewBlockVM(vm, meterVMRegistry) + if err := vm.Initialize( ctx, &snow.Context{ @@ -289,7 +297,7 @@ func newMainnetCChainVM( Log: tests.NewDefaultLogger("mainnet-vm-reexecution"), SharedMemory: atomicMemory.NewSharedMemory(mainnetCChainID), BCLookup: ids.NewAliaser(), - Metrics: metricsGatherer, + Metrics: vmMultiGatherer, WarpSigner: warpSigner, @@ -600,27 +608,3 @@ 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) - - 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") -} - -func getCounterMetricValue(registry prometheus.Gatherer, query string) (float64, error) { - metricFamilies, err := registry.Gather() - if err != nil { - return 0, fmt.Errorf("failed to gather metrics: %w", err) - } - - for _, mf := range metricFamilies { - if mf.GetName() == query { - return mf.GetMetric()[0].Counter.GetValue(), nil - } - } - - return 0, fmt.Errorf("metric %s not found", query) -}