Skip to content

Commit 8bb5241

Browse files
author
JS Fauteux
committed
Adding a profiler module override to connect to new MLAPI performance
data
1 parent 7217871 commit 8bb5241

12 files changed

Lines changed: 532 additions & 2 deletions

com.unity.multiplayer.mlapi/Editor/ProfilerModuleOverride.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.Runtime.InteropServices;
2+
using MLAPI.Profiling;
3+
4+
namespace ProfilerModuleOverride
5+
{
6+
[StructLayout(LayoutKind.Sequential)]
7+
public unsafe struct ClientInfo
8+
{
9+
public fixed byte targetName[320];
10+
public fixed byte channelName[320];
11+
public TickType type;
12+
public uint bytesSent;
13+
public fixed byte messageName[320];
14+
}
15+
}

com.unity.multiplayer.mlapi/Editor/ProfilerModuleOverride/ClientInfo.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Runtime.CompilerServices;
5+
using System.Runtime.InteropServices;
6+
using Unity.Collections.LowLevel.Unsafe;
7+
using Unity.Profiling;
8+
using Unity.Profiling.LowLevel;
9+
using Unity.Profiling.LowLevel.Unsafe;
10+
using UnityEngine;
11+
12+
namespace ProfilerModuleOverride
13+
{
14+
#if ENABLE_PROFILER
15+
[StructLayout(LayoutKind.Sequential)]
16+
#else
17+
[StructLayout(LayoutKind.Sequential, Size = 0)]
18+
#endif
19+
public readonly struct MLAPIProfilerCounterValue<T> where T : unmanaged
20+
{
21+
#if ENABLE_PROFILER
22+
[NativeDisableUnsafePtrRestriction]
23+
[NonSerialized]
24+
readonly unsafe T* m_Value;
25+
#endif
26+
27+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
28+
public MLAPIProfilerCounterValue(ProfilerCategory category, string name, ProfilerMarkerDataUnit dataUnit, ProfilerCounterOptions counterOptions)
29+
{
30+
#if ENABLE_PROFILER
31+
byte dataType = ProfilerUtility.GetProfilerMarkerDataType<T>();
32+
unsafe {
33+
m_Value = (T*)ProfilerUnsafeUtility.CreateCounterValue(out var counterPtr, name, category, MarkerFlags.Default, dataType, (byte)dataUnit, UnsafeUtility.SizeOf<T>(), counterOptions);
34+
}
35+
#endif
36+
}
37+
38+
public T Value
39+
{
40+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
41+
get {
42+
#if ENABLE_PROFILER
43+
unsafe {
44+
return *m_Value;
45+
}
46+
#else
47+
return default;
48+
#endif
49+
}
50+
51+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
52+
set {
53+
#if ENABLE_PROFILER
54+
unsafe {
55+
*m_Value = value;
56+
}
57+
#endif
58+
}
59+
}
60+
}
61+
}
62+
63+

