From 1c920b461c20076074b98549e979cbada419da06 Mon Sep 17 00:00:00 2001 From: Collin Smith Date: Fri, 12 Jun 2020 15:51:56 -0700 Subject: [PATCH] Created profilers for ping and rtt metrics #77 Implemented averaging of network latency samples via NetworkProfiler NetworkProfiler handles the interfacing between Profiler plugin and Pinger system Created IntervalBaseSystem which is a copy of IntervalSystem without dependency on any Aspect Added support for a PacketListener for Pinger system (receives callbacks for received ping packets) --- .../riiablo/engine/IntervalBaseSystem.java | 35 ++++++++++++ .../engine/client/NetworkProfiler.java | 54 +++++++++++++++++++ .../src/com/riiablo/engine/client/Pinger.java | 32 ++++++++--- .../riiablo/screen/NetworkedGameScreen.java | 4 ++ 4 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 core/src/com/riiablo/engine/IntervalBaseSystem.java create mode 100644 core/src/com/riiablo/engine/client/NetworkProfiler.java diff --git a/core/src/com/riiablo/engine/IntervalBaseSystem.java b/core/src/com/riiablo/engine/IntervalBaseSystem.java new file mode 100644 index 00000000..9d033247 --- /dev/null +++ b/core/src/com/riiablo/engine/IntervalBaseSystem.java @@ -0,0 +1,35 @@ +package com.riiablo.engine; + +import com.artemis.BaseSystem; + +public abstract class IntervalBaseSystem extends BaseSystem { + private final float interval; + + protected float acc; + + private float delta; + + public IntervalBaseSystem(float interval) { + this.interval = interval; + } + + protected float getIntervalDelta() { + return interval + delta; + } + + protected float getTimeDelta() { + return world.getDelta(); + } + + @Override + protected boolean checkProcessing() { + acc += getTimeDelta(); + if (acc >= interval) { + acc -= interval; + delta = (acc - delta); + return true; + } + + return false; + } +} diff --git a/core/src/com/riiablo/engine/client/NetworkProfiler.java b/core/src/com/riiablo/engine/client/NetworkProfiler.java new file mode 100644 index 00000000..de085d36 --- /dev/null +++ b/core/src/com/riiablo/engine/client/NetworkProfiler.java @@ -0,0 +1,54 @@ +package com.riiablo.engine.client; + +import com.riiablo.Riiablo; +import com.riiablo.engine.IntervalBaseSystem; +import com.riiablo.net.packet.d2gs.Ping; +import com.riiablo.profiler.SystemProfiler; + +public class NetworkProfiler extends IntervalBaseSystem implements Pinger.PacketListener { + private static final String TAG = "NetworkProfiler"; + private static final boolean DEBUG = !true; + + /** + * Seconds to store samples -- averages will be taken of this time frame. + */ + private static final float SAMPLES_DURATION = 30; + + protected Pinger pinger; + + protected SystemProfiler pingProfiler; + protected SystemProfiler rttProfiler; + + private long ping; + private long rtt; + + public NetworkProfiler() { + super(SAMPLES_DURATION / SystemProfiler.SAMPLES); + } + + @Override + protected void initialize() { + pinger.addPacketListener(this); + + pingProfiler = SystemProfiler.create("Ping"); + pingProfiler.setColor(0, 1, 1, 1); + + rttProfiler = SystemProfiler.create("RTT"); + rttProfiler.setColor(1, 0, 1, 1); + } + + @Override + protected void processSystem() { + pingProfiler.sample(ping * 1000000); + Riiablo.metrics.ping = pingProfiler.getAverage() / 1000000; + + rttProfiler.sample(rtt * 1000000); + Riiablo.metrics.rtt = rttProfiler.getAverage() / 1000000; + } + + @Override + public void onPingResponse(Pinger pinger, Ping packet, long ping, long rtt) { + this.ping = ping; + this.rtt = rtt; + } +} diff --git a/core/src/com/riiablo/engine/client/Pinger.java b/core/src/com/riiablo/engine/client/Pinger.java index 61622f7b..a4edd8ca 100644 --- a/core/src/com/riiablo/engine/client/Pinger.java +++ b/core/src/com/riiablo/engine/client/Pinger.java @@ -5,24 +5,24 @@ import java.io.OutputStream; import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; -import com.artemis.annotations.All; import com.artemis.annotations.Wire; -import com.artemis.systems.IntervalSystem; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.net.Socket; +import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.TimeUtils; -import com.riiablo.Riiablo; +import com.riiablo.engine.IntervalBaseSystem; import com.riiablo.net.packet.d2gs.D2GS; import com.riiablo.net.packet.d2gs.D2GSData; import com.riiablo.net.packet.d2gs.Ping; -@All -public class Pinger extends IntervalSystem { +public class Pinger extends IntervalBaseSystem { private static final String TAG = "Pinger"; private static final boolean DEBUG = !true; + final Array packetListeners = new Array<>(false, 16); + @Wire(name = "client.socket") protected Socket socket; @@ -30,12 +30,14 @@ public class Pinger extends IntervalSystem { // it may be possible to use Gdx.graphics.getFrameId() -- but that isn't related to engine tick private int tick; + public long ping; + public long rtt; // TODO: provide a running average of past N RTTs // private final double deltas[] = new double[5]; // private int deltaCount; public Pinger() { - super(null, 1.0f); + super(1.0f); } @Override @@ -55,7 +57,21 @@ public class Pinger extends IntervalSystem { } public void Ping(Ping packet) { - Riiablo.metrics.ping = TimeUtils.millis() - packet.sendTime() - packet.processTime(); - Riiablo.metrics.rtt = TimeUtils.millis() - packet.sendTime(); + ping = TimeUtils.millis() - packet.sendTime() - packet.processTime(); + rtt = TimeUtils.millis() - packet.sendTime(); + notifyPing(packet, ping, rtt); + } + + public boolean addPacketListener(PacketListener l) { + packetListeners.add(l); + return true; + } + + private void notifyPing(Ping packet, long ping, long rtt) { + for (PacketListener l : packetListeners) l.onPingResponse(this, packet, ping, rtt); + } + + public interface PacketListener { + void onPingResponse(Pinger pinger, Ping packet, long ping, long rtt); } } diff --git a/core/src/com/riiablo/screen/NetworkedGameScreen.java b/core/src/com/riiablo/screen/NetworkedGameScreen.java index 20fc0652..6232af4c 100644 --- a/core/src/com/riiablo/screen/NetworkedGameScreen.java +++ b/core/src/com/riiablo/screen/NetworkedGameScreen.java @@ -1,9 +1,12 @@ package com.riiablo.screen; import com.artemis.WorldConfigurationBuilder; + import com.badlogic.gdx.net.Socket; + import com.riiablo.engine.client.ClientNetworkReceiver; import com.riiablo.engine.client.ClientNetworkSyncronizer; +import com.riiablo.engine.client.NetworkProfiler; import com.riiablo.engine.client.Pinger; import com.riiablo.save.CharData; @@ -24,6 +27,7 @@ public class NetworkedGameScreen extends GameScreen { builder.with(WorldConfigurationBuilder.Priority.HIGH, new ClientNetworkReceiver()); builder.with(new ClientNetworkSyncronizer()); builder.with(new Pinger()); + builder.with(new NetworkProfiler()); return builder; }