Skip to content

Commit 3147be2

Browse files
author
Aleksandr Kriukov
committed
refactor thread ctx
1 parent eee3fb5 commit 3147be2

File tree

3 files changed

+112
-94
lines changed

3 files changed

+112
-94
lines changed

ydb/library/actors/core/executor_pool_basic.cpp

+14-38
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "executor_pool_basic.h"
22
#include "executor_pool_basic_feature_flags.h"
33
#include "actor.h"
4+
#include "executor_thread_ctx.h"
45
#include "probes.h"
56
#include "mailbox.h"
67
#include <ydb/library/actors/util/affinity.h>
@@ -167,7 +168,7 @@ namespace NActors {
167168
}
168169

169170
if (workerId >= 0) {
170-
Threads[workerId].ExchangeState(TExecutorThreadCtx::WS_NONE);
171+
Threads[workerId].ExchangeState(EThreadState::None);
171172
}
172173

173174
TAtomic x = AtomicGet(Semaphore);
@@ -191,7 +192,7 @@ namespace NActors {
191192
} else {
192193
if (const ui32 activation = Activations.Pop(++revolvingCounter)) {
193194
if (workerId >= 0) {
194-
Threads[workerId].ExchangeState(TExecutorThreadCtx::WS_RUNNING);
195+
Threads[workerId].ExchangeState(EThreadState::Work);
195196
}
196197
AtomicDecrement(Semaphore);
197198
TlsThreadContext->Timers.HPNow = GetCycleCountFast();
@@ -244,18 +245,18 @@ namespace NActors {
244245
inline void TBasicExecutorPool::WakeUpLoop(i16 currentThreadCount) {
245246
for (i16 i = 0;;) {
246247
TExecutorThreadCtx& threadCtx = Threads[i];
247-
TExecutorThreadCtx::TWaitState state = threadCtx.GetState();
248-
switch (state.Flag) {
249-
case TExecutorThreadCtx::WS_NONE:
250-
case TExecutorThreadCtx::WS_RUNNING:
248+
EThreadState state = threadCtx.GetState<EThreadState>();
249+
switch (state) {
250+
case EThreadState::None:
251+
case EThreadState::Work:
251252
if (++i >= MaxThreadCount - SharedExecutorsCount) {
252253
i = 0;
253254
}
254255
break;
255-
case TExecutorThreadCtx::WS_ACTIVE:
256-
case TExecutorThreadCtx::WS_BLOCKED:
257-
if (threadCtx.ReplaceState(state, TExecutorThreadCtx::WS_NONE)) {
258-
if (state.Flag == TExecutorThreadCtx::WS_BLOCKED) {
256+
case EThreadState::Spin:
257+
case EThreadState::Sleep:
258+
if (threadCtx.ReplaceState<EThreadState>(state, EThreadState::None)) {
259+
if (state == EThreadState::Sleep) {
259260
ui64 beforeUnpark = GetCycleCountFast();
260261
threadCtx.StartWakingTs = beforeUnpark;
261262
if (TlsThreadContext && TlsThreadContext->WaitingStats) {
@@ -601,38 +602,13 @@ namespace NActors {
601602
}
602603

603604
bool TExecutorThreadCtx::Wait(ui64 spinThresholdCycles, std::atomic<bool> *stopFlag) {
604-
TWaitState state = ExchangeState(WS_ACTIVE);
605-
Y_ABORT_UNLESS(state.Flag == WS_NONE, "WaitingFlag# %d", int(state.Flag));
606-
if (OwnerExecutorPool) {
607-
// if (!OwnerExecutorPool->SetSleepOwnSharedThread()) {
608-
// return false;
609-
// }
610-
// if (TBasicExecutorPool *pool = OtherExecutorPool; pool) {
611-
// if (!pool->SetSleepBorrowedSharedThread()) {
612-
// return false;
613-
// }
614-
//}
615-
}
605+
EThreadState state = ExchangeState<EThreadState>(EThreadState::Spin);
606+
Y_ABORT_UNLESS(state == EThreadState::None, "WaitingFlag# %d", int(state));
616607
if (spinThresholdCycles > 0) {
617608
// spin configured period
618609
Spin(spinThresholdCycles, stopFlag);
619-
// then - sleep
620-
state = GetState();
621-
if (state.Flag == WS_ACTIVE) {
622-
if (ReplaceState(state, WS_BLOCKED)) {
623-
if (Sleep(stopFlag)) { // interrupted
624-
return true;
625-
}
626-
} else {
627-
NextPool = state.NextPool;
628-
}
629-
}
630-
} else {
631-
Block(stopFlag);
632610
}
633-
634-
Y_DEBUG_ABORT_UNLESS(stopFlag->load() || GetState().Flag == WS_NONE);
635-
return false;
611+
return Sleep(stopFlag);
636612
}
637613

638614
}

ydb/library/actors/core/executor_thread.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ namespace NActors {
523523
std::vector<TExecutorPoolBaseMailboxed*> pools;
524524
do {
525525
if (NeedToReloadPools.load() == EState::NeedToReloadPools) {
526-
otherPool = dynamic_cast<TExecutorPoolBaseMailboxed*>(ThreadCtx->OtherExecutorPool.load());
526+
// otherPool = dynamic_cast<TExecutorPoolBaseMailboxed*>(ThreadCtx->OtherExecutorPool.load());
527527
NeedToReloadPools = EState::Running;
528528
}
529529
bool wasWorking = true;

ydb/library/actors/core/executor_thread_ctx.h

+97-55
Original file line numberDiff line numberDiff line change
@@ -11,66 +11,43 @@ namespace NActors {
1111
class TExecutorThread;
1212
class TBasicExecutorPool;
1313

14-
struct TExecutorThreadCtx {
15-
enum EWaitState : ui64 {
16-
WS_NONE,
17-
WS_ACTIVE,
18-
WS_BLOCKED,
19-
WS_RUNNING
20-
};
21-
22-
struct TWaitState {
23-
EWaitState Flag = WS_NONE;
24-
ui32 NextPool = Max<ui32>();
25-
26-
TWaitState() = default;
27-
28-
explicit TWaitState(ui64 state)
29-
: Flag(static_cast<EWaitState>(state & 0x7))
30-
, NextPool(state >> 3)
31-
{}
32-
33-
explicit TWaitState(EWaitState flag, ui32 nextPool = Max<ui32>())
34-
: Flag(flag)
35-
, NextPool(nextPool)
36-
{}
37-
38-
explicit operator ui64() {
39-
return Flag | ui64(NextPool << 3);
40-
}
41-
};
14+
enum class EThreadState : ui64 {
15+
None,
16+
Spin,
17+
Sleep,
18+
Work
19+
};
4220

21+
struct TGenericExecutorThreadCtx {
4322
TAutoPtr<TExecutorThread> Thread;
4423
TThreadParkPad WaitingPad;
4524

4625
private:
47-
std::atomic<ui64> WaitingFlag = WS_NONE;
26+
std::atomic<ui64> WaitingFlag = static_cast<ui64>(EThreadState::None);
4827

4928
public:
50-
TBasicExecutorPool *OwnerExecutorPool = nullptr;
51-
std::atomic<TBasicExecutorPool*> OtherExecutorPool = nullptr;
5229
ui64 StartWakingTs = 0;
53-
ui32 NextPool = 0;
54-
bool IsShared;
55-
56-
// different threads must spin/block on different cache-lines.
57-
// we add some padding bytes to enforce this rule;
5830

31+
template <typename TWaitState>
5932
TWaitState GetState() {
6033
return TWaitState(WaitingFlag.load());
6134
}
6235

63-
TWaitState ExchangeState(EWaitState flag, ui32 nextPool = Max<ui32>()) {
64-
return TWaitState(WaitingFlag.exchange(static_cast<ui64>(TWaitState(flag, nextPool))));
36+
template <typename TWaitState>
37+
TWaitState ExchangeState(TWaitState state) {
38+
return TWaitState(WaitingFlag.exchange(static_cast<ui64>(state)));
6539
}
6640

67-
bool ReplaceState(TWaitState &expected, EWaitState flag, ui32 nextPool = Max<ui32>()) {
41+
template <typename TWaitState>
42+
bool ReplaceState(TWaitState &expected, TWaitState state) {
6843
ui64 expectedInt = static_cast<ui64>(expected);
69-
bool result = WaitingFlag.compare_exchange_strong(expectedInt, static_cast<ui64>(TWaitState(flag, nextPool)));
44+
bool result = WaitingFlag.compare_exchange_strong(expectedInt, static_cast<ui64>(state));
7045
expected = TWaitState(expectedInt);
7146
return result;
7247
}
7348

49+
protected:
50+
template <typename TDerived, typename TWaitState>
7451
void Spin(ui64 spinThresholdCycles, std::atomic<bool> *stopFlag) {
7552
ui64 start = GetCycleCountFast();
7653
bool doSpin = true;
@@ -81,11 +58,11 @@ namespace NActors {
8158
break;
8259
}
8360
for (ui32 i = 0; i < 12; ++i) {
84-
TWaitState state = GetState();
85-
if (state.Flag == WS_ACTIVE) {
61+
TWaitState state = GetState<TWaitState>();
62+
if (static_cast<EThreadState>(state) == EThreadState::Spin) {
8663
SpinLockPause();
8764
} else {
88-
NextPool = state.NextPool;
65+
static_cast<TDerived*>(this)->AfterWakeUp(state);
8966
doSpin = false;
9067
break;
9168
}
@@ -100,36 +77,101 @@ namespace NActors {
10077
}
10178
}
10279

80+
template <typename TDerived, typename TWaitState>
10381
bool Sleep(std::atomic<bool> *stopFlag) {
10482
Y_DEBUG_ABORT_UNLESS(TlsThreadContext);
10583

106-
TWaitState state;
84+
TWaitState state = TWaitState{EThreadState::Spin};
85+
if (!ReplaceState<TWaitState>(state, TWaitState{EThreadState::Sleep})) {
86+
static_cast<TDerived*>(this)->AfterWakeUp(state);
87+
return false;
88+
}
89+
10790
do {
10891
TlsThreadContext->Timers.HPNow = GetCycleCountFast();
10992
TlsThreadContext->Timers.Elapsed += TlsThreadContext->Timers.HPNow - TlsThreadContext->Timers.HPStart;
11093
if (WaitingPad.Park()) // interrupted
11194
return true;
11295
TlsThreadContext->Timers.HPStart = GetCycleCountFast();
11396
TlsThreadContext->Timers.Parked += TlsThreadContext->Timers.HPStart - TlsThreadContext->Timers.HPNow;
114-
state = GetState();
115-
} while (state.Flag == WS_BLOCKED && !stopFlag->load(std::memory_order_relaxed));
116-
NextPool = state.NextPool;
97+
state = GetState<TWaitState>();
98+
} while (static_cast<EThreadState>(state) == EThreadState::Sleep && !stopFlag->load(std::memory_order_relaxed));
99+
100+
static_cast<TDerived*>(this)->AfterWakeUp(state);
117101
return false;
118102
}
103+
};
104+
105+
struct TExecutorThreadCtx : public TGenericExecutorThreadCtx {
106+
using TBase = TGenericExecutorThreadCtx;
107+
108+
TBasicExecutorPool *OwnerExecutorPool = nullptr;
109+
110+
void Spin(ui64 spinThresholdCycles, std::atomic<bool> *stopFlag) {
111+
this->TBase::Spin<TExecutorThreadCtx, EThreadState>(spinThresholdCycles, stopFlag);
112+
}
113+
114+
bool Sleep(std::atomic<bool> *stopFlag) {
115+
return this->TBase::Sleep<TExecutorThreadCtx, EThreadState>(stopFlag);
116+
}
119117

120118
bool Wait(ui64 spinThresholdCycles, std::atomic<bool> *stopFlag); // in executor_pool_basic.cpp
121119

122-
bool Block(std::atomic<bool> *stopFlag) {
123-
TWaitState state{WS_ACTIVE};
124-
if (ReplaceState(state, WS_BLOCKED)) {
125-
Y_ABORT_UNLESS(state.Flag == WS_ACTIVE, "WaitingFlag# %d", int(state.Flag));
126-
return Sleep(stopFlag);
127-
} else {
128-
return false;
129-
}
120+
void AfterWakeUp(EThreadState /*state*/) {
130121
}
131122

132123
TExecutorThreadCtx() = default;
133124
};
134125

126+
127+
constexpr ui32 MaxPoolsForSharedThreads = 4;
128+
129+
struct TSharedExecutorThreadCtx : public TGenericExecutorThreadCtx {
130+
using TBase = TGenericExecutorThreadCtx;
131+
132+
struct TWaitState {
133+
EThreadState Flag = EThreadState::None;
134+
ui32 NextPool = Max<ui32>();
135+
136+
TWaitState() = default;
137+
138+
TWaitState(ui64 state)
139+
: Flag(static_cast<EThreadState>(state & 0x7))
140+
, NextPool(state >> 3)
141+
{}
142+
143+
TWaitState(EThreadState flag, ui32 nextPool = Max<ui32>())
144+
: Flag(flag)
145+
, NextPool(nextPool)
146+
{}
147+
148+
explicit operator ui64() {
149+
return static_cast<ui64>(Flag) | ui64(NextPool << 3);
150+
}
151+
152+
explicit operator EThreadState() {
153+
return Flag;
154+
}
155+
};
156+
157+
std::atomic<TBasicExecutorPool*> ExecutorPools[MaxPoolsForSharedThreads];
158+
ui32 NextPool = 0;
159+
160+
void AfterWakeUp(TWaitState state) {
161+
NextPool = state.NextPool;
162+
}
163+
164+
void Spin(ui64 spinThresholdCycles, std::atomic<bool> *stopFlag) {
165+
this->TBase::Spin<TSharedExecutorThreadCtx, TWaitState>(spinThresholdCycles, stopFlag);
166+
}
167+
168+
bool Sleep(std::atomic<bool> *stopFlag) {
169+
return this->TBase::Sleep<TSharedExecutorThreadCtx, TWaitState>(stopFlag);
170+
}
171+
172+
bool Wait(ui64 spinThresholdCycles, std::atomic<bool> *stopFlag); // in executor_pool_basic.cpp
173+
174+
TSharedExecutorThreadCtx() = default;
175+
};
176+
135177
}

0 commit comments

Comments
 (0)