Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc4306cfe9 | ||
|
|
9b7199567b | ||
|
|
7c6c116713 | ||
|
|
5c9e9603de | ||
|
|
862b6a4886 | ||
|
|
a69dac7f16 |
@@ -0,0 +1,306 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CC: clang
|
||||||
|
CXX: clang++
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pre-commit:
|
||||||
|
runs-on: ubuntu-latest-amd64
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: /var/cache/apt/archives
|
||||||
|
key: apt-amd64-${{ hashFiles('.gitea/workflows/ci.yml') }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y git nodejs pre-commit
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pre-commit
|
||||||
|
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
|
||||||
|
|
||||||
|
- name: Run pre-commit
|
||||||
|
run: |
|
||||||
|
git config --global --add safe.directory "$PWD"
|
||||||
|
pre-commit run --all-files --show-diff-on-failure
|
||||||
|
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- name: 64-bit-versions
|
||||||
|
cmake_args: -DCMAKE_CXX_FLAGS=-DUSE_64_BIT=1
|
||||||
|
- name: debug
|
||||||
|
cmake_args: -DCMAKE_BUILD_TYPE=Debug
|
||||||
|
- name: simd-fallback
|
||||||
|
cmake_args: -DUSE_SIMD_FALLBACK=ON
|
||||||
|
- name: gcc
|
||||||
|
cmake_args: -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
|
||||||
|
runs-on: ubuntu-latest-amd64
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: /var/cache/apt/archives
|
||||||
|
key: apt-amd64-${{ hashFiles('.gitea/workflows/ci.yml') }}
|
||||||
|
|
||||||
|
- name: Install common dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y \
|
||||||
|
build-essential ccache cmake gcc g++ libc6-dbg \
|
||||||
|
ninja-build python3 valgrind zstd
|
||||||
|
sudo curl -Ls "https://minio.weaselab.dev/public/$(uname -m)/mc.RELEASE.2025-08-13T08-35-41Z" \
|
||||||
|
-o /usr/local/bin/mc && sudo chmod +x /usr/local/bin/mc
|
||||||
|
|
||||||
|
- name: Install LLVM toolchain
|
||||||
|
if: matrix.name != 'gcc'
|
||||||
|
run: |
|
||||||
|
. /etc/os-release
|
||||||
|
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||||
|
echo "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-21 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y \
|
||||||
|
clang-21 llvm-21 lld-21 mold
|
||||||
|
for tool in clang clang++ llvm-ar llvm-nm llvm-ranlib llvm-objcopy llvm-cov llvm-symbolizer lld ld.lld; do
|
||||||
|
sudo update-alternatives --install /usr/bin/${tool} ${tool} /usr/bin/${tool}-21 100
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
|
||||||
|
rm -rf build
|
||||||
|
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache ${{ matrix.cmake_args }}
|
||||||
|
ninja -C build
|
||||||
|
ccache -s
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
ctest --no-compress-output --test-output-size-passed 100000 --test-output-size-failed 100000 -T Test -j "$(nproc)" --timeout 90 > /dev/null
|
||||||
|
|
||||||
|
- name: Upload test results to MinIO
|
||||||
|
if: always()
|
||||||
|
env:
|
||||||
|
MINIO_ACCESS_KEY: ${{ secrets.MINIO_ACCESS_KEY }}
|
||||||
|
MC_HOST_minio: https://${{ secrets.MINIO_ACCESS_KEY }}:${{ secrets.MINIO_SECRET_KEY }}@minio.weaselab.dev
|
||||||
|
run: |
|
||||||
|
if [ -z "$MINIO_ACCESS_KEY" ]; then
|
||||||
|
echo "MinIO credentials not configured; skipping upload"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
zstd build/Testing/*/Test.xml
|
||||||
|
mc cp build/Testing/*/Test.xml.zst "minio/jenkins/conflict-set/${{ gitea.run_number }}/${{ matrix.name }}/"
|
||||||
|
|
||||||
|
- name: Test summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
python3 ctest_summary.py build/Testing/*/Test.xml \
|
||||||
|
--link "https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/${{ matrix.name }}/Test.xml.zst" \
|
||||||
|
| tee -a "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
|
release:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- runner: ubuntu-latest-amd64
|
||||||
|
arch: amd64
|
||||||
|
- runner: ubuntu-latest-arm64
|
||||||
|
arch: arm64
|
||||||
|
runs-on: ${{ matrix.runner }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: /var/cache/apt/archives
|
||||||
|
key: apt-${{ matrix.arch }}-${{ hashFiles('.gitea/workflows/ci.yml') }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
. /etc/os-release
|
||||||
|
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||||
|
echo "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-21 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y \
|
||||||
|
build-essential ccache clang-21 cmake devscripts \
|
||||||
|
libc6-dbg llvm-21 lld-21 mold ninja-build rpm \
|
||||||
|
valgrind zstd
|
||||||
|
sudo curl -Ls "https://minio.weaselab.dev/public/$(uname -m)/mc.RELEASE.2025-08-13T08-35-41Z" \
|
||||||
|
-o /usr/local/bin/mc && sudo chmod +x /usr/local/bin/mc
|
||||||
|
for tool in clang clang++ llvm-ar llvm-nm llvm-ranlib llvm-objcopy llvm-cov llvm-symbolizer lld ld.lld; do
|
||||||
|
sudo update-alternatives --install /usr/bin/${tool} ${tool} /usr/bin/${tool}-21 100
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Install paper build dependencies
|
||||||
|
if: matrix.arch == 'amd64'
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y \
|
||||||
|
biber latexmk \
|
||||||
|
texlive-bibtex-extra texlive-fonts-recommended \
|
||||||
|
texlive-latex-extra texlive-pictures
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .ccache
|
||||||
|
key: ccache-release-${{ matrix.arch }}-${{ gitea.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
ccache-release-${{ matrix.arch }}-
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
|
||||||
|
rm -rf build
|
||||||
|
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_FLAGS=-DNVALGRIND
|
||||||
|
ninja -C build
|
||||||
|
ccache -s
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
# On arm64, valgrind needs the MAKE_MEM_DEFINED client requests for
|
||||||
|
# https://git.weaselab.dev/weaselab/conflict-set/issues/39, but this
|
||||||
|
# build has -DNVALGRIND, which compiles them out. Skip valgrind
|
||||||
|
# tests here; they run annotated in the test job.
|
||||||
|
ctest --no-compress-output --test-output-size-passed 100000 --test-output-size-failed 100000 ${{ matrix.arch == 'arm64' && '-E valgrind' || '' }} -T Test -j "$(nproc)" --timeout 90 > /dev/null
|
||||||
|
|
||||||
|
- name: Package
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
cpack -G DEB
|
||||||
|
cpack -G RPM
|
||||||
|
|
||||||
|
- name: Build paper
|
||||||
|
if: matrix.arch == 'amd64'
|
||||||
|
run: |
|
||||||
|
cd paper
|
||||||
|
make
|
||||||
|
|
||||||
|
- name: Upload artifacts to MinIO
|
||||||
|
if: always()
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
MINIO_ACCESS_KEY: ${{ secrets.MINIO_ACCESS_KEY }}
|
||||||
|
MC_HOST_minio: https://${{ secrets.MINIO_ACCESS_KEY }}:${{ secrets.MINIO_SECRET_KEY }}@minio.weaselab.dev
|
||||||
|
run: |
|
||||||
|
if [ -z "$MINIO_ACCESS_KEY" ]; then
|
||||||
|
echo "MinIO credentials not configured; skipping upload"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
dest="minio/jenkins/conflict-set/${{ gitea.run_number }}/release-${{ matrix.arch }}/"
|
||||||
|
zstd build/Testing/*/Test.xml
|
||||||
|
mc cp build/Testing/*/Test.xml.zst "$dest"
|
||||||
|
if compgen -G "build/*.deb" > /dev/null; then
|
||||||
|
mc cp build/*.deb "$dest"
|
||||||
|
fi
|
||||||
|
if compgen -G "build/*.rpm" > /dev/null; then
|
||||||
|
mc cp build/*.rpm "$dest"
|
||||||
|
fi
|
||||||
|
if compgen -G "paper/*.pdf" > /dev/null; then
|
||||||
|
mc cp paper/*.pdf "$dest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Test summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
python3 ctest_summary.py build/Testing/*/Test.xml \
|
||||||
|
--link "https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/release-${{ matrix.arch }}/Test.xml.zst" \
|
||||||
|
| tee -a "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
runs-on: ubuntu-latest-amd64
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: /var/cache/apt/archives
|
||||||
|
key: apt-amd64-${{ hashFiles('.gitea/workflows/ci.yml') }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
. /etc/os-release
|
||||||
|
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc
|
||||||
|
echo "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-21 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y \
|
||||||
|
build-essential ccache clang-21 cmake gcovr \
|
||||||
|
libc6-dbg llvm-21 lld-21 mold ninja-build python3 valgrind zstd
|
||||||
|
sudo curl -Ls "https://minio.weaselab.dev/public/$(uname -m)/mc.RELEASE.2025-08-13T08-35-41Z" \
|
||||||
|
-o /usr/local/bin/mc && sudo chmod +x /usr/local/bin/mc
|
||||||
|
for tool in clang clang++ llvm-ar llvm-nm llvm-ranlib llvm-objcopy llvm-cov llvm-symbolizer lld ld.lld; do
|
||||||
|
sudo update-alternatives --install /usr/bin/${tool} ${tool} /usr/bin/${tool}-21 100
|
||||||
|
done
|
||||||
|
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .ccache
|
||||||
|
key: ccache-coverage-${{ gitea.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
ccache-coverage-
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
|
||||||
|
rm -rf build
|
||||||
|
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_C_FLAGS=--coverage -DCMAKE_CXX_FLAGS=--coverage \
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug -DDISABLE_TSAN=ON
|
||||||
|
ninja -C build
|
||||||
|
ccache -s
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
cd build
|
||||||
|
ctest --no-compress-output --test-output-size-passed 100000 --test-output-size-failed 100000 -T Test -j "$(nproc)" --timeout 90 > /dev/null
|
||||||
|
|
||||||
|
- name: Coverage report
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
gcov_args=(-f ConflictSet.cpp -f LongestCommonPrefix.h -f Metrics.h
|
||||||
|
--gcov-executable "llvm-cov gcov" --exclude-noncode-lines)
|
||||||
|
gcovr "${gcov_args[@]}" --cobertura > build/coverage.xml
|
||||||
|
gcovr "${gcov_args[@]}"
|
||||||
|
mkdir -p build/coverage_html
|
||||||
|
gcovr "${gcov_args[@]}" --html-details build/coverage_html/index.html
|
||||||
|
gcovr "${gcov_args[@]}" --fail-under-line 100 > /dev/null
|
||||||
|
|
||||||
|
- name: Upload results to MinIO
|
||||||
|
if: always()
|
||||||
|
env:
|
||||||
|
MINIO_ACCESS_KEY: ${{ secrets.MINIO_ACCESS_KEY }}
|
||||||
|
MC_HOST_minio: https://${{ secrets.MINIO_ACCESS_KEY }}:${{ secrets.MINIO_SECRET_KEY }}@minio.weaselab.dev
|
||||||
|
run: |
|
||||||
|
if [ -z "$MINIO_ACCESS_KEY" ]; then
|
||||||
|
echo "MinIO credentials not configured; skipping upload"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
dest="minio/jenkins/conflict-set/${{ gitea.run_number }}/coverage/"
|
||||||
|
zstd build/Testing/*/Test.xml
|
||||||
|
mc cp build/Testing/*/Test.xml.zst "$dest"
|
||||||
|
if [ -e build/coverage.xml ]; then
|
||||||
|
mc cp build/coverage.xml "$dest"
|
||||||
|
fi
|
||||||
|
if [ -d build/coverage_html ]; then
|
||||||
|
mc cp -r build/coverage_html "$dest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Test summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
python3 ctest_summary.py build/Testing/*/Test.xml \
|
||||||
|
--link "https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/coverage/Test.xml.zst" \
|
||||||
|
| tee -a "$GITHUB_STEP_SUMMARY"
|
||||||
|
echo "" | tee -a "$GITHUB_STEP_SUMMARY"
|
||||||
|
echo "📊 [Coverage report](https://minio.weaselab.dev/jenkins/conflict-set/${{ gitea.run_number }}/coverage/coverage_html/index.html)" | tee -a "$GITHUB_STEP_SUMMARY"
|
||||||
+1
-1
@@ -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.13
|
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"
|
||||||
|
|||||||
+6
-1
@@ -3648,7 +3648,12 @@ ConflictSet::ConflictSet(ConflictSet &&other) noexcept
|
|||||||
: impl(std::exchange(other.impl, nullptr)) {}
|
: impl(std::exchange(other.impl, nullptr)) {}
|
||||||
|
|
||||||
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
|
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
|
||||||
impl = std::exchange(other.impl, nullptr);
|
if (this != &other) {
|
||||||
|
if (impl) {
|
||||||
|
internal_destroy(impl);
|
||||||
|
}
|
||||||
|
impl = std::exchange(other.impl, nullptr);
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -119,7 +119,13 @@ ConflictSet::ConflictSet(ConflictSet &&other) noexcept
|
|||||||
: impl(std::exchange(other.impl, nullptr)) {}
|
: impl(std::exchange(other.impl, nullptr)) {}
|
||||||
|
|
||||||
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
|
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
|
||||||
impl = std::exchange(other.impl, nullptr);
|
if (this != &other) {
|
||||||
|
if (impl) {
|
||||||
|
impl->~Impl();
|
||||||
|
safe_free(impl, sizeof(Impl));
|
||||||
|
}
|
||||||
|
impl = std::exchange(other.impl, nullptr);
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ longestCommonPrefix(const uint8_t *ap, const uint8_t *bp, int cl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int end;
|
int end; // GCOVR_EXCL_LINE
|
||||||
|
|
||||||
// kStride * kUnrollCount at a time
|
// kStride * kUnrollCount at a time
|
||||||
end = cl & ~(kStride * kUnrollFactor - 1);
|
end = cl & ~(kStride * kUnrollFactor - 1);
|
||||||
|
|||||||
@@ -2,7 +2,16 @@ A data structure for optimistic concurrency control on ranges of bitwise-lexicog
|
|||||||
|
|
||||||
Intended as an alternative to FoundationDB's skip list.
|
Intended as an alternative to FoundationDB's skip list.
|
||||||
|
|
||||||
Hardware for all benchmarks is an AMD Ryzen 9 7900 with (2x32GB) 5600MT/s CL28-34-34-89 1.35V RAM
|
Hardware for all benchmarks is an AMD Ryzen 9 7900 with (2x32GB) 5600MT/s CL28-34-34-89 1.35V RAM.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ clang++ --version
|
||||||
|
|
||||||
|
Ubuntu clang version 21.1.8 (6ubuntu1)
|
||||||
|
Target: x86_64-pc-linux-gnu
|
||||||
|
Thread model: posix
|
||||||
|
InstalledDir: /usr/lib/llvm-21/bin
|
||||||
|
```
|
||||||
|
|
||||||
# Microbenchmark
|
# Microbenchmark
|
||||||
|
|
||||||
@@ -10,44 +19,45 @@ 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
|
||||||
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
||||||
| 172.03 | 5,812,791.77 | 0.4% | 3,130.62 | 879.00 | 3.562 | 509.23 | 0.0% | 0.01 | `point reads`
|
| 171.37 | 5,835,467.28 | 0.5% | 2,915.46 | 629.31 | 4.633 | 502.91 | 0.0% | 0.01 | `point reads`
|
||||||
| 167.44 | 5,972,130.71 | 0.2% | 3,065.14 | 862.27 | 3.555 | 494.30 | 0.0% | 0.01 | `prefix reads`
|
| 168.16 | 5,946,774.62 | 0.5% | 2,859.73 | 619.03 | 4.620 | 488.59 | 0.0% | 0.01 | `prefix reads`
|
||||||
| 238.77 | 4,188,130.84 | 0.9% | 3,589.93 | 1,259.30 | 2.851 | 637.12 | 0.0% | 0.01 | `range reads`
|
| 245.86 | 4,067,294.63 | 0.3% | 3,508.97 | 904.82 | 3.878 | 627.73 | 0.0% | 0.01 | `range reads`
|
||||||
| 424.01 | 2,358,426.70 | 0.2% | 5,620.05 | 2,242.35 | 2.506 | 854.80 | 1.7% | 0.01 | `point writes`
|
| 381.14 | 2,623,691.76 | 0.2% | 5,127.16 | 1,402.60 | 3.655 | 830.59 | 1.7% | 0.01 | `point writes`
|
||||||
| 418.45 | 2,389,780.56 | 0.4% | 5,525.07 | 2,211.05 | 2.499 | 831.71 | 1.7% | 0.01 | `prefix writes`
|
| 376.24 | 2,657,887.07 | 0.3% | 5,062.85 | 1,381.07 | 3.666 | 811.68 | 1.6% | 0.01 | `prefix writes`
|
||||||
| 254.87 | 3,923,568.88 | 2.6% | 3,187.01 | 1,366.50 | 2.332 | 529.11 | 2.7% | 0.02 | `range writes`
|
| 257.09 | 3,889,688.44 | 3.8% | 3,010.09 | 949.42 | 3.170 | 521.34 | 2.9% | 0.01 | `range writes`
|
||||||
| 675.96 | 1,479,374.50 | 3.3% | 7,735.41 | 3,468.60 | 2.230 | 1,386.02 | 1.8% | 0.01 | `monotonic increasing point writes`
|
| 629.71 | 1,588,026.28 | 4.0% | 6,809.60 | 2,320.32 | 2.935 | 1,247.08 | 1.3% | 0.01 | `monotonic increasing point writes`
|
||||||
| 137,986.20 | 7,247.10 | 0.6% | 789,752.33 | 699,462.00 | 1.129 | 144,824.14 | 0.0% | 0.01 | `worst case for radix tree`
|
| 126,164.50 | 7,926.16 | 1.7% | 772,460.25 | 463,264.67 | 1.667 | 141,512.00 | 0.2% | 0.01 | `worst case for radix tree`
|
||||||
| 21.63 | 46,231,564.03 | 1.0% | 448.00 | 107.14 | 4.181 | 84.00 | 0.0% | 0.01 | `create and destroy`
|
| 15.33 | 65,217,669.23 | 0.4% | 299.00 | 56.45 | 5.297 | 64.00 | 0.0% | 0.01 | `create and destroy`
|
||||||
|
|
||||||
## Radix tree (this implementation)
|
## Radix tree (this implementation)
|
||||||
|
|
||||||
|
|
||||||
| 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
|
||||||
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:----------
|
||||||
| 11.18 | 89,455,125.34 | 0.6% | 185.37 | 57.08 | 3.248 | 41.51 | 0.4% | 0.01 | `point reads`
|
| 12.81 | 78,088,759.03 | 0.7% | 187.38 | 47.15 | 3.974 | 33.70 | 0.5% | 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`
|
| 16.77 | 59,626,501.14 | 0.4% | 277.61 | 61.74 | 4.497 | 44.76 | 0.4% | 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`
|
| 42.45 | 23,556,818.87 | 0.4% | 856.96 | 156.09 | 5.490 | 126.22 | 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`
|
| 15.76 | 63,453,196.94 | 0.3% | 249.89 | 58.04 | 4.306 | 33.21 | 0.5% | 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`
|
| 29.71 | 33,662,499.39 | 0.1% | 509.14 | 109.33 | 4.657 | 70.26 | 0.5% | 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`
|
| 35.77 | 27,956,388.03 | 0.8% | 614.18 | 131.72 | 4.663 | 85.57 | 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`
|
| 80.13 | 12,480,456.47 | 1.5% | 1,279.04 | 294.90 | 4.337 | 234.68 | 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`
|
| 360,748.00 | 2,772.02 | 2.6% | 4,401,835.00 | 1,318,754.00 | 3.338 | 728,537.00 | 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`
|
| 90.69 | 11,027,103.45 | 1.0% | 1,686.00 | 333.80 | 5.051 | 284.00 | 0.0% | 0.01 | `create and destroy`
|
||||||
|
|
||||||
# "Real data" test
|
# "Real data" test
|
||||||
|
|
||||||
Point queries only, best of three runs. Gc ratio is the ratio of time spent doing garbage collection to time spent adding writes or doing garbage collection. Lower is better.
|
Point queries only. Gc ratio is the ratio of time spent doing garbage collection to time spent adding writes or doing garbage collection. Lower is better.
|
||||||
|
|
||||||
## skip list
|
## skip list
|
||||||
|
|
||||||
```
|
```
|
||||||
Check: 4.47891 seconds, 364.05 MB/s, Add: 4.55599 seconds, 123.058 MB/s, Gc ratio: 37.1145%
|
Check: 4.42779 seconds, 368.253 MB/s, Add: 4.64942 seconds, 120.586 MB/s, Gc ratio: 28.8784%, Peak idle memory: 5.51735e+06
|
||||||
```
|
```
|
||||||
|
|
||||||
## radix tree
|
## radix tree
|
||||||
|
|
||||||
```
|
```
|
||||||
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
|
Check: 0.891163 seconds, 1829.69 MB/s, Add: 1.23064 seconds, 455.579 MB/s, Gc ratio: 42.9417%, Peak idle memory: 2.28333e+06
|
||||||
```
|
```
|
||||||
|
|
||||||
## hash table
|
## hash table
|
||||||
@@ -55,5 +65,6 @@ Check: 0.953012 seconds, 1710.94 MB/s, Add: 1.30025 seconds, 431.188 MB/s, Gc ra
|
|||||||
(The hash table implementation doesn't work on range queries, and its purpose is to provide an idea of how fast point queries can be)
|
(The hash table implementation doesn't work on range queries, and its purpose is to provide an idea of how fast point queries can be)
|
||||||
|
|
||||||
```
|
```
|
||||||
Check: 0.804094 seconds, 2027.81 MB/s, Add: 0.652952 seconds, 858.645 MB/s, Gc ratio: 35.3885%
|
Check: 0.858484 seconds, 1899.33 MB/s, Add: 0.632886 seconds, 885.868 MB/s, Gc ratio: 41.252%, Peak idle memory: 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -903,7 +903,12 @@ ConflictSet::ConflictSet(ConflictSet &&other) noexcept
|
|||||||
: impl(std::exchange(other.impl, nullptr)) {}
|
: impl(std::exchange(other.impl, nullptr)) {}
|
||||||
|
|
||||||
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
|
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
|
||||||
impl = std::exchange(other.impl, nullptr);
|
if (this != &other) {
|
||||||
|
if (impl) {
|
||||||
|
internal_destroy(impl);
|
||||||
|
}
|
||||||
|
impl = std::exchange(other.impl, nullptr);
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Summarize a CTest Test.xml as markdown.
|
||||||
|
|
||||||
|
Intended for $GITHUB_STEP_SUMMARY in CI, where only the first few failures
|
||||||
|
are shown inline (pass --link to point at the full Test.xml). Also reusable
|
||||||
|
locally to print every failure from a downloaded Test.xml with --all.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import base64
|
||||||
|
import gzip
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
# Failure output is truncated to this many trailing characters, which is
|
||||||
|
# usually enough to include e.g. an ASan report's summary.
|
||||||
|
OUTPUT_TAIL_CHARS = 3000
|
||||||
|
|
||||||
|
|
||||||
|
def test_output(test):
|
||||||
|
value = test.find("./Results/Measurement/Value")
|
||||||
|
if value is None or value.text is None:
|
||||||
|
return ""
|
||||||
|
text = value.text
|
||||||
|
if value.get("encoding") == "base64":
|
||||||
|
raw = base64.b64decode(text)
|
||||||
|
if value.get("compression") == "gzip":
|
||||||
|
raw = gzip.decompress(raw)
|
||||||
|
text = raw.decode(errors="replace")
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("test_xml", help="path to a ctest Testing/*/Test.xml")
|
||||||
|
parser.add_argument(
|
||||||
|
"--inline",
|
||||||
|
type=int,
|
||||||
|
default=5,
|
||||||
|
help="how many failures to show inline (default 5)",
|
||||||
|
)
|
||||||
|
parser.add_argument("--all", action="store_true", help="show every failure inline")
|
||||||
|
parser.add_argument(
|
||||||
|
"--link", help="URL of the full Test.xml, linked when failures are elided"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
testing = ET.parse(args.test_xml).getroot().find("Testing")
|
||||||
|
tests = testing.findall("Test")
|
||||||
|
failed = [t for t in tests if t.get("Status") == "failed"]
|
||||||
|
notrun = sum(1 for t in tests if t.get("Status") == "notrun")
|
||||||
|
|
||||||
|
if not failed:
|
||||||
|
print(f"✅ All {len(tests) - notrun} tests passed")
|
||||||
|
else:
|
||||||
|
print(f"❌ {len(failed)} of {len(tests)} tests failed\n")
|
||||||
|
shown = failed if args.all else failed[: args.inline]
|
||||||
|
for test in shown:
|
||||||
|
name = test.findtext("Name")
|
||||||
|
output = test_output(test)[-OUTPUT_TAIL_CHARS:].strip()
|
||||||
|
print(f"<details><summary><code>{name}</code></summary>\n")
|
||||||
|
print("````")
|
||||||
|
print(output)
|
||||||
|
print("````")
|
||||||
|
print("</details>\n")
|
||||||
|
remaining = len(failed) - len(shown)
|
||||||
|
if remaining > 0:
|
||||||
|
more = f"… and {remaining} more"
|
||||||
|
if args.link:
|
||||||
|
more += f" — full list in [Test.xml]({args.link})"
|
||||||
|
print(more)
|
||||||
|
if notrun:
|
||||||
|
print(f"\n⚠️ {notrun} tests not run")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user