6 Commits

Author SHA1 Message Date
6a13c43a78 Remove mistakenly checked in printfs
All checks were successful
Tests / Clang total: 822, passed: 822
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 822, passed: 822
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 821, passed: 821
Tests / Coverage total: 820, passed: 820
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-18 14:03:09 -07:00
c6c438bae2 Address more missing coverage
cc #3. Found some non-trivial dead code this time!
2024-03-18 14:01:30 -07:00
7d4f832b43 Address some missing coverage
cc #3
2024-03-18 13:36:35 -07:00
5b0c3c2428 Exclude more from coverage
Only count ConflictSet.cpp in jenkins now, and also add some more
excludes for unreachable lines
2024-03-18 12:05:52 -07:00
f2b5e9b0bf Change max key len to 8, update corpus
Now that we don't have a fixed buffer reserved for partial key bytes,
there's nothing (obvious) that makes testing short versus long keys much
different. maybeDecreaseCapacity is an exception, and we'll write some
tests covering that manually.
2024-03-18 11:55:43 -07:00
8e0e65dac6 Count implicit key byte for maybeDecreaseCapacity 2024-03-18 11:42:53 -07:00
585 changed files with 669 additions and 91 deletions

View File

@@ -472,7 +472,8 @@ inline void Node256::copyChildrenAndKeyFrom(const Node256 &other) {
namespace { namespace {
std::string getSearchPathPrintable(Node *n); std::string getSearchPathPrintable(Node *n);
} std::string getSearchPath(Node *n);
} // namespace
// Bound memory usage following the analysis in the ART paper // Bound memory usage following the analysis in the ART paper
@@ -676,7 +677,7 @@ template <class NodeT> int getNodeIndex(NodeT *self, uint8_t index) {
// Precondition - an entry for index must exist in the node // Precondition - an entry for index must exist in the node
Node *&getChildExists(Node *self, uint8_t index) { Node *&getChildExists(Node *self, uint8_t index) {
switch (self->getType()) { switch (self->getType()) {
case Type_Node0: case Type_Node0: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE __builtin_unreachable(); // GCOVR_EXCL_LINE
case Type_Node3: { case Type_Node3: {
auto *self3 = static_cast<Node3 *>(self); auto *self3 = static_cast<Node3 *>(self);
@@ -1078,7 +1079,7 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
void maybeDecreaseCapacity(Node *&self, NodeAllocators *allocators, void maybeDecreaseCapacity(Node *&self, NodeAllocators *allocators,
ConflictSet::Impl *impl) { ConflictSet::Impl *impl) {
const int maxCapacity = const int maxCapacity =
(self->numChildren + int(self->entryPresent)) * self->partialKeyLen; (self->numChildren + int(self->entryPresent)) * (self->partialKeyLen + 1);
if (self->getCapacity() <= maxCapacity) { if (self->getCapacity() <= maxCapacity) {
return; return;
} }
@@ -1097,7 +1098,7 @@ void maybeDownsize(Node *self, NodeAllocators *allocators,
assert(self->getType() == kType); assert(self->getType() == kType);
static_assert(kType != Type_Node0); static_assert(kType != Type_Node0);
switch (kType) { switch (kType) {
case Type_Node0: case Type_Node0: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE __builtin_unreachable(); // GCOVR_EXCL_LINE
case Type_Node3: { case Type_Node3: {
auto *self3 = (Node3 *)self; auto *self3 = (Node3 *)self;
@@ -1201,7 +1202,7 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
if (self->numChildren != 0) { if (self->numChildren != 0) {
const bool update = result == dontInvalidate; const bool update = result == dontInvalidate;
switch (self->getType()) { switch (self->getType()) {
case Type_Node0: case Type_Node0: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE __builtin_unreachable(); // GCOVR_EXCL_LINE
case Type_Node3: case Type_Node3:
maybeDownsize<Type_Node3>(self, allocators, impl, result); maybeDownsize<Type_Node3>(self, allocators, impl, result);
@@ -1224,28 +1225,11 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
return result; return result;
} }
switch (self->getType()) { assert(self->getType() == Type_Node0);
case Type_Node0: allocators->node0.release((Node0 *)self);
allocators->node0.release((Node0 *)self);
break;
case Type_Node3:
allocators->node3.release((Node3 *)self);
break;
case Type_Node16:
allocators->node16.release((Node16 *)self);
break;
case Type_Node48:
allocators->node48.release((Node48 *)self);
break;
case Type_Node256:
allocators->node256.release((Node256 *)self);
break;
default: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE
}
switch (parent->getType()) { switch (parent->getType()) {
case Type_Node0: case Type_Node0: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE __builtin_unreachable(); // GCOVR_EXCL_LINE
case Type_Node3: { case Type_Node3: {
auto *parent3 = static_cast<Node3 *>(parent); auto *parent3 = static_cast<Node3 *>(parent);
@@ -1259,15 +1243,11 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
(parent->numChildren - (nodeIndex + 1))); (parent->numChildren - (nodeIndex + 1)));
--parent->numChildren; --parent->numChildren;
if (parent->numChildren == 0 && !parent->entryPresent && assert(parent->numChildren > 0 || parent->entryPresent);
parent->parent != nullptr) { const bool update = result == dontInvalidate;
return erase(parent, allocators, impl, dontInvalidate); maybeDownsize<Type_Node3>(parent, allocators, impl, result);
} else { if (update) {
const bool update = result == dontInvalidate; dontInvalidate = result;
maybeDownsize<Type_Node3>(parent, allocators, impl, result);
if (update) {
dontInvalidate = result;
}
} }
} break; } break;
case Type_Node16: { case Type_Node16: {
@@ -1282,16 +1262,16 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
(parent->numChildren - (nodeIndex + 1))); (parent->numChildren - (nodeIndex + 1)));
--parent->numChildren; --parent->numChildren;
if (parent->numChildren == 0 && !parent->entryPresent &&
parent->parent != nullptr) { // By kMinChildrenNode16
return erase(parent, allocators, impl, dontInvalidate); assert(parent->numChildren > 0);
} else {
const bool update = result == dontInvalidate; const bool update = result == dontInvalidate;
maybeDownsize<Type_Node16>(parent, allocators, impl, result); maybeDownsize<Type_Node16>(parent, allocators, impl, result);
if (update) { if (update) {
dontInvalidate = result; dontInvalidate = result;
}
} }
} break; } break;
case Type_Node48: { case Type_Node48: {
auto *parent48 = static_cast<Node48 *>(parent); auto *parent48 = static_cast<Node48 *>(parent);
@@ -1309,15 +1289,14 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
} }
--parent->numChildren; --parent->numChildren;
if (parent->numChildren == 0 && !parent->entryPresent &&
parent->parent != nullptr) { // By kMinChildrenNode48
return erase(parent, allocators, impl, dontInvalidate); assert(parent->numChildren > 0);
} else {
const bool update = result == dontInvalidate; const bool update = result == dontInvalidate;
maybeDownsize<Type_Node48>(parent, allocators, impl, result); maybeDownsize<Type_Node48>(parent, allocators, impl, result);
if (update) { if (update) {
dontInvalidate = result; dontInvalidate = result;
}
} }
} break; } break;
case Type_Node256: { case Type_Node256: {
@@ -1326,15 +1305,14 @@ Node *erase(Node *self, NodeAllocators *allocators, ConflictSet::Impl *impl,
parent256->children[parentsIndex].child = nullptr; parent256->children[parentsIndex].child = nullptr;
--parent->numChildren; --parent->numChildren;
if (parent->numChildren == 0 && !parent->entryPresent &&
parent->parent != nullptr) { // By kMinChildrenNode256
return erase(parent, allocators, impl, dontInvalidate); assert(parent->numChildren > 0);
} else {
const bool update = result == dontInvalidate; const bool update = result == dontInvalidate;
maybeDownsize<Type_Node256>(parent, allocators, impl, result); maybeDownsize<Type_Node256>(parent, allocators, impl, result);
if (update) { if (update) {
dontInvalidate = result; dontInvalidate = result;
}
} }
} break; } break;
default: // GCOVR_EXCL_LINE default: // GCOVR_EXCL_LINE
@@ -1374,7 +1352,7 @@ constexpr int kUnrollFactor = 4;
bool compareStride(const uint8_t *ap, const uint8_t *bp) { bool compareStride(const uint8_t *ap, const uint8_t *bp) {
#if defined(HAS_ARM_NEON) #if defined(HAS_ARM_NEON)
static_assert(kStride == 64); static_assert(kStride == 64);
uint8x16_t x[4]; uint8x16_t x[4]; // GCOVR_EXCL_LINE
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
x[i] = vceqq_u8(vld1q_u8(ap + i * 16), vld1q_u8(bp + i * 16)); x[i] = vceqq_u8(vld1q_u8(ap + i * 16), vld1q_u8(bp + i * 16));
} }
@@ -1384,7 +1362,7 @@ bool compareStride(const uint8_t *ap, const uint8_t *bp) {
uint64_t(-1); uint64_t(-1);
#elif defined(HAS_AVX) #elif defined(HAS_AVX)
static_assert(kStride == 64); static_assert(kStride == 64);
__m128i x[4]; __m128i x[4]; // GCOVR_EXCL_LINE
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
x[i] = _mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)(ap + i * 16)), x[i] = _mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)(ap + i * 16)),
_mm_loadu_si128((__m128i *)(bp + i * 16))); _mm_loadu_si128((__m128i *)(bp + i * 16)));
@@ -1403,7 +1381,7 @@ bool compareStride(const uint8_t *ap, const uint8_t *bp) {
int firstNeqStride(const uint8_t *ap, const uint8_t *bp) { int firstNeqStride(const uint8_t *ap, const uint8_t *bp) {
#if defined(HAS_AVX) #if defined(HAS_AVX)
static_assert(kStride == 64); static_assert(kStride == 64);
uint64_t c[kStride / 16]; uint64_t c[kStride / 16]; // GCOVR_EXCL_LINE
for (int i = 0; i < kStride; i += 16) { for (int i = 0; i < kStride; i += 16) {
const auto a = _mm_loadu_si128((__m128i *)(ap + i)); const auto a = _mm_loadu_si128((__m128i *)(ap + i));
const auto b = _mm_loadu_si128((__m128i *)(bp + i)); const auto b = _mm_loadu_si128((__m128i *)(bp + i));
@@ -1445,18 +1423,6 @@ int longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
goto bytes; goto bytes;
} }
// Optimistic early return
{
uint64_t a;
uint64_t b;
memcpy(&a, ap, 8);
memcpy(&b, bp, 8);
const auto mismatched = a ^ b;
if (mismatched) {
return std::countr_zero(mismatched) / 8;
}
}
// kStride * kUnrollCount at a time // kStride * kUnrollCount at a time
end = cl & ~(kStride * kUnrollFactor - 1); end = cl & ~(kStride * kUnrollFactor - 1);
while (i < end) { while (i < end) {
@@ -1484,8 +1450,8 @@ int longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
// word at a time // word at a time
end = cl & ~(sizeof(uint64_t) - 1); end = cl & ~(sizeof(uint64_t) - 1);
while (i < end) { while (i < end) {
uint64_t a; uint64_t a; // GCOVR_EXCL_LINE
uint64_t b; uint64_t b; // GCOVR_EXCL_LINE
memcpy(&a, ap, 8); memcpy(&a, ap, 8);
memcpy(&b, bp, 8); memcpy(&b, bp, 8);
const auto mismatched = a ^ b; const auto mismatched = a ^ b;
@@ -1640,7 +1606,7 @@ int64_t maxBetweenExclusive(Node *n, int begin, int end) {
} }
} }
switch (n->getType()) { switch (n->getType()) {
case Type_Node0: case Type_Node0: // GCOVR_EXCL_LINE
// We would have returned above, after not finding a child // We would have returned above, after not finding a child
__builtin_unreachable(); // GCOVR_EXCL_LINE __builtin_unreachable(); // GCOVR_EXCL_LINE
case Type_Node3: { case Type_Node3: {
@@ -1703,7 +1669,7 @@ Vector<uint8_t> getSearchPath(Arena &arena, Node *n) {
} }
std::reverse(result.begin(), result.end()); std::reverse(result.begin(), result.end());
return result; return result;
} } // GCOVR_EXCL_LINE
// Return true if the max version among all keys that start with key + [child], // Return true if the max version among all keys that start with key + [child],
// where begin < child < end, is <= readVersion // where begin < child < end, is <= readVersion
@@ -2480,11 +2446,11 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
assert(n != nullptr); assert(n != nullptr);
// Don't erase the root // Don't erase the root
if (n == root) { if (n == root) {
n = nextLogical(n); n = nextPhysical(n);
} }
for (; keyUpdates > 0 && n != nullptr; --keyUpdates) { for (; keyUpdates > 0 && n != nullptr; --keyUpdates) {
if (std::max(n->entry.pointVersion, n->entry.rangeVersion) <= if (n->entryPresent && std::max(n->entry.pointVersion,
oldestVersion) { n->entry.rangeVersion) <= oldestVersion) {
// Any transaction n would have prevented from committing is // Any transaction n would have prevented from committing is
// going to fail with TooOld anyway. // going to fail with TooOld anyway.
@@ -2495,7 +2461,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
n = erase(n, &allocators, this, dummy); n = erase(n, &allocators, this, dummy);
} else { } else {
maybeDecreaseCapacity(n, &allocators, this); maybeDecreaseCapacity(n, &allocators, this);
n = nextLogical(n); n = nextPhysical(n);
} }
} }
if (n == nullptr) { if (n == nullptr) {
@@ -2839,8 +2805,8 @@ Iterator firstGeq(Node *n, std::string_view key) {
case Type_Node256: case Type_Node256:
minNumChildren = kMinChildrenNode256; minNumChildren = kMinChildrenNode256;
break; break;
default: // GCOVR_EXCL_LINE default:
__builtin_unreachable(); // GCOVR_EXCL_LINE abort();
} }
if (node->numChildren + int(node->entryPresent) < minNumChildren) { if (node->numChildren + int(node->entryPresent) < minNumChildren) {
fprintf(stderr, fprintf(stderr,
@@ -2898,8 +2864,8 @@ int64_t getNodeSize(struct Node *n) {
return sizeof(Node48); return sizeof(Node48);
case Type_Node256: case Type_Node256:
return sizeof(Node256); return sizeof(Node256);
default: // GCOVR_EXCL_LINE default:
__builtin_unreachable(); // GCOVR_EXCL_LINE abort();
} }
} }

View File

@@ -531,7 +531,7 @@ template <class ConflictSetImpl> struct TestDriver {
ConflictSetImpl cs{oldestVersion}; ConflictSetImpl cs{oldestVersion};
ReferenceImpl refImpl{oldestVersion}; ReferenceImpl refImpl{oldestVersion};
constexpr static auto kMaxKeyLen = 128; constexpr static auto kMaxKeyLen = 8;
bool ok = true; bool ok = true;

2
Jenkinsfile vendored
View File

@@ -97,7 +97,7 @@ pipeline {
steps { steps {
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_BUILD_TYPE=Debug") CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_BUILD_TYPE=Debug")
sh ''' sh '''
gcovr --exclude '.*third_party.*' --cobertura > build/coverage.xml gcovr -f ConflictSet.cpp --cobertura > build/coverage.xml
''' '''
cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'build/coverage.xml', conditionalCoverageTargets: '70, 0, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '80, 0, 0', maxNumberOfBuilds: 0, methodCoverageTargets: '80, 0, 0', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false cobertura autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'build/coverage.xml', conditionalCoverageTargets: '70, 0, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '80, 0, 0', maxNumberOfBuilds: 0, methodCoverageTargets: '80, 0, 0', onlyStable: false, sourceEncoding: 'ASCII', zoomCoverageChart: false
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More