network stats + tweaks
parent
970334aa7a
commit
63db7893b4
|
@ -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: {
|
||||
char const *text = TextFormat("%s: ", it->name);
|
||||
if (it->name_width == 0) {
|
||||
it->name_width = (float)UIMeasureText(text, DBG_FONT_SIZE);
|
||||
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);
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue