3
0

MultiplayerDebugNetworkMetrics.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Source/Debug/MultiplayerDebugNetworkMetrics.h>
  9. #include <AzNetworking/Framework/INetworking.h>
  10. namespace Multiplayer
  11. {
  12. #ifdef IMGUI_ENABLED
  13. void MultiplayerDebugNetworkMetrics::OnImGuiUpdate()
  14. {
  15. const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
  16. const ImGuiTableFlags flags = ImGuiTableFlags_BordersV
  17. | ImGuiTableFlags_BordersOuterH
  18. | ImGuiTableFlags_Resizable
  19. | ImGuiTableFlags_RowBg
  20. | ImGuiTableFlags_NoBordersInBody;
  21. const ImGuiTreeNodeFlags nodeFlags = (ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
  22. AzNetworking::INetworking* networking = AZ::Interface<AzNetworking::INetworking>::Get();
  23. ImGui::Text("Total sockets monitored by TcpListenThread: %u", networking->GetTcpListenThreadSocketCount());
  24. ImGui::Text("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(networking->GetTcpListenThreadUpdateTime()));
  25. ImGui::Text("Total sockets monitored by UdpReaderThread: %u", networking->GetUdpReaderThreadSocketCount());
  26. ImGui::Text("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(networking->GetUdpReaderThreadUpdateTime()));
  27. ImGui::NewLine();
  28. for (auto& networkInterface : networking->GetNetworkInterfaces())
  29. {
  30. const AZ::Name& name = networkInterface.first;
  31. const AzNetworking::NetworkInterfaceMetrics& metrics = networkInterface.second->GetMetrics();
  32. const bool needsInit = m_sendHistograms.find(name) == m_sendHistograms.end();
  33. NetworkMetricDisplay& sendHistogram = m_sendHistograms[name];
  34. NetworkMetricDisplay& recvHistogram = m_recvHistograms[name];
  35. if (needsInit)
  36. {
  37. AZ::CVarFixedString sendName = name.GetCStr();
  38. sendName += " Send (Bytes/Sec)";
  39. sendHistogram.m_histogram.Init(sendName.c_str(), 250, ImGui::LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 100.0f);
  40. AZ::CVarFixedString recvName = name.GetCStr();
  41. recvName += " Receive (Bytes/Sec)";
  42. recvHistogram.m_histogram.Init(recvName.c_str(), 250, ImGui::LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 100.0f);
  43. }
  44. sendHistogram.m_histogram.PushValue(aznumeric_cast<float>(metrics.m_sendBytes - sendHistogram.m_lastValue));
  45. sendHistogram.m_lastValue = metrics.m_sendBytes;
  46. recvHistogram.m_histogram.PushValue(aznumeric_cast<float>(metrics.m_recvBytes - recvHistogram.m_lastValue));
  47. recvHistogram.m_lastValue = metrics.m_recvBytes;
  48. if (ImGui::CollapsingHeader(networkInterface.second->GetName().GetCStr()))
  49. {
  50. const char* protocol = networkInterface.second->GetType() == AzNetworking::ProtocolType::Tcp ? "Tcp" : "Udp";
  51. const char* trustZone = networkInterface.second->GetTrustZone() == AzNetworking::TrustZone::ExternalClientToServer ? "ExternalClientToServer" : "InternalServerToServer";
  52. const uint32_t port = aznumeric_cast<uint32_t>(networkInterface.second->GetPort());
  53. ImGui::Text("%sNetworkInterface open to %s on port %u", protocol, trustZone, port);
  54. sendHistogram.m_histogram.Draw(ImGui::GetColumnWidth(), 100.0f);
  55. recvHistogram.m_histogram.Draw(ImGui::GetColumnWidth(), 100.0f);
  56. if (ImGui::BeginTable("Traffic Details", 2, flags))
  57. {
  58. ImGui::TableSetupColumn("Stat", ImGuiTableColumnFlags_WidthStretch);
  59. ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 12.0f);
  60. ImGui::TableHeadersRow();
  61. ImGui::TableNextRow(); ImGui::TableNextColumn();
  62. ImGui::Text("Total time spent updating (ms)");
  63. ImGui::TableNextColumn();
  64. ImGui::Text("%lld", aznumeric_cast<AZ::s64>(metrics.m_updateTimeMs));
  65. ImGui::TableNextRow(); ImGui::TableNextColumn();
  66. ImGui::Text("Total number of connections");
  67. ImGui::TableNextColumn();
  68. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_connectionCount));
  69. ImGui::TableNextRow(); ImGui::TableNextColumn();
  70. ImGui::Text("Total send time (ms)");
  71. ImGui::TableNextColumn();
  72. ImGui::Text("%lld", aznumeric_cast<AZ::s64>(metrics.m_sendTimeMs));
  73. ImGui::TableNextRow(); ImGui::TableNextColumn();
  74. ImGui::Text("Total sent packets");
  75. ImGui::TableNextColumn();
  76. ImGui::Text("%llu", aznumeric_cast<AZ::s64>(metrics.m_sendPackets));
  77. ImGui::TableNextRow(); ImGui::TableNextColumn();
  78. ImGui::Text("Total sent bytes after compression");
  79. ImGui::TableNextColumn();
  80. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytes));
  81. ImGui::TableNextRow(); ImGui::TableNextColumn();
  82. ImGui::Text("Total sent bytes before compression");
  83. ImGui::TableNextColumn();
  84. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytesUncompressed));
  85. ImGui::TableNextRow(); ImGui::TableNextColumn();
  86. ImGui::Text("Total sent compressed packets without benefit");
  87. ImGui::TableNextColumn();
  88. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_sendCompressedPacketsNoGain));
  89. ImGui::TableNextRow(); ImGui::TableNextColumn();
  90. ImGui::Text("Total gain from packet compression");
  91. ImGui::TableNextColumn();
  92. ImGui::Text("%lld", aznumeric_cast<AZ::s64>(metrics.m_sendBytesCompressedDelta));
  93. ImGui::TableNextRow(); ImGui::TableNextColumn();
  94. ImGui::Text("Total packets resent");
  95. ImGui::TableNextColumn();
  96. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_resentPackets));
  97. ImGui::TableNextRow(); ImGui::TableNextColumn();
  98. ImGui::Text("Total receive time (ms)");
  99. ImGui::TableNextColumn();
  100. ImGui::Text("%lld", aznumeric_cast<AZ::s64>(metrics.m_recvTimeMs));
  101. ImGui::TableNextRow(); ImGui::TableNextColumn();
  102. ImGui::Text("Total received packets");
  103. ImGui::TableNextColumn();
  104. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_recvPackets));
  105. ImGui::TableNextRow(); ImGui::TableNextColumn();
  106. ImGui::Text("Total received bytes after compression");
  107. ImGui::TableNextColumn();
  108. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytes));
  109. ImGui::TableNextRow(); ImGui::TableNextColumn();
  110. ImGui::Text("Total received bytes before compression");
  111. ImGui::TableNextColumn();
  112. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytesUncompressed));
  113. ImGui::TableNextRow(); ImGui::TableNextColumn();
  114. ImGui::Text("Total packets discarded due to load");
  115. ImGui::TableNextColumn();
  116. ImGui::Text("%llu", aznumeric_cast<AZ::u64>(metrics.m_discardedPackets));
  117. ImGui::EndTable();
  118. }
  119. if (ImGui::BeginTable("Interface Overview", 7, flags))
  120. {
  121. // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On
  122. ImGui::TableSetupColumn("RemoteAddr", ImGuiTableColumnFlags_WidthStretch);
  123. ImGui::TableSetupColumn("Conn. Id", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 6.0f);
  124. ImGui::TableSetupColumn("Send (Bps)", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 10.0f);
  125. ImGui::TableSetupColumn("Recv (Bps)", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 10.0f);
  126. ImGui::TableSetupColumn("RTT (ms)", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 8.0f);
  127. ImGui::TableSetupColumn("% Lost", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 8.0f);
  128. ImGui::TableSetupColumn("Debug Settings", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 32.0f);
  129. ImGui::TableHeadersRow();
  130. auto displayConnectionRow = [](AzNetworking::IConnection& connection)
  131. {
  132. ImGui::PushID(&connection);
  133. const AzNetworking::ConnectionMetrics& metrics = connection.GetMetrics();
  134. const AzNetworking::IpAddress::IpString remoteAddr = connection.GetRemoteAddress().GetString();
  135. ImGui::TableNextRow();
  136. ImGui::TableNextColumn();
  137. ImGui::TreeNodeEx(remoteAddr.c_str(), nodeFlags);
  138. ImGui::TableNextColumn();
  139. ImGui::Text("%5llu", aznumeric_cast<AZ::u64>(connection.GetConnectionId()));
  140. ImGui::TableNextColumn();
  141. ImGui::Text("%9.2f", metrics.m_sendDatarate.GetBytesPerSecond());
  142. ImGui::TableNextColumn();
  143. ImGui::Text("%9.2f", metrics.m_recvDatarate.GetBytesPerSecond());
  144. ImGui::TableNextColumn();
  145. ImGui::Text("%7.2f", metrics.m_connectionRtt.GetRoundTripTimeSeconds() * 1000.0f);
  146. ImGui::TableNextColumn();
  147. ImGui::Text("%7.2f", metrics.m_sendDatarate.GetLossRatePercent());
  148. ImGui::TableNextColumn();
  149. {
  150. AzNetworking::ConnectionQuality& quality = connection.GetConnectionQuality();
  151. int32_t latency = aznumeric_cast<int32_t>(quality.m_latencyMs);
  152. int32_t variance = aznumeric_cast<int32_t>(quality.m_varianceMs);
  153. ImGui::SliderInt("Loss %", &quality.m_lossPercentage, 0, 100);
  154. if (ImGui::SliderInt("Latency(ms)", &latency, 0, 3000))
  155. {
  156. quality.m_latencyMs = AZ::TimeMs{ latency };
  157. }
  158. if (ImGui::SliderInt("Jitter(ms)", &variance, 0, 1000))
  159. {
  160. quality.m_varianceMs = AZ::TimeMs{ variance };
  161. }
  162. }
  163. ImGui::PopID();
  164. };
  165. networkInterface.second->GetConnectionSet().VisitConnections(displayConnectionRow);
  166. ImGui::EndTable();
  167. }
  168. }
  169. ImGui::NewLine();
  170. }
  171. ImGui::End();
  172. }
  173. #endif
  174. }