u/metrics: Add functions to write a metrics file

This commit is contained in:
Jakob Bornecrantz 2022-09-20 01:08:42 +01:00 committed by Moses Turner
parent 57a31fde7c
commit 7fa20a8b46
3 changed files with 351 additions and 1 deletions

View file

@ -61,6 +61,8 @@ add_library(
u_json.hpp
u_logging.c
u_logging.h
u_metrics.c
u_metrics.h
u_misc.c
u_misc.h
u_pacing.h
@ -98,7 +100,15 @@ add_library(
u_worker.hpp
"${CMAKE_CURRENT_BINARY_DIR}/u_git_tag.c"
)
target_link_libraries(aux_util PUBLIC aux-includes aux_generated_bindings aux_os aux_math)
target_link_libraries(
aux_util
PUBLIC
xrt-external-nanopb
aux-includes
aux_generated_bindings
aux_os
aux_math
)
# Is basically used everywhere, unavoidable.
if(XRT_HAVE_SYSTEM_CJSON)

View file

@ -0,0 +1,230 @@
// Copyright 2022, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Metrics saving functions.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup aux_util
*/
#include "os/os_threading.h"
#include "util/u_metrics.h"
#include "util/u_debug.h"
#include "monado_metrics.pb.h"
#include "pb_encode.h"
#include <stdio.h>
#define VERSION_MAJOR 1
#define VERSION_MINOR 1
static FILE *g_file = NULL;
static struct os_mutex g_file_mutex;
static bool g_metrics_initialized = false;
DEBUG_GET_ONCE_OPTION(metrics_file, "XRT_METRICS_FILE", NULL)
/*
*
* Helper functions.
*
*/
static void
write_record(monado_metrics_Record *r)
{
uint8_t buffer[monado_metrics_Record_size + 10]; // Including submessage
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
bool ret = pb_encode_submessage(&stream, &monado_metrics_Record_msg, r);
if (!ret) {
U_LOG_E("Failed to encode metrics message!");
return;
}
os_mutex_lock(&g_file_mutex);
fwrite(buffer, stream.bytes_written, 1, g_file);
os_mutex_unlock(&g_file_mutex);
}
static void
write_version(uint32_t major, uint32_t minor)
{
if (!g_metrics_initialized) {
return;
}
monado_metrics_Record record = monado_metrics_Record_init_default;
// Select which filed is used.
record.which_record = monado_metrics_Record_version_tag;
record.record.version.major = major;
record.record.version.minor = minor;
write_record(&record);
}
/*
*
* 'Exported' functions.
*
*/
void
u_metrics_init()
{
const char *str = debug_get_option_metrics_file();
if (str == NULL) {
U_LOG_D("No metrics file!");
return;
}
g_file = fopen(str, "wb");
if (g_file == NULL) {
U_LOG_E("Could not open '%s'!", str);
return;
}
os_mutex_init(&g_file_mutex);
g_metrics_initialized = true;
write_version(VERSION_MAJOR, VERSION_MINOR);
U_LOG_I("Opened metrics file: '%s'", str);
}
void
u_metrics_close()
{
if (!g_metrics_initialized) {
return;
}
U_LOG_I("Closing metrics file: '%s'", debug_get_option_metrics_file());
// At least try to avoid races.
os_mutex_lock(&g_file_mutex);
fflush(g_file);
fclose(g_file);
g_file = NULL;
os_mutex_unlock(&g_file_mutex);
os_mutex_destroy(&g_file_mutex);
g_metrics_initialized = false;
}
bool
u_metrics_is_active(void)
{
return g_metrics_initialized;
}
void
u_metrics_write_session_frame(struct u_metrics_session_frame *umsf)
{
if (!g_metrics_initialized) {
return;
}
monado_metrics_Record record = monado_metrics_Record_init_default;
// Select which filed is used.
record.which_record = monado_metrics_Record_session_frame_tag;
#define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.session_frame.FIELD = umsf->FIELD);
monado_metrics_SessionFrame_FIELDLIST(COPY, 0);
#undef COPY
write_record(&record);
}
void
u_metrics_write_used(struct u_metrics_used *umu)
{
if (!g_metrics_initialized) {
return;
}
monado_metrics_Record record = monado_metrics_Record_init_default;
// Select which filed is used.
record.which_record = monado_metrics_Record_used_tag;
#define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.used.FIELD = umu->FIELD);
monado_metrics_Used_FIELDLIST(COPY, 0);
#undef COPY
write_record(&record);
}
void
u_metrics_write_system_frame(struct u_metrics_system_frame *umsf)
{
if (!g_metrics_initialized) {
return;
}
monado_metrics_Record record = monado_metrics_Record_init_default;
// Select which filed is used.
record.which_record = monado_metrics_Record_system_frame_tag;
#define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.system_frame.FIELD = umsf->FIELD);
monado_metrics_SystemFrame_FIELDLIST(COPY, 0);
#undef COPY
write_record(&record);
}
void
u_metrics_write_system_gpu_info(struct u_metrics_system_gpu_info *umgi)
{
if (!g_metrics_initialized) {
return;
}
monado_metrics_Record record = monado_metrics_Record_init_default;
// Select which filed is used.
record.which_record = monado_metrics_Record_system_gpu_info_tag;
#define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.system_gpu_info.FIELD = umgi->FIELD);
monado_metrics_SystemGpuInfo_FIELDLIST(COPY, 0);
#undef COPY
write_record(&record);
}
void
u_metrics_write_system_present_info(struct u_metrics_system_present_info *umpi)
{
if (!g_metrics_initialized) {
return;
}
monado_metrics_Record record = monado_metrics_Record_init_default;
// Select which filed is used.
record.which_record = monado_metrics_Record_system_present_info_tag;
#define COPY(_0, _1, _2, _3, FIELD, _4) (record.record.system_present_info.FIELD = umpi->FIELD);
monado_metrics_SystemPresentInfo_FIELDLIST(COPY, 0);
#undef COPY
write_record(&record);
}

View file

@ -0,0 +1,110 @@
// Copyright 2022, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Metrics saving functions.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup aux_util
*/
#pragma once
#include "xrt/xrt_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
struct u_metrics_session_frame
{
int64_t session_id;
int64_t frame_id;
uint64_t predicted_frame_time_ns;
uint64_t predicted_wake_up_time_ns;
uint64_t predicted_gpu_done_time_ns;
uint64_t predicted_display_time_ns;
uint64_t predicted_display_period_ns;
uint64_t display_time_ns;
uint64_t when_predicted_ns;
uint64_t when_wait_woke_ns;
uint64_t when_begin_ns;
uint64_t when_delivered_ns;
uint64_t when_gpu_done_ns;
bool discarded;
};
struct u_metrics_used
{
int64_t session_id;
int64_t session_frame_id;
int64_t system_frame_id;
uint64_t when_ns;
};
struct u_metrics_system_frame
{
int64_t frame_id;
uint64_t predicted_display_time_ns;
uint64_t predicted_display_period_ns;
uint64_t desired_present_time_ns;
uint64_t wake_up_time_ns;
uint64_t present_slop_ns;
};
struct u_metrics_system_gpu_info
{
int64_t frame_id;
uint64_t gpu_start_ns;
uint64_t gpu_end_ns;
uint64_t when_ns;
};
struct u_metrics_system_present_info
{
int64_t frame_id;
uint64_t expected_comp_time_ns;
uint64_t predicted_wake_up_time_ns;
uint64_t predicted_done_time_ns;
uint64_t predicted_display_time_ns;
uint64_t when_predict_ns;
uint64_t when_woke_ns;
uint64_t when_began_ns;
uint64_t when_submitted_ns;
uint64_t when_infoed_ns;
uint64_t desired_present_time_ns;
uint64_t present_slop_ns;
uint64_t present_margin_ns;
uint64_t actual_present_time_ns;
uint64_t earliest_present_time_ns;
};
void
u_metrics_init(void);
void
u_metrics_close(void);
bool
u_metrics_is_active(void);
void
u_metrics_write_session_frame(struct u_metrics_session_frame *umsf);
void
u_metrics_write_used(struct u_metrics_used *umu);
void
u_metrics_write_system_frame(struct u_metrics_system_frame *umsf);
void
u_metrics_write_system_gpu_info(struct u_metrics_system_gpu_info *umgi);
void
u_metrics_write_system_present_info(struct u_metrics_system_present_info *umpi);
#ifdef __cplusplus
}
#endif