Add some metrics for addWrites and setOldestVersion

This commit is contained in:
2024-07-17 16:35:29 -07:00
parent 542371d562
commit 95596f831f

View File

@@ -587,6 +587,9 @@ struct Counter : private Metric {
}
};
thread_local double nodes_allocated_accum = 0;
thread_local double nodes_released_accum = 0;
template <class T> struct BoundedFreeListAllocator {
static_assert(sizeof(T) >= sizeof(void *));
@@ -622,6 +625,7 @@ template <class T> struct BoundedFreeListAllocator {
}
T *allocate(int partialKeyCapacity) {
++nodes_allocated_accum;
T *result = allocate_helper(partialKeyCapacity);
if constexpr (!std::is_same_v<T, Node0>) {
memset(result->children, 0, sizeof(result->children));
@@ -638,6 +642,7 @@ template <class T> struct BoundedFreeListAllocator {
}
void release(T *p) {
++nodes_released_accum;
if (freeListBytes >= kFreeListMaxMemory) {
removeNode(p);
return safe_free(p, sizeof(T) + p->partialKeyCapacity);
@@ -1399,12 +1404,15 @@ void maybeDownsize(Node *self, NodeAllocators *allocators,
}
}
thread_local double entries_erased_accum;
// Precondition: self is not the root. May invalidate nodes along the search
// path to self. May invalidate children of self->parent. Returns a pointer to
// the node after self. If erase invalidates the pointee of `dontInvalidate`, it
// will update it to its new pointee as well.
// will update it to its new pointee as well. Precondition: `self->entryPresent`
Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
bool logical, Node *&dontInvalidate) {
++entries_erased_accum;
assert(self->parent != nullptr);
#if DEBUG_VERBOSE && !defined(NDEBUG)
@@ -1417,6 +1425,7 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
auto *result = logical ? nextLogical(self) : nextPhysical(self);
removeKey(self);
assert(self->entryPresent);
self->entryPresent = false;
if (self->numChildren != 0) {
@@ -2779,6 +2788,8 @@ checkRangeRead(Node *n, std::span<const uint8_t> begin,
}
#endif
thread_local double insert_iterations_accum;
// Returns a pointer to the newly inserted node. Caller must set
// `entryPresent`, `entry` fields and `maxVersion` on the result. The search
// path of the result's parent will have `maxVersion` at least `writeVersion` as
@@ -2788,7 +2799,7 @@ template <bool kBegin>
insert(Node **self, std::span<const uint8_t> key, InternalVersionT writeVersion,
NodeAllocators *allocators, ConflictSet::Impl *impl) {
for (;;) {
for (;; ++insert_iterations_accum) {
if ((*self)->partialKeyLen > 0) {
// Handle an existing partial key
@@ -2897,11 +2908,14 @@ void destroyTree(Node *root) {
}
}
thread_local double entries_inserted_accum;
void addPointWrite(Node *&root, std::span<const uint8_t> key,
InternalVersionT writeVersion, NodeAllocators *allocators,
ConflictSet::Impl *impl) {
auto *n = insert<true>(&root, key, writeVersion, allocators, impl);
if (!n->entryPresent) {
++entries_inserted_accum;
auto *p = nextLogical(n);
addKey(n);
@@ -2972,6 +2986,7 @@ void addWriteRange(Node *&root, std::span<const uint8_t> begin,
beginNode->entryPresent = true;
if (insertedBegin) {
++entries_inserted_accum;
auto *p = nextLogical(beginNode);
beginNode->entry.rangeVersion =
p == nullptr ? InternalVersionT::zero
@@ -2992,6 +3007,7 @@ void addWriteRange(Node *&root, std::span<const uint8_t> begin,
endNode->entryPresent = true;
if (insertedEnd) {
++entries_inserted_accum;
auto *p = nextLogical(endNode);
endNode->entry.pointVersion =
p == nullptr ? InternalVersionT::zero
@@ -3148,8 +3164,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
gcScanStep(1000);
}
double write_byte_accum = 0;
for (int i = 0; i < count; ++i) {
const auto &w = writes[i];
write_byte_accum += w.begin.len + w.end.len;
auto begin = std::span<const uint8_t>(w.begin.p, w.begin.len);
auto end = std::span<const uint8_t>(w.end.p, w.end.len);
if (w.end.len > 0) {
@@ -3164,6 +3182,12 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
}
memory_bytes.set(totalBytes);
nodes_allocated_total.add(std::exchange(nodes_allocated_accum, 0));
nodes_released_total.add(std::exchange(nodes_released_accum, 0));
entries_inserted_total.add(std::exchange(entries_inserted_accum, 0));
entries_erased_total.add(std::exchange(entries_erased_accum, 0));
insert_iterations_total.add(std::exchange(insert_iterations_accum, 0));
write_bytes_total.add(write_byte_accum);
}
// Spends up to `fuel` gc'ing, and returns its unused fuel. Reclaims memory
@@ -3178,7 +3202,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
rootMaxVersion = std::max(rootMaxVersion, oldestVersion);
n = nextPhysical(n);
}
for (; fuel > 0 && n != nullptr;) {
double set_oldest_iterations_accum = 0;
for (; fuel > 0 && n != nullptr; ++set_oldest_iterations_accum) {
rezero(n, oldestVersion);
// The "make sure gc keeps up with writes" calculations assume that we're
// scanning key by key, not node by node. Make sure we only spend fuel
@@ -3199,6 +3224,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
n = nextPhysical(n);
}
}
gc_iterations_total.add(set_oldest_iterations_accum);
if (n == nullptr) {
removalKey = {};
oldestExtantVersion = oldestVersionAtGcBegin;
@@ -3235,6 +3261,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
keyUpdates = gcScanStep(keyUpdates);
memory_bytes.set(totalBytes);
nodes_allocated_total.add(std::exchange(nodes_allocated_accum, 0));
nodes_released_total.add(std::exchange(nodes_released_accum, 0));
entries_inserted_total.add(std::exchange(entries_inserted_accum, 0));
entries_erased_total.add(std::exchange(entries_erased_accum, 0));
}
int64_t getBytes() const { return totalBytes; }
@@ -3314,7 +3344,6 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
#define COUNTER(name, help) \
Counter name { this, #name, help }
// ==================== METRICS DEFINITIONS ====================
GAUGE(memory_bytes, "Total number of bytes in use");
COUNTER(point_read_total, "Total number of point reads checked");
COUNTER(point_read_short_circuit_total,
"Total number of point reads that did not require a full search to "
@@ -3343,6 +3372,21 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
COUNTER(too_olds_total,
"Total number of checks where the result is \"too old\"");
COUNTER(check_bytes_total, "Total number of key bytes checked");
GAUGE(memory_bytes, "Total number of bytes in use");
COUNTER(nodes_allocated_total,
"The total number of physical tree nodes allocated");
COUNTER(nodes_released_total,
"The total number of physical tree nodes released");
COUNTER(insert_iterations_total,
"The total number of iterations of the main loop for insertion");
COUNTER(entries_inserted_total,
"The total number of entries inserted in the tree");
COUNTER(entries_erased_total,
"The total number of entries erased from the tree");
COUNTER(
gc_iterations_total,
"The total number of iterations of the main loop for garbage collection");
COUNTER(write_bytes_total, "Total number of key bytes in calls to addWrites");
#if MEASURE_CHECK_CPU_TIME
COUNTER(check_cpu_seconds_total,
"Total cpu seconds spent in a call to check");