Add some metrics for addWrites and setOldestVersion
This commit is contained in:
@@ -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");
|
||||
|
Reference in New Issue
Block a user