15#define ASPIN_MAX_USEC 10
16#define ASPIN_INITIAL_TARGET 10
17#define ASPIN_NOSPIN (-2147483647 - 1)
20#define ASPIN_PERF_STATS
23typedef struct AdaptiveSpin {
24 atomic(int32) spintarget;
25#ifdef ASPIN_PERF_STATS
26 atomic(intptr) stats_uncontended;
27 atomic(intptr) stats_spin;
28 atomic(intptr) stats_futex;
29 atomic(intptr) stats_capped;
30 atomic(intptr) stats_timeout;
31 atomic(intptr) stats_yield;
35typedef struct AdaptiveSpinState {
46_meta_inline
void aspinRecordUncontended(_Inout_ AdaptiveSpin* aspin)
48#ifdef ASPIN_PERF_STATS
49 atomicFetchAdd(intptr, &aspin->stats_uncontended, 1, Relaxed);
55_meta_inline
void aspinRecordSpin(_Inout_ AdaptiveSpin* aspin)
57#ifdef ASPIN_PERF_STATS
58 atomicFetchAdd(intptr, &aspin->stats_spin, 1, Relaxed);
64_meta_inline
void aspinRecordFutex(_Inout_ AdaptiveSpin* aspin)
66#ifdef ASPIN_PERF_STATS
67 atomicFetchAdd(intptr, &aspin->stats_futex, 1, Relaxed);
73_meta_inline
void aspinRecordCapped(_Inout_ AdaptiveSpin* aspin)
75#ifdef ASPIN_PERF_STATS
76 atomicFetchAdd(intptr, &aspin->stats_capped, 1, Relaxed);
82_meta_inline
void aspinRecordTimeout(_Inout_ AdaptiveSpin* aspin)
84#ifdef ASPIN_PERF_STATS
85 atomicFetchAdd(intptr, &aspin->stats_timeout, 1, Relaxed);
91_meta_inline
void aspinRecordYield(_Inout_ AdaptiveSpin* aspin)
93#ifdef ASPIN_PERF_STATS
94 atomicFetchAdd(intptr, &aspin->stats_yield, 1, Relaxed);
100_meta_inline
void aspinInit(_Out_ AdaptiveSpin* aspin,
bool nospin)
102 memset(aspin, 0,
sizeof(AdaptiveSpin));
108 atomicStore(int32, &aspin->spintarget, nospin ? ASPIN_NOSPIN : ASPIN_INITIAL_TARGET, Relaxed);
111_meta_inline
void aspinBegin(_Inout_ AdaptiveSpin* aspin, _Out_ AdaptiveSpinState* ass,
115 ass->start = ass->now;
116 ass->spincap = ass->start + ASPIN_MAX_USEC;
118 ass->curtarget = atomicLoad(int32, &aspin->spintarget, Relaxed);
119 if (ass->curtarget < 1 && ass->curtarget != ASPIN_NOSPIN)
120 ass->curtarget = ASPIN_INITIAL_TARGET;
121 ass->spincount = (ass->curtarget == ASPIN_NOSPIN) ? 0 : ass->curtarget * 2;
123 ass->rstate = (ass->now & 0xffffffff);
126_meta_inline
bool aspinSpin(_Inout_ AdaptiveSpin* aspin, _Inout_ AdaptiveSpinState* ass)
130 if ((ass->spincount & 7) == 7)
134 if (ass->spincount > 0 && ass->now > ass->spincap) {
136 atomicStore(int32, &aspin->spintarget, (ass->curtarget * 2 - ass->spincount) / 2, Relaxed);
138 aspinRecordCapped(aspin);
141 if (ass->spincount > 0) {
150_meta_inline
bool aspinTimeout(_Inout_ AdaptiveSpin* aspin, _Inout_ AdaptiveSpinState* ass)
158 if (ass->spincount == 0)
161 if (ass->now > ass->endtime) {
162 aspinRecordTimeout(aspin);
168_meta_inline
void aspinAdapt(_Inout_ AdaptiveSpin* aspin, _Inout_ AdaptiveSpinState* ass)
171 if (ass->now > ass->endtime)
174 if (ass->curtarget != ASPIN_NOSPIN) {
175 if (ass->spincount > 0) {
177 int32 realtarget = atomicLoad(int32, &aspin->spintarget, Relaxed);
178 atomicFetchAdd(int32,
180 clamp(ass->curtarget - ass->spincount, -realtarget, realtarget) / 8 + 1,
182 aspinRecordSpin(aspin);
184 if (ass->now <= ass->spincap) {
186 atomicFetchAdd(int32, &aspin->spintarget, ass->curtarget / 8 + 1, Relaxed);
188 aspinRecordFutex(aspin);
191 aspinRecordFutex(aspin);
195_meta_inline int64 aspinTimeoutRemaining(_In_ AdaptiveSpinState* ass)
202aspinHandleContention(_Inout_opt_ AdaptiveSpin* aspin, _Inout_ AdaptiveSpinState* ass)
217 if (
lcgRandom(&ass->rstate) % (++ass->contention + 7) > 8) {
219 aspinRecordYield(aspin);
222 for (
int i = ass->contention * ass->contention; i >= 0; --i) {
228_meta_inline
void aspinEndContention(_Inout_ AdaptiveSpinState* ass)
Comparison and clamping macros.
CPU-specific operations and atomic primitives.
int32 lcgRandom(uint32 *state)
#define timeForever
Maximum representable time value (approximately year 294,276 CE)
Simple linear congruential pseudo-random number generator.
Operating system services.
Time manipulation and conversion functions.