|
|
//+-----------------------------------------------------------------------------
//
// File: lockperf.hxx
//
// Contents: class for lock monitoring for locks used by ole32.dll
//
// Classes: CLockPerfTracker
//
// History: 20-Dec-98 mprabhu Created
//
//------------------------------------------------------------------------------
#ifndef _LOCKPERF_HXX_
#define _LOCKPERF_HXX_
#if LOCK_PERF==1
// Max entries in the file-line table
#define MAX_LOCKPERF_FILEENTRY 512
// Max # of (different) locks tracked
#define MAX_LOCKS 64
//+-----------------------------------------------------------------------------
//
// Structure: CTlsLockPerf
//
// Synopsis: TlsEntry used when a lock is requested/held
//
//------------------------------------------------------------------------------
struct CTlsLockPerf { void *_lpLockPtr; DWORD _dwFlags; ULONG _loc; ULONG _idx; DWORD _dwRecursion; LARGE_INTEGER _liRequest; LARGE_INTEGER _liEntered; };
// Flags for TLS entries used when a lock is requested/held by a thread
#define TLS_LOCKPERF_INUSE 0x00000001
#define TLS_LOCKPERF_WAITING 0x00000010
#define TLS_LOCKPERF_ENTERED 0x00000020
// Max # of Tls Entries (== max # different locks a thread can hold at a time)
#define TLS_LOCKPERF_MAX 8
// LockPerf does not use OleTls, it allocates its own data during
// Thread_Attach and frees it during Thread_Detach.
// These two functions are used for the purpose.
HRESULT AllocLockPerfPvtTlsData(); void FreeLockPerfPvtTlsData();
// TlsIndex allocated during Process_Attach (DllMain)
extern DWORD gTlsLockPerfIndex;
//+-----------------------------------------------------------------------------
//
// Structure: CTlsLockPerf
//
// Synopsis: Represents a critical section guarded by a lock at a {file, line}
// in the code.
//
//------------------------------------------------------------------------------
class CFileLineEntry { public: DWORD dwNext; // wsed to chain data by LockName (i.e. by lpLockPtr).
BOOL bWriteCritSec; // are we writing to shared data at this location?
ULONG ulLockTableIdx; // index in the lock table for lpLockPtr
DWORD dwLine; // Line number, eg. 2345
const char *pszFile; // File name, eg. d:\nt\private\ole32\com\dcomrem\marshal.cxx
const char *pszLockName; // Name of the lock, eg. gComLock
void *lpLockPtr; // Critical section used by the lock.
DWORD dwNumEntrys; // Count of visits to this {file,line} by all threads.
DWORD dwWaitTime; // cumulative waiting time at this {file,line} entry point
DWORD dwLockedTime; // cumulative locked time.
DWORD dwContentionCount; // obtained from the lock.
DWORD dwAvgTime; // average time spent in this critical section.
};
//+-----------------------------------------------------------------------------
//
// Structure: CLockEntry
//
// Synopsis: Stores data for each individual lock object
//
//------------------------------------------------------------------------------
// This is used for cumulative data and for reader-writer locks when different
// reader threads could be at different locations in the code at a time.
// We keep track of the time when the first thread entered and the time the last
// thread left (possibly at different code locations) so as to calculate
// a shared lock time.
class CLockEntry { public: void *lpLockPtr; // the lock this entry represents
const char *pszLockName; // name of the lock
DWORD dwHead; // these two are used to chain the data by
DWORD dwTail; // LockName in the _LockPerfData array.
DWORD dwTotalWriteWaitTime; // total write wait time.
DWORD dwTotalWriteLockTime; // overall time spent holding this lock for Writes.
DWORD dwTotalWriteEntrys; // total write entry count for this lock.
DWORD dwTotalReadWaitTime; // total read wait time.
DWORD dwTotalReadLockTime; // overall time spent holding this lock for Reads.
DWORD dwTotalReadEntrys; // total read entry count for this lock.
DWORD dwWriterContentionCount; // overall write contention for this lock.
DWORD dwReaderContentionCount; // overall read contention for this lock.
DWORD dwSharedTime; // cumulative shared time
DWORD dwNumReaders; // count of simultaneous readers in the lock
LARGE_INTEGER liEntered; // time when the first reader entered this lock.
};
//+-----------------------------------------------------------------------------
//
// Class: CLockPerfTracker
//
// Synopsis: Exposes lock monitoring functionality.
//
//------------------------------------------------------------------------------
//
// This is the main lock tracking class. We just have one object called gLockTracker
// of this class. All locks interested in timing data must Register themselves before
// use and call appropriate methods eg. gLockTrack.ReaderWaiting ... etc.
// A lock is responsible for maintaining Contention counts (and optionally entry counts).
// These must be reported before the lock is destroyed.
//
class CLockPerfTracker { public: // called by the lock instance creation function.
void RegisterLock(void *lpLockPtr, BOOL bReadWrite);
// called by the lock code as its state changes depending upon the request
// bWriter argument of WriterWaiting and WriterEntered is only used internally.
void ReaderWaiting(const char*pszFile, DWORD dwLine, const char* pszLockName, void *lpLockPtr); void WriterWaiting(const char*pszFile, DWORD dwLine, const char* pszLockName, void *lpLockPtr, BOOL bWriter=TRUE); void ReaderEntered(const char*pszFile, DWORD dwLine, const char* pszLockName, void *lpLockPtr); void WriterEntered(const char*pszFile, DWORD dwLine, const char* pszLockName, void *lpLockPtr, BOOL bWriter=TRUE); void ReaderLeaving(void *lpLockPtr); void WriterLeaving(void *lpLockPtr);
// called by the lock instance prior to destruction/cleanup
void ReportContention(void *lpLockPtr, DWORD dwWriteEntrys, DWORD dwWriteContention, DWORD dwReadEntrys, DWORD dwReadContention); // called during Process_Attach to initialize statics
HRESULT Init(); // called during Process_Detach to report the timing information
void OutputPerfData(); private: // internal functions used by the tracker
ULONG FindOrCreateFileTableEntry(const char*pszFile, DWORD dwLine, const char* pszLockName, void *lpLockPtr, BOOL bWriter, ULONG *lpIdx); ULONG FindLockTableEntry(void *lpLockPtr);
void ProcessPerfData();
void UpdateFileTableEntry(CTlsLockPerf *pTlsEntry, LARGE_INTEGER *pLiUnlock); void OutputFileTableEntry(ULONG index, ULONG bByName, ULONG percent);
void UpdateHoggers(ULONG* hogList, ULONG index, ULONG listType); void OutputHoggers(ULONG *list);
// These are the tables that lock data is collected in.
// Each entry in _FileLineData corresponds to a code critical section.
// ({File, line} where the lock is entered).
static CFileLineEntry _FileLineData[MAX_LOCKPERF_FILEENTRY]; // Each entry in _LockData corresponds to a lock eg. gIPIDLock
static CLockEntry _LockData[MAX_LOCKS];
static LARGE_INTEGER _liFreq; // Performance Frequency on the system
static ULONG _numCritSecs; // count of {file,line} critical sections monitored
static ULONG _numLocks; // count of distinct locks being monitored
};
// single global object
extern CLockPerfTracker gLockTracker;
#endif //LOCK_PERF==1
#endif //_LOCKPERF_HXX_
|