summaryrefslogtreecommitdiff
path: root/includes/rts/SpinLock.h
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2010-01-22 16:49:11 +0000
committerSimon Marlow <marlowsd@gmail.com>2010-01-22 16:49:11 +0000
commit65ac2f4cefcea7ca78a65ca22889b51b5a27d1f0 (patch)
treea841ea73d574bbda83eb387c8db530c342eb84e9 /includes/rts/SpinLock.h
parentf1d99ae043da2a4825d88756275477d82d92c967 (diff)
downloadhaskell-65ac2f4cefcea7ca78a65ca22889b51b5a27d1f0.tar.gz
When acquiring a spinlock, yieldThread() every 1000 spins (#3553, #3758)
This helps when the thread holding the lock has been descheduled, which is the main cause of the "last-core slowdown" problem. With this patch, I get much better results with -N8 on an 8-core box, although some benchmarks are still worse than with 7 cores. I also added a yieldThread() into the any_work() loop of the parallel GC when it has no work to do. Oddly, this seems to improve performance on the parallel GC benchmarks even when all the cores are busy. Perhaps it is due to reducing contention on the memory bus.
Diffstat (limited to 'includes/rts/SpinLock.h')
-rw-r--r--includes/rts/SpinLock.h29
1 files changed, 18 insertions, 11 deletions
diff --git a/includes/rts/SpinLock.h b/includes/rts/SpinLock.h
index 3d0b56cfcb..8b337de73f 100644
--- a/includes/rts/SpinLock.h
+++ b/includes/rts/SpinLock.h
@@ -36,7 +36,6 @@ typedef StgWord SpinLock;
typedef lnat SpinLockCount;
-
#if defined(PROF_SPIN)
// PROF_SPIN enables counting the number of times we spin on a lock
@@ -45,13 +44,16 @@ typedef lnat SpinLockCount;
INLINE_HEADER void ACQUIRE_SPIN_LOCK(SpinLock * p)
{
StgWord32 r = 0;
-spin:
- r = cas((StgVolatilePtr)&(p->lock), 1, 0);
- if (r == 0) {
- p->spin++;
- busy_wait_nop();
- goto spin;
- }
+ nat i;
+ do {
+ for (i = 0; i < SPIN_COUNT; i++) {
+ r = cas((StgVolatilePtr)&(p->lock), 1, 0);
+ if (r != 0) return;
+ p->spin++;
+ busy_wait_nop();
+ }
+ yieldThread();
+ } while (1);
}
// release spin lock
@@ -75,10 +77,15 @@ INLINE_HEADER void initSpinLock(SpinLock * p)
INLINE_HEADER void ACQUIRE_SPIN_LOCK(SpinLock * p)
{
StgWord32 r = 0;
+ nat i;
do {
- r = cas((StgVolatilePtr)p, 1, 0);
- busy_wait_nop();
- } while(r == 0);
+ for (i = 0; i < SPIN_COUNT; i++) {
+ r = cas((StgVolatilePtr)p, 1, 0);
+ if (r != 0) return;
+ busy_wait_nop();
+ }
+ yieldThread();
+ } while (1);
}
// release spin lock