Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 additions and 0 deletions

View file

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace MLAPI.Profiling
{
public interface ITransportProfilerData
{
void BeginNewTick();
IReadOnlyDictionary<string, int> GetTransportProfilerData();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c016323c9d0c4e8990d946f8f3d6ce2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,142 @@
using System.Collections.Generic;
using MLAPI.Collections;
using MLAPI.Configuration;
using MLAPI.Transports;
using UnityEngine;
namespace MLAPI.Profiling
{
/// <summary>
/// NetworkProfiler for profiling network traffic
/// </summary>
public static class NetworkProfiler
{
/// <summary>
/// The ticks that has been recorded
/// </summary>
public static FixedQueue<ProfilerTick> Ticks { get; private set; }
/// <summary>
/// Whether or not the profiler is recording data
/// </summary>
public static bool IsRunning { get; private set; }
private static int s_TickHistory = 1024;
private static int s_EventIdCounter = 0;
private static ProfilerTick s_CurrentTick;
/// <summary>
/// Starts recording data for the Profiler
/// </summary>
/// <param name="historyLength">The amount of ticks to keep in memory</param>
public static void Start(int historyLength)
{
if (IsRunning) return;
s_EventIdCounter = 0;
Ticks = new FixedQueue<ProfilerTick>(historyLength);
s_TickHistory = historyLength;
s_CurrentTick = null;
IsRunning = true;
}
/// <summary>
/// Stops recording data
/// </summary>
public static void Stop()
{
Ticks = null; //leave to GC
s_CurrentTick = null; //leave to GC
IsRunning = false;
}
/// <summary>
/// Stops recording data and fills the buffer with the recorded ticks and returns the length;
/// </summary>
/// <param name="tickBuffer">The buffer to fill with the ticks</param>
/// <returns>The number of ticks recorded</returns>
public static int Stop(ref ProfilerTick[] tickBuffer)
{
if (!IsRunning) return 0;
int iteration = Ticks.Count > tickBuffer.Length ? tickBuffer.Length : Ticks.Count;
for (int i = 0; i < iteration; i++) tickBuffer[i] = Ticks[i];
Ticks = null; //leave to GC
s_CurrentTick = null; //leave to GC
IsRunning = false;
return iteration;
}
/// <summary>
/// Stops recording data and fills the buffer with the recorded ticks and returns the length;
/// </summary>
/// <param name="tickBuffer">The buffer to fill with the ticks</param>
/// <returns>The number of ticks recorded</returns>
public static int Stop(ref List<ProfilerTick> tickBuffer)
{
if (!IsRunning) return 0;
int iteration = Ticks.Count > tickBuffer.Count ? tickBuffer.Count : Ticks.Count;
for (int i = 0; i < iteration; i++) tickBuffer[i] = Ticks[i];
Ticks = null; //leave to GC
s_CurrentTick = null; //leave to GC
IsRunning = false;
return iteration;
}
internal static void StartTick(TickType type)
{
if (!IsRunning) return;
if (Ticks.Count == s_TickHistory)
{
Ticks.Dequeue();
}
var tick = new ProfilerTick()
{
Type = type,
Frame = Time.frameCount,
EventId = s_EventIdCounter
};
s_EventIdCounter++;
Ticks.Enqueue(tick);
s_CurrentTick = tick;
}
internal static void EndTick()
{
if (!IsRunning) return;
if (s_CurrentTick == null) return;
s_CurrentTick = null;
}
internal static void StartEvent(TickType eventType, uint bytes, NetworkChannel networkChannel, byte messageType)
{
if (!IsRunning) return;
if (s_CurrentTick == null) return;
string messageName = messageType < NetworkConstants.MESSAGE_NAMES.Length ? NetworkConstants.MESSAGE_NAMES[messageType] : "INVALID_MESSAGE_TYPE";
string channelName = networkChannel.ToString();
s_CurrentTick.StartEvent(eventType, bytes, channelName, messageName);
}
internal static void StartEvent(TickType eventType, uint bytes, NetworkChannel networkChannel, string messageName)
{
if (!IsRunning) return;
if (s_CurrentTick == null) return;
string channelName = networkChannel.ToString();
s_CurrentTick.StartEvent(eventType, bytes, channelName, messageName);
}
internal static void EndEvent()
{
if (!IsRunning) return;
if (s_CurrentTick == null) return;
s_CurrentTick.EndEvent();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1009676d0b4d5ea4ba2a8532b573ad32
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
namespace MLAPI.Profiling
{
internal static class PerformanceDataManager
{
private static PerformanceTickData s_ProfilerData = new PerformanceTickData();
private static int s_TickId;
internal static void BeginNewTick()
{
s_TickId = Math.Max(s_TickId, 0);
s_ProfilerData.Reset();
s_ProfilerData.TickId = s_TickId++;
}
internal static void Increment(string fieldName, int count = 1)
{
s_ProfilerData.Increment(fieldName, count);
}
internal static void AddTransportData(IReadOnlyDictionary<string, int> transportProfilerData)
{
s_ProfilerData.AddNonDuplicateData(transportProfilerData);
}
internal static PerformanceTickData GetData()
{
return s_ProfilerData;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 09fbe4f2c41c841b0a93d9ddea3c8413
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Linq;
namespace MLAPI.Profiling
{
public class PerformanceTickData
{
public int TickId;
private readonly ProfilingDataStore m_TickData = new ProfilingDataStore();
public void Increment(string fieldName, int count = 1)
{
m_TickData.Increment(fieldName, count);
}
public void AddNonDuplicateData(IReadOnlyDictionary<string, int> transportProfilerData)
{
foreach (var entry in transportProfilerData)
{
if (m_TickData.HasData(entry.Key))
{
continue;
}
m_TickData.Add(entry.Key, entry.Value);
}
}
public int GetData(string fieldName)
{
return m_TickData.GetData(fieldName);
}
public bool HasData(string fieldName)
{
return m_TickData.HasData(fieldName);
}
public void Reset()
{
m_TickData.Clear();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f4b98642f26d4f599a78409be2af56e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,24 @@
namespace MLAPI.Profiling
{
public static class ProfilerConstants
{
public const string Connections = nameof(Connections);
public const string ReceiveTickRate = nameof(ReceiveTickRate);
public const string NamedMessageReceived = nameof(NamedMessageReceived);
public const string UnnamedMessageReceived = nameof(UnnamedMessageReceived);
public const string NamedMessageSent = nameof(NamedMessageSent);
public const string UnnamedMessageSent = nameof(UnnamedMessageSent);
public const string ByteSent = nameof(ByteSent);
public const string ByteReceived = nameof(ByteReceived);
public const string NetworkVarDeltas = nameof(NetworkVarDeltas);
public const string NetworkVarUpdates = nameof(NetworkVarUpdates);
public const string RpcSent = nameof(RpcSent);
public const string RpcReceived = nameof(RpcReceived);
public const string RpcBatchesSent = nameof(RpcBatchesSent);
public const string RpcBatchesReceived = nameof(RpcBatchesReceived);
public const string RpcQueueProcessed = nameof(RpcQueueProcessed);
public const string RpcInQueueSize = nameof(RpcInQueueSize);
public const string RpcOutQueueSize = nameof(RpcOutQueueSize);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9a98852a5495e4a3aa515f0b5903847a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,36 @@
using System;
#if UNITY_2020_2_OR_NEWER
using Unity.Profiling.LowLevel;
#endif
namespace MLAPI.Profiling
{
internal struct ProfilerCounterUtility
{
#if UNITY_2020_2_OR_NEWER && ENABLE_PROFILER
public static byte GetProfilerMarkerDataType<T>()
{
switch (Type.GetTypeCode(typeof(T)))
{
case TypeCode.Int32:
return (byte)ProfilerMarkerDataType.Int32;
case TypeCode.UInt32:
return (byte)ProfilerMarkerDataType.UInt32;
case TypeCode.Int64:
return (byte)ProfilerMarkerDataType.Int64;
case TypeCode.UInt64:
return (byte)ProfilerMarkerDataType.UInt64;
case TypeCode.Single:
return (byte)ProfilerMarkerDataType.Float;
case TypeCode.Double:
return (byte)ProfilerMarkerDataType.Double;
case TypeCode.String:
return (byte)ProfilerMarkerDataType.String16;
default:
throw new ArgumentException($"Type {typeof(T)} is unsupported by ProfilerCounter.");
}
}
#endif
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 07be8245ee1e14efa8eb0331bbd9e618
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,67 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
#if UNITY_2020_2_OR_NEWER
using Unity.Profiling;
using Unity.Profiling.LowLevel;
using Unity.Profiling.LowLevel.Unsafe;
#endif
namespace MLAPI.Profiling
{
#if ENABLE_PROFILER
[StructLayout(LayoutKind.Sequential)]
#else
[StructLayout(LayoutKind.Sequential, Size = 0)]
#endif
internal readonly struct ProfilerCounterValue<T> where T : unmanaged
{
#if UNITY_2020_2_OR_NEWER
#if ENABLE_PROFILER
[NativeDisableUnsafePtrRestriction]
[NonSerialized]
readonly unsafe T* m_Value;
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ProfilerCounterValue(ProfilerCategory category, string name, ProfilerMarkerDataUnit dataUnit, ProfilerCounterOptions counterOptions)
{
#if ENABLE_PROFILER
byte dataType = ProfilerCounterUtility.GetProfilerMarkerDataType<T>();
unsafe
{
m_Value = (T*)ProfilerUnsafeUtility.CreateCounterValue(out var counterPtr, name, category, MarkerFlags.Default, dataType, (byte)dataUnit, UnsafeUtility.SizeOf<T>(), counterOptions);
}
#endif
}
public T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
#if ENABLE_PROFILER
unsafe
{
return *m_Value;
}
#else
return default;
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
#if ENABLE_PROFILER
unsafe
{
*m_Value = value;
}
#endif
}
}
#endif
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ba4f4ffe57ff47f2a99db73a9871b4e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,147 @@
#if UNITY_2020_2_OR_NEWER
using Unity.Profiling;
#endif
using UnityEngine;
namespace MLAPI.Profiling
{
internal static class ProfilerCountersInfo
{
#if UNITY_2020_2_OR_NEWER && ENABLE_PROFILER
// Operations
private static readonly ProfilerCounterValue<int> k_ConnectionsCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.Connections,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame);
private static readonly ProfilerCounterValue<int> k_TickRateCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.ReceiveTickRate,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
// Messages
private static readonly ProfilerCounterValue<int> k_NamedMessageReceivedCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NamedMessageReceived,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_UnnamedMessageReceivedCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.UnnamedMessageReceived,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_NamedMessageSentCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NamedMessageSent,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_UnnamedMessageSentCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.UnnamedMessageSent,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_BytesSentCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.ByteSent,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_BytesReceivedCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.ByteReceived,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_NetworkVarDeltasCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NetworkVarDeltas,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_NetworkVarUpdatesCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NetworkVarUpdates,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
// RPCs
private static readonly ProfilerCounterValue<int> k_RPCsSentCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.RpcSent,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_RPCsReceivedCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.RpcReceived,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_RPCBatchesSentCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.RpcBatchesSent,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_RPCBatchesReceivedCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.RpcBatchesReceived,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_RPCQueueProcessedCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.RpcQueueProcessed,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_RPCsInQueueSizeCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.RpcInQueueSize,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
private static readonly ProfilerCounterValue<int> k_RPCsOutQueueSizeCounterValue =
new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.RpcOutQueueSize,
ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
[RuntimeInitializeOnLoadMethod]
private static void RegisterMLAPIPerformanceEvent()
{
InitializeCounters();
NetworkManager.OnPerformanceDataEvent += OnPerformanceTickData;
}
private static void InitializeCounters()
{
k_ConnectionsCounterValue.Value = 0;
k_TickRateCounterValue.Value = 0;
k_NamedMessageReceivedCounterValue.Value = 0;
k_UnnamedMessageReceivedCounterValue.Value = 0;
k_NamedMessageSentCounterValue.Value = 0;
k_UnnamedMessageSentCounterValue.Value = 0;
k_BytesSentCounterValue.Value = 0;
k_BytesReceivedCounterValue.Value = 0;
k_NetworkVarDeltasCounterValue.Value = 0;
k_NetworkVarUpdatesCounterValue.Value = 0;
k_RPCsSentCounterValue.Value = 0;
k_RPCsReceivedCounterValue.Value = 0;
k_RPCBatchesSentCounterValue.Value = 0;
k_RPCBatchesReceivedCounterValue.Value = 0;
k_RPCQueueProcessedCounterValue.Value = 0;
k_RPCsInQueueSizeCounterValue.Value = 0;
k_RPCsOutQueueSizeCounterValue.Value = 0;
}
private static void OnPerformanceTickData(PerformanceTickData tickData)
{
// Operations
UpdateIntCounter(tickData, k_ConnectionsCounterValue, ProfilerConstants.Connections);
UpdateIntCounter(tickData, k_TickRateCounterValue, ProfilerConstants.ReceiveTickRate);
// Messages
UpdateIntCounter(tickData, k_NamedMessageReceivedCounterValue, ProfilerConstants.NamedMessageReceived);
UpdateIntCounter(tickData, k_UnnamedMessageReceivedCounterValue, ProfilerConstants.UnnamedMessageReceived);
UpdateIntCounter(tickData, k_NamedMessageSentCounterValue, ProfilerConstants.NamedMessageSent);
UpdateIntCounter(tickData, k_UnnamedMessageSentCounterValue, ProfilerConstants.UnnamedMessageSent);
UpdateIntCounter(tickData, k_BytesSentCounterValue, ProfilerConstants.ByteSent);
UpdateIntCounter(tickData, k_BytesReceivedCounterValue, ProfilerConstants.ByteReceived);
UpdateIntCounter(tickData, k_NetworkVarDeltasCounterValue, ProfilerConstants.NetworkVarDeltas);
UpdateIntCounter(tickData, k_NetworkVarUpdatesCounterValue, ProfilerConstants.NetworkVarUpdates);
// RPCs
UpdateIntCounter(tickData, k_RPCsSentCounterValue, ProfilerConstants.RpcSent);
UpdateIntCounter(tickData, k_RPCsReceivedCounterValue, ProfilerConstants.RpcReceived);
UpdateIntCounter(tickData, k_RPCBatchesSentCounterValue, ProfilerConstants.RpcBatchesSent);
UpdateIntCounter(tickData, k_RPCBatchesReceivedCounterValue, ProfilerConstants.RpcBatchesReceived);
UpdateIntCounter(tickData, k_RPCBatchesReceivedCounterValue, ProfilerConstants.RpcQueueProcessed);
UpdateIntCounter(tickData, k_RPCQueueProcessedCounterValue, ProfilerConstants.RpcInQueueSize);
UpdateIntCounter(tickData, k_RPCsInQueueSizeCounterValue, ProfilerConstants.RpcOutQueueSize);
}
private static void UpdateIntCounter(PerformanceTickData tickData, ProfilerCounterValue<int> counter, string fieldName)
{
if (tickData.HasData(fieldName))
{
counter.Value += tickData.GetData(fieldName);
}
}
#endif
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c12e40b02ca5a49ca8f9dbe35d34ab1b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,107 @@
using System.Collections.Generic;
using UnityEngine;
namespace MLAPI.Profiling
{
public struct Sample
{
public int Count;
public float TimeRecorded;
}
public class ProfilerStat
{
public ProfilerStat(string name)
{
PrettyPrintName = name;
ProfilerStatManager.Add(this);
}
public string PrettyPrintName;
protected int MaxSamples = 10;
protected LinkedList<Sample> Data = new LinkedList<Sample>();
private bool m_IsDirty = true;
protected float LastCount;
protected float LastTime;
public virtual void Record(int amt = 1)
{
m_IsDirty = true;
var t_now = Time.time;
// 'Record' can get called many times in the same frame (for the same exact timestamp)
// This not only blows out the samples but makes the rate computation break since we
// have n samples with a time delta of zero.
//
// Instead, if we want to record a value at the same exact time as our last
// sample, just adjust that sample
if (Data.First != null && Data.First.Value.TimeRecorded == t_now)
{
Data.First.Value = new Sample()
{
Count = Data.First.Value.Count + amt,
TimeRecorded = Data.First.Value.TimeRecorded
};
}
else
{
Data.AddFirst(new Sample() { Count = amt, TimeRecorded = Time.time });
while (Data.Count > MaxSamples)
{
Data.RemoveLast();
}
}
}
public virtual float SampleRate()
{
if (m_IsDirty)
{
LinkedListNode<Sample> node = Data.First;
LastCount = 0;
LastTime = Data.Last?.Value.TimeRecorded ?? 0.0f;
while (node != null)
{
LastCount += node.Value.Count;
node = node.Next;
}
m_IsDirty = false;
}
float delta = Time.time - LastTime;
if (delta == 0.0f)
{
return 0.0f;
}
return LastCount / delta;
}
}
public class ProfilerIncStat : ProfilerStat
{
public ProfilerIncStat(string name) : base(name) { }
private float m_InternalValue = 0f;
public override void Record(int amt = 1)
{
Data.AddFirst(new Sample() { Count = amt, TimeRecorded = Time.time });
while (Data.Count > MaxSamples)
{
Data.RemoveLast();
}
m_InternalValue += amt;
}
public override float SampleRate()
{
return m_InternalValue;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7868721cc45b74ed29d0d2f75247a94c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,32 @@
using System.Collections.Generic;
namespace MLAPI.Profiling
{
public static class ProfilerStatManager
{
public static List<ProfilerStat> AllStats = new List<ProfilerStat>();
public static readonly ProfilerIncStat Connections = new ProfilerIncStat("Connections");
public static readonly ProfilerStat BytesRcvd = new ProfilerStat("Bytes Rcvd");
public static readonly ProfilerStat BytesSent = new ProfilerStat("Bytes Sent");
public static readonly ProfilerStat RcvTickRate = new ProfilerStat("Rcv Tick Rate");
public static readonly ProfilerStat NetworkVarsRcvd = new ProfilerStat("Network Vars Rcvd");
public static readonly ProfilerStat NamedMessage = new ProfilerStat("Named Message");
public static readonly ProfilerStat UnnamedMessage = new ProfilerStat("UnNamed Message");
public static readonly ProfilerStat RpcsRcvd = new ProfilerStat("RPCs Rcvd");
public static readonly ProfilerStat RpcsSent = new ProfilerStat("RPCs Sent");
public static readonly ProfilerStat RpcBatchesRcvd = new ProfilerStat("RPC Batches Rcvd");
public static readonly ProfilerStat RpcBatchesSent = new ProfilerStat("RPC Batches Sent");
public static readonly ProfilerStat RpcsQueueProc = new ProfilerStat("RPCS-Processed");
public static readonly ProfilerStat RpcInQueueSize = new ProfilerStat("InQFrameSize");
public static readonly ProfilerStat RpcOutQueueSize = new ProfilerStat("OutQFrameSize");
public static readonly ProfilerIncStat NetTranforms = new ProfilerIncStat("NetTransforms");
public static void Add(ProfilerStat s)
{
AllStats.Add(s);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 84b82ec95778845a0bdb486da306cdb3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,202 @@
using System.Collections.Generic;
using System.IO;
using MLAPI.Serialization.Pooled;
namespace MLAPI.Profiling
{
/// <summary>
/// The type of Tick
/// </summary>
public enum TickType
{
/// <summary>
/// Event tick. During EventTick NetworkVars are flushed etc
/// </summary>
Event,
/// <summary>
/// Receive tick. During ReceiveTick data is received from the transport
/// </summary>
Receive,
/// <summary>
/// Send tick. During Send data is sent from Transport queue
/// </summary>
Send
}
/// <summary>
/// A tick in used for the Profiler
/// </summary>
public class ProfilerTick
{
/// <summary>
/// The events that occured during this tick
/// </summary>
public readonly List<TickEvent> Events = new List<TickEvent>();
/// <summary>
/// Writes the current ProfilerTick to the stream
/// </summary>
/// <param name="stream">The stream containing</param>
public void SerializeToStream(Stream stream)
{
using (var writer = PooledNetworkWriter.Get(stream))
{
writer.WriteUInt16Packed((ushort)Events.Count);
for (int i = 0; i < Events.Count; i++)
{
Events[i].SerializeToStream(stream);
}
}
}
/// <summary>
/// Creates a ProfilerTick from data in the provided stream
/// </summary>
/// <param name="stream">The stream containing the ProfilerTick data</param>
/// <returns>The ProfilerTick with data read from the stream</returns>
public static ProfilerTick FromStream(Stream stream)
{
var tick = new ProfilerTick();
using (var reader = PooledNetworkReader.Get(stream))
{
ushort count = reader.ReadUInt16Packed();
for (int i = 0; i < count; i++)
{
tick.Events.Add(TickEvent.FromStream(stream));
}
return tick;
}
}
internal void EndEvent()
{
for (int i = Events.Count - 1; i >= 0; i--)
{
if (!Events[i].Closed)
{
Events[i].Closed = true;
return;
}
}
}
internal void StartEvent(TickType type, uint bytes, string channelName, string messageType)
{
var tickEvent = new TickEvent()
{
Bytes = bytes,
ChannelName = string.IsNullOrEmpty(channelName) ? "NONE" : channelName,
MessageType = string.IsNullOrEmpty(messageType) ? "NONE" : messageType,
EventType = type,
Closed = false
};
Events.Add(tickEvent);
}
/// <summary>
/// The type of tick
/// </summary>
public TickType Type;
/// <summary>
/// The frame the tick executed on
/// </summary>
public int Frame;
/// <summary>
/// The id of the tick
/// </summary>
public int EventId;
/// <summary>
/// The amount of bytes that were sent and / or received during this tick
/// </summary>
public uint Bytes
{
get
{
uint bytes = 0;
for (int i = 0; i < Events.Count; i++)
{
bytes += Events[i].Bytes;
}
return bytes;
}
}
}
/// <summary>
/// A event that can occur during a Event
/// </summary>
public class TickEvent
{
/// <summary>
/// The type of evenmt
/// </summary>
public TickType EventType;
/// <summary>
/// The amount of bytes sent or received
/// </summary>
public uint Bytes;
/// <summary>
/// The name of the channel
/// </summary>
public string ChannelName;
/// <summary>
/// The message type
/// </summary>
public string MessageType;
/// <summary>
/// Whether or not the event is closed
/// </summary>
public bool Closed;
/// <summary>
/// Writes the TickEvent data to the stream
/// </summary>
/// <param name="stream">The stream to write the TickEvent data to</param>
public void SerializeToStream(Stream stream)
{
using (var writer = PooledNetworkWriter.Get(stream))
{
writer.WriteByte((byte)EventType);
writer.WriteUInt32Packed(Bytes);
writer.WriteStringPacked(ChannelName);
writer.WriteStringPacked(MessageType);
writer.WriteBool(Closed);
}
}
/// <summary>
/// Creates a TickEvent from data in the provided stream
/// </summary>
/// <param name="stream">The stream containing the TickEvent data</param>
/// <returns>The TickEvent with data read from the stream</returns>
public static TickEvent FromStream(Stream stream)
{
using (var reader = PooledNetworkReader.Get(stream))
{
var tickEvent = new TickEvent
{
EventType = (TickType)reader.ReadByte(),
Bytes = reader.ReadUInt32Packed(),
ChannelName = reader.ReadStringPacked(),
MessageType = reader.ReadStringPacked(),
Closed = reader.ReadBool()
};
return tickEvent;
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb0351e1061093243937674addac2367
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,39 @@
using System.Collections.Generic;
namespace MLAPI.Profiling
{
public class ProfilingDataStore
{
private readonly Dictionary<string, int> m_Dictionary = new Dictionary<string, int>();
public void Add(string fieldName, int value)
{
m_Dictionary.Add(fieldName, value);
}
public void Increment(string fieldName, int count = 1)
{
m_Dictionary[fieldName] = m_Dictionary.ContainsKey(fieldName) ? m_Dictionary[fieldName] + count : count;
}
public bool HasData(string fieldName)
{
return m_Dictionary.ContainsKey(fieldName);
}
public int GetData(string fieldName)
{
return m_Dictionary.ContainsKey(fieldName) ? m_Dictionary[fieldName] : 0;
}
public void Clear()
{
m_Dictionary.Clear();
}
public IReadOnlyDictionary<string, int> GetReadonly()
{
return m_Dictionary;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18cab32e87876465396e5f222a1a8c07
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: