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_ypos = DBG_START_YPOS;
typedef enum {
L_NONE = 0,
L_SP,
L_MP,
} limit_kind;
typedef struct debug_item {
debug_kind kind;
char const *name;
float name_width;
uint8_t skip;
limit_kind limit_to;
union {
union {
@ -57,7 +64,6 @@ typedef struct debug_item {
struct {
struct debug_item *items;
uint8_t is_collapsed;
uint8_t is_sp_only;
} list;
struct {
@ -114,8 +120,8 @@ static debug_item items[] = {
{ .kind = DITEM_END },
},
.is_sp_only = true,
}
},
.limit_to = L_SP,
},
{
.kind = DITEM_LIST,
@ -142,8 +148,27 @@ static debug_item items[] = {
},
{ .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,
@ -178,9 +203,9 @@ static debug_item items[] = {
{ .kind = DITEM_END },
},
.is_sp_only = true,
.is_collapsed = true,
}
},
.limit_to = L_SP,
},
{
.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) {
is_shadow_rendered = is_shadow;
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) {
case DITEM_GAP: {
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);
ypos += DBG_FONT_SPACING;
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);
ypos = res.y;
}break;
case DITEM_TEXT: {
if (it->name) {
char const *text = TextFormat("%s: ", it->name);
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);
}
debug_draw_result res = it->proc(it, xpos + it->name_width, ypos);
ypos = res.y;

View File

@ -1,6 +1,7 @@
#include "debug_ui.h"
#include "world/blocks.h"
#include "items.h"
#include "network.h"
void
ActExitGame(void) {
@ -269,3 +270,15 @@ uint8_t
CondIsWorldRunning(void) {
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 "raylib.h"
#include "platform.h"
#include "network.h"
#include "profiler.h"
//~ NOTE(zaklaus): helpers
@ -16,7 +17,16 @@ static inline debug_draw_result
DrawColoredText(float xpos, float ypos, char const *text, Color color) {
ZPL_ASSERT(text);
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
@ -99,3 +109,31 @@ DrawWorldStepSize(debug_item *it, float xpos, float ypos) {
(void)it;
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) {
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() {
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

View File

@ -11,6 +11,30 @@ int32_t network_client_tick(void);
void network_client_update(void *data);
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
int32_t network_server_start(const char *host, uint16_t port);
int32_t network_server_stop(void);

View File

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