您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
325 行
14 KiB
325 行
14 KiB
using System.Collections.Generic;
|
|
using Unity.DebugDisplay;
|
|
using Unity.Sample.Core;
|
|
using UnityEngine;
|
|
using UnityEngine.Profiling;
|
|
|
|
public class NetworkStatisticsClient
|
|
{
|
|
public FloatRollingAverage rtt { get { return m_RTT; } }
|
|
|
|
public bool notifyHardCatchup; // Set to true to record hard catchup for this update
|
|
|
|
public NetworkStatisticsClient(NetworkClient networkClient)
|
|
{
|
|
m_NetworkClient = networkClient;
|
|
//for (var i = 0; i < m_PackageContentStatistics.Length; i++)
|
|
//m_PackageContentStatistics[i] = new int[(int)NetworkCompressionReader.Type._NumTypes];
|
|
}
|
|
|
|
public void Update(float frameTimeScale, float interpTime)
|
|
{
|
|
Profiler.BeginSample("NetworkStatisticsClient.Update");
|
|
|
|
var clientCounters = m_NetworkClient.counters;
|
|
|
|
// Grab package content stats into our circular buffer
|
|
//if (clientCounters != null && m_PackageContentStatisticsLastSequence < clientCounters.packageContentStatsPackageSequence)
|
|
//{
|
|
// m_PackageContentStatisticsLastSequence = clientCounters.packageContentStatsPackageSequence;
|
|
// var i = m_PackageContentStatisticsLastSequence % m_PackageContentStatistics.Length;
|
|
// var packStats = clientCounters.packageContentStats;
|
|
// if (packStats != null)
|
|
// packStats.CopyTo(m_PackageContentStatistics[i], 0);
|
|
//}
|
|
|
|
|
|
m_FrameTimeScale = frameTimeScale;
|
|
m_StatsDeltaTime.Update(Time.deltaTime);
|
|
|
|
m_HardCatchup.Add(notifyHardCatchup ? 100 : 0);
|
|
notifyHardCatchup = false;
|
|
|
|
m_ServerSimTime.Update(m_NetworkClient.serverSimTime);
|
|
|
|
m_BytesIn.Update(clientCounters != null ? clientCounters.bytesIn : 0);
|
|
m_PackagesIn.Update(clientCounters != null ? clientCounters.packagesIn : 0);
|
|
|
|
m_HeaderBitsIn.Update(clientCounters != null ? clientCounters.headerBitsIn : 0);
|
|
|
|
m_BytesOut.Update(clientCounters != null ? clientCounters.bytesOut : 0);
|
|
m_PackagesOut.Update(clientCounters != null ? clientCounters.packagesOut : 0);
|
|
|
|
m_Latency.Update(m_NetworkClient.timeSinceSnapshot);
|
|
m_RTT.Update(m_NetworkClient.rtt);
|
|
m_CMDQ.Update(m_NetworkClient.lastAcknowlegdedCommandTime - m_NetworkClient.serverTime);
|
|
m_Interp.Update(interpTime * 1000);
|
|
|
|
m_SnapshotsIn.Update(clientCounters != null ? clientCounters.snapshotsIn : 0);
|
|
m_CommandsOut.Update(clientCounters != null ? clientCounters.commandsOut : 0);
|
|
m_EventsIn.Update(clientCounters != null ? clientCounters.eventsIn : 0);
|
|
m_EventsOut.Update(clientCounters != null ? clientCounters.eventsOut : 0);
|
|
|
|
// Calculate package loss pct
|
|
if (clientCounters != null && Time.time > m_NextLossCalc)
|
|
{
|
|
m_NextLossCalc = Time.time + 0.2f;
|
|
|
|
var packagesIn = clientCounters.packagesIn - m_PackageCountPrevIn;
|
|
m_PackageCountPrevIn = clientCounters.packagesIn;
|
|
|
|
var loss = clientCounters.packagesLostIn - m_PackageLossPrevIn;
|
|
m_PackageLossPrevIn = clientCounters.packagesLostIn;
|
|
|
|
var totalIn = packagesIn + loss;
|
|
m_PackagesLostPctIn = totalIn != 0 ? loss * 100 / totalIn : 0;
|
|
|
|
var packagesOut = clientCounters.packagesOut - m_PackageCountPrevOut;
|
|
m_PackageCountPrevOut = clientCounters.packagesOut;
|
|
|
|
loss = clientCounters.packagesLostOut - m_PackageLossPrevOut;
|
|
m_PackageLossPrevOut = clientCounters.packagesLostOut;
|
|
|
|
var totalOut = packagesOut + loss;
|
|
m_PackagesLostPctOut = totalOut != 0 ? loss * 100 / totalOut : 0;
|
|
}
|
|
|
|
m_PackageLossPctIn.Update(m_PackagesLostPctIn);
|
|
m_PackageLossPctOut.Update(m_PackagesLostPctOut);
|
|
|
|
switch (NetworkConfig.netStats.IntValue)
|
|
{
|
|
case 1: DrawCompactStats(); break;
|
|
case 2: DrawStats(); break;
|
|
case 3: DrawCounters(); break;
|
|
case 4: DrawPackageStatistics(); break;
|
|
}
|
|
|
|
if (NetworkConfig.netPrintStats.IntValue > 0)
|
|
{
|
|
if (Time.frameCount % NetworkConfig.netPrintStats.IntValue == 0)
|
|
{
|
|
PrintStats();
|
|
}
|
|
}
|
|
|
|
// Pass on a few key stats to gamestatistics
|
|
if (Game.game.m_GameStatistics != null)
|
|
{
|
|
Game.game.m_GameStatistics.rtt = Mathf.RoundToInt(m_RTT.average);
|
|
}
|
|
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
void PrintStats()
|
|
{
|
|
GameDebug.Log("Network stats");
|
|
GameDebug.Log("=============");
|
|
GameDebug.Log("Tick rate : " + Game.serverTickRate.IntValue);
|
|
GameDebug.Log("clientID : " + m_NetworkClient.clientId);
|
|
GameDebug.Log("rtt : " + m_NetworkClient.rtt);
|
|
GameDebug.Log("LastPkgSeq: " + m_NetworkClient.counters.packageContentStatsPackageSequence);
|
|
GameDebug.Log("ServerTime: " + m_NetworkClient.serverTime);
|
|
Console.Write("-------------------");
|
|
}
|
|
|
|
float bitheight = 0.01f;
|
|
void DrawPackageStatistics()
|
|
{
|
|
float x = Overlay.Managed.CellsWide - 20;
|
|
float y = Overlay.Managed.CellsTall - 8;
|
|
float dx = 1.0f; // bar spacing
|
|
float w = 1.0f; // width of bars
|
|
int maxbits = 0;
|
|
var stats = m_NetworkClient.counters.packageContentStats;
|
|
var last = m_NetworkClient.counters.packagesIn;
|
|
for (var i = last; i > 0 && i > last - stats.Length; --i)
|
|
{
|
|
var s = stats[i % stats.Length];
|
|
if (s == null)
|
|
continue;
|
|
var barx = x + (i - last) * dx;
|
|
|
|
for (int j = 0, c = s.Count; j < c; ++j)
|
|
{
|
|
var stat = s[j];
|
|
DebugOverlay.DrawRect(barx, y - (stat.sectionStart + stat.sectionLength) * bitheight, w, stat.sectionLength * bitheight, stat.color);
|
|
}
|
|
|
|
var lastStat = s[s.Count - 1];
|
|
if (lastStat.sectionStart + lastStat.sectionLength > maxbits)
|
|
maxbits = lastStat.sectionStart + lastStat.sectionLength;
|
|
}
|
|
|
|
int maxbytes = (maxbits + 7) / 8;
|
|
int step = Mathf.Max(1, maxbytes >> 4) * 16;
|
|
for (var i = 0; i <= maxbytes; i += step)
|
|
{
|
|
Overlay.Managed.Write((int)(x - 4), (int)(y - i * 8 * bitheight - 0.5f), "{0:###}b", i);
|
|
}
|
|
|
|
bitheight = Mathf.Min(0.01f, 10.0f / maxbits);
|
|
}
|
|
|
|
void DrawCompactStats()
|
|
{
|
|
var samplesPerSecond = 1.0f / m_StatsDeltaTime.average;
|
|
|
|
Overlay.Managed.Write(-50, -4, "pps (in/out): {0} / {1}", m_PackagesIn.graph.average * samplesPerSecond, m_PackagesOut.graph.average * samplesPerSecond);
|
|
Overlay.Managed.Write(-50, -3, "bps (in/out): {0:00.0} / {1:00.0}", m_BytesIn.graph.average * samplesPerSecond, m_BytesOut.graph.average * samplesPerSecond);
|
|
var startIndex = m_BytesIn.graph.GetData().HeadIndex;
|
|
DebugOverlay.DrawHist(-50, -2, 20, 2, m_BytesIn.graph.GetData().GetArray(), startIndex, Color.blue, 5.0f);
|
|
}
|
|
|
|
void DrawStats()
|
|
{
|
|
var samplesPerSecond = 1.0f / m_StatsDeltaTime.average;
|
|
int y = 2;
|
|
Overlay.Managed.Write(2, y++, " tick rate: {0}", m_NetworkClient.serverTickRate);
|
|
Overlay.Managed.Write(2, y++, " frame timescale: {0}", m_FrameTimeScale);
|
|
|
|
Overlay.Managed.Write(2, y++, " sim : {0:0.0} / {1:0.0} / {2:0.0} ({3:0.0})",
|
|
m_ServerSimTime.min,
|
|
m_ServerSimTime.min,
|
|
m_ServerSimTime.max,
|
|
m_ServerSimTime.stdDeviation);
|
|
|
|
Overlay.Managed.Write(2, y++, "^FF0 lat : {0:0.0} / {1:0.0} / {2:0.0}", m_Latency.min, m_Latency.average, m_Latency.max);
|
|
Overlay.Managed.Write(2, y++, "^0FF rtt : {0:0.0} / {1:0.0} / {2:0.0}", m_RTT.min, m_RTT.average, m_RTT.max);
|
|
Overlay.Managed.Write(2, y++, "^0F0 cmdq : {0:0.0} / {1:0.0} / {2:0.0}", m_CMDQ.min, m_CMDQ.average, m_CMDQ.max);
|
|
Overlay.Managed.Write(2, y++, "^F0F intp : {0:0.0} / {1:0.0} / {2:0.0}", m_Interp.min, m_Interp.average, m_Interp.max);
|
|
|
|
|
|
y++;
|
|
Overlay.Managed.Write(2, y++, "^22F header/payload/total bps (in):");
|
|
Overlay.Managed.Write(2, y++, "^22F {0:00.0} / {1:00.0} / {2:00.0} ({3})", m_HeaderBitsIn.graph.average / 8.0f * samplesPerSecond,
|
|
(m_BytesIn.graph.average - m_HeaderBitsIn.graph.average / 8.0f) * samplesPerSecond,
|
|
m_BytesIn.graph.average * samplesPerSecond,
|
|
m_NetworkClient.clientConfig.serverUpdateRate);
|
|
Overlay.Managed.Write(2, y++, "^F00 bps (out): {0:00.0}", m_BytesOut.graph.average * samplesPerSecond);
|
|
Overlay.Managed.Write(2, y++, " pps (in): {0:00.0}", m_PackagesIn.graph.average * samplesPerSecond);
|
|
Overlay.Managed.Write(2, y++, " pps (out): {0:00.0}", m_PackagesOut.graph.average * samplesPerSecond);
|
|
Overlay.Managed.Write(2, y++, " pl% (in): {0:00.0}", m_PackageLossPctIn.average);
|
|
Overlay.Managed.Write(2, y++, " pl% (out): {0:00.0}", m_PackageLossPctOut.average);
|
|
|
|
y++;
|
|
Overlay.Managed.Write(2, y++, " upd_srate: {0:00.0} ({1})", m_SnapshotsIn.graph.average * samplesPerSecond, m_NetworkClient.clientConfig.serverUpdateInterval);
|
|
Overlay.Managed.Write(2, y++, " cmd_srate: {0:00.0} ({1})", m_CommandsOut.graph.average * samplesPerSecond, m_NetworkClient.serverTickRate);
|
|
Overlay.Managed.Write(2, y++, " ev (in): {0:00.0}", m_EventsIn.graph.average * samplesPerSecond);
|
|
Overlay.Managed.Write(2, y++, " ev (out): {0:00.0}", m_EventsOut.graph.average * samplesPerSecond);
|
|
|
|
var startIndex = m_BytesIn.graph.GetData().HeadIndex;
|
|
var graphY = 5;
|
|
|
|
DebugOverlay.DrawGraph(38, graphY, 60, 5, m_Latency.GetData().GetArray(), startIndex, Color.yellow, 100);
|
|
DebugOverlay.DrawGraph(38, graphY, 60, 5, m_RTT.GetData().GetArray(), startIndex, Color.cyan, 100);
|
|
DebugOverlay.DrawGraph(38, graphY, 60, 5, m_CMDQ.GetData().GetArray(), startIndex, Color.green, 10);
|
|
DebugOverlay.DrawGraph(38, graphY, 60, 5, m_Interp.GetData().GetArray(), startIndex, Color.magenta, 100);
|
|
DebugOverlay.DrawHist(38, graphY, 60, 5, m_HardCatchup.GetArray(), startIndex, Color.red, 100);
|
|
|
|
m_2GraphData[0] = m_BytesIn.graph.GetData().GetArray();
|
|
m_2GraphData[1] = m_BytesOut.graph.GetData().GetArray();
|
|
|
|
graphY += 7;
|
|
DebugOverlay.DrawGraph(38, graphY, 60, 5, m_2GraphData, startIndex, m_BytesGraphColors);
|
|
|
|
graphY += 6;
|
|
DebugOverlay.DrawHist(38, graphY++, 60, 1, m_SnapshotsIn.graph.GetData().GetArray(), startIndex, Color.blue, 5.0f);
|
|
DebugOverlay.DrawHist(38, graphY++, 60, 1, m_CommandsOut.graph.GetData().GetArray(), startIndex, Color.red, 5.0f);
|
|
DebugOverlay.DrawHist(38, graphY++, 60, 1, m_EventsIn.graph.GetData().GetArray(), startIndex, Color.yellow, 5.0f);
|
|
DebugOverlay.DrawHist(38, graphY++, 60, 1, m_EventsOut.graph.GetData().GetArray(), startIndex, Color.green, 5.0f);
|
|
}
|
|
|
|
void DrawCounters()
|
|
{
|
|
var counters = m_NetworkClient.counters;
|
|
if (counters == null)
|
|
return;
|
|
|
|
int y = 2;
|
|
Overlay.Managed.Write(2, y++, " Bytes in : {0}", counters.bytesIn);
|
|
Overlay.Managed.Write(2, y++, " Bytes out : {0}", counters.bytesOut);
|
|
Overlay.Managed.Write(2, y++, " Packages in : {0}", counters.packagesIn);
|
|
Overlay.Managed.Write(2, y++, " Packages out : {0}", counters.packagesOut);
|
|
|
|
y++;
|
|
Overlay.Managed.Write(2, y++, " Stale packages : {0}", counters.packagesStaleIn);
|
|
Overlay.Managed.Write(2, y++, " Duplicate packages : {0}", counters.packagesDuplicateIn);
|
|
Overlay.Managed.Write(2, y++, " Out of order packages : {0}", counters.packagesOutOfOrderIn);
|
|
|
|
y++;
|
|
Overlay.Managed.Write(2, y++, " Lost packages in : {0}", counters.packagesLostIn);
|
|
Overlay.Managed.Write(2, y++, " Lost packages out : {0}", counters.packagesLostOut);
|
|
|
|
y++;
|
|
Overlay.Managed.Write(2, y++, " Fragmented packages in : {0}", counters.fragmentedPackagesIn);
|
|
Overlay.Managed.Write(2, y++, " Fragmented packages out : {0}", counters.fragmentedPackagesOut);
|
|
|
|
Overlay.Managed.Write(2, y++, " Fragmented packages lost in : {0}", counters.fragmentedPackagesLostIn);
|
|
Overlay.Managed.Write(2, y++, " Fragmented packages lost out : {0}", counters.fragmentedPackagesLostOut);
|
|
|
|
y++;
|
|
Overlay.Managed.Write(2, y++, " Choked packages lost : {0}", counters.chokedPackagesOut);
|
|
}
|
|
|
|
float m_FrameTimeScale;
|
|
NetworkClient m_NetworkClient;
|
|
|
|
float[][] m_2GraphData = new float[2][];
|
|
Color[] m_BytesGraphColors = new Color[] { Color.blue, Color.red };
|
|
//int[][] m_PackageContentStatistics = new int[k_NumPackageContentStats][];
|
|
//int m_PackageContentStatisticsLastSequence;
|
|
|
|
float m_NextLossCalc;
|
|
|
|
float m_PackagesLostPctIn;
|
|
int m_PackageCountPrevIn;
|
|
int m_PackageLossPrevIn;
|
|
|
|
float m_PackagesLostPctOut;
|
|
int m_PackageCountPrevOut;
|
|
int m_PackageLossPrevOut;
|
|
|
|
const int k_WindowSize = 120;
|
|
const int k_NumPackageContentStats = 16;
|
|
|
|
class Aggregator
|
|
{
|
|
public float previousValue;
|
|
public FloatRollingAverage graph = new FloatRollingAverage(k_WindowSize);
|
|
|
|
public void Update(float value)
|
|
{
|
|
graph.Update(value - previousValue);
|
|
previousValue = value;
|
|
}
|
|
}
|
|
|
|
FloatRollingAverage m_StatsDeltaTime = new FloatRollingAverage(k_WindowSize);
|
|
|
|
FloatRollingAverage m_ServerSimTime = new FloatRollingAverage(k_WindowSize);
|
|
|
|
FloatRollingAverage m_Latency = new FloatRollingAverage(k_WindowSize);
|
|
FloatRollingAverage m_RTT = new FloatRollingAverage(k_WindowSize);
|
|
FloatRollingAverage m_CMDQ = new FloatRollingAverage(k_WindowSize);
|
|
FloatRollingAverage m_Interp = new FloatRollingAverage(k_WindowSize);
|
|
CircularList<float> m_HardCatchup = new CircularList<float>(k_WindowSize);
|
|
|
|
Aggregator m_BytesIn = new Aggregator();
|
|
Aggregator m_PackagesIn = new Aggregator();
|
|
|
|
Aggregator m_HeaderBitsIn = new Aggregator();
|
|
|
|
Aggregator m_SnapshotsIn = new Aggregator();
|
|
Aggregator m_EventsIn = new Aggregator();
|
|
|
|
Aggregator m_BytesOut = new Aggregator();
|
|
Aggregator m_PackagesOut = new Aggregator();
|
|
|
|
FloatRollingAverage m_PackageLossPctIn = new FloatRollingAverage(k_WindowSize);
|
|
FloatRollingAverage m_PackageLossPctOut = new FloatRollingAverage(k_WindowSize);
|
|
|
|
Aggregator m_CommandsOut = new Aggregator();
|
|
Aggregator m_EventsOut = new Aggregator();
|
|
}
|