From b5476c81d2ab27dd4a46064d3fa45556630fd3cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Haisman?= Date: Fri, 11 Mar 2016 11:28:27 +0100 Subject: [PATCH] Spinlock spin with pause instruction Hi. I have noticed that Cygwin's spinlock goes into heavy sleeping code for each spin. It seems it would be a good idea to actually try to spin a bit first. There is this 'pause' instruction which let's the CPU make such busy loops be less busy. Here is a patch to do this. -- VH --- winsup/cygwin/thread.cc | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 06a487aab..531d6a846 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -1916,6 +1916,19 @@ pthread_spinlock::lock () { pthread_t self = ::pthread_self (); int result = -1; + unsigned spins = 0; + + /* + We want to spin using 'pause' instruction on multi-core system but we + want to avoid this on single-core systems. + + The limit of 1000 spins is semi-arbitrary. Microsoft suggests (in their + InitializeCriticalSectionAndSpinCount documentation on MSDN) they are + using spin count limit 4000 for their heap manager critical + sections. Other source suggest spin count as small as 200 for fast path + of mutex locking. + */ + unsigned const FAST_SPINS_LIMIT = wincap.cpu_count () != 1 ? 1000 : 0; do { @@ -1924,8 +1937,13 @@ pthread_spinlock::lock () set_owner (self); result = 0; } - else if (pthread::equal (owner, self)) + else if (unlikely(pthread::equal (owner, self))) result = EDEADLK; + else if (spins < FAST_SPINS_LIMIT) + { + ++spins; + __asm__ volatile ("pause":::); + } else { /* Minimal timeout to minimize CPU usage while still spinning. */