Compare commits
59 Commits
erase-betw
...
5c0cc1edf5
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
311794c37e | |||
dfa178ba19 | |||
a16d18edfe | |||
2b60287448 | |||
0a9ac59676 | |||
e3a77ed773 | |||
cdf9a8a7b0 | |||
305dfdd52f | |||
7261c91492 | |||
f11720f5ae | |||
e2b7298af5 | |||
8e1e344f4b | |||
3634b6a59b | |||
a3cc14c807 | |||
55b3275434 | |||
3a5b86ed9e | |||
159f2eef74 | |||
2952abe811 | |||
ce54746a4a | |||
b15959d62c | |||
b009de1c2b | |||
55a230c75e | |||
0711ec3831 | |||
0280bd77e5 | |||
359f6f0042 | |||
aa8504ddba | |||
fb7cf18f9b | |||
b808b97940 | |||
e480f66846 | |||
d5bc9221a0 | |||
9d23b81d6f |
16
Bench.cpp
16
Bench.cpp
@@ -361,21 +361,7 @@ void benchWorstCaseForRadixRangeRead() {
|
|||||||
void benchCreateAndDestroy() {
|
void benchCreateAndDestroy() {
|
||||||
ankerl::nanobench::Bench bench;
|
ankerl::nanobench::Bench bench;
|
||||||
|
|
||||||
bench.run("create and destroy", [&]() {
|
bench.run("create and destroy", [&]() { ConflictSet cs{0}; });
|
||||||
ConflictSet cs{0};
|
|
||||||
ConflictSet::WriteRange w;
|
|
||||||
uint8_t b[9];
|
|
||||||
b[8] = 0;
|
|
||||||
for (int64_t i = 0; i < 1000; i += 7) {
|
|
||||||
auto x = __builtin_bswap64(i);
|
|
||||||
memcpy(b, &x, 8);
|
|
||||||
w.begin.p = b;
|
|
||||||
w.begin.len = 8;
|
|
||||||
w.end.len = 0;
|
|
||||||
w.end.p = b;
|
|
||||||
cs.addWrites(&w, 1, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
@@ -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.12
|
VERSION 0.0.14
|
||||||
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"
|
||||||
@@ -276,9 +276,15 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND BUILD_TESTING)
|
|||||||
|
|
||||||
find_program(VALGRIND_EXE valgrind)
|
find_program(VALGRIND_EXE valgrind)
|
||||||
if(VALGRIND_EXE AND NOT CMAKE_CROSSCOMPILING)
|
if(VALGRIND_EXE AND NOT CMAKE_CROSSCOMPILING)
|
||||||
add_test(NAME conflict_set_blackbox_valgrind
|
list(LENGTH CORPUS_TESTS len)
|
||||||
COMMAND ${VALGRIND_EXE} --error-exitcode=99 --
|
math(EXPR last "${len} - 1")
|
||||||
$<TARGET_FILE:driver> ${CORPUS_TESTS})
|
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()
|
endif()
|
||||||
|
|
||||||
# api smoke tests
|
# api smoke tests
|
||||||
|
1648
ConflictSet.cpp
1648
ConflictSet.cpp
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,6 @@ using namespace weaselab;
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <callgrind.h>
|
#include <callgrind.h>
|
||||||
|
|
||||||
@@ -748,7 +747,10 @@ struct TestDriver {
|
|||||||
fprintf(stderr, "%p Set oldest version: %" PRId64 "\n", this,
|
fprintf(stderr, "%p Set oldest version: %" PRId64 "\n", this,
|
||||||
oldestVersion);
|
oldestVersion);
|
||||||
#endif
|
#endif
|
||||||
|
CALLGRIND_START_INSTRUMENTATION;
|
||||||
cs.setOldestVersion(oldestVersion);
|
cs.setOldestVersion(oldestVersion);
|
||||||
|
CALLGRIND_STOP_INSTRUMENTATION;
|
||||||
|
|
||||||
if constexpr (kEnableAssertions) {
|
if constexpr (kEnableAssertions) {
|
||||||
refImpl.setOldestVersion(oldestVersion);
|
refImpl.setOldestVersion(oldestVersion);
|
||||||
}
|
}
|
||||||
|
13
Jenkinsfile
vendored
13
Jenkinsfile
vendored
@@ -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 {
|
||||||
@@ -118,7 +129,7 @@ pipeline {
|
|||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
script {
|
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")
|
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 """
|
||||||
|
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;
|
||||||
|
}
|
21
README.md
21
README.md
@@ -24,16 +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
|
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | benchmark
|
||||||
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
||||||
| 10.80 | 92,600,541.52 | 0.6% | 180.38 | 54.49 | 3.310 | 41.51 | 0.4% | 0.01 | `point reads`
|
| 12.88 | 77,653,350.77 | 0.5% | 185.37 | 64.45 | 2.876 | 41.51 | 0.4% | 0.01 | `point reads`
|
||||||
| 15.00 | 66,687,691.68 | 0.4% | 278.44 | 76.44 | 3.642 | 55.56 | 0.3% | 0.01 | `prefix reads`
|
| 14.67 | 68,179,354.49 | 0.1% | 271.44 | 73.40 | 3.698 | 53.70 | 0.3% | 0.01 | `prefix reads`
|
||||||
| 36.81 | 27,163,394.61 | 0.4% | 795.06 | 187.91 | 4.231 | 142.67 | 0.2% | 0.01 | `range reads`
|
| 34.84 | 28,701,444.36 | 0.3% | 715.74 | 175.27 | 4.084 | 127.30 | 0.2% | 0.01 | `range reads`
|
||||||
| 18.14 | 55,137,674.01 | 1.2% | 338.19 | 92.86 | 3.642 | 42.81 | 0.4% | 0.01 | `point writes`
|
| 17.12 | 58,422,988.28 | 0.2% | 314.30 | 86.11 | 3.650 | 39.82 | 0.4% | 0.01 | `point writes`
|
||||||
| 33.19 | 30,127,119.71 | 0.1% | 681.03 | 170.05 | 4.005 | 98.68 | 0.2% | 0.01 | `prefix 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 | 1.9% | 779.70 | 195.45 | 3.989 | 114.21 | 0.0% | 0.01 | `range writes`
|
| 37.37 | 26,759,432.70 | 2.2% | 681.98 | 188.95 | 3.609 | 96.10 | 0.1% | 0.01 | `range 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`
|
| 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`
|
||||||
| 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`
|
| 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`
|
||||||
| 75.26 | 13,286,517.16 | 0.5% | 1,590.01 | 386.67 | 4.112 | 258.00 | 0.0% | 0.01 | `create and destroy`
|
| 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
|
# "Real data" test
|
||||||
|
|
||||||
@@ -48,7 +47,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.910234 seconds, 1791.35 MB/s, Add: 1.25908 seconds, 445.287 MB/s, Gc ratio: 44.0415%
|
Check: 0.953012 seconds, 1710.94 MB/s, Add: 1.30025 seconds, 431.188 MB/s, Gc ratio: 43.9816%, Peak idle memory: 2.28375e+06
|
||||||
```
|
```
|
||||||
|
|
||||||
## hash table
|
## hash table
|
||||||
|
127
ServerBench.cpp
127
ServerBench.cpp
@@ -6,22 +6,26 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "ConflictSet.h"
|
#include "ConflictSet.h"
|
||||||
#include "third_party/nadeau.h"
|
#include "third_party/nadeau.h"
|
||||||
|
|
||||||
std::atomic<int64_t> transactions;
|
std::atomic<int64_t> transactions;
|
||||||
|
|
||||||
constexpr int kBaseSearchDepth = 32;
|
constexpr int kBaseSearchDepth = 115;
|
||||||
constexpr int kWindowSize = 10000000;
|
constexpr int kWindowSize = 10000000;
|
||||||
|
|
||||||
std::basic_string<uint8_t> numToKey(int64_t num) {
|
std::string numToKey(int64_t num) {
|
||||||
std::basic_string<uint8_t> result;
|
std::string result;
|
||||||
result.resize(kBaseSearchDepth + sizeof(int64_t));
|
result.resize(kBaseSearchDepth + sizeof(int64_t));
|
||||||
memset(result.data(), 0, kBaseSearchDepth);
|
memset(result.data(), 0, kBaseSearchDepth);
|
||||||
int64_t be = __builtin_bswap64(num);
|
int64_t be = __builtin_bswap64(num);
|
||||||
@@ -41,13 +45,13 @@ void workload(weaselab::ConflictSet *cs) {
|
|||||||
auto pointK = numToKey(pointRv);
|
auto pointK = numToKey(pointRv);
|
||||||
weaselab::ConflictSet::ReadRange reads[] = {
|
weaselab::ConflictSet::ReadRange reads[] = {
|
||||||
{
|
{
|
||||||
{pointK.data(), int(pointK.size())},
|
{(const uint8_t *)pointK.data(), int(pointK.size())},
|
||||||
{nullptr, 0},
|
{nullptr, 0},
|
||||||
pointRv,
|
pointRv,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{beginK.data(), int(beginK.size())},
|
{(const uint8_t *)beginK.data(), int(beginK.size())},
|
||||||
{endK.data(), int(endK.size())},
|
{(const uint8_t *)endK.data(), int(endK.size())},
|
||||||
version - 2,
|
version - 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -66,7 +70,7 @@ void workload(weaselab::ConflictSet *cs) {
|
|||||||
{
|
{
|
||||||
weaselab::ConflictSet::WriteRange w;
|
weaselab::ConflictSet::WriteRange w;
|
||||||
auto k = numToKey(version);
|
auto k = numToKey(version);
|
||||||
w.begin.p = k.data();
|
w.begin.p = (const uint8_t *)k.data();
|
||||||
w.end.len = 0;
|
w.end.len = 0;
|
||||||
if (version % (kWindowSize / 2) == 0) {
|
if (version % (kWindowSize / 2) == 0) {
|
||||||
for (int l = 0; l <= k.size(); ++l) {
|
for (int l = 0; l <= k.size(); ++l) {
|
||||||
@@ -79,9 +83,9 @@ void workload(weaselab::ConflictSet *cs) {
|
|||||||
int64_t beginN = version - kWindowSize + rand() % kWindowSize;
|
int64_t beginN = version - kWindowSize + rand() % kWindowSize;
|
||||||
auto b = numToKey(beginN);
|
auto b = numToKey(beginN);
|
||||||
auto e = numToKey(beginN + 1000);
|
auto e = numToKey(beginN + 1000);
|
||||||
w.begin.p = b.data();
|
w.begin.p = (const uint8_t *)b.data();
|
||||||
w.begin.len = b.size();
|
w.begin.len = b.size();
|
||||||
w.end.p = e.data();
|
w.end.p = (const uint8_t *)e.data();
|
||||||
w.end.len = e.size();
|
w.end.len = e.size();
|
||||||
cs->addWrites(&w, 1, version);
|
cs->addWrites(&w, 1, version);
|
||||||
}
|
}
|
||||||
@@ -164,36 +168,29 @@ double toSeconds(timeval t) {
|
|||||||
return double(t.tv_sec) + double(t.tv_usec) * 1e-6;
|
return double(t.tv_sec) + double(t.tv_usec) * 1e-6;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <linux/perf_event.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
#include <linux/perf_event.h>
|
||||||
struct PerfCounter {
|
struct PerfCounter {
|
||||||
explicit PerfCounter(int event) {
|
PerfCounter(int type, int config, const std::string &labels = {},
|
||||||
|
int groupLeaderFd = -1)
|
||||||
|
: labels(labels) {
|
||||||
struct perf_event_attr pe;
|
struct perf_event_attr pe;
|
||||||
|
|
||||||
memset(&pe, 0, sizeof(pe));
|
memset(&pe, 0, sizeof(pe));
|
||||||
pe.type = PERF_TYPE_HARDWARE;
|
pe.type = type;
|
||||||
pe.size = sizeof(pe);
|
pe.size = sizeof(pe);
|
||||||
pe.config = event;
|
pe.config = config;
|
||||||
pe.inherit = 1;
|
pe.inherit = 1;
|
||||||
pe.exclude_kernel = 1;
|
pe.exclude_kernel = 1;
|
||||||
pe.exclude_hv = 1;
|
pe.exclude_hv = 1;
|
||||||
|
|
||||||
fd = perf_event_open(&pe, 0, -1, -1, 0);
|
fd = perf_event_open(&pe, 0, -1, groupLeaderFd, 0);
|
||||||
if (fd == -1) {
|
if (fd < 0 && errno != ENOENT && errno != EINVAL) {
|
||||||
fprintf(stderr, "Error opening leader %llx\n", pe.config);
|
perror(labels.c_str());
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t total() {
|
int64_t total() const {
|
||||||
int64_t count;
|
int64_t count;
|
||||||
if (read(fd, &count, sizeof(count)) != sizeof(count)) {
|
if (read(fd, &count, sizeof(count)) != sizeof(count)) {
|
||||||
perror("read instructions from perf");
|
perror("read instructions from perf");
|
||||||
@@ -202,10 +199,27 @@ struct PerfCounter {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
~PerfCounter() { close(fd); }
|
PerfCounter(PerfCounter &&other)
|
||||||
|
: fd(std::exchange(other.fd, -1)), labels(std::move(other.labels)) {}
|
||||||
|
PerfCounter &operator=(PerfCounter &&other) {
|
||||||
|
fd = std::exchange(other.fd, -1);
|
||||||
|
labels = std::move(other.labels);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~PerfCounter() {
|
||||||
|
if (fd >= 0) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok() const { return fd >= 0; }
|
||||||
|
const std::string &getLabels() const { return labels; }
|
||||||
|
int getFd() const { return fd; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fd;
|
int fd;
|
||||||
|
std::string labels;
|
||||||
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||||
int cpu, int group_fd, unsigned long flags) {
|
int cpu, int group_fd, unsigned long flags) {
|
||||||
int ret;
|
int ret;
|
||||||
@@ -214,11 +228,6 @@ private:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#else
|
|
||||||
struct PerfCounter {
|
|
||||||
explicit PerPerfCounter(int) {}
|
|
||||||
int64_t total() { return 0; }
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
@@ -233,8 +242,50 @@ int main(int argc, char **argv) {
|
|||||||
int metricsCount;
|
int metricsCount;
|
||||||
cs.getMetricsV1(&metrics, &metricsCount);
|
cs.getMetricsV1(&metrics, &metricsCount);
|
||||||
|
|
||||||
PerfCounter instructions{PERF_COUNT_HW_INSTRUCTIONS};
|
#ifdef __linux__
|
||||||
PerfCounter cycles{PERF_COUNT_HW_CPU_CYCLES};
|
PerfCounter instructions{PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS};
|
||||||
|
PerfCounter cycles{PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES, "",
|
||||||
|
instructions.getFd()};
|
||||||
|
|
||||||
|
std::vector<PerfCounter> cacheCounters;
|
||||||
|
for (auto [id, idStr] : std::initializer_list<std::pair<int, std::string>>{
|
||||||
|
{PERF_COUNT_HW_CACHE_L1D, "l1d"},
|
||||||
|
{PERF_COUNT_HW_CACHE_L1I, "l1i"},
|
||||||
|
{PERF_COUNT_HW_CACHE_LL, "ll"},
|
||||||
|
{PERF_COUNT_HW_CACHE_DTLB, "dtlb"},
|
||||||
|
{PERF_COUNT_HW_CACHE_ITLB, "itlb"},
|
||||||
|
{PERF_COUNT_HW_CACHE_BPU, "bpu"},
|
||||||
|
{PERF_COUNT_HW_CACHE_NODE, "node"},
|
||||||
|
}) {
|
||||||
|
for (auto [op, opStr] :
|
||||||
|
std::initializer_list<std::pair<int, std::string>>{
|
||||||
|
{PERF_COUNT_HW_CACHE_OP_READ, "read"},
|
||||||
|
{PERF_COUNT_HW_CACHE_OP_WRITE, "write"},
|
||||||
|
{PERF_COUNT_HW_CACHE_OP_PREFETCH, "prefetch"},
|
||||||
|
}) {
|
||||||
|
int groupLeaderFd = -1;
|
||||||
|
for (auto [result, resultStr] :
|
||||||
|
std::initializer_list<std::pair<int, std::string>>{
|
||||||
|
{PERF_COUNT_HW_CACHE_RESULT_MISS, "miss"},
|
||||||
|
{PERF_COUNT_HW_CACHE_RESULT_ACCESS, "access"},
|
||||||
|
}) {
|
||||||
|
auto labels = "{id=\"" + idStr + "\", op=\"" + opStr +
|
||||||
|
"\", result=\"" + resultStr + "\"}";
|
||||||
|
cacheCounters.emplace_back(PERF_TYPE_HW_CACHE,
|
||||||
|
id | (op << 8) | (result << 16), labels,
|
||||||
|
groupLeaderFd);
|
||||||
|
if (!cacheCounters.back().ok()) {
|
||||||
|
cacheCounters.pop_back();
|
||||||
|
} else {
|
||||||
|
if (groupLeaderFd == -1) {
|
||||||
|
groupLeaderFd = cacheCounters.back().getFd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
auto w = std::thread{workload, &cs};
|
auto w = std::thread{workload, &cs};
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -262,6 +313,7 @@ int main(int argc, char **argv) {
|
|||||||
"transactions_total ";
|
"transactions_total ";
|
||||||
body += std::to_string(transactions.load(std::memory_order_relaxed));
|
body += std::to_string(transactions.load(std::memory_order_relaxed));
|
||||||
body += "\n";
|
body += "\n";
|
||||||
|
#ifdef __linux__
|
||||||
body += "# HELP instructions_total Total number of instructions\n"
|
body += "# HELP instructions_total Total number of instructions\n"
|
||||||
"# TYPE instructions_total counter\n"
|
"# TYPE instructions_total counter\n"
|
||||||
"instructions_total ";
|
"instructions_total ";
|
||||||
@@ -272,6 +324,13 @@ int main(int argc, char **argv) {
|
|||||||
"cycles_total ";
|
"cycles_total ";
|
||||||
body += std::to_string(cycles.total());
|
body += std::to_string(cycles.total());
|
||||||
body += "\n";
|
body += "\n";
|
||||||
|
body += "# HELP cache_event_total Total number of cache events\n"
|
||||||
|
"# TYPE cache_event_total counter\n";
|
||||||
|
for (const auto &counter : cacheCounters) {
|
||||||
|
body += "cache_event_total" + counter.getLabels() + " " +
|
||||||
|
std::to_string(counter.total()) + "\n";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < metricsCount; ++i) {
|
for (int i = 0; i < metricsCount; ++i) {
|
||||||
body += "# HELP ";
|
body += "# HELP ";
|
||||||
|
176
SkipList.cpp
176
SkipList.cpp
@@ -22,9 +22,11 @@
|
|||||||
|
|
||||||
#include "ConflictSet.h"
|
#include "ConflictSet.h"
|
||||||
#include "Internal.h"
|
#include "Internal.h"
|
||||||
|
#include "Metrics.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) {
|
std::span<const uint8_t> keyAfter(Arena &arena, std::span<const uint8_t> key) {
|
||||||
auto result =
|
auto result =
|
||||||
@@ -115,15 +117,6 @@ bool operator==(const KeyInfo &lhs, const KeyInfo &rhs) {
|
|||||||
return !(lhs < rhs || rhs < lhs);
|
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 {
|
struct SortTask {
|
||||||
int begin;
|
int begin;
|
||||||
int size;
|
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) {
|
static int compare(const StringRef &a, const StringRef &b) {
|
||||||
int c = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
|
int c = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
|
||||||
if (c < 0)
|
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 {
|
class SkipList {
|
||||||
private:
|
private:
|
||||||
static constexpr int MaxLevels = 26;
|
RandomLevel randomLevel{0};
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Represent a node in the SkipList. The node has multiple (i.e., level)
|
// 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
|
// 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 swap(SkipList &other) { std::swap(header, other.header); }
|
||||||
|
|
||||||
void addConflictRanges(const Finger *fingers, int rangeCount,
|
// Returns the change in the number of entries
|
||||||
Version version) {
|
int64_t addConflictRanges(const Finger *fingers, int rangeCount,
|
||||||
|
Version version) {
|
||||||
|
int64_t result = rangeCount;
|
||||||
for (int r = rangeCount - 1; r >= 0; r--) {
|
for (int r = rangeCount - 1; r >= 0; r--) {
|
||||||
const Finger &startF = fingers[r * 2];
|
const Finger &startF = fingers[r * 2];
|
||||||
const Finger &endF = fingers[r * 2 + 1];
|
const Finger &endF = fingers[r * 2 + 1];
|
||||||
|
|
||||||
if (endF.found() == nullptr)
|
if (endF.found() == nullptr) {
|
||||||
|
++result;
|
||||||
insert(endF, endF.finger[0]->getMaxVersion(0));
|
insert(endF, endF.finger[0]->getMaxVersion(0));
|
||||||
|
}
|
||||||
|
|
||||||
remove(startF, endF);
|
result -= remove(startF, endF);
|
||||||
insert(startF, version);
|
insert(startF, version);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void detectConflicts(ReadConflictRange *ranges, int count,
|
// Return number of iterations of main loop
|
||||||
ConflictSet::Result *transactionConflictStatus) const {
|
int detectConflicts(ReadConflictRange *ranges, int count,
|
||||||
|
ConflictSet::Result *transactionConflictStatus) const {
|
||||||
const int M = 16;
|
const int M = 16;
|
||||||
int nextJob[M];
|
int nextJob[M];
|
||||||
CheckMax inProgress[M];
|
CheckMax inProgress[M];
|
||||||
if (!count)
|
if (!count)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
int started = std::min(M, count);
|
int started = std::min(M, count);
|
||||||
for (int i = 0; i < started; i++) {
|
for (int i = 0; i < started; i++) {
|
||||||
@@ -457,8 +453,9 @@ public:
|
|||||||
|
|
||||||
int prevJob = started - 1;
|
int prevJob = started - 1;
|
||||||
int job = 0;
|
int job = 0;
|
||||||
|
int iters = 0;
|
||||||
// vtune: 340 parts
|
// vtune: 340 parts
|
||||||
while (true) {
|
for (;; ++iters) {
|
||||||
if (inProgress[job].advance()) {
|
if (inProgress[job].advance()) {
|
||||||
if (started == count) {
|
if (started == count) {
|
||||||
if (prevJob == job)
|
if (prevJob == job)
|
||||||
@@ -474,6 +471,7 @@ public:
|
|||||||
prevJob = job;
|
prevJob = job;
|
||||||
job = nextJob[job];
|
job = nextJob[job];
|
||||||
}
|
}
|
||||||
|
return iters;
|
||||||
}
|
}
|
||||||
|
|
||||||
void find(const StringRef *values, Finger *results, int *temp, int count) {
|
void find(const StringRef *values, Finger *results, int *temp, int count) {
|
||||||
@@ -567,9 +565,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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])
|
if (start.finger[0] == end.finger[0])
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
Node *x = start.finger[0]->getNext(0);
|
Node *x = start.finger[0]->getNext(0);
|
||||||
|
|
||||||
@@ -578,17 +577,20 @@ private:
|
|||||||
if (start.finger[i] != end.finger[i])
|
if (start.finger[i] != end.finger[i])
|
||||||
start.finger[i]->setNext(i, end.finger[i]->getNext(i));
|
start.finger[i]->setNext(i, end.finger[i]->getNext(i));
|
||||||
|
|
||||||
|
int64_t result = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
Node *next = x->getNext(0);
|
Node *next = x->getNext(0);
|
||||||
x->destroy();
|
x->destroy();
|
||||||
|
++result;
|
||||||
if (x == end.finger[0])
|
if (x == end.finger[0])
|
||||||
break;
|
break;
|
||||||
x = next;
|
x = next;
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(const Finger &f, Version version) {
|
void insert(const Finger &f, Version version) {
|
||||||
int level = randomLevel();
|
int level = randomLevel.next();
|
||||||
// std::cout << std::string((const char*)value,length) << " level: " <<
|
// std::cout << std::string((const char*)value,length) << " level: " <<
|
||||||
// level << std::endl;
|
// level << std::endl;
|
||||||
Node *x = Node::create(f.value, level);
|
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 {
|
struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||||
Impl(int64_t oldestVersion)
|
Impl(int64_t oldestVersion)
|
||||||
: oldestVersion(oldestVersion), newestVersion(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,
|
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
|
||||||
int count) const {
|
int count) {
|
||||||
|
ReadContext tls;
|
||||||
Arena arena;
|
Arena arena;
|
||||||
auto *ranges = new (arena) ReadConflictRange[count];
|
auto *ranges = new (arena) ReadConflictRange[count];
|
||||||
for (int i = 0; i < count; ++i) {
|
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].begin = {reads[i].begin.p, size_t(reads[i].begin.len)};
|
||||||
ranges[i].end = reads[i].end.len > 0
|
ranges[i].end = reads[i].end.len > 0
|
||||||
? StringRef{reads[i].end.p, size_t(reads[i].end.len)}
|
? 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;
|
ranges[i].version = reads[i].readVersion;
|
||||||
results[i] = ConflictSet::Commit;
|
results[i] = ConflictSet::Commit;
|
||||||
}
|
}
|
||||||
skipList.detectConflicts(ranges, count, results);
|
int iters = skipList.detectConflicts(ranges, count, results);
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
if (reads[i].readVersion < oldestVersion ||
|
if (reads[i].readVersion < oldestVersion ||
|
||||||
reads[i].readVersion < newestVersion - 2e9) {
|
reads[i].readVersion < newestVersion - 2e9) {
|
||||||
results[i] = TooOld;
|
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,
|
void addWrites(const ConflictSet::WriteRange *writes, int count,
|
||||||
@@ -775,27 +796,33 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
StringRef values[stripeSize];
|
StringRef values[stripeSize];
|
||||||
int64_t writeVersions[stripeSize / 2];
|
int64_t writeVersions[stripeSize / 2];
|
||||||
int ss = stringCount - (stripes - 1) * stripeSize;
|
int ss = stringCount - (stripes - 1) * stripeSize;
|
||||||
|
int64_t entryDelta = 0;
|
||||||
for (int s = stripes - 1; s >= 0; s--) {
|
for (int s = stripes - 1; s >= 0; s--) {
|
||||||
for (int i = 0; i * 2 < ss; ++i) {
|
for (int i = 0; i * 2 < ss; ++i) {
|
||||||
const auto &w = combinedWriteConflictRanges[s * stripeSize / 2 + i];
|
const auto &w = combinedWriteConflictRanges[s * stripeSize / 2 + i];
|
||||||
values[i * 2] = w.first;
|
values[i * 2] = w.first;
|
||||||
values[i * 2 + 1] = w.second;
|
values[i * 2 + 1] = w.second;
|
||||||
keyUpdates += 3;
|
|
||||||
}
|
}
|
||||||
skipList.find(values, fingers, temp, ss);
|
skipList.find(values, fingers, temp, ss);
|
||||||
skipList.addConflictRanges(fingers, ss / 2, writeVersion);
|
entryDelta += skipList.addConflictRanges(fingers, ss / 2, writeVersion);
|
||||||
ss = stripeSize;
|
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) {
|
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);
|
assert(oldestVersion >= this->oldestVersion);
|
||||||
this->oldestVersion = oldestVersion;
|
this->oldestVersion = oldestVersion;
|
||||||
SkipList::Finger finger;
|
SkipList::Finger finger;
|
||||||
int temp;
|
int temp;
|
||||||
std::span<const uint8_t> key = removalKey;
|
std::span<const uint8_t> key = removalKey;
|
||||||
skipList.find(&key, &finger, &temp, 1);
|
skipList.find(&key, &finger, &temp, 1);
|
||||||
skipList.removeBefore(oldestVersion, finger, std::exchange(keyUpdates, 10));
|
skipList.removeBefore(oldestVersion, finger, std::exchange(keyUpdates, 0));
|
||||||
removalArena = Arena();
|
removalArena = Arena();
|
||||||
removalKey = copyToArena(
|
removalKey = copyToArena(
|
||||||
removalArena, {finger.getValue().data(), finger.getValue().size()});
|
removalArena, {finger.getValue().data(), finger.getValue().size()});
|
||||||
@@ -803,8 +830,56 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|||||||
|
|
||||||
int64_t totalBytes = 0;
|
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:
|
private:
|
||||||
int64_t keyUpdates = 10;
|
int64_t keyUpdates = 0;
|
||||||
Arena removalArena;
|
Arena removalArena;
|
||||||
std::span<const uint8_t> removalKey;
|
std::span<const uint8_t> removalKey;
|
||||||
int64_t oldestVersion;
|
int64_t oldestVersion;
|
||||||
@@ -825,6 +900,7 @@ void internal_addWrites(ConflictSet::Impl *impl,
|
|||||||
mallocBytesDelta = 0;
|
mallocBytesDelta = 0;
|
||||||
impl->addWrites(writes, count, writeVersion);
|
impl->addWrites(writes, count, writeVersion);
|
||||||
impl->totalBytes += mallocBytesDelta;
|
impl->totalBytes += mallocBytesDelta;
|
||||||
|
impl->memory_bytes.set(impl->totalBytes);
|
||||||
#if SHOW_MEMORY
|
#if SHOW_MEMORY
|
||||||
if (impl->totalBytes != mallocBytes) {
|
if (impl->totalBytes != mallocBytes) {
|
||||||
abort();
|
abort();
|
||||||
@@ -836,6 +912,7 @@ void internal_setOldestVersion(ConflictSet::Impl *impl, int64_t oldestVersion) {
|
|||||||
mallocBytesDelta = 0;
|
mallocBytesDelta = 0;
|
||||||
impl->setOldestVersion(oldestVersion);
|
impl->setOldestVersion(oldestVersion);
|
||||||
impl->totalBytes += mallocBytesDelta;
|
impl->totalBytes += mallocBytesDelta;
|
||||||
|
impl->memory_bytes.set(impl->totalBytes);
|
||||||
#if SHOW_MEMORY
|
#if SHOW_MEMORY
|
||||||
if (impl->totalBytes != mallocBytes) {
|
if (impl->totalBytes != mallocBytes) {
|
||||||
abort();
|
abort();
|
||||||
@@ -859,12 +936,11 @@ int64_t internal_getBytes(ConflictSet::Impl *impl) { return impl->totalBytes; }
|
|||||||
|
|
||||||
void internal_getMetricsV1(ConflictSet::Impl *impl,
|
void internal_getMetricsV1(ConflictSet::Impl *impl,
|
||||||
ConflictSet::MetricsV1 **metrics, int *count) {
|
ConflictSet::MetricsV1 **metrics, int *count) {
|
||||||
*metrics = nullptr;
|
return impl->getMetricsV1(metrics, count);
|
||||||
*count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double internal_getMetricValue(const ConflictSet::MetricsV1 *metric) {
|
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,
|
void ConflictSet::check(const ReadRange *reads, Result *results,
|
||||||
|
Binary file not shown.
BIN
corpus/008e3be49d62c3e7fa3785b882bdb65ee4b68977
Normal file
BIN
corpus/008e3be49d62c3e7fa3785b882bdb65ee4b68977
Normal file
Binary file not shown.
BIN
corpus/0164e1ae452d063faa26b90d924f52189f268011
Normal file
BIN
corpus/0164e1ae452d063faa26b90d924f52189f268011
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0325e533cf35c1e7ac95326c9b189911deffb27e
Normal file
BIN
corpus/0325e533cf35c1e7ac95326c9b189911deffb27e
Normal file
Binary file not shown.
BIN
corpus/0390280ec499c5f687428e700028c230e8ce944e
Normal file
BIN
corpus/0390280ec499c5f687428e700028c230e8ce944e
Normal file
Binary file not shown.
BIN
corpus/04239a60051c9a1779d9a896b84eff01f272f191
Normal file
BIN
corpus/04239a60051c9a1779d9a896b84eff01f272f191
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/05a091a7d5e921098504585a4201967860d310c6
Normal file
BIN
corpus/05a091a7d5e921098504585a4201967860d310c6
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.
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.
Binary file not shown.
BIN
corpus/0b724429644597a0c8feb3d95dced0c2a48e5ed0
Normal file
BIN
corpus/0b724429644597a0c8feb3d95dced0c2a48e5ed0
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/0da7d6000805c1f25907f3a2e8499ee119673f28
Normal file
BIN
corpus/0da7d6000805c1f25907f3a2e8499ee119673f28
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/10838bd79f36f824c41afa600c86f176f213ff79
Normal file
BIN
corpus/10838bd79f36f824c41afa600c86f176f213ff79
Normal file
Binary file not shown.
BIN
corpus/10970b15ecff0b0564ef8dc31c30680e5e4a4421
Normal file
BIN
corpus/10970b15ecff0b0564ef8dc31c30680e5e4a4421
Normal file
Binary file not shown.
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.
Binary file not shown.
BIN
corpus/158d2f871afe1bf811833d07a03415d89a868efe
Normal file
BIN
corpus/158d2f871afe1bf811833d07a03415d89a868efe
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/15f6e61dd6edef971d7c79bef0d14069b0a75c77
Normal file
BIN
corpus/15f6e61dd6edef971d7c79bef0d14069b0a75c77
Normal file
Binary file not shown.
BIN
corpus/170a0ec4714b5ee34045037b38f038a8e3fa2035
Normal file
BIN
corpus/170a0ec4714b5ee34045037b38f038a8e3fa2035
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/198314d10d86adbfb9d14a0a48cb01fd050cdd50
Normal file
BIN
corpus/198314d10d86adbfb9d14a0a48cb01fd050cdd50
Normal file
Binary file not shown.
BIN
corpus/1a591c014514af4b723cc6f5f0753319fa57b925
Normal file
BIN
corpus/1a591c014514af4b723cc6f5f0753319fa57b925
Normal file
Binary file not shown.
BIN
corpus/1ab0a409dbf44496ea9d7027ba8898805f396140
Normal file
BIN
corpus/1ab0a409dbf44496ea9d7027ba8898805f396140
Normal file
Binary file not shown.
BIN
corpus/1ac23fb78ff1d7ea8b6ca0e63184fbbc9199e68c
Normal file
BIN
corpus/1ac23fb78ff1d7ea8b6ca0e63184fbbc9199e68c
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1ce3c082d69e7b494e648186d23562d60808c096
Normal file
BIN
corpus/1ce3c082d69e7b494e648186d23562d60808c096
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/1e656ebd6c39b9fd6bea8c1bdaf12fe92642d507
Normal file
BIN
corpus/1e656ebd6c39b9fd6bea8c1bdaf12fe92642d507
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/1f1a703161be463bc598349de981d56fecff1f7a
Normal file
BIN
corpus/1f1a703161be463bc598349de981d56fecff1f7a
Normal file
Binary file not shown.
BIN
corpus/2141828fbf5049e21a703dac83d5726fdf32aaaf
Normal file
BIN
corpus/2141828fbf5049e21a703dac83d5726fdf32aaaf
Normal file
Binary file not shown.
BIN
corpus/21540fec17d78467a6fe450592da42ca03e8e268
Normal file
BIN
corpus/21540fec17d78467a6fe450592da42ca03e8e268
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/233112524bdcd6f77d4d51c080039bf1e1358bc2
Normal file
BIN
corpus/233112524bdcd6f77d4d51c080039bf1e1358bc2
Normal file
Binary file not shown.
BIN
corpus/236aae2fbf5a1c6716650bdc0187aadebd0fd4eb
Normal file
BIN
corpus/236aae2fbf5a1c6716650bdc0187aadebd0fd4eb
Normal file
Binary file not shown.
BIN
corpus/23d4c4704607cea96775f90eec72ec444a53327e
Normal file
BIN
corpus/23d4c4704607cea96775f90eec72ec444a53327e
Normal file
Binary file not shown.
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/29ae192a6404273b14be44d0f06d354e9eb5084b
Normal file
BIN
corpus/29ae192a6404273b14be44d0f06d354e9eb5084b
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/2a32a3d39a663771bda1be99ecfbe55ff780d2b2
Normal file
BIN
corpus/2a32a3d39a663771bda1be99ecfbe55ff780d2b2
Normal file
Binary file not shown.
BIN
corpus/2aa2ab713a18bc86e886777cf6008a871e590688
Normal file
BIN
corpus/2aa2ab713a18bc86e886777cf6008a871e590688
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.
Binary file not shown.
Binary file not shown.
BIN
corpus/2e28e709dc7a313255964e2c21d3c8c9b6c3ef1d
Normal file
BIN
corpus/2e28e709dc7a313255964e2c21d3c8c9b6c3ef1d
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/31bf521be5d9f9e7d99e1384b9ffe26197324c37
Normal file
BIN
corpus/31bf521be5d9f9e7d99e1384b9ffe26197324c37
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/3276a649b804693762b06581bf459b2f2accc03e
Normal file
BIN
corpus/3276a649b804693762b06581bf459b2f2accc03e
Normal file
Binary file not shown.
BIN
corpus/32b1f5278c998e688bf7a44d89f54a2c183e75eb
Normal file
BIN
corpus/32b1f5278c998e688bf7a44d89f54a2c183e75eb
Normal file
Binary file not shown.
Binary file not shown.
BIN
corpus/34a4d2436527e903d806a63c002cea88522f3a5e
Normal file
BIN
corpus/34a4d2436527e903d806a63c002cea88522f3a5e
Normal file
Binary file not shown.
BIN
corpus/351af0b05e0c3f3c74954de9f5aa64d292d1dcab
Normal file
BIN
corpus/351af0b05e0c3f3c74954de9f5aa64d292d1dcab
Normal file
Binary file not shown.
BIN
corpus/3530208307bb7a980d56987edbf1783c72ca2444
Normal file
BIN
corpus/3530208307bb7a980d56987edbf1783c72ca2444
Normal file
Binary file not shown.
BIN
corpus/35df5d1e51e37343461d1246ea693ea55ae46413
Normal file
BIN
corpus/35df5d1e51e37343461d1246ea693ea55ae46413
Normal file
Binary file not shown.
BIN
corpus/37636f0129daeb11db2665b746ec1d63650ddea7
Normal file
BIN
corpus/37636f0129daeb11db2665b746ec1d63650ddea7
Normal file
Binary file not shown.
BIN
corpus/3a5cb027cf0d324ad95683dd26c4fee6bfa322c3
Normal file
BIN
corpus/3a5cb027cf0d324ad95683dd26c4fee6bfa322c3
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
corpus/3b6efa6b4581d3f75d307ecdd5aa53b4fa3fea90
Normal file
BIN
corpus/3b6efa6b4581d3f75d307ecdd5aa53b4fa3fea90
Normal file
Binary file not shown.
BIN
corpus/3ba58d43a24139a702c6d5c83ce3cc9f82bac804
Normal file
BIN
corpus/3ba58d43a24139a702c6d5c83ce3cc9f82bac804
Normal file
Binary file not shown.
BIN
corpus/3c07b3837fed49692b1fe1b9c1f878d135f3ecda
Normal file
BIN
corpus/3c07b3837fed49692b1fe1b9c1f878d135f3ecda
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