Compare commits
20 Commits
v0.0.11
...
0a850f22e9
Author | SHA1 | Date | |
---|---|---|---|
0a850f22e9 | |||
479b39d055 | |||
482408d725 | |||
45995e3307 | |||
359b0b29ff | |||
54e47ebd40 | |||
1c9dda68a6 | |||
142455dd28 | |||
567d385fbd | |||
8a44055533 | |||
62516825d1 | |||
3d592bd6a9 | |||
f5f5fb620b | |||
e3d1b2e842 | |||
9f8800af16 | |||
182c065c8e | |||
2dba0d5be3 | |||
a1dfdf355c | |||
15919cb1c4 | |||
5ed9003a83 |
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.18)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
project(
|
project(
|
||||||
conflict-set
|
conflict-set
|
||||||
VERSION 0.0.11
|
VERSION 0.0.12
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
|
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
|
||||||
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"
|
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"
|
||||||
|
430
ConflictSet.cpp
430
ConflictSet.cpp
@@ -16,12 +16,12 @@ limitations under the License.
|
|||||||
|
|
||||||
#include "ConflictSet.h"
|
#include "ConflictSet.h"
|
||||||
#include "Internal.h"
|
#include "Internal.h"
|
||||||
|
#include "LongestCommonPrefix.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <compare>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -40,11 +40,13 @@ limitations under the License.
|
|||||||
#include <arm_neon.h>
|
#include <arm_neon.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __SANITIZE_THREAD__
|
||||||
#if defined(__has_feature)
|
#if defined(__has_feature)
|
||||||
#if __has_feature(thread_sanitizer)
|
#if __has_feature(thread_sanitizer)
|
||||||
#define __SANITIZE_THREAD__
|
#define __SANITIZE_THREAD__
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <memcheck.h>
|
#include <memcheck.h>
|
||||||
|
|
||||||
@@ -1123,12 +1125,68 @@ Node *getFirstChildExists(Node *self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caller is responsible for assigning a non-null pointer to the returned
|
void consumePartialKeyFull(Node *&self, std::span<const uint8_t> &key,
|
||||||
// reference if null. Updates child's max version to `newMaxVersion` if child
|
InternalVersionT writeVersion, WriteContext *tls) {
|
||||||
// exists but does not have a partial key.
|
// Handle an existing partial key
|
||||||
Node *&getOrCreateChild(Node *&self, uint8_t index,
|
int commonLen = std::min<int>(self->partialKeyLen, key.size());
|
||||||
|
int partialKeyIndex =
|
||||||
|
longestCommonPrefix(self->partialKey(), key.data(), commonLen);
|
||||||
|
if (partialKeyIndex < self->partialKeyLen) {
|
||||||
|
auto *old = self;
|
||||||
|
// Since root cannot have a partial key
|
||||||
|
assert(old->parent != nullptr);
|
||||||
|
InternalVersionT oldMaxVersion = exchangeMaxVersion(old, writeVersion);
|
||||||
|
|
||||||
|
// *self will have one child (old)
|
||||||
|
auto *newSelf = tls->allocate<Node3>(partialKeyIndex);
|
||||||
|
|
||||||
|
newSelf->parent = old->parent;
|
||||||
|
newSelf->parentsIndex = old->parentsIndex;
|
||||||
|
newSelf->partialKeyLen = partialKeyIndex;
|
||||||
|
newSelf->entryPresent = false;
|
||||||
|
newSelf->numChildren = 1;
|
||||||
|
|
||||||
|
memcpy(newSelf->partialKey(), old->partialKey(), newSelf->partialKeyLen);
|
||||||
|
|
||||||
|
uint8_t oldDistinguishingByte = old->partialKey()[partialKeyIndex];
|
||||||
|
old->parent = newSelf;
|
||||||
|
old->parentsIndex = oldDistinguishingByte;
|
||||||
|
newSelf->index[0] = oldDistinguishingByte;
|
||||||
|
newSelf->children[0] = old;
|
||||||
|
newSelf->childMaxVersion[0] = oldMaxVersion;
|
||||||
|
self = newSelf;
|
||||||
|
|
||||||
|
memmove(old->partialKey(), old->partialKey() + partialKeyIndex + 1,
|
||||||
|
old->partialKeyLen - (partialKeyIndex + 1));
|
||||||
|
old->partialKeyLen -= partialKeyIndex + 1;
|
||||||
|
|
||||||
|
// We would consider decreasing capacity here, but we can't invalidate
|
||||||
|
// old since it's not on the search path. setOldestVersion will clean it
|
||||||
|
// up.
|
||||||
|
}
|
||||||
|
key = key.subspan(partialKeyIndex, key.size() - partialKeyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume any partial key of `self`, and update `self` and
|
||||||
|
// `key` such that `self` is along the search path of `key`
|
||||||
|
inline __attribute__((always_inline)) void
|
||||||
|
consumePartialKey(Node *&self, std::span<const uint8_t> &key,
|
||||||
|
InternalVersionT writeVersion, WriteContext *tls) {
|
||||||
|
if (self->partialKeyLen > 0) {
|
||||||
|
consumePartialKeyFull(self, key, writeVersion, tls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the next node along the search path of key, consuming bytes of key
|
||||||
|
// such that the search path of the result + key is the same as the search path
|
||||||
|
// of self + key before the call. Creates a node if necessary. Updates
|
||||||
|
// `maxVersion` for result.
|
||||||
|
Node *&getOrCreateChild(Node *&self, std::span<const uint8_t> &key,
|
||||||
InternalVersionT newMaxVersion, WriteContext *tls) {
|
InternalVersionT newMaxVersion, WriteContext *tls) {
|
||||||
|
|
||||||
|
int index = key.front();
|
||||||
|
key = key.subspan(1, key.size() - 1);
|
||||||
|
|
||||||
// Fast path for if it exists already
|
// Fast path for if it exists already
|
||||||
switch (self->getType()) {
|
switch (self->getType()) {
|
||||||
case Type_Node0:
|
case Type_Node0:
|
||||||
@@ -1137,9 +1195,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
auto *self3 = static_cast<Node3 *>(self);
|
auto *self3 = static_cast<Node3 *>(self);
|
||||||
int i = getNodeIndex(self3, index);
|
int i = getNodeIndex(self3, index);
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
if (self3->children[i]->partialKeyLen == 0) {
|
consumePartialKey(self3->children[i], key, newMaxVersion, tls);
|
||||||
self3->childMaxVersion[i] = newMaxVersion;
|
self3->childMaxVersion[i] = newMaxVersion;
|
||||||
}
|
|
||||||
return self3->children[i];
|
return self3->children[i];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -1147,9 +1204,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
auto *self16 = static_cast<Node16 *>(self);
|
auto *self16 = static_cast<Node16 *>(self);
|
||||||
int i = getNodeIndex(self16, index);
|
int i = getNodeIndex(self16, index);
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
if (self16->children[i]->partialKeyLen == 0) {
|
consumePartialKey(self16->children[i], key, newMaxVersion, tls);
|
||||||
self16->childMaxVersion[i] = newMaxVersion;
|
self16->childMaxVersion[i] = newMaxVersion;
|
||||||
}
|
|
||||||
return self16->children[i];
|
return self16->children[i];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -1157,23 +1213,21 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
auto *self48 = static_cast<Node48 *>(self);
|
auto *self48 = static_cast<Node48 *>(self);
|
||||||
int secondIndex = self48->index[index];
|
int secondIndex = self48->index[index];
|
||||||
if (secondIndex >= 0) {
|
if (secondIndex >= 0) {
|
||||||
if (self48->children[secondIndex]->partialKeyLen == 0) {
|
consumePartialKey(self48->children[secondIndex], key, newMaxVersion, tls);
|
||||||
self48->childMaxVersion[secondIndex] = newMaxVersion;
|
self48->childMaxVersion[secondIndex] = newMaxVersion;
|
||||||
self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift] =
|
self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift] =
|
||||||
std::max(self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift],
|
std::max(self48->maxOfMax[secondIndex >> Node48::kMaxOfMaxShift],
|
||||||
newMaxVersion);
|
newMaxVersion);
|
||||||
}
|
|
||||||
return self48->children[secondIndex];
|
return self48->children[secondIndex];
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case Type_Node256: {
|
case Type_Node256: {
|
||||||
auto *self256 = static_cast<Node256 *>(self);
|
auto *self256 = static_cast<Node256 *>(self);
|
||||||
if (auto &result = self256->children[index]; result != nullptr) {
|
if (auto &result = self256->children[index]; result != nullptr) {
|
||||||
if (self256->children[index]->partialKeyLen == 0) {
|
consumePartialKey(result, key, newMaxVersion, tls);
|
||||||
self256->childMaxVersion[index] = newMaxVersion;
|
self256->childMaxVersion[index] = newMaxVersion;
|
||||||
self256->maxOfMax[index >> Node256::kMaxOfMaxShift] = std::max(
|
self256->maxOfMax[index >> Node256::kMaxOfMaxShift] = std::max(
|
||||||
self256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMaxVersion);
|
self256->maxOfMax[index >> Node256::kMaxOfMaxShift], newMaxVersion);
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -1181,6 +1235,14 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto *newChild = tls->allocate<Node0>(key.size());
|
||||||
|
newChild->numChildren = 0;
|
||||||
|
newChild->entryPresent = false;
|
||||||
|
newChild->partialKeyLen = key.size();
|
||||||
|
newChild->parentsIndex = index;
|
||||||
|
memcpy(newChild->partialKey(), key.data(), key.size());
|
||||||
|
key = {};
|
||||||
|
|
||||||
switch (self->getType()) {
|
switch (self->getType()) {
|
||||||
case Type_Node0: {
|
case Type_Node0: {
|
||||||
auto *self0 = static_cast<Node0 *>(self);
|
auto *self0 = static_cast<Node0 *>(self);
|
||||||
@@ -1215,8 +1277,10 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
}
|
}
|
||||||
self3->index[i + 1] = index;
|
self3->index[i + 1] = index;
|
||||||
auto &result = self3->children[i + 1];
|
auto &result = self3->children[i + 1];
|
||||||
result = nullptr;
|
self3->childMaxVersion[i + 1] = newMaxVersion;
|
||||||
|
result = newChild;
|
||||||
++self->numChildren;
|
++self->numChildren;
|
||||||
|
newChild->parent = self;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
case Type_Node16: {
|
case Type_Node16: {
|
||||||
@@ -1243,8 +1307,10 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
}
|
}
|
||||||
self16->index[i + 1] = index;
|
self16->index[i + 1] = index;
|
||||||
auto &result = self16->children[i + 1];
|
auto &result = self16->children[i + 1];
|
||||||
result = nullptr;
|
self16->childMaxVersion[i + 1] = newMaxVersion;
|
||||||
|
result = newChild;
|
||||||
++self->numChildren;
|
++self->numChildren;
|
||||||
|
newChild->parent = self;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
case Type_Node48: {
|
case Type_Node48: {
|
||||||
@@ -1267,7 +1333,11 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
self48->index[index] = nextFree;
|
self48->index[index] = nextFree;
|
||||||
self48->reverseIndex[nextFree] = index;
|
self48->reverseIndex[nextFree] = index;
|
||||||
auto &result = self48->children[nextFree];
|
auto &result = self48->children[nextFree];
|
||||||
result = nullptr;
|
self48->childMaxVersion[nextFree] = newMaxVersion;
|
||||||
|
self48->maxOfMax[nextFree >> Node48::kMaxOfMaxShift] = std::max(
|
||||||
|
newMaxVersion, self48->maxOfMax[nextFree >> Node48::kMaxOfMaxShift]);
|
||||||
|
result = newChild;
|
||||||
|
newChild->parent = self;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
case Type_Node256: {
|
case Type_Node256: {
|
||||||
@@ -1276,7 +1346,13 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
|
|||||||
auto *self256 = static_cast<Node256 *>(self);
|
auto *self256 = static_cast<Node256 *>(self);
|
||||||
++self->numChildren;
|
++self->numChildren;
|
||||||
self256->bitSet.set(index);
|
self256->bitSet.set(index);
|
||||||
return self256->children[index];
|
auto &result = self256->children[index];
|
||||||
|
self256->childMaxVersion[index] = newMaxVersion;
|
||||||
|
self256->maxOfMax[index >> Node256::kMaxOfMaxShift] = std::max(
|
||||||
|
newMaxVersion, self256->maxOfMax[index >> Node256::kMaxOfMaxShift]);
|
||||||
|
result = newChild;
|
||||||
|
newChild->parent = self;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
default: // GCOVR_EXCL_LINE
|
default: // GCOVR_EXCL_LINE
|
||||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||||
@@ -1687,167 +1763,6 @@ Node *nextSibling(Node *node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAS_AVX) || defined(HAS_ARM_NEON)
|
|
||||||
constexpr int kStride = 64;
|
|
||||||
#else
|
|
||||||
constexpr int kStride = 16;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
constexpr int kUnrollFactor = 4;
|
|
||||||
|
|
||||||
bool compareStride(const uint8_t *ap, const uint8_t *bp) {
|
|
||||||
#if defined(HAS_ARM_NEON)
|
|
||||||
static_assert(kStride == 64);
|
|
||||||
uint8x16_t x[4]; // GCOVR_EXCL_LINE
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
x[i] = vceqq_u8(vld1q_u8(ap + i * 16), vld1q_u8(bp + i * 16));
|
|
||||||
}
|
|
||||||
auto results = vreinterpretq_u16_u8(
|
|
||||||
vandq_u8(vandq_u8(x[0], x[1]), vandq_u8(x[2], x[3])));
|
|
||||||
bool eq = vget_lane_u64(vreinterpret_u64_u8(vshrn_n_u16(results, 4)), 0) ==
|
|
||||||
uint64_t(-1);
|
|
||||||
#elif defined(HAS_AVX)
|
|
||||||
static_assert(kStride == 64);
|
|
||||||
__m128i x[4]; // GCOVR_EXCL_LINE
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
x[i] = _mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)(ap + i * 16)),
|
|
||||||
_mm_loadu_si128((__m128i *)(bp + i * 16)));
|
|
||||||
}
|
|
||||||
auto eq =
|
|
||||||
_mm_movemask_epi8(_mm_and_si128(_mm_and_si128(x[0], x[1]),
|
|
||||||
_mm_and_si128(x[2], x[3]))) == 0xffff;
|
|
||||||
#else
|
|
||||||
// Hope it gets vectorized
|
|
||||||
auto eq = memcmp(ap, bp, kStride) == 0;
|
|
||||||
#endif
|
|
||||||
return eq;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Precondition: ap[:kStride] != bp[:kStride]
|
|
||||||
int firstNeqStride(const uint8_t *ap, const uint8_t *bp) {
|
|
||||||
#if defined(HAS_AVX)
|
|
||||||
static_assert(kStride == 64);
|
|
||||||
uint64_t c[kStride / 16]; // GCOVR_EXCL_LINE
|
|
||||||
for (int i = 0; i < kStride; i += 16) {
|
|
||||||
const auto a = _mm_loadu_si128((__m128i *)(ap + i));
|
|
||||||
const auto b = _mm_loadu_si128((__m128i *)(bp + i));
|
|
||||||
const auto compared = _mm_cmpeq_epi8(a, b);
|
|
||||||
c[i / 16] = _mm_movemask_epi8(compared) & 0xffff;
|
|
||||||
}
|
|
||||||
return std::countr_zero(~(c[0] | c[1] << 16 | c[2] << 32 | c[3] << 48));
|
|
||||||
#elif defined(HAS_ARM_NEON)
|
|
||||||
static_assert(kStride == 64);
|
|
||||||
for (int i = 0; i < kStride; i += 16) {
|
|
||||||
// 0xff for each match
|
|
||||||
uint16x8_t results =
|
|
||||||
vreinterpretq_u16_u8(vceqq_u8(vld1q_u8(ap + i), vld1q_u8(bp + i)));
|
|
||||||
// 0xf for each mismatch
|
|
||||||
uint64_t bitfield =
|
|
||||||
~vget_lane_u64(vreinterpret_u64_u8(vshrn_n_u16(results, 4)), 0);
|
|
||||||
if (bitfield) {
|
|
||||||
return i + (std::countr_zero(bitfield) >> 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
|
||||||
#else
|
|
||||||
int i = 0;
|
|
||||||
for (; i < kStride - 1; ++i) {
|
|
||||||
if (*ap++ != *bp++) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// This gets covered in local development
|
|
||||||
// GCOVR_EXCL_START
|
|
||||||
#if defined(HAS_AVX) && !defined(__SANITIZE_THREAD__)
|
|
||||||
__attribute__((target("avx512f,avx512bw"))) int
|
|
||||||
longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
|
|
||||||
int i = 0;
|
|
||||||
int end = cl & ~63;
|
|
||||||
while (i < end) {
|
|
||||||
const uint64_t eq =
|
|
||||||
_mm512_cmpeq_epi8_mask(_mm512_loadu_epi8(ap), _mm512_loadu_epi8(bp));
|
|
||||||
if (eq != uint64_t(-1)) {
|
|
||||||
return i + std::countr_one(eq);
|
|
||||||
}
|
|
||||||
i += 64;
|
|
||||||
ap += 64;
|
|
||||||
bp += 64;
|
|
||||||
}
|
|
||||||
if (i < cl) {
|
|
||||||
const uint64_t mask = (uint64_t(1) << (cl - i)) - 1;
|
|
||||||
const uint64_t eq = _mm512_cmpeq_epi8_mask(
|
|
||||||
_mm512_maskz_loadu_epi8(mask, ap), _mm512_maskz_loadu_epi8(mask, bp));
|
|
||||||
return i + std::countr_one(eq & mask);
|
|
||||||
}
|
|
||||||
assert(i == cl);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
__attribute__((target("default")))
|
|
||||||
#endif
|
|
||||||
// GCOVR_EXCL_STOP
|
|
||||||
|
|
||||||
int longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
|
|
||||||
assume(cl >= 0);
|
|
||||||
int i = 0;
|
|
||||||
int end;
|
|
||||||
|
|
||||||
// kStride * kUnrollCount at a time
|
|
||||||
end = cl & ~(kStride * kUnrollFactor - 1);
|
|
||||||
while (i < end) {
|
|
||||||
for (int j = 0; j < kUnrollFactor; ++j) {
|
|
||||||
if (!compareStride(ap, bp)) {
|
|
||||||
return i + firstNeqStride(ap, bp);
|
|
||||||
}
|
|
||||||
i += kStride;
|
|
||||||
ap += kStride;
|
|
||||||
bp += kStride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// kStride at a time
|
|
||||||
end = cl & ~(kStride - 1);
|
|
||||||
while (i < end) {
|
|
||||||
if (!compareStride(ap, bp)) {
|
|
||||||
return i + firstNeqStride(ap, bp);
|
|
||||||
}
|
|
||||||
i += kStride;
|
|
||||||
ap += kStride;
|
|
||||||
bp += kStride;
|
|
||||||
}
|
|
||||||
|
|
||||||
// word at a time
|
|
||||||
end = cl & ~(sizeof(uint64_t) - 1);
|
|
||||||
while (i < end) {
|
|
||||||
uint64_t a; // GCOVR_EXCL_LINE
|
|
||||||
uint64_t b; // GCOVR_EXCL_LINE
|
|
||||||
memcpy(&a, ap, 8);
|
|
||||||
memcpy(&b, bp, 8);
|
|
||||||
const auto mismatched = a ^ b;
|
|
||||||
if (mismatched) {
|
|
||||||
return i + std::countr_zero(mismatched) / 8;
|
|
||||||
}
|
|
||||||
i += 8;
|
|
||||||
ap += 8;
|
|
||||||
bp += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// byte at a time
|
|
||||||
while (i < cl) {
|
|
||||||
if (*ap != *bp) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++ap;
|
|
||||||
++bp;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logically this is the same as performing firstGeq and then checking against
|
// 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
|
// point or range version according to cmp, but this version short circuits as
|
||||||
// soon as it can prove that there's no conflict.
|
// soon as it can prove that there's no conflict.
|
||||||
@@ -2877,94 +2792,22 @@ checkMaxBetweenExclusiveImpl<true>(Node *n, int begin, int end,
|
|||||||
InternalVersionT readVersion, ReadContext *);
|
InternalVersionT readVersion, ReadContext *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Consume the partial key of `self` (which must exist), and update `self` and
|
// Returns a pointer the pointer to the newly inserted node in the tree. Caller
|
||||||
// `key` such that `self` is along the search path of `key`
|
// must set `entryPresent`, and `entry` fields. All nodes along the search path
|
||||||
void consumePartialKey(Node *&self, std::span<const uint8_t> &key,
|
// of the result will have `maxVersion` set to `writeVersion` as a
|
||||||
InternalVersionT writeVersion, WriteContext *tls) {
|
// postcondition. Nodes along the search path may be invalidated.
|
||||||
assert(self->partialKeyLen > 0);
|
|
||||||
// Handle an existing partial key
|
|
||||||
int commonLen = std::min<int>(self->partialKeyLen, key.size());
|
|
||||||
int partialKeyIndex =
|
|
||||||
longestCommonPrefix(self->partialKey(), key.data(), commonLen);
|
|
||||||
if (partialKeyIndex < self->partialKeyLen) {
|
|
||||||
auto *old = self;
|
|
||||||
// Since root cannot have a partial key
|
|
||||||
assert(old->parent != nullptr);
|
|
||||||
InternalVersionT oldMaxVersion = exchangeMaxVersion(old, writeVersion);
|
|
||||||
|
|
||||||
// *self will have one child (old)
|
|
||||||
auto *newSelf = tls->allocate<Node3>(partialKeyIndex);
|
|
||||||
|
|
||||||
newSelf->parent = old->parent;
|
|
||||||
newSelf->parentsIndex = old->parentsIndex;
|
|
||||||
newSelf->partialKeyLen = partialKeyIndex;
|
|
||||||
newSelf->entryPresent = false;
|
|
||||||
newSelf->numChildren = 1;
|
|
||||||
|
|
||||||
memcpy(newSelf->partialKey(), old->partialKey(), newSelf->partialKeyLen);
|
|
||||||
|
|
||||||
uint8_t oldDistinguishingByte = old->partialKey()[partialKeyIndex];
|
|
||||||
old->parent = newSelf;
|
|
||||||
old->parentsIndex = oldDistinguishingByte;
|
|
||||||
newSelf->index[0] = oldDistinguishingByte;
|
|
||||||
newSelf->children[0] = old;
|
|
||||||
newSelf->childMaxVersion[0] = oldMaxVersion;
|
|
||||||
self = newSelf;
|
|
||||||
|
|
||||||
memmove(old->partialKey(), old->partialKey() + partialKeyIndex + 1,
|
|
||||||
old->partialKeyLen - (partialKeyIndex + 1));
|
|
||||||
old->partialKeyLen -= partialKeyIndex + 1;
|
|
||||||
|
|
||||||
// We would consider decreasing capacity here, but we can't invalidate
|
|
||||||
// old since it's not on the search path. setOldestVersion will clean it
|
|
||||||
// up.
|
|
||||||
}
|
|
||||||
key = key.subspan(partialKeyIndex, key.size() - partialKeyIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a pointer to the newly inserted node. Caller must set
|
|
||||||
// `entryPresent`, and `entry` fields. All nodes along the search path of the
|
|
||||||
// result will have `maxVersion` set to `writeVersion` as a postcondition. Nodes
|
|
||||||
// along the search path may be invalidated.
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Node *insert(Node **self, std::span<const uint8_t> key,
|
Node **insert(Node **self, std::span<const uint8_t> key,
|
||||||
InternalVersionT writeVersion, WriteContext *tls,
|
InternalVersionT writeVersion, WriteContext *tls,
|
||||||
ConflictSet::Impl *impl) {
|
ConflictSet::Impl *impl) {
|
||||||
|
|
||||||
if ((*self)->partialKeyLen > 0) {
|
|
||||||
consumePartialKey(*self, key, writeVersion, tls);
|
|
||||||
}
|
|
||||||
assert(maxVersion(*self, impl) <= writeVersion);
|
assert(maxVersion(*self, impl) <= writeVersion);
|
||||||
setMaxVersion(*self, impl, writeVersion);
|
setMaxVersion(*self, impl, writeVersion);
|
||||||
|
|
||||||
for (;; ++tls->accum.insert_iterations) {
|
for (; key.size() != 0; ++tls->accum.insert_iterations) {
|
||||||
|
self = &getOrCreateChild(*self, key, writeVersion, tls);
|
||||||
if (key.size() == 0) {
|
|
||||||
return *self;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &child = getOrCreateChild(*self, key.front(), writeVersion, tls);
|
|
||||||
if (!child) {
|
|
||||||
child = tls->allocate<Node0>(key.size() - 1);
|
|
||||||
child->numChildren = 0;
|
|
||||||
child->entryPresent = false;
|
|
||||||
child->partialKeyLen = key.size() - 1;
|
|
||||||
child->parent = *self;
|
|
||||||
child->parentsIndex = key.front();
|
|
||||||
setMaxVersion(child, impl, writeVersion);
|
|
||||||
memcpy(child->partialKey(), key.data() + 1, child->partialKeyLen);
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
self = &child;
|
|
||||||
key = key.subspan(1, key.size() - 1);
|
|
||||||
|
|
||||||
if ((*self)->partialKeyLen > 0) {
|
|
||||||
consumePartialKey(*self, key, writeVersion, tls);
|
|
||||||
assert(maxVersion(*self, impl) <= writeVersion);
|
|
||||||
setMaxVersion(*self, impl, writeVersion);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyTree(Node *root) {
|
void destroyTree(Node *root) {
|
||||||
@@ -2996,7 +2839,7 @@ void addPointWrite(Node *&root, std::span<const uint8_t> key,
|
|||||||
InternalVersionT writeVersion, WriteContext *tls,
|
InternalVersionT writeVersion, WriteContext *tls,
|
||||||
ConflictSet::Impl *impl) {
|
ConflictSet::Impl *impl) {
|
||||||
++tls->accum.point_writes;
|
++tls->accum.point_writes;
|
||||||
auto *n = insert(&root, key, writeVersion, tls, impl);
|
auto *n = *insert(&root, key, writeVersion, tls, impl);
|
||||||
if (!n->entryPresent) {
|
if (!n->entryPresent) {
|
||||||
++tls->accum.entries_inserted;
|
++tls->accum.entries_inserted;
|
||||||
auto *p = nextLogical(n);
|
auto *p = nextLogical(n);
|
||||||
@@ -3063,41 +2906,16 @@ void addWriteRange(Node *&root, std::span<const uint8_t> begin,
|
|||||||
}
|
}
|
||||||
++tls->accum.range_writes;
|
++tls->accum.range_writes;
|
||||||
const bool beginIsPrefix = lcp == int(begin.size());
|
const bool beginIsPrefix = lcp == int(begin.size());
|
||||||
auto remaining = begin.subspan(0, lcp);
|
|
||||||
|
|
||||||
auto *n = root;
|
Node **useAsRoot =
|
||||||
|
insert(&root, begin.subspan(0, lcp), writeVersion, tls, impl);
|
||||||
|
|
||||||
for (;;) {
|
int consumed = lcp;
|
||||||
if (int(remaining.size()) <= n->partialKeyLen) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int i = longestCommonPrefix(n->partialKey(), remaining.data(),
|
|
||||||
n->partialKeyLen);
|
|
||||||
if (i != n->partialKeyLen) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *child = getChild(n, remaining[n->partialKeyLen]);
|
|
||||||
if (child == nullptr) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(maxVersion(n, impl) <= writeVersion);
|
|
||||||
setMaxVersion(n, impl, writeVersion);
|
|
||||||
|
|
||||||
remaining = remaining.subspan(n->partialKeyLen + 1,
|
|
||||||
remaining.size() - (n->partialKeyLen + 1));
|
|
||||||
n = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node **useAsRoot = &getInTree(n, impl);
|
|
||||||
|
|
||||||
int consumed = lcp - remaining.size();
|
|
||||||
|
|
||||||
begin = begin.subspan(consumed, begin.size() - consumed);
|
begin = begin.subspan(consumed, begin.size() - consumed);
|
||||||
end = end.subspan(consumed, end.size() - consumed);
|
end = end.subspan(consumed, end.size() - consumed);
|
||||||
|
|
||||||
auto *beginNode = insert(useAsRoot, begin, writeVersion, tls, impl);
|
auto *beginNode = *insert(useAsRoot, begin, writeVersion, tls, impl);
|
||||||
|
|
||||||
const bool insertedBegin = !beginNode->entryPresent;
|
const bool insertedBegin = !beginNode->entryPresent;
|
||||||
|
|
||||||
@@ -3114,7 +2932,7 @@ void addWriteRange(Node *&root, std::span<const uint8_t> begin,
|
|||||||
assert(writeVersion >= beginNode->entry.pointVersion);
|
assert(writeVersion >= beginNode->entry.pointVersion);
|
||||||
beginNode->entry.pointVersion = writeVersion;
|
beginNode->entry.pointVersion = writeVersion;
|
||||||
|
|
||||||
auto *endNode = insert(useAsRoot, end, writeVersion, tls, impl);
|
auto *endNode = *insert(useAsRoot, end, writeVersion, tls, impl);
|
||||||
|
|
||||||
const bool insertedEnd = !endNode->entryPresent;
|
const bool insertedEnd = !endNode->entryPresent;
|
||||||
|
|
||||||
@@ -3132,7 +2950,7 @@ void addWriteRange(Node *&root, std::span<const uint8_t> begin,
|
|||||||
if (beginIsPrefix && insertedEnd) {
|
if (beginIsPrefix && insertedEnd) {
|
||||||
// beginNode may have been invalidated when inserting end. TODO can we do
|
// beginNode may have been invalidated when inserting end. TODO can we do
|
||||||
// better?
|
// better?
|
||||||
beginNode = insert(useAsRoot, begin, writeVersion, tls, impl);
|
beginNode = *insert(useAsRoot, begin, writeVersion, tls, impl);
|
||||||
assert(beginNode->entryPresent);
|
assert(beginNode->entryPresent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3246,6 +3064,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
InternalVersionT::zero = tls.zero = oldestVersion;
|
InternalVersionT::zero = tls.zero = oldestVersion;
|
||||||
|
|
||||||
assert(writeVersion >= newestVersionFullPrecision);
|
assert(writeVersion >= newestVersionFullPrecision);
|
||||||
|
assert(tls.accum.entries_erased == 0);
|
||||||
|
assert(tls.accum.entries_inserted == 0);
|
||||||
|
|
||||||
if (oldestExtantVersion < writeVersion - kMaxCorrectVersionWindow)
|
if (oldestExtantVersion < writeVersion - kMaxCorrectVersionWindow)
|
||||||
[[unlikely]] {
|
[[unlikely]] {
|
||||||
@@ -3273,15 +3093,19 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
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) {
|
||||||
keyUpdates += 3;
|
|
||||||
addWriteRange(root, begin, end, InternalVersionT(writeVersion), &tls,
|
addWriteRange(root, begin, end, InternalVersionT(writeVersion), &tls,
|
||||||
this);
|
this);
|
||||||
} else {
|
} else {
|
||||||
keyUpdates += 2;
|
|
||||||
addPointWrite(root, begin, InternalVersionT(writeVersion), &tls, this);
|
addPointWrite(root, begin, InternalVersionT(writeVersion), &tls, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run gc at least 200% the rate we're inserting entries
|
||||||
|
keyUpdates +=
|
||||||
|
std::max<int64_t>(tls.accum.entries_inserted - tls.accum.entries_erased,
|
||||||
|
0) *
|
||||||
|
2;
|
||||||
|
|
||||||
memory_bytes.set(totalBytes);
|
memory_bytes.set(totalBytes);
|
||||||
point_writes_total.add(tls.accum.point_writes);
|
point_writes_total.add(tls.accum.point_writes);
|
||||||
range_writes_total.add(tls.accum.range_writes);
|
range_writes_total.add(tls.accum.range_writes);
|
||||||
|
17
Jenkinsfile
vendored
17
Jenkinsfile
vendored
@@ -117,15 +117,18 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
|
script {
|
||||||
|
filter_args = "-f ConflictSet.cpp -f LongestCommonPrefix.h"
|
||||||
|
}
|
||||||
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_BUILD_TYPE=Debug -DDISABLE_TSAN=ON")
|
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage -DCMAKE_BUILD_TYPE=Debug -DDISABLE_TSAN=ON")
|
||||||
sh '''
|
sh """
|
||||||
gcovr -f ConflictSet.cpp --cobertura > build/coverage.xml
|
gcovr ${filter_args} --cobertura > build/coverage.xml
|
||||||
'''
|
"""
|
||||||
recordCoverage qualityGates: [[criticality: 'NOTE', metric: 'MODULE']], tools: [[parser: 'COBERTURA', pattern: 'build/coverage.xml']]
|
recordCoverage qualityGates: [[criticality: 'NOTE', metric: 'MODULE']], tools: [[parser: 'COBERTURA', pattern: 'build/coverage.xml']]
|
||||||
sh '''
|
sh """
|
||||||
gcovr -f ConflictSet.cpp
|
gcovr ${filter_args}
|
||||||
gcovr -f ConflictSet.cpp --fail-under-line 100 > /dev/null
|
gcovr ${filter_args} --fail-under-line 100 > /dev/null
|
||||||
'''
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
185
LongestCommonPrefix.h
Normal file
185
LongestCommonPrefix.h
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <bit>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAS_AVX
|
||||||
|
#include <immintrin.h>
|
||||||
|
#elif HAS_ARM_NEON
|
||||||
|
#include <arm_neon.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __SANITIZE_THREAD__
|
||||||
|
#if defined(__has_feature)
|
||||||
|
#if __has_feature(thread_sanitizer)
|
||||||
|
#define __SANITIZE_THREAD__
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAS_AVX) || defined(HAS_ARM_NEON)
|
||||||
|
constexpr int kStride = 64;
|
||||||
|
#else
|
||||||
|
constexpr int kStride = 16;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr int kUnrollFactor = 4;
|
||||||
|
|
||||||
|
inline bool compareStride(const uint8_t *ap, const uint8_t *bp) {
|
||||||
|
#if defined(HAS_ARM_NEON)
|
||||||
|
static_assert(kStride == 64);
|
||||||
|
uint8x16_t x[4]; // GCOVR_EXCL_LINE
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
x[i] = vceqq_u8(vld1q_u8(ap + i * 16), vld1q_u8(bp + i * 16));
|
||||||
|
}
|
||||||
|
auto results = vreinterpretq_u16_u8(
|
||||||
|
vandq_u8(vandq_u8(x[0], x[1]), vandq_u8(x[2], x[3])));
|
||||||
|
bool eq = vget_lane_u64(vreinterpret_u64_u8(vshrn_n_u16(results, 4)), 0) ==
|
||||||
|
uint64_t(-1);
|
||||||
|
#elif defined(HAS_AVX)
|
||||||
|
static_assert(kStride == 64);
|
||||||
|
__m128i x[4]; // GCOVR_EXCL_LINE
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
x[i] = _mm_cmpeq_epi8(_mm_loadu_si128((__m128i *)(ap + i * 16)),
|
||||||
|
_mm_loadu_si128((__m128i *)(bp + i * 16)));
|
||||||
|
}
|
||||||
|
auto eq =
|
||||||
|
_mm_movemask_epi8(_mm_and_si128(_mm_and_si128(x[0], x[1]),
|
||||||
|
_mm_and_si128(x[2], x[3]))) == 0xffff;
|
||||||
|
#else
|
||||||
|
// Hope it gets vectorized
|
||||||
|
auto eq = memcmp(ap, bp, kStride) == 0;
|
||||||
|
#endif
|
||||||
|
return eq;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precondition: ap[:kStride] != bp[:kStride]
|
||||||
|
inline int firstNeqStride(const uint8_t *ap, const uint8_t *bp) {
|
||||||
|
#if defined(HAS_AVX)
|
||||||
|
static_assert(kStride == 64);
|
||||||
|
uint64_t c[kStride / 16]; // GCOVR_EXCL_LINE
|
||||||
|
for (int i = 0; i < kStride; i += 16) {
|
||||||
|
const auto a = _mm_loadu_si128((__m128i *)(ap + i));
|
||||||
|
const auto b = _mm_loadu_si128((__m128i *)(bp + i));
|
||||||
|
const auto compared = _mm_cmpeq_epi8(a, b);
|
||||||
|
c[i / 16] = _mm_movemask_epi8(compared) & 0xffff;
|
||||||
|
}
|
||||||
|
return std::countr_zero(~(c[0] | c[1] << 16 | c[2] << 32 | c[3] << 48));
|
||||||
|
#elif defined(HAS_ARM_NEON)
|
||||||
|
static_assert(kStride == 64);
|
||||||
|
for (int i = 0; i < kStride; i += 16) {
|
||||||
|
// 0xff for each match
|
||||||
|
uint16x8_t results =
|
||||||
|
vreinterpretq_u16_u8(vceqq_u8(vld1q_u8(ap + i), vld1q_u8(bp + i)));
|
||||||
|
// 0xf for each mismatch
|
||||||
|
uint64_t bitfield =
|
||||||
|
~vget_lane_u64(vreinterpret_u64_u8(vshrn_n_u16(results, 4)), 0);
|
||||||
|
if (bitfield) {
|
||||||
|
return i + (std::countr_zero(bitfield) >> 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||||
|
#else
|
||||||
|
int i = 0;
|
||||||
|
for (; i < kStride - 1; ++i) {
|
||||||
|
if (*ap++ != *bp++) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gets covered in local development
|
||||||
|
// GCOVR_EXCL_START
|
||||||
|
#if defined(HAS_AVX) && !defined(__SANITIZE_THREAD__)
|
||||||
|
__attribute__((target("avx512f,avx512bw"))) inline int
|
||||||
|
longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
|
||||||
|
int i = 0;
|
||||||
|
int end = cl & ~63;
|
||||||
|
while (i < end) {
|
||||||
|
const uint64_t eq =
|
||||||
|
_mm512_cmpeq_epi8_mask(_mm512_loadu_epi8(ap), _mm512_loadu_epi8(bp));
|
||||||
|
if (eq != uint64_t(-1)) {
|
||||||
|
return i + std::countr_one(eq);
|
||||||
|
}
|
||||||
|
i += 64;
|
||||||
|
ap += 64;
|
||||||
|
bp += 64;
|
||||||
|
}
|
||||||
|
if (i < cl) {
|
||||||
|
const uint64_t mask = (uint64_t(1) << (cl - i)) - 1;
|
||||||
|
const uint64_t eq = _mm512_cmpeq_epi8_mask(
|
||||||
|
_mm512_maskz_loadu_epi8(mask, ap), _mm512_maskz_loadu_epi8(mask, bp));
|
||||||
|
return i + std::countr_one(eq & mask);
|
||||||
|
}
|
||||||
|
assert(i == cl);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
__attribute__((target("default")))
|
||||||
|
#endif
|
||||||
|
// GCOVR_EXCL_STOP
|
||||||
|
|
||||||
|
inline int
|
||||||
|
longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
|
||||||
|
if (!(cl >= 0)) {
|
||||||
|
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
int end;
|
||||||
|
|
||||||
|
// kStride * kUnrollCount at a time
|
||||||
|
end = cl & ~(kStride * kUnrollFactor - 1);
|
||||||
|
while (i < end) {
|
||||||
|
for (int j = 0; j < kUnrollFactor; ++j) {
|
||||||
|
if (!compareStride(ap, bp)) {
|
||||||
|
return i + firstNeqStride(ap, bp);
|
||||||
|
}
|
||||||
|
i += kStride;
|
||||||
|
ap += kStride;
|
||||||
|
bp += kStride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kStride at a time
|
||||||
|
end = cl & ~(kStride - 1);
|
||||||
|
while (i < end) {
|
||||||
|
if (!compareStride(ap, bp)) {
|
||||||
|
return i + firstNeqStride(ap, bp);
|
||||||
|
}
|
||||||
|
i += kStride;
|
||||||
|
ap += kStride;
|
||||||
|
bp += kStride;
|
||||||
|
}
|
||||||
|
|
||||||
|
// word at a time
|
||||||
|
end = cl & ~(sizeof(uint64_t) - 1);
|
||||||
|
while (i < end) {
|
||||||
|
uint64_t a; // GCOVR_EXCL_LINE
|
||||||
|
uint64_t b; // GCOVR_EXCL_LINE
|
||||||
|
memcpy(&a, ap, 8);
|
||||||
|
memcpy(&b, bp, 8);
|
||||||
|
const auto mismatched = a ^ b;
|
||||||
|
if (mismatched) {
|
||||||
|
return i + std::countr_zero(mismatched) / 8;
|
||||||
|
}
|
||||||
|
i += 8;
|
||||||
|
ap += 8;
|
||||||
|
bp += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// byte at a time
|
||||||
|
while (i < cl) {
|
||||||
|
if (*ap != *bp) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++ap;
|
||||||
|
++bp;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
21
README.md
21
README.md
@@ -24,15 +24,16 @@ Hardware for all benchmarks is an AMD Ryzen 9 7900 with (2x32GB) 5600MT/s CL28-3
|
|||||||
|
|
||||||
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|
||||||
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
||||||
| 12.42 | 80,500,398.66 | 0.8% | 180.38 | 61.57 | 2.930 | 41.51 | 0.4% | 0.01 | `point reads`
|
| 10.80 | 92,600,541.52 | 0.6% | 180.38 | 54.49 | 3.310 | 41.51 | 0.4% | 0.01 | `point reads`
|
||||||
| 15.17 | 65,917,580.99 | 0.2% | 279.47 | 74.95 | 3.729 | 55.54 | 0.3% | 0.01 | `prefix reads`
|
| 15.00 | 66,687,691.68 | 0.4% | 278.44 | 76.44 | 3.642 | 55.56 | 0.3% | 0.01 | `prefix reads`
|
||||||
| 38.16 | 26,202,393.91 | 0.1% | 803.07 | 189.13 | 4.246 | 141.68 | 0.2% | 0.01 | `range reads`
|
| 36.81 | 27,163,394.61 | 0.4% | 795.06 | 187.91 | 4.231 | 142.67 | 0.2% | 0.01 | `range reads`
|
||||||
| 20.20 | 49,504,615.44 | 0.4% | 363.00 | 100.35 | 3.617 | 49.81 | 0.3% | 0.01 | `point writes`
|
| 18.14 | 55,137,674.01 | 1.2% | 338.19 | 92.86 | 3.642 | 42.81 | 0.4% | 0.01 | `point writes`
|
||||||
| 41.99 | 23,816,559.99 | 0.3% | 799.27 | 209.63 | 3.813 | 154.32 | 0.1% | 0.01 | `prefix writes`
|
| 33.19 | 30,127,119.71 | 0.1% | 681.03 | 170.05 | 4.005 | 98.68 | 0.2% | 0.01 | `prefix writes`
|
||||||
| 46.28 | 21,607,605.88 | 1.5% | 953.79 | 231.47 | 4.121 | 168.34 | 0.0% | 0.01 | `range writes`
|
| 37.37 | 26,759,432.70 | 1.9% | 779.70 | 195.45 | 3.989 | 114.21 | 0.0% | 0.01 | `range writes`
|
||||||
| 80.99 | 12,347,449.98 | 0.9% | 1,501.97 | 406.50 | 3.695 | 281.89 | 0.1% | 0.01 | `monotonic increasing point writes`
|
| 74.36 | 13,448,582.47 | 1.9% | 1,425.68 | 389.08 | 3.664 | 258.88 | 0.1% | 0.01 | `monotonic increasing point writes`
|
||||||
| 318,010.00 | 3,144.56 | 1.0% | 3,994,511.50 | 1,657,831.50 | 2.409 | 805,969.50 | 0.0% | 0.01 | `worst case for radix tree`
|
| 316,928.00 | 3,155.29 | 1.5% | 3,992,986.00 | 1,699,813.00 | 2.349 | 806,226.50 | 0.0% | 0.01 | `worst case for radix tree`
|
||||||
| 75.85 | 13,183,612.56 | 0.5% | 1,590.01 | 385.64 | 4.123 | 258.00 | 0.0% | 0.01 | `create and destroy`
|
| 75.26 | 13,286,517.16 | 0.5% | 1,590.01 | 386.67 | 4.112 | 258.00 | 0.0% | 0.01 | `create and destroy`
|
||||||
|
|
||||||
|
|
||||||
# "Real data" test
|
# "Real data" test
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ Check: 4.47891 seconds, 364.05 MB/s, Add: 4.55599 seconds, 123.058 MB/s, Gc rati
|
|||||||
## radix tree
|
## radix tree
|
||||||
|
|
||||||
```
|
```
|
||||||
Check: 0.963721 seconds, 1691.93 MB/s, Add: 1.3288 seconds, 421.924 MB/s, Gc ratio: 42.8819%
|
Check: 0.910234 seconds, 1791.35 MB/s, Add: 1.25908 seconds, 445.287 MB/s, Gc ratio: 44.0415%
|
||||||
```
|
```
|
||||||
|
|
||||||
## hash table
|
## hash table
|
||||||
|
@@ -76,6 +76,14 @@ void workload(weaselab::ConflictSet *cs) {
|
|||||||
} else {
|
} else {
|
||||||
w.begin.len = k.size();
|
w.begin.len = k.size();
|
||||||
cs->addWrites(&w, 1, version);
|
cs->addWrites(&w, 1, version);
|
||||||
|
int64_t beginN = version - kWindowSize + rand() % kWindowSize;
|
||||||
|
auto b = numToKey(beginN);
|
||||||
|
auto e = numToKey(beginN + 1000);
|
||||||
|
w.begin.p = b.data();
|
||||||
|
w.begin.len = b.size();
|
||||||
|
w.end.p = e.data();
|
||||||
|
w.end.len = e.size();
|
||||||
|
cs->addWrites(&w, 1, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// GC
|
// GC
|
||||||
|
BIN
corpus/00c9af5b41b4ae33c12623b6683b5a0315a6a4d4
Normal file
BIN
corpus/00c9af5b41b4ae33c12623b6683b5a0315a6a4d4
Normal file
Binary file not shown.
BIN
corpus/038c312d57a8f6fd53a629f2819237fb5f88da51
Normal file
BIN
corpus/038c312d57a8f6fd53a629f2819237fb5f88da51
Normal file
Binary file not shown.
BIN
corpus/043cb17815ddb8f3242a3c3dbf8e7c52263b0e30
Normal file
BIN
corpus/043cb17815ddb8f3242a3c3dbf8e7c52263b0e30
Normal file
Binary file not shown.
BIN
corpus/04aae30fd4c1fa9678360ee983a87c11b2d687b4
Normal file
BIN
corpus/04aae30fd4c1fa9678360ee983a87c11b2d687b4
Normal file
Binary file not shown.
BIN
corpus/05b04a01fa702668fc100f7988f01cfd52915afd
Normal file
BIN
corpus/05b04a01fa702668fc100f7988f01cfd52915afd
Normal file
Binary file not shown.
BIN
corpus/07859ccfb5f61cf15ab6aa01207ba71af1a767e6
Normal file
BIN
corpus/07859ccfb5f61cf15ab6aa01207ba71af1a767e6
Normal file
Binary file not shown.
BIN
corpus/090e0af733a378279f9781f66a1615c0624862a1
Normal file
BIN
corpus/090e0af733a378279f9781f66a1615c0624862a1
Normal file
Binary file not shown.
BIN
corpus/0c7354a5cee7966f239e458621f9b264f4b6f30e
Normal file
BIN
corpus/0c7354a5cee7966f239e458621f9b264f4b6f30e
Normal file
Binary file not shown.
BIN
corpus/0ce9c3bafcb3f3fd1909a66cef04783813fdbe97
Normal file
BIN
corpus/0ce9c3bafcb3f3fd1909a66cef04783813fdbe97
Normal file
Binary file not shown.
BIN
corpus/0f07620da89e8e85aa32907fc6678cf38bc8801f
Normal file
BIN
corpus/0f07620da89e8e85aa32907fc6678cf38bc8801f
Normal file
Binary file not shown.
BIN
corpus/0f35cf72c8ce773274cdc6d5c08bc2576a74b945
Normal file
BIN
corpus/0f35cf72c8ce773274cdc6d5c08bc2576a74b945
Normal file
Binary file not shown.
BIN
corpus/10d1bd7655fc06e36085fce25bbe3362b29a9783
Normal file
BIN
corpus/10d1bd7655fc06e36085fce25bbe3362b29a9783
Normal file
Binary file not shown.
BIN
corpus/119c75695f1b7fec2b57de3234fcb59bd20c5bbb
Normal file
BIN
corpus/119c75695f1b7fec2b57de3234fcb59bd20c5bbb
Normal file
Binary file not shown.
BIN
corpus/11f6db96f711313df1106ceeb011073ae70ee496
Normal file
BIN
corpus/11f6db96f711313df1106ceeb011073ae70ee496
Normal file
Binary file not shown.
BIN
corpus/132fad7a17c6495a057f56a24e3249ec46249bdc
Normal file
BIN
corpus/132fad7a17c6495a057f56a24e3249ec46249bdc
Normal file
Binary file not shown.
BIN
corpus/134be17afe8ab5ca62ce76cfafd523b581e90bb9
Normal file
BIN
corpus/134be17afe8ab5ca62ce76cfafd523b581e90bb9
Normal file
Binary file not shown.
BIN
corpus/16946b8d264a686b091def79de1bfb866a76b167
Normal file
BIN
corpus/16946b8d264a686b091def79de1bfb866a76b167
Normal file
Binary file not shown.
BIN
corpus/172b5521ec42c012938eb2072b65a5867f076a00
Normal file
BIN
corpus/172b5521ec42c012938eb2072b65a5867f076a00
Normal file
Binary file not shown.
BIN
corpus/17755f00a3ba63466403029710717edd74f85d2b
Normal file
BIN
corpus/17755f00a3ba63466403029710717edd74f85d2b
Normal file
Binary file not shown.
BIN
corpus/17df336a0f56637288409df17b3d78ee712e835b
Normal file
BIN
corpus/17df336a0f56637288409df17b3d78ee712e835b
Normal file
Binary file not shown.
BIN
corpus/1b8c9a3fdf96a2c0ec6c3c0fcf78c9ecb20a5962
Normal file
BIN
corpus/1b8c9a3fdf96a2c0ec6c3c0fcf78c9ecb20a5962
Normal file
Binary file not shown.
BIN
corpus/1d1be308eaaa98322da864cbd2ff16d154f6a01a
Normal file
BIN
corpus/1d1be308eaaa98322da864cbd2ff16d154f6a01a
Normal file
Binary file not shown.
BIN
corpus/1e7430360594743dae681f79880d275d6178b76a
Normal file
BIN
corpus/1e7430360594743dae681f79880d275d6178b76a
Normal file
Binary file not shown.
BIN
corpus/1f2dc3e792880d8e7fe51e9b0d2d71ed07b30dd0
Normal file
BIN
corpus/1f2dc3e792880d8e7fe51e9b0d2d71ed07b30dd0
Normal file
Binary file not shown.
BIN
corpus/24e62107b4170fb2ae39736ebf50046f1edf0836
Normal file
BIN
corpus/24e62107b4170fb2ae39736ebf50046f1edf0836
Normal file
Binary file not shown.
BIN
corpus/253fb84659e9d2ebdb9d57b10dea811f4179bf4b
Normal file
BIN
corpus/253fb84659e9d2ebdb9d57b10dea811f4179bf4b
Normal file
Binary file not shown.
BIN
corpus/257aeff186a0d62a1ea7de076ec3810370cda9d7
Normal file
BIN
corpus/257aeff186a0d62a1ea7de076ec3810370cda9d7
Normal file
Binary file not shown.
BIN
corpus/26c5d8fcbc341f7f1ed4e40de241d72dadc3f395
Normal file
BIN
corpus/26c5d8fcbc341f7f1ed4e40de241d72dadc3f395
Normal file
Binary file not shown.
BIN
corpus/26d331a3454e797f80079f672fc465d5ea482b4b
Normal file
BIN
corpus/26d331a3454e797f80079f672fc465d5ea482b4b
Normal file
Binary file not shown.
BIN
corpus/28ef0e90abb263ba353b918374e9062a16afdfb8
Normal file
BIN
corpus/28ef0e90abb263ba353b918374e9062a16afdfb8
Normal file
Binary file not shown.
BIN
corpus/29bef5af0375285e6b58fc608f39e26d7fcea507
Normal file
BIN
corpus/29bef5af0375285e6b58fc608f39e26d7fcea507
Normal file
Binary file not shown.
BIN
corpus/29dc0ea3cb06047a82042a6003d02c8055a85254
Normal file
BIN
corpus/29dc0ea3cb06047a82042a6003d02c8055a85254
Normal file
Binary file not shown.
1
corpus/2ae810daa467ba2bd354e835491a8b3026525764
Normal file
1
corpus/2ae810daa467ba2bd354e835491a8b3026525764
Normal file
@@ -0,0 +1 @@
|
|||||||
|
:<15><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:::::
|
BIN
corpus/2c10fee8ed419936045762ec8b917e0d4a9760df
Normal file
BIN
corpus/2c10fee8ed419936045762ec8b917e0d4a9760df
Normal file
Binary file not shown.
BIN
corpus/2d7ec7062763680f13772f7670f25dbd7077574d
Normal file
BIN
corpus/2d7ec7062763680f13772f7670f25dbd7077574d
Normal file
Binary file not shown.
BIN
corpus/3048c606615cd2ca599de803f534fdeb961b9439
Normal file
BIN
corpus/3048c606615cd2ca599de803f534fdeb961b9439
Normal file
Binary file not shown.
BIN
corpus/314dac4fdc9bb4896b5aacadfbbfe408899732e8
Normal file
BIN
corpus/314dac4fdc9bb4896b5aacadfbbfe408899732e8
Normal file
Binary file not shown.
BIN
corpus/322e7b4fe43ae5977f74a882984404dee9ee7e90
Normal file
BIN
corpus/322e7b4fe43ae5977f74a882984404dee9ee7e90
Normal file
Binary file not shown.
BIN
corpus/3328522dbba9d1d88befc4edf7ddf3a28d0c1e18
Normal file
BIN
corpus/3328522dbba9d1d88befc4edf7ddf3a28d0c1e18
Normal file
Binary file not shown.
BIN
corpus/33ea991ae4abe2b9bb1fa19028543d1d01411148
Normal file
BIN
corpus/33ea991ae4abe2b9bb1fa19028543d1d01411148
Normal file
Binary file not shown.
BIN
corpus/33ec7c523e4e73126edac3d32e2e9737b3839203
Normal file
BIN
corpus/33ec7c523e4e73126edac3d32e2e9737b3839203
Normal file
Binary file not shown.
BIN
corpus/3460a3af48f48e6657998179b974d8eccd618dd2
Normal file
BIN
corpus/3460a3af48f48e6657998179b974d8eccd618dd2
Normal file
Binary file not shown.
BIN
corpus/34b90ac8d0d24842c6e3634d5d4b40a4eb0e1ed1
Normal file
BIN
corpus/34b90ac8d0d24842c6e3634d5d4b40a4eb0e1ed1
Normal file
Binary file not shown.
BIN
corpus/35382c7ae1f09972f9c6829e585cf10503917411
Normal file
BIN
corpus/35382c7ae1f09972f9c6829e585cf10503917411
Normal file
Binary file not shown.
BIN
corpus/35e6c44a434a927dbd99a1bb6ddecbd0ecb45754
Normal file
BIN
corpus/35e6c44a434a927dbd99a1bb6ddecbd0ecb45754
Normal file
Binary file not shown.
BIN
corpus/36ae24ff8ae3dae3302e12bcb2acbb7e2574a148
Normal file
BIN
corpus/36ae24ff8ae3dae3302e12bcb2acbb7e2574a148
Normal file
Binary file not shown.
BIN
corpus/39184f515f2417da12ee98d262810085755d846e
Normal file
BIN
corpus/39184f515f2417da12ee98d262810085755d846e
Normal file
Binary file not shown.
BIN
corpus/3928db1fdf00d2056135391cb188fcbe804d5ec8
Normal file
BIN
corpus/3928db1fdf00d2056135391cb188fcbe804d5ec8
Normal file
Binary file not shown.
BIN
corpus/3bbcd74622cdf41760e234c1cd861b61c4305840
Normal file
BIN
corpus/3bbcd74622cdf41760e234c1cd861b61c4305840
Normal file
Binary file not shown.
BIN
corpus/3bed999a619dbe2eedee03ad5a2d2e8cdbef62f8
Normal file
BIN
corpus/3bed999a619dbe2eedee03ad5a2d2e8cdbef62f8
Normal file
Binary file not shown.
BIN
corpus/3c1f7d9c07946d7dd34d13246ceca500bd7b2c50
Normal file
BIN
corpus/3c1f7d9c07946d7dd34d13246ceca500bd7b2c50
Normal file
Binary file not shown.
BIN
corpus/3c74b098773c633bb593dc139aaef296e59bd766
Normal file
BIN
corpus/3c74b098773c633bb593dc139aaef296e59bd766
Normal file
Binary file not shown.
BIN
corpus/3d84be86223ee1047117c8b96dc8a582ef21ff38
Normal file
BIN
corpus/3d84be86223ee1047117c8b96dc8a582ef21ff38
Normal file
Binary file not shown.
BIN
corpus/3d931de827b1030b3e1d35b36a35395b332d80a9
Normal file
BIN
corpus/3d931de827b1030b3e1d35b36a35395b332d80a9
Normal file
Binary file not shown.
BIN
corpus/3df34e97d1b2ebaec718fb8137e7b797153ac48b
Normal file
BIN
corpus/3df34e97d1b2ebaec718fb8137e7b797153ac48b
Normal file
Binary file not shown.
BIN
corpus/3eab35eb7655db26a12f90948403e249c6237560
Normal file
BIN
corpus/3eab35eb7655db26a12f90948403e249c6237560
Normal file
Binary file not shown.
BIN
corpus/3f9df1388fef68bc7fe3ae8445992a4fb6805ee5
Normal file
BIN
corpus/3f9df1388fef68bc7fe3ae8445992a4fb6805ee5
Normal file
Binary file not shown.
BIN
corpus/3fab07c422c76377ea173f9be787362f150220b8
Normal file
BIN
corpus/3fab07c422c76377ea173f9be787362f150220b8
Normal file
Binary file not shown.
BIN
corpus/440e4f725ddcf632d56fbb3d768f99c1f4791cd7
Normal file
BIN
corpus/440e4f725ddcf632d56fbb3d768f99c1f4791cd7
Normal file
Binary file not shown.
BIN
corpus/458dbacffe320dba21c96c886d6f83f5a18a33cd
Normal file
BIN
corpus/458dbacffe320dba21c96c886d6f83f5a18a33cd
Normal file
Binary file not shown.
BIN
corpus/45b63e3bf07fbfa3ae81b24234e4809773ebddb1
Normal file
BIN
corpus/45b63e3bf07fbfa3ae81b24234e4809773ebddb1
Normal file
Binary file not shown.
BIN
corpus/45f5d2b9179b93b7a7341098157f85b53f490e49
Normal file
BIN
corpus/45f5d2b9179b93b7a7341098157f85b53f490e49
Normal file
Binary file not shown.
BIN
corpus/477b79472d79b4b4869d682430768c9a7c899a02
Normal file
BIN
corpus/477b79472d79b4b4869d682430768c9a7c899a02
Normal file
Binary file not shown.
BIN
corpus/48330eecab1796945467ce1bc5896e96c6ee0cd6
Normal file
BIN
corpus/48330eecab1796945467ce1bc5896e96c6ee0cd6
Normal file
Binary file not shown.
BIN
corpus/4850668db4c53678211212cda1d4ecbd8751239d
Normal file
BIN
corpus/4850668db4c53678211212cda1d4ecbd8751239d
Normal file
Binary file not shown.
BIN
corpus/48590dfc5187a5cbf6e6c51b40a74a4e3294b743
Normal file
BIN
corpus/48590dfc5187a5cbf6e6c51b40a74a4e3294b743
Normal file
Binary file not shown.
BIN
corpus/49bb8b62309eebbce1323fcf604a12db023504c4
Normal file
BIN
corpus/49bb8b62309eebbce1323fcf604a12db023504c4
Normal file
Binary file not shown.
BIN
corpus/4a3b960f09b621ba937c5d0dccedd0dea8acbb16
Normal file
BIN
corpus/4a3b960f09b621ba937c5d0dccedd0dea8acbb16
Normal file
Binary file not shown.
BIN
corpus/4ad43b5c18088e5f1aedca8ebaddeb509dc5e268
Normal file
BIN
corpus/4ad43b5c18088e5f1aedca8ebaddeb509dc5e268
Normal file
Binary file not shown.
BIN
corpus/4b06a3a1708dc45d0930a72f0b95cd5f026333ae
Normal file
BIN
corpus/4b06a3a1708dc45d0930a72f0b95cd5f026333ae
Normal file
Binary file not shown.
BIN
corpus/4c5b61a584949687865353d2d2c81bc00e7f7cbd
Normal file
BIN
corpus/4c5b61a584949687865353d2d2c81bc00e7f7cbd
Normal file
Binary file not shown.
BIN
corpus/4cd1d2a53abe09e67d764ad05991fc0c49261eb3
Normal file
BIN
corpus/4cd1d2a53abe09e67d764ad05991fc0c49261eb3
Normal file
Binary file not shown.
BIN
corpus/4e6104dac785c753c166da59ea1a1646217bfc6e
Normal file
BIN
corpus/4e6104dac785c753c166da59ea1a1646217bfc6e
Normal file
Binary file not shown.
BIN
corpus/4eb8b83ac7845b15dd1b147a4ce4869b2665cc12
Normal file
BIN
corpus/4eb8b83ac7845b15dd1b147a4ce4869b2665cc12
Normal file
Binary file not shown.
BIN
corpus/4f6f6c3d09001ba95b1f1d2e2c66715441247e5b
Normal file
BIN
corpus/4f6f6c3d09001ba95b1f1d2e2c66715441247e5b
Normal file
Binary file not shown.
BIN
corpus/5074dff46e60dfb9b38aee048d1a9d3cb53d5c87
Normal file
BIN
corpus/5074dff46e60dfb9b38aee048d1a9d3cb53d5c87
Normal file
Binary file not shown.
BIN
corpus/50cd28281e1dcafb95009dcc97969d23b0158ecf
Normal file
BIN
corpus/50cd28281e1dcafb95009dcc97969d23b0158ecf
Normal file
Binary file not shown.
BIN
corpus/50dbe583be2b8295745e6c627b8a46817e7dd752
Normal file
BIN
corpus/50dbe583be2b8295745e6c627b8a46817e7dd752
Normal file
Binary file not shown.
BIN
corpus/52680322ee127bd82e89b03c41692357b003ad53
Normal file
BIN
corpus/52680322ee127bd82e89b03c41692357b003ad53
Normal file
Binary file not shown.
BIN
corpus/539e8d43ae9c29ab09380a8b953b611da35101a3
Normal file
BIN
corpus/539e8d43ae9c29ab09380a8b953b611da35101a3
Normal file
Binary file not shown.
BIN
corpus/545bbfcd4bf29b9037eea23183105ca8e1160503
Normal file
BIN
corpus/545bbfcd4bf29b9037eea23183105ca8e1160503
Normal file
Binary file not shown.
BIN
corpus/54836b3cd14df1879738a1e8e9280e109c95b9e6
Normal file
BIN
corpus/54836b3cd14df1879738a1e8e9280e109c95b9e6
Normal file
Binary file not shown.
BIN
corpus/54add85ac0baafd3b074c2c78f9afb95eacd3a49
Normal file
BIN
corpus/54add85ac0baafd3b074c2c78f9afb95eacd3a49
Normal file
Binary file not shown.
BIN
corpus/54d128b61393dee1015d8dd68de68a302257a6fa
Normal file
BIN
corpus/54d128b61393dee1015d8dd68de68a302257a6fa
Normal file
Binary file not shown.
BIN
corpus/55b0c983e9dc4b24357cfd8c37399933b82875a5
Normal file
BIN
corpus/55b0c983e9dc4b24357cfd8c37399933b82875a5
Normal file
Binary file not shown.
BIN
corpus/56bbbabcc0ba4d36ba3fb335f49777d9814d0f4c
Normal file
BIN
corpus/56bbbabcc0ba4d36ba3fb335f49777d9814d0f4c
Normal file
Binary file not shown.
BIN
corpus/59cdf157f3040f98de762d8d771d4b4d70f170d7
Normal file
BIN
corpus/59cdf157f3040f98de762d8d771d4b4d70f170d7
Normal file
Binary file not shown.
BIN
corpus/5b05354760851996fbab364e9675a890e172cc59
Normal file
BIN
corpus/5b05354760851996fbab364e9675a890e172cc59
Normal file
Binary file not shown.
BIN
corpus/5d7ba8ef70a5f39193ce6289681286523067393d
Normal file
BIN
corpus/5d7ba8ef70a5f39193ce6289681286523067393d
Normal file
Binary file not shown.
BIN
corpus/5d9fd4f7eaa854395d3969acc414ee5afd01ccbf
Normal file
BIN
corpus/5d9fd4f7eaa854395d3969acc414ee5afd01ccbf
Normal file
Binary file not shown.
BIN
corpus/5e38b1c3d7033ee28165cdba66a3116d39f879a8
Normal file
BIN
corpus/5e38b1c3d7033ee28165cdba66a3116d39f879a8
Normal file
Binary file not shown.
BIN
corpus/5fd96158c704452bf94354946bddae654fc28186
Normal file
BIN
corpus/5fd96158c704452bf94354946bddae654fc28186
Normal file
Binary file not shown.
BIN
corpus/605edeedcabff8b19db629d4ebb1c039c22e9ed9
Normal file
BIN
corpus/605edeedcabff8b19db629d4ebb1c039c22e9ed9
Normal file
Binary file not shown.
BIN
corpus/615a0836aa95424ef2dc47f924a5ba658cd3814e
Normal file
BIN
corpus/615a0836aa95424ef2dc47f924a5ba658cd3814e
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user