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 {
|
template <class T> struct BoundedFreeListAllocator {
|
||||||
|
|
||||||
static_assert(sizeof(T) >= sizeof(void *));
|
static_assert(sizeof(T) >= sizeof(void *));
|
||||||
@@ -622,6 +625,7 @@ template <class T> struct BoundedFreeListAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
T *allocate(int partialKeyCapacity) {
|
T *allocate(int partialKeyCapacity) {
|
||||||
|
++nodes_allocated_accum;
|
||||||
T *result = allocate_helper(partialKeyCapacity);
|
T *result = allocate_helper(partialKeyCapacity);
|
||||||
if constexpr (!std::is_same_v<T, Node0>) {
|
if constexpr (!std::is_same_v<T, Node0>) {
|
||||||
memset(result->children, 0, sizeof(result->children));
|
memset(result->children, 0, sizeof(result->children));
|
||||||
@@ -638,6 +642,7 @@ template <class T> struct BoundedFreeListAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void release(T *p) {
|
void release(T *p) {
|
||||||
|
++nodes_released_accum;
|
||||||
if (freeListBytes >= kFreeListMaxMemory) {
|
if (freeListBytes >= kFreeListMaxMemory) {
|
||||||
removeNode(p);
|
removeNode(p);
|
||||||
return safe_free(p, sizeof(T) + p->partialKeyCapacity);
|
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
|
// 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
|
// 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
|
// 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,
|
Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
|
||||||
bool logical, Node *&dontInvalidate) {
|
bool logical, Node *&dontInvalidate) {
|
||||||
|
++entries_erased_accum;
|
||||||
assert(self->parent != nullptr);
|
assert(self->parent != nullptr);
|
||||||
|
|
||||||
#if DEBUG_VERBOSE && !defined(NDEBUG)
|
#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);
|
auto *result = logical ? nextLogical(self) : nextPhysical(self);
|
||||||
|
|
||||||
removeKey(self);
|
removeKey(self);
|
||||||
|
assert(self->entryPresent);
|
||||||
self->entryPresent = false;
|
self->entryPresent = false;
|
||||||
|
|
||||||
if (self->numChildren != 0) {
|
if (self->numChildren != 0) {
|
||||||
@@ -2779,6 +2788,8 @@ checkRangeRead(Node *n, std::span<const uint8_t> begin,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
thread_local double insert_iterations_accum;
|
||||||
|
|
||||||
// Returns a pointer to the newly inserted node. Caller must set
|
// Returns a pointer to the newly inserted node. Caller must set
|
||||||
// `entryPresent`, `entry` fields and `maxVersion` on the result. The search
|
// `entryPresent`, `entry` fields and `maxVersion` on the result. The search
|
||||||
// path of the result's parent will have `maxVersion` at least `writeVersion` as
|
// 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,
|
insert(Node **self, std::span<const uint8_t> key, InternalVersionT writeVersion,
|
||||||
NodeAllocators *allocators, ConflictSet::Impl *impl) {
|
NodeAllocators *allocators, ConflictSet::Impl *impl) {
|
||||||
|
|
||||||
for (;;) {
|
for (;; ++insert_iterations_accum) {
|
||||||
|
|
||||||
if ((*self)->partialKeyLen > 0) {
|
if ((*self)->partialKeyLen > 0) {
|
||||||
// Handle an existing partial key
|
// 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,
|
void addPointWrite(Node *&root, std::span<const uint8_t> key,
|
||||||
InternalVersionT writeVersion, NodeAllocators *allocators,
|
InternalVersionT writeVersion, NodeAllocators *allocators,
|
||||||
ConflictSet::Impl *impl) {
|
ConflictSet::Impl *impl) {
|
||||||
auto *n = insert<true>(&root, key, writeVersion, allocators, impl);
|
auto *n = insert<true>(&root, key, writeVersion, allocators, impl);
|
||||||
if (!n->entryPresent) {
|
if (!n->entryPresent) {
|
||||||
|
++entries_inserted_accum;
|
||||||
auto *p = nextLogical(n);
|
auto *p = nextLogical(n);
|
||||||
|
|
||||||
addKey(n);
|
addKey(n);
|
||||||
@@ -2972,6 +2986,7 @@ void addWriteRange(Node *&root, std::span<const uint8_t> begin,
|
|||||||
beginNode->entryPresent = true;
|
beginNode->entryPresent = true;
|
||||||
|
|
||||||
if (insertedBegin) {
|
if (insertedBegin) {
|
||||||
|
++entries_inserted_accum;
|
||||||
auto *p = nextLogical(beginNode);
|
auto *p = nextLogical(beginNode);
|
||||||
beginNode->entry.rangeVersion =
|
beginNode->entry.rangeVersion =
|
||||||
p == nullptr ? InternalVersionT::zero
|
p == nullptr ? InternalVersionT::zero
|
||||||
@@ -2992,6 +3007,7 @@ void addWriteRange(Node *&root, std::span<const uint8_t> begin,
|
|||||||
endNode->entryPresent = true;
|
endNode->entryPresent = true;
|
||||||
|
|
||||||
if (insertedEnd) {
|
if (insertedEnd) {
|
||||||
|
++entries_inserted_accum;
|
||||||
auto *p = nextLogical(endNode);
|
auto *p = nextLogical(endNode);
|
||||||
endNode->entry.pointVersion =
|
endNode->entry.pointVersion =
|
||||||
p == nullptr ? InternalVersionT::zero
|
p == nullptr ? InternalVersionT::zero
|
||||||
@@ -3148,8 +3164,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
gcScanStep(1000);
|
gcScanStep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double write_byte_accum = 0;
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
const auto &w = writes[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 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);
|
auto end = std::span<const uint8_t>(w.end.p, w.end.len);
|
||||||
if (w.end.len > 0) {
|
if (w.end.len > 0) {
|
||||||
@@ -3164,6 +3182,12 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
memory_bytes.set(totalBytes);
|
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
|
// 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);
|
rootMaxVersion = std::max(rootMaxVersion, oldestVersion);
|
||||||
n = nextPhysical(n);
|
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);
|
rezero(n, oldestVersion);
|
||||||
// The "make sure gc keeps up with writes" calculations assume that we're
|
// 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
|
// 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);
|
n = nextPhysical(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gc_iterations_total.add(set_oldest_iterations_accum);
|
||||||
if (n == nullptr) {
|
if (n == nullptr) {
|
||||||
removalKey = {};
|
removalKey = {};
|
||||||
oldestExtantVersion = oldestVersionAtGcBegin;
|
oldestExtantVersion = oldestVersionAtGcBegin;
|
||||||
@@ -3235,6 +3261,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
keyUpdates = gcScanStep(keyUpdates);
|
keyUpdates = gcScanStep(keyUpdates);
|
||||||
|
|
||||||
memory_bytes.set(totalBytes);
|
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; }
|
int64_t getBytes() const { return totalBytes; }
|
||||||
@@ -3314,7 +3344,6 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
#define COUNTER(name, help) \
|
#define COUNTER(name, help) \
|
||||||
Counter name { this, #name, help }
|
Counter name { this, #name, help }
|
||||||
// ==================== METRICS DEFINITIONS ====================
|
// ==================== METRICS DEFINITIONS ====================
|
||||||
GAUGE(memory_bytes, "Total number of bytes in use");
|
|
||||||
COUNTER(point_read_total, "Total number of point reads checked");
|
COUNTER(point_read_total, "Total number of point reads checked");
|
||||||
COUNTER(point_read_short_circuit_total,
|
COUNTER(point_read_short_circuit_total,
|
||||||
"Total number of point reads that did not require a full search to "
|
"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,
|
COUNTER(too_olds_total,
|
||||||
"Total number of checks where the result is \"too old\"");
|
"Total number of checks where the result is \"too old\"");
|
||||||
COUNTER(check_bytes_total, "Total number of key bytes checked");
|
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
|
#if MEASURE_CHECK_CPU_TIME
|
||||||
COUNTER(check_cpu_seconds_total,
|
COUNTER(check_cpu_seconds_total,
|
||||||
"Total cpu seconds spent in a call to check");
|
"Total cpu seconds spent in a call to check");
|
||||||
|
Reference in New Issue
Block a user