From 2a992e69028d8a560bf99df605c8d5da000165c9 Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 16:58:17 +0100 Subject: [PATCH 01/10] feat(Profiling): NetworkLoop sampling instead of "UpdateFunction.Invoke" --- Assets/Mirror/Core/NetworkLoop.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Assets/Mirror/Core/NetworkLoop.cs b/Assets/Mirror/Core/NetworkLoop.cs index a9cd49038e..98c6bb744d 100644 --- a/Assets/Mirror/Core/NetworkLoop.cs +++ b/Assets/Mirror/Core/NetworkLoop.cs @@ -28,6 +28,7 @@ using UnityEngine; using UnityEngine.LowLevel; using UnityEngine.PlayerLoop; +using UnityEngine.Profiling; namespace Mirror { @@ -187,12 +188,17 @@ static void NetworkEarlyUpdate() // however, we only want to call NetworkServer/Client in play mode. if (!Application.isPlaying) return; + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke" + Profiler.BeginSample("NetworkEarlyUpdate"); + NetworkTime.EarlyUpdate(); //Debug.Log($"NetworkEarlyUpdate {Time.time}"); NetworkServer.NetworkEarlyUpdate(); NetworkClient.NetworkEarlyUpdate(); // invoke event after mirror has done it's early updating. OnEarlyUpdate?.Invoke(); + + Profiler.EndSample(); } static void NetworkLateUpdate() @@ -201,11 +207,16 @@ static void NetworkLateUpdate() // however, we only want to call NetworkServer/Client in play mode. if (!Application.isPlaying) return; + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke" + Profiler.BeginSample("NetworkLateUpdate"); + //Debug.Log($"NetworkLateUpdate {Time.time}"); // invoke event before mirror does its final late updating. OnLateUpdate?.Invoke(); NetworkServer.NetworkLateUpdate(); NetworkClient.NetworkLateUpdate(); + + Profiler.EndSample(); } } } From 4ec274458fee36a9219565b185a46e3c35cbd3df Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:02:31 +0100 Subject: [PATCH 02/10] NetworkServer markers --- Assets/Mirror/Core/NetworkServer.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Assets/Mirror/Core/NetworkServer.cs b/Assets/Mirror/Core/NetworkServer.cs index 5d545e15ff..373b33bc90 100644 --- a/Assets/Mirror/Core/NetworkServer.cs +++ b/Assets/Mirror/Core/NetworkServer.cs @@ -3,6 +3,7 @@ using System.Linq; using Mirror.RemoteCalls; using UnityEngine; +using UnityEngine.Profiling; namespace Mirror { @@ -2034,12 +2035,19 @@ internal static void NetworkEarlyUpdate() } // process all incoming messages first before updating the world + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("NetworkServer.EarlyUpdate(): Process Transport Messages"); if (Transport.active != null) Transport.active.ServerEarlyUpdate(); + Profiler.EndSample(); + // step each connection's local time interpolation in early update. + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("NetworkServer.EarlyUpdate(): Update Connection's Time Interp."); foreach (NetworkConnectionToClient connection in connections.Values) connection.UpdateTimeInterpolation(); + Profiler.EndSample(); if (active) earlyUpdateDuration.End(); } @@ -2068,13 +2076,21 @@ internal static void NetworkLateUpdate() // Unity 2019 doesn't have Time.timeAsDouble yet bool sendIntervalElapsed = AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime); if (!Application.isPlaying || sendIntervalElapsed) + { + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("NetworkServer.LateUpdate(): Broadcast"); Broadcast(); + Profiler.EndSample(); + } } // process all outgoing messages after updating the world // (even if not active. still want to process disconnects etc.) + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("NetworkServer.LateUpdate(): Transport Flush"); if (Transport.active != null) Transport.active.ServerLateUpdate(); + Profiler.EndSample(); // measure actual tick rate every second. if (active) From 62ba66847da75032bbd6094f73e7537192573041 Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:03:50 +0100 Subject: [PATCH 03/10] NetworkClient markers --- Assets/Mirror/Core/NetworkClient.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Assets/Mirror/Core/NetworkClient.cs b/Assets/Mirror/Core/NetworkClient.cs index aa8883222e..a17e193844 100644 --- a/Assets/Mirror/Core/NetworkClient.cs +++ b/Assets/Mirror/Core/NetworkClient.cs @@ -3,6 +3,7 @@ using System.Linq; using Mirror.RemoteCalls; using UnityEngine; +using UnityEngine.Profiling; namespace Mirror { @@ -1500,8 +1501,11 @@ internal static void ChangeOwner(NetworkIdentity identity, ChangeOwnerMessage me internal static void NetworkEarlyUpdate() { // process all incoming messages first before updating the world + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("NetworkClient.EarlyUpdate(): Transport Processing"); if (Transport.active != null) Transport.active.ClientEarlyUpdate(); + Profiler.EndSample(); // time snapshot interpolation UpdateTimeInterpolation(); @@ -1532,7 +1536,10 @@ internal static void NetworkLateUpdate() bool sendIntervalElapsed = AccurateInterval.Elapsed(NetworkTime.localTime, sendInterval, ref lastSendTime); if (!Application.isPlaying || sendIntervalElapsed) { + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("NetworkClient.LateUpdate(): Broadcast"); Broadcast(); + Profiler.EndSample(); } UpdateConnectionQuality(); From 0b165ff3483430d8a210d8b8779d0b6ea453a055 Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:03:57 +0100 Subject: [PATCH 04/10] better --- Assets/Mirror/Core/NetworkServer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Mirror/Core/NetworkServer.cs b/Assets/Mirror/Core/NetworkServer.cs index 373b33bc90..ba9ec06e9b 100644 --- a/Assets/Mirror/Core/NetworkServer.cs +++ b/Assets/Mirror/Core/NetworkServer.cs @@ -2036,7 +2036,7 @@ internal static void NetworkEarlyUpdate() // process all incoming messages first before updating the world // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample("NetworkServer.EarlyUpdate(): Process Transport Messages"); + Profiler.BeginSample("NetworkServer.EarlyUpdate(): Transport Processing"); if (Transport.active != null) Transport.active.ServerEarlyUpdate(); Profiler.EndSample(); @@ -2044,7 +2044,7 @@ internal static void NetworkEarlyUpdate() // step each connection's local time interpolation in early update. // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample("NetworkServer.EarlyUpdate(): Update Connection's Time Interp."); + Profiler.BeginSample("NetworkServer.EarlyUpdate(): Connections Time Update"); foreach (NetworkConnectionToClient connection in connections.Values) connection.UpdateTimeInterpolation(); Profiler.EndSample(); From aefde5cd66dd32374d48b2db0c0f835d73ed51fb Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:06:41 +0100 Subject: [PATCH 05/10] better --- Assets/Mirror/Core/NetworkClient.cs | 4 ++-- Assets/Mirror/Core/NetworkServer.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Assets/Mirror/Core/NetworkClient.cs b/Assets/Mirror/Core/NetworkClient.cs index a17e193844..71d80d8f80 100644 --- a/Assets/Mirror/Core/NetworkClient.cs +++ b/Assets/Mirror/Core/NetworkClient.cs @@ -1502,7 +1502,7 @@ internal static void NetworkEarlyUpdate() { // process all incoming messages first before updating the world // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample("NetworkClient.EarlyUpdate(): Transport Processing"); + Profiler.BeginSample("NetworkClient: Transport Processing"); if (Transport.active != null) Transport.active.ClientEarlyUpdate(); Profiler.EndSample(); @@ -1537,7 +1537,7 @@ internal static void NetworkLateUpdate() if (!Application.isPlaying || sendIntervalElapsed) { // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample("NetworkClient.LateUpdate(): Broadcast"); + Profiler.BeginSample("NetworkClient: Broadcast"); Broadcast(); Profiler.EndSample(); } diff --git a/Assets/Mirror/Core/NetworkServer.cs b/Assets/Mirror/Core/NetworkServer.cs index ba9ec06e9b..df90b5a454 100644 --- a/Assets/Mirror/Core/NetworkServer.cs +++ b/Assets/Mirror/Core/NetworkServer.cs @@ -2036,7 +2036,7 @@ internal static void NetworkEarlyUpdate() // process all incoming messages first before updating the world // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample("NetworkServer.EarlyUpdate(): Transport Processing"); + Profiler.BeginSample("NetworkServer: Transport Processing"); if (Transport.active != null) Transport.active.ServerEarlyUpdate(); Profiler.EndSample(); @@ -2044,7 +2044,7 @@ internal static void NetworkEarlyUpdate() // step each connection's local time interpolation in early update. // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample("NetworkServer.EarlyUpdate(): Connections Time Update"); + Profiler.BeginSample("NetworkServer: Connections Time Update"); foreach (NetworkConnectionToClient connection in connections.Values) connection.UpdateTimeInterpolation(); Profiler.EndSample(); @@ -2078,7 +2078,7 @@ internal static void NetworkLateUpdate() if (!Application.isPlaying || sendIntervalElapsed) { // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample("NetworkServer.LateUpdate(): Broadcast"); + Profiler.BeginSample("NetworkServer: Broadcast"); Broadcast(); Profiler.EndSample(); } @@ -2087,7 +2087,7 @@ internal static void NetworkLateUpdate() // process all outgoing messages after updating the world // (even if not active. still want to process disconnects etc.) // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample("NetworkServer.LateUpdate(): Transport Flush"); + Profiler.BeginSample("NetworkServer: Transport Flush"); if (Transport.active != null) Transport.active.ServerLateUpdate(); Profiler.EndSample(); From b31fe9ec92e1e44fe362d0c0665b1b317176a3a9 Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:15:56 +0100 Subject: [PATCH 06/10] server: more --- Assets/Mirror/Core/NetworkServer.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Assets/Mirror/Core/NetworkServer.cs b/Assets/Mirror/Core/NetworkServer.cs index df90b5a454..0a065289f9 100644 --- a/Assets/Mirror/Core/NetworkServer.cs +++ b/Assets/Mirror/Core/NetworkServer.cs @@ -1929,7 +1929,11 @@ static void BroadcastToConnection(NetworkConnectionToClient connection) { // get serialization for this entity viewed by this connection // (if anything was serialized this time) + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("BroadcastToConnection: SerializeForConnection"); NetworkWriter serialization = SerializeForConnection(identity, connection); + Profiler.EndSample(); + if (serialization != null) { EntityStateMessage message = new EntityStateMessage @@ -1937,7 +1941,11 @@ static void BroadcastToConnection(NetworkConnectionToClient connection) netId = identity.netId, payload = serialization.ToArraySegment() }; + + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("BroadcastToConnection: Send"); connection.Send(message); + Profiler.EndSample(); } } // spawned list should have no null entries because we @@ -2018,7 +2026,10 @@ static void Broadcast() } // update connection to flush out batched messages + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("Broadcast: Flush"); connection.Update(); + Profiler.EndSample(); } } From 69d9aa2ff039182384ce7809862ac7f0829f7a25 Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:17:05 +0100 Subject: [PATCH 07/10] client: more --- Assets/Mirror/Core/NetworkClient.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Assets/Mirror/Core/NetworkClient.cs b/Assets/Mirror/Core/NetworkClient.cs index 71d80d8f80..805b0b5420 100644 --- a/Assets/Mirror/Core/NetworkClient.cs +++ b/Assets/Mirror/Core/NetworkClient.cs @@ -1635,7 +1635,11 @@ static void BroadcastToServer() { // get serialization for this entity viewed by this connection // (if anything was serialized this time) + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("BroadcastToServer: SerializeClient"); identity.SerializeClient(writer); + Profiler.EndSample(); + if (writer.Position > 0) { // send state update message @@ -1644,7 +1648,11 @@ static void BroadcastToServer() netId = identity.netId, payload = writer.ToArraySegment() }; + + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("BroadcastToServer: Flush"); Send(message); + Profiler.EndSample(); } } } From 4bebec8173b86cff446798bb2c68d6a4cb139e8c Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:24:26 +0100 Subject: [PATCH 08/10] per NI WIP --- Assets/Mirror/Core/NetworkIdentity.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Assets/Mirror/Core/NetworkIdentity.cs b/Assets/Mirror/Core/NetworkIdentity.cs index 17c55cde67..cef93388f7 100644 --- a/Assets/Mirror/Core/NetworkIdentity.cs +++ b/Assets/Mirror/Core/NetworkIdentity.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using Mirror.RemoteCalls; using UnityEngine; +using UnityEngine.Profiling; using UnityEngine.Serialization; #if UNITY_EDITOR @@ -936,6 +937,8 @@ internal static bool IsDirty(ulong mask, int index) // check ownerWritten/observersWritten to know if anything was written internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, NetworkWriter observersWriter) { + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample($"NetworkIdentity({name}): SerializeServer"); // TODO nonalloc // ensure NetworkBehaviours are valid before usage ValidateComponents(); NetworkBehaviour[] components = NetworkBehaviours; @@ -1004,11 +1007,16 @@ internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, Netw } } } + + Profiler.EndSample(); } // serialize components into writer on the client. internal void SerializeClient(NetworkWriter writer) { + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample($"NetworkIdentity({name}): SerializeClient"); // TODO nonalloc + // ensure NetworkBehaviours are valid before usage ValidateComponents(); NetworkBehaviour[] components = NetworkBehaviours; @@ -1061,6 +1069,8 @@ internal void SerializeClient(NetworkWriter writer) } } } + + Profiler.EndSample(); } // deserialize components from the client on the server. From bf4f0b5acb10a823eda5072545727373abf0a280 Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:50:11 +0100 Subject: [PATCH 09/10] nonalloc --- Assets/Mirror/Core/NetworkIdentity.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Assets/Mirror/Core/NetworkIdentity.cs b/Assets/Mirror/Core/NetworkIdentity.cs index cef93388f7..1748ae2483 100644 --- a/Assets/Mirror/Core/NetworkIdentity.cs +++ b/Assets/Mirror/Core/NetworkIdentity.cs @@ -225,6 +225,9 @@ internal set static readonly Dictionary sceneIds = new Dictionary(); + // profiling: cache the serialization string to avoid runtime allocations + string profilingSerializationTag = $"NetworkIdentity: Serialize"; // set to {name} in Awake + // Helper function to handle Command/Rpc internal void HandleRemoteCall(byte componentIndex, ushort functionHash, RemoteCallType remoteCallType, NetworkReader reader, NetworkConnectionToClient senderConnection = null) { @@ -333,6 +336,9 @@ void ValidateComponents() // internal so we can call it during unit tests too. internal void Awake() { + // cache profiling string to avoid runtime allocations + profilingSerializationTag = $"NetworkIdentity: Serialize {name}"; + // initialize NetworkBehaviour components. // Awake() is called immediately after initialization. // no one can overwrite it because NetworkIdentity is sealed. @@ -938,7 +944,8 @@ internal static bool IsDirty(ulong mask, int index) internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, NetworkWriter observersWriter) { // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample($"NetworkIdentity({name}): SerializeServer"); // TODO nonalloc + Profiler.BeginSample($"NetworkIdentity: Serialize {name}"); // TODO nonalloc + // ensure NetworkBehaviours are valid before usage ValidateComponents(); NetworkBehaviour[] components = NetworkBehaviours; @@ -1015,7 +1022,7 @@ internal void SerializeServer(bool initialState, NetworkWriter ownerWriter, Netw internal void SerializeClient(NetworkWriter writer) { // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke - Profiler.BeginSample($"NetworkIdentity({name}): SerializeClient"); // TODO nonalloc + Profiler.BeginSample($"NetworkIdentity: Serialize {name}"); // TODO nonalloc // ensure NetworkBehaviours are valid before usage ValidateComponents(); From ed586042055f56927fdcb5f66129534ca646c937 Mon Sep 17 00:00:00 2001 From: miwarnec Date: Thu, 31 Oct 2024 17:51:31 +0100 Subject: [PATCH 10/10] client measure transport --- Assets/Mirror/Core/NetworkClient.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Assets/Mirror/Core/NetworkClient.cs b/Assets/Mirror/Core/NetworkClient.cs index 805b0b5420..cf316d5b5d 100644 --- a/Assets/Mirror/Core/NetworkClient.cs +++ b/Assets/Mirror/Core/NetworkClient.cs @@ -1596,8 +1596,11 @@ void UpdateConnectionQuality() } // process all outgoing messages after updating the world + // profiling marker for shallow profiling to show more than "UpdateFunction.Invoke + Profiler.BeginSample("NetworkClient: Transport Flush"); if (Transport.active != null) Transport.active.ClientLateUpdate(); + Profiler.EndSample(); } // broadcast ///////////////////////////////////////////////////////////