51 Commits

Author SHA1 Message Date
a40b5dcd74 Add script to build .pkg file for macos
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-08 15:21:40 -07:00
193b1926ff Fix python type annotation
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-07 22:28:40 -07:00
1c900c5a8c Use PRE_LINK
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
According to
https://cmake.org/cmake/help/latest/command/add_custom_command.html this
more accurately matches the intent
2024-04-04 17:03:57 -07:00
90fdcdd51a Don't update mtime in privatize_symbols_macos.sh
It confuses ninja and we see things like the following:

ninja explain: stored deps info out of date for 'CMakeFiles/conflict-set-object.dir/ConflictSet.cpp.o' (1712275080328387291 vs 1712275080349012981)
2024-04-04 17:02:51 -07:00
eb3f6823eb Remove prettier
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
It caused a weird jenkins error trying to look at /etc/passwd. Not worth
the trouble for formatting yaml and md, which I'm barely using.
2024-04-04 16:29:26 -07:00
1534e10b75 Fix macos shared library name in conflict_set.py
Some checks failed
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-04-04 16:17:06 -07:00
3c100ccee8 Add prettier and black as pre-commit hooks
Some checks failed
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-04-04 15:59:27 -07:00
5cf45d1c35 Preliminary support for writing tests in python 2024-04-04 15:58:57 -07:00
4f97932893 Bump version
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-04 12:02:01 -07:00
24b0f6b7e4 Add missing _GLOBAL_OFFSET_TABLE_ symbol
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-04 11:36:32 -07:00
e77c3fdee6 Adding missing memset import 2024-04-04 11:35:44 -07:00
383b956bc0 Set debian libc6 dep precisely
Some checks failed
Tests / Clang total: 1096, failed: 2, passed: 1094
Tests / SIMD fallback total: 1096, failed: 2, passed: 1094
Tests / Release [gcc] total: 1096, failed: 1, passed: 1095
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-04-04 11:12:41 -07:00
5fad15305a Track x64 and arm imports in separate files 2024-04-04 11:04:26 -07:00
ad91fb36a5 Symbol tests for macos + whitelist imports/exports
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
commit 1ad8276100
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:44:35 2024 -0700

    Add symbols for arm build

commit 058e4d5302
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:42:48 2024 -0700

    Add _GLOBAL_OFFSET_TABLE_

commit a201f3ada8
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:34:05 2024 -0700

    Add memset to symbol imports

commit c1129ed0e2
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:32:28 2024 -0700

    Add symbol imports file

commit 618766ce2e
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:27:07 2024 -0700

    Fix objcopy filepath

commit e774a90007
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:24:44 2024 -0700

    Use shellcheck precommit without docker

commit baddea7f57
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:20:26 2024 -0700

    Update and freeze pre-commit hooks

commit 2d3e7b9004
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:19:55 2024 -0700

    Add shellcheck to pre-commit

    Closes #22

commit c4862fee9b
Author: Andrew Noyes <andrew@weaselab.dev>
Date:   Wed Apr 3 12:15:08 2024 -0700

    Add symbol tests for apple

    closes #21
2024-04-03 12:50:51 -07:00
38c1481432 Make visibility=hidden symbols private on macos
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-02 18:30:17 -07:00
771ae896e7 Check that -msimd128 flag is valid 2024-04-02 15:48:18 -07:00
5bf72bda61 Don't treat full_relro_flags as all one flag
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-02 14:20:22 -07:00
a534f3b758 Conditionally add -pie
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-02 14:15:11 -07:00
ae4fa889c7 Partial support for wasi-sdk
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-02 12:14:04 -07:00
e3d3b0ec0d objcopy doesn't support --keep-global-symbols for wasm
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-04-02 12:09:01 -07:00
dea8d6ae01 Align ArenaImpl allocation to alignof(ArenaImpl)
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
Fixes #20
2024-04-01 17:31:16 -07:00
dbc6f2313a Add missing cerrno include 2024-04-01 17:21:43 -07:00
4f51878642 Add -msimd128 if USE_SIMD_FALLBACK=OFF
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-30 17:57:50 -07:00
215865a462 Experimental wasm support 2024-03-30 16:20:55 -07:00
348ebf016a Enable relro for shared lib
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-29 21:51:02 -07:00
377259ffa0 Unsuppress -Wmaybe-uninitialized
I don't see the warning anymore locally
2024-03-29 18:57:43 -07:00
70220d95e7 Bump version
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-29 16:23:09 -07:00
71c39f9955 Opt-in to rpm/deb default package filenames
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-29 15:56:58 -07:00
8cc17158fd Fix preprocessing instructions for linux
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-28 14:58:29 -07:00
ab211c646a Apply compiler-appeasing syntax changes from Taoxi 2024-03-28 14:57:31 -07:00
7af961f141 Fix jenkins build
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-28 11:44:01 -07:00
a91df62608 Add USE_SIMD_FALLBACK build in jenkins
Some checks failed
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / SIMD fallback total: 1096, passed: 1096
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-03-28 11:33:53 -07:00
0a1843a161 Add USE_SIMD_FALLBACK
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-28 11:12:50 -07:00
4edf0315d9 Find insertion point for Node16 with simd
Closes #13
2024-03-28 10:47:20 -07:00
14515e186a Update readme benchmarks again
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
I think the last skiplisttest benchmark looked bad because I had vscode
+ firefox + ?? open
2024-03-27 16:47:36 -07:00
b0085df5ad Update symbols.txt
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-27 16:29:30 -07:00
76a7e17b29 Update readme benchmarks
Some checks failed
Tests / Clang total: 1096, failed: 2, passed: 1094
Tests / Release [gcc] total: 1096, failed: 2, passed: 1094
Tests / Release [gcc,aarch64] total: 824, failed: 2, passed: 822
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head There was a failure building this commit
I was incorrectly linking to an old build of conflict set, before the
conflict-set name change. I don't know what the regression is from, but
update the README for transparency now.
2024-03-27 16:12:45 -07:00
5cf43d1bfa Add weaselab namespace 2024-03-27 16:07:05 -07:00
25cc427ec5 Assert safe_free size is correct in debug builds
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
Closes #16
2024-03-27 15:34:24 -07:00
c15c2e7b44 Remove redundant static assert
Closes #14
2024-03-27 12:41:45 -07:00
a4d1f91670 Update README benchmark after adding getBytes
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-20 16:26:05 -07:00
b7cdecaf71 Document thread-safety in terms of constness 2024-03-20 16:16:15 -07:00
cda28643a6 Fix ConflictSet_getBytes 2024-03-20 16:15:43 -07:00
cdb5360b9a Allow _GLOBAL_OFFSET_TABLE_ usage
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-20 12:39:18 -07:00
ef224a60f4 Allow use of __tls_get_addr
Some checks failed
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, failed: 1, passed: 1095
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head There was a failure building this commit
2024-03-20 12:29:18 -07:00
6222b74787 Fix tests
Some checks failed
Tests / Clang total: 1096, failed: 2, passed: 1094
Tests / Release [gcc] total: 1096, failed: 2, passed: 1094
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head There was a failure building this commit
Add the new symbol, and update the valgrind client request so that
Node::partialKeyCapacity is defined.
2024-03-20 12:21:59 -07:00
19edc6f78f Interface change! Add ConflictSet::getBytes
Some checks failed
Tests / Clang total: 1096, failed: 3, passed: 1093
Tests / Release [gcc] total: 1096, failed: 2, passed: 1094
Tests / Release [gcc,aarch64] total: 824, failed: 1, passed: 823
Tests / Coverage total: 823, failed: 1, passed: 822
weaselab/conflict-set/pipeline/head There was a failure building this commit
Closes #12
2024-03-20 12:11:34 -07:00
3f9d01c46a Users will now do find_package(conflict-set)
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-19 19:05:54 -07:00
db03c6f901 Fix invalid package name for debian
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
2024-03-19 17:43:58 -07:00
c1698b040b Disable tsan for debug builds
All checks were successful
Tests / Clang total: 1096, passed: 1096
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc] total: 1096, passed: 1096
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 824, passed: 824
Tests / Coverage total: 823, passed: 823
weaselab/conflict-set/pipeline/head This commit looks good
Too slow
2024-03-19 16:54:29 -07:00
2e08b54785 Update README.md with 1.0 benchmarks
Some checks reported errors
weaselab/conflict-set/pipeline/head Something is wrong with the build of this commit
Closes #7
2024-03-19 16:41:59 -07:00
26 changed files with 780 additions and 318 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
.cache .cache
__pycache__
build build

View File

@@ -1,11 +1,11 @@
repos: repos:
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: b111689e7b5cba60be3c62d5db2bd1357f4d36ca rev: 6d365699efc33b1b432eab5b4ae331a19e1857de # frozen: v18.1.2
hooks: hooks:
- id: clang-format - id: clang-format
exclude: ".*third_party/.*" exclude: ".*third_party/.*"
- repo: https://github.com/cheshirekow/cmake-format-precommit - repo: https://github.com/cheshirekow/cmake-format-precommit
rev: e2c2116d86a80e72e7146a06e68b7c228afc6319 rev: e2c2116d86a80e72e7146a06e68b7c228afc6319 # frozen: v0.6.13
hooks: hooks:
- id: cmake-format - id: cmake-format
- repo: local - repo: local
@@ -13,7 +13,7 @@ repos:
- id: debug verbose check - id: debug verbose check
name: disallow checking in DEBUG_VERBOSE=1 name: disallow checking in DEBUG_VERBOSE=1
description: disallow checking in DEBUG_VERBOSE=1 description: disallow checking in DEBUG_VERBOSE=1
entry: '^#define DEBUG_VERBOSE 1$' entry: "^#define DEBUG_VERBOSE 1$"
language: pygrep language: pygrep
types: [c++] types: [c++]
- repo: local - repo: local
@@ -21,6 +21,14 @@ repos:
- id: debug verbose check - id: debug verbose check
name: disallow checking in SHOW_MEMORY=1 name: disallow checking in SHOW_MEMORY=1
description: disallow checking in SHOW_MEMORY=1 description: disallow checking in SHOW_MEMORY=1
entry: '^#define SHOW_MEMORY 1$' entry: "^#define SHOW_MEMORY 1$"
language: pygrep language: pygrep
types: [c++] types: [c++]
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: a23f6b85d0fdd5bb9d564e2579e678033debbdff # frozen: v0.10.0.1
hooks:
- id: shellcheck
- repo: https://github.com/psf/black
rev: 552baf822992936134cbd31a38f69c8cfe7c0f05 # frozen: 24.3.0
hooks:
- id: black

View File

