editor_network_profiler.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /**************************************************************************/
  2. /* editor_network_profiler.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "editor_network_profiler.h"
  31. #include "core/os/os.h"
  32. #include "editor_scale.h"
  33. #include "editor_settings.h"
  34. void EditorNetworkProfiler::_bind_methods() {
  35. ClassDB::bind_method(D_METHOD("_update_frame"), &EditorNetworkProfiler::_update_frame);
  36. ClassDB::bind_method(D_METHOD("_activate_pressed"), &EditorNetworkProfiler::_activate_pressed);
  37. ClassDB::bind_method(D_METHOD("_clear_pressed"), &EditorNetworkProfiler::_clear_pressed);
  38. ADD_SIGNAL(MethodInfo("enable_profiling", PropertyInfo(Variant::BOOL, "enable")));
  39. }
  40. void EditorNetworkProfiler::_notification(int p_what) {
  41. if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
  42. activate->set_icon(get_icon("Play", "EditorIcons"));
  43. clear_button->set_icon(get_icon("Clear", "EditorIcons"));
  44. incoming_bandwidth_text->set_right_icon(get_icon("ArrowDown", "EditorIcons"));
  45. outgoing_bandwidth_text->set_right_icon(get_icon("ArrowUp", "EditorIcons"));
  46. // This needs to be done here to set the faded color when the profiler is first opened
  47. incoming_bandwidth_text->add_color_override("font_color_uneditable", get_color("font_color", "Editor") * Color(1, 1, 1, 0.5));
  48. outgoing_bandwidth_text->add_color_override("font_color_uneditable", get_color("font_color", "Editor") * Color(1, 1, 1, 0.5));
  49. }
  50. }
  51. void EditorNetworkProfiler::_update_frame() {
  52. counters_display->clear();
  53. TreeItem *root = counters_display->create_item();
  54. for (Map<ObjectID, MultiplayerAPI::ProfilingInfo>::Element *E = nodes_data.front(); E; E = E->next()) {
  55. TreeItem *node = counters_display->create_item(root);
  56. for (int j = 0; j < counters_display->get_columns(); ++j) {
  57. node->set_text_align(j, j > 0 ? TreeItem::ALIGN_RIGHT : TreeItem::ALIGN_LEFT);
  58. }
  59. node->set_text(0, E->get().node_path);
  60. node->set_text(1, E->get().incoming_rpc == 0 ? "-" : itos(E->get().incoming_rpc));
  61. node->set_text(2, E->get().incoming_rset == 0 ? "-" : itos(E->get().incoming_rset));
  62. node->set_text(3, E->get().outgoing_rpc == 0 ? "-" : itos(E->get().outgoing_rpc));
  63. node->set_text(4, E->get().outgoing_rset == 0 ? "-" : itos(E->get().outgoing_rset));
  64. }
  65. }
  66. void EditorNetworkProfiler::_activate_pressed() {
  67. if (activate->is_pressed()) {
  68. activate->set_icon(get_icon("Stop", "EditorIcons"));
  69. activate->set_text(TTR("Stop"));
  70. } else {
  71. activate->set_icon(get_icon("Play", "EditorIcons"));
  72. activate->set_text(TTR("Start"));
  73. }
  74. emit_signal("enable_profiling", activate->is_pressed());
  75. }
  76. void EditorNetworkProfiler::_clear_pressed() {
  77. nodes_data.clear();
  78. set_bandwidth(0, 0);
  79. if (frame_delay->is_stopped()) {
  80. frame_delay->set_wait_time(0.1);
  81. frame_delay->start();
  82. }
  83. }
  84. void EditorNetworkProfiler::add_node_frame_data(const MultiplayerAPI::ProfilingInfo p_frame) {
  85. if (!nodes_data.has(p_frame.node)) {
  86. nodes_data.insert(p_frame.node, p_frame);
  87. } else {
  88. nodes_data[p_frame.node].incoming_rpc += p_frame.incoming_rpc;
  89. nodes_data[p_frame.node].incoming_rset += p_frame.incoming_rset;
  90. nodes_data[p_frame.node].outgoing_rpc += p_frame.outgoing_rpc;
  91. nodes_data[p_frame.node].outgoing_rset += p_frame.outgoing_rset;
  92. }
  93. if (frame_delay->is_stopped()) {
  94. frame_delay->set_wait_time(0.1);
  95. frame_delay->start();
  96. }
  97. }
  98. void EditorNetworkProfiler::set_bandwidth(int p_incoming, int p_outgoing) {
  99. incoming_bandwidth_text->set_text(vformat(TTR("%s/s"), String::humanize_size(p_incoming)));
  100. outgoing_bandwidth_text->set_text(vformat(TTR("%s/s"), String::humanize_size(p_outgoing)));
  101. // Make labels more prominent when the bandwidth is greater than 0 to attract user attention
  102. incoming_bandwidth_text->add_color_override(
  103. "font_color_uneditable",
  104. get_color("font_color", "Editor") * Color(1, 1, 1, p_incoming > 0 ? 1 : 0.5));
  105. outgoing_bandwidth_text->add_color_override(
  106. "font_color_uneditable",
  107. get_color("font_color", "Editor") * Color(1, 1, 1, p_outgoing > 0 ? 1 : 0.5));
  108. }
  109. bool EditorNetworkProfiler::is_profiling() {
  110. return activate->is_pressed();
  111. }
  112. EditorNetworkProfiler::EditorNetworkProfiler() {
  113. HBoxContainer *hb = memnew(HBoxContainer);
  114. hb->add_constant_override("separation", 8 * EDSCALE);
  115. add_child(hb);
  116. activate = memnew(Button);
  117. activate->set_toggle_mode(true);
  118. activate->set_text(TTR("Start"));
  119. activate->connect("pressed", this, "_activate_pressed");
  120. hb->add_child(activate);
  121. clear_button = memnew(Button);
  122. clear_button->set_text(TTR("Clear"));
  123. clear_button->connect("pressed", this, "_clear_pressed");
  124. hb->add_child(clear_button);
  125. hb->add_spacer();
  126. Label *lb = memnew(Label);
  127. lb->set_text(TTR("Down"));
  128. hb->add_child(lb);
  129. incoming_bandwidth_text = memnew(LineEdit);
  130. incoming_bandwidth_text->set_editable(false);
  131. incoming_bandwidth_text->set_custom_minimum_size(Size2(120, 0) * EDSCALE);
  132. incoming_bandwidth_text->set_align(LineEdit::Align::ALIGN_RIGHT);
  133. hb->add_child(incoming_bandwidth_text);
  134. Control *down_up_spacer = memnew(Control);
  135. down_up_spacer->set_custom_minimum_size(Size2(30, 0) * EDSCALE);
  136. hb->add_child(down_up_spacer);
  137. lb = memnew(Label);
  138. lb->set_text(TTR("Up"));
  139. hb->add_child(lb);
  140. outgoing_bandwidth_text = memnew(LineEdit);
  141. outgoing_bandwidth_text->set_editable(false);
  142. outgoing_bandwidth_text->set_custom_minimum_size(Size2(120, 0) * EDSCALE);
  143. outgoing_bandwidth_text->set_align(LineEdit::Align::ALIGN_RIGHT);
  144. hb->add_child(outgoing_bandwidth_text);
  145. // Set initial texts in the incoming/outgoing bandwidth labels
  146. set_bandwidth(0, 0);
  147. counters_display = memnew(Tree);
  148. counters_display->set_custom_minimum_size(Size2(300, 0) * EDSCALE);
  149. counters_display->set_v_size_flags(SIZE_EXPAND_FILL);
  150. counters_display->set_hide_folding(true);
  151. counters_display->set_hide_root(true);
  152. counters_display->set_columns(5);
  153. counters_display->set_column_titles_visible(true);
  154. counters_display->set_column_title(0, TTR("Node"));
  155. counters_display->set_column_expand(0, true);
  156. counters_display->set_column_min_width(0, 60 * EDSCALE);
  157. counters_display->set_column_title(1, TTR("Incoming RPC"));
  158. counters_display->set_column_expand(1, false);
  159. counters_display->set_column_min_width(1, 120 * EDSCALE);
  160. counters_display->set_column_title(2, TTR("Incoming RSET"));
  161. counters_display->set_column_expand(2, false);
  162. counters_display->set_column_min_width(2, 120 * EDSCALE);
  163. counters_display->set_column_title(3, TTR("Outgoing RPC"));
  164. counters_display->set_column_expand(3, false);
  165. counters_display->set_column_min_width(3, 120 * EDSCALE);
  166. counters_display->set_column_title(4, TTR("Outgoing RSET"));
  167. counters_display->set_column_expand(4, false);
  168. counters_display->set_column_min_width(4, 120 * EDSCALE);
  169. add_child(counters_display);
  170. frame_delay = memnew(Timer);
  171. frame_delay->set_wait_time(0.1);
  172. frame_delay->set_one_shot(true);
  173. add_child(frame_delay);
  174. frame_delay->connect("timeout", this, "_update_frame");
  175. }