diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs index 7c825abf35..dc1832df8b 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs @@ -1137,6 +1137,8 @@ private IEnumerator ApprovalTimeout(ulong clientId) private void HandleRawTransportPoll(NetworkEvent networkEvent, ulong clientId, NetworkChannel networkChannel, ArraySegment payload, float receiveTime) { + NetworkMetrics.TrackTransportBytesReceived(payload.Count); + switch (networkEvent) { case NetworkEvent.Connect: @@ -1220,6 +1222,7 @@ internal void HandleIncomingData(ulong clientId, NetworkChannel networkChannel, #if DEVELOPMENT_BUILD || UNITY_EDITOR s_HandleIncomingData.Begin(); #endif + if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) { NetworkLog.LogInfo("Unwrapping Data Header"); diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/MessageQueue/MessageQueueProcessor.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/MessageQueue/MessageQueueProcessor.cs index f6e5b49422..93666fde25 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/MessageQueue/MessageQueueProcessor.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/MessageQueue/MessageQueueProcessor.cs @@ -283,6 +283,8 @@ private void SendCallback(ulong clientId, MessageBatcher.SendStream sendStream) { channel = NetworkChannel.Fragmented; } + + m_MessageQueueContainer.NetworkManager.NetworkMetrics.TrackTransportBytesSent(length); m_MessageQueueContainer.NetworkManager.NetworkConfig.NetworkTransport.Send(clientId, sendBuffer, channel); } @@ -307,6 +309,7 @@ private void SendFrameQueueItem(MessageFrameItem item) case MessageQueueContainer.MessageType.ServerRpc: // TODO: Can we remove this special case for server RPCs? { + m_MessageQueueContainer.NetworkManager.NetworkMetrics.TrackTransportBytesSent(item.MessageData.Count); m_MessageQueueContainer.NetworkManager.NetworkConfig.NetworkTransport.Send(item.NetworkId, item.MessageData, channel); break; } @@ -314,6 +317,7 @@ private void SendFrameQueueItem(MessageFrameItem item) { foreach (ulong clientid in item.ClientNetworkIds) { + m_MessageQueueContainer.NetworkManager.NetworkMetrics.TrackTransportBytesSent(item.MessageData.Count); m_MessageQueueContainer.NetworkManager.NetworkConfig.NetworkTransport.Send(clientid, item.MessageData, channel); } diff --git a/com.unity.netcode.gameobjects/Runtime/Metrics/INetworkMetrics.cs b/com.unity.netcode.gameobjects/Runtime/Metrics/INetworkMetrics.cs index 05ce10279a..14d7e3275e 100644 --- a/com.unity.netcode.gameobjects/Runtime/Metrics/INetworkMetrics.cs +++ b/com.unity.netcode.gameobjects/Runtime/Metrics/INetworkMetrics.cs @@ -4,6 +4,10 @@ namespace Unity.Netcode { internal interface INetworkMetrics { + void TrackTransportBytesSent(long bytesCount); + + void TrackTransportBytesReceived(long bytesCount); + void TrackNetworkObject(NetworkObject networkObject); void TrackNamedMessageSent(ulong receiverClientId, string messageName, long bytesCount); diff --git a/com.unity.netcode.gameobjects/Runtime/Metrics/NetworkMetrics.cs b/com.unity.netcode.gameobjects/Runtime/Metrics/NetworkMetrics.cs index 1564218d32..1a816873fa 100644 --- a/com.unity.netcode.gameobjects/Runtime/Metrics/NetworkMetrics.cs +++ b/com.unity.netcode.gameobjects/Runtime/Metrics/NetworkMetrics.cs @@ -8,6 +8,15 @@ namespace Unity.Netcode { internal class NetworkMetrics : INetworkMetrics { + readonly Counter m_TransportBytesSent = new Counter(NetworkMetricTypes.TotalBytesSent.Id) + { + ShouldResetOnDispatch = true, + }; + readonly Counter m_TransportBytesReceived = new Counter(NetworkMetricTypes.TotalBytesReceived.Id) + { + ShouldResetOnDispatch = true, + }; + readonly EventMetric m_NamedMessageSentEvent = new EventMetric(NetworkMetricTypes.NamedMessageSent.Id); readonly EventMetric m_NamedMessageReceivedEvent = new EventMetric(NetworkMetricTypes.NamedMessageReceived.Id); readonly EventMetric m_UnnamedMessageSentEvent = new EventMetric(NetworkMetricTypes.UnnamedMessageSent.Id); @@ -32,6 +41,7 @@ internal class NetworkMetrics : INetworkMetrics public NetworkMetrics() { Dispatcher = new MetricDispatcherBuilder() + .WithCounters(m_TransportBytesSent, m_TransportBytesReceived) .WithMetricEvents(m_NamedMessageSentEvent, m_NamedMessageReceivedEvent) .WithMetricEvents(m_UnnamedMessageSentEvent, m_UnnamedMessageReceivedEvent) .WithMetricEvents(m_NetworkVariableDeltaSentEvent, m_NetworkVariableDeltaReceivedEvent) @@ -48,6 +58,16 @@ public NetworkMetrics() internal IMetricDispatcher Dispatcher { get; } + public void TrackTransportBytesSent(long bytesCount) + { + m_TransportBytesSent.Increment(bytesCount); + } + + public void TrackTransportBytesReceived(long bytesCount) + { + m_TransportBytesReceived.Increment(bytesCount); + } + public void TrackNetworkObject(NetworkObject networkObject) { if (!m_NetworkGameObjects.ContainsKey(networkObject.NetworkObjectId)) diff --git a/com.unity.netcode.gameobjects/Runtime/Metrics/NullNetworkMetrics.cs b/com.unity.netcode.gameobjects/Runtime/Metrics/NullNetworkMetrics.cs index f2e5e06f22..df27bb0857 100644 --- a/com.unity.netcode.gameobjects/Runtime/Metrics/NullNetworkMetrics.cs +++ b/com.unity.netcode.gameobjects/Runtime/Metrics/NullNetworkMetrics.cs @@ -4,6 +4,14 @@ namespace Unity.Netcode { internal class NullNetworkMetrics : INetworkMetrics { + public void TrackTransportBytesSent(long bytesCount) + { + } + + public void TrackTransportBytesReceived(long bytesCount) + { + } + public void TrackNetworkObject(NetworkObject networkObject) { } diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Metrics/NetworkMetricsRegistrationTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Metrics/NetworkMetricsRegistrationTests.cs index 8838c063c7..9aeaee346b 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Metrics/NetworkMetricsRegistrationTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Metrics/NetworkMetricsRegistrationTests.cs @@ -27,7 +27,7 @@ public void ValidateThatAllMetricTypesAreRegistered(Type metricType) Assert.NotNull(collection); Assert.That( - collection.Metrics, + collection.Metrics.OfType(), Has.Exactly(2).Matches( eventMetric => { diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Metrics/TransportBytesMetricsTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Metrics/TransportBytesMetricsTests.cs new file mode 100644 index 0000000000..cc6d15b013 --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Metrics/TransportBytesMetricsTests.cs @@ -0,0 +1,89 @@ +#if MULTIPLAYER_TOOLS +using System; +using System.Collections; +using System.IO; +using NUnit.Framework; +using Unity.Multiplayer.Tools.MetricTypes; +using Unity.Multiplayer.Tools.NetStats; +using Unity.Netcode.RuntimeTests.Metrics.Utlity; +using UnityEngine.TestTools; + +namespace Unity.Netcode.RuntimeTests.Metrics +{ + public class TransportBytesMetricsTests : SingleClientMetricTestBase + { + const long MessageOverhead = 9; + + [UnityTest] + public IEnumerator TrackTotalNumberOfBytesSent() + { + var messageName = Guid.NewGuid().ToString(); + using var memoryStream = new MemoryStream(); + using var binaryWriter = new BinaryWriter(memoryStream); + binaryWriter.Write(messageName); + + var observer = new TotalBytesObserver(ServerMetrics.Dispatcher, NetworkMetricTypes.TotalBytesSent); + + Server.CustomMessagingManager.SendNamedMessage(messageName, Client.LocalClientId, memoryStream); + + var nbFrames = 0; + while (!observer.Found || nbFrames < 10) + { + yield return null; + nbFrames++; + } + + Assert.True(observer.Found); + Assert.AreEqual(messageName.Length + MessageOverhead, observer.Value); + } + + [UnityTest] + public IEnumerator TrackTotalNumberOfBytesReceived() + { + var messageName = Guid.NewGuid().ToString(); + using var memoryStream = new MemoryStream(); + using var binaryWriter = new BinaryWriter(memoryStream); + binaryWriter.Write(messageName); + + var observer = new TotalBytesObserver(ClientMetrics.Dispatcher, NetworkMetricTypes.TotalBytesReceived); + + Server.CustomMessagingManager.SendNamedMessage(messageName, Client.LocalClientId, memoryStream); + + var nbFrames = 0; + while (!observer.Found || nbFrames < 10) + { + yield return null; + nbFrames++; + } + + Assert.True(observer.Found); + Assert.AreEqual(messageName.Length + MessageOverhead, observer.Value); + } + + private class TotalBytesObserver : IMetricObserver + { + private readonly DirectionalMetricInfo m_MetricInfo; + + public TotalBytesObserver(IMetricDispatcher dispatcher, DirectionalMetricInfo metricInfo) + { + m_MetricInfo = metricInfo; + + dispatcher.RegisterObserver(this); + } + + public bool Found { get; private set; } + + public long Value { get; private set; } + + public void Observe(MetricCollection collection) + { + if (collection.TryGetCounter(m_MetricInfo.Id, out var counter) && counter.Value > 0) + { + Found = true; + Value = counter.Value; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Metrics/TransportBytesMetricsTests.cs.meta b/com.unity.netcode.gameobjects/Tests/Runtime/Metrics/TransportBytesMetricsTests.cs.meta new file mode 100644 index 0000000000..2cfb1f3a0b --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Metrics/TransportBytesMetricsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a8be98b50d230114f853054c479341ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/testproject-tools-integration/Packages/manifest.json b/testproject-tools-integration/Packages/manifest.json index e13395beba..e3ff4cbc20 100644 --- a/testproject-tools-integration/Packages/manifest.json +++ b/testproject-tools-integration/Packages/manifest.json @@ -3,7 +3,7 @@ "dependencies": { "com.unity.ide.rider": "3.0.7", "com.unity.netcode.gameobjects": "file:../../com.unity.netcode.gameobjects", - "com.unity.multiplayer.tools": "0.0.1-preview.6", + "com.unity.multiplayer.tools": "0.0.1-preview.7", "com.unity.multiplayer.transport.utp": "file:../../com.unity.multiplayer.transport.utp", "com.unity.test-framework": "1.1.26", "com.unity.modules.ai": "1.0.0",