Skip to content

Commit 0ba2b0d

Browse files
authored
try optimize queue spinlock (#60)
* try optimize
1 parent 1f87c4f commit 0ba2b0d

File tree

5 files changed

+45
-26
lines changed

5 files changed

+45
-26
lines changed

bench/readme.md

+26-12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@
1414
| IntrusiveThreadPool_task_100000/iterations:10/repeats:5_stddev | 20.8 ms | 5.86 ms| 5 |
1515
| IntrusiveThreadPool_task_100000/iterations:10/repeats:5_cv | 6.50 % | 6.31 % | 5 |
1616

17+
### DistributedPool Task 100,000 (std::mutex)
18+
19+
| Benchmark | Time | CPU | Iterations |
20+
|-----------------------------------------------------------------|---------|--------|------------|
21+
| DistributedPool_task_100000/iterations:10/repeats:5 | 254 ms | 96.8 ms| 10 |
22+
| DistributedPool_task_100000/iterations:10/repeats:5 | 492 ms | 196 ms | 10 |
23+
| DistributedPool_task_100000/iterations:10/repeats:5 | 563 ms | 224 ms | 10 |
24+
| DistributedPool_task_100000/iterations:10/repeats:5 | 254 ms | 118 ms | 10 |
25+
| DistributedPool_task_100000/iterations:10/repeats:5 | 175 ms | 83.4 ms| 10 |
26+
| DistributedPool_task_100000/iterations:10/repeats:5_mean | 348 ms | 144 ms | 5 |
27+
| DistributedPool_task_100000/iterations:10/repeats:5_median | 254 ms | 118 ms | 5 |
28+
| DistributedPool_task_100000/iterations:10/repeats:5_stddev | 169 ms | 62.7 ms| 5 |
29+
| DistributedPool_task_100000/iterations:10/repeats:5_cv | 48.67 % | 43.65 %| 5 |
30+
1731
### DistributedPool Task 100,000 (spinlock)
1832

1933
| Benchmark | Time | CPU | Iterations |
@@ -42,19 +56,19 @@
4256
| DistributedPool_task_100000/iterations:10/repeats:5_stddev | 108 ms | 45.5 ms| 5 |
4357
| DistributedPool_task_100000/iterations:10/repeats:5_cv | 37.98 %| 39.18 %| 5 |
4458

45-
### DistributedPool Task 100,000 (std::mutex)
59+
### DistributedPool Task 100,000 (spinlock with weak mm)
4660

47-
| Benchmark | Time | CPU | Iterations |
48-
|-----------------------------------------------------------------|---------|--------|------------|
49-
| DistributedPool_task_100000/iterations:10/repeats:5 | 254 ms | 96.8 ms| 10 |
50-
| DistributedPool_task_100000/iterations:10/repeats:5 | 492 ms | 196 ms | 10 |
51-
| DistributedPool_task_100000/iterations:10/repeats:5 | 563 ms | 224 ms | 10 |
52-
| DistributedPool_task_100000/iterations:10/repeats:5 | 254 ms | 118 ms | 10 |
53-
| DistributedPool_task_100000/iterations:10/repeats:5 | 175 ms | 83.4 ms| 10 |
54-
| DistributedPool_task_100000/iterations:10/repeats:5_mean | 348 ms | 144 ms | 5 |
55-
| DistributedPool_task_100000/iterations:10/repeats:5_median | 254 ms | 118 ms | 5 |
56-
| DistributedPool_task_100000/iterations:10/repeats:5_stddev | 169 ms | 62.7 ms| 5 |
57-
| DistributedPool_task_100000/iterations:10/repeats:5_cv | 48.67 % | 43.65 %| 5 |
61+
| Benchmark | Time | CPU | Iterations |
62+
| --- | --- | --- | --- |
63+
| DistributedPool_task_100000/iterations:10/repeats:5 | 186 ms | 73.0 ms | 10 |
64+
| DistributedPool_task_100000/iterations:10/repeats:5 | 132 ms | 62.2 ms | 10 |
65+
| DistributedPool_task_100000/iterations:10/repeats:5 | 145 ms | 59.1 ms | 10 |
66+
| DistributedPool_task_100000/iterations:10/repeats:5 | 126 ms | 58.9 ms | 10 |
67+
| DistributedPool_task_100000/iterations:10/repeats:5 | 149 ms | 62.4 ms | 10 |
68+
| DistributedPool_task_100000/iterations:10/repeats:5_mean | 148 ms | 63.1 ms | 5 |
69+
| DistributedPool_task_100000/iterations:10/repeats:5_median | 145 ms | 62.2 ms | 5 |
70+
| DistributedPool_task_100000/iterations:10/repeats:5_stddev | 23.5 ms | 5.76 ms | 5 |
71+
| DistributedPool_task_100000/iterations:10/repeats:5_cv | 15.90 % | 9.13 % | 5 |
5872

5973
### Compare std::mutex and async_mutex with coro
6074

src/components/sync/queue_spinlock.h

+11-8
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,23 @@ class QueueSpinLock final {
1414
public:
1515
explicit Guard(QueueSpinLock& host) : host(host) { host.Acquire(this); }
1616
~Guard() {
17-
if (is_owner) Release();
17+
if (is_owner.load(std::memory_order_acquire)) Release();
1818
}
1919

2020
void Release() {
2121
host.Release(this);
22-
is_owner.store(false);
22+
is_owner.store(false, std::memory_order_release);
2323
}
2424

25-
void SetOwner() { is_owner.store(true); }
25+
void SetOwner() { is_owner.store(true, std::memory_order_release); }
2626

27-
void SetNext(Guard* guard) { next.store(guard); }
27+
void SetNext(Guard* guard) { next.store(guard, std::memory_order_release); }
2828

29-
bool IsOwner() const { return is_owner.load(); }
29+
bool IsOwner() const {
30+
return is_owner.load(std::memory_order_acquire);
31+
}
3032

31-
bool HasNext() const { return next.load() != nullptr; }
33+
bool HasNext() const { return next.load(std::memory_order_acquire) != nullptr; }
3234

3335
void SetNextOwner() { next.load()->SetOwner(); }
3436

@@ -40,7 +42,7 @@ class QueueSpinLock final {
4042

4143
private:
4244
void Acquire(Guard* guard) {
43-
auto ancestor = tail_.exchange(guard);
45+
auto ancestor = tail_.exchange(guard/*, std::memory_order_acquire*/);
4446
if (ancestor == nullptr) {
4547
guard->SetOwner();
4648
return;
@@ -58,7 +60,8 @@ class QueueSpinLock final {
5860
}
5961

6062
Guard* old_guard = guard;
61-
while (!tail_.compare_exchange_weak(old_guard, nullptr)) {
63+
while (!tail_.compare_exchange_weak(old_guard, nullptr/*,
64+
std::memory_order_release*/)) {
6265
if (guard->HasNext()) {
6366
guard->SetNextOwner();
6467
return;

src/fiber/awaiter/wait_group_awaiter.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <mutex>
88

99
#include <components/intrusive/list.h>
10+
#include <components/sync/queue_spinlock.h>
1011
#include <fiber/awaiter/awaiter.h>
1112

1213
namespace NFibers {
@@ -15,23 +16,23 @@ template <class W>
1516
class WaitGroupWaiter : public IAwaiter,
1617
public NComponents::Node<WaitGroupWaiter<W>> {
1718
public:
18-
using Guard = std::unique_lock<typename W::Spinlock>;
19+
using Guard = NSync::QueueSpinLock::Guard;
1920

20-
WaitGroupWaiter(W* wg, Guard guard) : wg(wg), guard(std::move(guard)){};
21+
WaitGroupWaiter(W* wg, Guard& guard) : wg(wg), guard(guard){};
2122

2223
void AwaitSuspend(StoppedFiber fiber) override {
2324
assert(fiber.IsValid());
2425

2526
stopped_fiber = fiber;
2627
wg->Park(this);
27-
guard.release()->unlock();
28+
guard.Release();
2829
}
2930

3031
void Schedule() { stopped_fiber.Schedule(); }
3132

3233
private:
3334
W* wg;
34-
Guard guard;
35+
Guard& guard;
3536
StoppedFiber stopped_fiber;
3637
};
3738

src/fiber/sync/wait_group.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void WaitGroup::Done() {
3838
void WaitGroup::Wait() {
3939
Waiter::Guard guard(spinlock_);
4040
if (counter_ > 0) {
41-
Waiter wg_waiter(this, std::move(guard));
41+
Waiter wg_waiter(this, guard);
4242
Suspend(&wg_waiter);
4343
}
4444
}

src/fiber/sync/wait_group.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88

99
#include <components/intrusive/list.h>
1010
#include <components/sync/spinLock.h>
11+
#include <components/sync/queue_spinlock.h>
1112
#include <fiber/awaiter/wait_group_awaiter.h>
1213

1314
namespace NFibers {
1415

1516
class WaitGroup {
16-
using Spinlock = NSync::SpinLock;
17+
using Spinlock = NSync::QueueSpinLock;
1718
using Waiter = WaitGroupWaiter<WaitGroup>;
1819

1920
friend Waiter;

0 commit comments

Comments
 (0)