cmd, core, metrics: support expensive optional metrics

This commit is contained in:
Péter Szilágyi 2019-03-25 09:45:50 +02:00
parent 32524efad6
commit 13d4adbbd9
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
6 changed files with 64 additions and 36 deletions

View file

@ -137,7 +137,6 @@ var (
utils.RPCCORSDomainFlag, utils.RPCCORSDomainFlag,
utils.RPCVirtualHostsFlag, utils.RPCVirtualHostsFlag,
utils.EthStatsURLFlag, utils.EthStatsURLFlag,
utils.MetricsEnabledFlag,
utils.FakePoWFlag, utils.FakePoWFlag,
utils.NoCompactionFlag, utils.NoCompactionFlag,
utils.GpoBlocksFlag, utils.GpoBlocksFlag,
@ -174,6 +173,8 @@ var (
} }
metricsFlags = []cli.Flag{ metricsFlags = []cli.Flag{
utils.MetricsEnabledFlag,
utils.MetricsEnabledExpensiveFlag,
utils.MetricsEnableInfluxDBFlag, utils.MetricsEnableInfluxDBFlag,
utils.MetricsInfluxDBEndpointFlag, utils.MetricsInfluxDBEndpointFlag,
utils.MetricsInfluxDBDatabaseFlag, utils.MetricsInfluxDBDatabaseFlag,

View file

@ -225,16 +225,8 @@ var AppHelpFlagGroups = []flagGroup{
}, debug.Flags...), }, debug.Flags...),
}, },
{ {
Name: "METRICS AND STATS", Name: "METRICS AND STATS",
Flags: []cli.Flag{ Flags: metricsFlags,
utils.MetricsEnabledFlag,
utils.MetricsEnableInfluxDBFlag,
utils.MetricsInfluxDBEndpointFlag,
utils.MetricsInfluxDBDatabaseFlag,
utils.MetricsInfluxDBUsernameFlag,
utils.MetricsInfluxDBPasswordFlag,
utils.MetricsInfluxDBTagsFlag,
},
}, },
{ {
Name: "WHISPER (EXPERIMENTAL)", Name: "WHISPER (EXPERIMENTAL)",

View file

@ -226,7 +226,7 @@ var (
} }
// Dashboard settings // Dashboard settings
DashboardEnabledFlag = cli.BoolFlag{ DashboardEnabledFlag = cli.BoolFlag{
Name: metrics.DashboardEnabledFlag, Name: "dashboard",
Usage: "Enable the dashboard", Usage: "Enable the dashboard",
} }
DashboardAddrFlag = cli.StringFlag{ DashboardAddrFlag = cli.StringFlag{
@ -644,9 +644,13 @@ var (
// Metrics flags // Metrics flags
MetricsEnabledFlag = cli.BoolFlag{ MetricsEnabledFlag = cli.BoolFlag{
Name: metrics.MetricsEnabledFlag, Name: "metrics",
Usage: "Enable metrics collection and reporting", Usage: "Enable metrics collection and reporting",
} }
MetricsEnabledExpensiveFlag = cli.BoolFlag{
Name: "metrics.expensive",
Usage: "Enable expensive metrics collection and reporting",
}
MetricsEnableInfluxDBFlag = cli.BoolFlag{ MetricsEnableInfluxDBFlag = cli.BoolFlag{
Name: "metrics.influxdb", Name: "metrics.influxdb",
Usage: "Enable metrics export/push to an external InfluxDB database", Usage: "Enable metrics export/push to an external InfluxDB database",

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -179,8 +180,9 @@ func (self *stateObject) GetCommittedState(db Database, key common.Hash) common.
return value return value
} }
// Track the amount of time wasted on reading the storge trie // Track the amount of time wasted on reading the storge trie
defer func(start time.Time) { self.db.StorageReads += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { self.db.StorageReads += time.Since(start) }(time.Now())
}
// Otherwise load the value from the database // Otherwise load the value from the database
enc, err := self.getTrie(db).TryGet(key[:]) enc, err := self.getTrie(db).TryGet(key[:])
if err != nil { if err != nil {
@ -221,8 +223,10 @@ func (self *stateObject) setState(key, value common.Hash) {
// updateTrie writes cached storage modifications into the object's storage trie. // updateTrie writes cached storage modifications into the object's storage trie.
func (self *stateObject) updateTrie(db Database) Trie { func (self *stateObject) updateTrie(db Database) Trie {
// Track the amount of time wasted on updating the storge trie // Track the amount of time wasted on updating the storge trie
defer func(start time.Time) { self.db.StorageUpdates += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { self.db.StorageUpdates += time.Since(start) }(time.Now())
}
// Update all the dirty slots in the trie
tr := self.getTrie(db) tr := self.getTrie(db)
for key, value := range self.dirtyStorage { for key, value := range self.dirtyStorage {
delete(self.dirtyStorage, key) delete(self.dirtyStorage, key)
@ -249,7 +253,9 @@ func (self *stateObject) updateRoot(db Database) {
self.updateTrie(db) self.updateTrie(db)
// Track the amount of time wasted on hashing the storge trie // Track the amount of time wasted on hashing the storge trie
defer func(start time.Time) { self.db.StorageHashes += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { self.db.StorageHashes += time.Since(start) }(time.Now())
}
self.data.Root = self.trie.Hash() self.data.Root = self.trie.Hash()
} }
@ -261,8 +267,9 @@ func (self *stateObject) CommitTrie(db Database) error {
return self.dbErr return self.dbErr
} }
// Track the amount of time wasted on committing the storge trie // Track the amount of time wasted on committing the storge trie
defer func(start time.Time) { self.db.StorageCommits += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { self.db.StorageCommits += time.Since(start) }(time.Now())
}
root, err := self.trie.Commit(nil) root, err := self.trie.Commit(nil)
if err == nil { if err == nil {
self.data.Root = root self.data.Root = root

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
@ -399,8 +400,9 @@ func (self *StateDB) Suicide(addr common.Address) bool {
// updateStateObject writes the given object to the trie. // updateStateObject writes the given object to the trie.
func (s *StateDB) updateStateObject(stateObject *stateObject) { func (s *StateDB) updateStateObject(stateObject *stateObject) {
// Track the amount of time wasted on updating the account from the trie // Track the amount of time wasted on updating the account from the trie
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
}
// Encode the account and update the account trie // Encode the account and update the account trie
addr := stateObject.Address() addr := stateObject.Address()
@ -414,8 +416,9 @@ func (s *StateDB) updateStateObject(stateObject *stateObject) {
// deleteStateObject removes the given object from the state trie. // deleteStateObject removes the given object from the state trie.
func (s *StateDB) deleteStateObject(stateObject *stateObject) { func (s *StateDB) deleteStateObject(stateObject *stateObject) {
// Track the amount of time wasted on deleting the account from the trie // Track the amount of time wasted on deleting the account from the trie
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
}
// Delete the account from the trie // Delete the account from the trie
stateObject.deleted = true stateObject.deleted = true
@ -433,8 +436,9 @@ func (s *StateDB) getStateObject(addr common.Address) (stateObject *stateObject)
return obj return obj
} }
// Track the amount of time wasted on loading the object from the database // Track the amount of time wasted on loading the object from the database
defer func(start time.Time) { s.AccountReads += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountReads += time.Since(start) }(time.Now())
}
// Load the object from the database // Load the object from the database
enc, err := s.trie.TryGet(addr[:]) enc, err := s.trie.TryGet(addr[:])
if len(enc) == 0 { if len(enc) == 0 {
@ -625,7 +629,9 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
s.Finalise(deleteEmptyObjects) s.Finalise(deleteEmptyObjects)
// Track the amount of time wasted on hashing the account trie // Track the amount of time wasted on hashing the account trie
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now())
}
return s.trie.Hash() return s.trie.Hash()
} }
@ -674,8 +680,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
delete(s.stateObjectsDirty, addr) delete(s.stateObjectsDirty, addr)
} }
// Write the account trie changes, measuing the amount of wasted time // Write the account trie changes, measuing the amount of wasted time
defer func(start time.Time) { s.AccountCommits += time.Since(start) }(time.Now()) if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountCommits += time.Since(start) }(time.Now())
}
root, err = s.trie.Commit(func(leaf []byte, parent common.Hash) error { root, err = s.trie.Commit(func(leaf []byte, parent common.Hash) error {
var account Account var account Account
if err := rlp.DecodeBytes(leaf, &account); err != nil { if err := rlp.DecodeBytes(leaf, &account); err != nil {

View file

@ -15,24 +15,41 @@ import (
) )
// Enabled is checked by the constructor functions for all of the // Enabled is checked by the constructor functions for all of the
// standard metrics. If it is true, the metric returned is a stub. // standard metrics. If it is true, the metric returned is a stub.
// //
// This global kill-switch helps quantify the observer effect and makes // This global kill-switch helps quantify the observer effect and makes
// for less cluttered pprof profiles. // for less cluttered pprof profiles.
var Enabled = false var Enabled = false
// MetricsEnabledFlag is the CLI flag name to use to enable metrics collections. // EnabledExpensive is a soft-flag meant for external packages to check if costly
const MetricsEnabledFlag = "metrics" // metrics gathering is allowed or not. The goal is to separate standard metrics
const DashboardEnabledFlag = "dashboard" // for health monitoring and debug metrics that might impact runtime performance.
var EnabledExpensive = false
// enablerFlags is the CLI flag names to use to enable metrics collections.
var enablerFlags = []string{"metrics", "dashboard"}
// expensiveEnablerFlags is the CLI flag names to use to enable metrics collections.
var expensiveEnablerFlags = []string{"metrics.expensive"}
// Init enables or disables the metrics system. Since we need this to run before // Init enables or disables the metrics system. Since we need this to run before
// any other code gets to create meters and timers, we'll actually do an ugly hack // any other code gets to create meters and timers, we'll actually do an ugly hack
// and peek into the command line args for the metrics flag. // and peek into the command line args for the metrics flag.
func init() { func init() {
for _, arg := range os.Args { for _, arg := range os.Args {
if flag := strings.TrimLeft(arg, "-"); flag == MetricsEnabledFlag || flag == DashboardEnabledFlag { flag := strings.TrimLeft(arg, "-")
log.Info("Enabling metrics collection")
Enabled = true for _, enabler := range enablerFlags {
if !Enabled && flag == enabler {
log.Info("Enabling metrics collection")
Enabled = true
}
}
for _, enabler := range expensiveEnablerFlags {
if !Enabled && flag == enabler {
log.Info("Enabling expensive metrics collection")
EnabledExpensive = true
}
} }
} }
} }