diff options
Diffstat (limited to 'editor')
-rw-r--r-- | editor/editor_network_profiler.cpp | 208 | ||||
-rw-r--r-- | editor/editor_network_profiler.h | 73 | ||||
-rw-r--r-- | editor/script_editor_debugger.cpp | 47 | ||||
-rw-r--r-- | editor/script_editor_debugger.h | 4 |
4 files changed, 331 insertions, 1 deletions
diff --git a/editor/editor_network_profiler.cpp b/editor/editor_network_profiler.cpp new file mode 100644 index 0000000000..5666448887 --- /dev/null +++ b/editor/editor_network_profiler.cpp @@ -0,0 +1,208 @@ +/*************************************************************************/ +/* editor_network_profiler.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_network_profiler.h" + +#include "core/os/os.h" +#include "editor_scale.h" +#include "editor_settings.h" + +void EditorNetworkProfiler::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_frame"), &EditorNetworkProfiler::_update_frame); + ClassDB::bind_method(D_METHOD("_activate_pressed"), &EditorNetworkProfiler::_activate_pressed); + ClassDB::bind_method(D_METHOD("_clear_pressed"), &EditorNetworkProfiler::_clear_pressed); + ADD_SIGNAL(MethodInfo("enable_profiling", PropertyInfo(Variant::BOOL, "enable"))); +} + +void EditorNetworkProfiler::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + activate->set_icon(get_icon("Play", "EditorIcons")); + clear_button->set_icon(get_icon("Clear", "EditorIcons")); + } +} + +void EditorNetworkProfiler::_update_frame() { + + counters_display->clear(); + + TreeItem *root = counters_display->create_item(); + + for (Map<ObjectID, MultiplayerAPI::ProfilingInfo>::Element *E = nodes_data.front(); E; E = E->next()) { + + TreeItem *node = counters_display->create_item(root); + + for (int j = 0; j < counters_display->get_columns(); ++j) { + node->set_text_align(j, j > 0 ? TreeItem::ALIGN_RIGHT : TreeItem::ALIGN_LEFT); + } + + node->set_text(0, E->get().node_path); + node->set_text(1, E->get().incoming_rpc == 0 ? "-" : itos(E->get().incoming_rpc)); + node->set_text(2, E->get().incoming_rset == 0 ? "-" : itos(E->get().incoming_rset)); + node->set_text(3, E->get().outgoing_rpc == 0 ? "-" : itos(E->get().outgoing_rpc)); + node->set_text(4, E->get().outgoing_rset == 0 ? "-" : itos(E->get().outgoing_rset)); + } +} + +void EditorNetworkProfiler::_activate_pressed() { + + if (activate->is_pressed()) { + activate->set_icon(get_icon("Stop", "EditorIcons")); + activate->set_text(TTR("Stop")); + } else { + activate->set_icon(get_icon("Play", "EditorIcons")); + activate->set_text(TTR("Start")); + } + emit_signal("enable_profiling", activate->is_pressed()); +} + +void EditorNetworkProfiler::_clear_pressed() { + nodes_data.clear(); + set_bandwidth(0, 0); + if (frame_delay->is_stopped()) { + frame_delay->set_wait_time(0.1); + frame_delay->start(); + } +} + +String EditorNetworkProfiler::_format_bandwidth(int p_value) { + String unit = "B"; + float v = p_value; + if (v > 1073741824.0) { + unit = "GiB"; + v /= 1073741824.0; + } else if (v > 1048576.0) { + unit = "MiB"; + v /= 1048576.0; + } else if (v > 1024.0) { + unit = "KiB"; + v /= 1024.0; + } + return vformat("%.1f %s/s", v, unit); +} + +void EditorNetworkProfiler::add_node_frame_data(const MultiplayerAPI::ProfilingInfo p_frame) { + + if (!nodes_data.has(p_frame.node)) { + nodes_data.insert(p_frame.node, p_frame); + } else { + nodes_data[p_frame.node].incoming_rpc += p_frame.incoming_rpc; + nodes_data[p_frame.node].incoming_rset += p_frame.incoming_rset; + nodes_data[p_frame.node].outgoing_rpc += p_frame.outgoing_rpc; + nodes_data[p_frame.node].outgoing_rset += p_frame.outgoing_rset; + } + + if (frame_delay->is_stopped()) { + frame_delay->set_wait_time(0.1); + frame_delay->start(); + } +} + +void EditorNetworkProfiler::set_bandwidth(int p_incoming, int p_outgoing) { + + incoming_bandwidth_text->set_text(_format_bandwidth(p_incoming)); + outgoing_bandwidth_text->set_text(_format_bandwidth(p_outgoing)); +} + +bool EditorNetworkProfiler::is_profiling() { + return activate->is_pressed(); +} + +EditorNetworkProfiler::EditorNetworkProfiler() { + + HBoxContainer *hb = memnew(HBoxContainer); + hb->add_constant_override("separation", 8 * EDSCALE); + add_child(hb); + + activate = memnew(Button); + activate->set_toggle_mode(true); + activate->set_text(TTR("Start")); + activate->connect("pressed", this, "_activate_pressed"); + hb->add_child(activate); + + clear_button = memnew(Button); + clear_button->set_text(TTR("Clear")); + clear_button->connect("pressed", this, "_clear_pressed"); + hb->add_child(clear_button); + + hb->add_spacer(); + + Label *lb = memnew(Label); + lb->set_text("Down "); + hb->add_child(lb); + + incoming_bandwidth_text = memnew(LineEdit); + incoming_bandwidth_text->set_editable(false); + incoming_bandwidth_text->set_custom_minimum_size(Size2(100, 0)); + incoming_bandwidth_text->set_align(LineEdit::Align::ALIGN_RIGHT); + incoming_bandwidth_text->set_text("0.0 B/s"); + hb->add_child(incoming_bandwidth_text); + + lb = memnew(Label); + lb->set_text("Up "); + hb->add_child(lb); + + outgoing_bandwidth_text = memnew(LineEdit); + outgoing_bandwidth_text->set_editable(false); + outgoing_bandwidth_text->set_custom_minimum_size(Size2(100, 0)); + outgoing_bandwidth_text->set_align(LineEdit::Align::ALIGN_RIGHT); + outgoing_bandwidth_text->set_text("0.0 B/s"); + hb->add_child(outgoing_bandwidth_text); + + counters_display = memnew(Tree); + counters_display->set_custom_minimum_size(Size2(300, 0) * EDSCALE); + counters_display->set_v_size_flags(SIZE_EXPAND_FILL); + counters_display->set_hide_folding(true); + counters_display->set_hide_root(true); + counters_display->set_columns(5); + counters_display->set_column_titles_visible(true); + counters_display->set_column_title(0, TTR("Node")); + counters_display->set_column_expand(0, true); + counters_display->set_column_min_width(0, 60); + counters_display->set_column_title(1, TTR("Incoming RPC")); + counters_display->set_column_expand(1, false); + counters_display->set_column_min_width(1, 120 * EDSCALE); + counters_display->set_column_title(2, TTR("Incoming RSET")); + counters_display->set_column_expand(2, false); + counters_display->set_column_min_width(2, 120 * EDSCALE); + counters_display->set_column_title(3, TTR("Outgoing RPC")); + counters_display->set_column_expand(3, false); + counters_display->set_column_min_width(3, 120 * EDSCALE); + counters_display->set_column_title(4, TTR("Outgoing RSET")); + counters_display->set_column_expand(4, false); + counters_display->set_column_min_width(4, 120 * EDSCALE); + add_child(counters_display); + + frame_delay = memnew(Timer); + frame_delay->set_wait_time(0.1); + frame_delay->set_one_shot(true); + add_child(frame_delay); + frame_delay->connect("timeout", this, "_update_frame"); +} diff --git a/editor/editor_network_profiler.h b/editor/editor_network_profiler.h new file mode 100644 index 0000000000..5046741cbc --- /dev/null +++ b/editor/editor_network_profiler.h @@ -0,0 +1,73 @@ +/*************************************************************************/ +/* editor_network_profiler.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITORNETWORKPROFILER_H +#define EDITORNETWORKPROFILER_H + +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/split_container.h" +#include "scene/gui/tree.h" + +class EditorNetworkProfiler : public VBoxContainer { + + GDCLASS(EditorNetworkProfiler, VBoxContainer) + +private: + Button *activate; + Button *clear_button; + Tree *counters_display; + LineEdit *incoming_bandwidth_text; + LineEdit *outgoing_bandwidth_text; + + Timer *frame_delay; + + Map<ObjectID, MultiplayerAPI::ProfilingInfo> nodes_data; + + void _update_frame(); + + void _activate_pressed(); + void _clear_pressed(); + String _format_bandwidth(int p_value); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void add_node_frame_data(const MultiplayerAPI::ProfilingInfo p_frame); + void set_bandwidth(int p_incoming, int p_outgoing); + bool is_profiling(); + + EditorNetworkProfiler(); +}; + +#endif //EDITORNETWORKPROFILER_H diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index fc5aecdbe9..b4b740b28d 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -33,6 +33,7 @@ #include "core/io/marshalls.h" #include "core/project_settings.h" #include "core/ustring.h" +#include "editor_network_profiler.h" #include "editor_node.h" #include "editor_profiler.h" #include "editor_settings.h" @@ -977,7 +978,20 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da profiler->add_frame_metric(metric, false); else profiler->add_frame_metric(metric, true); - + } else if (p_msg == "network_profile") { + int frame_size = 6; + for (int i = 0; i < p_data.size(); i += frame_size) { + MultiplayerAPI::ProfilingInfo pi; + pi.node = p_data[i + 0]; + pi.node_path = p_data[i + 1]; + pi.incoming_rpc = p_data[i + 2]; + pi.incoming_rset = p_data[i + 3]; + pi.outgoing_rpc = p_data[i + 4]; + pi.outgoing_rset = p_data[i + 5]; + network_profiler->add_node_frame_data(pi); + } + } else if (p_msg == "network_bandwidth") { + network_profiler->set_bandwidth(p_data[0], p_data[1]); } else if (p_msg == "kill_me") { editor->call_deferred("stop_child_process"); @@ -1193,6 +1207,10 @@ void ScriptEditorDebugger::_notification(int p_what) { if (profiler->is_profiling()) { _profiler_activate(true); } + + if (network_profiler->is_profiling()) { + _network_profiler_activate(true); + } } } @@ -1412,6 +1430,25 @@ void ScriptEditorDebugger::_profiler_activate(bool p_enable) { } } +void ScriptEditorDebugger::_network_profiler_activate(bool p_enable) { + + if (!connection.is_valid()) + return; + + if (p_enable) { + Array msg; + msg.push_back("start_network_profiling"); + ppeer->put_var(msg); + print_verbose("Starting network profiling."); + + } else { + Array msg; + msg.push_back("stop_network_profiling"); + ppeer->put_var(msg); + print_verbose("Ending network profiling."); + } +} + void ScriptEditorDebugger::_profiler_seeked() { if (!connection.is_valid() || !connection->is_connected_to_host()) @@ -2000,6 +2037,7 @@ void ScriptEditorDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("_expand_errors_list"), &ScriptEditorDebugger::_expand_errors_list); ClassDB::bind_method(D_METHOD("_collapse_errors_list"), &ScriptEditorDebugger::_collapse_errors_list); ClassDB::bind_method(D_METHOD("_profiler_activate"), &ScriptEditorDebugger::_profiler_activate); + ClassDB::bind_method(D_METHOD("_network_profiler_activate"), &ScriptEditorDebugger::_network_profiler_activate); ClassDB::bind_method(D_METHOD("_profiler_seeked"), &ScriptEditorDebugger::_profiler_seeked); ClassDB::bind_method(D_METHOD("_clear_errors_list"), &ScriptEditorDebugger::_clear_errors_list); @@ -2218,6 +2256,13 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { profiler->connect("break_request", this, "_profiler_seeked"); } + { //network profiler + network_profiler = memnew(EditorNetworkProfiler); + network_profiler->set_name(TTR("Network Profiler")); + tabs->add_child(network_profiler); + network_profiler->connect("enable_profiling", this, "_network_profiler_activate"); + } + { //monitors HSplitContainer *hsp = memnew(HSplitContainer); diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index 947b0cca52..812afd6990 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -50,6 +50,7 @@ class TreeItem; class HSplitContainer; class ItemList; class EditorProfiler; +class EditorNetworkProfiler; class ScriptEditorDebuggerInspectedObject; @@ -152,6 +153,7 @@ class ScriptEditorDebugger : public Control { Map<String, int> res_path_cache; EditorProfiler *profiler; + EditorNetworkProfiler *network_profiler; EditorNode *editor; @@ -196,6 +198,8 @@ class ScriptEditorDebugger : public Control { void _profiler_activate(bool p_enable); void _profiler_seeked(); + void _network_profiler_activate(bool p_enable); + void _paused(); void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj); |