mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-01-30 23:02:15 +00: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.
|
// Outstanding pings against this peer and how long the last one took to complete. Locked under the Peer lock.
|
||||||
private List<PendingPing> pendingPings;
|
private List<PendingPing> pendingPings;
|
||||||
private long lastPingTime;
|
private long[] lastPingTimes;
|
||||||
|
private static final int PING_MOVING_AVERAGE_WINDOW = 20;
|
||||||
|
|
||||||
private Channel channel;
|
private Channel channel;
|
||||||
private VersionMessage peerVersionMessage;
|
private VersionMessage peerVersionMessage;
|
||||||
@ -110,7 +111,7 @@ public class Peer {
|
|||||||
this.isAcked = false;
|
this.isAcked = false;
|
||||||
this.handler = new PeerHandler();
|
this.handler = new PeerHandler();
|
||||||
this.pendingPings = Lists.newLinkedList();
|
this.pendingPings = Lists.newLinkedList();
|
||||||
this.lastPingTime = Long.MAX_VALUE;
|
this.lastPingTimes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -775,15 +776,27 @@ public class Peer {
|
|||||||
public void complete() {
|
public void complete() {
|
||||||
Preconditions.checkNotNull(future, "Already completed");
|
Preconditions.checkNotNull(future, "Already completed");
|
||||||
Long elapsed = Long.valueOf(Utils.now().getTime() - startTimeMsec);
|
Long elapsed = Long.valueOf(Utils.now().getTime() - startTimeMsec);
|
||||||
synchronized (Peer.this) {
|
Peer.this.addPingTimeData(elapsed.longValue());
|
||||||
Peer.this.lastPingTime = elapsed.longValue();
|
|
||||||
}
|
|
||||||
log.debug("{}: ping time is {} msec", Peer.this.toString(), elapsed);
|
log.debug("{}: ping time is {} msec", Peer.this.toString(), elapsed);
|
||||||
future.set(elapsed);
|
future.set(elapsed);
|
||||||
future = null;
|
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.
|
* 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.
|
* 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}.
|
* been called or we did not hear back the "pong" message yet, returns {@link Long#MAX_VALUE}.
|
||||||
*/
|
*/
|
||||||
public long getLastPingTime() {
|
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) {
|
private void processPong(Pong m) {
|
||||||
|
@ -446,16 +446,28 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||||||
Utils.rollMockClock(0);
|
Utils.rollMockClock(0);
|
||||||
// No ping pong happened yet.
|
// No ping pong happened yet.
|
||||||
assertEquals(Long.MAX_VALUE, peer.getLastPingTime());
|
assertEquals(Long.MAX_VALUE, peer.getLastPingTime());
|
||||||
|
assertEquals(Long.MAX_VALUE, peer.getPingTime());
|
||||||
ListenableFuture<Long> future = peer.ping();
|
ListenableFuture<Long> future = peer.ping();
|
||||||
Ping pingMsg = (Ping) outbound();
|
Ping pingMsg = (Ping) outbound();
|
||||||
assertEquals(Long.MAX_VALUE, peer.getLastPingTime());
|
assertEquals(Long.MAX_VALUE, peer.getLastPingTime());
|
||||||
|
assertEquals(Long.MAX_VALUE, peer.getPingTime());
|
||||||
assertFalse(future.isDone());
|
assertFalse(future.isDone());
|
||||||
Utils.rollMockClock(5);
|
Utils.rollMockClock(5);
|
||||||
|
// The pong is returned.
|
||||||
inbound(peer, new Pong(pingMsg.getNonce()));
|
inbound(peer, new Pong(pingMsg.getNonce()));
|
||||||
assertTrue(future.isDone());
|
assertTrue(future.isDone());
|
||||||
long elapsed = future.get();
|
long elapsed = future.get();
|
||||||
assertTrue("" + elapsed, elapsed > 1000);
|
assertTrue("" + elapsed, elapsed > 1000);
|
||||||
assertEquals(elapsed, peer.getLastPingTime());
|
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() {
|
private Message outbound() {
|
||||||
|
@ -100,6 +100,7 @@ public class PeerMonitor {
|
|||||||
|
|
||||||
peerTableModel = new PeerTableModel();
|
peerTableModel = new PeerTableModel();
|
||||||
JTable peerTable = new JTable(peerTableModel);
|
JTable peerTable = new JTable(peerTableModel);
|
||||||
|
peerTable.setAutoCreateRowSorter(true);
|
||||||
JScrollPane scrollPane = new JScrollPane(peerTable);
|
JScrollPane scrollPane = new JScrollPane(peerTable);
|
||||||
window.getContentPane().add(scrollPane, BorderLayout.CENTER);
|
window.getContentPane().add(scrollPane, BorderLayout.CENTER);
|
||||||
window.pack();
|
window.pack();
|
||||||
@ -120,6 +121,7 @@ public class PeerMonitor {
|
|||||||
private final int USER_AGENT = 2;
|
private final int USER_AGENT = 2;
|
||||||
private final int CHAIN_HEIGHT = 3;
|
private final int CHAIN_HEIGHT = 3;
|
||||||
private final int PING_TIME = 4;
|
private final int PING_TIME = 4;
|
||||||
|
private final int LAST_PING_TIME = 5;
|
||||||
|
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
return peerGroup.numConnectedPeers();
|
return peerGroup.numConnectedPeers();
|
||||||
@ -132,13 +134,27 @@ public class PeerMonitor {
|
|||||||
case PROTOCOL_VERSION: return "Protocol version";
|
case PROTOCOL_VERSION: return "Protocol version";
|
||||||
case USER_AGENT: return "User Agent";
|
case USER_AGENT: return "User Agent";
|
||||||
case CHAIN_HEIGHT: return "Chain height";
|
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();
|
default: throw new RuntimeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getColumnCount() {
|
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) {
|
public Object getValueAt(int row, int col) {
|
||||||
@ -154,11 +170,12 @@ public class PeerMonitor {
|
|||||||
case CHAIN_HEIGHT:
|
case CHAIN_HEIGHT:
|
||||||
return peer.getBestHeight();
|
return peer.getBestHeight();
|
||||||
case PING_TIME:
|
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)
|
if (time == Long.MAX_VALUE)
|
||||||
return "";
|
return 0L;
|
||||||
else
|
else
|
||||||
return String.format("%d ms", time);
|
return time;
|
||||||
|
|
||||||
default: throw new RuntimeException();
|
default: throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user