vk: profiler: metrics: store filepath, but print only filename

Previously, source filepath was truncated right at metric registration,
so only the filename was stored.  Now, full source filepath is stored.
The truncation to its filename happens only in metrics print.  This way
we preserve full information, but also throw away redundancy in print.
This commit is contained in:
nilsoncore 2023-09-18 00:35:35 +03:00
parent 79c2d5768f
commit d5df2d2791
3 changed files with 35 additions and 59 deletions

View File

@ -10,14 +10,12 @@
// I.e. it is invalid to call any of the functions before the first of aprof_scope_init/APROF_SCOPE_INIT/APROF_SCOPE_DECLARE_BEGIN is called.
// TODO: explicit initialization function
#define APROF_FILENAME(filepath) aprof_get_filename_from_filepath( filepath, Q_strlen( filepath ) )
#define APROF_SCOPE_DECLARE(scope) \
static aprof_scope_id_t _aprof_scope_id_##scope = -1
// scope_name is expected to be static and alive for the entire duration of the program
#define APROF_SCOPE_INIT_EX(scope, scope_name, flags) \
_aprof_scope_id_##scope = aprof_scope_init(scope_name, flags, APROF_FILENAME( __FILE__ ), __LINE__)
_aprof_scope_id_##scope = aprof_scope_init(scope_name, flags, __FILE__, __LINE__)
#define APROF_SCOPE_INIT(scope, scope_name) APROF_SCOPE_INIT_EX(scope, scope_name, 0)
@ -27,7 +25,7 @@
#define APROF_SCOPE_DECLARE_BEGIN_EX(scope, scope_name, flags) \
static aprof_scope_id_t _aprof_scope_id_##scope = -1; \
if (_aprof_scope_id_##scope == -1) { \
_aprof_scope_id_##scope = aprof_scope_init(scope_name, flags, APROF_FILENAME( __FILE__ ), __LINE__); \
_aprof_scope_id_##scope = aprof_scope_init(scope_name, flags, __FILE__, __LINE__); \
} \
aprof_scope_event(_aprof_scope_id_##scope, 1)
@ -45,14 +43,8 @@
typedef int aprof_scope_id_t;
// Returns pointer to filename in filepath string.
// Ideally, this function should be static and visible only inside file scope,
// but then the `APROF_FILENAME` macro would not work.
// Also, maybe this function should be inside filesystem or something like that.
const char *aprof_get_filename_from_filepath( const char *filepath, size_t filepath_length );
// scope_name should be static const, and not on stack
aprof_scope_id_t aprof_scope_init(const char *scope_name, uint32_t flags, const char *source_filename, int source_line);
aprof_scope_id_t aprof_scope_init(const char *scope_name, uint32_t flags, const char *source_file, int source_line);
void aprof_scope_event(aprof_scope_id_t, int begin);
// Returns event index for previous frame
uint32_t aprof_scope_frame( void );
@ -77,7 +69,7 @@ enum {
typedef struct {
const char *name;
uint32_t flags;
const char *source_filename;
const char *source_file;
int source_line;
} aprof_scope_t;
@ -157,28 +149,7 @@ uint64_t aprof_time_platform_to_ns( uint64_t platform_time ) {
aprof_state_t g_aprof = {0};
// Returns pointer to filename in filepath string.
// Examples:
// on Windows: C:/Users/User/xash3d-fwgs/ref/vk/vk_rtx.c -> vk_rtx.c
// on Linux: /home/user/xash3d-fwgs/ref/vk/vk_rtx.c -> vk.rtx.c (imaginary example, not tested)
const char *aprof_get_filename_from_filepath( const char *filepath, size_t filepath_length ) {
if ( !filepath_length )
filepath_length = Q_strlen( filepath );
int cursor = filepath_length - 1;
while ( cursor > 0 ) {
char c = filepath[cursor];
if ( c == '/' || c == '\\' ) {
// Advance by 1 char to skip the folder delimiter symbol itself.
return &filepath[cursor + 1];
}
cursor -= 1;
}
return NULL;
}
aprof_scope_id_t aprof_scope_init(const char *scope_name, uint32_t flags, const char *source_filename, int source_line) {
aprof_scope_id_t aprof_scope_init(const char *scope_name, uint32_t flags, const char *source_file, int source_line) {
#if defined(_WIN32)
if (_aprof_frequency.QuadPart == 0)
QueryPerformanceFrequency(&_aprof_frequency);
@ -192,7 +163,7 @@ aprof_scope_id_t aprof_scope_init(const char *scope_name, uint32_t flags, const
g_aprof.scopes[g_aprof.num_scopes].name = scope_name;
g_aprof.scopes[g_aprof.num_scopes].flags = flags;
g_aprof.scopes[g_aprof.num_scopes].source_filename = source_filename;
g_aprof.scopes[g_aprof.num_scopes].source_file = source_file;
g_aprof.scopes[g_aprof.num_scopes].source_line = source_line;
return g_aprof.num_scopes++;
}

View File

@ -220,16 +220,7 @@ static void drawCPUProfilerScopes(int draw, const aprof_event_t *events, uint64_
const uint64_t delta_ns = timestamp_ns - stack[depth].begin_ns;
if (!g_speeds.frame.scopes[scope_id].initialized) {
R_SpeedsRegisterMetric(
/* p_value */ &g_speeds.frame.scopes[scope_id].time_us,
/* module */ "scope",
/* name */ scope->name,
/* type */ kSpeedsMetricMicroseconds,
/* reset */ true,
/* var_name */ scope->name,
/* file */ scope->source_filename,
/* line */ scope->source_line);
R_SpeedsRegisterMetric(&g_speeds.frame.scopes[scope_id].time_us, "scope", scope->name, kSpeedsMetricMicroseconds, /* reset */ true, scope->name, scope->source_file, scope->source_line);
g_speeds.frame.scopes[scope_id].initialized = 1;
}
@ -442,16 +433,7 @@ static void drawGPUProfilerScopes(qboolean draw, int y, uint64_t frame_begin_tim
const char *name = gpurofl->scopes[scope_index].name;
if (!g_speeds.frame.gpu_scopes[scope_index].initialized) {
R_SpeedsRegisterMetric(
/* p_value */ &g_speeds.frame.gpu_scopes[scope_index].time_us,
/* module */ "gpuscope",
/* name */ name,
/* type */ kSpeedsMetricMicroseconds,
/* reset */ true,
/* var_name */ name,
/* file */ APROF_FILENAME( __FILE__ ),
/* line */ __LINE__);
R_SpeedsRegisterMetric(&g_speeds.frame.gpu_scopes[scope_index].time_us,"gpuscope", name, kSpeedsMetricMicroseconds, /* reset */ true, name, __FILE__, __LINE__);
g_speeds.frame.gpu_scopes[scope_index].initialized = 1;
}
@ -729,6 +711,30 @@ static const char *getMetricTypeName(r_speeds_metric_type_t type) {
return "UNKNOWN";
}
// Returns pointer to filename in filepath string.
// Maybe function like this should be inside filesystem?
// Examples:
// on Windows: C:\Users\User\xash3d-fwgs\ref\vk\vk_rtx.c -> vk_rtx.c
// on Linux: /home/user/xash3d-fwgs/ref/vk/vk_rtx.c -> vk.rtx.c (imaginary example, not tested)
static const char *get_filename_from_filepath( const char *filepath ) {
size_t length = Q_strlen( filepath );
int cursor = length - 1;
while ( cursor > 0 ) {
char c = filepath[cursor];
if ( c == '/' || c == '\\' ) {
// Advance by 1 char to skip the folder delimiter symbol itself, but
// make sure that we are not exceeding the length.
if ( cursor < length )
cursor += 1;
return &filepath[cursor];
}
cursor -= 1;
}
return NULL;
}
// Actually does the job of `r_speeds_mlist` and `r_speeds_mtable` commands.
// We can't just directly call this function from little command handler ones, because
// all the metrics calculations happen inside `R_SpeedsDisplayMore` function.
@ -770,7 +776,7 @@ static void doPrintMetrics( r_speeds_mprint_mode_t *print_mode, const char *prin
char value_with_unit[16];
metricTypeSnprintf( value_with_unit, sizeof( value_with_unit ), *metric->p_value, metric->type );
gEngine.Con_Printf( row_format, metric->name, value_with_unit, metric->var_name, metric->src_file, metric->src_line );
gEngine.Con_Printf( row_format, metric->name, value_with_unit, metric->var_name, get_filename_from_filepath( metric->src_file ), metric->src_line );
}
gEngine.Con_Printf( line_format, line, line, line, line );
gEngine.Con_Printf( header_format, "module.metric_name", "value", "variable", "registration_location" );

View File

@ -1,6 +1,5 @@
#pragma once
#include "xash3d_types.h"
#include "profiler.h" // APROF_FILENAME
#include <stdint.h>
void R_SpeedsInit( void );
@ -23,9 +22,9 @@ void R_SpeedsRegisterMetric(int* p_value, const char *module, const char *name,
// A counter is a value accumulated during a single frame, and reset to zero between frames.
// Examples: drawn models count, scope times, etc.
#define R_SPEEDS_COUNTER(var, name, type) \
R_SpeedsRegisterMetric(&(var), MODULE_NAME, name, type, /*reset*/ true, #var, APROF_FILENAME( __FILE__ ), __LINE__)
R_SpeedsRegisterMetric(&(var), MODULE_NAME, name, type, /*reset*/ true, #var, __FILE__, __LINE__)
// A metric is computed and preserved across frame boundaries.
// Examples: total allocated memory, cache sizes, etc.
#define R_SPEEDS_METRIC(var, name, type) \
R_SpeedsRegisterMetric(&(var), MODULE_NAME, name, type, /*reset*/ false, #var, APROF_FILENAME( __FILE__ ), __LINE__)
R_SpeedsRegisterMetric(&(var), MODULE_NAME, name, type, /*reset*/ false, #var, __FILE__, __LINE__)