Propose a metrics interface
Some checks failed
Tests / Clang total: 1533, failed: 2, passed: 1531
Tests / SIMD fallback total: 1533, failed: 2, passed: 1531
Tests / Release [gcc] total: 1533, failed: 2, passed: 1531
Tests / Release [gcc,aarch64] total: 1144, failed: 2, passed: 1142
Tests / Coverage total: 1151, passed: 1151
weaselab/conflict-set/pipeline/head There was a failure building this commit

This commit is contained in:
2024-07-12 12:00:46 -07:00
parent 1e82f7fe22
commit 3ac16bc966
8 changed files with 197 additions and 3 deletions

View File

@@ -546,7 +546,38 @@ static_assert(kBytesPerKey - sizeof(Node0) >= kMinNodeSurplus);
constexpr int64_t kFreeListMaxMemory = 1 << 20;
struct Metric {
Metric *prev;
const char *name;
const char *help;
ConflictSet::MetricsV1::Type type;
double value;
protected:
Metric(ConflictSet::Impl *impl, const char *name, const char *help,
ConflictSet::MetricsV1::Type type);
};
struct Gauge : private Metric {
Gauge(ConflictSet::Impl *impl, const char *name, const char *help)
: Metric(impl, name, help, ConflictSet::MetricsV1::Gauge) {}
void set(double value) { this->value = value; }
};
struct Counter : private Metric {
Counter(ConflictSet::Impl *impl, const char *name, const char *help)
: Metric(impl, name, help, ConflictSet::MetricsV1::Counter) {}
void add(double value) {
assert(value >= 0);
this->value += value;
}
};
template <class T> struct BoundedFreeListAllocator {
Counter *allocated_total = nullptr;
Counter *released_total = nullptr;
static_assert(sizeof(T) >= sizeof(void *));
static_assert(std::derived_from<T, Node>);
static_assert(std::is_trivial_v<T>);
@@ -580,6 +611,7 @@ template <class T> struct BoundedFreeListAllocator {
}
T *allocate(int partialKeyCapacity) {
allocated_total->add(1);
T *result = allocate_helper(partialKeyCapacity);
if constexpr (!std::is_same_v<T, Node0>) {
memset(result->children, 0, sizeof(result->children));
@@ -596,6 +628,7 @@ template <class T> struct BoundedFreeListAllocator {
}
void release(T *p) {
released_total->add(1);
if (freeListBytes >= kFreeListMaxMemory) {
removeNode(p);
return safe_free(p, sizeof(T) + p->partialKeyCapacity);
@@ -3136,6 +3169,16 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
allocators.~NodeAllocators();
new (&allocators) NodeAllocators();
allocators.node0.allocated_total = &node0_allocated_total;
allocators.node3.allocated_total = &node3_allocated_total;
allocators.node16.allocated_total = &node16_allocated_total;
allocators.node48.allocated_total = &node48_allocated_total;
allocators.node256.allocated_total = &node256_allocated_total;
allocators.node0.released_total = &node0_released_total;
allocators.node3.released_total = &node3_released_total;
allocators.node16.released_total = &node16_released_total;
allocators.node48.released_total = &node48_released_total;
allocators.node256.released_total = &node256_released_total;
removalKeyArena = Arena{};
removalKey = {};
@@ -3160,8 +3203,14 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
// Intentionally not resetting totalBytes
}
explicit Impl(int64_t oldestVersion) { init(oldestVersion); }
~Impl() { destroyTree(root); }
explicit Impl(int64_t oldestVersion) {
init(oldestVersion);
initMetrics();
}
~Impl() {
destroyTree(root);
safe_free(metrics, metricsCount * sizeof(metrics[0]));
}
NodeAllocators allocators;
@@ -3177,8 +3226,63 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
int64_t oldestVersionAtGcBegin;
int64_t newestVersionFullPrecision;
int64_t totalBytes = 0;
MetricsV1 *metrics;
int metricsCount = 0;
void initMetrics() {
metrics = (MetricsV1 *)safe_malloc(metricsCount * sizeof(metrics[0]));
for (auto [i, m] = std::make_tuple(0, metricList); i < metricsCount;
++i, m = m->prev) {
metrics[i].name = m->name;
metrics[i].help = m->help;
metrics[i].value = &m->value;
metrics[i].type = m->type;
}
std::sort(metrics, metrics + metricsCount,
[](const MetricsV1 &lhs, const MetricsV1 &rhs) -> bool {
return std::string_view(lhs.name) < std::string_view(rhs.name);
});
}
Metric *metricList = nullptr;
#define GAUGE(name, help) \
Gauge name { this, #name, help }
#define COUNTER(name, help) \
Counter name { this, #name, help }
// ==================== METRICS DEFINITIONS ====================
COUNTER(node0_allocated_total,
"Total number of nodes of type \"Node0\" that have been allocated");
COUNTER(node3_allocated_total,
"Total number of nodes of type \"Node3\" that have been allocated");
COUNTER(node16_allocated_total,
"Total number of nodes of type \"Node16\" that have been allocated");
COUNTER(node48_allocated_total,
"Total number of nodes of type \"Node48\" that have been allocated");
COUNTER(node256_allocated_total,
"Total number of nodes of type \"Node256\" that have been allocated");
COUNTER(node0_released_total,
"Total number of nodes of type \"Node0\" that have been released");
COUNTER(node3_released_total,
"Total number of nodes of type \"Node3\" that have been released");
COUNTER(node16_released_total,
"Total number of nodes of type \"Node16\" that have been released");
COUNTER(node48_released_total,
"Total number of nodes of type \"Node48\" that have been released");
COUNTER(node256_released_total,
"Total number of nodes of type \"Node256\" that have been released");
// ==================== END METRICS DEFINITIONS ====================
#undef GAUGE
#undef COUNTER
};
Metric::Metric(ConflictSet::Impl *impl, const char *name, const char *help,
ConflictSet::MetricsV1::Type type)
: prev(std::exchange(impl->metricList, this)), name(name), help(help),
type(type), value(0) {
++impl->metricsCount;
}
InternalVersionT maxVersion(Node *n, ConflictSet::Impl *impl) {
int index = n->parentsIndex;
n = n->parent;
@@ -3308,6 +3412,12 @@ void internal_destroy(ConflictSet::Impl *impl) {
int64_t internal_getBytes(ConflictSet::Impl *impl) { return impl->getBytes(); }
void internal_getMetricsV1(ConflictSet::Impl *impl,
ConflictSet::MetricsV1 **metrics, int *count) {
*metrics = impl->metrics;
*count = impl->metricsCount;
}
// ==================== END IMPLEMENTATION ====================
// GCOVR_EXCL_START
@@ -3392,6 +3502,10 @@ void ConflictSet::setOldestVersion(int64_t oldestVersion) {
int64_t ConflictSet::getBytes() const { return internal_getBytes(impl); }
void ConflictSet::getMetricsV1(MetricsV1 **metrics, int *count) const {
return internal_getMetricsV1(impl, metrics, count);
}
ConflictSet::ConflictSet(int64_t oldestVersion)
: impl(internal_create(oldestVersion)) {}
@@ -3447,6 +3561,7 @@ static_assert(std::is_standard_layout_v<ConflictSet::Result>);
static_assert(std::is_standard_layout_v<ConflictSet::Key>);
static_assert(std::is_standard_layout_v<ConflictSet::ReadRange>);
static_assert(std::is_standard_layout_v<ConflictSet::WriteRange>);
static_assert(std::is_standard_layout_v<ConflictSet::MetricsV1>);
namespace {