Hash :
9faf7059
Author :
Date :
2023-06-20T19:04:49
Optimize angle::Spinlock performance
This optimization is a preparation for future commits.
Performance was tested by defining `ContextMutexType = angle::Spinlock`
to use `SharedContextMutex<angle::Spinlock>` as `mSharedContextMutex`.
Test result is average time for 1000'000 `glGetError()` calls on S906B
with locked CPU frequencies:
SharedContextMutex<angle::Spinlock>
Before the optimization: 14.289 ms
After the optimization: 12.941 ms (-9.4%)
Performance when not using `angle::Spinlock` (current code):
SingleContextMutex: 9.115 ms (-36.2%)
SharedContextMutex<std::mutex>: 29.186 ms (+204.3%)
Bug: angleproject:8226
Change-Id: I447ff807cd6b72ff3fc115e73736fe63eb642785
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4632728
Commit-Queue: Igor Nazarov <i.nazarov@samsung.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Spinlock.h:
// Spinlock is a lock that loops actively until it gets the resource.
// Only use it when the lock will be granted in reasonably short time.
#ifndef COMMON_SPINLOCK_H_
#define COMMON_SPINLOCK_H_
#include "common/angleutils.h"
#ifdef _MSC_VER
# include <intrin.h> // for _mm_pause() and __yield()
#endif
#if defined(__ARM_ARCH_7__) || defined(__aarch64__)
# if defined(__GNUC__) || defined(__clang__)
# include <arm_acle.h> // for __yield()
# endif
#endif
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
# define ANGLE_SMT_PAUSE() _mm_pause()
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
# define ANGLE_SMT_PAUSE() __asm__ __volatile__("pause;")
#elif defined(_M_ARM) || defined(_M_ARM64) || defined(__ARM_ARCH_7__) || defined(__aarch64__)
# define ANGLE_SMT_PAUSE() __yield()
#else
# define ANGLE_SMT_PAUSE() static_cast<void>(0)
#endif
namespace angle
{
class Spinlock
{
public:
Spinlock() noexcept;
bool try_lock() noexcept;
void lock() noexcept;
void unlock() noexcept;
private:
std::atomic_int mLock;
};
ANGLE_INLINE Spinlock::Spinlock() noexcept : mLock(0) {}
ANGLE_INLINE bool Spinlock::try_lock() noexcept
{
// Relaxed check first to prevent unnecessary cache misses.
return mLock.load(std::memory_order_relaxed) == 0 &&
mLock.exchange(1, std::memory_order_acquire) == 0;
}
ANGLE_INLINE void Spinlock::lock() noexcept
{
while (mLock.exchange(1, std::memory_order_acquire) != 0)
{
// Relaxed wait to prevent unnecessary cache misses.
while (mLock.load(std::memory_order_relaxed) != 0)
{
// Optimization for simultaneous multithreading.
ANGLE_SMT_PAUSE();
}
}
}
ANGLE_INLINE void Spinlock::unlock() noexcept
{
mLock.store(0, std::memory_order_release);
}
} // namespace angle
#endif // COMMON_SPINLOCK_H_