diff --git a/ConflictSet.cpp b/ConflictSet.cpp index c0977c9..2bfa6a1 100644 --- a/ConflictSet.cpp +++ b/ConflictSet.cpp @@ -1711,23 +1711,31 @@ struct SearchStepWise { } }; -thread_local double accume_point_read = 0; -thread_local double accume_prefix_read = 0; -thread_local double accume_range_read = 0; -thread_local double accume_max_between = 0; +thread_local double point_read_accum = 0; +thread_local double prefix_read_accum = 0; +thread_local double range_read_accum = 0; +thread_local double point_read_short_circuit_accum = 0; +thread_local double prefix_read_short_circuit_accum = 0; +thread_local double range_read_short_circuit_accum = 0; +thread_local double point_read_iterations_accum = 0; +thread_local double prefix_read_iterations_accum = 0; +thread_local double range_read_iterations_accum = 0; +thread_local double range_read_node_scan_accum = 0; // Logically this is the same as performing firstGeq and then checking against // point or range version according to cmp, but this version short circuits as // soon as it can prove that there's no conflict. bool checkPointRead(Node *n, const std::span key, InternalVersionT readVersion, ConflictSet::Impl *impl) { - ++accume_point_read; + ++point_read_accum; #if DEBUG_VERBOSE && !defined(NDEBUG) fprintf(stderr, "Check point read: %s\n", printable(key).c_str()); #endif auto remaining = key; for (;;) { + ++point_read_iterations_accum; if (maxVersion(n, impl) <= readVersion) { + ++point_read_short_circuit_accum; return true; } if (remaining.size() == 0) { @@ -1799,18 +1807,20 @@ downLeftSpine: // short circuits as soon as it can prove that there's no conflict. bool checkPrefixRead(Node *n, const std::span key, InternalVersionT readVersion, ConflictSet::Impl *impl) { - ++accume_prefix_read; + ++prefix_read_accum; #if DEBUG_VERBOSE && !defined(NDEBUG) fprintf(stderr, "Check prefix read: %s\n", printable(key).c_str()); #endif auto remaining = key; for (;;) { + ++prefix_read_iterations_accum; auto m = maxVersion(n, impl); if (remaining.size() == 0) { return m <= readVersion; } if (m <= readVersion) { + ++prefix_read_short_circuit_accum; return true; } @@ -2041,7 +2051,7 @@ scan16(const InternalVersionT *vs, int begin, int end, template bool checkMaxBetweenExclusive(Node *n, int begin, int end, InternalVersionT readVersion) { - ++accume_max_between; + ++range_read_node_scan_accum; assume(-1 <= begin); assume(begin <= 256); assume(-1 <= end); @@ -2639,7 +2649,7 @@ template bool checkRangeReadImpl(Node *n, std::span begin, std::span end, InternalVersionT readVersion, ConflictSet::Impl *impl) { - ++accume_range_read; + ++range_read_accum; int lcp = longestCommonPrefix(begin.data(), end.data(), std::min(begin.size(), end.size())); if (lcp == int(begin.size()) && end.size() == begin.size() + 1 && @@ -2654,10 +2664,12 @@ bool checkRangeReadImpl(Node *n, std::span begin, SearchStepWise search{n, begin.subspan(0, lcp)}; Arena arena; for (;;) { + ++range_read_iterations_accum; assert(getSearchPath(arena, search.n) <=> begin.subspan(0, lcp - search.remaining.size()) == 0); if (maxVersion(search.n, impl) <= readVersion) { + ++range_read_short_circuit_accum; return true; } if (search.step()) { @@ -2696,20 +2708,24 @@ bool checkRangeReadImpl(Node *n, std::span begin, for (;;) { bool leftDone = checkRangeLeftSide.step(); + ++range_read_iterations_accum; bool rightDone = checkRangeRightSide.step(); + ++range_read_iterations_accum; if (!leftDone && !rightDone) { continue; } if (leftDone && rightDone) { break; } else if (leftDone) { - while (!checkRangeRightSide.step()) - ; + while (!checkRangeRightSide.step()) { + ++range_read_iterations_accum; + } break; } else { assert(rightDone); - while (!checkRangeLeftSide.step()) - ; + while (!checkRangeLeftSide.step()) { + ++range_read_iterations_accum; + } } break; } @@ -3057,10 +3073,9 @@ Node *firstGeqPhysical(Node *n, const std::span key) { struct __attribute__((visibility("hidden"))) ConflictSet::Impl { void check(const ReadRange *reads, Result *result, int count) { - assert(accume_point_read == 0); - assert(accume_prefix_read == 0); - assert(accume_range_read == 0); - assert(accume_max_between == 0); + int commits_accum = 0; + int conflicts_accum = 0; + int too_olds_accum = 0; for (int i = 0; i < count; ++i) { const auto &r = reads[i]; auto begin = std::span(r.begin.p, r.begin.len); @@ -3076,11 +3091,30 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl { InternalVersionT(reads[i].readVersion), this)) ? Commit : Conflict; + commits_accum += result[i] == Commit; + conflicts_accum += result[i] == Conflict; + too_olds_accum += result[i] == TooOld; } - read_point_total.add(std::exchange(accume_point_read, 0)); - read_prefix_total.add(std::exchange(accume_prefix_read, 0)); - read_range_total.add(std::exchange(accume_range_read, 0)); - read_range_node_total.add(std::exchange(accume_max_between, 0)); + point_read_total.add(std::exchange(point_read_accum, 0)); + prefix_read_total.add(std::exchange(prefix_read_accum, 0)); + range_read_total.add(std::exchange(range_read_accum, 0)); + range_read_node_scan_total.add( + std::exchange(range_read_node_scan_accum, 0)); + point_read_short_circuit_total.add( + std::exchange(point_read_short_circuit_accum, 0)); + prefix_read_short_circuit_total.add( + std::exchange(prefix_read_short_circuit_accum, 0)); + range_read_short_circuit_total.add( + std::exchange(range_read_short_circuit_accum, 0)); + point_read_iterations_total.add( + std::exchange(point_read_iterations_accum, 0)); + prefix_read_iterations_total.add( + std::exchange(prefix_read_iterations_accum, 0)); + range_read_iterations_total.add( + std::exchange(range_read_iterations_accum, 0)); + commits_total.add(commits_accum); + conflicts_total.add(conflicts_accum); + too_olds_total.add(too_olds_accum); } void addWrites(const WriteRange *writes, int count, int64_t writeVersion) { @@ -3266,13 +3300,34 @@ 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(read_point_total, "Total number of point reads checked."); - COUNTER(read_prefix_total, "Total number of prefix reads checked."); - COUNTER(read_range_total, "Total number of range reads checked."); - COUNTER(read_range_node_total, - "Total number of range checks of individual nodes while " - "checking a range read."); + 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 " + "check"); + COUNTER(point_read_iterations_total, + "Total number of iterations of the main loop for point read checks"); + COUNTER(prefix_read_total, "Total number of prefix reads checked"); + COUNTER(prefix_read_short_circuit_total, + "Total number of prefix reads that did not require a full search to " + "check"); + COUNTER(prefix_read_iterations_total, + "Total number of iterations of the main loop for prefix read checks"); + COUNTER(range_read_total, "Total number of range reads checked"); + COUNTER(range_read_short_circuit_total, + "Total number of range reads that did not require a full search to " + "check"); + COUNTER(range_read_iterations_total, + "Total number of iterations of the main loops for range read checks"); + COUNTER(range_read_node_scan_total, + "Total number of scans of individual nodes while " + "checking a range read"); + COUNTER(commits_total, + "Total number of checks where the result is \"commit\""); + COUNTER(conflicts_total, + "Total number of checks where the result is \"conflict\""); + COUNTER(too_olds_total, + "Total number of checks where the result is \"too old\""); // ==================== END METRICS DEFINITIONS ==================== #undef GAUGE #undef COUNTER