vk/speeds: preserve metric names that might not be registered initially

When `r_speeds_graphs` cvar is read for the first time, not all metrics
might be registered yet. It leads to some graphs missing.

Retry searching for these metrics on further frames, thus preserving the
graph list from previous session fully.
This commit is contained in:
Ivan Avdeev 2023-06-13 11:52:46 -07:00
parent c72ff1d0c5
commit 5dda220751
1 changed files with 133 additions and 85 deletions

View File

@ -40,10 +40,11 @@ typedef struct {
} r_speeds_metric_t;
typedef struct {
char name[64];
float *data;
int data_count;
int data_write;
int source_metric;
int source_metric; // can be -1 for missing metrics
int height;
int max_value; // Computed automatically every frame
@ -95,8 +96,8 @@ static void speedsStrcat( const char *msg ) {
static void speedsPrintf( const char *msg, ... ) _format(1);
static void speedsPrintf( const char *msg, ... ) {
va_list argptr;
char text[MAX_SPEEDS_MESSAGE];
va_list argptr;
char text[MAX_SPEEDS_MESSAGE];
va_start( argptr, msg );
Q_vsnprintf( text, sizeof( text ), msg, argptr );
@ -280,6 +281,42 @@ static void handlePause( uint32_t prev_frame_index ) {
}
}
typedef struct {
const char *s;
int len;
} const_string_view_t;
static int stringViewCmp(const_string_view_t sv, const char* s) {
for (int i = 0; i < sv.len; ++i) {
const int d = sv.s[i] - s[i];
if (d != 0)
return d;
if (s[i] == '\0')
return 1;
}
// Check that both strings end the same
return '\0' - s[sv.len];
}
static int findMetricIndexByName( const_string_view_t name) {
for (int i = 0; i < g_speeds.metrics_count; ++i) {
if (stringViewCmp(name, g_speeds.metrics[i].name) == 0)
return i;
}
return -1;
}
static int findGraphIndexByName( const_string_view_t name) {
for (int i = 0; i < g_speeds.graphs_count; ++i) {
if (stringViewCmp(name, g_speeds.graphs[i].name) == 0)
return i;
}
return -1;
}
static int drawGraph( r_speeds_graph_t *const graph, int frame_bar_y ) {
const int min_width = 100 * g_speeds.font_metrics.scale;
const int graph_width = clampi32(
@ -289,6 +326,22 @@ static int drawGraph( r_speeds_graph_t *const graph, int frame_bar_y ) {
min_width, vk_frame.width); // clamp to min_width..frame_width
const int graph_height = graph->height * g_speeds.font_metrics.scale;
if (graph->source_metric < 0) {
// Check whether this metric has been registered
const int metric_index = findMetricIndexByName((const_string_view_t){graph->name, Q_strlen(graph->name)});
if (metric_index >= 0) {
graph->source_metric = metric_index;
g_speeds.metrics[metric_index].graph_index = graph - g_speeds.graphs;
} else {
const char *name = graph->name;
rgba_t text_color = {0xff, 0x00, 0x00, 0xff};
gEngine.Con_DrawString(0, frame_bar_y, name, text_color);
frame_bar_y += g_speeds.font_metrics.glyph_height;
return frame_bar_y;
}
}
const r_speeds_metric_t *const metric = g_speeds.metrics + graph->source_metric;
const int graph_max_value = metric->max_value ? Q_max(metric->max_value, graph->max_value) : graph->max_value;
@ -493,7 +546,10 @@ static void getCurrentFontMetrics(void) {
static int drawGraphs( int y ) {
for (int i = 0; i < g_speeds.graphs_count; ++i) {
r_speeds_graph_t *const graph = g_speeds.graphs + i;
graph->data[graph->data_write] = *g_speeds.metrics[graph->source_metric].p_value;
if (graph->source_metric >= 0)
graph->data[graph->data_write] = *g_speeds.metrics[graph->source_metric].p_value;
graph->data_write = (graph->data_write + 1) % graph->data_count;
y = drawGraph(graph, y) + 10;
}
@ -512,31 +568,36 @@ static void togglePause( void ) {
}
}
typedef struct {
const char *s;
int len;
} const_string_view_t;
static void speedsGraphAdd(const_string_view_t name, int metric_index) {
gEngine.Con_Printf("Adding profiler graph for metric %.*s(%d) at graph index %d\n", name.len, name.s, metric_index, g_speeds.graphs_count);
static int stringViewCmp(const_string_view_t sv, const char* s) {
for (int i = 0; i < sv.len; ++i) {
const int d = sv.s[i] - s[i];
if (d != 0)
return d;
if (s[i] == '\0')
return 1;
if (g_speeds.graphs_count == MAX_GRAPHS) {
gEngine.Con_Printf(S_ERROR "Cannot add graph \"%.*s\", no free graphs slots (max=%d)\n", name.len, name.s, MAX_GRAPHS);
return;
}
// Check that both strings end the same
return '\0' - s[sv.len];
}
static int findMetricIndexByName( const_string_view_t name) {
for (int i = 0; i < g_speeds.metrics_count; ++i) {
if (stringViewCmp(name, g_speeds.metrics[i].name) == 0)
return i;
if (metric_index >= 0) {
r_speeds_metric_t *const metric = g_speeds.metrics + metric_index;
metric->graph_index = g_speeds.graphs_count;
}
return -1;
r_speeds_graph_t *const graph = g_speeds.graphs + g_speeds.graphs_count++;
// TODO make these customizable
graph->data_count = 256;
graph->height = 100;
graph->max_value = 1; // Will be computed automatically on first frame
graph->color[3] = 255;
const int len = Q_min(name.len, sizeof(graph->name) - 1);
memcpy(graph->name, name.s, len);
graph->name[len] = '\0';
getColorForString(graph->name, graph->color);
ASSERT(!graph->data);
graph->data = Mem_Calloc(vk_core.pool, graph->data_count * sizeof(float));
graph->data_write = 0;
graph->source_metric = metric_index;
}
static void speedsGraphAddByMetricName( const_string_view_t name ) {
@ -552,63 +613,45 @@ static void speedsGraphAddByMetricName( const_string_view_t name ) {
return;
}
if (g_speeds.graphs_count == MAX_GRAPHS) {
gEngine.Con_Printf(S_ERROR "Cannot add graph for metric \"%.*s\", no free graphs slots (max=%d)\n", name.len, name.s, MAX_GRAPHS);
return;
}
gEngine.Con_Printf("Adding profiler graph for metric %.*s(%d) at graph index %d\n", name.len, name.s, metric_index, g_speeds.graphs_count);
metric->graph_index = g_speeds.graphs_count++;
r_speeds_graph_t *const graph = g_speeds.graphs + metric->graph_index;
// TODO make these customizable
graph->data_count = 256;
graph->height = 100;
graph->max_value = 1; // Will be computed automatically on first frame
graph->color[3] = 255;
getColorForString(metric->name, graph->color);
ASSERT(!graph->data);
graph->data = Mem_Calloc(vk_core.pool, graph->data_count * sizeof(float));
graph->data_write = 0;
graph->source_metric = metric_index;
speedsGraphAdd( name, metric_index );
}
static void speedsGraphRemoveByMetricName( const_string_view_t name ) {
const int metric_index = findMetricIndexByName(name);
if (metric_index < 0) {
gEngine.Con_Printf(S_ERROR "Metric \"%.*s\" not found\n", name.len, name.s);
return;
}
static void speedsGraphDelete( r_speeds_graph_t *graph ) {
ASSERT(graph->data);
Mem_Free(graph->data);
graph->data = NULL;
graph->name[0] = '\0';
r_speeds_metric_t *const metric = g_speeds.metrics + metric_index;
if (metric->graph_index < 0) {
gEngine.Con_Printf(S_WARN "Metric \"%.*s\" doesn't have a graph\n", name.len, name.s);
return;
}
gEngine.Con_Printf("Removing profiler graph for metric %.*s(%d) at graph index %d\n", name.len, name.s, metric_index, metric->graph_index);
// Remove/free the graph itself
const int graph_index = metric->graph_index;
{
r_speeds_graph_t *const graph = g_speeds.graphs + metric->graph_index;
ASSERT(graph->data);
Mem_Free(graph->data);
graph->data = NULL;
ASSERT(graph->source_metric >= 0);
if (graph->source_metric >= 0) {
ASSERT(graph->source_metric < g_speeds.metrics_count);
r_speeds_metric_t *const metric = g_speeds.metrics + graph->source_metric;
metric->graph_index = -1;
}
graph->source_metric = -1;
}
static void speedsGraphRemoveByName( const_string_view_t name ) {
const int graph_index = findGraphIndexByName(name);
if (graph_index < 0) {
gEngine.Con_Printf(S_ERROR "Graph \"%.*s\" not found\n", name.len, name.s);
return;
}
r_speeds_graph_t *const graph = g_speeds.graphs + graph_index;
speedsGraphDelete( graph );
gEngine.Con_Printf("Removing profiler graph %.*s(%d) at graph index %d\n", name.len, name.s, graph->source_metric, graph_index);
// Move all further graphs one slot back, also updating their indices
for (int i = graph_index + 1; i < g_speeds.graphs_count; ++i) {
r_speeds_graph_t *const dst = g_speeds.graphs + i - 1;
const r_speeds_graph_t *const src = g_speeds.graphs + i;
g_speeds.metrics[src->source_metric].graph_index--;
if (src->source_metric >= 0) {
ASSERT(src->source_metric < g_speeds.metrics_count);
g_speeds.metrics[src->source_metric].graph_index--;
}
memcpy(dst, src, sizeof(r_speeds_graph_t));
}
@ -620,13 +663,7 @@ static void speedsGraphsRemoveAll( void ) {
gEngine.Con_Printf("Removing all %d profiler graphs\n", g_speeds.graphs_count);
for (int i = 0; i < g_speeds.graphs_count; ++i) {
r_speeds_graph_t *const graph = g_speeds.graphs + i;
ASSERT(graph->data);
Mem_Free(graph->data);
graph->data = NULL;
ASSERT(graph->source_metric >= 0);
ASSERT(graph->source_metric < g_speeds.metrics_count);
g_speeds.metrics[graph->source_metric].graph_index = -1;
speedsGraphDelete(graph);
}
g_speeds.graphs_count = 0;
@ -646,7 +683,13 @@ static void processGraphCvar( void ) {
while (*p) {
const char *next = Q_strchrnul(p, ',');
const const_string_view_t name = {p, next - p};
speedsGraphAddByMetricName( name );
const int metric_index = findMetricIndexByName(name);
if (metric_index < 0) {
gEngine.Con_Printf(S_WARN "Metric \"%.*s\" not found (yet? can be registered later)\n", name.len, name.s);
}
speedsGraphAdd( name, metric_index );
if (!*next)
break;
p = next + 1;
@ -724,7 +767,7 @@ static void graphCmd( void ) {
for (int i = 2; i < argc; ++i) {
const char *const arg = gEngine.Cmd_Argv(i);
const const_string_view_t name = {arg, Q_strlen(arg) };
speedsGraphRemoveByMetricName( name );
speedsGraphRemoveByName( name );
}
break;
case Clear:
@ -739,21 +782,26 @@ static void graphCmd( void ) {
// update cvar
{
g_speeds.graphs_list[0] = '\0';
const int len = sizeof(g_speeds.graphs_list) - 1;
char *const buf = g_speeds.graphs_list;
buf[0] = '\0';
int off = 0;
for (int i = 0; i < g_speeds.graphs_count; ++i) {
const r_speeds_graph_t *const graph = g_speeds.graphs + i;
ASSERT(graph->source_metric >= 0);
ASSERT(graph->source_metric < g_speeds.metrics_count);
const char *const name = g_speeds.metrics[graph->source_metric].name;
if (off)
buf[off++] = ',';
off += Q_strncat(buf + off, name, sizeof(buf) - off);
if (off == sizeof(buf))
//gEngine.Con_Reportf("buf='%s' off=%d %s(%d)\n", buf, off, graph->name, (int)Q_strlen(graph->name));
const char *s = graph->name;
while (off < len && *s)
buf[off++] = *s++;
buf[off] = '\0';
if (off >= len - 1)
break;
}