[tor-commits] [tor-browser] 09/90: Bug 1784018 - Remove deprecated OSSpinLocks r=glandium
gitolite role
git at cupani.torproject.org
Tue Nov 22 09:57:44 UTC 2022
This is an automated email from the git hooks/post-receive script.
richard pushed a commit to branch tor-browser-102.5.0esr-12.0-1
in repository tor-browser.
commit 686cf978b10db3507631fec4a827c57207af1477
Author: Gabriele Svelto <gsvelto at mozilla.com>
AuthorDate: Wed Aug 24 09:18:57 2022 +0000
Bug 1784018 - Remove deprecated OSSpinLocks r=glandium
On macOS versions prior to 10.15 os_unfair_locks cannot spin in kernel-space
which degrades performance significantly. To obviate for this we spin in
user-space like OSSpinLock does, for the same number of times and invoking
x86-specific pause instructions in-between the locking attempts to avoid
starving a thread that might be running on the same physical core.
Differential Revision: https://phabricator.services.mozilla.com/D154205
---
memory/build/Mutex.cpp | 4 +--
memory/build/Mutex.h | 82 +++++++++++++++++++++++++++-----------------------
2 files changed, 47 insertions(+), 39 deletions(-)
diff --git a/memory/build/Mutex.cpp b/memory/build/Mutex.cpp
index 5a7c6d46e99c..8bc69635efa5 100644
--- a/memory/build/Mutex.cpp
+++ b/memory/build/Mutex.cpp
@@ -7,7 +7,7 @@
#if defined(XP_DARWIN)
// static
-bool Mutex::UseUnfairLocks() {
+bool Mutex::SpinInKernelSpace() {
if (__builtin_available(macOS 10.15, *)) {
return true;
}
@@ -16,6 +16,6 @@ bool Mutex::UseUnfairLocks() {
}
// static
-bool Mutex::gFallbackToOSSpinLock = !UseUnfairLocks();
+bool Mutex::gSpinInKernelSpace = SpinInKernelSpace();
#endif // defined(XP_DARWIN)
diff --git a/memory/build/Mutex.h b/memory/build/Mutex.h
index 3827a8a6757f..3a86d0e2e75d 100644
--- a/memory/build/Mutex.h
+++ b/memory/build/Mutex.h
@@ -10,7 +10,7 @@
#if defined(XP_WIN)
# include <windows.h>
#elif defined(XP_DARWIN)
-# include <libkern/OSAtomic.h>
+# include "mozilla/Assertions.h"
# include <os/lock.h>
#else
# include <pthread.h>
@@ -31,12 +31,6 @@ OS_UNFAIR_LOCK_AVAILABILITY
OS_EXPORT OS_NOTHROW OS_NONNULL_ALL void os_unfair_lock_lock_with_options(
os_unfair_lock_t lock, os_unfair_lock_options_t options);
}
-
-static_assert(OS_UNFAIR_LOCK_INIT._os_unfair_lock_opaque == OS_SPINLOCK_INIT,
- "OS_UNFAIR_LOCK_INIT and OS_SPINLOCK_INIT have the same "
- "value");
-static_assert(sizeof(os_unfair_lock) == sizeof(OSSpinLock),
- "os_unfair_lock and OSSpinLock are the same size");
#endif // defined(XP_DARWIN)
// Mutexes based on spinlocks. We can't use normal pthread spinlocks in all
@@ -48,10 +42,7 @@ struct Mutex {
#if defined(XP_WIN)
CRITICAL_SECTION mMutex;
#elif defined(XP_DARWIN)
- union {
- os_unfair_lock mUnfairLock;
- OSSpinLock mSpinLock;
- } mMutex;
+ os_unfair_lock mMutex;
#else
pthread_mutex_t mMutex;
#endif
@@ -63,10 +54,7 @@ struct Mutex {
return false;
}
#elif defined(XP_DARWIN)
- // The hack below works because both OS_UNFAIR_LOCK_INIT and
- // OS_SPINLOCK_INIT initialize the lock to 0 and in both case it's a 32-bit
- // integer.
- mMutex.mUnfairLock = OS_UNFAIR_LOCK_INIT;
+ mMutex = OS_UNFAIR_LOCK_INIT;
#elif defined(XP_LINUX) && !defined(ANDROID)
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr) != 0) {
@@ -90,19 +78,46 @@ struct Mutex {
#if defined(XP_WIN)
EnterCriticalSection(&mMutex);
#elif defined(XP_DARWIN)
- if (Mutex::gFallbackToOSSpinLock) {
- OSSpinLockLock(&mMutex.mSpinLock);
- } else {
- // We rely on a non-public function to improve performance here.
- // The OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION flag informs the kernel that
- // the calling thread is able to make progress even in absence of actions
- // from other threads and the OS_UNFAIR_LOCK_ADAPTIVE_SPIN one causes the
- // kernel to spin on a contested lock if the owning thread is running on
- // the same physical core (presumably only on x86 CPUs given that ARM
- // macs don't have cores capable of SMT).
+ // We rely on a non-public function to improve performance here.
+ // The OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION flag informs the kernel that
+ // the calling thread is able to make progress even in absence of actions
+ // from other threads and the OS_UNFAIR_LOCK_ADAPTIVE_SPIN one causes the
+ // kernel to spin on a contested lock if the owning thread is running on
+ // the same physical core (presumably only on x86 CPUs given that ARM
+ // macs don't have cores capable of SMT). On versions of macOS older than
+ // 10.15 the latter is not available and we spin in userspace instead.
+ if (Mutex::gSpinInKernelSpace) {
os_unfair_lock_lock_with_options(
- &mMutex.mUnfairLock,
+ &mMutex,
OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION | OS_UNFAIR_LOCK_ADAPTIVE_SPIN);
+ } else {
+# if defined(__x86_64__)
+ // On older versions of macOS (10.14 and older) the
+ // `OS_UNFAIR_LOCK_ADAPTIVE_SPIN` flag is not supported by the kernel,
+ // we spin in user-space instead like `OSSpinLock` does:
+ // https://github.com/apple/darwin-libplatform/blob/215b09856ab5765b7462a91be7076183076600df/src/os/lock.c#L183-L198
+ // Note that `OSSpinLock` uses 1000 iterations on x86-64:
+ // https://github.com/apple/darwin-libplatform/blob/215b09856ab5765b7462a91be7076183076600df/src/os/lock.c#L93
+ // ...but we only use 100 like it does on ARM:
+ // https://github.com/apple/darwin-libplatform/blob/215b09856ab5765b7462a91be7076183076600df/src/os/lock.c#L90
+ // We choose this value because it yields the same results in our
+ // benchmarks but is less likely to have detrimental effects caused by
+ // excessive spinning.
+ uint32_t retries = 100;
+
+ do {
+ if (os_unfair_lock_trylock(&mMutex)) {
+ return;
+ }
+
+ __asm__ __volatile__("pause");
+ } while (retries--);
+
+ os_unfair_lock_lock_with_options(&mMutex,
+ OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);
+# else
+ MOZ_CRASH("User-space spin-locks should never be used on ARM");
+# endif // defined(__x86_64__)
}
#else
pthread_mutex_lock(&mMutex);
@@ -113,19 +128,15 @@ struct Mutex {
#if defined(XP_WIN)
LeaveCriticalSection(&mMutex);
#elif defined(XP_DARWIN)
- if (Mutex::gFallbackToOSSpinLock) {
- OSSpinLockUnlock(&mMutex.mSpinLock);
- } else {
- os_unfair_lock_unlock(&mMutex.mUnfairLock);
- }
+ os_unfair_lock_unlock(&mMutex);
#else
pthread_mutex_unlock(&mMutex);
#endif
}
#if defined(XP_DARWIN)
- static bool UseUnfairLocks();
- static bool gFallbackToOSSpinLock;
+ static bool SpinInKernelSpace();
+ static bool gSpinInKernelSpace;
#endif // XP_DARWIN
};
@@ -153,10 +164,7 @@ struct StaticMutex {
typedef Mutex StaticMutex;
# if defined(XP_DARWIN)
-// The hack below works because both OS_UNFAIR_LOCK_INIT and OS_SPINLOCK_INIT
-// initialize the lock to 0 and in both case it's a 32-bit integer.
-# define STATIC_MUTEX_INIT \
- { .mUnfairLock = OS_UNFAIR_LOCK_INIT }
+# define STATIC_MUTEX_INIT OS_UNFAIR_LOCK_INIT
# elif defined(XP_LINUX) && !defined(ANDROID)
# define STATIC_MUTEX_INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
# else
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the tor-commits
mailing list