u/live_stats: Add helper to do live statistics on nano-seconds durations

This commit is contained in:
Jakob Bornecrantz 2024-01-03 19:09:27 +00:00
parent cd2274b370
commit 40534011e8
3 changed files with 225 additions and 0 deletions

View file

@ -61,6 +61,8 @@ add_library(
u_json.hpp
u_limited_unique_id.cpp
u_limited_unique_id.h
u_live_stats.cpp
u_live_stats.h
u_logging.c
u_logging.h
u_metrics.c

View file

@ -0,0 +1,117 @@
// Copyright 2024, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Live stats tracking and printing.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup aux_util
*/
#include "u_live_stats.h"
#include <inttypes.h>
#include <algorithm>
/*
*
* Helper functions.
*
*/
static void
print_as_ms(u_pp_delegate_t dg, uint64_t value_ns)
{
uint64_t in_us = value_ns / 1000;
uint64_t in_ms = in_us / 1000;
uint64_t in_1_000_ms = in_ms / 1000;
uint64_t in_1_000_000_ms = in_1_000_ms / 1000;
// Prints " M'TTT'###.FFFms"
// " M'"
if (in_1_000_000_ms >= 1) {
u_pp(dg, " %" PRIu64 "'", in_1_000_000_ms);
} else {
// " M'"
u_pp(dg, " ");
}
// "TTT'"
if (in_1_000_ms >= 1000) {
// Need to pad with zeros
u_pp(dg, "%03" PRIu64 "'", in_1_000_ms % 1000);
} else if (in_1_000_ms >= 1) {
// Pad with spaces, we need to write a number.
u_pp(dg, "%3" PRIu64 "'", in_1_000_ms);
} else {
// "TTT'"
u_pp(dg, " ");
}
// "###"
if (in_ms >= 1000) {
// Need to pad with zeros
u_pp(dg, "%03" PRIu64, in_ms % 1000);
} else {
// Pad with spaces, always need a numbere here.
u_pp(dg, "%3" PRIu64, in_ms % 1000);
}
// ".FFFms"
u_pp(dg, ".%03" PRIu64 "ms", in_us % 1000);
}
/*
*
* 'Exported' functions.
*
*/
extern "C" void
u_ls_ns_get_and_reset(struct u_live_stats_ns *uls, uint64_t *out_median, uint64_t *out_mean, uint64_t *out_worst)
{
uint32_t count = uls->value_count;
if (count == 0) {
*out_median = 0;
*out_mean = 0;
*out_worst = 0;
return;
}
std::sort(&uls->values[0], &uls->values[count]);
uint64_t worst = uls->values[count - 1]; // Always greater then 0.
uint64_t median = uls->values[count / 2];
uint64_t mean = 0;
for (uint32_t i = 0; i < count; ++i) {
mean += uls->values[i] / count;
}
uls->value_count = 0;
*out_median = median;
*out_mean = mean;
*out_worst = worst;
}
extern "C" void
u_ls_ns_print_header(u_pp_delegate_t dg)
{
// "xxxxYYYYzzzzWWWW M'TTT'###.FFFms M'TTT'###.FFFms M'TTT'###.FFFms"
u_pp(dg, " name median mean worst");
}
extern "C" void
u_ls_ns_print_and_reset(struct u_live_stats_ns *uls, u_pp_delegate_t dg)
{
uint64_t median, mean, worst;
u_ls_ns_get_and_reset(uls, &median, &mean, &worst);
u_pp(dg, "%16s", uls->name);
print_as_ms(dg, median);
print_as_ms(dg, mean);
print_as_ms(dg, worst);
}

View file

@ -0,0 +1,106 @@
// Copyright 2024, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Live stats tracking and printing.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup aux_util
*/
#pragma once
#include "xrt/xrt_compiler.h"
#include "util/u_pretty_print.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!
* Number of chars for the name of the live stats.
*
* @ingroup aux_util
*/
#define U_LIVE_STATS_NAME_COUNT (16)
/*!
* Max number of values that can be put into the trackers.
*
* @ingroup aux_util
*/
#define U_LIVE_STATS_VALUE_COUNT (1024)
/*!
* Struct to do live statistic tracking and printing of nano-seconds values,
* used by amongst other the compositor pacing code.
*
* @ingroup aux_util
*/
struct u_live_stats_ns
{
//! Small name used for printing.
char name[U_LIVE_STATS_NAME_COUNT];
//! Number of values currently in struct.
uint32_t value_count;
//! The values that will be used to calculate statistics.
uint64_t values[U_LIVE_STATS_VALUE_COUNT];
};
/*!
* Add a value to the live stats struct, returns true if the struct is full
* either before or after adding the value.
*
* @public @memberof u_live_stats_ns
* @ingroup aux_util
*/
static inline bool
u_ls_ns_add(struct u_live_stats_ns *uls, uint64_t value)
{
if (uls->value_count >= ARRAY_SIZE(uls->values)) {
return true;
}
uls->values[uls->value_count++] = value;
if (uls->value_count >= ARRAY_SIZE(uls->values)) {
return true;
}
return false;
}
/*!
* Get the median, mean and worst of the current set of values,
* then reset the struct.
*
* @public @memberof u_live_stats_ns
*/
void
u_ls_ns_get_and_reset(struct u_live_stats_ns *uls, uint64_t *out_median, uint64_t *out_mean, uint64_t *out_worst);
/*!
* Prints a header that looks nice before @ref u_ls_print_and_reset,
* adding details about columns. Doesn't include any newlines.
*
* @public @memberof u_live_stats_ns
*/
void
u_ls_ns_print_header(u_pp_delegate_t dg);
/*!
* Prints the calculated values and resets the struct, can be used with
* @ref u_ls_ns_print_header to get a nice header to the values. Doesn't
* include any newlines.
*
* @public @memberof u_live_stats_ns
*/
void
u_ls_ns_print_and_reset(struct u_live_stats_ns *uls, u_pp_delegate_t dg);
#ifdef __cplusplus
}
#endif