Merge pull request #31870 from JFonS/add_network_profiler
Add network profiler
This commit is contained in:
commit
768d637a1b
10 changed files with 579 additions and 1 deletions
|
@ -33,6 +33,10 @@
|
||||||
#include "core/io/marshalls.h"
|
#include "core/io/marshalls.h"
|
||||||
#include "scene/main/node.h"
|
#include "scene/main/node.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
#include "core/os/os.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
_FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) {
|
_FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) {
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
@ -166,6 +170,14 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_
|
||||||
ERR_FAIL_COND_MSG(root_node == NULL, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it.");
|
ERR_FAIL_COND_MSG(root_node == NULL, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it.");
|
||||||
ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small.");
|
ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small.");
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (profiling) {
|
||||||
|
bandwidth_incoming_data.write[bandwidth_incoming_pointer].timestamp = OS::get_singleton()->get_ticks_msec();
|
||||||
|
bandwidth_incoming_data.write[bandwidth_incoming_pointer].packet_size = p_packet_len;
|
||||||
|
bandwidth_incoming_pointer = (bandwidth_incoming_pointer + 1) % bandwidth_incoming_data.size();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t packet_type = p_packet[0];
|
uint8_t packet_type = p_packet[0];
|
||||||
|
|
||||||
switch (packet_type) {
|
switch (packet_type) {
|
||||||
|
@ -284,6 +296,14 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
|
||||||
|
|
||||||
p_offset++;
|
p_offset++;
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (profiling) {
|
||||||
|
ObjectID id = p_node->get_instance_id();
|
||||||
|
_init_node_profile(id);
|
||||||
|
profiler_frame_data[id].incoming_rpc += 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
|
|
||||||
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
|
ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small.");
|
||||||
|
@ -322,6 +342,14 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
|
||||||
bool can_call = _can_call_mode(p_node, rset_mode, p_from);
|
bool can_call = _can_call_mode(p_node, rset_mode, p_from);
|
||||||
ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
|
ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (profiling) {
|
||||||
|
ObjectID id = p_node->get_instance_id();
|
||||||
|
_init_node_profile(id);
|
||||||
|
profiler_frame_data[id].incoming_rset += 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Variant value;
|
Variant value;
|
||||||
Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());
|
Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());
|
||||||
|
|
||||||
|
@ -512,6 +540,14 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (profiling) {
|
||||||
|
bandwidth_outgoing_data.write[bandwidth_outgoing_pointer].timestamp = OS::get_singleton()->get_ticks_msec();
|
||||||
|
bandwidth_outgoing_data.write[bandwidth_outgoing_pointer].packet_size = ofs;
|
||||||
|
bandwidth_outgoing_pointer = (bandwidth_outgoing_pointer + 1) % bandwidth_outgoing_data.size();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// See if all peers have cached path (is so, call can be fast).
|
// See if all peers have cached path (is so, call can be fast).
|
||||||
bool has_all_peers = _send_confirm_path(from_path, psc, p_to);
|
bool has_all_peers = _send_confirm_path(from_path, psc, p_to);
|
||||||
|
|
||||||
|
@ -615,6 +651,15 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip_rpc) {
|
if (!skip_rpc) {
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (profiling) {
|
||||||
|
ObjectID id = p_node->get_instance_id();
|
||||||
|
_init_node_profile(id);
|
||||||
|
profiler_frame_data[id].outgoing_rpc += 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
_send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount);
|
_send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,6 +754,14 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (profiling) {
|
||||||
|
ObjectID id = p_node->get_instance_id();
|
||||||
|
_init_node_profile(id);
|
||||||
|
profiler_frame_data[id].outgoing_rset += 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const Variant *vptr = &p_value;
|
const Variant *vptr = &p_value;
|
||||||
|
|
||||||
_send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1);
|
_send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1);
|
||||||
|
@ -792,6 +845,96 @@ bool MultiplayerAPI::is_object_decoding_allowed() const {
|
||||||
return allow_object_decoding;
|
return allow_object_decoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiplayerAPI::profiling_start() {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
profiling = true;
|
||||||
|
profiler_frame_data.clear();
|
||||||
|
|
||||||
|
bandwidth_incoming_pointer = 0;
|
||||||
|
bandwidth_incoming_data.resize(16384); // ~128kB
|
||||||
|
for (int i = 0; i < bandwidth_incoming_data.size(); ++i) {
|
||||||
|
bandwidth_incoming_data.write[i].packet_size = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bandwidth_outgoing_pointer = 0;
|
||||||
|
bandwidth_outgoing_data.resize(16384); // ~128kB
|
||||||
|
for (int i = 0; i < bandwidth_outgoing_data.size(); ++i) {
|
||||||
|
bandwidth_outgoing_data.write[i].packet_size = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiplayerAPI::profiling_end() {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
profiling = false;
|
||||||
|
bandwidth_incoming_data.clear();
|
||||||
|
bandwidth_outgoing_data.clear();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int MultiplayerAPI::get_profiling_frame(ProfilingInfo *r_info) {
|
||||||
|
int i = 0;
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
for (Map<ObjectID, ProfilingInfo>::Element *E = profiler_frame_data.front(); E; E = E->next()) {
|
||||||
|
r_info[i] = E->get();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
profiler_frame_data.clear();
|
||||||
|
#endif
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MultiplayerAPI::get_incoming_bandwidth_usage() {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
return _get_bandwidth_usage(bandwidth_incoming_data, bandwidth_incoming_pointer);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int MultiplayerAPI::get_outgoing_bandwidth_usage() {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
return _get_bandwidth_usage(bandwidth_outgoing_data, bandwidth_outgoing_pointer);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
int MultiplayerAPI::_get_bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) {
|
||||||
|
int total_bandwidth = 0;
|
||||||
|
|
||||||
|
uint32_t timestamp = OS::get_singleton()->get_ticks_msec();
|
||||||
|
uint32_t final_timestamp = timestamp - 1000;
|
||||||
|
|
||||||
|
int i = (p_pointer + p_buffer.size() - 1) % p_buffer.size();
|
||||||
|
|
||||||
|
while (i != p_pointer && p_buffer[i].packet_size > 0) {
|
||||||
|
if (p_buffer[i].timestamp < final_timestamp) {
|
||||||
|
return total_bandwidth;
|
||||||
|
}
|
||||||
|
total_bandwidth += p_buffer[i].packet_size;
|
||||||
|
i = (i + p_buffer.size() - 1) % p_buffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_EXPLAIN("Reached the end of the bandwidth profiler buffer, values might be inaccurate.");
|
||||||
|
ERR_FAIL_COND_V(i == p_pointer, total_bandwidth);
|
||||||
|
return total_bandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiplayerAPI::_init_node_profile(ObjectID p_node) {
|
||||||
|
if (profiler_frame_data.has(p_node))
|
||||||
|
return;
|
||||||
|
profiler_frame_data.insert(p_node, ProfilingInfo());
|
||||||
|
profiler_frame_data[p_node].node = p_node;
|
||||||
|
profiler_frame_data[p_node].node_path = Object::cast_to<Node>(ObjectDB::get_instance(p_node))->get_path();
|
||||||
|
profiler_frame_data[p_node].incoming_rpc = 0;
|
||||||
|
profiler_frame_data[p_node].incoming_rset = 0;
|
||||||
|
profiler_frame_data[p_node].outgoing_rpc = 0;
|
||||||
|
profiler_frame_data[p_node].outgoing_rset = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void MultiplayerAPI::_bind_methods() {
|
void MultiplayerAPI::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
|
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
|
||||||
ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
|
ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
|
||||||
|
@ -842,6 +985,9 @@ MultiplayerAPI::MultiplayerAPI() :
|
||||||
allow_object_decoding(false) {
|
allow_object_decoding(false) {
|
||||||
rpc_sender_id = 0;
|
rpc_sender_id = 0;
|
||||||
root_node = NULL;
|
root_node = NULL;
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
profiling = false;
|
||||||
|
#endif
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,16 @@ class MultiplayerAPI : public Reference {
|
||||||
|
|
||||||
GDCLASS(MultiplayerAPI, Reference);
|
GDCLASS(MultiplayerAPI, Reference);
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct ProfilingInfo {
|
||||||
|
ObjectID node;
|
||||||
|
String node_path;
|
||||||
|
int incoming_rpc;
|
||||||
|
int incoming_rset;
|
||||||
|
int outgoing_rpc;
|
||||||
|
int outgoing_rset;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//path sent caches
|
//path sent caches
|
||||||
struct PathSentCache {
|
struct PathSentCache {
|
||||||
|
@ -55,6 +65,23 @@ private:
|
||||||
Map<int, NodeInfo> nodes;
|
Map<int, NodeInfo> nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
struct BandwidthFrame {
|
||||||
|
uint32_t timestamp;
|
||||||
|
int packet_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
int bandwidth_incoming_pointer;
|
||||||
|
Vector<BandwidthFrame> bandwidth_incoming_data;
|
||||||
|
int bandwidth_outgoing_pointer;
|
||||||
|
Vector<BandwidthFrame> bandwidth_outgoing_data;
|
||||||
|
Map<ObjectID, ProfilingInfo> profiler_frame_data;
|
||||||
|
bool profiling;
|
||||||
|
|
||||||
|
void _init_node_profile(ObjectID p_node);
|
||||||
|
int _get_bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer);
|
||||||
|
#endif
|
||||||
|
|
||||||
Ref<NetworkedMultiplayerPeer> network_peer;
|
Ref<NetworkedMultiplayerPeer> network_peer;
|
||||||
int rpc_sender_id;
|
int rpc_sender_id;
|
||||||
Set<int> connected_peers;
|
Set<int> connected_peers;
|
||||||
|
@ -130,6 +157,13 @@ public:
|
||||||
void set_allow_object_decoding(bool p_enable);
|
void set_allow_object_decoding(bool p_enable);
|
||||||
bool is_object_decoding_allowed() const;
|
bool is_object_decoding_allowed() const;
|
||||||
|
|
||||||
|
void profiling_start();
|
||||||
|
void profiling_end();
|
||||||
|
|
||||||
|
int get_profiling_frame(ProfilingInfo *r_info);
|
||||||
|
int get_incoming_bandwidth_usage();
|
||||||
|
int get_outgoing_bandwidth_usage();
|
||||||
|
|
||||||
MultiplayerAPI();
|
MultiplayerAPI();
|
||||||
~MultiplayerAPI();
|
~MultiplayerAPI();
|
||||||
};
|
};
|
||||||
|
|
|
@ -769,6 +769,14 @@ void ScriptDebuggerRemote::_poll_events() {
|
||||||
profiling = false;
|
profiling = false;
|
||||||
_send_profiling_data(false);
|
_send_profiling_data(false);
|
||||||
print_line("PROFILING END!");
|
print_line("PROFILING END!");
|
||||||
|
} else if (command == "start_network_profiling") {
|
||||||
|
|
||||||
|
multiplayer->profiling_start();
|
||||||
|
profiling_network = true;
|
||||||
|
} else if (command == "stop_network_profiling") {
|
||||||
|
|
||||||
|
multiplayer->profiling_end();
|
||||||
|
profiling_network = false;
|
||||||
} else if (command == "reload_scripts") {
|
} else if (command == "reload_scripts") {
|
||||||
reload_all_scripts = true;
|
reload_all_scripts = true;
|
||||||
} else if (command == "breakpoint") {
|
} else if (command == "breakpoint") {
|
||||||
|
@ -918,6 +926,18 @@ void ScriptDebuggerRemote::idle_poll() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (profiling_network) {
|
||||||
|
uint64_t pt = OS::get_singleton()->get_ticks_msec();
|
||||||
|
if (pt - last_net_bandwidth_time > 200) {
|
||||||
|
last_net_bandwidth_time = pt;
|
||||||
|
_send_network_bandwidth_usage();
|
||||||
|
}
|
||||||
|
if (pt - last_net_prof_time > 100) {
|
||||||
|
last_net_prof_time = pt;
|
||||||
|
_send_network_profiling_data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (reload_all_scripts) {
|
if (reload_all_scripts) {
|
||||||
|
|
||||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||||
|
@ -929,6 +949,35 @@ void ScriptDebuggerRemote::idle_poll() {
|
||||||
_poll_events();
|
_poll_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptDebuggerRemote::_send_network_profiling_data() {
|
||||||
|
ERR_FAIL_COND(multiplayer.is_null());
|
||||||
|
|
||||||
|
int n_nodes = multiplayer->get_profiling_frame(&network_profile_info.write[0]);
|
||||||
|
|
||||||
|
packet_peer_stream->put_var("network_profile");
|
||||||
|
packet_peer_stream->put_var(n_nodes * 6);
|
||||||
|
for (int i = 0; i < n_nodes; ++i) {
|
||||||
|
packet_peer_stream->put_var(network_profile_info[i].node);
|
||||||
|
packet_peer_stream->put_var(network_profile_info[i].node_path);
|
||||||
|
packet_peer_stream->put_var(network_profile_info[i].incoming_rpc);
|
||||||
|
packet_peer_stream->put_var(network_profile_info[i].incoming_rset);
|
||||||
|
packet_peer_stream->put_var(network_profile_info[i].outgoing_rpc);
|
||||||
|
packet_peer_stream->put_var(network_profile_info[i].outgoing_rset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptDebuggerRemote::_send_network_bandwidth_usage() {
|
||||||
|
ERR_FAIL_COND(multiplayer.is_null());
|
||||||
|
|
||||||
|
int incoming_bandwidth = multiplayer->get_incoming_bandwidth_usage();
|
||||||
|
int outgoing_bandwidth = multiplayer->get_outgoing_bandwidth_usage();
|
||||||
|
|
||||||
|
packet_peer_stream->put_var("network_bandwidth");
|
||||||
|
packet_peer_stream->put_var(2);
|
||||||
|
packet_peer_stream->put_var(incoming_bandwidth);
|
||||||
|
packet_peer_stream->put_var(outgoing_bandwidth);
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptDebuggerRemote::send_message(const String &p_message, const Array &p_args) {
|
void ScriptDebuggerRemote::send_message(const String &p_message, const Array &p_args) {
|
||||||
|
|
||||||
mutex->lock();
|
mutex->lock();
|
||||||
|
@ -1068,6 +1117,10 @@ void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) {
|
||||||
live_edit_funcs = p_funcs;
|
live_edit_funcs = p_funcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptDebuggerRemote::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
|
||||||
|
multiplayer = p_multiplayer;
|
||||||
|
}
|
||||||
|
|
||||||
bool ScriptDebuggerRemote::is_profiling() const {
|
bool ScriptDebuggerRemote::is_profiling() const {
|
||||||
|
|
||||||
return profiling;
|
return profiling;
|
||||||
|
@ -1117,12 +1170,15 @@ ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_fun
|
||||||
|
|
||||||
ScriptDebuggerRemote::ScriptDebuggerRemote() :
|
ScriptDebuggerRemote::ScriptDebuggerRemote() :
|
||||||
profiling(false),
|
profiling(false),
|
||||||
|
profiling_network(false),
|
||||||
max_frame_functions(16),
|
max_frame_functions(16),
|
||||||
skip_profile_frame(false),
|
skip_profile_frame(false),
|
||||||
reload_all_scripts(false),
|
reload_all_scripts(false),
|
||||||
tcp_client(Ref<StreamPeerTCP>(memnew(StreamPeerTCP))),
|
tcp_client(Ref<StreamPeerTCP>(memnew(StreamPeerTCP))),
|
||||||
packet_peer_stream(Ref<PacketPeerStream>(memnew(PacketPeerStream))),
|
packet_peer_stream(Ref<PacketPeerStream>(memnew(PacketPeerStream))),
|
||||||
last_perf_time(0),
|
last_perf_time(0),
|
||||||
|
last_net_prof_time(0),
|
||||||
|
last_net_bandwidth_time(0),
|
||||||
performance(Engine::get_singleton()->get_singleton_object("Performance")),
|
performance(Engine::get_singleton()->get_singleton_object("Performance")),
|
||||||
requested_quit(false),
|
requested_quit(false),
|
||||||
mutex(Mutex::create()),
|
mutex(Mutex::create()),
|
||||||
|
@ -1154,6 +1210,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() :
|
||||||
add_error_handler(&eh);
|
add_error_handler(&eh);
|
||||||
|
|
||||||
profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions"));
|
profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions"));
|
||||||
|
network_profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions"));
|
||||||
profile_info_ptrs.resize(profile_info.size());
|
profile_info_ptrs.resize(profile_info.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,11 +54,13 @@ class ScriptDebuggerRemote : public ScriptDebugger {
|
||||||
|
|
||||||
Vector<ScriptLanguage::ProfilingInfo> profile_info;
|
Vector<ScriptLanguage::ProfilingInfo> profile_info;
|
||||||
Vector<ScriptLanguage::ProfilingInfo *> profile_info_ptrs;
|
Vector<ScriptLanguage::ProfilingInfo *> profile_info_ptrs;
|
||||||
|
Vector<MultiplayerAPI::ProfilingInfo> network_profile_info;
|
||||||
|
|
||||||
Map<StringName, int> profiler_function_signature_map;
|
Map<StringName, int> profiler_function_signature_map;
|
||||||
float frame_time, idle_time, physics_time, physics_frame_time;
|
float frame_time, idle_time, physics_time, physics_frame_time;
|
||||||
|
|
||||||
bool profiling;
|
bool profiling;
|
||||||
|
bool profiling_network;
|
||||||
int max_frame_functions;
|
int max_frame_functions;
|
||||||
bool skip_profile_frame;
|
bool skip_profile_frame;
|
||||||
bool reload_all_scripts;
|
bool reload_all_scripts;
|
||||||
|
@ -67,6 +69,8 @@ class ScriptDebuggerRemote : public ScriptDebugger {
|
||||||
Ref<PacketPeerStream> packet_peer_stream;
|
Ref<PacketPeerStream> packet_peer_stream;
|
||||||
|
|
||||||
uint64_t last_perf_time;
|
uint64_t last_perf_time;
|
||||||
|
uint64_t last_net_prof_time;
|
||||||
|
uint64_t last_net_bandwidth_time;
|
||||||
Object *performance;
|
Object *performance;
|
||||||
bool requested_quit;
|
bool requested_quit;
|
||||||
Mutex *mutex;
|
Mutex *mutex;
|
||||||
|
@ -123,10 +127,14 @@ class ScriptDebuggerRemote : public ScriptDebugger {
|
||||||
void _send_video_memory();
|
void _send_video_memory();
|
||||||
LiveEditFuncs *live_edit_funcs;
|
LiveEditFuncs *live_edit_funcs;
|
||||||
|
|
||||||
|
Ref<MultiplayerAPI> multiplayer;
|
||||||
|
|
||||||
ErrorHandlerList eh;
|
ErrorHandlerList eh;
|
||||||
static void _err_handler(void *, const char *, const char *, int p_line, const char *, const char *, ErrorHandlerType p_type);
|
static void _err_handler(void *, const char *, const char *, int p_line, const char *, const char *, ErrorHandlerType p_type);
|
||||||
|
|
||||||
void _send_profiling_data(bool p_for_frame);
|
void _send_profiling_data(bool p_for_frame);
|
||||||
|
void _send_network_profiling_data();
|
||||||
|
void _send_network_bandwidth_usage();
|
||||||
|
|
||||||
struct FrameData {
|
struct FrameData {
|
||||||
|
|
||||||
|
@ -170,6 +178,7 @@ public:
|
||||||
|
|
||||||
virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata);
|
virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata);
|
||||||
virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs);
|
virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs);
|
||||||
|
virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
|
||||||
|
|
||||||
virtual bool is_profiling() const;
|
virtual bool is_profiling() const;
|
||||||
virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data);
|
virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data);
|
||||||
|
|
|
@ -482,6 +482,7 @@ public:
|
||||||
|
|
||||||
virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {}
|
virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {}
|
||||||
virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {}
|
virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {}
|
||||||
|
virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {}
|
||||||
|
|
||||||
virtual bool is_profiling() const = 0;
|
virtual bool is_profiling() const = 0;
|
||||||
virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data) = 0;
|
virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data) = 0;
|
||||||
|
|
208
editor/editor_network_profiler.cpp
Normal file
208
editor/editor_network_profiler.cpp
Normal file
|
@ -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");
|
||||||
|
}
|
73
editor/editor_network_profiler.h
Normal file
73
editor/editor_network_profiler.h
Normal file
|
@ -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
|
|
@ -33,6 +33,7 @@
|
||||||
#include "core/io/marshalls.h"
|
#include "core/io/marshalls.h"
|
||||||
#include "core/project_settings.h"
|
#include "core/project_settings.h"
|
||||||
#include "core/ustring.h"
|
#include "core/ustring.h"
|
||||||
|
#include "editor_network_profiler.h"
|
||||||
#include "editor_node.h"
|
#include "editor_node.h"
|
||||||
#include "editor_profiler.h"
|
#include "editor_profiler.h"
|
||||||
#include "editor_settings.h"
|
#include "editor_settings.h"
|
||||||
|
@ -992,7 +993,20 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
|
||||||
profiler->add_frame_metric(metric, false);
|
profiler->add_frame_metric(metric, false);
|
||||||
else
|
else
|
||||||
profiler->add_frame_metric(metric, true);
|
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") {
|
} else if (p_msg == "kill_me") {
|
||||||
|
|
||||||
editor->call_deferred("stop_child_process");
|
editor->call_deferred("stop_child_process");
|
||||||
|
@ -1208,6 +1222,10 @@ void ScriptEditorDebugger::_notification(int p_what) {
|
||||||
if (profiler->is_profiling()) {
|
if (profiler->is_profiling()) {
|
||||||
_profiler_activate(true);
|
_profiler_activate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (network_profiler->is_profiling()) {
|
||||||
|
_network_profiler_activate(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1427,6 +1445,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() {
|
void ScriptEditorDebugger::_profiler_seeked() {
|
||||||
|
|
||||||
if (!connection.is_valid() || !connection->is_connected_to_host())
|
if (!connection.is_valid() || !connection->is_connected_to_host())
|
||||||
|
@ -2020,6 +2057,7 @@ void ScriptEditorDebugger::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("_expand_errors_list"), &ScriptEditorDebugger::_expand_errors_list);
|
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("_collapse_errors_list"), &ScriptEditorDebugger::_collapse_errors_list);
|
||||||
ClassDB::bind_method(D_METHOD("_profiler_activate"), &ScriptEditorDebugger::_profiler_activate);
|
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("_profiler_seeked"), &ScriptEditorDebugger::_profiler_seeked);
|
||||||
ClassDB::bind_method(D_METHOD("_clear_errors_list"), &ScriptEditorDebugger::_clear_errors_list);
|
ClassDB::bind_method(D_METHOD("_clear_errors_list"), &ScriptEditorDebugger::_clear_errors_list);
|
||||||
|
|
||||||
|
@ -2245,6 +2283,13 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
||||||
profiler->connect("break_request", this, "_profiler_seeked");
|
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
|
{ //monitors
|
||||||
|
|
||||||
HSplitContainer *hsp = memnew(HSplitContainer);
|
HSplitContainer *hsp = memnew(HSplitContainer);
|
||||||
|
|
|
@ -50,6 +50,7 @@ class TreeItem;
|
||||||
class HSplitContainer;
|
class HSplitContainer;
|
||||||
class ItemList;
|
class ItemList;
|
||||||
class EditorProfiler;
|
class EditorProfiler;
|
||||||
|
class EditorNetworkProfiler;
|
||||||
|
|
||||||
class ScriptEditorDebuggerInspectedObject;
|
class ScriptEditorDebuggerInspectedObject;
|
||||||
|
|
||||||
|
@ -155,6 +156,7 @@ class ScriptEditorDebugger : public Control {
|
||||||
Map<String, int> res_path_cache;
|
Map<String, int> res_path_cache;
|
||||||
|
|
||||||
EditorProfiler *profiler;
|
EditorProfiler *profiler;
|
||||||
|
EditorNetworkProfiler *network_profiler;
|
||||||
|
|
||||||
EditorNode *editor;
|
EditorNode *editor;
|
||||||
|
|
||||||
|
@ -199,6 +201,8 @@ class ScriptEditorDebugger : public Control {
|
||||||
void _profiler_activate(bool p_enable);
|
void _profiler_activate(bool p_enable);
|
||||||
void _profiler_seeked();
|
void _profiler_seeked();
|
||||||
|
|
||||||
|
void _network_profiler_activate(bool p_enable);
|
||||||
|
|
||||||
void _paused();
|
void _paused();
|
||||||
|
|
||||||
void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj);
|
void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj);
|
||||||
|
|
|
@ -2096,6 +2096,7 @@ SceneTree::SceneTree() {
|
||||||
|
|
||||||
if (ScriptDebugger::get_singleton()) {
|
if (ScriptDebugger::get_singleton()) {
|
||||||
ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree, this);
|
ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree, this);
|
||||||
|
ScriptDebugger::get_singleton()->set_multiplayer(multiplayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true));
|
root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true));
|
||||||
|
|
Loading…
Reference in a new issue