Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MP] Improve network profiler. #68758

Merged
merged 1 commit into from Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 8 additions & 2 deletions modules/multiplayer/editor/editor_network_profiler.cpp
Expand Up @@ -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)));
}
}

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion modules/multiplayer/editor/editor_network_profiler.h
Expand Up @@ -66,7 +66,7 @@ class EditorNetworkProfiler : public VBoxContainer {
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();

Expand Down
26 changes: 16 additions & 10 deletions modules/multiplayer/multiplayer_debugger.cpp
Expand Up @@ -126,28 +126,33 @@ 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;
}

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;
}
Expand All @@ -159,24 +164,25 @@ 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) {
rpc_node_data.clear();
}

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;
}
}

Expand Down
2 changes: 2 additions & 0 deletions modules/multiplayer/multiplayer_debugger.h
Expand Up @@ -41,7 +41,9 @@ class MultiplayerDebugger {
ObjectID node;
String node_path;
int incoming_rpc = 0;
int incoming_size = 0;
int outgoing_rpc = 0;
int outgoing_size = 0;
};

struct RPCFrame {
Expand Down
8 changes: 0 additions & 8 deletions modules/multiplayer/scene_cache_interface.cpp
Expand Up @@ -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());
Expand Down Expand Up @@ -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);
Expand Down
41 changes: 24 additions & 17 deletions modules/multiplayer/scene_multiplayer.cpp
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand All @@ -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;
}
Expand Down Expand Up @@ -319,15 +326,15 @@ 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.
if (P == p_from || (peer < 0 && P != -peer)) {
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) {
Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down
13 changes: 9 additions & 4 deletions modules/multiplayer/scene_multiplayer.h
Expand Up @@ -103,6 +103,15 @@ class SceneMultiplayer : public MultiplayerAPI {
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();

Expand Down Expand Up @@ -163,10 +172,6 @@ class SceneMultiplayer : public MultiplayerAPI {

Ref<SceneCacheInterface> get_path_cache() { return cache; }

#ifdef DEBUG_ENABLED
void profile_bandwidth(const String &p_inout, int p_size);
#endif

SceneMultiplayer();
~SceneMultiplayer();
};
Expand Down
5 changes: 0 additions & 5 deletions modules/multiplayer/scene_replication_interface.cpp
Expand Up @@ -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);
Expand Down
21 changes: 8 additions & 13 deletions modules/multiplayer/scene_rpc_interface.cpp
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

// 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);
_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);

// 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);
Expand Down Expand Up @@ -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);
}

Expand Down
5 changes: 4 additions & 1 deletion modules/multiplayer/scene_rpc_interface.h
Expand Up @@ -81,8 +81,11 @@ class SceneRPCInterface : public RefCounted {

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);
Expand Down