Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace MLAPI.Profiling
|
||||
{
|
||||
public interface ITransportProfilerData
|
||||
{
|
||||
void BeginNewTick();
|
||||
IReadOnlyDictionary<string, int> GetTransportProfilerData();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0c016323c9d0c4e8990d946f8f3d6ce2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1009676d0b4d5ea4ba2a8532b573ad32
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 09fbe4f2c41c841b0a93d9ddea3c8413
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9f4b98642f26d4f599a78409be2af56e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9a98852a5495e4a3aa515f0b5903847a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 07be8245ee1e14efa8eb0331bbd9e618
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0ba4f4ffe57ff47f2a99db73a9871b4e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c12e40b02ca5a49ca8f9dbe35d34ab1b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7868721cc45b74ed29d0d2f75247a94c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 84b82ec95778845a0bdb486da306cdb3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fb0351e1061093243937674addac2367
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 18cab32e87876465396e5f222a1a8c07
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue