proxygen
|
#include <MicroLock.h>
Public Member Functions | |
void | unlock (unsigned slot) |
void | unlock () |
void | init () |
Protected Member Functions | |
detail::Futex * | word () const |
uint32_t | baseShift (unsigned slot) const |
uint32_t | heldBit (unsigned slot) const |
uint32_t | waitBit (unsigned slot) const |
Static Protected Member Functions | |
static void | lockSlowPath (uint32_t oldWord, detail::Futex<> *wordPtr, uint32_t slotHeldBit, unsigned maxSpins, unsigned maxYields) |
Protected Attributes | |
uint8_t | lock_ |
Tiny exclusive lock that packs four lock slots into a single byte. Each slot is an independent real, sleeping lock. The default lock and unlock functions operate on slot zero, which modifies only the low two bits of the host byte.
You should zero-initialize the bits of a MicroLock that you intend to use.
If you're not space-constrained, prefer std::mutex, which will likely be faster, since it has more than two bits of information to work with.
You are free to put a MicroLock in a union with some other object. If, for example, you want to use the bottom two bits of a pointer as a lock, you can put a MicroLock in a union with the pointer and limit yourself to MicroLock slot zero, which will use the two least-significant bits in the bottom byte.
(Note that such a union is safe only because MicroLock is based on a character type, and even under a strict interpretation of C++'s aliasing rules, character types may alias anything.)
MicroLock uses a dirty trick: it actually operates on the full 32-bit, four-byte-aligned bit of memory into which it is embedded. It never modifies bits outside the ones it's defined to modify, but it accesses all the bits in the 32-bit memory location for purposes of futex management.
The MaxSpins template parameter controls the number of times we spin trying to acquire the lock. MaxYields controls the number of times we call sched_yield; once we've tried to acquire the lock MaxSpins + MaxYields times, we sleep on the lock futex. By adjusting these parameters, you can make MicroLock behave as much or as little like a conventional spinlock as you'd like.
With the default template options, the timings for uncontended acquire-then-release come out as follows on Intel(R) Xeon(R) CPU E5-2660 0 @ 2.20GHz, in /opt, as of the master tree at Tue, 01 Mar 2016 19:48:15.
MicroSpinLockUncontendedBenchmark 13.46ns 74.28M PicoSpinLockUncontendedBenchmark 14.99ns 66.71M MicroLockUncontendedBenchmark 27.06ns 36.96M StdMutexUncontendedBenchmark 25.18ns 39.72M
(The virtual dispatch benchmark is provided for scale.)
While the uncontended case for MicroLock is competitive with the glibc 2.2.0 implementation of std::mutex, std::mutex is likely to be faster in the contended case, because we need to wake up all waiters when we release.
Make sure to benchmark your particular workload.
Definition at line 99 of file MicroLock.h.
|
inlineprotected |
Definition at line 135 of file MicroLock.h.
References folly::kIsLittleEndian, lock_, uint32_t, and word().
Referenced by heldBit(), and waitBit().
|
inlineprotected |
Definition at line 144 of file MicroLock.h.
References baseShift().
Referenced by folly::MicroLockBase< MaxSpins, MaxYields >::lock(), folly::MicroLockBase< MaxSpins, MaxYields >::try_lock(), and unlock().
|
inline |
Definition at line 124 of file MicroLock.h.
|
staticprotected |
Definition at line 24 of file MicroLock.cpp.
References folly::asm_volatile_pause(), folly::detail::futexWait(), retry, uint32_t, and folly::fibers::yield().
Referenced by folly::MicroLockBase< MaxSpins, MaxYields >::lock().
|
inline |
Definition at line 152 of file MicroLock.h.
References folly::detail::futexWake(), heldBit(), uint32_t, waitBit(), and word().
|
inline |
Definition at line 120 of file MicroLock.h.
|
inlineprotected |
Definition at line 148 of file MicroLock.h.
References baseShift().
Referenced by folly::MicroLockBase< MaxSpins, MaxYields >::lock(), and unlock().
|
inlineprotected |
Definition at line 129 of file MicroLock.h.
References lock_, and uint32_t.
Referenced by baseShift(), folly::MicroLockBase< MaxSpins, MaxYields >::lock(), folly::MicroLockBase< MaxSpins, MaxYields >::try_lock(), and unlock().
|
protected |
Definition at line 105 of file MicroLock.h.
Referenced by baseShift(), and word().