Add objects replication and RPC stats table to Network Profiler

This commit is contained in:
Wojtek Figat
2023-09-26 10:33:12 +02:00
parent da47088250
commit 6621e70ae7
10 changed files with 343 additions and 34 deletions

View File

@@ -3,6 +3,9 @@
#pragma once
#include "Types.h"
#if COMPILE_WITH_PROFILER
#include "Engine/Core/Collections/Dictionary.h"
#endif
enum class NetworkMessageIDs : uint8
{
@@ -35,4 +38,22 @@ public:
static void OnNetworkMessageObjectDespawn(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
static void OnNetworkMessageObjectRole(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
static void OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
#if COMPILE_WITH_PROFILER
struct ProfilerEvent
{
uint16 Count = 0;
uint16 DataSize = 0;
uint16 MessageSize = 0;
uint16 Receivers = 0;
};
/// <summary>
/// Enables network usage profiling tools. Captures network objects replication and RPCs send statistics.
/// </summary>
static bool EnableProfiling;
static Dictionary<Pair<ScriptingTypeHandle, StringAnsiView>, ProfilerEvent> ProfilerEvents;
#endif
};

View File

@@ -40,6 +40,11 @@ bool NetworkReplicator::EnableLog = false;
#define NETWORK_REPLICATOR_LOG(messageType, format, ...)
#endif
#if COMPILE_WITH_PROFILER
bool NetworkInternal::EnableProfiling = false;
Dictionary<Pair<ScriptingTypeHandle, StringAnsiView>, NetworkInternal::ProfilerEvent> NetworkInternal::ProfilerEvents;
#endif
PACK_STRUCT(struct NetworkMessageObjectReplicate
{
NetworkMessageIDs ID = NetworkMessageIDs::ObjectReplicate;
@@ -1806,6 +1811,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
NetworkMessage msg = peer->BeginSendMessage();
msg.WriteStructure(msgData);
msg.WriteBytes(stream->GetBuffer(), msgDataSize);
uint32 dataSize = msgDataSize, messageSize = msg.Length;
if (isClient)
peer->EndSendMessage(NetworkChannelType::Unreliable, msg);
else
@@ -1824,6 +1830,8 @@ void NetworkInternal::NetworkReplicatorUpdate()
msg = peer->BeginSendMessage();
msg.WriteStructure(msgDataPart);
msg.WriteBytes(stream->GetBuffer() + msgDataPart.PartStart, msgDataPart.PartSize);
messageSize += msg.Length;
dataSize += msgDataPart.PartSize;
dataStart += msgDataPart.PartSize;
if (isClient)
peer->EndSendMessage(NetworkChannelType::Unreliable, msg);
@@ -1832,7 +1840,18 @@ void NetworkInternal::NetworkReplicatorUpdate()
}
ASSERT_LOW_LAYER(dataStart == size);
// TODO: stats for bytes send per object type
#if COMPILE_WITH_PROFILER
// Network stats recording
if (EnableProfiling)
{
const Pair<ScriptingTypeHandle, StringAnsiView> name(obj->GetTypeHandle(), StringAnsiView::Empty);
auto& profileEvent = ProfilerEvents[name];
profileEvent.Count++;
profileEvent.DataSize += dataSize;
profileEvent.MessageSize += messageSize;
profileEvent.Receivers += isClient ? 1 : CachedTargets.Count();
}
#endif
}
}
@@ -1873,6 +1892,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
NetworkMessage msg = peer->BeginSendMessage();
msg.WriteStructure(msgData);
msg.WriteBytes(e.ArgsData.Get(), e.ArgsData.Length());
uint32 dataSize = e.ArgsData.Length(), messageSize = msg.Length, receivers = 0;
NetworkChannelType channel = (NetworkChannelType)e.Info.Channel;
if (e.Info.Server && isClient)
{
@@ -1882,13 +1902,27 @@ void NetworkInternal::NetworkReplicatorUpdate()
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Server RPC '{}::{}' called with non-empty list of targets is not supported (only server will receive it)", e.Name.First.ToString(), e.Name.Second.ToString());
#endif
peer->EndSendMessage(channel, msg);
receivers = 1;
}
else if (e.Info.Client && (isServer || isHost))
{
// Server -> Client(s)
BuildCachedTargets(NetworkManager::Clients, item.TargetClientIds, e.Targets, NetworkManager::LocalClientId);
peer->EndSendMessage(channel, msg, CachedTargets);
receivers = CachedTargets.Count();
}
#if COMPILE_WITH_PROFILER
// Network stats recording
if (EnableProfiling && receivers)
{
auto& profileEvent = ProfilerEvents[e.Name];
profileEvent.Count++;
profileEvent.DataSize += dataSize;
profileEvent.MessageSize += messageSize;
profileEvent.Receivers += receivers;
}
#endif
}
RpcQueue.Clear();
}