@@ -34,7 +34,7 @@ ConflictSet::ReadRange singleton(Arena &arena, std::span<const uint8_t> key) {
std::span<uint8_t>(new (arena) uint8_t[key.size() + 1], key.size() + 1); std::span<uint8_t>(new (arena) uint8_t[key.size() + 1], key.size() + 1);
memcpy(r.data(), key.data(), key.size()); memcpy(r.data(), key.data(), key.size());
r[key.size()] = 0; r[key.size()] = 0;
return {key.data(), int(key.size()), r.data(), int(r.size())}; return {{key.data(), int(key.size())}, {r.data(), int(r.size())}, 0};
} }
ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) { ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) {
@@ -52,7 +52,7 @@ ConflictSet::ReadRange prefixRange(Arena &arena, std::span<const uint8_t> key) {
auto r = std::span<uint8_t>(new (arena) uint8_t[index + 1], index + 1); auto r = std::span<uint8_t>(new (arena) uint8_t[index + 1], index + 1);
memcpy(r.data(), key.data(), index + 1); memcpy(r.data(), key.data(), index + 1);
r[r.size() - 1]++; r[r.size() - 1]++;
return {key.data(), int(key.size()), r.data(), int(r.size())}; return {{key.data(), int(key.size())}, {r.data(), int(r.size())}, 0};
} }
void benchConflictSet() { void benchConflictSet() {

View File

@@ -1,15 +1,28 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.18)
project( project(
conflict_set conflict-set
VERSION 0.0.1 VERSION 0.0.3
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"
LANGUAGES C CXX) LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
file(WRITE ${CMAKE_BINARY_DIR}/version.txt ${PROJECT_VERSION})
include(CMakePushCheckState)
include(CheckCXXCompilerFlag)
include(CheckIncludeFileCXX)
include(CheckCXXSourceCompiles)
set(DEFAULT_BUILD_TYPE "Release") set(DEFAULT_BUILD_TYPE "Release")
if(EMSCRIPTEN OR CMAKE_SYSTEM_NAME STREQUAL WASI)
set(WASM ON)
else()
set(WASM OFF)
endif()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message( message(
STATUS STATUS
@@ -23,16 +36,32 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
endif() endif()
add_compile_options(-fdata-sections -ffunction-sections -Wswitch-enum add_compile_options(-fdata-sections -ffunction-sections -Wswitch-enum
-Werror=switch-enum) -Werror=switch-enum -fPIC)
set(full_relro_flags "-pie;LINKER:-z,relro,-z,now,-z,noexecstack")
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${full_relro_flags})
check_cxx_source_compiles("int main(){}" HAS_FULL_RELRO FAIL_REGEX "warning:")
if(HAS_FULL_RELRO)
add_link_options(${full_relro_flags})
endif()
cmake_pop_check_state()
set(version_script_flags LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${version_script_flags})
check_cxx_source_compiles("int main(){}" HAS_VERSION_SCRIPT FAIL_REGEX
"warning:")
cmake_pop_check_state()
option(USE_SIMD_FALLBACK
"Use fallback implementations of functions that use SIMD" OFF)
# This is encouraged according to # This is encouraged according to
# https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq # https://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq
include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/third_party/valgrind) include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/third_party/valgrind)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
add_compile_options(-Wno-maybe-uninitialized
$<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
endif()
if(APPLE) if(APPLE)
add_link_options(-Wl,-dead_strip) add_link_options(-Wl,-dead_strip)
@@ -40,32 +69,46 @@ else()
add_link_options(-Wl,--gc-sections) add_link_options(-Wl,--gc-sections)
endif() endif()
include(CheckIncludeFileCXX) if(EMSCRIPTEN)
include(CMakePushCheckState) # https://github.com/emscripten-core/emscripten/issues/15377#issuecomment-1285167486
add_link_options(-lnodefs.js -lnoderawfs.js)
cmake_push_check_state() add_link_options(-s ALLOW_MEMORY_GROWTH)
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
check_include_file_cxx("immintrin.h" HAS_AVX)
if(HAS_AVX)
add_compile_options(-mavx)
add_compile_definitions(HAS_AVX)
endif() endif()
cmake_pop_check_state()
check_include_file_cxx("arm_neon.h" HAS_ARM_NEON) if(NOT USE_SIMD_FALLBACK)
if(HAS_ARM_NEON) cmake_push_check_state()
add_compile_definitions(HAS_ARM_NEON) list(APPEND CMAKE_REQUIRED_FLAGS -msimd128)
check_include_file_cxx("wasm_simd128.h" HAS_WASM_SIMD)
if(HAS_WASM_SIMD)
add_compile_options(-msimd128)
add_compile_definitions(HAS_WASM_SIMD)
endif()
cmake_pop_check_state()
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_FLAGS -mavx)
check_include_file_cxx("immintrin.h" HAS_AVX)
if(HAS_AVX)
add_compile_options(-mavx)
add_compile_definitions(HAS_AVX)
endif()
cmake_pop_check_state()
check_include_file_cxx("arm_neon.h" HAS_ARM_NEON)
if(HAS_ARM_NEON)
add_compile_definitions(HAS_ARM_NEON)
endif()
endif() endif()
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "") set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
add_library(${PROJECT_NAME}_object OBJECT ConflictSet.cpp) add_library(${PROJECT_NAME}-object OBJECT ConflictSet.cpp)
target_compile_options(${PROJECT_NAME}_object PRIVATE -fPIC -fno-exceptions target_compile_options(${PROJECT_NAME}-object PRIVATE -fno-exceptions
-fvisibility=hidden) -fvisibility=hidden)
target_include_directories(${PROJECT_NAME}_object target_include_directories(${PROJECT_NAME}-object
PRIVATE ${CMAKE_SOURCE_DIR}/include) PRIVATE ${CMAKE_SOURCE_DIR}/include)
add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:${PROJECT_NAME}_object>) add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
set_target_properties( set_target_properties(
${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}/radix_tree") "${CMAKE_BINARY_DIR}/radix_tree")
@@ -73,24 +116,32 @@ if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C) set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE C)
endif() endif()
if(NOT APPLE) if(HAS_VERSION_SCRIPT)
target_link_options(${PROJECT_NAME} PRIVATE target_link_options(${PROJECT_NAME} PRIVATE
LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map) LINKER:--version-script=${CMAKE_SOURCE_DIR}/linker.map)
endif() endif()
add_library(${PROJECT_NAME}_static STATIC add_library(${PROJECT_NAME}-static STATIC
$<TARGET_OBJECTS:${PROJECT_NAME}_object>) $<TARGET_OBJECTS:${PROJECT_NAME}-object>)
if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) if(NOT CMAKE_BUILD_TYPE STREQUAL Debug)
set_target_properties(${PROJECT_NAME}_static PROPERTIES LINKER_LANGUAGE C) set_target_properties(${PROJECT_NAME}-static PROPERTIES LINKER_LANGUAGE C)
endif() endif()
if(NOT APPLE AND CMAKE_OBJCOPY) if(APPLE)
add_custom_command( add_custom_command(
TARGET conflict_set_static TARGET ${PROJECT_NAME}-static
PRE_LINK
COMMAND ${CMAKE_SOURCE_DIR}/privatize_symbols_macos.sh
$<TARGET_OBJECTS:${PROJECT_NAME}-object>)
else()
add_custom_command(
TARGET ${PROJECT_NAME}-static
POST_BUILD POST_BUILD
COMMAND COMMAND
${CMAKE_OBJCOPY} --keep-global-symbols=${CMAKE_SOURCE_DIR}/symbols.txt ${CMAKE_OBJCOPY}
$<TARGET_FILE:${PROJECT_NAME}_static>) --keep-global-symbols=${CMAKE_SOURCE_DIR}/symbol-exports.txt
$<TARGET_FILE:${PROJECT_NAME}-static> || echo
"Proceeding with all symbols global in static library")
endif() endif()
set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG) set(TEST_FLAGS -Wall -Wextra -Wunreachable-code -Wpedantic -UNDEBUG)
@@ -99,30 +150,51 @@ include(CTest)
if(BUILD_TESTING) if(BUILD_TESTING)
# Shared library version of FoundationDB's skip list implementation # corpus tests, which are tests curated by libfuzzer. The goal is to get broad
add_library(skip_list SHARED SkipList.cpp) # coverage with a small number of tests.
target_compile_options(skip_list PRIVATE -fPIC -fno-exceptions
-fvisibility=hidden)
target_include_directories(skip_list PUBLIC ${CMAKE_SOURCE_DIR}/include)
set_target_properties(skip_list PROPERTIES LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}/skip_list")
set_target_properties(skip_list PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
set_target_properties(skip_list PROPERTIES VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR})
# Shared library version of a std::unordered_map-based conflict set (point file(GLOB CORPUS_TESTS ${CMAKE_SOURCE_DIR}/corpus/*)
# queries only)
add_library(hash_table SHARED HashTable.cpp)
target_compile_options(hash_table PRIVATE -fPIC -fno-exceptions
-fvisibility=hidden)
target_include_directories(hash_table PUBLIC ${CMAKE_SOURCE_DIR}/include)
set_target_properties(hash_table PROPERTIES LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}/hash_table")
set_target_properties(hash_table PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
set_target_properties(
hash_table PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
${PROJECT_VERSION_MAJOR})
# extra testing that relies on shared libraries, which aren't available with
# wasm
if(NOT WASM)
# Shared library version of FoundationDB's skip list implementation
add_library(skip_list SHARED SkipList.cpp)
target_compile_options(skip_list PRIVATE -fno-exceptions
-fvisibility=hidden)
target_include_directories(skip_list PUBLIC ${CMAKE_SOURCE_DIR}/include)
set_target_properties(skip_list PROPERTIES LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}/skip_list")
set_target_properties(skip_list PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
set_target_properties(
skip_list PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
${PROJECT_VERSION_MAJOR})
# Shared library version of a std::unordered_map-based conflict set (point
# queries only)
add_library(hash_table SHARED HashTable.cpp)
target_compile_options(hash_table PRIVATE -fno-exceptions
-fvisibility=hidden)
target_include_directories(hash_table PUBLIC ${CMAKE_SOURCE_DIR}/include)
set_target_properties(
hash_table PROPERTIES LIBRARY_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}/hash_table")
set_target_properties(hash_table PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
set_target_properties(
hash_table PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION
${PROJECT_VERSION_MAJOR})
add_executable(driver_skip_list TestDriver.cpp)
target_compile_options(driver_skip_list PRIVATE ${TEST_FLAGS})
target_link_libraries(driver_skip_list PRIVATE skip_list)
foreach(TEST ${CORPUS_TESTS})
get_filename_component(hash ${TEST} NAME)
add_test(NAME skip_list_${hash} COMMAND driver_skip_list ${TEST})
endforeach()
endif()
# ad hoc testing
add_executable(conflict_set_main ConflictSet.cpp) add_executable(conflict_set_main ConflictSet.cpp)
target_include_directories(conflict_set_main target_include_directories(conflict_set_main
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
@@ -149,10 +221,7 @@ if(BUILD_TESTING)
endif() endif()
endif() endif()
# corpus tests # whitebox tests
file(GLOB CORPUS_TESTS ${CMAKE_SOURCE_DIR}/corpus/*)
add_executable(fuzz_driver ConflictSet.cpp FuzzTestDriver.cpp) add_executable(fuzz_driver ConflictSet.cpp FuzzTestDriver.cpp)
target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS}) target_compile_options(fuzz_driver PRIVATE ${TEST_FLAGS})
if(NOT CMAKE_CROSSCOMPILING) if(NOT CMAKE_CROSSCOMPILING)
@@ -167,9 +236,8 @@ if(BUILD_TESTING)
add_test(NAME conflict_set_fuzz_${hash} COMMAND fuzz_driver ${TEST}) add_test(NAME conflict_set_fuzz_${hash} COMMAND fuzz_driver ${TEST})
endforeach() endforeach()
# tsan # tsan tests
if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
if(NOT CMAKE_CROSSCOMPILING)
add_executable(tsan_driver ConflictSet.cpp FuzzTestDriver.cpp) add_executable(tsan_driver ConflictSet.cpp FuzzTestDriver.cpp)
target_compile_options(tsan_driver PRIVATE ${TEST_FLAGS} -fsanitize=thread) target_compile_options(tsan_driver PRIVATE ${TEST_FLAGS} -fsanitize=thread)
target_link_options(tsan_driver PRIVATE -fsanitize=thread) target_link_options(tsan_driver PRIVATE -fsanitize=thread)
@@ -182,24 +250,26 @@ if(BUILD_TESTING)
endforeach() endforeach()
endif() endif()
# blackbox tests
add_executable(driver TestDriver.cpp) add_executable(driver TestDriver.cpp)
target_compile_options(driver PRIVATE ${TEST_FLAGS}) target_compile_options(driver PRIVATE ${TEST_FLAGS})
target_link_libraries(driver PRIVATE ${PROJECT_NAME}) target_link_libraries(driver PRIVATE ${PROJECT_NAME})
foreach(TEST ${CORPUS_TESTS})
get_filename_component(hash ${TEST} NAME)
add_test(NAME conflict_set_blackbox_${hash} COMMAND driver ${TEST})
endforeach()
# scripted tests. Written manually to fill in anything libfuzzer couldn't
# find.
add_executable(script_test ScriptTest.cpp) add_executable(script_test ScriptTest.cpp)
target_compile_options(script_test PRIVATE ${TEST_FLAGS}) target_compile_options(script_test PRIVATE ${TEST_FLAGS})
target_link_libraries(script_test PRIVATE ${PROJECT_NAME}) target_link_libraries(script_test PRIVATE ${PROJECT_NAME})
file(GLOB SCRIPT_TESTS ${CMAKE_SOURCE_DIR}/script_tests/*) file(GLOB SCRIPT_TESTS ${CMAKE_SOURCE_DIR}/script_tests/*)
foreach(TEST ${SCRIPT_TESTS}) foreach(TEST ${SCRIPT_TESTS})
get_filename_component(name ${TEST} NAME) get_filename_component(name ${TEST} NAME)
add_test(NAME conflict_set_script_${name} COMMAND script_test ${TEST}) add_test(NAME conflict_set_script_${name} COMMAND script_test ${TEST})
endforeach() endforeach()
add_executable(driver_skip_list TestDriver.cpp)
target_compile_options(driver_skip_list PRIVATE ${TEST_FLAGS})
target_link_libraries(driver_skip_list PRIVATE skip_list)
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 add_test(NAME conflict_set_blackbox_valgrind
@@ -207,12 +277,6 @@ if(BUILD_TESTING)
$<TARGET_FILE:driver> ${CORPUS_TESTS}) $<TARGET_FILE:driver> ${CORPUS_TESTS})
endif() endif()
foreach(TEST ${CORPUS_TESTS})
get_filename_component(hash ${TEST} NAME)
add_test(NAME conflict_set_blackbox_${hash} COMMAND driver ${TEST})
add_test(NAME skip_list_${hash} COMMAND driver_skip_list ${TEST})
endforeach()
# api smoke tests # api smoke tests
# c90 # c90
@@ -233,31 +297,45 @@ if(BUILD_TESTING)
PROPERTIES CXX_STANDARD_REQUIRED ON) PROPERTIES CXX_STANDARD_REQUIRED ON)
add_test(NAME conflict_set_cxx_api_test COMMAND conflict_set_cxx_api_test) add_test(NAME conflict_set_cxx_api_test COMMAND conflict_set_cxx_api_test)
if(NOT APPLE AND NOT CMAKE_BUILD_TYPE STREQUAL Debug) # symbol visibility tests
if(NOT WASM AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
if(APPLE)
set(symbol_exports ${CMAKE_SOURCE_DIR}/apple-symbol-exports.txt)
set(symbol_imports ${CMAKE_SOURCE_DIR}/apple-symbol-imports.txt)
else()
set(symbol_exports ${CMAKE_SOURCE_DIR}/symbol-exports.txt)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
set(symbol_imports ${CMAKE_SOURCE_DIR}/aarch64-symbol-imports.txt)
else()
set(symbol_imports ${CMAKE_SOURCE_DIR}/symbol-imports.txt)
endif()
endif()
add_test( add_test(
NAME conflict_set_shared_symbols NAME conflict_set_shared_symbols
COMMAND ${CMAKE_SOURCE_DIR}/test_symbols.sh COMMAND
$<TARGET_FILE:${PROJECT_NAME}> ${CMAKE_SOURCE_DIR}/symbols.txt) ${CMAKE_SOURCE_DIR}/test_symbols.sh $<TARGET_FILE:${PROJECT_NAME}>
${symbol_exports} ${symbol_imports})
add_test( add_test(
NAME conflict_set_static_symbols NAME conflict_set_static_symbols
COMMAND COMMAND
${CMAKE_SOURCE_DIR}/test_symbols.sh ${CMAKE_SOURCE_DIR}/test_symbols.sh
$<TARGET_FILE:${PROJECT_NAME}_static> ${CMAKE_SOURCE_DIR}/symbols.txt) $<TARGET_FILE:${PROJECT_NAME}-static> ${symbol_exports}
${symbol_imports})
endif() endif()
# bench # bench
add_executable(conflict_set_bench Bench.cpp) 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})
set_target_properties(conflict_set_bench PROPERTIES SKIP_BUILD_RPATH ON) set_target_properties(conflict_set_bench PROPERTIES SKIP_BUILD_RPATH ON)
add_executable(real_data_bench RealDataBench.cpp) add_executable(real_data_bench RealDataBench.cpp)
target_link_libraries(real_data_bench PRIVATE ${PROJECT_NAME}) target_link_libraries(real_data_bench PRIVATE ${PROJECT_NAME})
set_target_properties(real_data_bench PROPERTIES SKIP_BUILD_RPATH ON) set_target_properties(real_data_bench PROPERTIES SKIP_BUILD_RPATH ON)
endif() endif()
# packaging # packaging
set(CPACK_PACKAGE_CONTACT andrew@weaselab.dev) set(CPACK_PACKAGE_CONTACT andrew@weaselab.dev)
set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME all)
set(CPACK_PACKAGE_VENDOR "Weaselab") set(CPACK_PACKAGE_VENDOR "Weaselab")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
@@ -267,6 +345,29 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) set(CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
set(CPACK_RPM_SPEC_INSTALL_POST "/bin/true") # avoid stripping set(CPACK_RPM_SPEC_INSTALL_POST "/bin/true") # avoid stripping
set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0") set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0")
set(CPACK_RPM_FILE_NAME RPM-DEFAULT)
# deb
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
# see *-imports.txt - dependency versions need to be synced with symbol versions
if(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.17)")
else()
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.14)")
endif()
# macos
if(APPLE)
find_program(PANDOC_EXE pandoc)
if(PANDOC_EXE)
execute_process(COMMAND ${PANDOC_EXE} ${CMAKE_SOURCE_DIR}/README.md -o
${CMAKE_BINARY_DIR}/README.txt)
set(CPACK_RESOURCE_FILE_README ${CMAKE_BINARY_DIR}/README.txt)
endif()
configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_BINARY_DIR}/LICENSE.txt
COPYONLY)
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_BINARY_DIR}/LICENSE.txt)
endif()
include(CPack) include(CPack)
@@ -278,7 +379,7 @@ target_include_directories(
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>) $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>)
target_include_directories( target_include_directories(
${PROJECT_NAME}_static ${PROJECT_NAME}-static
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>) $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>)
@@ -287,13 +388,16 @@ set_target_properties(
SOVERSION ${PROJECT_VERSION_MAJOR}) SOVERSION ${PROJECT_VERSION_MAJOR})
install( install(
TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_static TARGETS ${PROJECT_NAME} ${PROJECT_NAME}-static
EXPORT ConflictSetConfig EXPORT ${PROJECT_NAME}Config
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY include/ install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
install(EXPORT ConflictSetConfig install(EXPORT ${PROJECT_NAME}Config
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/ConflictSet/cmake) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake)
cpack_add_component(all)

View File

@@ -29,6 +29,7 @@ limitations under the License.
#include <span> #include <span>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <type_traits>
#include <utility> #include <utility>
#ifdef HAS_AVX #ifdef HAS_AVX
@@ -39,6 +40,8 @@ limitations under the License.
#include <memcheck.h> #include <memcheck.h>
using namespace weaselab;
// Use assert for checking potentially complex properties during tests. // Use assert for checking potentially complex properties during tests.
// Use assume to hint simple properties to the optimizer. // Use assume to hint simple properties to the optimizer.
@@ -216,6 +219,7 @@ struct Node {
/* end section that's copied to the next node */ /* end section that's copied to the next node */
uint8_t *partialKey(); uint8_t *partialKey();
size_t size() const;
Type getType() const { return type; } Type getType() const { return type; }
int32_t getCapacity() const { return partialKeyCapacity; } int32_t getCapacity() const { return partialKeyCapacity; }
@@ -249,6 +253,8 @@ struct Node0 : Node {
void copyChildrenAndKeyFrom(const Node0 &other); void copyChildrenAndKeyFrom(const Node0 &other);
void copyChildrenAndKeyFrom(const struct Node3 &other); void copyChildrenAndKeyFrom(const struct Node3 &other);
size_t size() const { return sizeof(Node0) + getCapacity(); }
}; };
struct Node3 : Node { struct Node3 : Node {
@@ -262,6 +268,8 @@ struct Node3 : Node {
void copyChildrenAndKeyFrom(const Node0 &other); void copyChildrenAndKeyFrom(const Node0 &other);
void copyChildrenAndKeyFrom(const Node3 &other); void copyChildrenAndKeyFrom(const Node3 &other);
void copyChildrenAndKeyFrom(const struct Node16 &other); void copyChildrenAndKeyFrom(const struct Node16 &other);
size_t size() const { return sizeof(Node3) + getCapacity(); }
}; };
struct Node16 : Node { struct Node16 : Node {
@@ -275,6 +283,8 @@ struct Node16 : Node {
void copyChildrenAndKeyFrom(const Node3 &other); void copyChildrenAndKeyFrom(const Node3 &other);
void copyChildrenAndKeyFrom(const Node16 &other); void copyChildrenAndKeyFrom(const Node16 &other);
void copyChildrenAndKeyFrom(const struct Node48 &other); void copyChildrenAndKeyFrom(const struct Node48 &other);
size_t size() const { return sizeof(Node16) + getCapacity(); }
}; };
struct Node48 : Node { struct Node48 : Node {
@@ -290,6 +300,8 @@ struct Node48 : Node {
void copyChildrenAndKeyFrom(const Node16 &other); void copyChildrenAndKeyFrom(const Node16 &other);
void copyChildrenAndKeyFrom(const Node48 &other); void copyChildrenAndKeyFrom(const Node48 &other);
void copyChildrenAndKeyFrom(const struct Node256 &other); void copyChildrenAndKeyFrom(const struct Node256 &other);
size_t size() const { return sizeof(Node48) + getCapacity(); }
}; };
struct Node256 : Node { struct Node256 : Node {
@@ -299,6 +311,8 @@ struct Node256 : Node {
uint8_t *partialKey() { return (uint8_t *)(this + 1); } uint8_t *partialKey() { return (uint8_t *)(this + 1); }
void copyChildrenAndKeyFrom(const Node48 &other); void copyChildrenAndKeyFrom(const Node48 &other);
void copyChildrenAndKeyFrom(const Node256 &other); void copyChildrenAndKeyFrom(const Node256 &other);
size_t size() const { return sizeof(Node256) + getCapacity(); }
}; };
inline void Node0::copyChildrenAndKeyFrom(const Node0 &other) { inline void Node0::copyChildrenAndKeyFrom(const Node0 &other) {
@@ -535,7 +549,7 @@ template <class T> struct BoundedFreeListAllocator {
} else { } else {
// The intent is to filter out too-small nodes in the freelist // The intent is to filter out too-small nodes in the freelist
removeNode(n); removeNode(n);
safe_free(n); safe_free(n, sizeof(T) + n->partialKeyCapacity);
} }
} }
@@ -547,10 +561,9 @@ template <class T> struct BoundedFreeListAllocator {
} }
void release(T *p) { void release(T *p) {
static_assert(std::is_trivially_destructible_v<T>);
if (freeListBytes >= kFreeListMaxMemory) { if (freeListBytes >= kFreeListMaxMemory) {
removeNode(p); removeNode(p);
return safe_free(p); return safe_free(p, sizeof(T) + p->partialKeyCapacity);
} }
memcpy((void *)p, &freeList, sizeof(freeList)); memcpy((void *)p, &freeList, sizeof(freeList));
freeList = p; freeList = p;
@@ -560,11 +573,11 @@ template <class T> struct BoundedFreeListAllocator {
~BoundedFreeListAllocator() { ~BoundedFreeListAllocator() {
for (void *iter = freeList; iter != nullptr;) { for (void *iter = freeList; iter != nullptr;) {
VALGRIND_MAKE_MEM_DEFINED(iter, sizeof(iter)); VALGRIND_MAKE_MEM_DEFINED(iter, sizeof(Node));
auto *tmp = iter; auto *tmp = (T *)iter;
memcpy(&iter, iter, sizeof(void *)); memcpy(&iter, iter, sizeof(void *));
removeNode(((T *)tmp)); removeNode((tmp));
safe_free(tmp); safe_free(tmp, sizeof(T) + tmp->partialKeyCapacity);
} }
} }
@@ -590,6 +603,23 @@ uint8_t *Node::partialKey() {
} }
} }
size_t Node::size() const {
switch (type) {
case Type_Node0:
return ((Node0 *)this)->size();
case Type_Node3:
return ((Node3 *)this)->size();
case Type_Node16:
return ((Node16 *)this)->size();
case Type_Node48:
return ((Node48 *)this)->size();
case Type_Node256:
return ((Node256 *)this)->size();
default: // GCOVR_EXCL_LINE
__builtin_unreachable(); // GCOVR_EXCL_LINE
}
}
struct NodeAllocators { struct NodeAllocators {
BoundedFreeListAllocator<Node0> node0; BoundedFreeListAllocator<Node0> node0;
BoundedFreeListAllocator<Node3> node3; BoundedFreeListAllocator<Node3> node3;
@@ -925,6 +955,42 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
assert(self->getType() == Type_Node16); assert(self->getType() == Type_Node16);
++self->numChildren; ++self->numChildren;
#ifdef HAS_AVX
__m128i key_vec = _mm_set1_epi8(index);
__m128i indices;
memcpy(&indices, self16->index, sizeof(self16->index));
__m128i results = _mm_cmpeq_epi8(key_vec, _mm_min_epu8(key_vec, indices));
int mask = (1 << (self->numChildren - 1)) - 1;
uint32_t bitfield = _mm_movemask_epi8(results) & mask;
bitfield |= uint32_t(1) << (self->numChildren - 1);
int i = std::countr_zero(bitfield);
if (i < self->numChildren - 1) {
memmove(self16->index + i + 1, self16->index + i,
self->numChildren - (i + 1));
memmove(self16->children + i + 1, self16->children + i,
(self->numChildren - (i + 1)) * sizeof(Child));
}
#elif defined(HAS_ARM_NEON)
uint8x16_t indices;
memcpy(&indices, self16->index, sizeof(self16->index));
// 0xff for each leq
auto results = vcleq_u8(vdupq_n_u8(index), indices);
uint64_t mask = (uint64_t(1) << ((self->numChildren - 1) * 4)) - 1;
// 0xf for each 0xff (within mask)
uint64_t bitfield =
vget_lane_u64(
vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(results), 4)),
0) &
mask;
bitfield |= uint64_t(0xf) << ((self->numChildren - 1) * 4);
int i = std::countr_zero(bitfield) / 4;
if (i < self->numChildren - 1) {
memmove(self16->index + i + 1, self16->index + i,
self->numChildren - (i + 1));
memmove(self16->children + i + 1, self16->children + i,
(self->numChildren - (i + 1)) * sizeof(Child));
}
#else
int i = 0; int i = 0;
for (; i < int(self->numChildren) - 1; ++i) { for (; i < int(self->numChildren) - 1; ++i) {
if (int(self16->index[i]) > int(index)) { if (int(self16->index[i]) > int(index)) {
@@ -935,6 +1001,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
break; break;
} }
} }
#endif
self16->index[i] = index; self16->index[i] = index;
auto &result = self16->children[i].child; auto &result = self16->children[i].child;
result = nullptr; result = nullptr;
@@ -950,8 +1017,8 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
self = newSelf; self = newSelf;
goto insert256; goto insert256;
} }
insert48:
insert48:
auto *self48 = static_cast<Node48 *>(self); auto *self48 = static_cast<Node48 *>(self);
self48->bitSet.set(index); self48->bitSet.set(index);
++self->numChildren; ++self->numChildren;
@@ -963,6 +1030,7 @@ Node *&getOrCreateChild(Node *&self, uint8_t index,
return result; return result;
} }
case Type_Node256: { case Type_Node256: {
insert256: insert256:
auto *self256 = static_cast<Node256 *>(self); auto *self256 = static_cast<Node256 *>(self);
++self->numChildren; ++self->numChildren;
@@ -1012,7 +1080,7 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
allocators->node0.release(self0); allocators->node0.release(self0);
} else { } else {
removeNode(self0); removeNode(self0);
safe_free(self0); safe_free(self0, self0->size());
} }
self = newSelf; self = newSelf;
} break; } break;
@@ -1025,7 +1093,7 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
allocators->node3.release(self3); allocators->node3.release(self3);
} else { } else {
removeNode(self3); removeNode(self3);
safe_free(self3); safe_free(self3, self3->size());
} }
self = newSelf; self = newSelf;
} break; } break;
@@ -1038,7 +1106,7 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
allocators->node16.release(self16); allocators->node16.release(self16);
} else { } else {
removeNode(self16); removeNode(self16);
safe_free(self16); safe_free(self16, self16->size());
} }
self = newSelf; self = newSelf;
} break; } break;
@@ -1051,7 +1119,7 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
allocators->node48.release(self48); allocators->node48.release(self48);
} else { } else {
removeNode(self48); removeNode(self48);
safe_free(self48); safe_free(self48, self48->size());
} }
self = newSelf; self = newSelf;
} break; } break;
@@ -1064,7 +1132,7 @@ void freeAndMakeCapacityAtLeast(Node *&self, int capacity,
allocators->node256.release(self256); allocators->node256.release(self256);
} else { } else {
removeNode(self256); removeNode(self256);
safe_free(self256); safe_free(self256, self256->size());
} }
self = newSelf; self = newSelf;
} break; } break;
@@ -2178,7 +2246,7 @@ void destroyTree(Node *root) {
assert(c != nullptr); assert(c != nullptr);
toFree.push_back(c); toFree.push_back(c);
} }
safe_free(n); safe_free(n, n->size());
} }
} }
@@ -2435,10 +2503,10 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
} }
if (n == nullptr) { if (n == nullptr) {
removalKey = {}; removalKey = {};
return; } else {
removalKeyArena = Arena();
removalKey = getSearchPath(removalKeyArena, n);
} }
removalKeyArena = Arena();
removalKey = getSearchPath(removalKeyArena, n);
} }
explicit Impl(int64_t oldestVersion) : oldestVersion(oldestVersion) { explicit Impl(int64_t oldestVersion) : oldestVersion(oldestVersion) {
@@ -2467,6 +2535,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
Node *root; Node *root;
int64_t rootMaxVersion; int64_t rootMaxVersion;
int64_t oldestVersion; int64_t oldestVersion;
int64_t totalBytes = 0;
}; };
// Precondition - an entry for index must exist in the node // Precondition - an entry for index must exist in the node
@@ -2520,20 +2589,39 @@ void ConflictSet::check(const ReadRange *reads, Result *results,
void ConflictSet::addWrites(const WriteRange *writes, int count, void ConflictSet::addWrites(const WriteRange *writes, int count,
int64_t writeVersion) { int64_t writeVersion) {
return impl->addWrites(writes, count, writeVersion); mallocBytesDelta = 0;
impl->addWrites(writes, count, writeVersion);
impl->totalBytes += mallocBytesDelta;
#if SHOW_MEMORY
if (impl->totalBytes != mallocBytes) {
abort();
}
#endif
} }
void ConflictSet::setOldestVersion(int64_t oldestVersion) { void ConflictSet::setOldestVersion(int64_t oldestVersion) {
return impl->setOldestVersion(oldestVersion); mallocBytesDelta = 0;
impl->setOldestVersion(oldestVersion);
impl->totalBytes += mallocBytesDelta;
#if SHOW_MEMORY
if (impl->totalBytes != mallocBytes) {
abort();
}
#endif
} }
int64_t ConflictSet::getBytes() const { return impl->totalBytes; }
ConflictSet::ConflictSet(int64_t oldestVersion) ConflictSet::ConflictSet(int64_t oldestVersion)
: impl(new (safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {} : impl((mallocBytesDelta = 0,
new(safe_malloc(sizeof(Impl))) Impl{oldestVersion})) {
impl->totalBytes += mallocBytesDelta;
}
ConflictSet::~ConflictSet() { ConflictSet::~ConflictSet() {
if (impl) { if (impl) {
impl->~Impl(); impl->~Impl();
safe_free(impl); safe_free(impl, sizeof(*impl));
} }
} }
@@ -2559,24 +2647,44 @@ ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
__attribute__((__visibility__("default"))) void __attribute__((__visibility__("default"))) void
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count, ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
int64_t writeVersion) { int64_t writeVersion) {
((ConflictSet::Impl *)cs)->addWrites(writes, count, writeVersion); auto *impl = ((ConflictSet::Impl *)cs);
mallocBytesDelta = 0;
impl->addWrites(writes, count, writeVersion);
impl->totalBytes += mallocBytesDelta;
} }
__attribute__((__visibility__("default"))) void __attribute__((__visibility__("default"))) void
ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) { ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) {
((ConflictSet::Impl *)cs)->setOldestVersion(oldestVersion); auto *impl = ((ConflictSet::Impl *)cs);
mallocBytesDelta = 0;
impl->setOldestVersion(oldestVersion);
impl->totalBytes += mallocBytesDelta;
} }
__attribute__((__visibility__("default"))) void * __attribute__((__visibility__("default"))) void *
ConflictSet_create(int64_t oldestVersion) { ConflictSet_create(int64_t oldestVersion) {
return new (safe_malloc(sizeof(ConflictSet::Impl))) mallocBytesDelta = 0;
auto *result = new (safe_malloc(sizeof(ConflictSet::Impl)))
ConflictSet::Impl{oldestVersion}; ConflictSet::Impl{oldestVersion};
result->totalBytes += mallocBytesDelta;
return result;
} }
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) { __attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
using Impl = ConflictSet::Impl; using Impl = ConflictSet::Impl;
((Impl *)cs)->~Impl(); ((Impl *)cs)->~Impl();
safe_free(cs); safe_free(cs, sizeof(Impl));
}
__attribute__((__visibility__("default"))) int64_t
ConflictSet_getBytes(void *cs) {
using Impl = ConflictSet::Impl;
return ((Impl *)cs)->totalBytes;
} }
} }
// Make sure abi is well-defined
static_assert(std::is_standard_layout_v<ConflictSet::Result>);
static_assert(std::is_standard_layout_v<ConflictSet::Key>);
static_assert(std::is_standard_layout_v<ConflictSet::ReadRange>);
static_assert(std::is_standard_layout_v<ConflictSet::WriteRange>);
namespace { namespace {
std::string getSearchPathPrintable(Node *n) { std::string getSearchPathPrintable(Node *n) {
@@ -2789,8 +2897,8 @@ Iterator firstGeq(Node *n, std::string_view key) {
} }
} }
bool checkCorrectness(Node *node, int64_t oldestVersion, [[maybe_unused]] bool checkCorrectness(Node *node, int64_t oldestVersion,
ConflictSet::Impl *impl) { ConflictSet::Impl *impl) {
bool success = true; bool success = true;
checkParentPointers(node, success); checkParentPointers(node, success);

View File

@@ -96,13 +96,15 @@ void ConflictSet::setOldestVersion(int64_t oldestVersion) {
return impl->setOldestVersion(oldestVersion); return impl->setOldestVersion(oldestVersion);
} }
int64_t ConflictSet::getBytes() const { return -1; }
ConflictSet::ConflictSet(int64_t oldestVersion) ConflictSet::ConflictSet(int64_t oldestVersion)
: impl(new (safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {} : impl(new(safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {}
ConflictSet::~ConflictSet() { ConflictSet::~ConflictSet() {
if (impl) { if (impl) {
impl->~Impl(); impl->~Impl();
safe_free(impl); safe_free(impl, sizeof(Impl));
} }
} }
@@ -142,6 +144,11 @@ ConflictSet_create(int64_t oldestVersion) {
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) { __attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
using Impl = ConflictSet::Impl; using Impl = ConflictSet::Impl;
((Impl *)cs)->~Impl(); ((Impl *)cs)->~Impl();
safe_free(cs); safe_free(cs, sizeof(Impl));
}
__attribute__((__visibility__("default"))) int64_t
ConflictSet_getBytes(void *cs) {
using Impl = ConflictSet::Impl;
return -1;
} }
} }

View File

@@ -2,6 +2,8 @@
#include "ConflictSet.h" #include "ConflictSet.h"
using namespace weaselab;
#include <bit> #include <bit>
#include <cassert> #include <cassert>
#include <compare> #include <compare>
@@ -56,43 +58,55 @@ operator<=>(const std::span<const uint8_t> &lhs,
#if SHOW_MEMORY #if SHOW_MEMORY
inline int64_t mallocBytes = 0; inline int64_t mallocBytes = 0;
inline int64_t peakMallocBytes = 0; inline int64_t peakMallocBytes = 0;
constexpr auto kIntMallocHeaderSize = 16; #endif
inline thread_local int64_t mallocBytesDelta = 0;
#ifndef NDEBUG
constexpr auto kMallocHeaderSize = 16;
#endif #endif
// malloc that aborts on OOM and thus always returns a non-null pointer. Must be // malloc that aborts on OOM and thus always returns a non-null pointer. Must be
// paired with `safe_free`. // paired with `safe_free`.
__attribute__((always_inline)) inline void *safe_malloc(size_t s) { __attribute__((always_inline)) inline void *safe_malloc(size_t s) {
mallocBytesDelta += s;
#if SHOW_MEMORY #if SHOW_MEMORY
mallocBytes += s; mallocBytes += s;
if (mallocBytes > peakMallocBytes) { if (mallocBytes > peakMallocBytes) {
peakMallocBytes = mallocBytes; peakMallocBytes = mallocBytes;
} }
void *p = malloc(s + kIntMallocHeaderSize);
if (p == nullptr) {
abort();
}
memcpy(p, &s, sizeof(s));
return (char *)p + kIntMallocHeaderSize;
#else
void *p = malloc(s);
if (p == nullptr) {
abort();
}
return p;
#endif #endif
void *p = malloc(s
#ifndef NDEBUG
+ kMallocHeaderSize
#endif
);
if (p == nullptr) {
abort();
}
#ifndef NDEBUG
memcpy(p, &s, sizeof(s));
(char *&)p += kMallocHeaderSize;
#endif
return p;
} }
// Must be paired with `safe_malloc`. // Must be paired with `safe_malloc`.
// //
// There's nothing safer about this than free. Only called safe_free for // There's nothing safer about this than free. Only called safe_free for
// symmetry with safe_malloc. // symmetry with safe_malloc.
__attribute__((always_inline)) inline void safe_free(void *p) { __attribute__((always_inline)) inline void safe_free(void *p, size_t s) {
mallocBytesDelta -= s;
#if SHOW_MEMORY #if SHOW_MEMORY
size_t s;
memcpy(&s, (char *)p - kIntMallocHeaderSize, sizeof(s));
mallocBytes -= s; mallocBytes -= s;
free((char *)p - kIntMallocHeaderSize); free(p);
#else #else
#ifndef NDEBUG
(char *&)p -= kMallocHeaderSize;
size_t expected;
memcpy(&expected, p, sizeof(expected));
assert(s == expected);
#endif
free(p); free(p);
#endif #endif
} }
@@ -140,6 +154,7 @@ inline void *operator new[](size_t size, std::align_val_t align,
/// align must be a power of two /// align must be a power of two
template <class T> T *align_up(T *t, size_t align) { template <class T> T *align_up(T *t, size_t align) {
assert(std::popcount(align) == 1);
auto unaligned = uintptr_t(t); auto unaligned = uintptr_t(t);
auto aligned = (unaligned + align - 1) & ~(align - 1); auto aligned = (unaligned + align - 1) & ~(align - 1);
return reinterpret_cast<T *>(reinterpret_cast<char *>(t) + aligned - return reinterpret_cast<T *>(reinterpret_cast<char *>(t) + aligned -
@@ -148,6 +163,7 @@ template <class T> T *align_up(T *t, size_t align) {
/// align must be a power of two /// align must be a power of two
constexpr inline int align_up(uint32_t unaligned, uint32_t align) { constexpr inline int align_up(uint32_t unaligned, uint32_t align) {
assert(std::popcount(align) == 1);
return (unaligned + align - 1) & ~(align - 1); return (unaligned + align - 1) & ~(align - 1);
} }
@@ -163,12 +179,10 @@ struct Arena::ArenaImpl {
uint8_t *begin() { return reinterpret_cast<uint8_t *>(this + 1); } uint8_t *begin() { return reinterpret_cast<uint8_t *>(this + 1); }
}; };
static_assert(sizeof(Arena::ArenaImpl) == 16);
static_assert(alignof(Arena::ArenaImpl) == 8);
inline Arena::Arena(int initialSize) : impl(nullptr) { inline Arena::Arena(int initialSize) : impl(nullptr) {
if (initialSize > 0) { if (initialSize > 0) {
auto allocationSize = align_up(initialSize + sizeof(ArenaImpl), 16); auto allocationSize =
align_up(initialSize + sizeof(ArenaImpl), alignof(ArenaImpl));
impl = (Arena::ArenaImpl *)safe_malloc(allocationSize); impl = (Arena::ArenaImpl *)safe_malloc(allocationSize);
impl->prev = nullptr; impl->prev = nullptr;
impl->capacity = allocationSize - sizeof(ArenaImpl); impl->capacity = allocationSize - sizeof(ArenaImpl);
@@ -179,7 +193,7 @@ inline Arena::Arena(int initialSize) : impl(nullptr) {
inline void onDestroy(Arena::ArenaImpl *impl) { inline void onDestroy(Arena::ArenaImpl *impl) {
while (impl) { while (impl) {
auto *prev = impl->prev; auto *prev = impl->prev;
safe_free(impl); safe_free(impl, sizeof(Arena::ArenaImpl) + impl->capacity);
impl = prev; impl = prev;
} }
} }
@@ -204,7 +218,7 @@ inline void *operator new(size_t size, std::align_val_t align, Arena &arena) {
(arena.impl ? std::max<int>(sizeof(Arena::ArenaImpl), (arena.impl ? std::max<int>(sizeof(Arena::ArenaImpl),
arena.impl->capacity * 2) arena.impl->capacity * 2)
: 0)), : 0)),
16); alignof(Arena::ArenaImpl));
auto *impl = (Arena::ArenaImpl *)safe_malloc(allocationSize); auto *impl = (Arena::ArenaImpl *)safe_malloc(allocationSize);
impl->prev = arena.impl; impl->prev = arena.impl;
impl->capacity = allocationSize - sizeof(Arena::ArenaImpl); impl->capacity = allocationSize - sizeof(Arena::ArenaImpl);

11
Jenkinsfile vendored
View File

@@ -48,6 +48,17 @@ pipeline {
recordIssues(tools: [clang()]) recordIssues(tools: [clang()])
} }
} }
stage('SIMD fallback') {
agent {
dockerfile {
args '-v /home/jenkins/ccache:/ccache'
reuseNode true
}
}
steps {
CleanBuildAndTest("-DUSE_SIMD_FALLBACK=ON")
}
}
stage('Release [gcc]') { stage('Release [gcc]') {
agent { agent {
dockerfile { dockerfile {

108
README.md
View File

@@ -9,76 +9,76 @@ Hardware for all benchmarks is a mac m1 2020.
## Skip list ## Skip list
``` ```
New conflict set: 1.927 sec New conflict set: 1.957 sec
0.649 Mtransactions/sec 0.639 Mtransactions/sec
2.595 Mkeys/sec 2.555 Mkeys/sec
Detect only: 1.838 sec Detect only: 1.845 sec
0.680 Mtransactions/sec 0.678 Mtransactions/sec
2.721 Mkeys/sec 2.710 Mkeys/sec
Skiplist only: 1.256 sec Skiplist only: 1.263 sec
0.995 Mtransactions/sec 0.990 Mtransactions/sec
3.981 Mkeys/sec 3.960 Mkeys/sec
Performance counters: Performance counters:
Build: 0.0381 Build: 0.0546
Add: 0.0499 Add: 0.0563
Detect: 1.84 Detect: 1.84
D.Sort: 0.411 D.Sort: 0.412
D.Combine: 0.0141 D.Combine: 0.0141
D.CheckRead: 0.667 D.CheckRead: 0.671
D.CheckIntraBatch: 0.00673 D.CheckIntraBatch: 0.0068
D.MergeWrite: 0.589 D.MergeWrite: 0.592
D.RemoveBefore: 0.146 D.RemoveBefore: 0.146
``` ```
## Radix tree (this implementation) ## Radix tree (this implementation)
``` ```
New conflict set: 1.318 sec New conflict set: 1.366 sec
0.949 Mtransactions/sec 0.915 Mtransactions/sec
3.795 Mkeys/sec 3.660 Mkeys/sec
Detect only: 1.202 sec Detect only: 1.248 sec
1.040 Mtransactions/sec 1.002 Mtransactions/sec
4.160 Mkeys/sec 4.007 Mkeys/sec
Skiplist only: 0.542 sec Skiplist only: 0.573 sec
2.307 Mtransactions/sec 2.182 Mtransactions/sec
9.227 Mkeys/sec 8.730 Mkeys/sec
Performance counters: Performance counters:
Build: 0.0566 Build: 0.0594
Add: 0.058 Add: 0.0572
Detect: 1.2 Detect: 1.25
D.Sort: 0.411 D.Sort: 0.418
D.Combine: 0.0136 D.Combine: 0.0149
D.CheckRead: 0.22 D.CheckRead: 0.232
D.CheckIntraBatch: 0.00659 D.CheckIntraBatch: 0.0067
D.MergeWrite: 0.322 D.MergeWrite: 0.341
D.RemoveBefore: 0.226 D.RemoveBefore: 0.232
``` ```
# Our benchmark # Our benchmark
## Skip list ## Skip list
| ns/op | op/s | err% | total | benchmark | ns/op | op/s | err% | total | benchmark |
|--------------------:|--------------------:|--------:|----------:|:---------- | -----: | -----------: | ---: | ----: | :---------------------------------- |
| 257.12 | 3,889,241.18 | 0.2% | 0.01 | `point reads` | 246.99 | 4,048,700.59 | 0.2% | 0.01 | `point reads` |
| 276.38 | 3,618,145.21 | 0.3% | 0.01 | `prefix reads` | 260.16 | 3,843,784.65 | 0.1% | 0.01 | `prefix reads` |
| 494.19 | 2,023,531.84 | 0.2% | 0.01 | `range reads` | 493.35 | 2,026,953.19 | 0.1% | 0.01 | `range reads` |
| 451.22 | 2,216,229.54 | 1.3% | 0.01 | `point writes` | 462.05 | 2,164,289.23 | 0.6% | 0.01 | `point writes` |
| 435.80 | 2,294,622.46 | 0.3% | 0.01 | `prefix writes` | 448.19 | 2,231,205.25 | 0.9% | 0.01 | `prefix writes` |
| 246.67 | 4,053,999.27 | 4.2% | 0.02 | `range writes` | 255.83 | 3,908,845.72 | 1.5% | 0.02 | `range writes` |
| 555.46 | 1,800,304.91 | 0.9% | 0.01 | `monotonic increasing point writes` | 582.63 | 1,716,349.02 | 1.3% | 0.01 | `monotonic increasing point writes` |
## Radix tree (this implementation) ## Radix tree (this implementation)
| ns/op | op/s | err% | total | benchmark | ns/op | op/s | err% | total | benchmark |
|--------------------:|--------------------:|--------:|----------:|:---------- | -----: | ------------: | ---: | ----: | :---------------------------------- |
| 19.40 | 51,554,711.61 | 0.2% | 0.01 | `point reads` | 19.42 | 51,483,206.67 | 0.3% | 0.01 | `point reads` |
| 57.10 | 17,514,573.13 | 0.4% | 0.01 | `prefix reads` | 58.43 | 17,115,612.57 | 0.1% | 0.01 | `prefix reads` |
| 215.65 | 4,637,096.77 | 0.4% | 0.01 | `range reads` | 216.09 | 4,627,766.60 | 0.2% | 0.01 | `range reads` |
| 27.52 | 36,340,784.38 | 0.2% | 0.01 | `point writes` | 28.35 | 35,267,567.72 | 0.2% | 0.01 | `point writes` |
| 42.16 | 23,720,515.40 | 0.7% | 0.01 | `prefix writes` | 43.43 | 23,026,226.17 | 0.2% | 0.01 | `prefix writes` |
| 48.33 | 20,691,082.14 | 2.7% | 0.01 | `range writes` | 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes` |
| 87.93 | 11,372,164.55 | 2.5% | 0.01 | `monotonic increasing point writes` | 92.38 | 10,824,863.69 | 4.1% | 0.01 | `monotonic increasing point writes` |
# "Real data" test # "Real data" test
@@ -87,13 +87,13 @@ Point queries only, best of three runs. Gc ratio is the ratio of time spent doin
## skip list ## skip list
``` ```
Check: 11.3839 seconds, 328.404 MB/s, Add: 5.32878 seconds, 131.745 MB/s, Gc ratio: 45.5903% Check: 11.3385 seconds, 329.718 MB/s, Add: 5.35612 seconds, 131.072 MB/s, Gc ratio: 45.7173%
``` ```
## radix tree ## radix tree
``` ```
Check: 2.55069 seconds, 1465.69 MB/s, Add: 2.08443 seconds, 336.801 MB/s, Gc ratio: 41.748% Check: 2.48583 seconds, 1503.93 MB/s, Add: 2.12768 seconds, 329.954 MB/s, Gc ratio: 41.7943%
``` ```
## hash table ## hash table
@@ -101,5 +101,5 @@ Check: 2.55069 seconds, 1465.69 MB/s, Add: 2.08443 seconds, 336.801 MB/s, Gc rat
(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: 1.84205 seconds, 2029.54 MB/s, Add: 0.60281 seconds, 1164.61 MB/s, Gc ratio: 48.8159% Check: 1.83386 seconds, 2038.6 MB/s, Add: 0.601411 seconds, 1167.32 MB/s, Gc ratio: 48.9776%
``` ```

View File

@@ -1,13 +1,18 @@
#include <ConflictSet.h> #include <ConflictSet.h>
#include <cerrno>
#include <chrono> #include <chrono>
#include <cstdio>
#include <cstring> #include <cstring>
#include <fcntl.h> #include <fcntl.h>
#include <string_view>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <vector> #include <vector>
using namespace weaselab;
double now() { double now() {
return std::chrono::duration_cast<std::chrono::nanoseconds>( return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch()) std::chrono::steady_clock::now().time_since_epoch())
@@ -28,7 +33,7 @@ constexpr inline size_t rightAlign(size_t offset, size_t alignment) {
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
// Use with this dataset https://snap.stanford.edu/data/memetracker9.html // Use with this dataset https://snap.stanford.edu/data/memetracker9.html
// Preprocess the files with `sed -i '' '/^Q/d'` // Preprocess the files with `sed -i'' '/^Q/d'`
double checkTime = 0; double checkTime = 0;
double addTime = 0; double addTime = 0;
@@ -40,6 +45,8 @@ int main(int argc, const char **argv) {
int64_t version = 0; int64_t version = 0;
double timer = 0; double timer = 0;
int64_t peakMemory = 0;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
int fd = open(argv[i], O_RDONLY); int fd = open(argv[i], O_RDONLY);
struct stat st; struct stat st;
@@ -109,6 +116,10 @@ int main(int argc, const char **argv) {
write = {}; write = {};
reads.clear(); reads.clear();
if (cs.getBytes() > peakMemory) {
peakMemory = cs.getBytes();
}
timer = now(); timer = now();
cs.setOldestVersion(version - 10000); cs.setOldestVersion(version - 10000);
gcTime += now() - timer; gcTime += now() - timer;
@@ -118,8 +129,9 @@ int main(int argc, const char **argv) {
close(fd); close(fd);
} }
printf( printf("Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: "
"Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: %g%%\n", "%g%%, Peak idle memory: %g\n",
checkTime, checkBytes / checkTime * 1e-6, addTime, checkTime, checkBytes / checkTime * 1e-6, addTime,
addBytes / addTime * 1e-6, gcTime / (gcTime + addTime) * 1e2); addBytes / addTime * 1e-6, gcTime / (gcTime + addTime) * 1e2,
double(peakMemory));
} }

View File

@@ -149,7 +149,7 @@ private:
setMaxVersion(level, v); setMaxVersion(level, v);
} }
void destroy() { safe_free(this); } void destroy() { safe_free(this, getNodeSize()); }
private: private:
int getNodeSize() const { int getNodeSize() const {
@@ -627,6 +627,8 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
removalArena, {finger.getValue().data(), finger.getValue().size()}); removalArena, {finger.getValue().data(), finger.getValue().size()});
} }
int64_t totalBytes = 0;
private: private:
int64_t keyUpdates = 10; int64_t keyUpdates = 10;
Arena removalArena; Arena removalArena;
@@ -637,25 +639,44 @@ private:
void ConflictSet::check(const ReadRange *reads, Result *results, void ConflictSet::check(const ReadRange *reads, Result *results,
int count) const { int count) const {
return impl->check(reads, results, count); impl->check(reads, results, count);
} }
void ConflictSet::addWrites(const WriteRange *writes, int count, void ConflictSet::addWrites(const WriteRange *writes, int count,
int64_t writeVersion) { int64_t writeVersion) {
return impl->addWrites(writes, count, writeVersion); mallocBytesDelta = 0;
impl->addWrites(writes, count, writeVersion);
impl->totalBytes += mallocBytesDelta;
#if SHOW_MEMORY
if (impl->totalBytes != mallocBytes) {
abort();
}
#endif
} }
void ConflictSet::setOldestVersion(int64_t oldestVersion) { void ConflictSet::setOldestVersion(int64_t oldestVersion) {
return impl->setOldestVersion(oldestVersion); mallocBytesDelta = 0;
impl->setOldestVersion(oldestVersion);
impl->totalBytes += mallocBytesDelta;
#if SHOW_MEMORY
if (impl->totalBytes != mallocBytes) {
abort();
}
#endif
} }
int64_t ConflictSet::getBytes() const { return impl->totalBytes; }
ConflictSet::ConflictSet(int64_t oldestVersion) ConflictSet::ConflictSet(int64_t oldestVersion)
: impl(new (safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {} : impl((mallocBytesDelta = 0,
new(safe_malloc(sizeof(Impl))) Impl{oldestVersion})) {
impl->totalBytes += mallocBytesDelta;
}
ConflictSet::~ConflictSet() { ConflictSet::~ConflictSet() {
if (impl) { if (impl) {
impl->~Impl(); impl->~Impl();
safe_free(impl); safe_free(impl, sizeof(Impl));
} }
} }
@@ -695,7 +716,12 @@ ConflictSet_create(int64_t oldestVersion) {
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) { __attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
using Impl = ConflictSet::Impl; using Impl = ConflictSet::Impl;
((Impl *)cs)->~Impl(); ((Impl *)cs)->~Impl();
safe_free(cs); safe_free(cs, sizeof(Impl));
}
__attribute__((__visibility__("default"))) int64_t
ConflictSet_getBytes(void *cs) {
using Impl = ConflictSet::Impl;
return ((Impl *)cs)->totalBytes;
} }
} }

View File

@@ -0,0 +1,8 @@
__stack_chk_fail@GLIBC_2.17
__stack_chk_guard@GLIBC_2.17
abort@GLIBC_2.17
free@GLIBC_2.17
malloc@GLIBC_2.17
memcpy@GLIBC_2.17
memmove@GLIBC_2.17
memset@GLIBC_2.17

17
apple-symbol-exports.txt Normal file
View File

@@ -0,0 +1,17 @@
_ConflictSet_addWrites
_ConflictSet_check
_ConflictSet_create
_ConflictSet_destroy
_ConflictSet_getBytes
_ConflictSet_setOldestVersion
__ZN8weaselab11ConflictSet16setOldestVersionEx
__ZN8weaselab11ConflictSet9addWritesEPKNS0_10WriteRangeEix
__ZN8weaselab11ConflictSetC1EOS0_
__ZN8weaselab11ConflictSetC1Ex
__ZN8weaselab11ConflictSetC2EOS0_
__ZN8weaselab11ConflictSetC2Ex
__ZN8weaselab11ConflictSetD1Ev
__ZN8weaselab11ConflictSetD2Ev
__ZN8weaselab11ConflictSetaSEOS0_
__ZNK8weaselab11ConflictSet5checkEPKNS0_9ReadRangeEPNS0_6ResultEi
__ZNK8weaselab11ConflictSet8getBytesEv

7
apple-symbol-imports.txt Normal file
View File

@@ -0,0 +1,7 @@
__tlv_bootstrap
_abort
_bzero
_free
_malloc
_memcpy
_memmove

120
conflict_set.py Normal file
View File

@@ -0,0 +1,120 @@
import ctypes
import enum
import os
from typing import Optional
_lib = None
for f in (
os.path.dirname(__file__) + "/build/radix_tree/libconflict-set.so.0",
os.path.dirname(__file__) + "/build/radix_tree/libconflict-set.0.dylib",
):
try:
_lib = ctypes.cdll.LoadLibrary(f)
except:
pass
if _lib is None:
import sys
print("Could not find libconflict-set", file=sys.stderr)
sys.exit(1)
class _Key(ctypes.Structure):
_fields_ = [("p", ctypes.POINTER(ctypes.c_ubyte)), ("len", ctypes.c_int)]
class ReadRange(ctypes.Structure):
_fields_ = [
("begin", _Key),
("end", _Key),
("readVersion", ctypes.c_int64),
]
class WriteRange(ctypes.Structure):
_fields_ = [("begin", _Key), ("end", _Key)]
_lib.ConflictSet_create.argtypes = (ctypes.c_int64,)
_lib.ConflictSet_create.restype = ctypes.c_void_p
_lib.ConflictSet_check.argtypes = (
ctypes.c_void_p,
ctypes.POINTER(ReadRange),
ctypes.POINTER(ctypes.c_int),
ctypes.c_int,
)
_lib.ConflictSet_addWrites.argtypes = (
ctypes.c_void_p,
ctypes.POINTER(WriteRange),
ctypes.c_int,
ctypes.c_int64,
)
_lib.ConflictSet_setOldestVersion.argtypes = (ctypes.c_void_p, ctypes.c_int64)
_lib.ConflictSet_destroy.argtypes = (ctypes.c_void_p,)
class Result(enum.Enum):
COMMIT = 0
CONFLICT = 1
TOO_OLD = 2
def write(begin: bytes, end: Optional[bytes] = None) -> WriteRange:
b = (ctypes.c_ubyte * len(begin))()
b.value = begin
if end is None:
e = (ctypes.c_ubyte * 0)()
e.value = b""
else:
e = (ctypes.c_ubyte * len(end))()
e.value = end
return WriteRange(_Key(b, len(b)), _Key(e, len(e)))
def read(version: int, begin: bytes, end: Optional[bytes] = None) -> ReadRange:
b = (ctypes.c_ubyte * len(begin))()
b.value = begin
if end is None:
e = (ctypes.c_ubyte * 0)()
e.value = b""
else:
e = (ctypes.c_ubyte * len(end))()
e.value = end
return ReadRange(_Key(b, len(b)), _Key(e, len(e)), version)
class ConflictSet:
def __init__(self, version: int = 0) -> None:
self.p = _lib.ConflictSet_create(version)
def addWrites(self, version: int, *writes: WriteRange):
_lib.ConflictSet_addWrites(
self.p, (WriteRange * len(writes))(*writes), len(writes), version
)
def check(self, *reads: ReadRange) -> list[Result]:
r = (ctypes.c_int * len(reads))()
_lib.ConflictSet_check(self.p, *reads, r, 1)
return [Result(x) for x in r]
def setOldestVersion(self, version: int) -> None:
_lib.ConflictSet_setOldestVersion(self.p, version)
def __enter__(self):
return self
def close(self) -> None:
if self.p is not None:
_lib.ConflictSet_destroy(self.p)
self.p = None
def __exit__(self, exception_type, exception_value, exception_traceback):
if self.p is not None:
_lib.ConflictSet_destroy(self.p)
self.p = None

View File

@@ -7,6 +7,7 @@ int main(void) {
ConflictSet_WriteRange w; ConflictSet_WriteRange w;
ConflictSet_Result result; ConflictSet_Result result;
ConflictSet_ReadRange r; ConflictSet_ReadRange r;
int64_t bytes;
w.begin.p = (const uint8_t *)"0000"; w.begin.p = (const uint8_t *)"0000";
w.begin.len = 4; w.begin.len = 4;
w.end.len = 0; w.end.len = 0;
@@ -17,6 +18,8 @@ int main(void) {
r.readVersion = 0; r.readVersion = 0;
ConflictSet_check(cs, &r, &result, 1); ConflictSet_check(cs, &r, &result, 1);
assert(result == ConflictSet_Conflict); assert(result == ConflictSet_Conflict);
bytes = ConflictSet_getBytes(cs);
assert(bytes > 0);
ConflictSet_destroy(cs); ConflictSet_destroy(cs);
return 0; return 0;
} }

View File

@@ -2,6 +2,8 @@
#include <cassert> #include <cassert>
using namespace weaselab;
int main(void) { int main(void) {
ConflictSet cs(0); ConflictSet cs(0);
ConflictSet::WriteRange w; ConflictSet::WriteRange w;
@@ -17,4 +19,6 @@ int main(void) {
r.readVersion = 0; r.readVersion = 0;
cs.check(&r, &result, 1); cs.check(&r, &result, 1);
assert(result == ConflictSet::Conflict); assert(result == ConflictSet::Conflict);
int64_t bytes = cs.getBytes();
assert(bytes > 0);
} }

View File

@@ -1,32 +1,19 @@
giff --git a/fdbserver/CMakeLists.txt b/fdbserver/CMakeLists.txt diff --git a/fdbserver/CMakeLists.txt b/fdbserver/CMakeLists.txt
index 3f353c2ef..cd0834761 100644 index 3f353c2ef..074a18628 100644
--- a/fdbserver/CMakeLists.txt --- a/fdbserver/CMakeLists.txt
+++ b/fdbserver/CMakeLists.txt +++ b/fdbserver/CMakeLists.txt
@@ -22,6 +22,9 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/workloads) @@ -22,6 +22,9 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/workloads)
add_flow_target(EXECUTABLE NAME fdbserver SRCS ${FDBSERVER_SRCS}) add_flow_target(EXECUTABLE NAME fdbserver SRCS ${FDBSERVER_SRCS})
+find_package(ConflictSet) +find_package(conflict-set)
+target_link_libraries(fdbserver PRIVATE conflict_set_static) +target_link_libraries(fdbserver PRIVATE conflict-set-static)
+ +
if (WITH_SWIFT) if (WITH_SWIFT)
# Setup the Swift sources in FDBServer. # Setup the Swift sources in FDBServer.
include(FindSwiftLibs) include(FindSwiftLibs)
diff --git a/fdbserver/Resolver.actor.cpp b/fdbserver/Resolver.actor.cpp
index bf4118f5f..d3b4eaad8 100644
--- a/fdbserver/Resolver.actor.cpp
+++ b/fdbserver/Resolver.actor.cpp
@@ -132,7 +132,7 @@ struct Resolver : ReferenceCounted<Resolver> {
AsyncVar<int64_t> totalStateBytes;
AsyncTrigger checkNeededVersion;
std::map<NetworkAddress, ProxyRequestsInfo> proxyInfoMap;
- ConflictSet* conflictSet;
+ ConflictSet2* conflictSet;
TransientStorageMetricSample iopsSample;
// Use LogSystem as backend for txnStateStore. However, the real commit
diff --git a/fdbserver/SkipList.cpp b/fdbserver/SkipList.cpp diff --git a/fdbserver/SkipList.cpp b/fdbserver/SkipList.cpp
index b48d32c6b..da106b5d2 100644 index b48d32c6b..da99e03aa 100644
--- a/fdbserver/SkipList.cpp --- a/fdbserver/SkipList.cpp
+++ b/fdbserver/SkipList.cpp +++ b/fdbserver/SkipList.cpp
@@ -25,6 +25,7 @@ @@ -25,6 +25,7 @@
@@ -46,50 +33,35 @@ index b48d32c6b..da106b5d2 100644
static std::vector<PerfDoubleCounter*> skc; static std::vector<PerfDoubleCounter*> skc;
static thread_local uint32_t g_seed = 0; static thread_local uint32_t g_seed = 0;
@@ -782,26 +785,34 @@ private: @@ -783,10 +786,14 @@ private:
}
}; };
-struct ConflictSet { struct ConflictSet {
- ConflictSet() : removalKey(makeString(0)), oldestVersion(0) {} - ConflictSet() : removalKey(makeString(0)), oldestVersion(0) {}
- ~ConflictSet() {} + ConflictSet() : versionHistory(0), removalKey(makeString(0)), oldestVersion(0) {}
+struct ConflictSet2 { ~ConflictSet() {}
+ ConflictSet2() : versionHistory(0), removalKey(makeString(0)), oldestVersion(0) {}
+ ~ConflictSet2() {}
+#if USE_RADIX_TREE +#if USE_RADIX_TREE
+ ConflictSet versionHistory; + weaselab::ConflictSet versionHistory;
+#else +#else
SkipList versionHistory; SkipList versionHistory;
+#endif +#endif
Key removalKey; Key removalKey;
Version oldestVersion; Version oldestVersion;
}; };
@@ -795,7 +802,11 @@ ConflictSet* newConflictSet() {
-ConflictSet* newConflictSet() { return new ConflictSet;
- return new ConflictSet;
+ConflictSet2* newConflictSet() {
+ return new ConflictSet2;
} }
-void clearConflictSet(ConflictSet* cs, Version v) { void clearConflictSet(ConflictSet* cs, Version v) {
- SkipList(v).swap(cs->versionHistory); - SkipList(v).swap(cs->versionHistory);
+void clearConflictSet(ConflictSet2* cs, Version v) {
+#if USE_RADIX_TREE +#if USE_RADIX_TREE
+ cs->versionHistory = ConflictSet{ 0 }; + cs->versionHistory = weaselab::ConflictSet{ 0 };
+#else +#else
+ SkipList().swap(cs->versionHistory); + SkipList().swap(cs->versionHistory);
+#endif +#endif
} }
-void destroyConflictSet(ConflictSet* cs) { void destroyConflictSet(ConflictSet* cs) {
+void destroyConflictSet(ConflictSet2* cs) {
delete cs; delete cs;
}
-ConflictBatch::ConflictBatch(ConflictSet* cs,
+ConflictBatch::ConflictBatch(ConflictSet2* cs,
std::map<int, VectorRef<int>>* conflictingKeyRangeMap,
Arena* resolveBatchReplyArena)
: cs(cs), transactionCount(0), conflictingKeyRangeMap(conflictingKeyRangeMap),
@@ -971,11 +982,15 @@ void ConflictBatch::detectConflicts(Version now, @@ -971,11 +982,15 @@ void ConflictBatch::detectConflicts(Version now,
t = timer(); t = timer();
if (newOldestVersion > cs->oldestVersion) { if (newOldestVersion > cs->oldestVersion) {
@@ -112,7 +84,7 @@ index b48d32c6b..da106b5d2 100644
+#if USE_RADIX_TREE +#if USE_RADIX_TREE
+ Arena arena; + Arena arena;
+ auto* reads = new (arena) ConflictSet::ReadRange[combinedReadConflictRanges.size()]; + auto* reads = new (arena) weaselab::ConflictSet::ReadRange[combinedReadConflictRanges.size()];
+ +
+ for (int i = 0; i < combinedReadConflictRanges.size(); ++i) { + for (int i = 0; i < combinedReadConflictRanges.size(); ++i) {
+ auto& read = reads[i]; + auto& read = reads[i];
@@ -122,11 +94,11 @@ index b48d32c6b..da106b5d2 100644
+ read.end.p = combinedReadConflictRanges[i].end.begin(); + read.end.p = combinedReadConflictRanges[i].end.begin();
+ read.end.len = combinedReadConflictRanges[i].end.size(); + read.end.len = combinedReadConflictRanges[i].end.size();
+ } + }
+ auto* results = new (arena) ConflictSet::Result[combinedReadConflictRanges.size()]; + auto* results = new (arena) weaselab::ConflictSet::Result[combinedReadConflictRanges.size()];
+ cs->versionHistory.check(reads, results, combinedReadConflictRanges.size()); + cs->versionHistory.check(reads, results, combinedReadConflictRanges.size());
+ +
+ for (int i = 0; i < combinedReadConflictRanges.size(); ++i) { + for (int i = 0; i < combinedReadConflictRanges.size(); ++i) {
+ if (results[i] == ConflictSet::Conflict) { + if (results[i] == weaselab::ConflictSet::Conflict) {
+ transactionConflictStatus[combinedReadConflictRanges[i].transaction] = true; + transactionConflictStatus[combinedReadConflictRanges[i].transaction] = true;
+ if (combinedReadConflictRanges[i].conflictingKeyRange != nullptr) { + if (combinedReadConflictRanges[i].conflictingKeyRange != nullptr) {
+ combinedReadConflictRanges[i].conflictingKeyRange->push_back(*combinedReadConflictRanges[i].cKRArena, + combinedReadConflictRanges[i].conflictingKeyRange->push_back(*combinedReadConflictRanges[i].cKRArena,
@@ -147,7 +119,7 @@ index b48d32c6b..da106b5d2 100644
+#if USE_RADIX_TREE +#if USE_RADIX_TREE
+ Arena arena; + Arena arena;
+ auto* writes = new (arena) ConflictSet::WriteRange[combinedWriteConflictRanges.size()]; + auto* writes = new (arena) weaselab::ConflictSet::WriteRange[combinedWriteConflictRanges.size()];
+ +
+ for (int i = 0; i < combinedWriteConflictRanges.size(); ++i) { + for (int i = 0; i < combinedWriteConflictRanges.size(); ++i) {
+ auto& write = writes[i]; + auto& write = writes[i];
@@ -164,15 +136,6 @@ index b48d32c6b..da106b5d2 100644
} }
void ConflictBatch::combineWriteConflictRanges() { void ConflictBatch::combineWriteConflictRanges() {
@@ -1115,7 +1171,7 @@ void skipListTest() {
double start;
- ConflictSet* cs = newConflictSet();
+ ConflictSet2* cs = newConflictSet();
Arena testDataArena;
VectorRef<VectorRef<KeyRangeRef>> testData;
@@ -1197,6 +1253,4 @@ void skipListTest() { @@ -1197,6 +1253,4 @@ void skipListTest() {
for (const auto& counter : skc) { for (const auto& counter : skc) {
printf("%20s: %s\n", counter->getMetric().name().c_str(), counter->getMetric().formatted().c_str()); printf("%20s: %s\n", counter->getMetric().name().c_str(), counter->getMetric().formatted().c_str());
@@ -180,35 +143,3 @@ index b48d32c6b..da106b5d2 100644
- -
- printf("%d entries in version history\n", cs->versionHistory.count()); - printf("%d entries in version history\n", cs->versionHistory.count());
} }
diff --git a/fdbserver/include/fdbserver/ConflictSet.h b/fdbserver/include/fdbserver/ConflictSet.h
index 90ed2c406..b7e31217c 100644
--- a/fdbserver/include/fdbserver/ConflictSet.h
+++ b/fdbserver/include/fdbserver/ConflictSet.h
@@ -28,13 +28,13 @@
#include "fdbclient/CommitTransaction.h"
#include "fdbserver/ResolverBug.h"
-struct ConflictSet;
-ConflictSet* newConflictSet();
-void clearConflictSet(ConflictSet*, Version);
-void destroyConflictSet(ConflictSet*);
+struct ConflictSet2;
+ConflictSet2* newConflictSet();
+void clearConflictSet(ConflictSet2*, Version);
+void destroyConflictSet(ConflictSet2*);
struct ConflictBatch {
- explicit ConflictBatch(ConflictSet*,
+ explicit ConflictBatch(ConflictSet2*,
std::map<int, VectorRef<int>>* conflictingKeyRangeMap = nullptr,
Arena* resolveBatchReplyArena = nullptr);
~ConflictBatch();
@@ -54,7 +54,7 @@ struct ConflictBatch {
void GetTooOldTransactions(std::vector<int>& tooOldTransactions);
private:
- ConflictSet* cs;
+ ConflictSet2* cs;
Standalone<VectorRef<struct TransactionInfo*>> transactionInfo;
std::vector<struct KeyInfo> points;
int transactionCount;

View File

@@ -19,6 +19,7 @@ limitations under the License.
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
namespace weaselab {
/** A data structure for optimistic concurrency control on ranges of /** A data structure for optimistic concurrency control on ranges of
* bitwise-lexicographically-ordered keys. * bitwise-lexicographically-ordered keys.
* *
@@ -26,7 +27,7 @@ limitations under the License.
* - It's safe to operate on two different ConflictSets in two different * - It's safe to operate on two different ConflictSets in two different
* threads concurrently * threads concurrently
* - It's safe to have multiple threads operating on the same ConflictSet * - It's safe to have multiple threads operating on the same ConflictSet
* concurrently if and only if all threads only call `check`. * concurrently if and only if all threads only call const methods
*/ */
struct __attribute__((__visibility__("default"))) ConflictSet { struct __attribute__((__visibility__("default"))) ConflictSet {
enum Result { enum Result {
@@ -84,6 +85,9 @@ struct __attribute__((__visibility__("default"))) ConflictSet {
~ConflictSet(); ~ConflictSet();
/** Returns the total bytes in use by this ConflictSet */
int64_t getBytes() const;
#if __cplusplus > 199711L #if __cplusplus > 199711L
ConflictSet(ConflictSet &&) noexcept; ConflictSet(ConflictSet &&) noexcept;
ConflictSet &operator=(ConflictSet &&) noexcept; ConflictSet &operator=(ConflictSet &&) noexcept;
@@ -97,6 +101,7 @@ struct __attribute__((__visibility__("default"))) ConflictSet {
private: private:
Impl *impl; Impl *impl;
}; };
} /* namespace weaselab */
#else #else
@@ -107,7 +112,8 @@ private:
* - It's safe to operate on two different ConflictSets in two different * - It's safe to operate on two different ConflictSets in two different
* threads concurrently * threads concurrently
* - It's safe to have multiple threads operating on the same ConflictSet * - It's safe to have multiple threads operating on the same ConflictSet
* concurrently if and only if all threads only call `check`. * concurrently if and only if all threads only call functions that accept a
* const ConflictSet pointer
*/ */
typedef struct ConflictSet ConflictSet; typedef struct ConflictSet ConflictSet;
@@ -147,7 +153,8 @@ typedef struct {
} ConflictSet_WriteRange; } ConflictSet_WriteRange;
/** The result of checking reads[i] is written in results[i] */ /** The result of checking reads[i] is written in results[i] */
void ConflictSet_check(ConflictSet *cs, const ConflictSet_ReadRange *reads, void ConflictSet_check(const ConflictSet *cs,
const ConflictSet_ReadRange *reads,
ConflictSet_Result *results, int count); ConflictSet_Result *results, int count);
/** `writes` must be sorted ascending, and must not have adjacent or /** `writes` must be sorted ascending, and must not have adjacent or
@@ -169,4 +176,7 @@ ConflictSet *ConflictSet_create(int64_t oldestVersion);
void ConflictSet_destroy(ConflictSet *cs); void ConflictSet_destroy(ConflictSet *cs);
/** Returns the total bytes in use by this ConflictSet */
int64_t ConflictSet_getBytes(const ConflictSet *cs);
#endif #endif

33
package_macos.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/bash
set -euxo pipefail
umask 022
SRC_DIR="${0%/*}"
BUILD_ARM="$(mktemp -d -t conflict-set-arm)"
BUILD_X86="$(mktemp -d -t conflict-set-x86)"
cmake_args=(-DCMAKE_CXX_FLAGS=-DNVALGRIND -DCPACK_PACKAGING_INSTALL_PREFIX=/usr/local)
cmake -S"$SRC_DIR" -B"$BUILD_ARM" -DCMAKE_OSX_ARCHITECTURES=arm64 "${cmake_args[@]}"
cmake --build "$BUILD_ARM" --target conflict-set --target conflict-set-static
cmake -S"$SRC_DIR" -B"$BUILD_X86" -DCMAKE_OSX_ARCHITECTURES=x86_64 "${cmake_args[@]}"
cmake --build "$BUILD_X86" --target conflict-set --target conflict-set-static
VERSION="$(cat "$BUILD_ARM/version.txt")"
lipo -create "$BUILD_ARM/radix_tree/libconflict-set.$VERSION.dylib" "$BUILD_X86/radix_tree/libconflict-set.$VERSION.dylib" -output "libconflict-set.$VERSION.dylib.tmp"
lipo -create "$BUILD_ARM"/libconflict-set-static.a "$BUILD_X86"/libconflict-set-static.a -output libconflict-set-static.a.tmp
mv "libconflict-set.$VERSION.dylib.tmp" "$BUILD_ARM/radix_tree/libconflict-set.$VERSION.dylib"
mv libconflict-set-static.a.tmp "$BUILD_ARM/libconflict-set-static.a"
pushd "$BUILD_ARM"
cpack -G productbuild
popd
mv "$BUILD_ARM/conflict-set-$VERSION-Darwin.pkg" .
rm -rf "$BUILD_ARM" "$BUILD_X86"

8
privatize_symbols_macos.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
# This has the effect of making visibility=hidden symbols private in object files
for obj in "$@" ; do
ld -r "$obj" -o "$obj.tmp"
touch -r "$obj" "$obj.tmp"
mv "$obj.tmp" "$obj"
done

17
symbol-exports.txt Normal file
View File

@@ -0,0 +1,17 @@
ConflictSet_addWrites
ConflictSet_check
ConflictSet_create
ConflictSet_destroy
ConflictSet_getBytes
ConflictSet_setOldestVersion
_ZN8weaselab11ConflictSet16setOldestVersionEl
_ZN8weaselab11ConflictSet9addWritesEPKNS0_10WriteRangeEil
_ZN8weaselab11ConflictSetaSEOS0_
_ZN8weaselab11ConflictSetC1El
_ZN8weaselab11ConflictSetC1EOS0_
_ZN8weaselab11ConflictSetC2El
_ZN8weaselab11ConflictSetC2EOS0_
_ZN8weaselab11ConflictSetD1Ev
_ZN8weaselab11ConflictSetD2Ev
_ZNK8weaselab11ConflictSet5checkEPKNS0_9ReadRangeEPNS0_6ResultEi
_ZNK8weaselab11ConflictSet8getBytesEv

9
symbol-imports.txt Normal file
View File

@@ -0,0 +1,9 @@
_GLOBAL_OFFSET_TABLE_
__stack_chk_fail@GLIBC_2.4
__tls_get_addr@GLIBC_2.3
abort@GLIBC_2.2.5
free@GLIBC_2.2.5
malloc@GLIBC_2.2.5
memcpy@GLIBC_2.14
memmove@GLIBC_2.2.5
memset@GLIBC_2.2.5

View File

@@ -1,15 +0,0 @@
ConflictSet_addWrites
ConflictSet_check
ConflictSet_create
ConflictSet_destroy
ConflictSet_setOldestVersion
_ZN11ConflictSet16setOldestVersionEl
_ZN11ConflictSet9addWritesEPKNS_10WriteRangeEil
_ZN11ConflictSetaSEOS_
_ZN11ConflictSetC1El
_ZN11ConflictSetC1EOS_
_ZN11ConflictSetC2El
_ZN11ConflictSetC2EOS_
_ZN11ConflictSetD1Ev
_ZN11ConflictSetD2Ev
_ZNK11ConflictSet5checkEPKNS_9ReadRangeEPNS_6ResultEi

9
test_conflict_set.py Normal file
View File

@@ -0,0 +1,9 @@
from conflict_set import *
def test_conflict_set():
with ConflictSet() as cs:
cs.addWrites(1, write(b""))
assert cs.check(read(0, b"")) == [Result.CONFLICT]
cs.setOldestVersion(1)
assert cs.check(read(0, b"")) == [Result.TOO_OLD]

View File

@@ -2,5 +2,15 @@
set -euo pipefail set -euo pipefail
# ./test_symbols.sh <library> <expected exported symbols file> <allowed imported symbols file>
diff -u <(sort < "$2") <(nm "$1" | grep " T " | cut -f3 -d " " | sort) diff -u <(sort < "$2") <(nm "$1" | grep " T " | cut -f3 -d " " | sort)
nm "$1" | grep " U " | (! grep -Pv 'abort|free|malloc|mem[a-z]*|__ashlti3|__stack_chk_[a-z]*') ec=0
for symbol in $(nm "$1" | grep " U " | sed 's/ U //') ; do
if ! grep --fixed-strings "$symbol" "$3" > /dev/null ; then
echo "Imported symbol $symbol not present in $3"
ec=1
fi
done
exit $ec