Implement a much faster spinlock.
authorMatthew Dillon <dillon@dragonflybsd.org>
Sun, 21 May 2006 20:23:29 +0000 (20:23 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sun, 21 May 2006 20:23:29 +0000 (20:23 +0000)
commitd666840ad3312b8c37863f61c8ee3139682230ed
tree49fa3b9bbbb53011a9d468802e52d8883ea3f19c
parenta523caf4590f1956b8e5fe33695050a6fe633a0e
Implement a much faster spinlock.

* Spinlocks can't conflict with FAST interrupts without deadlocking anyway,
  so instead of using a critical section simply do not allow an interrupt
  thread to preempt the current thread if it is holding a spinlock.  This
  cuts spinlock overhead in half.

* Implement shared spinlocks in addition to exclusive spinlocks.  Shared
  spinlocks would be used, e.g. for file descriptor table lookups.

* Cache a shared spinlock by using the spinlock's lock field as a bitfield,
  one for each cpu (bit 31 for exclusive locks).  A shared spinlock sets
  its cpu's shared bit and does not bother clearing it on unlock.

  This means that multiple, parallel shared spinlock accessors do NOT incur
  a cache conflict on the spinlock.  ALL parallel shared accessors operate
  at full speed (~10ns vs ~40-100ns in overhead).  90% of the 10ns in
  overhead is due to a necessary MFENCE to interlock against exclusive
  spinlocks on the mutex.  However, this MFENCE only has to play with
  pending cpu-local memory writes so it will always run at near full speed.

* Exclusive spinlocks in the face of previously cached shared spinlocks
  are now slightly more expensive because they have to clear the cached
  shared spinlock bits by checking the globaldata structure for each
  conflicting cpu to see if it is still holding a shared spinlock.  However,
  only the initial (unavoidable) atomic swap involves potential cache
  conflicts.  The shared bit checks involve only memory reads and the
  situation should be self-correcting from a performance standpoint since
  the shared bits then get cleared.

* Add sysctl's for basic spinlock performance testing.  Setting
  debug.spin_lock_test issues a test.  Tests #2 and #3 loop
  debug.spin_test_count times.  p.s. these tests will stall the whole
   machine.

1       Test the indefinite wait code
2       Time the best-case exclusive lock overhead
3       Time the best-case shared lock overhead

* TODO: A shared->exclusive spinlock upgrade inline with positive feedback,
  and an exclusive->shared spinlock downgrade inline.
13 files changed:
sys/kern/kern_ktr.c
sys/kern/kern_lock.c
sys/kern/kern_spinlock.c
sys/kern/lwkt_rwlock.c
sys/kern/lwkt_thread.c
sys/kern/lwkt_token.c
sys/netproto/smb/smb_subr.h
sys/sys/globaldata.h
sys/sys/spinlock.h
sys/sys/spinlock2.h
sys/sys/thread.h
sys/vfs/ntfs/ntfs_subr.c
sys/vm/vm_zone.c