Skip to content

Commit

Permalink
HPCC-30156 Instrument CriticalSection
Browse files Browse the repository at this point in the history
Signed-off-by: Richard Chapman <[email protected]>
  • Loading branch information
richardkchapman committed Sep 6, 2023
1 parent 0ef5fbe commit c52bd06
Showing 1 changed file with 165 additions and 13 deletions.
178 changes: 165 additions & 13 deletions testing/unittests/unittests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,145 @@ CPPUNIT_TEST_SUITE_REGISTRATION( PipeRunTest );
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( PipeRunTest, "PipeRunTest" );
#endif

#ifndef _WIN32
//#define TIME_CRITSECS
#define CHECK_CS_CONTENTION

class InstrumentedCriticalSection
{
private:
MutexId mutex;
#ifdef _ASSERT_LOCK_SUPPORT
ThreadId owner = 0;
#endif
unsigned depth = 0;
#ifdef TIME_CRITSECS
cycle_t waitCycles = 0;
cycle_t holdCycles = 0;
cycle_t holdStart = 0;
#endif
#ifdef CHECK_CS_CONTENTION
unsigned contended = 0;
unsigned uncontended = 0;
bool wasContended = false;
#endif
InstrumentedCriticalSection (const CriticalSection &);
public:
inline InstrumentedCriticalSection()
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
#ifdef _DEBUG
verifyex(pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE)==0); // verify supports attr
#else
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
#endif
pthread_mutex_init(&mutex, &attr);
pthread_mutexattr_destroy(&attr);
}

inline ~InstrumentedCriticalSection()
{
#ifdef _ASSERT_LOCK_SUPPORT
assert(owner==0);
#endif
assert(depth==0);
pthread_mutex_destroy(&mutex);
#ifdef TIME_CRITSECS
if (waitCycles || holdCycles)
{
DBGLOG("Total wait time for CritSec: %" I64F "u ms", cycle_to_millisec(waitCycles));
DBGLOG("Total hold time for CritSec: %" I64F "u ms", cycle_to_millisec(holdCycles));
}
#endif
#ifdef CHECK_CS_CONTENTION
reportContended(true);
#endif
}

inline void enter()
{
cycle_t start = get_cycles_now();
#ifdef CHECK_CS_CONTENTION
bool isContended = depth != 0;
#endif
#ifdef _ASSERT_LOCK_SUPPORT
ThreadId me = GetCurrentThreadId();
#endif
pthread_mutex_lock(&mutex);
#ifdef TIME_CRITSECS
holdStart = get_cycles_now();
waitCycles += holdStart-start;
#endif
depth++;
#ifdef CHECK_CS_CONTENTION
if (isContended)
contended++;
else
uncontended++;
wasContended = isContended;
#endif
#ifdef _ASSERT_LOCK_SUPPORT
owner = me;
#endif
}

inline void leave()
{
bool isContended = false;
depth--;
if (!depth)
{
#ifdef _ASSERT_LOCK_SUPPORT
owner = 0;
#endif
#ifdef CHECK_CS_CONTENTION
isContended = wasContended;
#endif
#ifdef TIME_CRITSECS
holdCycles += get_cycles_now()-holdStart;
#endif
}
pthread_mutex_unlock(&mutex);
if (isContended)
reportContended(false);
}
inline void assertLocked()
{
#ifdef _ASSERT_LOCK_SUPPORT
assertex(owner == GetCurrentThreadId());
#endif
}
#ifdef CHECK_CS_CONTENTION
void reportContended(bool destructor);
#endif
};

static SpinLock sl;
void InstrumentedCriticalSection::reportContended(bool destructor)
{
if (contended*2 > uncontended && contended % 1000 == 0)
{
SpinBlock block(sl);
DBGLOG("Heavily contended critsec %u/%u", contended, contended+uncontended);
printStackReport();
}
else if (destructor && contended > 1000)
{
SpinBlock block(sl);
DBGLOG("Contended critsec %u/%u", contended, contended+uncontended);
}
}

