network stats + tweaks

isolation_bkp/dynres
Dominik Madarász 2021-11-07 14:41:13 +01:00
parent 970334aa7a
commit 63db7893b4
7 changed files with 181 additions and 18 deletions

View File

@ -42,11 +42,18 @@ static uint8_t is_handle_ctrl_held;
static float debug_xpos = DBG_START_XPOS; static float debug_xpos = DBG_START_XPOS;
static float debug_ypos = DBG_START_YPOS; static float debug_ypos = DBG_START_YPOS;
typedef enum {
L_NONE = 0,
L_SP,
L_MP,
} limit_kind;
typedef struct debug_item { typedef struct debug_item {
debug_kind kind; debug_kind kind;
char const *name; char const *name;
float name_width; float name_width;
uint8_t skip; uint8_t skip;
limit_kind limit_to;
union { union {
union { union {
@ -57,7 +64,6 @@ typedef struct debug_item {
struct { struct {
struct debug_item *items; struct debug_item *items;
uint8_t is_collapsed; uint8_t is_collapsed;
uint8_t is_sp_only;
} list; } list;
struct { struct {
@ -114,8 +120,8 @@ static debug_item items[] = {
{ .kind = DITEM_END }, { .kind = DITEM_END },
}, },
.is_sp_only = true, },
} .limit_to = L_SP,
}, },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
@ -142,8 +148,27 @@ static debug_item items[] = {
}, },
{ .kind = DITEM_END }, { .kind = DITEM_END },
}, },
.is_sp_only = true, },
} .limit_to = L_SP,
},
{
.kind = DITEM_LIST,
.name = "conn metrics",
.list = {
.items = (debug_item[]) {
{ .kind = DITEM_COND, .on_success = CondClientDisconnected },
{ .kind = DITEM_TEXT, .name = "status", .proc = DrawLiteral, .text = "disconnected" },
{ .kind = DITEM_COND, .on_success = CondClientConnected },
{ .kind = DITEM_TEXT, .name = "status", .proc = DrawLiteral, .text = "connected" },
{ .kind = DITEM_COND, .on_success = CondClientConnected },
{ .kind = DITEM_TEXT, .proc = DrawNetworkStats },
{ .kind = DITEM_END },
},
},
.limit_to = L_MP,
}, },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
@ -178,9 +203,9 @@ static debug_item items[] = {
{ .kind = DITEM_END }, { .kind = DITEM_END },
}, },
.is_sp_only = true,
.is_collapsed = true, .is_collapsed = true,
} },
.limit_to = L_SP,
}, },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
@ -210,6 +235,8 @@ static debug_item items[] = {
debug_draw_result debug_draw_list(debug_item *list, float xpos, float ypos, bool is_shadow) { debug_draw_result debug_draw_list(debug_item *list, float xpos, float ypos, bool is_shadow) {
is_shadow_rendered = is_shadow; is_shadow_rendered = is_shadow;
for (debug_item *it = list; it->kind != DITEM_END; it += 1) { for (debug_item *it = list; it->kind != DITEM_END; it += 1) {
if (it->limit_to == L_SP && game_get_kind() != GAMEKIND_SINGLE) continue;
if (it->limit_to == L_MP && game_get_kind() == GAMEKIND_SINGLE) continue;
switch (it->kind) { switch (it->kind) {
case DITEM_GAP: { case DITEM_GAP: {
ypos += DBG_GAP_HEIGHT; ypos += DBG_GAP_HEIGHT;
@ -234,18 +261,20 @@ debug_draw_result debug_draw_list(debug_item *list, float xpos, float ypos, bool
UIDrawText(it->name, xpos, ypos, DBG_FONT_SIZE, color); UIDrawText(it->name, xpos, ypos, DBG_FONT_SIZE, color);
ypos += DBG_FONT_SPACING; ypos += DBG_FONT_SPACING;
if (it->list.is_collapsed) break; if (it->list.is_collapsed) break;
if (it->list.is_sp_only && game_get_kind() != GAMEKIND_SINGLE) break;
debug_draw_result res = debug_draw_list(it->list.items, xpos+DBG_LIST_XPOS_OFFSET, ypos, is_shadow); debug_draw_result res = debug_draw_list(it->list.items, xpos+DBG_LIST_XPOS_OFFSET, ypos, is_shadow);
ypos = res.y; ypos = res.y;
}break; }break;
case DITEM_TEXT: { case DITEM_TEXT: {
char const *text = TextFormat("%s: ", it->name); if (it->name) {
if (it->name_width == 0) { char const *text = TextFormat("%s: ", it->name);
it->name_width = (float)UIMeasureText(text, DBG_FONT_SIZE); if (it->name_width == 0) {
it->name_width = (float)UIMeasureText(text, DBG_FONT_SIZE);
}
UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, RAYWHITE);
ZPL_ASSERT(it->proc);
} }
UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, RAYWHITE);
ZPL_ASSERT(it->proc);
debug_draw_result res = it->proc(it, xpos + it->name_width, ypos); debug_draw_result res = it->proc(it, xpos + it->name_width, ypos);
ypos = res.y; ypos = res.y;

View File

@ -1,6 +1,7 @@
#include "debug_ui.h" #include "debug_ui.h"
#include "world/blocks.h" #include "world/blocks.h"
#include "items.h" #include "items.h"
#include "network.h"
void void
ActExitGame(void) { ActExitGame(void) {
@ -269,3 +270,15 @@ uint8_t
CondIsWorldRunning(void) { CondIsWorldRunning(void) {
return !world_is_paused(); return !world_is_paused();
} }
// NOTE(zaklaus): connection metrics
uint8_t
CondClientConnected(void) {
return network_client_is_connected();
}
uint8_t
CondClientDisconnected(void) {
return !network_client_is_connected();
}

View File

@ -1,6 +1,7 @@
#include "debug_ui.h" #include "debug_ui.h"
#include "raylib.h" #include "raylib.h"
#include "platform.h" #include "platform.h"
#include "network.h"
#include "profiler.h" #include "profiler.h"
//~ NOTE(zaklaus): helpers //~ NOTE(zaklaus): helpers
@ -16,7 +17,16 @@ static inline debug_draw_result
DrawColoredText(float xpos, float ypos, char const *text, Color color) { DrawColoredText(float xpos, float ypos, char const *text, Color color) {
ZPL_ASSERT(text); ZPL_ASSERT(text);
UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, color); UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, color);
return (debug_draw_result){.x = xpos + UIMeasureText(text, DBG_FONT_SIZE), .y = ypos + DBG_FONT_SPACING};
char const *p = text;
uint8_t newlines = 1;
do {
if (*p == '\n')
++newlines;
} while (*p++ != 0);
return (debug_draw_result){.x = xpos + UIMeasureText(text, DBG_FONT_SIZE), .y = ypos + DBG_FONT_SPACING*newlines};
} }
static inline debug_draw_result static inline debug_draw_result
@ -99,3 +109,31 @@ DrawWorldStepSize(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
return DrawFormattedText(xpos, ypos, TextFormat("%d ms", (int16_t)(sim_step_size*1000.f))); return DrawFormattedText(xpos, ypos, TextFormat("%d ms", (int16_t)(sim_step_size*1000.f)));
} }
// NOTE(zaklaus): network stats
static inline debug_draw_result
DrawNetworkStats(debug_item *it, float xpos, float ypos) {
(void)it;
network_client_stats s = network_client_fetch_stats();
#define _kb(x) ((x) / 1024)
debug_draw_result r;
r = DrawFormattedText(xpos, ypos, TextFormat("dn total: %d kb", _kb(s.incoming_total)));
r = DrawFormattedText(xpos, r.y, TextFormat("recv total: %lld kb", _kb(s.total_received)));
r = DrawFormattedText(xpos, r.y, TextFormat("up total: %lld kb", _kb(s.outgoing_total)));
r = DrawFormattedText(xpos, r.y, TextFormat("sent total: %lld kb", _kb(s.total_sent)));
r = DrawFormattedText(xpos, r.y, TextFormat("dn rate: %.02f kb/sec (%.02f kbit/sec)", _kb(s.incoming_bandwidth), _kb(s.incoming_bandwidth * 8.0f)));
r = DrawFormattedText(xpos, r.y, TextFormat("up rate: %.02f kb/sec (%.02f kbit/sec)", _kb(s.outgoing_bandwidth), _kb(s.outgoing_bandwidth * 8.0f)));
r = DrawFormattedText(xpos, r.y, TextFormat("packets sent: %lld", s.packets_sent));
r = DrawFormattedText(xpos, r.y, TextFormat("packets lost: %d (%.02f%%)", s.packets_lost, s.packet_loss));
r = DrawFormattedText(xpos, r.y, TextFormat("ping: %d ms", s.ping));
#undef _kb
return r;
}

View File

@ -152,7 +152,7 @@ void game_init(game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t
if (game_mode == GAMEKIND_HEADLESS) { if (game_mode == GAMEKIND_HEADLESS) {
network_server_start(0, 27000); network_server_start(0, 27000);
ecs_set_target_fps(world_ecs(), 60); //ecs_set_target_fps(world_ecs(), 60);
} }
} }

View File

@ -98,6 +98,65 @@ int32_t network_client_tick() {
bool network_client_is_connected() { bool network_client_is_connected() {
return peer ? enet_peer_get_state(peer) == ENET_PEER_STATE_CONNECTED : false; return peer ? enet_peer_get_state(peer) == ENET_PEER_STATE_CONNECTED : false;
} }
network_client_stats
network_client_fetch_stats(void) {
if (!network_client_is_connected())
return (network_client_stats){0};
network_client_stats stats = {0};
stats.incoming_total = peer->incomingDataTotal;
stats.total_received = peer->totalDataReceived;
stats.outgoing_total = peer->outgoingDataTotal;
stats.total_sent = peer->totalDataSent;
static double next_measure = 0.0;
static float incoming_bandwidth = 0.0f;
static float outgoing_bandwidth = 0.0f;
if (next_measure < zpl_time_rel()) {
#define MAX_RATE_SAMPLES 8
static uint64_t last_total_sent = 0;
static uint64_t last_total_recv = 0;
static uint64_t rolling_counter = 0;
static uint64_t sent_buffer[MAX_RATE_SAMPLES] = {0};
static uint64_t recv_buffer[MAX_RATE_SAMPLES] = {0};
uint64_t sent_delta = stats.total_sent - last_total_sent;
uint64_t recv_delta = stats.total_received - last_total_recv;
last_total_sent = stats.total_sent;
last_total_recv = stats.total_received;
sent_buffer[rolling_counter % MAX_RATE_SAMPLES] = sent_delta;
recv_buffer[rolling_counter % MAX_RATE_SAMPLES] = recv_delta;
++rolling_counter;
for (int i = 0; i < MAX_RATE_SAMPLES; i++) {
stats.incoming_bandwidth += recv_buffer[i];
stats.outgoing_bandwidth += sent_buffer[i];
}
incoming_bandwidth = stats.incoming_bandwidth /= MAX_RATE_SAMPLES;
outgoing_bandwidth = stats.outgoing_bandwidth /= MAX_RATE_SAMPLES;
next_measure = zpl_time_rel() + 1.0;
} else {
stats.incoming_bandwidth = incoming_bandwidth;
stats.outgoing_bandwidth = outgoing_bandwidth;
}
stats.packets_sent = peer->totalPacketsSent;
stats.packets_lost = peer->totalPacketsLost;
if (stats.packets_sent > 0) {
stats.packet_loss = stats.packets_lost / (float)stats.packets_sent;
}
stats.ping = peer->roundTripTime;
stats.low_ping = peer->lowestRoundTripTime;
return stats;
}
//~ NOTE(zaklaus): server //~ NOTE(zaklaus): server

View File

@ -11,6 +11,30 @@ int32_t network_client_tick(void);
void network_client_update(void *data); void network_client_update(void *data);
bool network_client_is_connected(); bool network_client_is_connected();
typedef struct {
// NOTE(zaklaus): persistent stats bytes
uint32_t incoming_total;
uint64_t total_received;
uint32_t outgoing_total;
uint64_t total_sent;
// NOTE(zaklaus): bandwidth (bytes/sec)
float incoming_bandwidth;
float outgoing_bandwidth;
// NOTE(zaklaus): packet integrity
uint64_t packets_sent;
uint32_t packets_lost;
float packet_loss;
// NOTE(zaklaus): ping
uint32_t ping;
uint32_t low_ping;
} network_client_stats;
network_client_stats
network_client_fetch_stats(void);
// NOTE(zaklaus): server // NOTE(zaklaus): server
int32_t network_server_start(const char *host, uint16_t port); int32_t network_server_start(const char *host, uint16_t port);
int32_t network_server_stop(void); int32_t network_server_stop(void);

View File

@ -311,9 +311,9 @@ int32_t world_update() {
slow_ms = WORLD_TRACKER_UPDATE_MP_SLOW_MS; slow_ms = WORLD_TRACKER_UPDATE_MP_SLOW_MS;
} }
world_tracker_update(0, fast_ms, 2); world_tracker_update(0, fast_ms, 1);
world_tracker_update(1, normal_ms, 4); world_tracker_update(1, normal_ms, 2);
world_tracker_update(2, slow_ms, 6); world_tracker_update(2, slow_ms, 3);
debug_replay_update(); debug_replay_update();
return 0; return 0;