Compare commits
49 Commits
v0.0.12
...
tagged-poi
Author | SHA1 | Date | |
---|---|---|---|
af1e2299de | |||
230e96063d | |||
f41a62471b | |||
d8f85dedc4 | |||
656939560b | |||
5580f9b71d | |||
628d16b7e6 | |||
d9e4a7d1b6 | |||
52201fa4c7 | |||
0814822d82 | |||
41df2398e8 | |||
84c4d0fcba | |||
6241533dfb | |||
0abf6a1ecf | |||
867136ff1b | |||
4b8f7320d3 | |||
6628092384 | |||
a0a4f1afea | |||
ca479c03ce | |||
0a2e133ab9 | |||
b0b31419b0 | |||
5c0cc1edf5 | |||
de47aa53b0 | |||
56893f9702 | |||
e2234be10f | |||
ce853680f2 | |||
5c39c1d64f | |||
55b73c8ddb | |||
b9503f8258 | |||
c4c4531bd3 | |||
2037d37c66 | |||
6fe6a244af | |||
8a4b370e2a | |||
394f09f9fb | |||
5e06a30357 | |||
cb6e4292f2 | |||
154a48ded0 | |||
c11b4714b5 | |||
bc13094406 | |||
c9d742b696 | |||
795ae7cb01 | |||
849e2d3e5c | |||
1560037680 | |||
764c31bbc8 | |||
ee3361952a | |||
8a04e57353 | |||
7f86fdee66 | |||
442755d0a6 | |||
e15b3bb137 |
@@ -7,7 +7,6 @@
|
||||
void showMemory(const ConflictSet &cs);
|
||||
#endif
|
||||
|
||||
#define ANKERL_NANOBENCH_IMPLEMENT
|
||||
#include "third_party/nanobench.h"
|
||||
|
||||
constexpr int kNumKeys = 1000000;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(
|
||||
conflict-set
|
||||
VERSION 0.0.12
|
||||
VERSION 0.0.14
|
||||
DESCRIPTION
|
||||
"A data structure for optimistic concurrency control on ranges of bitwise-lexicographically-ordered keys."
|
||||
HOMEPAGE_URL "https://git.weaselab.dev/weaselab/conflict-set"
|
||||
@@ -72,12 +72,6 @@ else()
|
||||
add_link_options(-Wl,--gc-sections)
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
# https://github.com/emscripten-core/emscripten/issues/15377#issuecomment-1285167486
|
||||
add_link_options(-lnodefs.js -lnoderawfs.js)
|
||||
add_link_options(-s ALLOW_MEMORY_GROWTH)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SIMD_FALLBACK)
|
||||
cmake_push_check_state()
|
||||
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
|
||||
@@ -144,6 +138,8 @@ include(CTest)
|
||||
# disable tests if this is being used through e.g. FetchContent
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
|
||||
add_library(nanobench ${CMAKE_CURRENT_SOURCE_DIR}/nanobench.cpp)
|
||||
|
||||
set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG)
|
||||
|
||||
# corpus tests, which are tests curated by libfuzzer. The goal is to get broad
|
||||
@@ -191,6 +187,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
target_include_directories(conflict_set_main
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_compile_definitions(conflict_set_main PRIVATE ENABLE_MAIN)
|
||||
target_link_libraries(conflict_set_main PRIVATE nanobench)
|
||||
|
||||
if(NOT APPLE)
|
||||
# libfuzzer target, to generate/manage corpus
|
||||
@@ -251,6 +248,19 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
add_test(NAME conflict_set_blackbox_${hash} COMMAND driver ${TEST})
|
||||
endforeach()
|
||||
|
||||
find_program(VALGRIND_EXE valgrind)
|
||||
if(VALGRIND_EXE AND NOT CMAKE_CROSSCOMPILING)
|
||||
list(LENGTH CORPUS_TESTS len)
|
||||
math(EXPR last "${len} - 1")
|
||||
set(partition_size 100)
|
||||
foreach(i RANGE 0 ${last} ${partition_size})
|
||||
list(SUBLIST CORPUS_TESTS ${i} ${partition_size} partition)
|
||||
add_test(NAME conflict_set_blackbox_valgrind_${i}
|
||||
COMMAND ${VALGRIND_EXE} --error-exitcode=99 --
|
||||
$<TARGET_FILE:driver> ${partition})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# scripted tests. Written manually to fill in anything libfuzzer couldn't
|
||||
# find.
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
@@ -271,19 +281,14 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_conflict_set.py test ${TEST}
|
||||
--build-dir ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
find_program(VALGRIND_EXE valgrind)
|
||||
if(VALGRIND_EXE AND NOT CMAKE_CROSSCOMPILING)
|
||||
list(LENGTH CORPUS_TESTS len)
|
||||
math(EXPR last "${len} - 1")
|
||||
set(partition_size 100)
|
||||
foreach(i RANGE 0 ${last} ${partition_size})
|
||||
list(SUBLIST CORPUS_TESTS ${i} ${partition_size} partition)
|
||||
add_test(NAME conflict_set_blackbox_valgrind_${i}
|
||||
COMMAND ${VALGRIND_EXE} --error-exitcode=99 --
|
||||
$<TARGET_FILE:driver> ${partition})
|
||||
if(VALGRIND_EXE AND NOT CMAKE_CROSSCOMPILING)
|
||||
add_test(
|
||||
NAME script_test_${TEST}_valgrind
|
||||
COMMAND
|
||||
${VALGRIND_EXE} ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test_conflict_set.py test ${TEST}
|
||||
--build-dir ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
@@ -336,7 +341,7 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
|
||||
# bench
|
||||
add_executable(conflict_set_bench Bench.cpp)
|
||||
target_link_libraries(conflict_set_bench PRIVATE ${PROJECT_NAME})
|
||||
target_link_libraries(conflict_set_bench PRIVATE ${PROJECT_NAME} nanobench)
|
||||
set_target_properties(conflict_set_bench PROPERTIES SKIP_BUILD_RPATH ON)
|
||||
add_executable(real_data_bench RealDataBench.cpp)
|
||||
target_link_libraries(real_data_bench PRIVATE ${PROJECT_NAME})
|
||||
@@ -351,6 +356,14 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
||||
add_executable(server_bench ServerBench.cpp)
|
||||
target_link_libraries(server_bench PRIVATE ${PROJECT_NAME})
|
||||
set_target_properties(server_bench PROPERTIES SKIP_BUILD_RPATH ON)
|
||||
|
||||
add_executable(interleaving_test InterleavingTest.cpp)
|
||||
# work around lack of musttail for gcc
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_options(interleaving_test PRIVATE -Og
|
||||
-foptimize-sibling-calls)
|
||||
endif()
|
||||
target_link_libraries(interleaving_test PRIVATE nanobench)
|
||||
endif()
|
||||
|
||||
# packaging
|
||||
|
805
ConflictSet.cpp
805
ConflictSet.cpp
File diff suppressed because it is too large
Load Diff
256
InterleavingTest.cpp
Normal file
256
InterleavingTest.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
#include <alloca.h>
|
||||
#include <cassert>
|
||||
#ifdef __x86_64__
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#include "third_party/nanobench.h"
|
||||
|
||||
struct Job {
|
||||
int *input;
|
||||
// Returned void* is a function pointer to the next continuation. We have to
|
||||
// use void* because otherwise the type would be recursive.
|
||||
typedef void *(*continuation)(Job *);
|
||||
continuation next;
|
||||
};
|
||||
|
||||
void *stepJob(Job *j) {
|
||||
auto done = --(*j->input) == 0;
|
||||
#ifdef __x86_64__
|
||||
_mm_clflush(j->input);
|
||||
#endif
|
||||
return done ? nullptr : (void *)stepJob;
|
||||
}
|
||||
|
||||
void sequential(Job **jobs, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
do {
|
||||
jobs[i]->next = (Job::continuation)jobs[i]->next(jobs[i]);
|
||||
} while (jobs[i]->next);
|
||||
}
|
||||
}
|
||||
|
||||
void sequentialNoFuncPtr(Job **jobs, int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
while (stepJob(jobs[i]))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void interleaveSwapping(Job **jobs, int remaining) {
|
||||
int current = 0;
|
||||
while (remaining > 0) {
|
||||
auto next = (Job::continuation)jobs[current]->next(jobs[current]);
|
||||
jobs[current]->next = next;
|
||||
if (next == nullptr) {
|
||||
jobs[current] = jobs[remaining - 1];
|
||||
--remaining;
|
||||
} else {
|
||||
++current;
|
||||
}
|
||||
if (current == remaining) {
|
||||
current = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void interleaveBoundedCyclicList(Job **jobs, int count) {
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr int kConcurrent = 32;
|
||||
Job *inProgress[kConcurrent];
|
||||
int nextJob[kConcurrent];
|
||||
|
||||
int started = std::min(kConcurrent, count);
|
||||
for (int i = 0; i < started; i++) {
|
||||
inProgress[i] = jobs[i];
|
||||
nextJob[i] = i + 1;
|
||||
}
|
||||
nextJob[started - 1] = 0;
|
||||
|
||||
int prevJob = started - 1;
|
||||
int job = 0;
|
||||
for (;;) {
|
||||
auto next = (Job::continuation)inProgress[job]->next(inProgress[job]);
|
||||
inProgress[job]->next = next;
|
||||
if (next == nullptr) {
|
||||
if (started == count) {
|
||||
if (prevJob == job)
|
||||
break;
|
||||
nextJob[prevJob] = nextJob[job];
|
||||
job = prevJob;
|
||||
} else {
|
||||
int temp = started++;
|
||||
inProgress[job] = jobs[temp];
|
||||
}
|
||||
}
|
||||
prevJob = job;
|
||||
job = nextJob[job];
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __has_attribute
|
||||
#define __has_attribute(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_attribute(musttail)
|
||||
#define MUSTTAIL __attribute__((musttail))
|
||||
#else
|
||||
#define MUSTTAIL
|
||||
#endif
|
||||
|
||||
struct Context {
|
||||
constexpr static int kConcurrent = 32;
|
||||
Job **jobs;
|
||||
Job *inProgress[kConcurrent];
|
||||
void (*continuation[kConcurrent])(Context *, int64_t prevJob, int64_t job,
|
||||
int64_t started, int64_t count);
|
||||
int nextJob[kConcurrent];
|
||||
};
|
||||
|
||||
void keepGoing(Context *context, int64_t prevJob, int64_t job, int64_t started,
|
||||
int64_t count) {
|
||||
prevJob = job;
|
||||
job = context->nextJob[job];
|
||||
MUSTTAIL return context->continuation[job](context, prevJob, job, started,
|
||||
count);
|
||||
}
|
||||
|
||||
void stepJobTailCall(Context *context, int64_t prevJob, int64_t job,
|
||||
int64_t started, int64_t count);
|
||||
|
||||
void complete(Context *context, int64_t prevJob, int64_t job, int64_t started,
|
||||
int64_t count) {
|
||||
if (started == count) {
|
||||
if (prevJob == job) {
|
||||
return;
|
||||
}
|
||||
context->nextJob[prevJob] = context->nextJob[job];
|
||||
job = prevJob;
|
||||
} else {
|
||||
context->inProgress[job] = context->jobs[started++];
|
||||
context->continuation[job] = stepJobTailCall;
|
||||
}
|
||||
prevJob = job;
|
||||
job = context->nextJob[job];
|
||||
MUSTTAIL return context->continuation[job](context, prevJob, job, started,
|
||||
count);
|
||||
}
|
||||
|
||||
void stepJobTailCall(Context *context, int64_t prevJob, int64_t job,
|
||||
int64_t started, int64_t count) {
|
||||
auto *j = context->inProgress[job];
|
||||
auto done = --(*j->input) == 0;
|
||||
#ifdef __x86_64__
|
||||
_mm_clflush(j->input);
|
||||
#endif
|
||||
if (done) {
|
||||
MUSTTAIL return complete(context, prevJob, job, started, count);
|
||||
} else {
|
||||
context->continuation[job] = stepJobTailCall;
|
||||
MUSTTAIL return keepGoing(context, prevJob, job, started, count);
|
||||
}
|
||||
}
|
||||
|
||||
void useTailCalls(Job **jobs, int count) {
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
Context context;
|
||||
context.jobs = jobs;
|
||||
int64_t started = std::min(Context::kConcurrent, count);
|
||||
for (int i = 0; i < started; i++) {
|
||||
context.inProgress[i] = jobs[i];
|
||||
context.nextJob[i] = i + 1;
|
||||
context.continuation[i] = stepJobTailCall;
|
||||
}
|
||||
context.nextJob[started - 1] = 0;
|
||||
int prevJob = started - 1;
|
||||
int job = 0;
|
||||
return context.continuation[job](&context, prevJob, job, started, count);
|
||||
}
|
||||
|
||||
void interleaveCyclicList(Job **jobs, int count) {
|
||||
auto *nextJob = (int *)alloca(sizeof(int) * count);
|
||||
|
||||
for (int i = 0; i < count - 1; ++i) {
|
||||
nextJob[i] = i + 1;
|
||||
}
|
||||
nextJob[count - 1] = 0;
|
||||
|
||||
int prevJob = count - 1;
|
||||
int job = 0;
|
||||
for (;;) {
|
||||
auto next = (Job::continuation)jobs[job]->next(jobs[job]);
|
||||
jobs[job]->next = next;
|
||||
if (next == nullptr) {
|
||||
if (prevJob == job)
|
||||
break;
|
||||
nextJob[prevJob] = nextJob[job];
|
||||
job = prevJob;
|
||||
}
|
||||
prevJob = job;
|
||||
job = nextJob[job];
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
ankerl::nanobench::Bench bench;
|
||||
|
||||
constexpr int kNumJobs = 10000;
|
||||
bench.relative(true);
|
||||
|
||||
Job jobs[kNumJobs];
|
||||
Job jobsCopy[kNumJobs];
|
||||
int iters = 0;
|
||||
int originalInput[kNumJobs];
|
||||
for (int i = 0; i < kNumJobs; ++i) {
|
||||
originalInput[i] = rand() % 5 + 3;
|
||||
jobs[i].input = new int{originalInput[i]};
|
||||
jobs[i].next = stepJob;
|
||||
iters += *jobs[i].input;
|
||||
}
|
||||
bench.batch(iters);
|
||||
|
||||
for (auto [scheduler, name] :
|
||||
{std::make_pair(sequentialNoFuncPtr, "sequentialNoFuncPtr"),
|
||||
std::make_pair(sequential, "sequential"),
|
||||
std::make_pair(useTailCalls, "useTailCalls"),
|
||||
std::make_pair(interleaveSwapping, "interleavingSwapping"),
|
||||
std::make_pair(interleaveBoundedCyclicList,
|
||||
"interleaveBoundedCyclicList"),
|
||||
std::make_pair(interleaveCyclicList, "interleaveCyclicList")}) {
|
||||
for (int i = 0; i < kNumJobs; ++i) {
|
||||
*jobs[i].input = originalInput[i];
|
||||
}
|
||||
memcpy(jobsCopy, jobs, sizeof(jobs));
|
||||
Job *ps[kNumJobs];
|
||||
for (int i = 0; i < kNumJobs; ++i) {
|
||||
ps[i] = jobsCopy + i;
|
||||
}
|
||||
scheduler(ps, kNumJobs);
|
||||
for (int i = 0; i < kNumJobs; ++i) {
|
||||
if (*jobsCopy[i].input != 0) {
|
||||
fprintf(stderr, "%s failed\n", name);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bench.run(name, [&]() {
|
||||
for (int i = 0; i < kNumJobs; ++i) {
|
||||
*jobs[i].input = originalInput[i];
|
||||
}
|
||||
memcpy(jobsCopy, jobs, sizeof(jobs));
|
||||
Job *ps[kNumJobs];
|
||||
for (int i = 0; i < kNumJobs; ++i) {
|
||||
ps[i] = jobsCopy + i;
|
||||
}
|
||||
scheduler(ps, kNumJobs);
|
||||
});
|
||||
}
|
||||
for (int i = 0; i < kNumJobs; ++i) {
|
||||
delete jobs[i].input;
|
||||
}
|
||||
}
|
@@ -20,7 +20,6 @@ using namespace weaselab;
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <callgrind.h>
|
||||
|
||||
|
13
Jenkinsfile
vendored
13
Jenkinsfile
vendored
@@ -48,6 +48,17 @@ pipeline {
|
||||
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') {
|
||||
agent {
|
||||
dockerfile {
|
||||
@@ -118,7 +129,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
filter_args = "-f ConflictSet.cpp -f LongestCommonPrefix.h"
|
||||
filter_args = "-f ConflictSet.cpp -f LongestCommonPrefix.h -f Metrics.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")
|
||||
sh """
|
||||
|
64
Metrics.h
Normal file
64
Metrics.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "ConflictSet.h"
|
||||
#include "Internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <atomic>
|
||||
#include <tuple>
|
||||
|
||||
struct Metric {
|
||||
Metric *prev;
|
||||
const char *name;
|
||||
const char *help;
|
||||
weaselab::ConflictSet::MetricsV1::Type type;
|
||||
std::atomic<int64_t> value;
|
||||
|
||||
protected:
|
||||
Metric(Metric *&metricList, int &metricsCount, const char *name,
|
||||
const char *help, weaselab::ConflictSet::MetricsV1::Type type)
|
||||
: prev(std::exchange(metricList, this)), name(name), help(help),
|
||||
type(type), value(0) {
|
||||
++metricsCount;
|
||||
}
|
||||
};
|
||||
|
||||
struct Gauge : private Metric {
|
||||
Gauge(Metric *&metricList, int &metricsCount, const char *name,
|
||||
const char *help)
|
||||
: Metric(metricList, metricsCount, name, help,
|
||||
weaselab::ConflictSet::MetricsV1::Gauge) {}
|
||||
|
||||
void set(int64_t value) {
|
||||
this->value.store(value, std::memory_order_relaxed);
|
||||
}
|
||||
};
|
||||
|
||||
struct Counter : private Metric {
|
||||
Counter(Metric *&metricList, int &metricsCount, const char *name,
|
||||
const char *help)
|
||||
: Metric(metricList, metricsCount, name, help,
|
||||
weaselab::ConflictSet::MetricsV1::Counter) {}
|
||||
// Expensive. Accumulate locally and then call add instead of repeatedly
|
||||
// calling add.
|
||||
void add(int64_t value) {
|
||||
assert(value >= 0);
|
||||
static_assert(std::atomic<int64_t>::is_always_lock_free);
|
||||
this->value.fetch_add(value, std::memory_order_relaxed);
|
||||
}
|
||||
};
|
||||
|
||||
inline weaselab::ConflictSet::MetricsV1 *initMetrics(Metric *metricsList,
|
||||
int metricsCount) {
|
||||
weaselab::ConflictSet::MetricsV1 *metrics =
|
||||
(weaselab::ConflictSet::MetricsV1 *)safe_malloc(metricsCount *
|
||||
sizeof(metrics[0]));
|
||||
for (auto [i, m] = std::make_tuple(metricsCount - 1, metricsList); i >= 0;
|
||||
--i, m = m->prev) {
|
||||
metrics[i].name = m->name;
|
||||
metrics[i].help = m->help;
|
||||
metrics[i].p = m;
|
||||
metrics[i].type = m->type;
|
||||
}
|
||||
return metrics;
|
||||
}
|
18
README.md
18
README.md
@@ -24,15 +24,15 @@ 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
|
||||
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
||||
| 11.18 | 89,455,125.34 | 0.6% | 185.37 | 57.08 | 3.248 | 41.51 | 0.4% | 0.01 | `point reads`
|
||||
| 14.53 | 68,800,688.89 | 0.4% | 282.41 | 74.80 | 3.776 | 55.06 | 0.3% | 0.01 | `prefix reads`
|
||||
| 36.54 | 27,367,576.87 | 0.2% | 798.06 | 188.90 | 4.225 | 141.69 | 0.2% | 0.01 | `range reads`
|
||||
| 16.69 | 59,912,106.02 | 0.6% | 314.57 | 86.29 | 3.645 | 39.84 | 0.4% | 0.01 | `point writes`
|
||||
| 30.09 | 33,235,744.07 | 0.5% | 591.33 | 155.92 | 3.793 | 82.69 | 0.2% | 0.01 | `prefix writes`
|
||||
| 35.77 | 27,956,388.03 | 1.4% | 682.25 | 187.63 | 3.636 | 96.12 | 0.1% | 0.01 | `range writes`
|
||||
| 74.04 | 13,505,408.41 | 2.7% | 1,448.95 | 392.10 | 3.695 | 260.53 | 0.1% | 0.01 | `monotonic increasing point writes`
|
||||
| 330,984.50 | 3,021.29 | 1.9% | 3,994,153.50 | 1,667,309.00 | 2.396 | 806,019.50 | 0.0% | 0.01 | `worst case for radix tree`
|
||||
| 92.46 | 10,814,961.65 | 0.5% | 1,800.00 | 463.41 | 3.884 | 297.00 | 0.0% | 0.01 | `create and destroy`
|
||||
| 12.88 | 77,653,350.77 | 0.5% | 185.37 | 64.45 | 2.876 | 41.51 | 0.4% | 0.01 | `point reads`
|
||||
| 14.67 | 68,179,354.49 | 0.1% | 271.44 | 73.40 | 3.698 | 53.70 | 0.3% | 0.01 | `prefix reads`
|
||||
| 34.84 | 28,701,444.36 | 0.3% | 715.74 | 175.27 | 4.084 | 127.30 | 0.2% | 0.01 | `range reads`
|
||||
| 17.12 | 58,422,988.28 | 0.2% | 314.30 | 86.11 | 3.650 | 39.82 | 0.4% | 0.01 | `point writes`
|
||||
| 31.42 | 31,830,804.65 | 0.1% | 591.06 | 158.07 | 3.739 | 82.67 | 0.2% | 0.01 | `prefix writes`
|
||||
| 37.37 | 26,759,432.70 | 2.2% | 681.98 | 188.95 | 3.609 | 96.10 | 0.1% | 0.01 | `range writes`
|
||||
| 76.72 | 13,035,140.63 | 2.3% | 1,421.28 | 387.17 | 3.671 | 257.76 | 0.1% | 0.01 | `monotonic increasing point writes`
|
||||
| 297,452.00 | 3,361.89 | 0.9% | 3,508,083.00 | 1,500,834.67 | 2.337 | 727,525.33 | 0.1% | 0.01 | `worst case for radix tree`
|
||||
| 87.70 | 11,402,490.60 | 1.0% | 1,795.00 | 442.09 | 4.060 | 297.00 | 0.0% | 0.01 | `create and destroy`
|
||||
|
||||
# "Real data" test
|
||||
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
std::atomic<int64_t> transactions;
|
||||
|
||||
constexpr int kBaseSearchDepth = 32;
|
||||
constexpr int kBaseSearchDepth = 115;
|
||||
constexpr int kWindowSize = 10000000;
|
||||
|
||||
std::string numToKey(int64_t num) {
|
||||
|
176
SkipList.cpp
176
SkipList.cpp
@@ -22,9 +22,11 @@
|
||||
|
||||
#include "ConflictSet.h"
|
||||
#include "Internal.h"
|
||||
#include "Metrics.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) {
|
||||
auto result =
|
||||
@@ -115,15 +117,6 @@ bool operator==(const KeyInfo &lhs, const KeyInfo &rhs) {
|
||||
return !(lhs < rhs || rhs < lhs);
|
||||
}
|
||||
|
||||
void swapSort(std::vector<KeyInfo> &points, int a, int b) {
|
||||
if (points[b] < points[a]) {
|
||||
KeyInfo temp;
|
||||
temp = points[a];
|
||||
points[a] = points[b];
|
||||
points[b] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
struct SortTask {
|
||||
int begin;
|
||||
int size;
|
||||
@@ -183,13 +176,6 @@ void sortPoints(std::vector<KeyInfo> &points) {
|
||||
}
|
||||
}
|
||||
|
||||
static thread_local uint32_t g_seed = 0;
|
||||
|
||||
static inline int skfastrand() {
|
||||
g_seed = g_seed * 1664525L + 1013904223L;
|
||||
return g_seed;
|
||||
}
|
||||
|
||||
static int compare(const StringRef &a, const StringRef &b) {
|
||||
int c = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
|
||||
if (c < 0)
|
||||
@@ -215,20 +201,24 @@ struct ReadConflictRange {
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr int MaxLevels = 26;
|
||||
|
||||
struct RandomLevel {
|
||||
explicit RandomLevel(uint32_t seed) : seed(seed) {}
|
||||
|
||||
int next() {
|
||||
int result = __builtin_clz(seed | (uint32_t(-1) >> (MaxLevels - 1)));
|
||||
seed = seed * 1664525L + 1013904223L;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t seed;
|
||||
};
|
||||
|
||||
class SkipList {
|
||||
private:
|
||||
static constexpr int MaxLevels = 26;
|
||||
|
||||
int randomLevel() const {
|
||||
uint32_t i = uint32_t(skfastrand()) >> (32 - (MaxLevels - 1));
|
||||
int level = 0;
|
||||
while (i & 1) {
|
||||
i >>= 1;
|
||||
level++;
|
||||
}
|
||||
assert(level < MaxLevels);
|
||||
return level;
|
||||
}
|
||||
RandomLevel randomLevel{0};
|
||||
|
||||
// Represent a node in the SkipList. The node has multiple (i.e., level)
|
||||
// pointers to other nodes, and keeps a record of the max versions for each
|
||||
@@ -426,27 +416,33 @@ public:
|
||||
}
|
||||
void swap(SkipList &other) { std::swap(header, other.header); }
|
||||
|
||||
void addConflictRanges(const Finger *fingers, int rangeCount,
|
||||
Version version) {
|
||||
// Returns the change in the number of entries
|
||||
int64_t addConflictRanges(const Finger *fingers, int rangeCount,
|
||||
Version version) {
|
||||
int64_t result = rangeCount;
|
||||
for (int r = rangeCount - 1; r >= 0; r--) {
|
||||
const Finger &startF = fingers[r * 2];
|
||||
const Finger &endF = fingers[r * 2 + 1];
|
||||
|
||||
if (endF.found() == nullptr)
|
||||
if (endF.found() == nullptr) {
|
||||
++result;
|
||||
insert(endF, endF.finger[0]->getMaxVersion(0));
|
||||
}
|
||||
|
||||
remove(startF, endF);
|
||||
result -= remove(startF, endF);
|
||||
insert(startF, version);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void detectConflicts(ReadConflictRange *ranges, int count,
|
||||
ConflictSet::Result *transactionConflictStatus) const {
|
||||
// Return number of iterations of main loop
|
||||
int detectConflicts(ReadConflictRange *ranges, int count,
|
||||
ConflictSet::Result *transactionConflictStatus) const {
|
||||
const int M = 16;
|
||||
int nextJob[M];
|
||||
CheckMax inProgress[M];
|
||||
if (!count)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
int started = std::min(M, count);
|
||||
for (int i = 0; i < started; i++) {
|
||||
@@ -457,8 +453,9 @@ public:
|
||||
|
||||
int prevJob = started - 1;
|
||||
int job = 0;
|
||||
int iters = 0;
|
||||
// vtune: 340 parts
|
||||
while (true) {
|
||||
for (;; ++iters) {
|
||||
if (inProgress[job].advance()) {
|
||||
if (started == count) {
|
||||
if (prevJob == job)
|
||||
@@ -474,6 +471,7 @@ public:
|
||||
prevJob = job;
|
||||
job = nextJob[job];
|
||||
}
|
||||
return iters;
|
||||
}
|
||||
|
||||
void find(const StringRef *values, Finger *results, int *temp, int count) {
|
||||
@@ -567,9 +565,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void remove(const Finger &start, const Finger &end) {
|
||||
// Returns the number of entries removed
|
||||
int64_t remove(const Finger &start, const Finger &end) {
|
||||
if (start.finger[0] == end.finger[0])
|
||||
return;
|
||||
return 0;
|
||||
|
||||
Node *x = start.finger[0]->getNext(0);
|
||||
|
||||
@@ -578,17 +577,20 @@ private:
|
||||
if (start.finger[i] != end.finger[i])
|
||||
start.finger[i]->setNext(i, end.finger[i]->getNext(i));
|
||||
|
||||
int64_t result = 0;
|
||||
while (true) {
|
||||
Node *next = x->getNext(0);
|
||||
x->destroy();
|
||||
++result;
|
||||
if (x == end.finger[0])
|
||||
break;
|
||||
x = next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void insert(const Finger &f, Version version) {
|
||||
int level = randomLevel();
|
||||
int level = randomLevel.next();
|
||||
// std::cout << std::string((const char*)value,length) << " level: " <<
|
||||
// level << std::endl;
|
||||
Node *x = Node::create(f.value, level);
|
||||
@@ -704,17 +706,27 @@ private:
|
||||
};
|
||||
};
|
||||
|
||||
struct SkipListConflictSet {};
|
||||
struct ReadContext {
|
||||
int64_t commits_accum = 0;
|
||||
int64_t conflicts_accum = 0;
|
||||
int64_t too_olds_accum = 0;
|
||||
int64_t check_bytes_accum = 0;
|
||||
};
|
||||
|
||||
struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
Impl(int64_t oldestVersion)
|
||||
: oldestVersion(oldestVersion), newestVersion(oldestVersion),
|
||||
skipList(oldestVersion) {}
|
||||
skipList(oldestVersion) {
|
||||
metrics = initMetrics(metricsList, metricsCount);
|
||||
}
|
||||
~Impl() { safe_free(metrics, metricsCount * sizeof(metrics[0])); }
|
||||
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
|
||||
int count) const {
|
||||
int count) {
|
||||
ReadContext tls;
|
||||
Arena arena;
|
||||
auto *ranges = new (arena) ReadConflictRange[count];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
tls.check_bytes_accum += reads[i].begin.len + reads[i].end.len;
|
||||
ranges[i].begin = {reads[i].begin.p, size_t(reads[i].begin.len)};
|
||||
ranges[i].end = reads[i].end.len > 0
|
||||
? StringRef{reads[i].end.p, size_t(reads[i].end.len)}
|
||||
@@ -722,13 +734,22 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
ranges[i].version = reads[i].readVersion;
|
||||
results[i] = ConflictSet::Commit;
|
||||
}
|
||||
skipList.detectConflicts(ranges, count, results);
|
||||
int iters = skipList.detectConflicts(ranges, count, results);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (reads[i].readVersion < oldestVersion ||
|
||||
reads[i].readVersion < newestVersion - 2e9) {
|
||||
results[i] = TooOld;
|
||||
}
|
||||
tls.commits_accum += results[i] == Commit;
|
||||
tls.conflicts_accum += results[i] == Conflict;
|
||||
tls.too_olds_accum += results[i] == TooOld;
|
||||
}
|
||||
range_read_iterations_total.add(iters);
|
||||
range_read_total.add(count);
|
||||
commits_total.add(tls.commits_accum);
|
||||
conflicts_total.add(tls.conflicts_accum);
|
||||
too_olds_total.add(tls.too_olds_accum);
|
||||
check_bytes_total.add(tls.check_bytes_accum);
|
||||
}
|
||||
|
||||
void addWrites(const ConflictSet::WriteRange *writes, int count,
|
||||
@@ -775,27 +796,33 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
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--) {
|
||||
for (int i = 0; i * 2 < ss; ++i) {
|
||||
const auto &w = combinedWriteConflictRanges[s * stripeSize / 2 + i];
|
||||
values[i * 2] = w.first;
|
||||
values[i * 2 + 1] = w.second;
|
||||
keyUpdates += 3;
|
||||
}
|
||||
skipList.find(values, fingers, temp, ss);
|
||||
skipList.addConflictRanges(fingers, ss / 2, writeVersion);
|
||||
entryDelta += skipList.addConflictRanges(fingers, ss / 2, writeVersion);
|
||||
ss = stripeSize;
|
||||
}
|
||||
|
||||
// Run gc at least 200% the rate we're inserting entries
|
||||
keyUpdates += std::max<int64_t>(entryDelta, 0) * 2;
|
||||
}
|
||||
|
||||
void setOldestVersion(int64_t oldestVersion) {
|
||||
// This isn't 100% accurate. It overcounts if you hit the end
|
||||
gc_iterations_total.add(keyUpdates);
|
||||
|
||||
assert(oldestVersion >= this->oldestVersion);
|
||||
this->oldestVersion = oldestVersion;
|
||||
SkipList::Finger finger;
|
||||
int temp;
|
||||
std::span<const uint8_t> key = removalKey;
|
||||
skipList.find(&key, &finger, &temp, 1);
|
||||
skipList.removeBefore(oldestVersion, finger, std::exchange(keyUpdates, 10));
|
||||
skipList.removeBefore(oldestVersion, finger, std::exchange(keyUpdates, 0));
|
||||
removalArena = Arena();
|
||||
removalKey = copyToArena(
|
||||
removalArena, {finger.getValue().data(), finger.getValue().size()});
|
||||
@@ -803,8 +830,56 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
|
||||
int64_t totalBytes = 0;
|
||||
|
||||
MetricsV1 *metrics;
|
||||
int metricsCount = 0;
|
||||
Metric *metricsList = nullptr;
|
||||
|
||||
#define GAUGE(name, help) \
|
||||
Gauge name { metricsList, metricsCount, #name, help }
|
||||
#define COUNTER(name, help) \
|
||||
Counter name { metricsList, metricsCount, #name, help }
|
||||
// ==================== METRICS DEFINITIONS ====================
|
||||
COUNTER(range_read_total, "Total number of range reads checked");
|
||||
COUNTER(range_read_iterations_total,
|
||||
"Total number of iterations of the main loops for range read checks");
|
||||
COUNTER(commits_total,
|
||||
"Total number of checks where the result is \"commit\"");
|
||||
COUNTER(conflicts_total,
|
||||
"Total number of checks where the result is \"conflict\"");
|
||||
COUNTER(too_olds_total,
|
||||
"Total number of checks where the result is \"too old\"");
|
||||
COUNTER(check_bytes_total, "Total number of key bytes checked");
|
||||
GAUGE(memory_bytes, "Total number of bytes in use");
|
||||
COUNTER(nodes_allocated_total,
|
||||
"The total number of physical tree nodes allocated");
|
||||
COUNTER(nodes_released_total,
|
||||
"The total number of physical tree nodes released");
|
||||
COUNTER(insert_iterations_total,
|
||||
"The total number of iterations of the main loop for insertion. "
|
||||
"Includes searches where the entry already existed, and so insertion "
|
||||
"did not take place");
|
||||
COUNTER(entries_inserted_total,
|
||||
"The total number of entries inserted in the tree");
|
||||
COUNTER(entries_erased_total,
|
||||
"The total number of entries erased from the tree");
|
||||
COUNTER(
|
||||
gc_iterations_total,
|
||||
"The total number of iterations of the main loop for garbage collection");
|
||||
COUNTER(write_bytes_total, "Total number of key bytes in calls to addWrites");
|
||||
GAUGE(oldest_version,
|
||||
"The lowest version that doesn't result in \"TooOld\" for checks");
|
||||
GAUGE(newest_version, "The version of the most recent call to addWrites");
|
||||
// ==================== END METRICS DEFINITIONS ====================
|
||||
#undef GAUGE
|
||||
#undef COUNTER
|
||||
|
||||
void getMetricsV1(MetricsV1 **metrics, int *count) {
|
||||
*metrics = this->metrics;
|
||||
*count = metricsCount;
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t keyUpdates = 10;
|
||||
int64_t keyUpdates = 0;
|
||||
Arena removalArena;
|
||||
std::span<const uint8_t> removalKey;
|
||||
int64_t oldestVersion;
|
||||
@@ -825,6 +900,7 @@ void internal_addWrites(ConflictSet::Impl *impl,
|
||||
mallocBytesDelta = 0;
|
||||
impl->addWrites(writes, count, writeVersion);
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
impl->memory_bytes.set(impl->totalBytes);
|
||||
#if SHOW_MEMORY
|
||||
if (impl->totalBytes != mallocBytes) {
|
||||
abort();
|
||||
@@ -836,6 +912,7 @@ void internal_setOldestVersion(ConflictSet::Impl *impl, int64_t oldestVersion) {
|
||||
mallocBytesDelta = 0;
|
||||
impl->setOldestVersion(oldestVersion);
|
||||
impl->totalBytes += mallocBytesDelta;
|
||||
impl->memory_bytes.set(impl->totalBytes);
|
||||
#if SHOW_MEMORY
|
||||
if (impl->totalBytes != mallocBytes) {
|
||||
abort();
|
||||
@@ -859,12 +936,11 @@ int64_t internal_getBytes(ConflictSet::Impl *impl) { return impl->totalBytes; }
|
||||
|
||||
void internal_getMetricsV1(ConflictSet::Impl *impl,
|
||||
ConflictSet::MetricsV1 **metrics, int *count) {
|
||||
*metrics = nullptr;
|
||||
*count = 0;
|
||||
return impl->getMetricsV1(metrics, count);
|
||||
}
|
||||
|
||||
double internal_getMetricValue(const ConflictSet::MetricsV1 *metric) {
|
||||
return 0;
|
||||
return ((Metric *)metric->p)->value.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void ConflictSet::check(const ReadRange *reads, Result *results,
|
||||
|
BIN
corpus/008e3be49d62c3e7fa3785b882bdb65ee4b68977
Normal file
BIN
corpus/008e3be49d62c3e7fa3785b882bdb65ee4b68977
Normal file
Binary file not shown.
BIN
corpus/0292e5991e94d8861e8240171e7ce2c0a9742616
Normal file
BIN
corpus/0292e5991e94d8861e8240171e7ce2c0a9742616
Normal file
Binary file not shown.
BIN
corpus/0390280ec499c5f687428e700028c230e8ce944e
Normal file
BIN
corpus/0390280ec499c5f687428e700028c230e8ce944e
Normal file
Binary file not shown.
BIN
corpus/05a9e20eac1e7efb9b40fa032c35f76f87622210
Normal file
BIN
corpus/05a9e20eac1e7efb9b40fa032c35f76f87622210
Normal file
Binary file not shown.
BIN
corpus/076952738748aac93fca3e1e59b104547e4177ba
Normal file
BIN
corpus/076952738748aac93fca3e1e59b104547e4177ba
Normal file
Binary file not shown.
BIN
corpus/0a0d13abb457f88bc0e9964f52ea5019ddb904db
Normal file
BIN
corpus/0a0d13abb457f88bc0e9964f52ea5019ddb904db
Normal file
Binary file not shown.
BIN
corpus/0b1ed19f50f707d5e805bcbed195bff0bcad8c7c
Normal file
BIN
corpus/0b1ed19f50f707d5e805bcbed195bff0bcad8c7c
Normal file
Binary file not shown.
BIN
corpus/0b287addaa1aa43c286023650cd407af888ea016
Normal file
BIN
corpus/0b287addaa1aa43c286023650cd407af888ea016
Normal file
Binary file not shown.
BIN
corpus/0b2bceb19aee5dd7b6d2fcc05a435c81116d06ef
Normal file
BIN
corpus/0b2bceb19aee5dd7b6d2fcc05a435c81116d06ef
Normal file
Binary file not shown.
BIN
corpus/10970b15ecff0b0564ef8dc31c30680e5e4a4421
Normal file
BIN
corpus/10970b15ecff0b0564ef8dc31c30680e5e4a4421
Normal file
Binary file not shown.
BIN
corpus/1357a36bfcab4e48cf165b984e1840f3e8c6ce51
Normal file
BIN
corpus/1357a36bfcab4e48cf165b984e1840f3e8c6ce51
Normal file
Binary file not shown.
BIN
corpus/13fc09a23701cb6c66e26480926f8fdfa9b0bbd4
Normal file
BIN
corpus/13fc09a23701cb6c66e26480926f8fdfa9b0bbd4
Normal file
Binary file not shown.
BIN
corpus/170a0ec4714b5ee34045037b38f038a8e3fa2035
Normal file
BIN
corpus/170a0ec4714b5ee34045037b38f038a8e3fa2035
Normal file
Binary file not shown.
BIN
corpus/175195f4753b812598e59f9d14742c1aeed67180
Normal file
BIN
corpus/175195f4753b812598e59f9d14742c1aeed67180
Normal file
Binary file not shown.
BIN
corpus/1863492b4bfa4e57a2dd04457f45dd1adbc1b43b
Normal file
BIN
corpus/1863492b4bfa4e57a2dd04457f45dd1adbc1b43b
Normal file
Binary file not shown.
BIN
corpus/198314d10d86adbfb9d14a0a48cb01fd050cdd50
Normal file
BIN
corpus/198314d10d86adbfb9d14a0a48cb01fd050cdd50
Normal file
Binary file not shown.
BIN
corpus/1b73191605897b8fb531d18ce6309d5bd5118268
Normal file
BIN
corpus/1b73191605897b8fb531d18ce6309d5bd5118268
Normal file
Binary file not shown.
BIN
corpus/1d73c395d1885ce584ddc66ebea3137a89222307
Normal file
BIN
corpus/1d73c395d1885ce584ddc66ebea3137a89222307
Normal file
Binary file not shown.
BIN
corpus/1f1a703161be463bc598349de981d56fecff1f7a
Normal file
BIN
corpus/1f1a703161be463bc598349de981d56fecff1f7a
Normal file
Binary file not shown.
BIN
corpus/2171f6a0942d0ad29e1e2f163c0193228ab83e37
Normal file
BIN
corpus/2171f6a0942d0ad29e1e2f163c0193228ab83e37
Normal file
Binary file not shown.
BIN
corpus/23098c203c4d176ab274847ed6131d1e72bb2f79
Normal file
BIN
corpus/23098c203c4d176ab274847ed6131d1e72bb2f79
Normal file
Binary file not shown.
BIN
corpus/23d4c4704607cea96775f90eec72ec444a53327e
Normal file
BIN
corpus/23d4c4704607cea96775f90eec72ec444a53327e
Normal file
Binary file not shown.
BIN
corpus/256d76a7b41e7ed6e7baca0a4968a872f670b40e
Normal file
BIN
corpus/256d76a7b41e7ed6e7baca0a4968a872f670b40e
Normal file
Binary file not shown.
BIN
corpus/26cb93458db8c96971c2dac90d1656309626057c
Normal file
BIN
corpus/26cb93458db8c96971c2dac90d1656309626057c
Normal file
Binary file not shown.
BIN
corpus/288d8bc1d39945470448074ce98e4cc92e95c4df
Normal file
BIN
corpus/288d8bc1d39945470448074ce98e4cc92e95c4df
Normal file
Binary file not shown.
BIN
corpus/290bc08207a6de4b9adceb42003d4aeb5758bfdd
Normal file
BIN
corpus/290bc08207a6de4b9adceb42003d4aeb5758bfdd
Normal file
Binary file not shown.
BIN
corpus/2b2a3848abb733ce26310bce956cc299144e2c37
Normal file
BIN
corpus/2b2a3848abb733ce26310bce956cc299144e2c37
Normal file
Binary file not shown.
BIN
corpus/2cbf5f3c9d7c4fe38f2da48096d37d29fa75eec6
Normal file
BIN
corpus/2cbf5f3c9d7c4fe38f2da48096d37d29fa75eec6
Normal file
Binary file not shown.
BIN
corpus/2d74492e45925f685ebcd3e3d1323504245daa2f
Normal file
BIN
corpus/2d74492e45925f685ebcd3e3d1323504245daa2f
Normal file
Binary file not shown.
BIN
corpus/2f850fa41006d53a3b4869295c319f077f585e27
Normal file
BIN
corpus/2f850fa41006d53a3b4869295c319f077f585e27
Normal file
Binary file not shown.
BIN
corpus/3246c5494cf81eb96a15a962352bf3f62cf44188
Normal file
BIN
corpus/3246c5494cf81eb96a15a962352bf3f62cf44188
Normal file
Binary file not shown.
BIN
corpus/32b1f5278c998e688bf7a44d89f54a2c183e75eb
Normal file
BIN
corpus/32b1f5278c998e688bf7a44d89f54a2c183e75eb
Normal file
Binary file not shown.
BIN
corpus/33cfb152724161924444fe07e0cdb07b8b8462fc
Normal file
BIN
corpus/33cfb152724161924444fe07e0cdb07b8b8462fc
Normal file
Binary file not shown.
BIN
corpus/3530208307bb7a980d56987edbf1783c72ca2444
Normal file
BIN
corpus/3530208307bb7a980d56987edbf1783c72ca2444
Normal file
Binary file not shown.
BIN
corpus/37636f0129daeb11db2665b746ec1d63650ddea7
Normal file
BIN
corpus/37636f0129daeb11db2665b746ec1d63650ddea7
Normal file
Binary file not shown.
BIN
corpus/3b6efa6b4581d3f75d307ecdd5aa53b4fa3fea90
Normal file
BIN
corpus/3b6efa6b4581d3f75d307ecdd5aa53b4fa3fea90
Normal file
Binary file not shown.
BIN
corpus/3db73b996b015cf7eb099e36a0c20488d2a3c3f2
Normal file
BIN
corpus/3db73b996b015cf7eb099e36a0c20488d2a3c3f2
Normal file
Binary file not shown.
BIN
corpus/3dd78f16a8656e4839afb2eb4cdc7a028f4d28b8
Normal file
BIN
corpus/3dd78f16a8656e4839afb2eb4cdc7a028f4d28b8
Normal file
Binary file not shown.
BIN
corpus/3e227dd4f09486eaafb4a0840dfe8c8b3487e7e7
Normal file
BIN
corpus/3e227dd4f09486eaafb4a0840dfe8c8b3487e7e7
Normal file
Binary file not shown.
BIN
corpus/3feb7520632cdb454178f4fa5b63a5665d739e1c
Normal file
BIN
corpus/3feb7520632cdb454178f4fa5b63a5665d739e1c
Normal file
Binary file not shown.
BIN
corpus/403cac13d939872be09b35ba73712a7026412ad2
Normal file
BIN
corpus/403cac13d939872be09b35ba73712a7026412ad2
Normal file
Binary file not shown.
BIN
corpus/4137466d9c418d90463f635ac6401ec69da598ab
Normal file
BIN
corpus/4137466d9c418d90463f635ac6401ec69da598ab
Normal file
Binary file not shown.
BIN
corpus/4206bbb85073ab30a5f04f17bcec0b6b09dec446
Normal file
BIN
corpus/4206bbb85073ab30a5f04f17bcec0b6b09dec446
Normal file
Binary file not shown.
BIN
corpus/43950334272a0d818f646b118439717c19a99837
Normal file
BIN
corpus/43950334272a0d818f646b118439717c19a99837
Normal file
Binary file not shown.
BIN
corpus/4920f8c7afdef94d228a5683c8d31cebf40c27a8
Normal file
BIN
corpus/4920f8c7afdef94d228a5683c8d31cebf40c27a8
Normal file
Binary file not shown.
BIN
corpus/4aee549dc867bd0fa32db38bd1680d66ef1a80e4
Normal file
BIN
corpus/4aee549dc867bd0fa32db38bd1680d66ef1a80e4
Normal file
Binary file not shown.
BIN
corpus/4b5566948ffa7391486512028b4c6198fd3db2ef
Normal file
BIN
corpus/4b5566948ffa7391486512028b4c6198fd3db2ef
Normal file
Binary file not shown.
BIN
corpus/4d1195f71091e5f9ceea90258f39bbe7a00b4a49
Normal file
BIN
corpus/4d1195f71091e5f9ceea90258f39bbe7a00b4a49
Normal file
Binary file not shown.
BIN
corpus/4e12dbd10635705a7230aa0f062e590264828cde
Normal file
BIN
corpus/4e12dbd10635705a7230aa0f062e590264828cde
Normal file
Binary file not shown.
BIN
corpus/4ee3990f6a97d901eaa69a32216a17f9f86e8c77
Normal file
BIN
corpus/4ee3990f6a97d901eaa69a32216a17f9f86e8c77
Normal file
Binary file not shown.
BIN
corpus/51e5cec7499e74815b4bef1a7998671053595961
Normal file
BIN
corpus/51e5cec7499e74815b4bef1a7998671053595961
Normal file
Binary file not shown.
BIN
corpus/54952d3ba4a1dca49238f941dee26d26edc46db2
Normal file
BIN
corpus/54952d3ba4a1dca49238f941dee26d26edc46db2
Normal file
Binary file not shown.
BIN
corpus/57e1c08766ffade2c8221997d16b5e0ad7ecc93c
Normal file
BIN
corpus/57e1c08766ffade2c8221997d16b5e0ad7ecc93c
Normal file
Binary file not shown.
BIN
corpus/5acdc011bd62a40c8e018a2621545bf4e005a903
Normal file
BIN
corpus/5acdc011bd62a40c8e018a2621545bf4e005a903
Normal file
Binary file not shown.
BIN
corpus/5ede0d70336f00fad64d4a617e5b34f53533a306
Normal file
BIN
corpus/5ede0d70336f00fad64d4a617e5b34f53533a306
Normal file
Binary file not shown.
BIN
corpus/63edba2479b48db7458149a7df2e2c224920877c
Normal file
BIN
corpus/63edba2479b48db7458149a7df2e2c224920877c
Normal file
Binary file not shown.
BIN
corpus/6769617662feb59ce9e326d3263cc75951e0a0bc
Normal file
BIN
corpus/6769617662feb59ce9e326d3263cc75951e0a0bc
Normal file
Binary file not shown.
BIN
corpus/688ce2c66897225949c811ce88c2fde511d69047
Normal file
BIN
corpus/688ce2c66897225949c811ce88c2fde511d69047
Normal file
Binary file not shown.
BIN
corpus/6b44ebb59ae80f72048e8c2c5572a7901166a461
Normal file
BIN
corpus/6b44ebb59ae80f72048e8c2c5572a7901166a461
Normal file
Binary file not shown.
BIN
corpus/6bea64428c692936d5017a7bfc9a9bbae4a7c646
Normal file
BIN
corpus/6bea64428c692936d5017a7bfc9a9bbae4a7c646
Normal file
Binary file not shown.
BIN
corpus/6bf94eb62dc0d1ac85f7529f3efbdea197c37c4a
Normal file
BIN
corpus/6bf94eb62dc0d1ac85f7529f3efbdea197c37c4a
Normal file
Binary file not shown.
BIN
corpus/6cc2abc6c19e461912bb07ae9d3031ebb1c6f2a7
Normal file
BIN
corpus/6cc2abc6c19e461912bb07ae9d3031ebb1c6f2a7
Normal file
Binary file not shown.
BIN
corpus/6ce54355659c0427e3d4c109b6e350e1b744b18b
Normal file
BIN
corpus/6ce54355659c0427e3d4c109b6e350e1b744b18b
Normal file
Binary file not shown.
BIN
corpus/6edf9950965a9643a3f5611164e77fdcc3f31b99
Normal file
BIN
corpus/6edf9950965a9643a3f5611164e77fdcc3f31b99
Normal file
Binary file not shown.
BIN
corpus/73894bc13e0bae69f58b228e148341143ebd5a8a
Normal file
BIN
corpus/73894bc13e0bae69f58b228e148341143ebd5a8a
Normal file
Binary file not shown.
BIN
corpus/74ebc76aa3859fb9db3b51af55713cbd845f99f0
Normal file
BIN
corpus/74ebc76aa3859fb9db3b51af55713cbd845f99f0
Normal file
Binary file not shown.
BIN
corpus/7754ffffb55baeb3e25d9c772d11e0efec95f751
Normal file
BIN
corpus/7754ffffb55baeb3e25d9c772d11e0efec95f751
Normal file
Binary file not shown.
BIN
corpus/7879186e12b1fa9339efa2aa37e80136df0e427c
Normal file
BIN
corpus/7879186e12b1fa9339efa2aa37e80136df0e427c
Normal file
Binary file not shown.
BIN
corpus/79e82b2aeffca8c33516ce8723ac5acfa85e2c61
Normal file
BIN
corpus/79e82b2aeffca8c33516ce8723ac5acfa85e2c61
Normal file
Binary file not shown.
BIN
corpus/7badef6c646baf6f1ac4aadedcb3842be1dd876c
Normal file
BIN
corpus/7badef6c646baf6f1ac4aadedcb3842be1dd876c
Normal file
Binary file not shown.
BIN
corpus/7be2015fa9574d6ce2405d3b45a5d42905d4095c
Normal file
BIN
corpus/7be2015fa9574d6ce2405d3b45a5d42905d4095c
Normal file
Binary file not shown.
BIN
corpus/7e7b26c627325c68b5de1cb17d7e0bd35f6e2039
Normal file
BIN
corpus/7e7b26c627325c68b5de1cb17d7e0bd35f6e2039
Normal file
Binary file not shown.
BIN
corpus/7e7b3164f81316a25b103f3b391867692ea5cec0
Normal file
BIN
corpus/7e7b3164f81316a25b103f3b391867692ea5cec0
Normal file
Binary file not shown.
BIN
corpus/7e8f30ffd0b8f665d87159020d0c977bca72a972
Normal file
BIN
corpus/7e8f30ffd0b8f665d87159020d0c977bca72a972
Normal file
Binary file not shown.
BIN
corpus/834f54738de969afb72c5355bc6bf226aee2bc46
Normal file
BIN
corpus/834f54738de969afb72c5355bc6bf226aee2bc46
Normal file
Binary file not shown.
BIN
corpus/83fb951c0b10b3a0beffbb100314c717a8085c05
Normal file
BIN
corpus/83fb951c0b10b3a0beffbb100314c717a8085c05
Normal file
Binary file not shown.
BIN
corpus/841521614f7ecab8ba225275035ad413024dd552
Normal file
BIN
corpus/841521614f7ecab8ba225275035ad413024dd552
Normal file
Binary file not shown.
BIN
corpus/845ac7d3ef2e4e3844308ba4aa966cef34dae1c7
Normal file
BIN
corpus/845ac7d3ef2e4e3844308ba4aa966cef34dae1c7
Normal file
Binary file not shown.
BIN
corpus/86707e4f00fefde1e3fde7e5d3d66260658f0dbc
Normal file
BIN
corpus/86707e4f00fefde1e3fde7e5d3d66260658f0dbc
Normal file
Binary file not shown.
BIN
corpus/87cc513105ddaf135e4246c74d6565e1db093d28
Normal file
BIN
corpus/87cc513105ddaf135e4246c74d6565e1db093d28
Normal file
Binary file not shown.
BIN
corpus/8958075c5dc3a865cc90f5b903a42ff13aa6f38d
Normal file
BIN
corpus/8958075c5dc3a865cc90f5b903a42ff13aa6f38d
Normal file
Binary file not shown.
BIN
corpus/8ac6ec6cd81157f7d50c7c7b6d04cd449a3680fb
Normal file
BIN
corpus/8ac6ec6cd81157f7d50c7c7b6d04cd449a3680fb
Normal file
Binary file not shown.
BIN
corpus/8ad5c9dd3bc2f5323dc895bd924c45351413ee4d
Normal file
BIN
corpus/8ad5c9dd3bc2f5323dc895bd924c45351413ee4d
Normal file
Binary file not shown.
BIN
corpus/8c41ef3f7296bfb6205b075316ef446b481031fd
Normal file
BIN
corpus/8c41ef3f7296bfb6205b075316ef446b481031fd
Normal file
Binary file not shown.
BIN
corpus/8da5e78560a6abf37ce4996d089c9810bcd60e6d
Normal file
BIN
corpus/8da5e78560a6abf37ce4996d089c9810bcd60e6d
Normal file
Binary file not shown.
BIN
corpus/8f87d63e31c652e7e3f746e6406f067818ecc68d
Normal file
BIN
corpus/8f87d63e31c652e7e3f746e6406f067818ecc68d
Normal file
Binary file not shown.
BIN
corpus/9010fce51ca20e78fadcf10003ad80dec1a92b38
Normal file
BIN
corpus/9010fce51ca20e78fadcf10003ad80dec1a92b38
Normal file
Binary file not shown.
BIN
corpus/904e5d8ff4df7175e5d97536d687bbfa2a8b6c50
Normal file
BIN
corpus/904e5d8ff4df7175e5d97536d687bbfa2a8b6c50
Normal file
Binary file not shown.
BIN
corpus/9097c0a5f4a1a725413d8ac7b5a42c1c17b6eb31
Normal file
BIN
corpus/9097c0a5f4a1a725413d8ac7b5a42c1c17b6eb31
Normal file
Binary file not shown.
BIN
corpus/91bf7637038424fdff9a6fea9afc9166399284f7
Normal file
BIN
corpus/91bf7637038424fdff9a6fea9afc9166399284f7
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