Compare commits
3 Commits
cdb5360b9a
...
a4d1f91670
Author | SHA1 | Date | |
---|---|---|---|
a4d1f91670 | |||
b7cdecaf71 | |||
cda28643a6 |
@@ -2607,16 +2607,25 @@ ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
|
||||
__attribute__((__visibility__("default"))) void
|
||||
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
|
||||
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
|
||||
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 *
|
||||
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};
|
||||
result->totalBytes += mallocBytesDelta;
|
||||
return result;
|
||||
}
|
||||
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
|
||||
using Impl = ConflictSet::Impl;
|
||||
@@ -2630,6 +2639,12 @@ ConflictSet_getBytes(void *cs) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
||||
std::string getSearchPathPrintable(Node *n) {
|
||||
|
100
README.md
100
README.md
@@ -9,49 +9,49 @@ Hardware for all benchmarks is a mac m1 2020.
|
||||
## Skip list
|
||||
|
||||
```
|
||||
New conflict set: 1.964 sec
|
||||
New conflict set: 1.962 sec
|
||||
0.637 Mtransactions/sec
|
||||
2.546 Mkeys/sec
|
||||
Detect only: 1.859 sec
|
||||
0.672 Mtransactions/sec
|
||||
2.690 Mkeys/sec
|
||||
Skiplist only: 1.275 sec
|
||||
0.980 Mtransactions/sec
|
||||
3.921 Mkeys/sec
|
||||
2.548 Mkeys/sec
|
||||
Detect only: 1.842 sec
|
||||
0.679 Mtransactions/sec
|
||||
2.714 Mkeys/sec
|
||||
Skiplist only: 1.261 sec
|
||||
0.991 Mtransactions/sec
|
||||
3.964 Mkeys/sec
|
||||
Performance counters:
|
||||
Build: 0.0496
|
||||
Add: 0.0539
|
||||
Detect: 1.86
|
||||
D.Sort: 0.412
|
||||
D.Combine: 0.0139
|
||||
D.CheckRead: 0.682
|
||||
D.CheckIntraBatch: 0.00673
|
||||
D.MergeWrite: 0.593
|
||||
D.RemoveBefore: 0.148
|
||||
Build: 0.0597
|
||||
Add: 0.0587
|
||||
Detect: 1.84
|
||||
D.Sort: 0.411
|
||||
D.Combine: 0.0136
|
||||
D.CheckRead: 0.67
|
||||
D.CheckIntraBatch: 0.00671
|
||||
D.MergeWrite: 0.592
|
||||
D.RemoveBefore: 0.146
|
||||
```
|
||||
|
||||
## Radix tree (this implementation)
|
||||
|
||||
```
|
||||
New conflict set: 1.289 sec
|
||||
0.970 Mtransactions/sec
|
||||
3.879 Mkeys/sec
|
||||
Detect only: 1.199 sec
|
||||
1.043 Mtransactions/sec
|
||||
4.170 Mkeys/sec
|
||||
Skiplist only: 0.542 sec
|
||||
2.305 Mtransactions/sec
|
||||
9.220 Mkeys/sec
|
||||
New conflict set: 1.285 sec
|
||||
0.973 Mtransactions/sec
|
||||
3.892 Mkeys/sec
|
||||
Detect only: 1.196 sec
|
||||
1.045 Mtransactions/sec
|
||||
4.180 Mkeys/sec
|
||||
Skiplist only: 0.539 sec
|
||||
2.320 Mtransactions/sec
|
||||
9.281 Mkeys/sec
|
||||
Performance counters:
|
||||
Build: 0.0395
|
||||
Add: 0.0492
|
||||
Build: 0.0377
|
||||
Add: 0.0493
|
||||
Detect: 1.2
|
||||
D.Sort: 0.411
|
||||
D.Sort: 0.41
|
||||
D.Combine: 0.0135
|
||||
D.CheckRead: 0.22
|
||||
D.CheckIntraBatch: 0.00652
|
||||
D.MergeWrite: 0.322
|
||||
D.RemoveBefore: 0.223
|
||||
D.CheckRead: 0.219
|
||||
D.CheckIntraBatch: 0.00654
|
||||
D.MergeWrite: 0.319
|
||||
D.RemoveBefore: 0.224
|
||||
```
|
||||
|
||||
# Our benchmark
|
||||
@@ -60,25 +60,25 @@ Performance counters:
|
||||
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 249.47 | 4,008,533.72 | 0.5% | 0.01 | `point reads`
|
||||
| 236.78 | 4,223,252.12 | 0.4% | 0.01 | `prefix reads`
|
||||
| 432.76 | 2,310,737.74 | 0.1% | 0.01 | `range reads`
|
||||
| 449.42 | 2,225,105.96 | 0.5% | 0.01 | `point writes`
|
||||
| 438.47 | 2,280,674.39 | 0.3% | 0.01 | `prefix writes`
|
||||
| 242.92 | 4,116,581.59 | 3.7% | 0.02 | `range writes`
|
||||
| 553.31 | 1,807,319.60 | 0.7% | 0.01 | `monotonic increasing point writes`
|
||||
| 246.99 | 4,048,700.59 | 0.2% | 0.01 | `point reads`
|
||||
| 260.16 | 3,843,784.65 | 0.1% | 0.01 | `prefix reads`
|
||||
| 493.35 | 2,026,953.19 | 0.1% | 0.01 | `range reads`
|
||||
| 462.05 | 2,164,289.23 | 0.6% | 0.01 | `point writes`
|
||||
| 448.19 | 2,231,205.25 | 0.9% | 0.01 | `prefix writes`
|
||||
| 255.83 | 3,908,845.72 | 1.5% | 0.02 | `range writes`
|
||||
| 582.63 | 1,716,349.02 | 1.3% | 0.01 | `monotonic increasing point writes`
|
||||
|
||||
## Radix tree (this implementation)
|
||||
|
||||
| ns/op | op/s | err% | total | benchmark
|
||||
|--------------------:|--------------------:|--------:|----------:|:----------
|
||||
| 19.35 | 51,669,510.11 | 0.2% | 0.01 | `point reads`
|
||||
| 56.64 | 17,655,057.00 | 0.2% | 0.01 | `prefix reads`
|
||||
| 217.04 | 4,607,450.05 | 0.2% | 0.01 | `range reads`
|
||||
| 26.31 | 38,012,015.29 | 0.0% | 0.01 | `point writes`
|
||||
| 41.45 | 24,124,003.19 | 0.2% | 0.01 | `prefix writes`
|
||||
| 48.33 | 20,691,082.14 | 0.0% | 0.01 | `range writes`
|
||||
| 84.92 | 11,775,856.81 | 4.0% | 0.01 | `monotonic increasing point writes`
|
||||
| 19.42 | 51,483,206.67 | 0.3% | 0.01 | `point reads`
|
||||
| 58.43 | 17,115,612.57 | 0.1% | 0.01 | `prefix reads`
|
||||
| 216.09 | 4,627,766.60 | 0.2% | 0.01 | `range reads`
|
||||
| 28.35 | 35,267,567.72 | 0.2% | 0.01 | `point writes`
|
||||
| 43.43 | 23,026,226.17 | 0.2% | 0.01 | `prefix writes`
|
||||
| 50.00 | 20,000,000.00 | 0.0% | 0.01 | `range writes`
|
||||
| 92.38 | 10,824,863.69 | 4.1% | 0.01 | `monotonic increasing point writes`
|
||||
|
||||
# "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
|
||||
|
||||
```
|
||||
Check: 11.267 seconds, 331.812 MB/s, Add: 5.33323 seconds, 131.635 MB/s, Gc ratio: 45.4671%
|
||||
Check: 11.3385 seconds, 329.718 MB/s, Add: 5.35612 seconds, 131.072 MB/s, Gc ratio: 45.7173%
|
||||
```
|
||||
|
||||
## radix tree
|
||||
|
||||
```
|
||||
Check: 2.48508 seconds, 1504.38 MB/s, Add: 2.07295 seconds, 338.666 MB/s, Gc ratio: 42.2825%
|
||||
Check: 2.48583 seconds, 1503.93 MB/s, Add: 2.12768 seconds, 329.954 MB/s, Gc ratio: 41.7943%
|
||||
```
|
||||
|
||||
## hash table
|
||||
@@ -101,5 +101,5 @@ Check: 2.48508 seconds, 1504.38 MB/s, Add: 2.07295 seconds, 338.666 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)
|
||||
|
||||
```
|
||||
Check: 1.83931 seconds, 2032.56 MB/s, Add: 0.607861 seconds, 1154.93 MB/s, Gc ratio: 48.7142%
|
||||
Check: 1.83386 seconds, 2038.6 MB/s, Add: 0.601411 seconds, 1167.32 MB/s, Gc ratio: 48.9776%
|
||||
```
|
||||
|
@@ -7,6 +7,7 @@ int main(void) {
|
||||
ConflictSet_WriteRange w;
|
||||
ConflictSet_Result result;
|
||||
ConflictSet_ReadRange r;
|
||||
int64_t bytes;
|
||||
w.begin.p = (const uint8_t *)"0000";
|
||||
w.begin.len = 4;
|
||||
w.end.len = 0;
|
||||
@@ -17,6 +18,8 @@ int main(void) {
|
||||
r.readVersion = 0;
|
||||
ConflictSet_check(cs, &r, &result, 1);
|
||||
assert(result == ConflictSet_Conflict);
|
||||
bytes = ConflictSet_getBytes(cs);
|
||||
assert(bytes > 0);
|
||||
ConflictSet_destroy(cs);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -17,4 +17,6 @@ int main(void) {
|
||||
r.readVersion = 0;
|
||||
cs.check(&r, &result, 1);
|
||||
assert(result == ConflictSet::Conflict);
|
||||
int64_t bytes = cs.getBytes();
|
||||
assert(bytes > 0);
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ limitations under the License.
|
||||
* - It's safe to operate on two different ConflictSets in two different
|
||||
* threads concurrently
|
||||
* - 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 {
|
||||
enum Result {
|
||||
@@ -110,7 +110,8 @@ private:
|
||||
* - It's safe to operate on two different ConflictSets in two different
|
||||
* threads concurrently
|
||||
* - 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;
|
||||
|
||||
@@ -150,7 +151,8 @@ typedef struct {
|
||||
} ConflictSet_WriteRange;
|
||||
|
||||
/** 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);
|
||||
|
||||
/** `writes` must be sorted ascending, and must not have adjacent or
|
||||
@@ -173,6 +175,6 @@ ConflictSet *ConflictSet_create(int64_t oldestVersion);
|
||||
void ConflictSet_destroy(ConflictSet *cs);
|
||||
|
||||
/** Returns the total bytes in use by this ConflictSet */
|
||||
int64_t ConflictSet_getBytes(ConflictSet *cs);
|
||||
int64_t ConflictSet_getBytes(const ConflictSet *cs);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user