Test 64 bit versions
All checks were successful
Tests / Clang total: 2710, passed: 2710
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / 64 bit versions total: 2710, passed: 2710
Tests / Debug total: 2708, passed: 2708
Tests / SIMD fallback total: 2710, passed: 2710
Tests / Release [gcc] total: 2710, passed: 2710
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 2020, passed: 2020
Tests / Coverage total: 2036, passed: 2036
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.92% (1825/1845) * Branch Coverage: 66.85% (1480/2214) * Complexity Density: 0.00 * Lines of Code: 1845 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good

Keep 32 bit versions the default though
This commit is contained in:
2024-08-21 13:58:09 -07:00
parent 442755d0a6
commit 7f86fdee66
2 changed files with 80 additions and 11 deletions

View File

@@ -87,22 +87,42 @@ constexpr int64_t kMaxCorrectVersionWindow =
std::numeric_limits<int32_t>::max(); std::numeric_limits<int32_t>::max();
static_assert(kNominalVersionWindow <= kMaxCorrectVersionWindow); static_assert(kNominalVersionWindow <= kMaxCorrectVersionWindow);
#ifndef USE_64_BIT
#define USE_64_BIT 0
#endif
struct InternalVersionT { struct InternalVersionT {
constexpr InternalVersionT() = default; constexpr InternalVersionT() = default;
constexpr explicit InternalVersionT(int64_t value) : value(value) {} constexpr explicit InternalVersionT(int64_t value) : value(value) {}
constexpr int64_t toInt64() const { return value; } // GCOVR_EXCL_LINE constexpr int64_t toInt64() const { return value; } // GCOVR_EXCL_LINE
constexpr auto operator<=>(const InternalVersionT &rhs) const { constexpr auto operator<=>(const InternalVersionT &rhs) const {
#if USE_64_BIT
return value <=> rhs.value;
#else
// Maintains ordering after overflow, as long as the full-precision versions // Maintains ordering after overflow, as long as the full-precision versions
// are within `kMaxCorrectVersionWindow` of eachother. // are within `kMaxCorrectVersionWindow` of eachother.
return int32_t(value - rhs.value) <=> 0; return int32_t(value - rhs.value) <=> 0;
#endif
} }
constexpr bool operator==(const InternalVersionT &) const = default; constexpr bool operator==(const InternalVersionT &) const = default;
#if USE_64_BIT
static const InternalVersionT zero;
#else
static thread_local InternalVersionT zero; static thread_local InternalVersionT zero;
#endif
private: private:
#if USE_64_BIT
int64_t value;
#else
uint32_t value; uint32_t value;
#endif
}; };
#if USE_64_BIT
const InternalVersionT InternalVersionT::zero{0};
#else
thread_local InternalVersionT InternalVersionT::zero; thread_local InternalVersionT InternalVersionT::zero;
#endif
struct Entry { struct Entry {
InternalVersionT pointVersion; InternalVersionT pointVersion;
@@ -518,8 +538,13 @@ std::string getSearchPath(Node *n);
// Each node with an entry present gets a budget of kBytesPerKey. Node0 always // Each node with an entry present gets a budget of kBytesPerKey. Node0 always
// has an entry present. // has an entry present.
// Induction hypothesis is that each node's surplus is >= kMinNodeSurplus // Induction hypothesis is that each node's surplus is >= kMinNodeSurplus
#if USE_64_BIT
constexpr int kBytesPerKey = 144;
constexpr int kMinNodeSurplus = 104;
#else
constexpr int kBytesPerKey = 112; constexpr int kBytesPerKey = 112;
constexpr int kMinNodeSurplus = 80; constexpr int kMinNodeSurplus = 80;
#endif
// Cound the entry itself as a child // Cound the entry itself as a child
constexpr int kMinChildrenNode0 = 1; constexpr int kMinChildrenNode0 = 1;
constexpr int kMinChildrenNode3 = 2; constexpr int kMinChildrenNode3 = 2;
@@ -724,9 +749,13 @@ struct WriteContext {
int64_t write_bytes; int64_t write_bytes;
} accum; } accum;
#if USE_64_BIT
static constexpr InternalVersionT zero{0};
#else
// Cache a copy of InternalVersionT::zero, so we don't need to do the TLS // Cache a copy of InternalVersionT::zero, so we don't need to do the TLS
// lookup as often. // lookup as often.
InternalVersionT zero; InternalVersionT zero;
#endif
WriteContext() { memset(&accum, 0, sizeof(accum)); } WriteContext() { memset(&accum, 0, sizeof(accum)); }
@@ -1563,6 +1592,9 @@ void rezero16(InternalVersionT *vs, InternalVersionT zero) {
} }
} }
#if USE_64_BIT
void rezero(Node *, InternalVersionT) {}
#else
void rezero(Node *n, InternalVersionT z) { void rezero(Node *n, InternalVersionT z) {
#if DEBUG_VERBOSE && !defined(NDEBUG) #if DEBUG_VERBOSE && !defined(NDEBUG)
fprintf(stderr, "rezero to %" PRId64 ": %s\n", z.toInt64(), fprintf(stderr, "rezero to %" PRId64 ": %s\n", z.toInt64(),
@@ -1605,6 +1637,7 @@ void rezero(Node *n, InternalVersionT z) {
__builtin_unreachable(); // GCOVR_EXCL_LINE __builtin_unreachable(); // GCOVR_EXCL_LINE
} }
} }
#endif
void mergeWithChild(Node *&self, WriteContext *tls, ConflictSet::Impl *impl, void mergeWithChild(Node *&self, WriteContext *tls, ConflictSet::Impl *impl,
Node *&dontInvalidate, Node3 *self3) { Node *&dontInvalidate, Node3 *self3) {
@@ -1987,7 +2020,14 @@ downLeftSpine:
} }
#ifdef HAS_AVX #ifdef HAS_AVX
uint32_t compare16_32bit(const InternalVersionT *vs, InternalVersionT rv) { uint32_t compare16(const InternalVersionT *vs, InternalVersionT rv) {
#if USE_64_BIT
uint32_t compared = 0;
for (int i = 0; i < 16; ++i) {
compared |= (vs[i] > rv) << i;
}
return compared;
#else
uint32_t compared = 0; uint32_t compared = 0;
__m128i w[4]; // GCOVR_EXCL_LINE __m128i w[4]; // GCOVR_EXCL_LINE
memcpy(w, vs, sizeof(w)); memcpy(w, vs, sizeof(w));
@@ -2001,15 +2041,26 @@ uint32_t compare16_32bit(const InternalVersionT *vs, InternalVersionT rv) {
<< (i * 4); << (i * 4);
} }
return compared; return compared;
#endif
} }
__attribute__((target("avx512f"))) uint32_t __attribute__((target("avx512f"))) uint32_t
compare16_32bit_avx512(const InternalVersionT *vs, InternalVersionT rv) { compare16_avx512(const InternalVersionT *vs, InternalVersionT rv) {
#if USE_64_BIT
int64_t r;
memcpy(&r, &rv, sizeof(r));
uint32_t low =
_mm512_cmpgt_epi64_mask(_mm512_loadu_epi64(vs), _mm512_set1_epi64(r));
uint32_t high =
_mm512_cmpgt_epi64_mask(_mm512_loadu_epi64(vs + 8), _mm512_set1_epi64(r));
return low | (high << 8);
#else
uint32_t r; uint32_t r;
memcpy(&r, &rv, sizeof(r)); memcpy(&r, &rv, sizeof(r));
return _mm512_cmpgt_epi32_mask( return _mm512_cmpgt_epi32_mask(
_mm512_sub_epi32(_mm512_loadu_epi32(vs), _mm512_set1_epi32(r)), _mm512_sub_epi32(_mm512_loadu_epi32(vs), _mm512_set1_epi32(r)),
_mm512_setzero_epi32()); _mm512_setzero_epi32());
#endif
} }
#endif #endif
@@ -2066,9 +2117,9 @@ bool scan16(const InternalVersionT *vs, const uint8_t *is, int begin, int end,
uint32_t compared = 0; uint32_t compared = 0;
if constexpr (kAVX512) { if constexpr (kAVX512) {
compared = compare16_32bit_avx512(vs, readVersion); // GCOVR_EXCL_LINE compared = compare16_avx512(vs, readVersion);
} else { } else {
compared = compare16_32bit(vs, readVersion); // GCOVR_EXCL_LINE compared = compare16(vs, readVersion);
} }
return !(compared & mask); return !(compared & mask);
@@ -2127,9 +2178,9 @@ bool scan16(const InternalVersionT *vs, int begin, int end,
#elif defined(HAS_AVX) #elif defined(HAS_AVX)
uint32_t conflict; uint32_t conflict;
if constexpr (kAVX512) { if constexpr (kAVX512) {
conflict = compare16_32bit_avx512(vs, readVersion); // GCOVR_EXCL_LINE conflict = compare16_avx512(vs, readVersion);
} else { } else {
conflict = compare16_32bit(vs, readVersion); // GCOVR_EXCL_LINE conflict = compare16(vs, readVersion);
} }
conflict &= (1 << end) - 1; conflict &= (1 << end) - 1;
conflict >>= begin; conflict >>= begin;
@@ -2264,12 +2315,9 @@ bool checkMaxBetweenExclusiveImpl(Node *n, int begin, int end,
uint32_t compared = 0; uint32_t compared = 0;
if constexpr (kAVX512) { if constexpr (kAVX512) {
compared = // GCOVR_EXCL_LINE compared = compare16_avx512(self->childMaxVersion, readVersion);
compare16_32bit_avx512(self->childMaxVersion, // GCOVR_EXCL_LINE
readVersion); // GCOVR_EXCL_LINE
} else { } else {
compared = compare16_32bit(self->childMaxVersion, compared = compare16(self->childMaxVersion, readVersion);
readVersion); // GCOVR_EXCL_LINE
} }
return !(compared & mask) && firstRangeOk; return !(compared & mask) && firstRangeOk;
@@ -3137,10 +3185,12 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
} }
void addWrites(const WriteRange *writes, int count, int64_t writeVersion) { void addWrites(const WriteRange *writes, int count, int64_t writeVersion) {
#if !USE_64_BIT
// There could be other conflict sets in the same thread. We need // There could be other conflict sets in the same thread. We need
// InternalVersionT::zero to be correct for this conflict set for the // InternalVersionT::zero to be correct for this conflict set for the
// lifetime of the current call frame. // lifetime of the current call frame.
InternalVersionT::zero = tls.zero = oldestVersion; InternalVersionT::zero = tls.zero = oldestVersion;
#endif
assert(writeVersion >= newestVersionFullPrecision); assert(writeVersion >= newestVersionFullPrecision);
assert(tls.accum.entries_erased == 0); assert(tls.accum.entries_erased == 0);
@@ -3255,7 +3305,9 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
InternalVersionT oldestVersion{o}; InternalVersionT oldestVersion{o};
this->oldestVersionFullPrecision = o; this->oldestVersionFullPrecision = o;
this->oldestVersion = oldestVersion; this->oldestVersion = oldestVersion;
#if !USE_64_BIT
InternalVersionT::zero = tls.zero = oldestVersion; InternalVersionT::zero = tls.zero = oldestVersion;
#endif
#ifdef NDEBUG #ifdef NDEBUG
// This is here for performance reasons, since we want to amortize the cost // This is here for performance reasons, since we want to amortize the cost
// of storing the search path as a string. In tests, we want to exercise the // of storing the search path as a string. In tests, we want to exercise the
@@ -3304,7 +3356,9 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
root->entry.pointVersion = this->oldestVersion; root->entry.pointVersion = this->oldestVersion;
root->entry.rangeVersion = this->oldestVersion; root->entry.rangeVersion = this->oldestVersion;
#if !USE_64_BIT
InternalVersionT::zero = tls.zero = this->oldestVersion; InternalVersionT::zero = tls.zero = this->oldestVersion;
#endif
// Intentionally not resetting totalBytes // Intentionally not resetting totalBytes
} }
@@ -3751,6 +3805,9 @@ Node *firstGeq(Node *n, std::string_view key) {
n, std::span<const uint8_t>((const uint8_t *)key.data(), key.size())); n, std::span<const uint8_t>((const uint8_t *)key.data(), key.size()));
} }
#if USE_64_BIT
void checkVersionsGeqOldestExtant(Node *, InternalVersionT) {}
#else
void checkVersionsGeqOldestExtant(Node *n, void checkVersionsGeqOldestExtant(Node *n,
InternalVersionT oldestExtantVersion) { InternalVersionT oldestExtantVersion) {
if (n->entryPresent) { if (n->entryPresent) {
@@ -3794,6 +3851,7 @@ void checkVersionsGeqOldestExtant(Node *n,
abort(); abort();
} }
} }
#endif
[[maybe_unused]] InternalVersionT [[maybe_unused]] InternalVersionT
checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion, checkMaxVersion(Node *root, Node *node, InternalVersionT oldestVersion,

11
Jenkinsfile vendored
View File

@@ -48,6 +48,17 @@ pipeline {
recordIssues(tools: [clang()]) recordIssues(tools: [clang()])
} }
} }
stage('64 bit versions') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DCMAKE_CXX_FLAGS=-DUSE_64_BIT=1")
}
}
stage('Debug') { stage('Debug') {
agent { agent {
dockerfile { dockerfile {