class InstrumentedCriticalBlock
{
InstrumentedCriticalSection &crit;
public:
inline InstrumentedCriticalBlock(InstrumentedCriticalSection &c) : crit(c) { crit.enter(); }
inline ~InstrumentedCriticalBlock() { crit.leave(); }
};
#endif

class RelaxedAtomicTimingTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE( RelaxedAtomicTimingTest );
Expand All @@ -936,11 +1075,12 @@ class RelaxedAtomicTimingTest : public CppUnit::TestFixture

void testRun()
{
testRunner(0);
testRunner(1);
testRunner(2);
// testRunner(0);
// testRunner(1);
// testRunner(2);
testRunner(3);
testRunner(4);
// testRunner(4);
// testRunner(5);
}

void testRunner(unsigned mode)
Expand All @@ -949,25 +1089,27 @@ class RelaxedAtomicTimingTest : public CppUnit::TestFixture
unsigned count = 100000000;
RelaxedAtomic<int> ra[201];
CriticalSection lock[201];
InstrumentedCriticalSection ilock[201];

for (int a = 0; a < 201; a++)
ra[a] = 0;

class T : public CThreaded
{
public:
T(unsigned _count, RelaxedAtomic<int> &_ra, CriticalSection &_lock, unsigned _mode) : CThreaded(""), count(_count), ra(_ra), lock(_lock), mode(_mode)
T(unsigned _count, RelaxedAtomic<int> &_ra, CriticalSection &_lock, InstrumentedCriticalSection &_ilock, unsigned _mode)
: CThreaded(""), count(_count), ra(_ra), lock(_lock), ilock(_ilock), mode(_mode)
{}
virtual int run() override
{
switch(mode)
{
case 0: test0(); break;
case 1: test1(); break;
// Disabled next two for now as slow and not especially interesting
// case 2: test2(); break;
// case 3: test3(); break;
case 4: test4(); break;
case 2: test2(); break;
case 3: test3(); break;
case 4: test4(); break;
case 5: test5(); break;
}
return 0;
}
Expand All @@ -993,6 +1135,15 @@ class RelaxedAtomicTimingTest : public CppUnit::TestFixture
}
}
void test3()
{
int &a = (int &) ra;
while (count--)
{
InstrumentedCriticalBlock b(ilock);
a++;
}
}
void test4()
{
RelaxedAtomic<int> &a = ra;
while (count--)
Expand All @@ -1001,7 +1152,7 @@ class RelaxedAtomicTimingTest : public CppUnit::TestFixture
a.fastAdd(1);
}
}
void test4()
void test5()
{
int &a = (int &) ra;
while (count--)
Expand All @@ -1016,9 +1167,10 @@ class RelaxedAtomicTimingTest : public CppUnit::TestFixture
unsigned count;
RelaxedAtomic<int> &ra;
CriticalSection &lock;
} t1a(count, ra[0], lock[0], mode), t2a(count, ra[0], lock[0], mode), t3a(count, ra[0], lock[0], mode),
t1b(count, ra[0], lock[0], mode), t2b(count, ra[1], lock[1], mode), t3b(count, ra[2], lock[2], mode),
t1c(count, ra[0], lock[0], mode), t2c(count, ra[100], lock[100], mode), t3c(count, ra[200], lock[200], mode);;
InstrumentedCriticalSection &ilock;
} t1a(count, ra[0], lock[0], ilock[0], mode), t2a(count, ra[0], lock[0], ilock[0], mode), t3a(count, ra[0], lock[0], ilock[0], mode),
t1b(count, ra[0], lock[1], ilock[1], mode), t2b(count, ra[1], lock[2], ilock[2], mode), t3b(count, ra[2], lock[3], ilock[3], mode),
t1c(count, ra[0], lock[4], ilock[4], mode), t2c(count, ra[100], lock[100], ilock[100], mode), t3c(count, ra[200], lock[200], ilock[200], mode);;
DBGLOG("Testing RelaxedAtomics (test mode %u)", mode);
t1a.start();
t2a.start();
Expand Down

0 comments on commit c52bd06

Please sign in to comment.