Merge pull request #68758 from Faless/mp/4.x_better_debug

[MP] Improve network profiler.
This commit is contained in:
Rémi Verschelde 2022-11-18 23:29:02 +01:00
commit 1bc131afb8
No known key found for this signature in database
GPG key ID: C3336907360768E1
10 changed files with 72 additions and 61 deletions

View file

@ -67,8 +67,8 @@ void EditorNetworkProfiler::_update_frame() {
}
node->set_text(0, E.value.node_path);
node->set_text(1, E.value.incoming_rpc == 0 ? "-" : itos(E.value.incoming_rpc));
node->set_text(2, E.value.outgoing_rpc == 0 ? "-" : itos(E.value.outgoing_rpc));
node->set_text(1, E.value.incoming_rpc == 0 ? "-" : vformat(TTR("%d (%s)"), E.value.incoming_rpc, String::humanize_size(E.value.incoming_size)));
node->set_text(2, E.value.outgoing_rpc == 0 ? "-" : vformat(TTR("%d (%s)"), E.value.outgoing_rpc, String::humanize_size(E.value.outgoing_size)));
}
}
@ -99,6 +99,12 @@ void EditorNetworkProfiler::add_node_frame_data(const RPCNodeInfo p_frame) {
nodes_data[p_frame.node].incoming_rpc += p_frame.incoming_rpc;
nodes_data[p_frame.node].outgoing_rpc += p_frame.outgoing_rpc;
}
if (p_frame.incoming_rpc) {
nodes_data[p_frame.node].incoming_size = p_frame.incoming_size / p_frame.incoming_rpc;
}
if (p_frame.outgoing_rpc) {
nodes_data[p_frame.node].outgoing_size = p_frame.outgoing_size / p_frame.outgoing_rpc;
}
if (frame_delay->is_stopped()) {
frame_delay->set_wait_time(0.1);

View file

@ -66,7 +66,7 @@ protected:
static void _bind_methods();
public:
void add_node_frame_data(const RPCNodeInfo p_frame);
void add_node_frame_data(RPCNodeInfo p_frame);
void set_bandwidth(int p_incoming, int p_outgoing);
bool is_profiling();

View file

@ -126,12 +126,14 @@ void MultiplayerDebugger::BandwidthProfiler::tick(double p_frame_time, double p_
Array MultiplayerDebugger::RPCFrame::serialize() {
Array arr;
arr.push_back(infos.size() * 4);
arr.push_back(infos.size() * 6);
for (int i = 0; i < infos.size(); ++i) {
arr.push_back(uint64_t(infos[i].node));
arr.push_back(infos[i].node_path);
arr.push_back(infos[i].incoming_rpc);
arr.push_back(infos[i].incoming_size);
arr.push_back(infos[i].outgoing_rpc);
arr.push_back(infos[i].outgoing_size);
}
return arr;
}
@ -139,15 +141,18 @@ Array MultiplayerDebugger::RPCFrame::serialize() {
bool MultiplayerDebugger::RPCFrame::deserialize(const Array &p_arr) {
ERR_FAIL_COND_V(p_arr.size() < 1, false);
uint32_t size = p_arr[0];
ERR_FAIL_COND_V(size % 4, false);
ERR_FAIL_COND_V(size % 6, false);
ERR_FAIL_COND_V((uint32_t)p_arr.size() != size + 1, false);
infos.resize(size / 4);
infos.resize(size / 6);
int idx = 1;
for (uint32_t i = 0; i < size / 4; ++i) {
for (uint32_t i = 0; i < size / 6; i++) {
infos.write[i].node = uint64_t(p_arr[idx]);
infos.write[i].node_path = p_arr[idx + 1];
infos.write[i].incoming_rpc = p_arr[idx + 2];
infos.write[i].outgoing_rpc = p_arr[idx + 3];
infos.write[i].incoming_size = p_arr[idx + 3];
infos.write[i].outgoing_rpc = p_arr[idx + 4];
infos.write[i].outgoing_size = p_arr[idx + 5];
idx += 6;
}
return true;
}
@ -159,8 +164,6 @@ void MultiplayerDebugger::RPCProfiler::init_node(const ObjectID p_node) {
rpc_node_data.insert(p_node, RPCNodeInfo());
rpc_node_data[p_node].node = p_node;
rpc_node_data[p_node].node_path = Object::cast_to<Node>(ObjectDB::get_instance(p_node))->get_path();
rpc_node_data[p_node].incoming_rpc = 0;
rpc_node_data[p_node].outgoing_rpc = 0;
}
void MultiplayerDebugger::RPCProfiler::toggle(bool p_enable, const Array &p_opts) {
@ -168,15 +171,18 @@ void MultiplayerDebugger::RPCProfiler::toggle(bool p_enable, const Array &p_opts
}
void MultiplayerDebugger::RPCProfiler::add(const Array &p_data) {
ERR_FAIL_COND(p_data.size() < 2);
const ObjectID id = p_data[0];
const String what = p_data[1];
ERR_FAIL_COND(p_data.size() != 3);
const String what = p_data[0];
const ObjectID id = p_data[1];
const int size = p_data[2];
init_node(id);
RPCNodeInfo &info = rpc_node_data[id];
if (what == "rpc_in") {
info.incoming_rpc++;
info.incoming_size += size;
} else if (what == "rpc_out") {
info.outgoing_rpc++;
info.outgoing_size += size;
}
}

View file

@ -41,7 +41,9 @@ public:
ObjectID node;
String node_path;
int incoming_rpc = 0;
int incoming_size = 0;
int outgoing_rpc = 0;
int outgoing_size = 0;
};
struct RPCFrame {

View file

@ -99,10 +99,6 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer();
ERR_FAIL_COND(multiplayer_peer.is_null());
#ifdef DEBUG_ENABLED
multiplayer->profile_bandwidth("out", packet.size());
#endif
multiplayer_peer->set_transfer_channel(0);
multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
multiplayer->send_command(p_from, packet.ptr(), packet.size());
@ -155,10 +151,6 @@ Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, Pat
Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer();
ERR_FAIL_COND_V(multiplayer_peer.is_null(), ERR_BUG);
#ifdef DEBUG_ENABLED
multiplayer->profile_bandwidth("out", packet.size() * p_peers.size());
#endif
Error err = OK;
for (int peer_id : p_peers) {
multiplayer_peer->set_transfer_channel(0);

View file

@ -40,12 +40,12 @@
#endif
#ifdef DEBUG_ENABLED
void SceneMultiplayer::profile_bandwidth(const String &p_inout, int p_size) {
_FORCE_INLINE_ void SceneMultiplayer::_profile_bandwidth(const String &p_what, int p_value) {
if (EngineDebugger::is_profiling("multiplayer")) {
Array values;
values.push_back(p_inout);
values.push_back(p_what);
values.push_back(OS::get_singleton()->get_ticks_msec());
values.push_back(p_size);
values.push_back(p_value);
EngineDebugger::profiler_add_frame_data("multiplayer", values);
}
}
@ -91,6 +91,10 @@ Error SceneMultiplayer::poll() {
Error err = multiplayer_peer->get_packet(&packet, len);
ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Error getting packet! %d", err));
#ifdef DEBUG_ENABLED
_profile_bandwidth("in", len);
#endif
if (pending_peers.has(sender)) {
if (pending_peers[sender].local) {
// If the auth is over, admit the peer at the first packet.
@ -220,10 +224,6 @@ void SceneMultiplayer::_process_packet(int p_from, const uint8_t *p_packet, int
ERR_FAIL_COND_MSG(root_path.is_empty(), "Multiplayer root was not initialized. If you are using custom multiplayer, remember to set the root path via SceneMultiplayer.set_root_path before using it.");
ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small.");
#ifdef DEBUG_ENABLED
profile_bandwidth("in", p_packet_len);
#endif
// Extract the `packet_type` from the LSB three bits:
uint8_t packet_type = p_packet[0] & CMD_MASK;
@ -258,6 +258,13 @@ void SceneMultiplayer::_process_packet(int p_from, const uint8_t *p_packet, int
}
}
#ifdef DEBUG_ENABLED
_FORCE_INLINE_ Error SceneMultiplayer::_send(const uint8_t *p_packet, int p_packet_len) {
_profile_bandwidth("out", p_packet_len);
return multiplayer_peer->put_packet(p_packet, p_packet_len);
}
#endif
Error SceneMultiplayer::send_command(int p_to, const uint8_t *p_packet, int p_packet_len) {
if (server_relay && get_unique_id() != 1 && p_to != 1 && multiplayer_peer->is_server_relay_supported()) {
// Send relay packet.
@ -268,19 +275,19 @@ Error SceneMultiplayer::send_command(int p_to, const uint8_t *p_packet, int p_pa
relay_buffer->put_data(p_packet, p_packet_len);
multiplayer_peer->set_target_peer(1);
const Vector<uint8_t> data = relay_buffer->get_data_array();
return multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position());
return _send(data.ptr(), relay_buffer->get_position());
}
if (p_to > 0) {
ERR_FAIL_COND_V(!connected_peers.has(p_to), ERR_BUG);
multiplayer_peer->set_target_peer(p_to);
return multiplayer_peer->put_packet(p_packet, p_packet_len);
return _send(p_packet, p_packet_len);
} else {
for (const int &pid : connected_peers) {
if (p_to && pid == -p_to) {
continue;
}
multiplayer_peer->set_target_peer(pid);
multiplayer_peer->put_packet(p_packet, p_packet_len);
_send(p_packet, p_packet_len);
}
return OK;
}
@ -319,7 +326,7 @@ void SceneMultiplayer::_process_sys(int p_from, const uint8_t *p_packet, int p_p
multiplayer_peer->set_transfer_channel(p_channel);
if (peer > 0) {
multiplayer_peer->set_target_peer(peer);
multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position());
_send(data.ptr(), relay_buffer->get_position());
} else {
for (const int &P : connected_peers) {
// Not to sender, nor excluded.
@ -327,7 +334,7 @@ void SceneMultiplayer::_process_sys(int p_from, const uint8_t *p_packet, int p_p
continue;
}
multiplayer_peer->set_target_peer(P);
multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position());
_send(data.ptr(), relay_buffer->get_position());
}
}
if (peer == 0 || peer == -1) {
@ -373,11 +380,11 @@ void SceneMultiplayer::_admit_peer(int p_id) {
// Send new peer to already connected.
encode_uint32(p_id, &buf[2]);
multiplayer_peer->set_target_peer(P);
multiplayer_peer->put_packet(buf, sizeof(buf));
_send(buf, sizeof(buf));
// Send already connected to new peer.
encode_uint32(P, &buf[2]);
multiplayer_peer->set_target_peer(p_id);
multiplayer_peer->put_packet(buf, sizeof(buf));
_send(buf, sizeof(buf));
}
}
@ -412,7 +419,7 @@ void SceneMultiplayer::_del_peer(int p_id) {
continue;
}
multiplayer_peer->set_target_peer(P);
multiplayer_peer->put_packet(buf, sizeof(buf));
_send(buf, sizeof(buf));
}
}
@ -468,7 +475,7 @@ Error SceneMultiplayer::send_auth(int p_to, Vector<uint8_t> p_data) {
multiplayer_peer->set_target_peer(p_to);
multiplayer_peer->set_transfer_channel(0);
multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
return multiplayer_peer->put_packet(packet_cache.ptr(), p_data.size() + 2);
return _send(packet_cache.ptr(), p_data.size() + 2);
}
Error SceneMultiplayer::complete_auth(int p_peer) {
@ -478,7 +485,7 @@ Error SceneMultiplayer::complete_auth(int p_peer) {
pending_peers[p_peer].local = true;
// Notify the remote peer that the authentication has completed.
uint8_t buf[2] = { NETWORK_COMMAND_SYS, SYS_COMMAND_AUTH };
Error err = multiplayer_peer->put_packet(buf, 2);
Error err = _send(buf, 2);
// The remote peer already reported the authentication as completed, so admit the peer.
// May generate new packets, so it must happen after sending confirmation.
if (pending_peers[p_peer].remote) {

View file

@ -103,6 +103,15 @@ private:
Ref<SceneReplicationInterface> replicator;
Ref<SceneRPCInterface> rpc;
#ifdef DEBUG_ENABLED
_FORCE_INLINE_ void _profile_bandwidth(const String &p_what, int p_value);
_FORCE_INLINE_ Error _send(const uint8_t *p_packet, int p_packet_len); // Also profiles.
#else
_FORCE_INLINE_ Error _send(const uint8_t *p_packet, int p_packet_len) {
return multiplayer_peer->put_packet(p_packet, p_packet_len);
}
#endif
protected:
static void _bind_methods();
@ -163,10 +172,6 @@ public:
Ref<SceneCacheInterface> get_path_cache() { return cache; }
#ifdef DEBUG_ENABLED
void profile_bandwidth(const String &p_inout, int p_size);
#endif
SceneMultiplayer();
~SceneMultiplayer();
};

View file

@ -362,13 +362,8 @@ Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const Obje
Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable) {
ERR_FAIL_COND_V(!p_buffer || p_size < 1, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(!multiplayer, ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!multiplayer->has_multiplayer_peer(), ERR_UNCONFIGURED);
#ifdef DEBUG_ENABLED
multiplayer->profile_bandwidth("out", p_size);
#endif
Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer();
peer->set_transfer_channel(0);
peer->set_transfer_mode(p_reliable ? MultiplayerPeer::TRANSFER_MODE_RELIABLE : MultiplayerPeer::TRANSFER_MODE_UNRELIABLE);

View file

@ -52,16 +52,15 @@
#define BYTE_ONLY_OR_NO_ARGS_FLAG (1 << BYTE_ONLY_OR_NO_ARGS_SHIFT)
#ifdef DEBUG_ENABLED
_FORCE_INLINE_ void SceneRPCInterface::_profile_node_data(const String &p_what, ObjectID p_id) {
_FORCE_INLINE_ void SceneRPCInterface::_profile_node_data(const String &p_what, ObjectID p_id, int p_size) {
if (EngineDebugger::is_profiling("rpc")) {
Array values;
values.push_back(p_id);
values.push_back(p_what);
values.push_back(p_id);
values.push_back(p_size);
EngineDebugger::profiler_add_frame_data("rpc", values);
}
}
#else
_FORCE_INLINE_ void SceneRPCInterface::_profile_node_data(const String &p_what, ObjectID p_id) {}
#endif
// Returns the packet size stripping the node path added when the node is not yet cached.
@ -277,7 +276,7 @@ void SceneRPCInterface::_process_rpc(Node *p_node, const uint16_t p_rpc_method_i
argp.resize(argc);
#ifdef DEBUG_ENABLED
_profile_node_data("rpc_in", p_node->get_instance_id());
_profile_node_data("rpc_in", p_node->get_instance_id(), p_packet_len);
#endif
int out;
@ -399,13 +398,13 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
ERR_FAIL_COND(node_id_compression > 3);
ERR_FAIL_COND(name_id_compression > 1);
#ifdef DEBUG_ENABLED
_profile_node_data("rpc_out", p_from->get_instance_id(), ofs);
#endif
// We can now set the meta
packet_cache.write[0] = command_type + (node_id_compression << NODE_ID_COMPRESSION_SHIFT) + (name_id_compression << NAME_ID_COMPRESSION_SHIFT) + (byte_only_or_no_args ? BYTE_ONLY_OR_NO_ARGS_FLAG : 0);
#ifdef DEBUG_ENABLED
multiplayer->profile_bandwidth("out", ofs);
#endif
// Take chance and set transfer mode, since all send methods will use it.
peer->set_transfer_channel(p_config.channel);
peer->set_transfer_mode(p_config.transfer_mode);
@ -477,10 +476,6 @@ Error SceneRPCInterface::rpcp(Object *p_obj, int p_peer_id, const StringName &p_
}
if (p_peer_id != caller_id) {
#ifdef DEBUG_ENABLED
_profile_node_data("rpc_out", node->get_instance_id());
#endif
_send_rpc(node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount);
}

View file

@ -81,8 +81,11 @@ private:
HashMap<ObjectID, RPCConfigCache> rpc_cache;
#ifdef DEBUG_ENABLED
_FORCE_INLINE_ void _profile_node_data(const String &p_what, ObjectID p_id, int p_size);
#endif
protected:
_FORCE_INLINE_ void _profile_node_data(const String &p_what, ObjectID p_id);
void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset);
void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount);