feat: bucketized futexes - #2469
Conversation
There was a problem hiding this comment.
Benchmark Results
Details
| Benchmark | Current: d3446a9 | Previous: 2e23902 | Performance Ratio |
|---|---|---|---|
| startup_benchmark Build Time | 82.65 s |
80.34 s |
1.03 ❗ |
| startup_benchmark File Size | 0.77 MB |
0.80 MB |
0.96 ❗ |
| Startup Time - 1 core | 0.69 s (±0.02 s) |
0.75 s (±0.02 s) |
0.93 ❗ |
| Startup Time - 2 cores | 0.70 s (±0.03 s) |
0.74 s (±0.02 s) |
0.95 ❗ |
| Startup Time - 4 cores | 0.72 s (±0.02 s) |
0.74 s (±0.02 s) |
0.97 |
| multithreaded_benchmark Build Time | 81.23 s |
82.11 s |
0.99 ❗ |
| multithreaded_benchmark File Size | 0.88 MB |
0.86 MB |
1.03 ❗ |
| Multithreaded Pi Efficiency - 2 Threads | 91.83 % (±8.80 %) |
85.89 % (±6.61 %) |
1.07 |
| Multithreaded Pi Efficiency - 4 Threads | 45.18 % (±2.89 %) |
43.43 % (±2.56 %) |
1.04 |
| Multithreaded Pi Efficiency - 8 Threads | 26.48 % (±1.70 %) |
25.76 % (±1.53 %) |
1.03 |
| micro_benchmarks Build Time | 80.25 s |
80.40 s |
1.00 ❗ |
| micro_benchmarks File Size | 0.89 MB |
0.86 MB |
1.03 ❗ |
| Scheduling time - 1 thread | 64.23 ticks (±1.98 ticks) |
62.65 ticks (±4.06 ticks) |
1.03 |
| Scheduling time - 2 threads | 37.50 ticks (±5.89 ticks) |
34.08 ticks (±4.10 ticks) |
1.10 |
| Micro - Time for syscall (getpid) | 3.21 ticks (±0.52 ticks) |
3.45 ticks (±0.58 ticks) |
0.93 |
| Memcpy speed - (built_in) block size 4096 | 79646.67 MByte/s (±55666.05 MByte/s) |
82448.38 MByte/s (±56997.13 MByte/s) |
0.97 |
| Memcpy speed - (built_in) block size 1048576 | 30604.34 MByte/s (±24669.01 MByte/s) |
30585.98 MByte/s (±24707.84 MByte/s) |
1.00 |
| Memcpy speed - (built_in) block size 16777216 | 28763.57 MByte/s (±23568.32 MByte/s) |
26340.06 MByte/s (±21720.96 MByte/s) |
1.09 |
| Memset speed - (built_in) block size 4096 | 79943.39 MByte/s (±55878.72 MByte/s) |
82292.76 MByte/s (±56891.50 MByte/s) |
0.97 |
| Memset speed - (built_in) block size 1048576 | 31324.31 MByte/s (±25103.08 MByte/s) |
31323.85 MByte/s (±25145.86 MByte/s) |
1.00 |
| Memset speed - (built_in) block size 16777216 | 29517.89 MByte/s (±24009.86 MByte/s) |
27104.68 MByte/s (±22209.94 MByte/s) |
1.09 |
| Memcpy speed - (rust) block size 4096 | 75809.82 MByte/s (±52772.14 MByte/s) |
74097.96 MByte/s (±51811.44 MByte/s) |
1.02 |
| Memcpy speed - (rust) block size 1048576 | 30528.91 MByte/s (±24576.30 MByte/s) |
30361.60 MByte/s (±24602.37 MByte/s) |
1.01 |
| Memcpy speed - (rust) block size 16777216 | 29004.83 MByte/s (±23757.32 MByte/s) |
27625.34 MByte/s (±22806.88 MByte/s) |
1.05 |
| Memset speed - (rust) block size 4096 | 76319.23 MByte/s (±53139.69 MByte/s) |
74373.47 MByte/s (±51976.48 MByte/s) |
1.03 |
| Memset speed - (rust) block size 1048576 | 31264.77 MByte/s (±25007.03 MByte/s) |
31110.89 MByte/s (±25033.24 MByte/s) |
1.00 |
| Memset speed - (rust) block size 16777216 | 29745.53 MByte/s (±24187.01 MByte/s) |
28386.93 MByte/s (±23265.03 MByte/s) |
1.05 |
| alloc_benchmarks Build Time | 78.67 s |
74.76 s |
1.05 ❗ |
| alloc_benchmarks File Size | 0.85 MB |
0.87 MB |
0.97 ❗ |
| Allocations - Allocation success | 91.38 % |
91.31 % |
1.00 ❗ |
| Allocations - Deallocation success | 100.00 % |
100.00 % |
1 |
| Allocations - Pre-fail Allocations | 61.60 % |
61.44 % |
1.00 ❗ |
| Allocations - Average Allocation time | 7836.82 Ticks (±195.83 Ticks) |
5860.58 Ticks (±98.43 Ticks) |
1.34 ❗ |
| Allocations - Average Allocation time (no fail) | 8542.16 Ticks (±307.81 Ticks) |
6554.81 Ticks (±92.86 Ticks) |
1.30 ❗ |
| Allocations - Average Deallocation time | 2492.95 Ticks (±798.79 Ticks) |
1805.01 Ticks (±250.35 Ticks) |
1.38 |
| mutex_benchmark Build Time | 79.32 s |
79.82 s |
0.99 ❗ |
| mutex_benchmark File Size | 0.89 MB |
0.86 MB |
1.03 ❗ |
| Mutex Stress Test Average Time per Iteration - 1 Threads | 12.32 ns (±0.47 ns) |
12.10 ns (±0.41 ns) |
1.02 |
| Mutex Stress Test Average Time per Iteration - 2 Threads | 99.62 ns (±5.91 ns) |
40.26 ns (±1.68 ns) |
2.47 ❗ |
This comment was automatically generated by workflow using github-action-benchmark.
17f45b2 to
2f2342e
Compare
|
I can indeed make it generic, it's just that AFAIK there is no other usecase in the code for now for such a map. So this may be a case of "premature abstraction" :D But if you insist, I'll gladly do it :) |
| } | ||
|
|
||
| fn hash_key(v: usize) -> usize { | ||
| let v = (v >> 3).to_be_bytes(); |
There was a problem hiding this comment.
If you're trying to remove the zero bits resulting from AtomicU32's alignment, then you have to shift by 2, not 3. Since you're hashing anyway, I don't think this is necessary anyway.
There was a problem hiding this comment.
I was trying to remove the last 3 bits from the address, which for some reason I believed to always be 0
But you are correct that this is in any case not needed since we hash. It may be the remain of an attempt to not use a hash function at all for better performance.
If it produced a more or less uniformly distributed distribution, (addr >> 3) % N would likely be better as it is less intensive than computing a hash.
Let me know what you think :)
| type Bucket = InterruptSpinMutex<TaskListBucket>; | ||
|
|
||
| #[repr(transparent)] | ||
| struct TaskListBucket(LinkedList<BucketElem>); |
There was a problem hiding this comment.
Using a linked-list here is a bit unfortunate – if there are a lot of tasks, the hashbrown::HashTable as an inner map to avoid having to recompute the hash while keeping hashmap-like lookup performance. Or alternatively, use a BTreeMap – that will also reduce memory usage as addresses become unused.
There was a problem hiding this comment.
I think there is the same reasoning here... Wanting to avoid doing two hashes of the key. But I can switch to a BTreeMap.
And also it was likely easier to think in terms of iterators on a linked list than on a map
2f2342e to
d3446a9
Compare
While tracking #2468, I initially suspected the futex lock to be an issue, so I applied the "Todo" and made a bucket list instead of the single lock.
I have based this off on #2468 so that we get performance results that make sense.