6 Commits

Author SHA1 Message Date
c46f633dbf Skip sorting if already sorted for skip list
All checks were successful
Tests / 64 bit versions total: 7950, passed: 7950
Tests / Debug total: 7948, passed: 7948
Tests / SIMD fallback total: 7950, passed: 7950
Tests / Release [clang] total: 7950, passed: 7950
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 7950, passed: 7950
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [clang,aarch64] total: 5268, passed: 5268
Tests / Coverage total: 5316, passed: 5316
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 97.67% (3138/3213) * Branch Coverage: 42.05% (18734/44548) * Complexity Density: 0.00 * Lines of Code: 3213 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-11-12 13:25:29 -08:00
400350946c Point read/write workload for server_bench 2024-11-12 10:50:03 -08:00
607a4ef6e2 Require musttail and preserve_none for interleaved 2024-11-11 21:40:05 -08:00
b0750772ec Don't do hardening check if cross compiling
All checks were successful
Tests / 64 bit versions total: 7950, passed: 7950
Tests / Debug total: 7948, passed: 7948
Tests / SIMD fallback total: 7950, passed: 7950
Tests / Release [clang] total: 7950, passed: 7950
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 7950, passed: 7950
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [clang,aarch64] total: 5268, passed: 5268
Tests / Coverage total: 5316, passed: 5316
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 97.67% (3139/3214) * Branch Coverage: 42.05% (18734/44548) * Complexity Density: 0.00 * Lines of Code: 3214 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
2024-11-11 16:56:28 -08:00
86abc02188 Build binaries compatible with cf-protection
Some checks failed
Tests / 64 bit versions total: 7950, passed: 7950
Tests / Debug total: 7948, passed: 7948
Tests / SIMD fallback total: 7950, passed: 7950
Tests / Release [clang] total: 7950, passed: 7950
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 7950, passed: 7950
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [clang,aarch64] total: 5269, failed: 1, passed: 5268
Tests / Coverage total: 5316, passed: 5316
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-11-11 16:17:57 -08:00
a90e353fcd Use llvm-objcopy if using clang and it's available
This works around a weird error I was getting when trying to link a
translation unit that included Internal.h with libconflict-set-static.a
with clang + gnu objcopy
2024-11-11 12:09:36 -08:00
58 changed files with 64 additions and 262 deletions

View File

@@ -32,12 +32,7 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
endif()
add_compile_options(
-Werror=switch-enum
-Wswitch-enum
-Wunused-variable
-fPIC
-fdata-sections
-ffunction-sections
-Werror=switch-enum -Wswitch-enum -fPIC -fdata-sections -ffunction-sections
-fno-jump-tables # https://github.com/llvm/llvm-project/issues/54247
)
@@ -109,11 +104,19 @@ else()
add_link_options(-Wl,--gc-sections)
endif()
if(USE_SIMD_FALLBACK)
add_compile_definitions(USE_SIMD_FALLBACK)
else()
if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
if(NOT USE_SIMD_FALLBACK)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
check_include_file_cxx("immintrin.h" HAS_AVX)
if(HAS_AVX)
add_compile_options(-mavx)
add_compile_definitions(HAS_AVX)
endif()
cmake_pop_check_state()
check_include_file_cxx("arm_neon.h" HAS_ARM_NEON)
if(HAS_ARM_NEON)
add_compile_definitions(HAS_ARM_NEON)
endif()
endif()
@@ -343,7 +346,8 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
# c++98
add_executable(conflict_set_cxx_api_test conflict_set_cxx_api_test.cpp)
target_compile_options(conflict_set_cxx_api_test PRIVATE ${TEST_FLAGS})
target_link_libraries(conflict_set_cxx_api_test PRIVATE ${PROJECT_NAME})
target_link_libraries(conflict_set_cxx_api_test
PRIVATE ${PROJECT_NAME}-static)
set_target_properties(conflict_set_cxx_api_test PROPERTIES CXX_STANDARD 98)
set_target_properties(conflict_set_cxx_api_test
PROPERTIES CXX_STANDARD_REQUIRED ON)

