mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-16 03:45:24 +00:00
u/live_stats: Add helper to do live statistics on nano-seconds durations
This commit is contained in:
parent
cd2274b370
commit
40534011e8
|
@ -61,6 +61,8 @@ add_library(
|
||||||
u_json.hpp
|
u_json.hpp
|
||||||
u_limited_unique_id.cpp
|
u_limited_unique_id.cpp
|
||||||
u_limited_unique_id.h
|
u_limited_unique_id.h
|
||||||
|
u_live_stats.cpp
|
||||||
|
u_live_stats.h
|
||||||
u_logging.c
|
u_logging.c
|
||||||
u_logging.h
|
u_logging.h
|
||||||
u_metrics.c
|
u_metrics.c
|
||||||
|
|
117
src/xrt/auxiliary/util/u_live_stats.cpp
Normal file
117
src/xrt/auxiliary/util/u_live_stats.cpp
Normal 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);
|
||||||
|
}
|
106
src/xrt/auxiliary/util/u_live_stats.h
Normal file
106
src/xrt/auxiliary/util/u_live_stats.h
Normal 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
|
Loading…
Reference in a new issue