From 3c5a23b2c191c7cffa8c2e7bb53d5d6793f98e32 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 25 Jan 2017 18:20:55 -0800 Subject: [PATCH] peer: estimate RTT to peer using the ping and pong messages This commit enhances the peer struct slightly be attempting to measure the ping time to the remote node based on when we send a ping message an dhow long it takes for us to receive a pong response. The current method used to measure RTT is rather rough and could be make much more accurate via the usage of an EMA/WMA and also via attempting to measure processing time within the readMessage and writeMessage functions. --- peer.go | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/peer.go b/peer.go index 8bc8e956..745e94eb 100644 --- a/peer.go +++ b/peer.go @@ -76,6 +76,15 @@ type peer struct { inbound bool id int32 + // pingTime is a rough estimate of the RTT (round-trip-time) between us + // and the connected peer. This time is expressed in micro seconds. + // TODO(roasbeef): also use a WMA or EMA? + pingTime int64 + + // pingLastSend is the Unix time expressed in nanoseconds when we sent + // our last ping message. + pingLastSend int64 + // For purposes of detecting retransmits, etc. lastNMessages map[lnwire.Message]struct{} @@ -382,6 +391,15 @@ out: var targetChan *wire.OutPoint switch msg := nextMsg.(type) { + case *lnwire.Pong: + // When we receive a Pong message in response to our + // last ping message, we'll use the time in which we + // sent the ping message to measure a rough estimate of + // round trip time. + pingSendTime := atomic.LoadInt64(&p.pingLastSend) + delay := (time.Now().UnixNano() - pingSendTime) / 1000 + atomic.StoreInt64(&p.pingTime, delay) + case *lnwire.Ping: p.queueMsg(lnwire.NewPong(msg.Nonce), nil) @@ -531,16 +549,21 @@ out: for { select { case outMsg := <-p.sendQueue: - switch m := outMsg.msg.(type) { - // TODO(roasbeef): handle special write cases - } - if err := p.writeMessage(outMsg.msg); err != nil { - peerLog.Errorf("unable to write message: %v", err) + peerLog.Errorf("unable to write message: %v", + err) p.Disconnect() break out } + switch outMsg.msg.(type) { + case *lnwire.Ping: + // TODO(roasbeef): do this before the write? + // possibly account for processing within func? + now := time.Now().UnixNano() + atomic.StoreInt64(&p.pingLastSend, now) + } + // Synchronize with the writeHandler. p.sendQueueSync <- struct{}{} case <-p.quit: @@ -647,6 +670,11 @@ out: p.wg.Done() } +// PingTime returns the estimated ping time to the peer in microseconds. +func (p *peer) PingTime() int64 { + return atomic.LoadInt64(&p.pingTime) +} + // queueMsg queues a new lnwire.Message to be eventually sent out on the // wire. func (p *peer) queueMsg(msg lnwire.Message, doneChan chan struct{}) {