-
Notifications
You must be signed in to change notification settings - Fork 461
feat: New MLAPI Profiler using Profiler Dynamic Modules and Overrides #501
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using MLAPI.Profiling; | ||
| using Unity.Profiling; | ||
| using UnityEditor; | ||
| using UnityEngine; | ||
|
|
||
| namespace MLAPI | ||
| { | ||
| [InitializeOnLoad] | ||
| public static class MLAPIProfilerModule | ||
| { | ||
| #if UNITY_2020_2_OR_NEWER && ENABLE_PROFILER | ||
| const string RPCModuleName = "MLAPI RPCs"; | ||
| const string OperationModuleName = "MLAPI Operations"; | ||
| const string MessageModuleName = "MLAPI Messages"; | ||
|
|
||
| /// <summary> | ||
| /// This needs to be in synced with the internal dynamic module structure to provide our own counters | ||
| /// </summary> | ||
| [Serializable] | ||
| public class MLAPIProfilerCounter | ||
| { | ||
| public string m_Name; | ||
| public string m_Category; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// This needs to be in synced with the internal dynamic module structure to provide our own counters | ||
| /// </summary> | ||
| [Serializable] | ||
| public class MLAPIProfilerModuleData | ||
| { | ||
| public List<MLAPIProfilerCounter> m_ChartCounters = new List<MLAPIProfilerCounter>(); | ||
| public List<MLAPIProfilerCounter> m_DetailCounters = new List<MLAPIProfilerCounter>(); | ||
| public string m_Name; | ||
| } | ||
|
|
||
| [Serializable] | ||
| public class MLAPIModules | ||
| { | ||
| public List<MLAPIProfilerModuleData> m_Modules; | ||
| } | ||
|
|
||
| private static List<MLAPIProfilerCounter> CreateRPCCounters() => new List<MLAPIProfilerCounter>() | ||
| { | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCsSent, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCsReceived, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCBatchesSent, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCBatchesReceived, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCQueueProcessed, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCsInQueueSize, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCsOutQueueSize, m_Category = ProfilerCategory.Network.Name }, | ||
| }; | ||
|
|
||
| private static List<MLAPIProfilerCounter> CreateOperationsCounters() => new List<MLAPIProfilerCounter>() | ||
| { | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfConnections, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.ReceiveTickRate, m_Category = ProfilerCategory.Network.Name }, | ||
| }; | ||
|
|
||
| private static List<MLAPIProfilerCounter> CreateMessagesCounters() => new List<MLAPIProfilerCounter>() | ||
| { | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfNamedMessages, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfUnnamedMessages, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberBytesSent, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberBytesReceived, m_Category = ProfilerCategory.Network.Name }, | ||
| new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberNetworkVarsReceived, m_Category = ProfilerCategory.Network.Name }, | ||
| }; | ||
|
|
||
| private delegate List<MLAPIProfilerCounter> CounterListFactoryDelegate(); | ||
|
|
||
| private static bool CreateMLAPIDynamicModule(ref MLAPIModules mlapiModules, string moduleName, CounterListFactoryDelegate counterListFactoryDelegate) | ||
| { | ||
| var module = mlapiModules.m_Modules.Find(x => x.m_Name == moduleName); | ||
| if (module == null) | ||
| { | ||
| var newModule = new MLAPIProfilerModuleData(); | ||
| newModule.m_Name = moduleName; | ||
| newModule.m_ChartCounters = counterListFactoryDelegate(); | ||
| newModule.m_DetailCounters = counterListFactoryDelegate(); | ||
| mlapiModules.m_Modules.Add(newModule); | ||
| return true; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
| #endif | ||
|
|
||
| static MLAPIProfilerModule() | ||
| { | ||
| #if UNITY_2020_2_OR_NEWER && ENABLE_PROFILER | ||
| var dynamicModulesJson = EditorPrefs.GetString("ProfilerWindow.DynamicModules"); | ||
|
|
||
| var dynamicModules = JsonUtility.FromJson<MLAPIModules>(dynamicModulesJson); | ||
|
|
||
| if (dynamicModules != null) | ||
| { | ||
| bool wasCreated = CreateMLAPIDynamicModule(ref dynamicModules, RPCModuleName, CreateRPCCounters); | ||
| wasCreated |= CreateMLAPIDynamicModule(ref dynamicModules, OperationModuleName, CreateOperationsCounters); | ||
| wasCreated |= CreateMLAPIDynamicModule(ref dynamicModules, MessageModuleName, CreateMessagesCounters); | ||
| if (wasCreated) | ||
| { | ||
| EditorPrefs.SetString("ProfilerWindow.DynamicModules", JsonUtility.ToJson(dynamicModules)); | ||
| } | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
|
|
||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| using System; | ||
| #if UNITY_2020_2_OR_NEWER | ||
| using Unity.Profiling.LowLevel; | ||
| #endif | ||
|
|
||
| namespace MLAPI.Profiling | ||
| { | ||
| 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 | ||
| } | ||
| } | ||
|
|
||
|
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| 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 | ||
| using UnityEngine; | ||
|
|
||
| namespace MLAPI.Profiling | ||
| { | ||
| #if ENABLE_PROFILER | ||
| [StructLayout(LayoutKind.Sequential)] | ||
| #else | ||
| [StructLayout(LayoutKind.Sequential, Size = 0)] | ||
| #endif | ||
| public readonly struct ProfilerCounterValue<T> where T : unmanaged | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit, should be internal? Especially since this is sort of a copy of the upcoming work in the core package, we don't want anyone to start leveraging this
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
| { | ||
| #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 | ||
| } | ||
| } | ||
|
|
||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| using System; | ||
| #if UNITY_2020_2_OR_NEWER | ||
| using Unity.Profiling; | ||
| #endif | ||
| using UnityEngine; | ||
|
|
||
| namespace MLAPI.Profiling | ||
| { | ||
|
|
||
| public static class ProfilerCountersInfo | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit, should be internal
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
| { | ||
| #if UNITY_2020_2_OR_NEWER && ENABLE_PROFILER | ||
| // Operations | ||
| public static ProfilerCounterValue<int> ConnectionsCounterValue = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit, all these counters can be private I think. With them being public we are exposing them to be modified, which isn't the intent
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Updated |
||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfConnections, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> TickRateCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.ReceiveTickRate, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| //Messages | ||
| public static ProfilerCounterValue<int> NamedMessagesCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfNamedMessages, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> UnnamedMessagesCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfUnnamedMessages, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> BytesSentCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberBytesSent, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> BytesReceivedCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberBytesReceived, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> NetworkVarsCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberNetworkVarsReceived, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| //RPCs | ||
| public static ProfilerCounterValue<int> RPCsSentCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfRPCsSent, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> RPCsReceivedCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfRPCsReceived, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> RPCBatchesSentCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfRPCBatchesSent, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> RPCBatchesReceivedCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfRPCBatchesReceived, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> RPCQueueProcessedCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfRPCQueueProcessed, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> RPCsInQueueSizeCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfRPCsInQueueSize, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| public static ProfilerCounterValue<int> RPCsOutQueueSizeCounterValue = | ||
| new ProfilerCounterValue<int>(ProfilerCategory.Network, ProfilerConstants.NumberOfRPCsOutQueueSize, | ||
| ProfilerMarkerDataUnit.Count, ProfilerCounterOptions.FlushOnEndOfFrame); | ||
|
|
||
| [RuntimeInitializeOnLoadMethod] | ||
| static void RegisterMLAPIPerformanceEvent() | ||
| { | ||
| NetworkingManager.OnPerformanceDataEvent += OnPerformanceTickData; | ||
| } | ||
|
|
||
| static void OnPerformanceTickData(PerformanceTickData tickData) | ||
| { | ||
| //Operations | ||
| ConnectionsCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfConnections); | ||
| TickRateCounterValue.Value += tickData.GetData(ProfilerConstants.ReceiveTickRate); | ||
|
|
||
| //Messages | ||
| NamedMessagesCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfNamedMessages); | ||
| UnnamedMessagesCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfUnnamedMessages); | ||
| BytesSentCounterValue.Value += tickData.GetData(ProfilerConstants.NumberBytesSent); | ||
| BytesReceivedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberBytesReceived); | ||
| NetworkVarsCounterValue.Value += tickData.GetData(ProfilerConstants.NumberNetworkVarsReceived); | ||
|
|
||
| //RPCs | ||
| RPCsSentCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCsSent); | ||
| RPCsReceivedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCsReceived); | ||
| RPCBatchesSentCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCBatchesSent); | ||
| RPCBatchesReceivedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCBatchesReceived); | ||
| RPCBatchesReceivedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCBatchesReceived); | ||
| RPCQueueProcessedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCQueueProcessed); | ||
| RPCsInQueueSizeCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCsInQueueSize); | ||
| RPCsOutQueueSizeCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCsOutQueueSize); | ||
| } | ||
| #endif | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit, these can be private I think. In fact I think the whole class should probably be internal since it doesn't expose any public APIs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done