View File

@@ -14,16 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#if !defined(USE_SIMD_FALLBACK) && defined(__has_include)
#if defined(__x86_64__) && __has_include("immintrin.h")
#define HAS_AVX 1
#include <immintrin.h>
#elif __has_include("arm_neon.h")
#define HAS_ARM_NEON 1
#include <arm_neon.h>
#endif
#endif
#include "ConflictSet.h"
#include "Internal.h"
#include "LongestCommonPrefix.h"
@@ -44,6 +34,12 @@ limitations under the License.
#include <type_traits>
#include <utility>
#ifdef HAS_AVX
#include <immintrin.h>
#elif defined(HAS_ARM_NEON)
#include <arm_neon.h>
#endif
#ifndef __SANITIZE_THREAD__
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
@@ -700,6 +696,8 @@ constexpr int64_t kMaxFreeListBytes = 1 << 20;
// doesn't meet the capacity constraints, it's freed and a new node is allocated
// with the minimum capacity. The hope is that "unfit" nodes don't get stuck in
// the free list.
//
// TODO valgrind annotations
template <class T> struct NodeAllocator {
static_assert(std::derived_from<T, Node>);
@@ -736,7 +734,6 @@ template <class T> struct NodeAllocator {
p->parent = freeList;
freeList = p;
freeListSize += sizeof(T) + p->partialKeyCapacity;
VALGRIND_MAKE_MEM_NOACCESS(p, sizeof(T) + p->partialKeyCapacity);
}
void deferRelease(T *p, Node *forwardTo) {
@@ -758,13 +755,6 @@ template <class T> struct NodeAllocator {
void releaseDeferred() {
if (deferredList != nullptr) {
deferredListFront->parent = freeList;
#ifndef NVALGRIND
for (auto *iter = deferredList; iter != freeList;) {
auto *tmp = iter;
iter = (T *)iter->parent;
VALGRIND_MAKE_MEM_NOACCESS(tmp, sizeof(T) + tmp->partialKeyCapacity);
}
#endif
freeList = std::exchange(deferredList, nullptr);
}
for (T *n = std::exchange(deferredListOverflow, nullptr); n != nullptr;) {
@@ -785,7 +775,6 @@ template <class T> struct NodeAllocator {
assert(deferredList == nullptr);
assert(deferredListOverflow == nullptr);
for (T *iter = freeList; iter != nullptr;) {
VALGRIND_MAKE_MEM_DEFINED(iter, sizeof(T));
auto *tmp = iter;
iter = (T *)iter->parent;
removeNode(tmp);
@@ -803,7 +792,6 @@ private:
T *allocate_helper(int minCapacity, int maxCapacity) {
if (freeList != nullptr) {
VALGRIND_MAKE_MEM_DEFINED(freeList, sizeof(T));
freeListSize -= sizeof(T) + freeList->partialKeyCapacity;
assume(freeList->partialKeyCapacity >= 0);
assume(minCapacity >= 0);
@@ -812,11 +800,6 @@ private:
freeList->partialKeyCapacity <= maxCapacity) {
auto *result = freeList;
freeList = (T *)freeList->parent;
VALGRIND_MAKE_MEM_UNDEFINED(result,
sizeof(T) + result->partialKeyCapacity);
VALGRIND_MAKE_MEM_DEFINED(&result->partialKeyCapacity,
sizeof(result->partialKeyCapacity));
VALGRIND_MAKE_MEM_DEFINED(&result->type, sizeof(result->type));
return result;
} else {
auto *p = freeList;
@@ -5347,11 +5330,6 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
gc_iterations_total.add(set_oldest_iterations_accum);
if (n == nullptr) {
removalKey = {};
if (removalBufferSize > kMaxRemovalBufferSize) {
safe_free(removalBuffer, removalBufferSize);
removalBufferSize = kMinRemovalBufferSize;
removalBuffer = (uint8_t *)safe_malloc(removalBufferSize);
}
oldestExtantVersion = oldestVersionAtGcBegin;
oldest_extant_version.set(oldestExtantVersion);
oldestVersionAtGcBegin = oldestVersionFullPrecision;
@@ -5362,47 +5340,12 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
oldestExtantVersion, oldestVersionAtGcBegin);
#endif
} else {
// Store the current search path to resume the scan later
saveRemovalKey(n);
removalKeyArena = Arena();
removalKey = getSearchPath(removalKeyArena, n);
}
return fuel;
}
void saveRemovalKey(Node *n) {
uint8_t *cursor = removalBuffer + removalBufferSize;
int size = 0;
auto reserve = [&](int delta) {
if (size + delta > removalBufferSize) [[unlikely]] {
int newBufSize = std::max(removalBufferSize * 2, size + delta);
uint8_t *newBuf = (uint8_t *)safe_malloc(newBufSize);
memcpy(newBuf + newBufSize - size, cursor, size);
safe_free(removalBuffer, removalBufferSize);
removalBuffer = newBuf;
removalBufferSize = newBufSize;
cursor = newBuf + newBufSize - size;
}
};
for (;;) {
auto partialKey = TrivialSpan{n->partialKey(), n->partialKeyLen};
reserve(partialKey.size());
size += partialKey.size();
cursor -= partialKey.size();
memcpy(cursor, partialKey.data(), partialKey.size());
if (n->parent == nullptr) {
break;
}
reserve(1);
++size;
--cursor;
*cursor = n->parentsIndex;
n = n->parent;
}
removalKey = {cursor, size};
}
void setOldestVersion(int64_t newOldestVersion) {
assert(newOldestVersion >= 0);
assert(newOldestVersion <= newestVersionFullPrecision);
@@ -5453,7 +5396,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
writeContext.~WriteContext();
new (&writeContext) WriteContext();
// Leave removalBuffer as is
removalKeyArena = Arena{};
removalKey = {};
keyUpdates = 10;
@@ -5485,16 +5428,11 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
~Impl() {
eraseTree(root, &writeContext);
safe_free(metrics, metricsCount * sizeof(metrics[0]));
safe_free(removalBuffer, removalBufferSize);
}
WriteContext writeContext;
static constexpr int kMinRemovalBufferSize = 1 << 10;
// Eventually downsize if larger than this value
static constexpr int kMaxRemovalBufferSize = 1 << 16;
uint8_t *removalBuffer = (uint8_t *)safe_malloc(kMinRemovalBufferSize);
int removalBufferSize = kMinRemovalBufferSize;
Arena removalKeyArena;
TrivialSpan removalKey;
int64_t keyUpdates;
@@ -5920,13 +5858,13 @@ void checkVersionsGeqOldestExtant(Node *n,
case Type_Node0: {
} break;
case Type_Node3: {
[[maybe_unused]] auto *self = static_cast<Node3 *>(n);
auto *self = static_cast<Node3 *>(n);
for (int i = 0; i < 3; ++i) {
assert(self->childMaxVersion[i] >= oldestExtantVersion);
}
} break;
case Type_Node16: {
[[maybe_unused]] auto *self = static_cast<Node16 *>(n);
auto *self = static_cast<Node16 *>(n);
for (int i = 0; i < 16; ++i) {
assert(self->childMaxVersion[i] >= oldestExtantVersion);
}
@@ -5936,7 +5874,7 @@ void checkVersionsGeqOldestExtant(Node *n,
for (int i = 0; i < 48; ++i) {
assert(self->childMaxVersion[i] >= oldestExtantVersion);
}
for ([[maybe_unused]] auto m : self->maxOfMax) {
for (auto m : self->maxOfMax) {
assert(m >= oldestExtantVersion);
}
} break;
@@ -5945,7 +5883,7 @@ void checkVersionsGeqOldestExtant(Node *n,
for (int i = 0; i < 256; ++i) {
assert(self->childMaxVersion[i] >= oldestExtantVersion);
}
for ([[maybe_unused]] auto m : self->maxOfMax) {
for (auto m : self->maxOfMax) {
assert(m >= oldestExtantVersion);
}
} break;

4
Jenkinsfile vendored
View File

@@ -91,7 +91,7 @@ pipeline {
minio bucket: 'jenkins', credentialsId: 'jenkins-minio', excludes: '', host: 'minio.weaselab.dev', includes: 'build/*.deb,build/*.rpm,paper/*.pdf', targetFolder: '${JOB_NAME}/${BUILD_NUMBER}/${STAGE_NAME}/'
}
}
stage('gcc') {
stage('Release [gcc]') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
@@ -99,7 +99,7 @@ pipeline {
}
}
steps {
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++")
CleanBuildAndTest("-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS=-DNVALGRIND")
recordIssues(tools: [gcc()])
}
}

View File

@@ -5,7 +5,7 @@
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <span>
#include <string_view>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -64,7 +64,7 @@ int main(int argc, const char **argv) {
auto *const mapOriginal = begin;
const auto sizeOriginal = size;
using StringView = std::span<const uint8_t>;
using StringView = std::basic_string_view<uint8_t>;
StringView write;
std::vector<StringView> reads;
@@ -78,9 +78,9 @@ int main(int argc, const char **argv) {
end = (uint8_t *)memchr(begin, '\n', size);
if (line.size() > 0 && line[0] == 'P') {
write = line.subspan(2, line.size());
write = line.substr(2, line.size());
} else if (line.size() > 0 && line[0] == 'L') {
reads.push_back(line.subspan(2, line.size()));
reads.push_back(line.substr(2, line.size()));
} else if (line.empty()) {
{
readRanges.resize(reads.size());

View File

@@ -23,97 +23,6 @@
#include "Internal.h"
#include "third_party/nadeau.h"
constexpr int kCacheLine = 64; // TODO mac m1 is 128
template <class T> struct TxQueue {
explicit TxQueue(int lgSlotCount)
: slotCount(1 << lgSlotCount), slotCountMask(slotCount - 1),
slots(new T[slotCount]) {
// Otherwise we can't tell the difference between full and empty.
assert(!(slotCountMask & 0x80000000));
}
/// Call from producer thread, after ensuring consumer is no longer accessing
/// it somehow
~TxQueue() { delete[] slots; }
/// Must be called from the producer thread
void push(T t) {
if (wouldBlock()) {
// Wait for pops to change and try again
consumer.pops.wait(producer.lastPopRead, std::memory_order_relaxed);
producer.lastPopRead = consumer.pops.load(std::memory_order_acquire);
}
slots[producer.pushesNonAtomic++ & slotCountMask] = std::move(t);
// seq_cst so that the notify can't be ordered before the store
producer.pushes.store(producer.pushesNonAtomic, std::memory_order_seq_cst);
// We have to notify every time, since we don't know if this is the last
// push ever
producer.pushes.notify_one();
}
/// Must be called from the producer thread
uint32_t outstanding() {
return producer.pushesNonAtomic -
consumer.pops.load(std::memory_order_relaxed);
}
/// Returns true if a call to push might block. Must be called from the
/// producer thread.
bool wouldBlock() {
// See if we can determine that overflow won't happen entirely from state
// local to the producer
if (producer.pushesNonAtomic - producer.lastPopRead == slotCount - 1) {
// Re-read pops with memory order
producer.lastPopRead = consumer.pops.load(std::memory_order_acquire);
return producer.pushesNonAtomic - producer.lastPopRead == slotCount - 1;
}
return false;
}
/// Valid until the next pop, or until this queue is destroyed.
T *pop() {
// See if we can determine that there's an entry we can pop entirely from
// state local to the consumer
if (consumer.lastPushRead - consumer.popsNonAtomic == 0) {
// Re-read pushes with memory order and try again
consumer.lastPushRead = producer.pushes.load(std::memory_order_acquire);
if (consumer.lastPushRead - consumer.popsNonAtomic == 0) {
// Wait for pushes to change and try again
producer.pushes.wait(consumer.lastPushRead, std::memory_order_relaxed);
consumer.lastPushRead = producer.pushes.load(std::memory_order_acquire);
}
}
auto result = &slots[consumer.popsNonAtomic++ & slotCountMask];
// We only have to write pops with memory order if we've run out of items.
// We know that we'll eventually run out.
if (consumer.lastPushRead - consumer.popsNonAtomic == 0) {
// seq_cst so that the notify can't be ordered before the store
consumer.pops.store(consumer.popsNonAtomic, std::memory_order_seq_cst);
consumer.pops.notify_one();
}
return result;
}
private:
const uint32_t slotCount;
const uint32_t slotCountMask;
T *slots;
struct alignas(kCacheLine) ProducerState {
std::atomic<uint32_t> pushes{0};
uint32_t pushesNonAtomic{0};
uint32_t lastPopRead{0};
};
struct alignas(kCacheLine) ConsumerState {
std::atomic<uint32_t> pops{0};
uint32_t popsNonAtomic{0};
uint32_t lastPushRead{0};
};
ProducerState producer;
ConsumerState consumer;
};
std::atomic<int64_t> transactions;
int64_t safeUnaryMinus(int64_t x) {
@@ -157,69 +66,49 @@ template <class... Ts> std::string tupleKey(const Ts &...ts) {
constexpr int kTotalKeyRange = 1'000'000'000;
constexpr int kWindowSize = 1'000'000;
constexpr int kNumReadKeysPerTx = 10;
constexpr int kNumWriteKeysPerTx = 5;
constexpr int kNumKeys = 10;
struct Transaction {
std::vector<std::string> keys;
std::vector<weaselab::ConflictSet::ReadRange> reads;
std::vector<weaselab::ConflictSet::WriteRange> writes;
int64_t version;
int64_t oldestVersion;
Transaction() = default;
explicit Transaction(int64_t version)
: version(version), oldestVersion(version - kWindowSize) {
void workload(weaselab::ConflictSet *cs) {
int64_t version = kWindowSize;
for (;; transactions.fetch_add(1, std::memory_order_relaxed)) {
std::vector<int64_t> keyIndices;
for (int i = 0; i < std::max(kNumReadKeysPerTx, kNumWriteKeysPerTx); ++i) {
for (int i = 0; i < kNumKeys; ++i) {
keyIndices.push_back(rand() % kTotalKeyRange);
}
std::sort(keyIndices.begin(), keyIndices.end());
std::vector<std::string> keys;
constexpr std::string_view fullString =
"this is a string, where a prefix of it is used as an element of the "
"tuple forming the key";
for (int i = 0; i < int(keyIndices.size()); ++i) {
for (int i = 0; i < kNumKeys; ++i) {
keys.push_back(
tupleKey(0x100, keyIndices[i] / fullString.size(),
fullString.substr(0, keyIndices[i] % fullString.size())));
// printf("%s\n", printable(keys.back()).c_str());
}
for (int i = 0; i < kNumWriteKeysPerTx; ++i) {
std::vector<weaselab::ConflictSet::ReadRange> reads;
std::vector<weaselab::ConflictSet::WriteRange> writes;
std::vector<weaselab::ConflictSet::Result> results;
for (int i = 0; i < kNumKeys; ++i) {
writes.push_back({{(const uint8_t *)keys[i].data(), int(keys[i].size())},
{nullptr, 0}});
}
reads.push_back({{(const uint8_t *)keys[0].data(), int(keys[0].size())},
{(const uint8_t *)keys[1].data(), int(keys[1].size())},
version - kWindowSize});
static_assert(kNumReadKeysPerTx >= 3);
for (int i = 2; i < kNumReadKeysPerTx; ++i) {
reads.push_back({{(const uint8_t *)keys[i].data(), int(keys[i].size())},
{nullptr, 0},
version - kWindowSize});
}
results.resize(reads.size());
cs->check(reads.data(), results.data(), reads.size());
bool ok = true;
for (auto result : results) {
ok &= result == weaselab::ConflictSet::Commit;
}
cs->addWrites(writes.data(), ok ? writes.size() : 0, version);
cs->setOldestVersion(version - kWindowSize);
++version;
}
Transaction(Transaction &&) = default;
Transaction &operator=(Transaction &&) = default;
Transaction(Transaction const &) = delete;
Transaction const &operator=(Transaction const &) = delete;
};
struct Resolver {
void resolve(const weaselab::ConflictSet::ReadRange *reads, int readCount,
const weaselab::ConflictSet::WriteRange *writes, int writeCount,
int64_t newVersion, int64_t newOldestVersion) {
results.resize(readCount);
cs.check(reads, results.data(), readCount);
cs.addWrites(writes, writeCount, newVersion);
cs.setOldestVersion(newOldestVersion);
}
ConflictSet cs{0};
private:
std::vector<weaselab::ConflictSet::Result> results;
};
}
// Adapted from getaddrinfo man page
int getListenFd(const char *node, const char *service) {
@@ -362,8 +251,7 @@ int main(int argc, char **argv) {
{
int listenFd = getListenFd(argv[1], argv[2]);
Resolver resolver;
auto &cs = resolver.cs;
weaselab::ConflictSet cs{0};
weaselab::ConflictSet::MetricsV1 *metrics;
int metricsCount;
cs.getMetricsV1(&metrics, &metricsCount);
@@ -412,23 +300,7 @@ int main(int argc, char **argv) {
}
#endif
TxQueue<std::unique_ptr<Transaction>> queue{10};
auto workloadThread = std::thread{[&]() {
for (int64_t version = kWindowSize;;
++version, transactions.fetch_add(1, std::memory_order_relaxed)) {
auto tx = std::make_unique<Transaction>(version);
queue.push(std::move(tx));
}
}};
auto resolverThread = std::thread{[&]() {
for (;;) {
auto tx = queue.pop()->get();
resolver.resolve(tx->reads.data(), tx->reads.size(), tx->writes.data(),
tx->writes.size(), tx->version, tx->oldestVersion);
}
}};
auto w = std::thread{workload, &cs};
for (;;) {
struct sockaddr_storage peer_addr = {};

View File

@@ -796,6 +796,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
int temp[stripeSize];
int stripes = (stringCount + stripeSize - 1) / stripeSize;
StringRef values[stripeSize];
int64_t writeVersions[stripeSize / 2];
int ss = stringCount - (stripes - 1) * stripeSize;
int64_t entryDelta = 0;
for (int s = stripes - 1; s >= 0; s--) {

View File

@@ -1,4 +1,3 @@
___chkstk_darwin
___stack_chk_fail
___stack_chk_guard
__tlv_bootstrap
@@ -6,7 +5,6 @@ _abort
_bzero
_free
_malloc
_memcmp
_memcpy
_memmove
dyld_stub_binder

View File

@@ -8,7 +8,7 @@ SRC_DIR="${0%/*}"
BUILD_ARM="$(mktemp -d -t conflict-set-arm)"
BUILD_X86="$(mktemp -d -t conflict-set-x86)"
cmake_args=(-DCMAKE_CXX_FLAGS=-DNVALGRIND -DCPACK_PACKAGING_INSTALL_PREFIX=/usr/local -DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++)
cmake_args=(-DCMAKE_CXX_FLAGS=-DNVALGRIND -DCPACK_PACKAGING_INSTALL_PREFIX=/usr/local)
cmake -S"$SRC_DIR" -B"$BUILD_ARM" -DCMAKE_OSX_ARCHITECTURES=arm64 "${cmake_args[@]}"
cmake --build "$BUILD_ARM" --target conflict-set --target conflict-set-static

View File

@@ -1,4 +1,3 @@
import struct
from conflict_set import *
@@ -165,16 +164,6 @@ def test_fixup_256():
cs.check(read(0, bytes([1]), bytes([2])))
def test_large_removal_buffer():
with DebugConflictSet() as cs:
for i in range(1000):
# create extra gc work
for j in range(100):
cs.addWrites(1000 + i)
cs.addWrites(1000 + i, write(struct.pack(">l", i) + bytes([0] * 100000)))
cs.setOldestVersion(i)
if __name__ == "__main__":
# budget "pytest" for ctest integration without pulling in a dependency. You can of course still use pytest in local development.
import argparse