mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-01-18 13:22:42 +01:00
Implement calculation of a moving average of ping times. Improve PeerMonitor by making columns sortable.
This commit is contained in:
parent
3f89eda933
commit
26f63550be
@ -88,7 +88,8 @@ public class Peer {
|
||||
|
||||
// Outstanding pings against this peer and how long the last one took to complete. Locked under the Peer lock.
|
||||
private List<PendingPing> pendingPings;
|
||||
private long lastPingTime;
|
||||
private long[] lastPingTimes;
|
||||
private static final int PING_MOVING_AVERAGE_WINDOW = 20;
|
||||
|
||||
private Channel channel;
|
||||
private VersionMessage peerVersionMessage;
|
||||
@ -110,7 +111,7 @@ public class Peer {
|
||||
this.isAcked = false;
|
||||
this.handler = new PeerHandler();
|
||||
this.pendingPings = Lists.newLinkedList();
|
||||
this.lastPingTime = Long.MAX_VALUE;
|
||||
this.lastPingTimes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -775,15 +776,27 @@ public class Peer {
|
||||
public void complete() {
|
||||
Preconditions.checkNotNull(future, "Already completed");
|
||||
Long elapsed = Long.valueOf(Utils.now().getTime() - startTimeMsec);
|
||||
synchronized (Peer.this) {
|
||||
Peer.this.lastPingTime = elapsed.longValue();
|
||||
}
|
||||
Peer.this.addPingTimeData(elapsed.longValue());
|
||||
log.debug("{}: ping time is {} msec", Peer.this.toString(), elapsed);
|
||||
future.set(elapsed);
|
||||
future = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a ping time sample to the averaging window. */
|
||||
private synchronized void addPingTimeData(long sample) {
|
||||
if (lastPingTimes == null) {
|
||||
lastPingTimes = new long[PING_MOVING_AVERAGE_WINDOW];
|
||||
// Initialize the averaging window to the first sample.
|
||||
Arrays.fill(lastPingTimes, sample);
|
||||
} else {
|
||||
// Shift all elements backwards by one.
|
||||
System.arraycopy(lastPingTimes, 1, lastPingTimes, 0, lastPingTimes.length - 1);
|
||||
// And append the new sample to the end.
|
||||
lastPingTimes[lastPingTimes.length - 1] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the peer a ping message and returns a future that will be invoked when the pong is received back.
|
||||
* The future provides a number which is the number of milliseconds elapsed between the ping and the pong.
|
||||
@ -806,7 +819,22 @@ public class Peer {
|
||||
* been called or we did not hear back the "pong" message yet, returns {@link Long#MAX_VALUE}.
|
||||
*/
|
||||
public long getLastPingTime() {
|
||||
return lastPingTime;
|
||||
if (lastPingTimes == null)
|
||||
return Long.MAX_VALUE;
|
||||
return lastPingTimes[lastPingTimes.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a moving average of the last N ping/pong cycles. If {@link com.google.bitcoin.core.Peer#ping()} has never
|
||||
* been called or we did not hear back the "pong" message yet, returns {@link Long#MAX_VALUE}. The moving average
|
||||
* window is 5 buckets.
|
||||
*/
|
||||
public long getPingTime() {
|
||||
if (lastPingTimes == null)
|
||||
return Long.MAX_VALUE;
|
||||
long sum = 0;
|
||||
for (long i : lastPingTimes) sum += i;
|
||||
return (long)((double) sum / lastPingTimes.length);
|
||||
}
|
||||
|
||||
private void processPong(Pong m) {
|
||||
|
@ -446,16 +446,28 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
Utils.rollMockClock(0);
|
||||
// No ping pong happened yet.
|
||||
assertEquals(Long.MAX_VALUE, peer.getLastPingTime());
|
||||
assertEquals(Long.MAX_VALUE, peer.getPingTime());
|
||||
ListenableFuture<Long> future = peer.ping();
|
||||
Ping pingMsg = (Ping) outbound();
|
||||
assertEquals(Long.MAX_VALUE, peer.getLastPingTime());
|
||||
assertEquals(Long.MAX_VALUE, peer.getPingTime());
|
||||
assertFalse(future.isDone());
|
||||
Utils.rollMockClock(5);
|
||||
// The pong is returned.
|
||||
inbound(peer, new Pong(pingMsg.getNonce()));
|
||||
assertTrue(future.isDone());
|
||||
long elapsed = future.get();
|
||||
assertTrue("" + elapsed, elapsed > 1000);
|
||||
assertEquals(elapsed, peer.getLastPingTime());
|
||||
assertEquals(elapsed, peer.getPingTime());
|
||||
// Do it again and make sure it affects the average.
|
||||
future = peer.ping();
|
||||
outbound();
|
||||
Utils.rollMockClock(50);
|
||||
inbound(peer, new Pong(pingMsg.getNonce()));
|
||||
elapsed = future.get();
|
||||
assertEquals(elapsed, peer.getLastPingTime());
|
||||
assertEquals(14000, peer.getPingTime());
|
||||
}
|
||||
|
||||
private Message outbound() {
|
||||
|
@ -100,6 +100,7 @@ public class PeerMonitor {
|
||||
|
||||
peerTableModel = new PeerTableModel();
|
||||
JTable peerTable = new JTable(peerTableModel);
|
||||
peerTable.setAutoCreateRowSorter(true);
|
||||
JScrollPane scrollPane = new JScrollPane(peerTable);
|
||||
window.getContentPane().add(scrollPane, BorderLayout.CENTER);
|
||||
window.pack();
|
||||
@ -120,6 +121,7 @@ public class PeerMonitor {
|
||||
private final int USER_AGENT = 2;
|
||||
private final int CHAIN_HEIGHT = 3;
|
||||
private final int PING_TIME = 4;
|
||||
private final int LAST_PING_TIME = 5;
|
||||
|
||||
public int getRowCount() {
|
||||
return peerGroup.numConnectedPeers();
|
||||
@ -132,13 +134,27 @@ public class PeerMonitor {
|
||||
case PROTOCOL_VERSION: return "Protocol version";
|
||||
case USER_AGENT: return "User Agent";
|
||||
case CHAIN_HEIGHT: return "Chain height";
|
||||
case PING_TIME: return "Ping time";
|
||||
case PING_TIME: return "Average ping";
|
||||
case LAST_PING_TIME: return "Last ping";
|
||||
default: throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public int getColumnCount() {
|
||||
return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
public Class<?> getColumnClass(int column) {
|
||||
switch (column) {
|
||||
case PROTOCOL_VERSION:
|
||||
return Integer.class;
|
||||
case CHAIN_HEIGHT:
|
||||
case PING_TIME:
|
||||
case LAST_PING_TIME:
|
||||
return Long.class;
|
||||
default:
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
|
||||
public Object getValueAt(int row, int col) {
|
||||
@ -154,11 +170,12 @@ public class PeerMonitor {
|
||||
case CHAIN_HEIGHT:
|
||||
return peer.getBestHeight();
|
||||
case PING_TIME:
|
||||
long time = peer.getLastPingTime();
|
||||
case LAST_PING_TIME:
|
||||
long time = col == PING_TIME ? peer.getPingTime() : peer.getLastPingTime();
|
||||
if (time == Long.MAX_VALUE)
|
||||
return "";
|
||||
return 0L;
|
||||
else
|
||||
return String.format("%d ms", time);
|
||||
return time;
|
||||
|
||||
default: throw new RuntimeException();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user