|
|
/*++
Copyright (c) 1998-2001 Microsoft Corporation
Module Name : HashTest.cpp
Abstract: Test harness for LKRhash
Author: George V. Reilly (GeorgeRe) 06-Jan-1998
Environment: Win32 - User Mode
Project: LKRhash
Revision History:
--*/
#include "precomp.hxx"
DECLARE_DEBUG_PRINTS_OBJECT();
#define HASHTEST_STATIC_DATA
#include "WordHash.h"
#include "IniFile.h"
void test_iterators(unsigned highload, int initsize, int nsubtbls, int nInsertIfNotFound);
#ifdef LKR_STL_ITERATORS
#pragma message("test STL iterators")
void test_stl_iterators(unsigned highload, int initsize, int nsubtbls); #endif // LKR_STL_ITERATORS
#ifndef LKRHASH_KERNEL_MODE
void print_table_statistics(const CLKRHashTableStats& stats);
# ifdef LOCK_INSTRUMENTATION
void print_lock_statistics(const CLKRHashTableStats &stats); # endif
#endif // !LKRHASH_KERNEL_MODE
int expand_key_set(int maxkeys, int numkeys, bool fVerbose) ; #ifdef LKRHASH_KERNEL_MODE
void #else
unsigned __stdcall #endif
exercise_table(void *pinput);
// how many CPUs on this machine?
int NumProcessors() { static int s_nCPUs = 0; if (s_nCPUs == 0) { #ifdef LKRHASH_KERNEL_MODE
s_nCPUs = KeNumberProcessors; #else // !LKRHASH_KERNEL_MODE
SYSTEM_INFO si; GetSystemInfo(&si); s_nCPUs = si.dwNumberOfProcessors; #endif // !LKRHASH_KERNEL_MODE
} return s_nCPUs; }
// globals
int g_nokeys=0 ; CWord g_wordtable[MAXKEYS];
bool CheckRefCounts( LONG nRef, int iFirst = 0, int iLast = -1) { if (iLast == -1) iLast = g_nokeys; IRTLTRACE3("\nCheckRefCounts(%d, [%d,%d))\n", nRef, iFirst, iLast); bool f = true;
for (int i = iFirst; i != iLast; ++i) { f = f && (g_wordtable[i].m_cRefs == nRef); if (g_wordtable[i].m_cRefs != nRef) IRTLTRACE4("\nCRC: %d, %hs, expected %d, got %d\n", i, g_wordtable[i].m_str.m_psz, nRef, g_wordtable[i].m_cRefs); IRTLASSERT(g_wordtable[i].m_cRefs == nRef); }
return f; }
bool CWordHash::sm_fCaseInsensitive = true; bool CWordHash::sm_fMemCmp = false; int CWordHash::sm_nLastChars = 16; bool CWordHash::sm_fRefTrace = false; bool CWordHash::sm_fMultiKeys = false; bool CWordHash::sm_fUseLocks = true; bool CWordHash::sm_fNonPagedAllocs = true;
struct thread_data { CWordHash* ptbl ;
int threadno ; int first_key ; int last_key ; int rounds ; int lookup_freq ; unsigned highload ;
int cinserts ; int cdeletes ; int clookups ; int cfailures ; int m_nInsertIfNotFound; int m_nFindKeyCopy; int m_nSeed; // random seed
double duration ; HANDLE hevFinished; HANDLE hThread; } ;
const TCHAR* CommaNumber( int n, TCHAR* ptszBuff) { TCHAR* ptsz = ptszBuff; TCHAR tchComma = '\0';
int aThousands[4]; int iThousands = 0; unsigned int u = n;
if (n < 0) { *ptsz++ = '-'; u = -n; }
do { aThousands[iThousands++] = u % 1000; u /= 1000; } while (u != 0);
while (--iThousands >= 0) { u = aThousands[iThousands];
if (tchComma) *ptsz++ = tchComma;
unsigned d = u % 10; u /= 10; unsigned t = u % 10; u /= 10; unsigned h = u;
if (h > 0 || tchComma) *ptsz++ = (TCHAR) (h + '0'); if (t > 0 || h > 0 || tchComma) *ptsz++ = (TCHAR) (t + '0'); *ptsz++ = (TCHAR) (d + '0');
tchComma = ','; }
*ptsz = '\0'; return ptszBuff; }
#ifndef LKRHASH_KERNEL_MODE
typedef union { FILETIME ft; __int64 l64; } FILETIME_UINT64;
# define FILETIME_1_SECOND 10000000
# define FILETIME_1_MILLISECOND 10000
HANDLE HashTestCreateEvent() { return CreateEvent(NULL, // no security attributes
FALSE, // auto reset
FALSE, // not signalled
NULL); // no name
}
void HashTestResumeThread( HANDLE hThread) { ResumeThread(hThread); }
HANDLE HashTestCreateThread( unsigned (__stdcall * pfnThreadProc) (void *), void* pvContext, bool fSuspended) { unsigned dummy; return (HANDLE) _beginthreadex(NULL, 0, pfnThreadProc, pvContext, fSuspended ? CREATE_SUSPENDED : 0, &dummy); }
DWORD HashTestWaitForMultipleObjects( DWORD nCount, CONST HANDLE *lpHandles) { return WaitForMultipleObjects(nCount, lpHandles, TRUE, INFINITE); }
#else // LKRHASH_KERNEL_MODE
# define GetTickCount() NtGetTickCount()
# define GetCurrentThread() NtCurrentThread()
void SetThreadIdealProcessor( HANDLE hThread, DWORD dwIdealProcessor ) { NtSetInformationThread( hThread, ThreadIdealProcessor, &dwIdealProcessor, sizeof(dwIdealProcessor) ); }
// non-threadsafe implementation of rand and srand, stolen from CRT
unsigned long _holdrand = 1234567890;
void __cdecl srand( unsigned int seed) { _holdrand = (unsigned long) seed; }
int __cdecl rand() { return ((_holdrand = _holdrand * 214013L + 2531011L) >> 16) & 0x7fff; }
HANDLE HashTestCreateEvent() { HANDLE hEvent = NULL;
NTSTATUS status = NtCreateEvent( &hEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE); return hEvent; }
void HashTestResumeThread( HANDLE hThread) { NtResumeThread(hThread, NULL); }
HANDLE HashTestCreateThread( void (* pfnThreadProc) (void *), void* pvContext, bool fSuspended) { NTSTATUS status; HANDLE threadHandle; OBJECT_ATTRIBUTES objectAttributes;
//
// Create the thread.
//
InitializeObjectAttributes( &objectAttributes, // ObjectAttributes
NULL, // ObjectName
OBJ_KERNEL_HANDLE, // Attributes
NULL, // RootDirectory
NULL // SecurityDescriptor
); status = PsCreateSystemThread( &threadHandle, // ThreadHandle
THREAD_ALL_ACCESS, // DesiredAccess
&objectAttributes, // ObjectAttributes
NULL, // ProcessHandle
NULL, // ClientId
pfnThreadProc, // StartRoutine
pvContext // StartContext
);
if (!fSuspended) HashTestResumeThread(threadHandle);
return threadHandle; }
BOOL CloseHandle( HANDLE h) { return NT_SUCCESS(NtClose(h)); }
DWORD HashTestWaitForMultipleObjects( DWORD nCount, CONST HANDLE *lpHandles) { HANDLE ahHandles[MAX_THREADS+1];
for (int i = 0; i < nCount; ++i) ahHandles[i] = lpHandles[i]; return NtWaitForMultipleObjects((CHAR) nCount, ahHandles, WaitAll, FALSE, NULL); }
BOOL SetEvent( HANDLE hEvent) { return NT_SUCCESS(NtSetEvent(hEvent, NULL)); }
#endif // LKRHASH_KERNEL_MODE
#ifdef _M_IX86
// Use RDTSC to read timestamp
void GetCycleCount( LARGE_INTEGER *pliTimeStamp) { ULONG Lo; LONG Hi; _asm { _emit 0x0f _emit 0x31 mov Lo, eax mov Hi, edx } /* _asm */ pliTimeStamp->LowPart = Lo; pliTimeStamp->HighPart = Hi; } #endif // _M_IX86
int LKR_TestHashTable( CIniFileSettings& ifs) { CWordHash *pTbl ; int num_threads ; thread_data de_area[MAX_THREADS] ; HANDLE ahEvents[MAX_THREADS]; TCHAR tsz[1024] ; FILE *fp ; int keys_per_thread ; int i ; int sum_ins, sum_dels, sum_lookups ; int failures = 0, total_failures = 0; bool fVerbose = false; double dblSumDuration3 = 0; DWORD dwRunTime = GetTickCount(); int nBaseOps = 0;
#ifdef _NO_TRACING_
CREATE_DEBUG_PRINT_OBJECT("hashtest"); #endif
SetThreadIdealProcessor(GetCurrentThread(), 0);
_tprintf(_TEXT("\nTest driver for LKRhash\n") #ifdef LKRHASH_KERNEL_MODE
_TEXT(" (Kernel)") #endif
#ifdef IRTLDEBUG
_TEXT(" (Debug)") #endif
#ifdef LKR_PUBLIC_API
_TEXT(" (Public API)") #else
_TEXT(" (Internal API)") #endif
#ifdef LKR_COUNTDOWN
_TEXT(" (CountDown)") #else
_TEXT(" (CountUp)") #endif
#ifdef LKR_INDEX_HIBITS
_TEXT(" (Index hibits)\n") #else
_TEXT(" (No Index hibits)\n") #endif
#ifdef LKR_CONTRACT
_TEXT(" (Contraction)") #else
_TEXT(" (No Contraction)") #endif
#ifdef LKR_HYSTERESIS
_TEXT(" (Hysteresis)") #else
_TEXT(" (No Hysteresis)") #endif
#ifdef LKR_CONTRACT_BY_DIVISION
_TEXT(" (Contract: B > R/L)\n") #else
_TEXT(" (Contract: R < L*B)\n") #endif
#ifdef LKR_EXPAND_BY_DIVISION
_TEXT(" (Expand: B < R/L)") #else
_TEXT(" (Expand: R > L*B)") #endif
#ifdef LKR_EXPAND_CALC_FREELIST
_TEXT(" (Expand: Calc)") #else
_TEXT(" (Expand: No Calc)") #endif
#ifdef LKR_ALLOC_STATS
_TEXT(" (Alloc stats)") #else
_TEXT(" (No Alloc stats)") #endif
#ifdef LKR_OPS_STATS
_TEXT(" (Ops stats)\n") #else
_TEXT(" (No Ops stats)\n") #endif
#ifdef LKR_ALLOW_NULL_RECORDS
_TEXT(" (NULL records)") #endif
#ifdef LKR_DEPRECATED_ITERATORS
_TEXT(" (Deprecated Iterators)") #endif
#ifdef LKR_STL_ITERATORS
_TEXT(" (STL-style Iterators") # if LKR_STL_ITERATORS >= 2
_TEXT(", verbose)") # else
_TEXT(")") # endif
#else // !LKR_STL_ITERATORS
_TEXT(" (No STL-style Iterators)") #endif // !LKR_STL_ITERATORS
#ifdef LKR_APPLY_IF
_TEXT(" (ApplyIf)\n") #else
_TEXT(" (No ApplyIf)\n") #endif
#ifdef LKR_USE_BUCKET_LOCKS
_TEXT(" (Use Bucket Locks)") #else
_TEXT(" (No Bucket Locks)") #endif
#ifdef LKR_EXPOSED_TABLE_LOCK
_TEXT(" (Exposed Table Lock)") #endif
#ifdef LOCKS_SWITCH_TO_THREAD
_TEXT(" (SwitchToThread)\n") #else
_TEXT(" (Sleep)\n") #endif
#ifdef LOCK_NO_INTERLOCKED_TID
_TEXT(" (non-interlocked Tid)") #else // !LOCK_NO_INTERLOCKED_TID
_TEXT(" (interlocked Tid)") #endif // !LOCK_NO_INTERLOCKED_TID
#ifdef LOCK_ASM
_TEXT(" (Locks: ASM)") #else // !LOCK_ASM
_TEXT(" (Locks: no ASM)") #endif // !LOCK_ASM
_TEXT("\n\n") ) ;
#if defined(LKRHASH_ACACHE)
const TCHAR tszAllocator[] = _TEXT("ACache"); #elif defined(LKRHASH_ROCKALL_FAST)
const TCHAR tszAllocator[] = _TEXT("Rockall FAST_HEAP"); #elif defined(LKRHASH_PAGEDHEAP)
const TCHAR tszAllocator[] = _TEXT("CPagedHeap"); #elif defined(LKRHASH_NONPAGEDHEAP)
const TCHAR tszAllocator[] = _TEXT("CNonPagedHeap"); #elif defined(LKRHASH_NONPAGEDLOOKASIDE)
const TCHAR tszAllocator[] = _TEXT("CNonPagedLookasideList"); #elif defined(LKRHASH_PAGEDLOOKASIDE)
const TCHAR tszAllocator[] = _TEXT("CPagedLookasideList"); #else
const TCHAR tszAllocator[] = _TEXT("Default allocator (global operator new)"); #endif
_tprintf(_TEXT("%s version.\n"), tszAllocator);
IrtlSetDebugOutput(ifs.m_fDebugSpew ? 1 : 0);
#ifdef SAMPLE_LKRHASH_TESTCLASS
Test(fVerbose); if (fVerbose) _tprintf(_TEXT("Test succeeded\n")); #else
UNREFERENCED_PARAMETER(fVerbose); #endif // SAMPLE_LKRHASH_TESTCLASS
fp = _tfopen(ifs.m_tszDataFile, _TEXT("r") ) ; if (fp == NULL) { _tprintf(_TEXT("Can't open file `%s'.\n"), ifs.m_tszDataFile) ; return 1; }
char sz[1024];
_tprintf(_TEXT("Reading `%s' "), ifs.m_tszDataFile); for (g_nokeys = 0; g_nokeys < ifs.m_nMaxKeys; ) { if (fgets(sz, sizeof(sz)/sizeof(sz[0]), fp) == NULL) break; int cch = strlen(sz); // TODO: check for duplicates
if (cch > 0 && sz[cch-1] == '\n') sz[--cch] = '\0'; if (cch >= MAX_STRSIZE) sz[MAX_STRSIZE-1] = '\0'; if (cch > 0) { g_wordtable[g_nokeys].m_iIndex = g_nokeys; g_wordtable[g_nokeys++].m_str.Set(sz, cch); } if (g_nokeys % 10000 == 0) putchar('.'); }
fclose(fp) ;
_tprintf(_TEXT("\nLoaded %s keys from `%s', \n\t"), CommaNumber(g_nokeys, tsz), ifs.m_tszDataFile); g_nokeys = expand_key_set(ifs.m_nMaxKeys, g_nokeys, true) ; _tprintf(_TEXT(" expanded to %s keys.\n\n"), CommaNumber(g_nokeys, tsz));
int cchTotal = 0, cchMin = INT_MAX, cchMax = 0; for (i = 0; i < g_nokeys; ++i) { cchTotal += g_wordtable[i].m_str.m_cch; cchMin = min(cchMin, g_wordtable[i].m_str.m_cch); cchMax = max(cchMax, g_wordtable[i].m_str.m_cch); }
srand(ifs.m_nSeed) ;
_stprintf(tsz, _TEXT("%d"), ifs.m_nInitSize); if (ifs.m_nInitSize == LK_SMALL_TABLESIZE) _tcscpy(tsz, _TEXT("small")); else if (ifs.m_nInitSize == LK_MEDIUM_TABLESIZE) _tcscpy(tsz, _TEXT("medium")); else if (ifs.m_nInitSize == LK_LARGE_TABLESIZE) _tcscpy(tsz, _TEXT("large"));
DWORD initsize2 = ifs.m_nInitSize; DWORD nsubtbls2 = ifs.m_nSubTables; LK_TABLESIZE lkts = CWordHash::NumSubTables(ifs.m_nInitSize, nsubtbls2); _tprintf(_TEXT("Max load=%d, initsize=%s, ") _TEXT("%d subtables (%d tables, size=%d, lkts=%d).\n"), ifs.m_nHighLoad, tsz, ifs.m_nSubTables, nsubtbls2, initsize2, lkts); _tprintf(_TEXT("Lookup freq = %d, %d-%d threads, ") _TEXT("%d round%s.\n"), ifs.m_nLookupFreq, ifs.m_nMinThreads, ifs.m_nMaxThreads, ifs.m_nRounds, (ifs.m_nRounds==1 ? "" : "s")); _tprintf(_TEXT("%s keys from `%s'.\n"), CommaNumber(g_nokeys, tsz), ifs.m_tszDataFile); _tprintf(_TEXT("Key length: avg = %d, min = %d, max = %d.\n"), cchTotal / g_nokeys, cchMin, cchMax); _tprintf(_TEXT("Base Table = %s. Hash method = %s.\n"), CWordHash::ClassName(), CWordHash::HashMethod()); #ifdef LOCK_DEFAULT_SPIN_IMPLEMENTATION
# ifdef LKRHASH_GLOBAL_LOCK
_tprintf(_TEXT("GlobalLock = %s, ") _TEXT("%d bytes, ") _TEXT("Spin Count = %hd, ") _TEXT("Adj Factor = %.2f.\n"), CWordHash::GlobalLock::ClassName(), sizeof(CWordHash::GlobalLock), ifs.m_wTableSpin, CWordHash::GlobalLock::GetDefaultSpinAdjustmentFactor()); # endif
_tprintf(_TEXT("TableLock = %s, ") _TEXT("%d bytes, ") _TEXT("Spin Count = %hd, ") _TEXT("Adj Factor = %.2f.\n"), CWordHash::TableLock::ClassName(), sizeof(CWordHash::TableLock), ifs.m_wTableSpin, CWordHash::TableLock::GetDefaultSpinAdjustmentFactor()); _tprintf(_TEXT("BucketLock = %s, ") _TEXT("%d bytes, ") _TEXT("Spin Count = %hd, ") _TEXT("Adj Factor = %.2f.\n"), CWordHash::BucketLock::ClassName(), sizeof(CWordHash::BucketLock), ifs.m_wBucketSpin, CWordHash::BucketLock::GetDefaultSpinAdjustmentFactor()); #endif // LOCK_DEFAULT_SPIN_IMPLEMENTATION
#ifdef LOCK_PER_LOCK_SPINCOUNTS
_tprintf(_TEXT("Per")); #else
_tprintf(_TEXT("No per")); #endif
_tprintf(_TEXT("-lock spincounts. #CPUs = %d. Random seed = %d. ") _TEXT("Nodes/Clump = %d.\n"), NumProcessors(), ifs.m_nSeed, CWordHash::NODES_PER_CLUMP );
_tprintf(_TEXT("InsertIfNotFound = %d, FindKeyCopy = %d, ") _TEXT("MultiKeys=%d, UseLocks=%d\n"), ifs.m_nInsertIfNotFound, ifs.m_nFindKeyCopy, ifs.m_fMultiKeys, ifs.m_fUseLocks); _tprintf(_TEXT("NonPagedAllocs=%d, RefTrace=%d, ") _TEXT("DebugSpew=%d, Allocator=%s.\n"), ifs.m_fNonPagedAllocs, ifs.m_fRefTrace, ifs.m_fDebugSpew, CLKRhashAllocator::ClassName());
#ifndef LKRHASH_KERNEL_MODE
time_t tmNow; time(&tmNow);
_tprintf(_TEXT("\nRun: %s\n\n"), _tctime(&tmNow)); #endif // !LKRHASH_KERNEL_MODE
if (ifs.m_fTestIterators) { test_iterators(ifs.m_nHighLoad, ifs.m_nInitSize, ifs.m_nSubTables, ifs.m_nInsertIfNotFound); #ifdef LKR_STL_ITERATORS
test_stl_iterators(ifs.m_nHighLoad, ifs.m_nInitSize, ifs.m_nSubTables); #endif // LKR_STL_ITERATORS
}
#ifndef LKRHASH_KERNEL_MODE
# ifdef _INC_MMSYSTEM
// set multimedia timer's period to be 1 millisecond (or the closest
// approximation that the hardware can manage). This is usually more
// accurate than GetTickCount. I have had very dubious results from
// QueryPerformanceCounter on multiprocessor machines, including
// negative(!) durations (timer skew between processors?)
timeBeginPeriod(1); # endif // _INC_MMSYSTEM
#endif // !LKRHASH_KERNEL_MODE
_tprintf(_TEXT("Starting threads...\n\n"));
int nTotalOps = 0; int step = (ifs.m_nMinThreads <= ifs.m_nMaxThreads) ? +1 : -1;
dwRunTime = GetTickCount() - dwRunTime;
for (num_threads = ifs.m_nMinThreads; num_threads != ifs.m_nMaxThreads + step; num_threads += step ) { IRTLTRACE1("\nStarting %8d\n", num_threads);
pTbl = new CWordHash(ifs.m_nHighLoad, ifs.m_nInitSize, ifs.m_nSubTables) ; pTbl->SetTableLockSpinCount(ifs.m_wTableSpin); pTbl->SetBucketLockSpinCount(ifs.m_wBucketSpin);
keys_per_thread = g_nokeys/num_threads ; for (i = 0; i < num_threads; i++) { de_area[i].ptbl = pTbl ; de_area[i].threadno = i+1 ; de_area[i].first_key = i*keys_per_thread ; de_area[i].last_key = ((i == num_threads - 1) ? g_nokeys : (i+1)*keys_per_thread) ; de_area[i].rounds = ifs.m_nRounds ; de_area[i].highload = ifs.m_nHighLoad ; de_area[i].lookup_freq = ifs.m_nLookupFreq ; de_area[i].m_nInsertIfNotFound = ifs.m_nInsertIfNotFound; de_area[i].m_nFindKeyCopy = ifs.m_nFindKeyCopy; de_area[i].m_nSeed = ifs.m_nSeed; de_area[i].hevFinished = HashTestCreateEvent(); IRTLASSERT(de_area[i].hevFinished != NULL); ahEvents[i] = de_area[i].hevFinished;
de_area[i].hThread = HashTestCreateThread(exercise_table, &de_area[i], true); }
#ifndef LKRHASH_KERNEL_MODE
# ifdef _INC_MMSYSTEM
DWORD dwMMT1 = timeGetTime(); # endif // _INC_MMSYSTEM
#endif // !LKRHASH_KERNEL_MODE
for (i = 0; i < num_threads; i++) { HashTestResumeThread(de_area[i].hThread); CloseHandle(de_area[i].hThread); }
DWORD dw = HashTestWaitForMultipleObjects(num_threads, ahEvents); UNREFERENCED_PARAMETER(dw);
#ifndef LKRHASH_KERNEL_MODE
# ifdef _INC_MMSYSTEM
DWORD dwMMT2 = timeGetTime(); # endif // _INC_MMSYSTEM
#endif // !LKRHASH_KERNEL_MODE
for (i = 0; i < num_threads; i++) CloseHandle(ahEvents[i]);
#ifndef LKRHASH_KERNEL_MODE
# ifdef _INC_MMSYSTEM
double duration3 = double(dwMMT2 - dwMMT1) / 1000.0; dblSumDuration3 += duration3;
dwRunTime += dwMMT2 - dwMMT1; # else
dblSumDuration3 = 1.0; # endif // _INC_MMSYSTEM
#endif // !LKRHASH_KERNEL_MODE
sum_ins = sum_dels = sum_lookups = 0 ;
for (i = 0; i < num_threads; i++) { sum_ins += de_area[i].cinserts ; sum_dels += de_area[i].cdeletes ; sum_lookups += de_area[i].clookups ; failures += de_area[i].cfailures ; } int nOps = sum_ins + sum_dels + sum_lookups;
total_failures += failures; nTotalOps += nOps; // TODO: weight?
#ifdef LKRHASH_KERNEL_MODE
#else // !LKRHASH_KERNEL_MODE
# ifdef _INC_MMSYSTEM
int nOpsRate3 = (int)(nOps / duration3);
if (num_threads == ifs.m_nMinThreads) nBaseOps = nOpsRate3;
TCHAR tszSumIns[16], tszSumDels[16], tszSumLookups[16]; TCHAR tszNOps3[16]; # else
UNREFERENCED_PARAMETER(nBaseOps); # endif // _INC_MMSYSTEM
#ifndef LOCK_INSTRUMENTATION
if (num_threads == ifs.m_nMinThreads) #endif // LOCK_INSTRUMENTATION
{ _tprintf(_TEXT("%5s %10s %9s %6s") _TEXT("%8s %8s %8s\n"), _TEXT("Thrds"), _TEXT("Ops/sec"), _TEXT("Duration"), _TEXT("Ratio"), _TEXT("Inserts"), _TEXT("Deletes"), _TEXT("Lookups")); }
# ifdef _INC_MMSYSTEM
TCHAR tszSummary[200];
_stprintf(tszSummary, _TEXT("%5d %10s %9.3f %6.3f") _TEXT("%7sK %7sK %7sK\n"), num_threads, CommaNumber(nOpsRate3, tszNOps3), duration3, double(nOpsRate3) / double(nBaseOps), CommaNumber((sum_ins + 500) / 1000, tszSumIns), CommaNumber((sum_dels + 500) / 1000, tszSumDels), CommaNumber((sum_lookups + 500) / 1000, tszSumLookups) ); _tprintf("%s", tszSummary); IRTLTRACE1("%s", tszSummary); # endif // _INC_MMSYSTEM
if (failures != 0) _tprintf(_TEXT("%d failed operations!\n"), failures); #endif // !LKRHASH_KERNEL_MODE
#ifdef LOCK_INSTRUMENTATION
print_lock_statistics(pTbl->GetStatistics()); #ifdef LKRHASH_GLOBAL_LOCK
CWordHash::GlobalLock::ResetGlobalStatistics(); #endif
CWordHash::BucketLock::ResetGlobalStatistics(); CWordHash::TableLock::ResetGlobalStatistics(); _tprintf(_TEXT("\n")); #endif
pTbl->Destroy(); }
TCHAR tszNTotalOps3[16]; _tprintf(_TEXT("\nAverage Ops = %s. RunTime = %d:%02d.%03d.\n"), CommaNumber(int(nTotalOps / dblSumDuration3), tszNTotalOps3), dwRunTime / 60000, (dwRunTime / 1000) % 60, dwRunTime % 1000);
if (total_failures != 0) _tprintf(_TEXT("%d total failed operations!\n"), total_failures);
#ifndef LKRHASH_KERNEL_MODE
# ifdef _INC_MMSYSTEM
timeEndPeriod(1); # endif // _INC_MMSYSTEM
#endif // !LKRHASH_KERNEL_MODE
return 0; } // LKR_TestHashTable
void test_iterators( unsigned highload, int initsize, int nsubtbls, int nInsertIfNotFound) { _tprintf(_TEXT("Testing iterators...\n"));
int i; CWordHash *pTbl = new CWordHash(highload, initsize, nsubtbls) ; LK_RETCODE lkrc;
IRTLASSERT(0 == pTbl->Size()); IRTLASSERT(pTbl->CheckTable() == 0);
IRTLTRACE0("Table is empty. Building...\n");
int cInsertIfNotFounds = 0; for (i = 0 ; i < g_nokeys ; i++ ) { lkrc = pTbl->InsertRecord(&g_wordtable[i], false); if (lkrc != LK_SUCCESS) IRTLTRACE3("i = %d, word = `%hs', lkrc = %d\n", i, g_wordtable[i].m_str.m_psz, lkrc); IRTLASSERT(lkrc == LK_SUCCESS);
#ifdef LKR_EXPOSED_TABLE_LOCK
if (nInsertIfNotFound > 0 && rand() % nInsertIfNotFound == 0) { pTbl->WriteLock();
int x = rand() % g_nokeys; CStr* pstrKey1 = &g_wordtable[x].m_str; CWord* pRec1 = NULL;
lkrc = pTbl->FindKey(pstrKey1, &pRec1);
if (pRec1 != NULL) { IRTLASSERT(lkrc == LK_SUCCESS); IRTLASSERT(pRec1 == &g_wordtable[x]); IRTLASSERT(x <= i); --g_wordtable[x].m_cRefs; } else { ++cInsertIfNotFounds; IRTLASSERT(x > i); IRTLASSERT(lkrc == LK_NO_SUCH_KEY);
lkrc = pTbl->InsertRecord(&g_wordtable[x], false); IRTLASSERT(lkrc == LK_SUCCESS); InterlockedIncrement(&g_wordtable[x].m_cInsertIfNotFounds);
lkrc = pTbl->DeleteKey(&g_wordtable[x].m_str); IRTLASSERT(lkrc == LK_SUCCESS); } pTbl->WriteUnlock(); } #endif // LKR_EXPOSED_TABLE_LOCK
}
IRTLTRACE1("cInsertIfNotFounds = %d\n", cInsertIfNotFounds); #ifdef LKR_EXPOSED_TABLE_LOCK
pTbl->ReadLock();
IRTLTRACE2("Checking that table has %d records (size = %d)\n", g_nokeys, pTbl->Size()); IRTLASSERT(g_nokeys == (int) pTbl->Size()); IRTLASSERT(pTbl->CheckTable() == 0);
pTbl->ReadUnlock(); #endif // LKR_EXPOSED_TABLE_LOCK
IRTLTRACE0("Clearing the table\n"); pTbl->Clear(); IRTLASSERT(0 == pTbl->Size()); IRTLASSERT(pTbl->CheckTable() == 0);
IRTLTRACE0("Seeing what crud is left in the table\n"); size_t cRec = 0;
for (i = 0 ; i < g_nokeys ; i++ ) { CStr* pstrKey = &g_wordtable[i].m_str; CWord* pRec = NULL;
lkrc = pTbl->FindKey(pstrKey, &pRec);
if (pRec != NULL) { IRTLASSERT(pRec == &g_wordtable[i]); --pRec->m_cRefs; IRTLTRACE1("%hs\n", g_wordtable[i].m_str.m_psz); ++cRec; } } IRTLTRACE1("Found %d records that shouldn't have been there\n", cRec);
pTbl->Clear(); pTbl->Destroy();
pTbl = new CWordHash(highload, initsize, nsubtbls) ;
IRTLTRACE0("Rebuilding the table\n"); for (i = 0 ; i < g_nokeys ; i++ ) IRTLVERIFY(pTbl->InsertRecord(&g_wordtable[i]) == LK_SUCCESS);
IRTLASSERT(g_nokeys == (int) pTbl->Size()); IRTLASSERT(pTbl->CheckTable() == 0);
#ifdef LKR_DEPRECATED_ITERATORS
IRTLTRACE0("Checking iterators\n"); cRec = 0; CWordHash::CIterator iter(LKL_READLOCK); for (lkrc = pTbl->InitializeIterator(&iter); lkrc == LK_SUCCESS; lkrc = pTbl->IncrementIterator(&iter)) { ++cRec; const CStr* pstrKey = iter.Key(); CWord* pRec = iter.Record(); IRTLASSERT(&g_wordtable[0] <= pRec && pRec < &g_wordtable[g_nokeys]); IRTLASSERT(!pRec->m_fIterated); pRec->m_fIterated = true;
if (CWordHash::TableLock::Recursion() != LOCK_NON_RECURSIVE && CWordHash::BucketLock::Recursion() != LOCK_NON_RECURSIVE) { // Check that the lock can be safely acquired recursively
// (the table is already locked by the iterator).
int x = rand() % g_nokeys; CStr* pstrKey2 = &g_wordtable[x].m_str; CWord* pRec2 = NULL; LK_RETCODE lkrc2= pTbl->FindKey(pstrKey2, &pRec2); IRTLASSERT(lkrc2 == LK_SUCCESS && pRec2 == &g_wordtable[x]); if (pRec2 != NULL) --pRec2->m_cRefs; } } IRTLASSERT(lkrc == LK_NO_MORE_ELEMENTS); IRTLASSERT((int) cRec == g_nokeys);
lkrc = pTbl->CloseIterator(&iter); IRTLASSERT(lkrc == LK_SUCCESS);
for (i = 0 ; i < g_nokeys ; i++ ) { IRTLASSERT(g_wordtable[i].m_fIterated); g_wordtable[i].m_fIterated = false; }
do { cRec = rand() % (g_nokeys - 1); } while (cRec == 0); IRTLTRACE1("Checking abandoning of const iterators after %d iterations\n", cRec);
const CWordHash *pTblConst = pTbl; CWordHash::CConstIterator iterConst;
for (lkrc = pTblConst->InitializeIterator(&iterConst); lkrc == LK_SUCCESS; lkrc = pTblConst->IncrementIterator(&iterConst)) { if (--cRec == 0) break; const CStr* pszKey = iterConst.Key(); const CWord* pRec = iterConst.Record(); IRTLASSERT(&g_wordtable[0] <= pRec && pRec < &g_wordtable[g_nokeys]); } IRTLASSERT(lkrc != LK_NO_MORE_ELEMENTS);
lkrc = pTblConst->CloseIterator(&iterConst); IRTLASSERT(lkrc == LK_SUCCESS); #endif // LKR_DEPRECATED_ITERATORS
#ifndef LKRHASH_KERNEL_MODE
IRTLTRACE0("Gathering statistics\n"); CLKRHashTableStats stats = pTbl->GetStatistics(); print_table_statistics(stats); #endif // !LKRHASH_KERNEL_MODE
#ifdef LOCK_INSTRUMENTATION
print_lock_statistics(stats); CWordHash::BucketLock::ResetGlobalStatistics(); CWordHash::TableLock::ResetGlobalStatistics(); #endif
_tprintf(_TEXT("\n"));
IRTLTRACE0("Cleaning up by hand\n"); for (i = 0 ; i < g_nokeys ; i++ ) { IRTLVERIFY(pTbl->DeleteKey(&g_wordtable[i].m_str) == LK_SUCCESS); } IRTLASSERT(0 == pTbl->Size());
pTbl->Destroy(); }
#ifdef LKR_STL_ITERATORS
void test_stl_iterators2( CWordHash *pTbl);
void test_stl_iterators( unsigned highload, int initsize, int nsubtbls) { _tprintf(_TEXT("\nTesting STL iterators...\n"));
_tprintf(_TEXT("subtable iter = %d, iter = %d\n"), sizeof(CLKRLinearHashTable::Iterator), sizeof(CLKRHashTable::Iterator));
int i; bool f; CWordHash *pTbl; CWordHash::iterator iter; const int iFirst = 5; // g_nokeys / 5;
const int iLast = 10; // 4 * g_nokeys / 5;
// pTbl = new CWordHash(highload, initsize, nsubtbls) ;
IRTLTRACE1("\n\nAbout to create table with %d records\n\n", iLast - iFirst); pTbl = new CWordHash(&g_wordtable[iFirst], &g_wordtable[iLast], highload, initsize, nsubtbls) ;
for (iter = pTbl->begin(); iter != pTbl->end(); ++iter) { const CStr* pstrKey = iter.Key(); CWord* pRec = iter.Record(); CWord& rRec = *iter; bool fIterated = rRec.m_fIterated; LONG cRefs = iter->m_cRefs;
UNREFERENCED_PARAMETER(pstrKey); UNREFERENCED_PARAMETER(pRec); UNREFERENCED_PARAMETER(fIterated); UNREFERENCED_PARAMETER(cRefs);
IRTLASSERT(&g_wordtable[iFirst] <= pRec && pRec < &g_wordtable[iLast]); IRTLASSERT(pRec - g_wordtable == pRec->m_iIndex); IRTLASSERT(rRec.m_iIndex == pRec->m_iIndex); IRTLTRACE3("\nRecord: %p, %d, %hs\n", pRec, rRec.m_iIndex, pstrKey->m_psz); }
IRTLTRACE1("\n\nAbout to search %d records\n\n", pTbl->Size()); for (i = iFirst; i != iLast; ++i) { f = pTbl->Find(&g_wordtable[i].m_str, iter); IRTLASSERT(f && iter.Record() == &g_wordtable[i]); IRTLTRACE2("\n\tFound: %d, %hs\n", i, iter.Key()->m_psz); } f = pTbl->Find(&g_wordtable[iLast].m_str, iter); IRTLASSERT(!f); IRTLASSERT(iter == pTbl->end());
i = pTbl->Size(); IRTLTRACE1("\n\nAbout to erase %d records\n\n", i);
for (iter = pTbl->begin(); iter != pTbl->end(); --i) { IRTLTRACE1("\n\terase %d\n", i); IRTLVERIFY(pTbl->Erase(iter)); }
IRTLASSERT(i == 0); IRTLASSERT(pTbl->Size() == 0); CheckRefCounts(0);
IRTLTRACE1("\n\nAbout to insert %d records\n\n", iLast - iFirst); for (i = iFirst; i != iLast; ++i) { f = pTbl->Insert(&g_wordtable[i], iter); IRTLASSERT(f && iter.Record() == &g_wordtable[i]); IRTLTRACE2("\n\tInserted: %d, %hs\n", i, iter.Key()->m_psz); }
// Reset iter so that it isn't pointing to anything, raising its refcount
iter = pTbl->end(); CheckRefCounts(1, iFirst, iLast);
IRTLTRACE1("\n\nAbout to Erase2 %d records\n\n", iLast - iFirst); CWordHash::iterator iterBegin = pTbl->begin(), iterEnd = pTbl->end(); f = pTbl->Erase(iterBegin, iterEnd); IRTLASSERT(f && pTbl->Size() == 0);
CheckRefCounts(0);
IRTLTRACE1("\n\nAbout to insert %d records, again\n\n", iLast - iFirst); for (i = iFirst; i != iLast; ++i) { f = pTbl->Insert(&g_wordtable[i], iter); IRTLASSERT(f && iter.Record() == &g_wordtable[i]); IRTLTRACE2("\n\tInserted: %d, %hs\n", i, iter.Key()->m_psz); }
// Reset iter so that it isn't pointing to anything, raising its refcount
iter = pTbl->end(); CheckRefCounts(1, iFirst, iLast);
IRTLTRACE1("\nAbout to equalrange and erase2 %d records, backwards\n\n", iLast - iFirst); for (i = iLast; --i >= iFirst; ) { CWordHash::iterator iterLast;
f = pTbl->EqualRange(&g_wordtable[i].m_str, iter, iterLast); IRTLASSERT(f && iter.Record() == &g_wordtable[i]); IRTLTRACE3("\n\tEqualRange: %d, \"%hs\", %d\n", i, iter.Key()->m_psz, iter.Record()->m_cRefs);
f = pTbl->Erase(iter, iterLast); IRTLASSERT(f); IRTLTRACE1("\n\tErase2d: %d\n", i); }
IRTLASSERT(pTbl->Size() == 0); CheckRefCounts(0);
pTbl->Destroy();
#if 1
pTbl = new CWordHash(highload, initsize, nsubtbls) ; #else
pTbl = new CWordHash(1, // LK_DFLT_MAXLOAD * 6,
100000, // LK_SMALL_TABLESIZE,
17); // # subtables
#endif
CheckRefCounts(0); IRTLTRACE0("Building the table\n"); for (i = 0 ; i < g_nokeys ; i++ ) { g_wordtable[i].m_fIterated = false; IRTLVERIFY(pTbl->InsertRecord(&g_wordtable[i]) == LK_SUCCESS); }
IRTLASSERT(g_nokeys == (int) pTbl->Size()); IRTLASSERT(pTbl->CheckTable() == 0);
test_stl_iterators2(pTbl);
IRTLTRACE0("Cleaning up by hand\n"); for (i = 0 ; i < g_nokeys ; i++ ) { IRTLVERIFY(pTbl->DeleteKey(&g_wordtable[i].m_str) == LK_SUCCESS); } IRTLASSERT(0 == pTbl->Size());
pTbl->Destroy(); }
void test_stl_iterators2( CWordHash *pTbl) { IRTLTRACE0("Checking STL iterators\n"); size_t cRec = 0; int i; for (CWordHash::iterator iter = pTbl->begin(); iter != pTbl->end(); ++iter) { ++cRec; const CStr* pstrKey = iter.Key(); CWord* pRec = iter.Record();
UNREFERENCED_PARAMETER(pstrKey); IRTLASSERT(&g_wordtable[0] <= pRec && pRec < &g_wordtable[g_nokeys]); IRTLASSERT(!pRec->m_fIterated); pRec->m_fIterated = true; // IRTLTRACE3("%d: %p, %hs\n", cRec, pRec, pstrKey->m_psz);
} IRTLASSERT((int) cRec == g_nokeys);
IRTLTRACE1("Checking that all %d records were touched\n", g_nokeys); CheckRefCounts(1);
for (i = 0 ; i < g_nokeys ; i++ ) { IRTLASSERT(g_wordtable[i].m_fIterated); g_wordtable[i].m_fIterated = false; } }
#endif // LKR_STL_ITERATORS
#ifndef LKRHASH_KERNEL_MODE
void print_table_statistics(const CLKRHashTableStats& stats) { _tprintf(_TEXT("#Records=%d, #BucketChains=%d, ") _TEXT("DirSize=%d, LongestChain=%3d,\n"), stats.RecordCount, stats.TableSize, stats.DirectorySize, stats.LongestChain); _tprintf(_TEXT("#Empty Buckets=%d, Split Factor=%.2f, ") _TEXT("AvgSrchLen=%.2f, Expected SL=%.2f,\n"), stats.EmptySlots, stats.SplitFactor, stats.AvgSearchLength, stats.ExpSearchLength);
_tprintf(_TEXT("Avg Unsuccessful SrchLen=%.2f, ExpUSL=%.2f.\n"), stats.AvgUSearchLength, stats.ExpUSearchLength);
_tprintf(_TEXT("\nBucket Chain Lengths ") _TEXT("(node clump size = %d, bucket size = %d bytes):\n"), stats.NodeClumpSize, stats.CBucketSize); for (int j = 0; j < CLKRHashTableStats::MAX_BUCKETS; ++j) { if (stats.m_aBucketLenHistogram[j] == 0) { _tprintf(_TEXT("\n")); break; } _tprintf(_TEXT(" %10d: %6d"), stats.BucketSize(j), stats.m_aBucketLenHistogram[j]); if (j % 4 == 3) _tprintf(_TEXT("\n")); }
_tprintf(_TEXT("\n")); }
#ifdef LOCK_INSTRUMENTATION
void print_lock_statistics(const CLKRHashTableStats& stats) { _tprintf(_TEXT("Global Locks Statistics:") _TEXT("\n total locks created = %ld, ") _TEXT("total contentions = %ld, ") _TEXT("#sleeps = %ld,") _TEXT("\n total spins = %I64d, ") _TEXT("av spins/contention = %.1f, ") _TEXT("\n #readlocks = %d, ") _TEXT("#writelocks=%d\n"), stats.m_gls.m_cTotalLocks, stats.m_gls.m_cContendedLocks, stats.m_gls.m_nSleeps, stats.m_gls.m_cTotalSpins, stats.m_gls.m_nAverageSpins, stats.m_gls.m_nReadLocks, stats.m_gls.m_nWriteLocks );
_tprintf(_TEXT("Averaged SubTable Locks Statistics:") _TEXT("\n Total locks = %d, ") _TEXT("#contentions = %.1f, ") _TEXT("sleeps = %.1f; ") _TEXT("\n total spins = %.1f, ") _TEXT("avg spins = %.1f, ") _TEXT("\n #readlocks = %.1f, ") _TEXT("#writelocks=%.1f\n"), stats.m_alsTable.m_nItems, stats.m_alsTable.m_nContentions, stats.m_alsTable.m_nSleeps, stats.m_alsTable.m_nContentionSpins, stats.m_alsTable.m_nAverageSpins, stats.m_alsTable.m_nReadLocks, stats.m_alsTable.m_nWriteLocks);
_tprintf(_TEXT("Averaged Bucket Locks Statistics:") _TEXT("\n Total locks = %d, ") _TEXT("#contentions = %.1f, ") _TEXT("sleeps = %.1f; ") _TEXT("\n total spins = %.1f, ") _TEXT("avg spins = %.1f, ") _TEXT("\n #readlocks = %.1f, ") _TEXT("#writelocks=%.1f\n"), stats.m_alsBucketsAvg.m_nItems, stats.m_alsBucketsAvg.m_nContentions, stats.m_alsBucketsAvg.m_nSleeps, stats.m_alsBucketsAvg.m_nContentionSpins, stats.m_alsBucketsAvg.m_nAverageSpins, stats.m_alsBucketsAvg.m_nReadLocks, stats.m_alsBucketsAvg.m_nWriteLocks);
_tprintf(_TEXT("\n")); }
#endif // LOCK_INSTRUMENTATION
#endif // !LKRHASH_KERNEL_MODE
int expand_key_set(int maxkeys, int numkeys, bool fVerbose) { int totkeys = numkeys ; if (totkeys > maxkeys) return maxkeys;
char* pszTemp = new char [20 + CStr::sm_cchMax];
for (int k = 0; ; k++) { for(int i = 0; i < numkeys; i++) { if (totkeys == maxkeys) { delete [] pszTemp; return(totkeys) ; }
sprintf(pszTemp, "%d%hs", k, g_wordtable[i].m_str.m_psz); g_wordtable[totkeys++].m_str.Set(pszTemp, strlen(pszTemp)); }
if (fVerbose) putchar('.'); } // notreached
}
#ifdef LKRHASH_KERNEL_MODE
void #else
unsigned __stdcall #endif
exercise_table( void* pinput) { CWordHash* pTbl; thread_data* pdea = (thread_data*) pinput ; int cfailed_ins=0 ; int cfailed_dels=0 ; int cFoundSuccesses=0, cFoundFails=0 ; int x, i ; LK_RETCODE lkrc;
SetThreadIdealProcessor(GetCurrentThread(), pdea->threadno % NumProcessors());
#ifndef LKRHASH_KERNEL_MODE
LARGE_INTEGER liFreq = {0,0}, liT1 = {0,0}, liT2 = {0,0}; IRTLVERIFY(QueryPerformanceFrequency(&liFreq)); IRTLVERIFY(QueryPerformanceCounter(&liT1)); #endif // !LKRHASH_KERNEL_MODE
pdea->cinserts = 0 ; pdea->cdeletes = 0 ; pdea->clookups = 0 ; pTbl = pdea->ptbl ; srand(pdea->m_nSeed);
for (int rnd = 0; rnd < pdea->rounds; rnd++) { IRTLASSERT(pTbl->CheckTable() == 0);
// Insert all the keys, randomly searching after each insertion
for (i = pdea->first_key ; i < pdea->last_key ; i++ ) { #ifdef IRTLDEBUG
CStr* pstrKey1 = &g_wordtable[i].m_str; CWord* pRec1 = NULL; lkrc = pTbl->FindKey(pstrKey1, &pRec1); IRTLASSERT(lkrc == LK_NO_SUCH_KEY && pRec1 == NULL); #endif // IRTLDEBUG
if (pTbl->InsertRecord(&g_wordtable[i] ) != LK_SUCCESS ) { cfailed_ins++ ; } else { #ifdef IRTLDEBUG
pstrKey1 = &g_wordtable[i].m_str; lkrc = pTbl->FindKey(pstrKey1, &pRec1); IRTLASSERT(lkrc == LK_SUCCESS && pRec1 == &g_wordtable[i]); pTbl->AddRefRecord(pRec1, LKAR_EXPLICIT_RELEASE); #endif // IRTLDEBUG
g_wordtable[i].m_fInserted = true; }
pdea->cinserts++ ;
for (int lu = 0; lu < pdea->lookup_freq; lu++) { x = rand() % (pdea->last_key - pdea->first_key) + pdea->first_key; bool fPresent = (x <= i); // should it be found?
CWord* pRec = NULL;
if (pdea->m_nFindKeyCopy > 0 && rand() % pdea->m_nFindKeyCopy == 0) { char szTemp[MAX_STRSIZE]; strcpy(szTemp, g_wordtable[x].m_str.m_psz); CStr strTemp(szTemp, g_wordtable[x].m_str.m_cch, false); lkrc = pTbl->FindKey(&strTemp, &pRec); } else lkrc = pTbl->FindKey(&g_wordtable[x].m_str, &pRec);
if (fPresent) { if (lkrc != LK_SUCCESS || pRec != &g_wordtable[x] ) { ++g_wordtable[x].m_cNotFound; IRTLTRACE(_TEXT("%d: Not found (%hs): x = %d, i = %d, ") _TEXT("cnf = %d, rnd = %d, lkrc = %d, ") _TEXT("pRec(%hs), %d\n"), pdea->threadno, g_wordtable[x].m_str.m_psz, x, i, g_wordtable[x].m_cNotFound, rnd, lkrc, pRec != NULL ? pRec->m_str.m_psz : "<null>", pRec != NULL ? (pRec - g_wordtable) / sizeof(CWord) : -1); cFoundFails++ ; } else { #ifdef IRTLDEBUG
pTbl->AddRefRecord(pRec, LKAR_EXPLICIT_RELEASE); #else
--g_wordtable[x].m_cRefs; #endif
cFoundSuccesses++ ; } } else // not fPresent
{ IRTLASSERT(lkrc != LK_SUCCESS && pRec == NULL); if (lkrc == LK_SUCCESS || pRec != NULL) { IRTLTRACE(_TEXT("%d: found when not present (%hs): ") _TEXT("x = %d, i = %d, ") _TEXT("cnf = %d, rnd = %d, lkrc = %d, ") _TEXT("pRec(%hs), %d\n"), pdea->threadno, g_wordtable[x].m_str.m_psz, x, i, g_wordtable[x].m_cNotFound, rnd, lkrc, pRec != NULL ? pRec->m_str.m_psz : "<null>", pRec != NULL ? (pRec - g_wordtable) / sizeof(CWord) : -1); cFoundFails++ ; } else { // wasn't found, but it wasn't present, so this is good
cFoundSuccesses++ ; } } }
pdea->clookups += pdea->lookup_freq ; #ifdef LKR_EXPOSED_TABLE_LOCK
if (pdea->m_nInsertIfNotFound > 0 && rand() % pdea->m_nInsertIfNotFound == 0) { bool fWrite = (rand() & 1) != 0;
if (fWrite) pTbl->WriteLock(); else pTbl->ReadLock(); x = rand() % (pdea->last_key - pdea->first_key) + pdea->first_key; CStr* pstrKey2 = &g_wordtable[x].m_str; CWord* pRec2 = NULL; lkrc = pTbl->FindKey(pstrKey2, &pRec2); if (pRec2 != NULL) { IRTLASSERT(lkrc == LK_SUCCESS); IRTLASSERT(pRec2 == &g_wordtable[x]); IRTLASSERT(x <= i); #ifdef IRTLDEBUG
pTbl->AddRefRecord(pRec2, LKAR_EXPLICIT_RELEASE); #else
--g_wordtable[x].m_cRefs; #endif
} else if (fWrite) { IRTLASSERT(x > i); IRTLASSERT(lkrc == LK_NO_SUCH_KEY);
lkrc = pTbl->InsertRecord(&g_wordtable[x], false); IRTLASSERT(lkrc == LK_SUCCESS); InterlockedIncrement(&g_wordtable[x].m_cInsertIfNotFounds); lkrc = pTbl->DeleteKey(&g_wordtable[x].m_str); IRTLASSERT(lkrc == LK_SUCCESS); } if (fWrite) pTbl->WriteUnlock(); else pTbl->ReadUnlock(); } #endif // LKR_EXPOSED_TABLE_LOCK
}
IRTLASSERT(cfailed_ins == 0) ; IRTLASSERT(cFoundFails == 0) ; IRTLASSERT(cFoundSuccesses == ((2 * rnd + 1) * pdea->lookup_freq * (pdea->last_key - pdea->first_key)));
IRTLTRACE(_TEXT("Thrd %u, rnd %d: %d inserts done, not found %d, ") _TEXT("f=%d, l=%d\n"), pdea->threadno, rnd, pdea->cinserts, cFoundFails, pdea->first_key, pdea->last_key) ; IRTLASSERT(pTbl->CheckTable() == 0);
// Delete all the keys, randomly searching before each deletion
for (i = pdea->first_key ; i < pdea->last_key ; i++ ) { for (int lu = 0; lu < pdea->lookup_freq; lu++) { x = rand() % (pdea->last_key - pdea->first_key) + pdea->first_key; bool fPresent = (x >= i); // should it be found?
CWord* pRec3 = NULL;
if (pdea->m_nFindKeyCopy > 0 && rand() % pdea->m_nFindKeyCopy == 0) { char szTemp[MAX_STRSIZE]; strcpy(szTemp, g_wordtable[x].m_str.m_psz); CStr strTemp(szTemp, g_wordtable[x].m_str.m_cch, false); lkrc = pTbl->FindKey(&strTemp, &pRec3); } else lkrc = pTbl->FindKey(&g_wordtable[x].m_str, &pRec3);
if (fPresent) { if (lkrc != LK_SUCCESS || pRec3 != &g_wordtable[x] ) { ++g_wordtable[x].m_cNotFound; IRTLTRACE(_TEXT("%d: Not found (%hs): x = %d, i = %d, ") _TEXT("cnf = %d, rnd = %d, lkrc = %d, ") _TEXT("pRec(%hs), %d\n"), pdea->threadno, g_wordtable[x].m_str.m_psz, x, i, g_wordtable[x].m_cNotFound, rnd, lkrc, pRec3 != NULL ? pRec3->m_str.m_psz : "<null>", pRec3 != NULL ? (pRec3 - g_wordtable) / sizeof(CWord) : -1); cFoundFails++ ; } else { #ifdef IRTLDEBUG
pTbl->AddRefRecord(pRec3, LKAR_EXPLICIT_RELEASE); #else
--g_wordtable[x].m_cRefs; #endif
cFoundSuccesses++ ; } } else // !fPresent
{ IRTLASSERT(lkrc != LK_SUCCESS && pRec3 == NULL); if (lkrc == LK_SUCCESS || pRec3 != NULL) { IRTLTRACE(_TEXT("%d: found when not present (%hs): ") _TEXT("x = %d, i = %d, ") _TEXT("cnf = %d, rnd = %d, lkrc = %d, ") _TEXT("pRec(%hs), %d\n"), pdea->threadno, g_wordtable[x].m_str.m_psz, x, i, g_wordtable[x].m_cNotFound, rnd, lkrc, pRec3 != NULL ? pRec3->m_str.m_psz : "<null>", pRec3 != NULL ? (pRec3 - g_wordtable) / sizeof(CWord) : -1); cFoundFails++ ; } else { // wasn't found, but it wasn't present, so this is good
cFoundSuccesses++ ; } } } pdea->clookups += pdea->lookup_freq ;
#ifdef IRTLDEBUG
CStr* pstrKey4 = &g_wordtable[i].m_str; CWord* pRec4 = NULL; lkrc = pTbl->FindKey(pstrKey4, &pRec4); IRTLASSERT(lkrc == LK_SUCCESS && pRec4 == &g_wordtable[i]); pTbl->AddRefRecord(pRec4, LKAR_EXPLICIT_RELEASE); #endif // IRTLDEBUG
if (pTbl->DeleteKey(&g_wordtable[i].m_str) != LK_SUCCESS ) { cfailed_dels++ ; } else { #ifdef IRTLDEBUG
pstrKey4 = &g_wordtable[i].m_str; lkrc = pTbl->FindKey(pstrKey4, &pRec4); IRTLASSERT(lkrc == LK_NO_SUCH_KEY && pRec4 == NULL); #endif // IRTLDEBUG
g_wordtable[i].m_fInserted = false; } pdea->cdeletes++ ; }
#ifdef IRTLDEBUG
int cBadKeys = 0; for (i = pdea->first_key ; i < pdea->last_key ; i++ ) { if (g_wordtable[i].m_cNotFound > 0) { ++cBadKeys; IRTLTRACE(_TEXT("%-20hs: #not found = %d, hash = %d, %08x\n"), g_wordtable[i].m_str.m_psz, g_wordtable[i].m_cNotFound, CWordHash::CalcKeyHash(CWordHash::ExtractKey( &g_wordtable[i])), CWordHash::CalcKeyHash(CWordHash::ExtractKey( &g_wordtable[i]))); } } if (cBadKeys > 0) IRTLTRACE1("%d bad keys\n", cBadKeys); IRTLASSERT(cBadKeys == 0); #endif // IRTLDEBUG
IRTLASSERT(cfailed_dels == 0 ) ; IRTLASSERT(cFoundFails == 0 ) ; IRTLASSERT(cFoundSuccesses == ((2 * rnd + 2) * pdea->lookup_freq * (pdea->last_key - pdea->first_key))); IRTLTRACE(_TEXT("Thrd %u, rnd %d: %d deletes done, not found %d, ") _TEXT("f=%d, l=%d\n"), pdea->threadno, rnd, pdea->cdeletes, cFoundFails, pdea->first_key, pdea->last_key) ; } // (for rnd)
#ifndef LKRHASH_KERNEL_MODE
IRTLVERIFY(QueryPerformanceCounter(&liT2)); pdea->duration = (liT2.QuadPart-liT1.QuadPart) / (double) liFreq.QuadPart; #endif // !LKRHASH_KERNEL_MODE
IRTLASSERT(pTbl->CheckTable() == 0);
IRTLTRACE3("Thread %u terminating: %d found, %d not found\n", pdea->threadno, cFoundSuccesses, cFoundFails) ;
if (cFoundSuccesses != (2 * pdea->rounds * pdea->lookup_freq * (pdea->last_key - pdea->first_key)) || cFoundFails != 0 || cfailed_ins != 0 || cfailed_dels != 0) { _tprintf(_TEXT("Thread %u: found = %d, not found = %d, ") _TEXT("\nfailed inserts = %d, failed deletes = %d\n"), pdea->threadno, cFoundSuccesses, cFoundFails, cfailed_ins, cfailed_dels); }
pdea->cfailures = cfailed_ins + cfailed_dels + cFoundFails;
if (pdea->hevFinished != NULL) SetEvent(pdea->hevFinished);
#ifndef LKRHASH_KERNEL_MODE
return 0; #endif
}
|