Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add metrics to simulator #706

Merged
merged 76 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
414a7cf
add tps
anusha-ctrl Jun 28, 2023
41f94ec
merge
anusha-ctrl Jun 28, 2023
c65a8e7
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jun 28, 2023
bf74d46
get block build metrics
anusha-ctrl Jun 28, 2023
0ed532e
Add issuance time, confirmed time, issued-> acceptance time, verify time
anusha-ctrl Jun 29, 2023
cedb3b0
Log times at end of batch
anusha-ctrl Jun 29, 2023
461c2c6
cleaner
anusha-ctrl Jun 29, 2023
750ed9f
address comments
anusha-ctrl Jun 29, 2023
5c521d7
remove unused code block
anusha-ctrl Jun 29, 2023
3655c66
avoids taking len of channel
darioush Jun 29, 2023
7b0f663
nits
darioush Jun 29, 2023
f225dfb
Merge pull request #707 from ava-labs/add-metrics-to-simulator0
anusha-ctrl Jun 29, 2023
be68d42
pass in stringID
anusha-ctrl Jun 29, 2023
173f847
move to loader
anusha-ctrl Jun 29, 2023
a3b6020
remove unused field
anusha-ctrl Jun 29, 2023
2fef11e
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jun 30, 2023
c8f3da5
revert file back
anusha-ctrl Jun 30, 2023
775e5e9
cleaner
anusha-ctrl Jun 30, 2023
ca504d3
lint
anusha-ctrl Jun 30, 2023
7395f60
make it work for ws or for rpc
anusha-ctrl Jun 30, 2023
c9b9604
protect
anusha-ctrl Jun 30, 2023
35480f8
endpoint
anusha-ctrl Jun 30, 2023
867b81e
no return on defer
anusha-ctrl Jun 30, 2023
4511cc5
sep to a funciton
anusha-ctrl Jun 30, 2023
616d9c8
have blockchainidstr passed in
anusha-ctrl Jun 30, 2023
131ab7d
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jun 30, 2023
5262218
typo
anusha-ctrl Jun 30, 2023
46d1208
pass in metrics through config
anusha-ctrl Jun 30, 2023
6666a59
address comments
anusha-ctrl Jun 30, 2023
c30bf85
address more comments and edit err policy of metrics functions
anusha-ctrl Jun 30, 2023
2048ffa
add more logging to load_test
anusha-ctrl Jun 30, 2023
99e6f27
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jun 30, 2023
d7d09ff
typo
anusha-ctrl Jun 30, 2023
875048e
better check
anusha-ctrl Jul 3, 2023
cce96a7
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jul 3, 2023
59a2d29
fix endpoints
anusha-ctrl Jul 3, 2023
b07cfa9
typo:
anusha-ctrl Jul 3, 2023
710a222
individual
anusha-ctrl Jul 4, 2023
d919724
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jul 6, 2023
63731b7
histogram
anusha-ctrl Jul 6, 2023
9821242
address feedback:
anusha-ctrl Jul 6, 2023
2ad7ad3
remove metrics from default
anusha-ctrl Jul 6, 2023
7856705
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jul 7, 2023
649daca
address comments
anusha-ctrl Jul 11, 2023
2ffda7a
simplify time metrics
anusha-ctrl Jul 11, 2023
e4fb332
better explanation
anusha-ctrl Jul 11, 2023
8849b75
address comments
anusha-ctrl Jul 19, 2023
8e7bbdc
address comments
anusha-ctrl Jul 19, 2023
f7d3850
cleanup
anusha-ctrl Jul 19, 2023
c81454e
more cleanup
anusha-ctrl Jul 19, 2023
2fb7c3b
rename vars for clarity
anusha-ctrl Jul 19, 2023
1773e13
ws
anusha-ctrl Jul 19, 2023
f3867e5
cleanup
anusha-ctrl Jul 19, 2023
3c4f54a
address comments
anusha-ctrl Jul 19, 2023
e918d4d
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jul 19, 2023
14e1d55
ws
anusha-ctrl Jul 19, 2023
ee390f5
expose metrics add flag
anusha-ctrl Jul 19, 2023
cc51ea9
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jul 19, 2023
2825310
fix blocking issue of http server and gracefully stop it
anusha-ctrl Jul 20, 2023
85cc2f8
cleanup
anusha-ctrl Jul 20, 2023
ea1e609
use constant
anusha-ctrl Jul 20, 2023
2651d76
add issuance to confirmation metrics
anusha-ctrl Jul 20, 2023
92bb91f
ws
anusha-ctrl Jul 20, 2023
aa464fb
Merge branch 'master' into add-metrics-to-simulator
aaronbuchwald Jul 26, 2023
c3d777b
simplify metrics server
anusha-ctrl Jul 26, 2023
d049a98
Bump avalanchego to v1.10.5 and bump Subnet-EVM for v0.5.3 release (#…
aaronbuchwald Jul 26, 2023
0fcf0d7
handle control c
anusha-ctrl Jul 27, 2023
ebe20cd
print out output
anusha-ctrl Jul 27, 2023
11d4295
clean up
anusha-ctrl Jul 27, 2023
33cbe16
clean up
anusha-ctrl Jul 27, 2023
5c80926
remove go routines to close client
anusha-ctrl Jul 27, 2023
710bed0
address comments
anusha-ctrl Jul 31, 2023
e1cf6c3
memory leak
anusha-ctrl Jul 31, 2023
8b87e94
fix
anusha-ctrl Jul 31, 2023
a2ff6f9
print
anusha-ctrl Jul 31, 2023
d26845c
Merge branch 'master' into add-metrics-to-simulator
anusha-ctrl Jul 31, 2023
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
6 changes: 5 additions & 1 deletion cmd/simulator/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/spf13/viper"
)

