Skip to content

Commit

Permalink
make spinlocks degrade better when under high contention
Browse files Browse the repository at this point in the history
  • Loading branch information
erh committed Oct 13, 2011
1 parent 3cf3191 commit 6867235
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 3 deletions.
10 changes: 8 additions & 2 deletions dbtests/spin_lock_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <boost/thread/thread.hpp>
#include "dbtests.h"
#include "../util/concurrency/spin_lock.h"
#include "../util/timer.h"

namespace {

Expand Down Expand Up @@ -73,8 +74,10 @@ namespace {
int counter = 0;

const int threads = 64;
const int incs = 10000;
const int incs = 50000;
LockTester* testers[threads];

Timer timer;

for ( int i = 0; i < threads; i++ ) {
testers[i] = new LockTester( &spin, &counter );
Expand All @@ -87,7 +90,10 @@ namespace {
ASSERT_EQUALS( testers[i]->requests(), incs );
delete testers[i];
}


int ms = timer.millis();
log() << "spinlock ConcurrentIncs time: " << ms << endl;

ASSERT_EQUALS( counter, threads*incs );
#if defined(__linux__)
ASSERT( SpinLock::isfast() );
Expand Down
31 changes: 30 additions & 1 deletion util/concurrency/spin_lock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,36 @@ namespace mongo {
#if defined(_WIN32)
EnterCriticalSection(&_cs);
#elif defined(__USE_XOPEN2K)
pthread_spin_lock( &_lock );

/**
* this is designed to perform close to the default spin lock
* the reason for the mild insanity is to prevent horrible performance
* when contention spikes
* it allows spinlocks to be used in many more places
* which is good because even with this change they are about 8x faster on linux
*/

if ( pthread_spin_trylock( &_lock ) == 0 )
return;

for ( int i=0; i<1000; i++ )
if ( pthread_spin_trylock( &_lock ) == 0 )
return;

for ( int i=0; i<1000; i++ ) {
if ( pthread_spin_trylock( &_lock ) == 0 )
return;
pthread_yield();
}

struct timespec t;
t.tv_sec = 0;
t.tv_nsec = 5000000;

while ( pthread_spin_trylock( &_lock ) != 0 ) {
nanosleep(&t, NULL);
}

#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
// fast path
if (!_locked && !__sync_lock_test_and_set(&_locked, true)) {
Expand Down

0 comments on commit 6867235

Please sign in to comment.