View File

@@ -3,14 +3,17 @@
#if COMPILE_WITH_PROFILER
#include "ProfilingTools.h"
#include "Engine/Core/Types/Pair.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/Time.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Networking/NetworkInternal.h"
ProfilingTools::MainStats ProfilingTools::Stats;
Array<ProfilingTools::ThreadStats, InlinedAllocation<64>> ProfilingTools::EventsCPU;
Array<ProfilerGPU::Event> ProfilingTools::EventsGPU;
Array<ProfilingTools::NetworkEventStat> ProfilingTools::EventsNetwork;
class ProfilingToolsService : public EngineService
{
@@ -120,6 +123,40 @@ void ProfilingToolsService::Update()
frame.Extract(ProfilingTools::EventsGPU);
}
// Get the last events from networking runtime
{
auto& networkEvents = ProfilingTools::EventsNetwork;
networkEvents.Resize(NetworkInternal::ProfilerEvents.Count());
int32 i = 0;
for (const auto& e : NetworkInternal::ProfilerEvents)
{
const auto& src = e.Value;
auto& dst = networkEvents[i++];
dst.Count = src.Count;
dst.DataSize = src.DataSize;
dst.MessageSize = src.MessageSize;
dst.Receivers = src.Receivers;
const StringAnsiView& typeName = e.Key.First.GetType().Fullname;
uint64 len = Math::Min<uint64>(typeName.Length(), ARRAY_COUNT(dst.Name) - 10);
Platform::MemoryCopy(dst.Name, typeName.Get(), len);
const StringAnsiView& name = e.Key.Second;
if (name.HasChars())
{
uint64 pos = len;
dst.Name[pos++] = ':';
dst.Name[pos++] = ':';
len = Math::Min<uint64>(name.Length(), ARRAY_COUNT(dst.Name) - pos - 1);
Platform::MemoryCopy(dst.Name + pos, name.Get(), len);
dst.Name[pos + len] = 0;
}
else
{
dst.Name[len] = 0;
}
}
NetworkInternal::ProfilerEvents.Clear();
}
#if 0
// Print CPU events to the log
{
@@ -173,6 +210,7 @@ void ProfilingToolsService::Dispose()
ProfilingTools::EventsCPU.Clear();
ProfilingTools::EventsCPU.SetCapacity(0);
ProfilingTools::EventsGPU.SetCapacity(0);
ProfilingTools::EventsNetwork.SetCapacity(0);
}
bool ProfilingTools::GetEnabled()
@@ -184,6 +222,7 @@ void ProfilingTools::SetEnabled(bool enabled)
{
ProfilerCPU::Enabled = enabled;
ProfilerGPU::Enabled = enabled;
NetworkInternal::EnableProfiling = enabled;
}
#endif

View File

@@ -105,6 +105,24 @@ public:
API_FIELD() Array<ProfilerCPU::Event> Events;
};
/// <summary>
/// The network stat.
/// </summary>
API_STRUCT(NoDefault) struct NetworkEventStat
{
DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkEventStat);
// Amount of occurrences.
API_FIELD() uint16 Count;
// Transferred data size (in bytes).
API_FIELD() uint16 DataSize;
// Transferred message (data+header) size (in bytes).
API_FIELD() uint16 MessageSize;
// Amount of peers that will receive this message.
API_FIELD() uint16 Receivers;
API_FIELD(Private, NoArray) byte Name[120];
};
public:
/// <summary>
/// Controls the engine profiler (CPU, GPU, etc.) usage.
@@ -130,6 +148,11 @@ public:
/// The GPU rendering profiler events.
/// </summary>
API_FIELD(ReadOnly) static Array<ProfilerGPU::Event> EventsGPU;
/// <summary>
/// The networking profiler events.
/// </summary>
API_FIELD(ReadOnly) static Array<NetworkEventStat> EventsNetwork;
};
#endif