const Version = "v0.1.0"
const Version = "v0.1.1"

const (
ConfigFilePathKey = "config-file"
Expand All @@ -27,6 +27,7 @@ const (
VersionKey = "version"
TimeoutKey = "timeout"
BatchSizeKey = "batch-size"
MetricsPortKey = "metrics-port"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

)

var (
Expand All @@ -44,6 +45,7 @@ type Config struct {
KeyDir string `json:"key-dir"`
Timeout time.Duration `json:"timeout"`
BatchSize uint64 `json:"batch-size"`
MetricsPort uint64 `json:"metrics-port"`
}

func BuildConfig(v *viper.Viper) (Config, error) {
Expand All @@ -56,6 +58,7 @@ func BuildConfig(v *viper.Viper) (Config, error) {
KeyDir: v.GetString(KeyDirKey),
Timeout: v.GetDuration(TimeoutKey),
BatchSize: v.GetUint64(BatchSizeKey),
MetricsPort: v.GetUint64(MetricsPortKey),
}
if len(c.Endpoints) == 0 {
return c, ErrNoEndpoints
Expand Down Expand Up @@ -118,4 +121,5 @@ func addSimulatorFlags(fs *pflag.FlagSet) {
fs.Duration(TimeoutKey, 5*time.Minute, "Specify the timeout for the simulator to complete (0 indicates no timeout)")
fs.String(LogLevelKey, "info", "Specify the log level to use in the simulator")
fs.Uint64(BatchSizeKey, 100, "Specify the batchsize for the worker to issue and confirm txs")
fs.Uint64(MetricsPortKey, 8082, "Specify the port to use for the metrics server")
}
5 changes: 3 additions & 2 deletions cmd/simulator/load/funder.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"math/big"

"github.com/ava-labs/subnet-evm/cmd/simulator/key"
"github.com/ava-labs/subnet-evm/cmd/simulator/metrics"
"github.com/ava-labs/subnet-evm/cmd/simulator/txs"
"github.com/ava-labs/subnet-evm/core/types"
"github.com/ava-labs/subnet-evm/ethclient"
Expand All @@ -21,7 +22,7 @@ import (
// DistributeFunds ensures that each address in keys has at least [minFundsPerAddr] by sending funds
// from the key with the highest starting balance.
// This function returns a set of at least [numKeys] keys, each having a minimum balance [minFundsPerAddr].
func DistributeFunds(ctx context.Context, client ethclient.Client, keys []*key.Key, numKeys int, minFundsPerAddr *big.Int) ([]*key.Key, error) {
func DistributeFunds(ctx context.Context, client ethclient.Client, keys []*key.Key, numKeys int, minFundsPerAddr *big.Int, m *metrics.Metrics) ([]*key.Key, error) {
if len(keys) < numKeys {
return nil, fmt.Errorf("insufficient number of keys %d < %d", len(keys), numKeys)
}
Expand Down Expand Up @@ -107,7 +108,7 @@ func DistributeFunds(ctx context.Context, client ethclient.Client, keys []*key.K
return nil, fmt.Errorf("failed to generate fund distribution sequence from %s of length %d", maxFundsKey.Address, len(needFundsAddrs))
}
worker := NewSingleAddressTxWorker(ctx, client, maxFundsKey.Address)
txFunderAgent := txs.NewIssueNAgent[*types.Transaction](txSequence, worker, numTxs)
txFunderAgent := txs.NewIssueNAgent[*types.Transaction](txSequence, worker, numTxs, m)

if err := txFunderAgent.Execute(ctx); err != nil {
return nil, err
Expand Down
92 changes: 90 additions & 2 deletions cmd/simulator/load/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,36 @@ package load
import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"io/ioutil"
"math/big"
"net/http"
"os"
"os/signal"
"strconv"
"strings"
"syscall"

"github.com/ava-labs/subnet-evm/cmd/simulator/config"
"github.com/ava-labs/subnet-evm/cmd/simulator/key"
"github.com/ava-labs/subnet-evm/cmd/simulator/metrics"
"github.com/ava-labs/subnet-evm/cmd/simulator/txs"
"github.com/ava-labs/subnet-evm/core/types"
"github.com/ava-labs/subnet-evm/ethclient"
"github.com/ava-labs/subnet-evm/params"
"github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/sync/errgroup"
)

const (
MetricsEndpoint = "/metrics" // Endpoint for the Prometheus Metrics Server
)

// ExecuteLoader creates txSequences from [config] and has txAgents execute the specified simulation.
func ExecuteLoader(ctx context.Context, config config.Config) error {
if config.Timeout > 0 {
Expand All @@ -29,6 +44,24 @@ func ExecuteLoader(ctx context.Context, config config.Config) error {
defer cancel()
}

// Create buffered sigChan to receive SIGINT notifications
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT)

// Create context with cancel
ctx, cancel := context.WithCancel(ctx)

go func() {
// Blocks until we receive a SIGINT notification or if parent context is done
select {
case <-sigChan:
case <-ctx.Done():
}

// Cancel the child context and end all processes
cancel()
}()

// Construct the arguments for the load simulator
clients := make([]ethclient.Client, 0, len(config.Endpoints))
for i := 0; i < config.Workers; i++ {
Expand Down Expand Up @@ -62,8 +95,14 @@ func ExecuteLoader(ctx context.Context, config config.Config) error {
// to fund gas for all of their transactions.
maxFeeCap := new(big.Int).Mul(big.NewInt(params.GWei), big.NewInt(config.MaxFeeCap))
minFundsPerAddr := new(big.Int).Mul(maxFeeCap, big.NewInt(int64(config.TxsPerWorker*params.TxGas)))

// Create metrics
reg := prometheus.NewRegistry()
m := metrics.NewMetrics(reg)
metricsPort := strconv.Itoa(int(config.MetricsPort))

log.Info("Distributing funds", "numTxsPerWorker", config.TxsPerWorker, "minFunds", minFundsPerAddr)
keys, err = DistributeFunds(ctx, clients[0], keys, config.Workers, minFundsPerAddr)
keys, err = DistributeFunds(ctx, clients[0], keys, config.Workers, minFundsPerAddr, m)
if err != nil {
return err
}
Expand Down Expand Up @@ -112,7 +151,7 @@ func ExecuteLoader(ctx context.Context, config config.Config) error {
log.Info("Constructing tx agents...", "numAgents", config.Workers)
agents := make([]txs.Agent[*types.Transaction], 0, config.Workers)
for i := 0; i < config.Workers; i++ {
agents = append(agents, txs.NewIssueNAgent[*types.Transaction](txSequences[i], NewSingleAddressTxWorker(ctx, clients[i], senders[i]), config.BatchSize))
agents = append(agents, txs.NewIssueNAgent[*types.Transaction](txSequences[i], NewSingleAddressTxWorker(ctx, clients[i], senders[i]), config.BatchSize, m))
}

log.Info("Starting tx agents...")
Expand All @@ -124,10 +163,59 @@ func ExecuteLoader(ctx context.Context, config config.Config) error {
})
}

go startMetricsServer(ctx, metricsPort, reg)

log.Info("Waiting for tx agents...")
if err := eg.Wait(); err != nil {
return err
}
log.Info("Tx agents completed successfully.")

printOutputFromMetricsServer(metricsPort)
return nil
}

func startMetricsServer(ctx context.Context, metricsPort string, reg *prometheus.Registry) {
// Create a prometheus server to expose individual tx metrics
server := &http.Server{
Addr: fmt.Sprintf(":%s", metricsPort),
}

// Start up go routine to listen for SIGINT notifications to gracefully shut down server
go func() {
// Blocks until signal is received
<-ctx.Done()

if err := server.Shutdown(ctx); err != nil {
log.Error("Metrics server error: %v", err)
}
log.Info("Received a SIGINT signal: Gracefully shutting down metrics server")
}()

// Start metrics server
http.Handle(MetricsEndpoint, promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}))
log.Info(fmt.Sprintf("Metrics Server: localhost:%s%s", metricsPort, MetricsEndpoint))
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
log.Error("Metrics server error: %v", err)
}
}

func printOutputFromMetricsServer(metricsPort string) {
// Get response from server
resp, err := http.Get(fmt.Sprintf("http://localhost:%s%s", metricsPort, MetricsEndpoint))
if err != nil {
log.Error("cannot get response from metrics servers", "err", err)
return
}
// Read response body
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Error("cannot read response body", "err", err)
return
}
// Print out formatted individual metrics
parts := strings.Split(string(respBody), "\n")
for _, s := range parts {
fmt.Printf(" \t\t\t%s\n", s)
}
}
42 changes: 42 additions & 0 deletions cmd/simulator/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// (c) 2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package metrics
aaronbuchwald marked this conversation as resolved.
Show resolved Hide resolved

import (
"github.com/prometheus/client_golang/prometheus"
)

type Metrics struct {
// Summary of the quantiles of Individual Issuance Tx Times
IssuanceTxTimes prometheus.Summary
// Summary of the quantiles of Individual Confirmation Tx Times
ConfirmationTxTimes prometheus.Summary
// Summary of the quantiles of Individual Issuance To Confirmation Tx Times
IssuanceToConfirmationTxTimes prometheus.Summary
}

// NewMetrics creates and returns a Metrics and registers it with a Collector
func NewMetrics(reg prometheus.Registerer) *Metrics {
m := &Metrics{
IssuanceTxTimes: prometheus.NewSummary(prometheus.SummaryOpts{
Name: "tx_issuance_time",
Help: "Individual Tx Issuance Times for a Load Test",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
}),
ConfirmationTxTimes: prometheus.NewSummary(prometheus.SummaryOpts{
Name: "tx_confirmation_time",
Help: "Individual Tx Confirmation Times for a Load Test",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
}),
IssuanceToConfirmationTxTimes: prometheus.NewSummary(prometheus.SummaryOpts{
Name: "tx_issuance_to_confirmation_time",
Help: "Individual Tx Issuance To Confirmation Times for a Load Test",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
}),
}
reg.MustRegister(m.IssuanceTxTimes)
reg.MustRegister(m.ConfirmationTxTimes)
reg.MustRegister(m.IssuanceToConfirmationTxTimes)
return m
}
Loading
Loading