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
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:
119
ConflictSet.cpp
119
ConflictSet.cpp
@@ -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 {
|
||||
|
||||
|
Reference in New Issue
Block a user