com.unity.multiplayer.mlapi/Editor/ProfilerModuleOverride/MLAPIProfilerCounterValue.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using MLAPI.Profiling;
4+
using Unity.Profiling;
5+
using UnityEditor;
6+
using UnityEngine;
7+
8+
namespace ProfilerModuleOverride
9+
{
10+
[InitializeOnLoad]
11+
public class NetworkProfilerOverride
12+
{
13+
#if UNITY_2020_2_OR_NEWER
14+
const string RPCModuleName = "MLAPI RPCs";
15+
const string OperationModuleName = "MLAPI Operations";
16+
const string MessageModuleName = "MLAPI Messages";
17+
18+
[System.Serializable]
19+
public class MLAPIProfilerCounter
20+
{
21+
public string m_Name;
22+
public string m_Category;
23+
}
24+
25+
[System.Serializable]
26+
public class MLAPIProfilerModuleData
27+
{
28+
public MLAPIProfilerModuleData()
29+
{
30+
m_ChartCounters = new List<MLAPIProfilerCounter>();
31+
m_DetailCounters = new List<MLAPIProfilerCounter>();
32+
}
33+
34+
public List<MLAPIProfilerCounter> m_ChartCounters;
35+
public List<MLAPIProfilerCounter> m_DetailCounters;
36+
public string m_Name;
37+
}
38+
39+
[System.Serializable]
40+
public class MLAPIModules
41+
{
42+
public List<MLAPIProfilerModuleData> m_Modules;
43+
}
44+
45+
private static List<MLAPIProfilerCounter> CreateRPCCounters()
46+
{
47+
var list = new List<MLAPIProfilerCounter>();
48+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCsSent.ToString(), m_Category = ProfilerCategory.Network.Name });
49+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCsReceived.ToString(), m_Category = ProfilerCategory.Network.Name });
50+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCBatchesSent.ToString(), m_Category = ProfilerCategory.Network.Name });
51+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCBatchesReceived.ToString(), m_Category = ProfilerCategory.Network.Name });
52+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCQueueProcessed.ToString(), m_Category = ProfilerCategory.Network.Name });
53+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCsInQueueSize.ToString(), m_Category = ProfilerCategory.Network.Name });
54+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfRPCsOutQueueSize.ToString(), m_Category = ProfilerCategory.Network.Name });
55+
return list;
56+
}
57+
58+
private static List<MLAPIProfilerCounter> CreateOperationsCounters()
59+
{
60+
var list = new List<MLAPIProfilerCounter>();
61+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfConnections.ToString(), m_Category = ProfilerCategory.Network.Name });
62+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.ReceiveTickRate.ToString(), m_Category = ProfilerCategory.Network.Name });
63+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfTransportSends.ToString(), m_Category = ProfilerCategory.Network.Name });
64+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfTransportSendQueues.ToString(), m_Category = ProfilerCategory.Network.Name });
65+
return list;
66+
}
67+
68+
private static List<MLAPIProfilerCounter> CreateMessagesCounters()
69+
{
70+
var list = new List<MLAPIProfilerCounter>();
71+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfNamedMessages.ToString(), m_Category = ProfilerCategory.Network.Name });
72+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberOfUnnamedMessages.ToString(), m_Category = ProfilerCategory.Network.Name });
73+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberBytesSent.ToString(), m_Category = ProfilerCategory.Network.Name });
74+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberBytesReceived.ToString(), m_Category = ProfilerCategory.Network.Name });
75+
list.Add(new MLAPIProfilerCounter() { m_Name = ProfilerConstants.NumberNetworkVarsReceived.ToString(), m_Category = ProfilerCategory.Network.Name });
76+
return list;
77+
}
78+
79+
private delegate List<MLAPIProfilerCounter> CounterFunction();
80+
81+
private static bool UpdateOrCreateModule(ref MLAPIModules mlapiModules, string moduleName, CounterFunction counterFunction)
82+
{
83+
bool hasChanged = false;
84+
var module = mlapiModules.m_Modules.Find(x => x.m_Name == moduleName);
85+
if (module == null)
86+
{
87+
var newModule = new MLAPIProfilerModuleData();
88+
newModule.m_Name = moduleName;
89+
newModule.m_ChartCounters = counterFunction();
90+
newModule.m_DetailCounters = counterFunction();
91+
mlapiModules.m_Modules.Add(newModule);
92+
hasChanged = true;
93+
}
94+
else
95+
{
96+
var counters = counterFunction();
97+
if (module.m_ChartCounters.Count != counters.Count || module.m_DetailCounters.Count != counters.Count)
98+
{
99+
module.m_ChartCounters = counters;
100+
module.m_DetailCounters = counters;
101+
hasChanged = true;
102+
}
103+
}
104+
105+
return hasChanged;
106+
}
107+
#endif
108+
109+
static NetworkProfilerOverride()
110+
{
111+
// NetworkingOperationsProfilerOverrides.drawDetailsViewOverride = OperationsDrawDetailsViewOverride;
112+
// NetworkingMessagesProfilerOverrides.getCustomChartCounters = GetCustomMessageCounters;
113+
// NetworkingOperationsProfilerOverrides.getCustomChartCounters = GetCustomOperationsCounters;
114+
#if UNITY_2020_2_OR_NEWER
115+
var mlapiModulesJson = EditorPrefs.GetString("ProfilerWindow.DynamicModules");
116+
117+
var mlapiModules = JsonUtility.FromJson<MLAPIModules>(mlapiModulesJson);
118+
119+
if (mlapiModules != null)
120+
{
121+
bool hasChanged = UpdateOrCreateModule(ref mlapiModules, RPCModuleName, CreateRPCCounters);
122+
hasChanged = hasChanged && UpdateOrCreateModule(ref mlapiModules, OperationModuleName, CreateOperationsCounters);
123+
hasChanged = hasChanged && UpdateOrCreateModule(ref mlapiModules, MessageModuleName, CreateMessagesCounters);
124+
if (hasChanged)
125+
{
126+
EditorPrefs.SetString("ProfilerWindow.DynamicModules", JsonUtility.ToJson(mlapiModules));
127+
}
128+
}
129+
130+
MLAPI.NetworkingManager.OnPerformanceDataEvent += OnPerformanceTickData;
131+
#endif
132+
}
133+
134+
static void OnPerformanceTickData(PerformanceTickData tickData)
135+
{
136+
137+
#if UNITY_2020_2_OR_NEWER
138+
//Operations
139+
ProfilerInfo.ConnectionsCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfConnections.ToString());
140+
ProfilerInfo.TickRateCounterValue.Value += tickData.GetData(ProfilerConstants.ReceiveTickRate.ToString());
141+
ProfilerInfo.TransportSendsCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfTransportSends.ToString());
142+
ProfilerInfo.TransportSendQueuesCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfTransportSendQueues.ToString());
143+
144+
//Messages
145+
ProfilerInfo.NamedMessagesCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfNamedMessages.ToString());
146+
ProfilerInfo.UnnamedMessagesCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfUnnamedMessages.ToString());
147+
ProfilerInfo.BytesSentCounterValue.Value += tickData.GetData(ProfilerConstants.NumberBytesSent.ToString());
148+
ProfilerInfo.BytesReceivedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberBytesReceived.ToString());
149+
ProfilerInfo.NetworkVarsCounterValue.Value += tickData.GetData(ProfilerConstants.NumberNetworkVarsReceived.ToString());
150+
151+
//RPCs
152+
ProfilerInfo.RPCsSentCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCsSent.ToString());
153+
ProfilerInfo.RPCsReceivedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCsReceived.ToString());
154+
ProfilerInfo.RPCBatchesSentCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCBatchesSent.ToString());
155+
ProfilerInfo.RPCBatchesReceivedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCBatchesReceived.ToString());
156+
ProfilerInfo.RPCBatchesReceivedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCBatchesReceived.ToString());
157+
ProfilerInfo.RPCQueueProcessedCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCQueueProcessed.ToString());
158+
ProfilerInfo.RPCsInQueueSizeCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCsInQueueSize.ToString());
159+
ProfilerInfo.RPCsOutQueueSizeCounterValue.Value += tickData.GetData(ProfilerConstants.NumberOfRPCsOutQueueSize.ToString());
160+
#endif
161+
}
162+
163+
// private static List<NetworkCounterData> GetCustomMessageCounters()
164+
// {
165+
// return new List<NetworkCounterData>
166+
// {
167+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfNamedMessages.ToString() },
168+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfUnnamedMessages.ToString() },
169+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberBytesSent.ToString() },
170+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberBytesReceived.ToString() },
171+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberNetworkVarsReceived.ToString() },
172+
// };
173+
// }
174+
//
175+
// private static List<NetworkCounterData> GetCustomOperationsCounters()
176+
// {
177+
// return new List<NetworkCounterData>
178+
// {
179+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfConnections.ToString() },
180+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.ReceiveTickRate.ToString() },
181+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfTransportSends.ToString() },
182+
// new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfTransportSendQueues.ToString() },
183+
// // new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfRPCsSent.ToString() },
184+
// // new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfRPCsReceived.ToString() },
185+
// // new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfRPCBatchesSent.ToString() },
186+
// // new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfRPCBatchesReceived.ToString() },
187+
// // new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfRPCQueueProcessed.ToString() },
188+
// // new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfRPCsInQueueSize.ToString() },
189+
// // new NetworkCounterData { category = ProfilerCategory.Network.Name, name = ProfilerConstants.NumberOfRPCsOutQueueSize.ToString() },
190+
// };
191+
// }
192+
//
193+
// public static ClientInfo[] GetClientFromProfilerStream(int frame)
194+
// {
195+
// using (var frameData = ProfilerDriver.GetHierarchyFrameDataView(frame, 0,
196+
// HierarchyFrameDataView.ViewModes.Default, HierarchyFrameDataView.columnDontSort, false))
197+
// {
198+
// var returnVal = new List<ClientInfo> { };
199+
// if (frameData != null && frameData.valid)
200+
// {
201+
// var count = frameData.GetFrameMetaDataCount(ProfilerInfo.kNetworkingOperationsProfilerModuleGUID,
202+
// ProfilerInfo.kClientDataTag);
203+
// for (int i = 0; i < count; i++)
204+
// {
205+
// var clientInfos =
206+
// frameData.GetFrameMetaData<ClientInfo>(ProfilerInfo.kNetworkingOperationsProfilerModuleGUID, ProfilerInfo.kClientDataTag, i);
207+
// returnVal.AddRange(clientInfos);
208+
// }
209+
// }
210+
// return returnVal.ToArray();
211+
// }
212+
// }
213+
// static void OperationsDrawDetailsViewOverride(Rect position, int frame)
214+
// {
215+
// var clientInfos = GetClientFromProfilerStream(frame);
216+
//
217+
// if (clientInfos.Any())
218+
// {
219+
// EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
220+
// EditorGUILayout.LabelField("ClientID|GameObject");
221+
// EditorGUILayout.LabelField("ChannelName");
222+
// EditorGUILayout.LabelField("MessageName");
223+
// EditorGUILayout.LabelField("TickType");
224+
// EditorGUILayout.LabelField("BytesSent");
225+
// EditorGUILayout.EndHorizontal();
226+
// EditorGUILayout.Separator();
227+
// }
228+
//
229+
// unsafe
230+
// {
231+
// foreach (var clientInfo in clientInfos)
232+
// {
233+
// const int arraySize = 320;
234+
// var arr = new byte[arraySize];
235+
// Marshal.Copy((IntPtr) clientInfo.targetName, arr, 0, arraySize);
236+
// var targetName = Encoding.ASCII.GetString(arr);
237+
// Marshal.Copy((IntPtr) clientInfo.channelName, arr, 0, arraySize);
238+
// var channelName = Encoding.ASCII.GetString(arr);
239+
// Marshal.Copy((IntPtr) clientInfo.messageName, arr, 0, arraySize);
240+
// var messageName = Encoding.ASCII.GetString(arr);
241+
//
242+
// EditorGUILayout.BeginHorizontal();
243+
// EditorGUILayout.LabelField($"{targetName}");
244+
// EditorGUILayout.LabelField($"{channelName}");
245+
// EditorGUILayout.LabelField($"{messageName}");
246+
// EditorGUILayout.LabelField($"{clientInfo.type}");
247+
// EditorGUILayout.LabelField($"{clientInfo.bytesSent}");
248+
// EditorGUILayout.EndHorizontal();
249+
// }
250+
// }
251+
// }
252+
}
253+
}

com.unity.multiplayer.mlapi/Editor/ProfilerModuleOverride/NetworkProfilerOverride.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)