From a957788426ff011acf662e29ec5fc0525c1a578f Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Tue, 27 Oct 2015 14:57:02 +0100 Subject: [PATCH] extracted congestion control into its own class --- src/client/client.cpp | 2 +- src/net/CongestionControl.hpp | 61 ++++++++++++ src/net/ConnectionHandler.hpp | 31 +----- src/net/net.cpp | 177 ++++++++++++++++++++-------------- src/ui/HUD.hpp | 4 +- src/ui/ui.cpp | 14 +-- 6 files changed, 179 insertions(+), 110 deletions(-) create mode 100644 src/net/CongestionControl.hpp diff --git a/src/client/client.cpp b/src/client/client.cpp index 3c30a62..0eec984 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -167,7 +167,7 @@ void InteractiveState::Update(int dt) { } hud.Display(res.block_types[player.GetInventorySlot() + 1]); if (stat_timer.Hit()) { - hud.UpdateNetStats(master); + hud.UpdateNetStats(master.NetStat()); } hud.Update(dt); diff --git a/src/net/CongestionControl.hpp b/src/net/CongestionControl.hpp new file mode 100644 index 0000000..73d1d85 --- /dev/null +++ b/src/net/CongestionControl.hpp @@ -0,0 +1,61 @@ +#ifndef BLANK_NET_CONGESTIONCONTROL_HPP_ +#define BLANK_NET_CONGESTIONCONTROL_HPP_ + +#include +#include + + +namespace blank { + +class CongestionControl { + +public: + CongestionControl(); + + /// packet loss as factor + float PacketLoss() const noexcept { return packet_loss; } + /// smooth average round trip time in milliseconds + float RoundTripTime() const noexcept { return rtt; } + /// estimated kilobytes transferred per second + float Upstream() const noexcept { return tx_kbps; } + /// estimated kilobytes received per second + float Downstream() const noexcept { return rx_kbps; } + + void PacketSent(std::uint16_t) noexcept; + void PacketLost(std::uint16_t) noexcept; + void PacketReceived(std::uint16_t) noexcept; + + void PacketIn(const UDPpacket &) noexcept; + void PacketOut(const UDPpacket &) noexcept; + +private: + void UpdatePacketLoss() noexcept; + void UpdateRTT(std::uint16_t) noexcept; + bool SamplePacket(std::uint16_t) const noexcept; + int HeadDiff(std::uint16_t) const noexcept; + void UpdateStats() noexcept; + +private: + const unsigned int packet_overhead; + const unsigned int sample_skip; + + unsigned int packets_lost; + unsigned int packets_received; + float packet_loss; + + Uint32 stamps[16]; + std::size_t stamp_cursor; + std::uint16_t stamp_last; + float rtt; + + Uint32 next_sample; + std::size_t tx_bytes; + std::size_t rx_bytes; + float tx_kbps; + float rx_kbps; + +}; + +} + +#endif diff --git a/src/net/ConnectionHandler.hpp b/src/net/ConnectionHandler.hpp index 76103fe..ff5e0e4 100644 --- a/src/net/ConnectionHandler.hpp +++ b/src/net/ConnectionHandler.hpp @@ -1,6 +1,7 @@ #ifndef BLANK_NET_CONNECTIONHANDLER_HPP_ #define BLANK_NET_CONNECTIONHANDLER_HPP_ +#include "CongestionControl.hpp" #include "Packet.hpp" #include @@ -13,14 +14,7 @@ class ConnectionHandler { public: ConnectionHandler(); - /// packet loss as factor - float PacketLoss() const noexcept { return packet_loss; } - /// smooth average round trip time in milliseconds - float RoundTripTime() const noexcept { return rtt; } - /// estimated kilobytes transferred per second - float Upstream() const noexcept { return tx_kbps; } - /// estimated kilobytes received per second - float Downstream() const noexcept { return rx_kbps; } + const CongestionControl &NetStat() const noexcept { return cc; } void PacketSent(std::uint16_t) noexcept; void PacketLost(std::uint16_t); @@ -34,12 +28,6 @@ public: virtual void OnTimeout() { } private: - void UpdatePacketLoss() noexcept; - void UpdateRTT(std::uint16_t) noexcept; - bool SamplePacket(std::uint16_t) const noexcept; - int HeadDiff(std::uint16_t) const noexcept; - void UpdateStats() noexcept; - // called as soon as the remote end ack'd given packet virtual void OnPacketReceived(std::uint16_t) { } // called if the remote end probably didn't get given packet @@ -60,20 +48,7 @@ private: virtual void On(const Packet::Message &) { } private: - unsigned int packets_lost; - unsigned int packets_received; - float packet_loss; - - Uint32 stamps[16]; - std::size_t stamp_cursor; - std::uint16_t stamp_last; - float rtt; - - Uint32 next_sample; - std::size_t tx_bytes; - std::size_t rx_bytes; - float tx_kbps; - float rx_kbps; + CongestionControl cc; }; diff --git a/src/net/net.cpp b/src/net/net.cpp index 0686d54..4de800e 100644 --- a/src/net/net.cpp +++ b/src/net/net.cpp @@ -1,3 +1,4 @@ +#include "CongestionControl.hpp" #include "Connection.hpp" #include "ConnectionHandler.hpp" #include "io.hpp" @@ -30,6 +31,102 @@ constexpr size_t Packet::BlockUpdate::MAX_LEN; constexpr size_t Packet::Message::MAX_LEN; constexpr size_t Packet::Message::MAX_MESSAGE_LEN; + +CongestionControl::CongestionControl() +// I know, I know, it's an estimate (about 20 for IPv4, 48 for IPv6) +: packet_overhead(20) +// only sample every eighth packet for measuring RTT +, sample_skip(8) +, packets_lost(0) +, packets_received(0) +, packet_loss(0.0f) +, stamp_cursor(15) +, stamp_last(0) +, rtt(64.0f) +, next_sample(1000) +, tx_bytes(0) +, rx_bytes(0) +, tx_kbps(0.0f) +, rx_kbps(0.0f) { + Uint32 now = SDL_GetTicks(); + for (Uint32 &s : stamps) { + s = now; + } + next_sample += now; +} + +void CongestionControl::PacketSent(uint16_t seq) noexcept { + if (!SamplePacket(seq)) { + return; + } + stamp_cursor = (stamp_cursor + 1) % 16; + stamps[stamp_cursor] = SDL_GetTicks(); + stamp_last = seq; +} + +void CongestionControl::PacketLost(uint16_t seq) noexcept { + ++packets_lost; + UpdatePacketLoss(); + UpdateRTT(seq); +} + +void CongestionControl::PacketReceived(uint16_t seq) noexcept { + ++packets_received; + UpdatePacketLoss(); + UpdateRTT(seq); +} + +void CongestionControl::UpdatePacketLoss() noexcept { + unsigned int packets_total = packets_lost + packets_received; + if (packets_total >= 256) { + packet_loss = float(packets_lost) / float(packets_total); + packets_lost = 0; + packets_received = 0; + } +} + +void CongestionControl::UpdateRTT(std::uint16_t seq) noexcept { + if (!SamplePacket(seq)) return; + int diff = HeadDiff(seq); + if (diff > 0 || diff < -15) { + // packet outside observed time frame + return; + } + int cur_rtt = SDL_GetTicks() - stamps[(stamp_cursor + diff + 16) % 16]; + rtt += (cur_rtt - rtt) * 0.1f; +} + +bool CongestionControl::SamplePacket(std::uint16_t seq) const noexcept { + return seq % sample_skip == 0; +} + +int CongestionControl::HeadDiff(std::uint16_t seq) const noexcept { + int16_t diff = int16_t(seq) - int16_t(stamp_last); + return diff / sample_skip; +} + +void CongestionControl::PacketIn(const UDPpacket &pack) noexcept { + rx_bytes += pack.len + packet_overhead; + UpdateStats(); +} + +void CongestionControl::PacketOut(const UDPpacket &pack) noexcept { + tx_bytes += pack.len + packet_overhead; + UpdateStats(); +} + +void CongestionControl::UpdateStats() noexcept { + Uint32 now = SDL_GetTicks(); + if (now >= next_sample) { + tx_kbps = float(tx_bytes) * (1.0f / 1024.0f); + rx_kbps = float(rx_bytes) * (1.0f / 1024.0f); + tx_bytes = 0; + rx_bytes = 0; + next_sample += 1000; + } +} + + Connection::Connection(const IPaddress &addr) : handler(nullptr) , addr(addr) @@ -155,96 +252,30 @@ uint16_t Connection::SendPing(UDPpacket &udp_pack, UDPsocket sock) { ConnectionHandler::ConnectionHandler() -: packets_lost(0) -, packets_received(0) -, packet_loss(0.0f) -, stamp_cursor(15) -, stamp_last(0) -, rtt(64.0f) -, next_sample(1000) -, tx_bytes(0) -, rx_bytes(0) -, tx_kbps(0.0f) -, rx_kbps(0.0f) { - Uint32 now = SDL_GetTicks(); - for (Uint32 &s : stamps) { - s = now; - } - next_sample += now; +: cc() { + } void ConnectionHandler::PacketSent(uint16_t seq) noexcept { - if (!SamplePacket(seq)) { - return; - } - stamp_cursor = (stamp_cursor + 1) % 16; - stamps[stamp_cursor] = SDL_GetTicks(); - stamp_last = seq; + cc.PacketSent(seq); } void ConnectionHandler::PacketLost(uint16_t seq) { OnPacketLost(seq); - ++packets_lost; - UpdatePacketLoss(); - UpdateRTT(seq); + cc.PacketLost(seq); } void ConnectionHandler::PacketReceived(uint16_t seq) { OnPacketReceived(seq); - ++packets_received; - UpdatePacketLoss(); - UpdateRTT(seq); -} - -void ConnectionHandler::UpdatePacketLoss() noexcept { - unsigned int packets_total = packets_lost + packets_received; - if (packets_total >= 256) { - packet_loss = float(packets_lost) / float(packets_total); - packets_lost = 0; - packets_received = 0; - } -} - -void ConnectionHandler::UpdateRTT(std::uint16_t seq) noexcept { - if (!SamplePacket(seq)) return; - int diff = HeadDiff(seq); - if (diff > 0 || diff < -15) { - // packet outside observed time frame - return; - } - int cur_rtt = SDL_GetTicks() - stamps[(stamp_cursor + diff + 16) % 16]; - rtt += (cur_rtt - rtt) * 0.1f; -} - -bool ConnectionHandler::SamplePacket(std::uint16_t seq) const noexcept { - // only sample every eighth packet - return seq % 8 == 0; -} - -int ConnectionHandler::HeadDiff(std::uint16_t seq) const noexcept { - int16_t diff = int16_t(seq) - int16_t(stamp_last); - return diff / 8; + cc.PacketReceived(seq); } void ConnectionHandler::PacketIn(const UDPpacket &pack) noexcept { - rx_bytes += pack.len + 20; // I know, I know, it's an estimate (about 48 for IPv6) - UpdateStats(); + cc.PacketIn(pack); } void ConnectionHandler::PacketOut(const UDPpacket &pack) noexcept { - tx_bytes += pack.len + 20; - UpdateStats(); -} - -void ConnectionHandler::UpdateStats() noexcept { - Uint32 now = SDL_GetTicks(); - if (now >= next_sample) { - tx_kbps = float(tx_bytes) * (1.0f / 1024.0f); - rx_kbps = float(rx_bytes) * (1.0f / 1024.0f); - tx_bytes = 0; - rx_bytes = 0; - next_sample += 1000; - } + cc.PacketOut(pack); } diff --git a/src/ui/HUD.hpp b/src/ui/HUD.hpp index b6ae7d7..b842da3 100644 --- a/src/ui/HUD.hpp +++ b/src/ui/HUD.hpp @@ -14,7 +14,7 @@ namespace blank { class Block; class BlockTypeRegistry; class Config; -class ConnectionHandler; +class CongestionControl; class Environment; class Font; class Player; @@ -44,7 +44,7 @@ public: void UpdateOrientation(); // net stats - void UpdateNetStats(const ConnectionHandler &); + void UpdateNetStats(const CongestionControl &); // message box void PostMessage(const char *); diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 6c7ab6a..8768095 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -17,7 +17,7 @@ #include "../graphics/Viewport.hpp" #include "../io/TokenStreamReader.hpp" #include "../model/bounds.hpp" -#include "../net/ConnectionHandler.hpp" +#include "../net/CongestionControl.hpp" #include "../world/BlockLookup.hpp" #include "../world/World.hpp" #include "../world/WorldManipulator.hpp" @@ -381,19 +381,21 @@ void HUD::PostMessage(const char *msg) { } -void HUD::UpdateNetStats(const ConnectionHandler &conn) { +void HUD::UpdateNetStats(const CongestionControl &stat) { + if (!config.video.debug) return; + std::stringstream s; s << std::fixed << std::setprecision(1) - << "TX: " << conn.Upstream() - << "KB/s, RX: " << conn.Downstream() << "KB/s"; + << "TX: " << stat.Upstream() + << "KB/s, RX: " << stat.Downstream() << "KB/s"; bandwidth_text.Set(env.assets.small_ui_font, s.str()); s.str(""); - s << "RTT: " << conn.RoundTripTime() << "ms"; + s << "RTT: " << stat.RoundTripTime() << "ms"; rtt_text.Set(env.assets.small_ui_font, s.str()); s.str(""); - s << "Packet loss: " << (conn.PacketLoss() * 100.0f) << "%"; + s << "Packet loss: " << (stat.PacketLoss() * 100.0f) << "%"; packet_loss_text.Set(env.assets.small_ui_font, s.str()); show_net = true; -- 2.39.2