diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index edd0eb4d95..a5947252cd 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -38,13 +38,12 @@ import ( ) var ( - MaxHashFetch = 512 // Amount of hashes to be fetched per retrieval request - MaxBlockFetch = 128 // Amount of blocks to be fetched per retrieval request - MaxHeaderFetch = 192 // Amount of block headers to be fetched per retrieval request - MaxSkeletonSize = 128 // Number of header fetches to need for a skeleton assembly - MaxBodyFetch = 128 // Amount of block bodies to be fetched per retrieval request - MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request - MaxStateFetch = 384 // Amount of node state values to allow fetching per request + MaxHashFetch = 512 // Amount of hashes to be fetched per retrieval request + MaxBlockFetch = 128 // Amount of blocks to be fetched per retrieval request + MaxHeaderFetch = 192 // Amount of block headers to be fetched per retrieval request + MaxSkeletonSize = 128 // Number of header fetches to need for a skeleton assembly + MaxReceiptFetch = 256 // Amount of transaction receipts to allow fetching per request + MaxStateFetch = 1024 // Amount of node state values to allow fetching per request rttMinEstimate = 2 * time.Second // Minimum round-trip time to target for download requests rttMaxEstimate = 20 * time.Second // Maximum round-trip time to target for download requests diff --git a/eth/downloader/metrics.go b/eth/downloader/metrics.go index d4eb337946..2c0190ecda 100644 --- a/eth/downloader/metrics.go +++ b/eth/downloader/metrics.go @@ -38,6 +38,9 @@ var ( receiptDropMeter = metrics.NewRegisteredMeter("eth/downloader/receipts/drop", nil) receiptTimeoutMeter = metrics.NewRegisteredMeter("eth/downloader/receipts/timeout", nil) - stateInMeter = metrics.NewRegisteredMeter("eth/downloader/states/in", nil) - stateDropMeter = metrics.NewRegisteredMeter("eth/downloader/states/drop", nil) + stateInMeter = metrics.NewRegisteredMeter("eth/downloader/states/in", nil) + stateReqTimer = metrics.NewRegisteredTimer("eth/download/state/req", nil) + stateDropMeter = metrics.NewRegisteredMeter("eth/downloader/states/drop", nil) + stateNodeSizeMeter = metrics.NewRegisteredMeter("eth/download/state/nodesize", nil) + stateRespSizeMeter = metrics.NewRegisteredMeter("eth/download/state/size", nil) ) diff --git a/eth/downloader/statesync.go b/eth/downloader/statesync.go index b422557d58..2e63969b46 100644 --- a/eth/downloader/statesync.go +++ b/eth/downloader/statesync.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/trie" "golang.org/x/crypto/sha3" ) @@ -41,6 +42,7 @@ type stateReq struct { peer *peerConnection // Peer that we're requesting from response [][]byte // Response data of the peer (nil for timeouts) dropped bool // Flag whether the peer dropped off early + sendAt time.Time // Time when the request was made } // timedOut returns if this request timed out. @@ -336,6 +338,10 @@ func (s *stateSync) loop() (err error) { return err } req.peer.SetNodeDataIdle(delivered) + // Trace average rtt of state request + if metrics.EnabledExpensive { + stateReqTimer.UpdateSince(req.sendAt) + } } } return nil @@ -375,6 +381,7 @@ func (s *stateSync) assignTasks() { req.peer.log.Trace("Requesting new batch of data", "type", "state", "count", len(req.items)) select { case s.d.trackStateReq <- req: + req.sendAt = time.Now() req.peer.FetchNodeData(req.items) case <-s.cancel: case <-s.d.cancelCh: @@ -428,6 +435,7 @@ func (s *stateSync) process(req *stateReq) (int, error) { }(time.Now()) // Iterate over all the delivered data and inject one-by-one into the trie + size := 0 for _, blob := range req.response { _, hash, err := s.processNodeData(blob) switch err { @@ -443,6 +451,12 @@ func (s *stateSync) process(req *stateReq) (int, error) { return successful, fmt.Errorf("invalid state node %s: %v", hash.TerminalString(), err) } delete(req.tasks, hash) + size += len(blob) + } + // Trace the average node size and total response size we receive + if metrics.EnabledExpensive && len(req.response) > 0 { + stateNodeSizeMeter.Mark(int64(size / len(req.response))) + stateRespSizeMeter.Mark(int64(size)) } // Put unfulfilled tasks back into the retry queue npeers := s.d.peers.Len() diff --git a/eth/handler.go b/eth/handler.go index 4ce2d1c82f..368ed2f6b8 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" @@ -584,6 +585,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { hash common.Hash bytes int data [][]byte + start = time.Now() + count int ) for bytes < softResponseLimit && len(data) < downloader.MaxStateFetch { // Retrieve the hash of the next state entry @@ -597,6 +600,11 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { data = append(data, entry) bytes += len(entry) } + count += 1 + } + // Trace the time cost for looking for a trie node in database. + if count > 0 && metrics.EnabledExpensive { + reqStateLookupTimer.Update(time.Duration(time.Since(start)) / time.Duration(count)) } return p.SendNodeData(data) diff --git a/eth/metrics.go b/eth/metrics.go index 0533a2a875..4a28f749f9 100644 --- a/eth/metrics.go +++ b/eth/metrics.go @@ -46,6 +46,7 @@ var ( reqStateInTrafficMeter = metrics.NewRegisteredMeter("eth/req/states/in/traffic", nil) reqStateOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/states/out/packets", nil) reqStateOutTrafficMeter = metrics.NewRegisteredMeter("eth/req/states/out/traffic", nil) + reqStateLookupTimer = metrics.NewRegisteredTimer("eth/req/states/out/lookup", nil) reqReceiptInPacketsMeter = metrics.NewRegisteredMeter("eth/req/receipts/in/packets", nil) reqReceiptInTrafficMeter = metrics.NewRegisteredMeter("eth/req/receipts/in/traffic", nil) reqReceiptOutPacketsMeter = metrics.NewRegisteredMeter("eth/req/receipts/out/packets", nil)