Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1421 lines
32 KiB

/*++
Copyright (c) 1998-2001 Microsoft Corporation
Module Name:
counters.cxx
Abstract:
Contains the performance monitoring counter management code
Author:
Eric Stenson (ericsten) 25-Sep-2000
Revision History:
--*/
#include "precomp.h"
#include "countersp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, UlInitializeCounters )
#pragma alloc_text( PAGE, UlTerminateCounters )
#pragma alloc_text( PAGE, UlCreateSiteCounterEntry )
#if REFERENCE_DEBUG
#pragma alloc_text( PAGE, UlReferenceSiteCounterEntry )
#pragma alloc_text( PAGE, UlDereferenceSiteCounterEntry )
#endif
#pragma alloc_text( PAGE, UlGetGlobalCounters )
#pragma alloc_text( PAGE, UlGetSiteCounters )
#endif // ALLOC_PRAGMA
#if 0
NOT PAGEABLE -- UlIncCounter
NOT PAGEABLE -- UlDecCounter
NOT PAGEABLE -- UlAddCounter
NOT PAGEABLE -- UlResetCounter
NOT PAGEABLE -- UlIncSiteCounter
NOT PAGEABLE -- UlDecSiteCounter
NOT PAGEABLE -- UlAddSiteCounter
NOT PAGEABLE -- UlResetSiteCounter
NOT PAGEABLE -- UlMaxSiteCounter
NOT PAGEABLE -- UlMaxSiteCounter64
#endif
BOOLEAN g_InitCountersCalled = FALSE;
HTTP_GLOBAL_COUNTERS g_UlGlobalCounters;
FAST_MUTEX g_SiteCounterListMutex;
LIST_ENTRY g_SiteCounterListHead = {NULL,NULL};
LONG g_SiteCounterListCount = 0;
/***************************************************************************++
Routine Description:
Performs global initialization of the global (cache) and instance (per
site) counters.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlInitializeCounters(
VOID
)
{
NTSTATUS Status = STATUS_SUCCESS;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( !g_InitCountersCalled );
UlTrace(PERF_COUNTERS, ("http!UlInitializeCounters\n"));
if (!g_InitCountersCalled)
{
//
// zero out global counter block
//
RtlZeroMemory(&g_UlGlobalCounters, sizeof(HTTP_GLOBAL_COUNTERS));
//
// init Site Counter list
//
ExInitializeFastMutex(&g_SiteCounterListMutex);
InitializeListHead(&g_SiteCounterListHead);
g_SiteCounterListCount = 0;
// done!
g_InitCountersCalled = TRUE;
}
RETURN( Status );
} // UlInitializeCounters
/***************************************************************************++
Routine Description:
Performs global cleanup of the global (cache) and instance (per
site) counters.
--***************************************************************************/
VOID
UlTerminateCounters(
VOID
)
{
//
// [debug only] Walk list of counters and check the ref count for each counter block.
//
#if DBG
PLIST_ENTRY pEntry;
PUL_SITE_COUNTER_ENTRY pCounterEntry;
if (!g_InitCountersCalled)
{
goto End;
}
if (IsListEmpty(&g_SiteCounterListHead))
{
ASSERT(0 == g_SiteCounterListCount);
// Good! No counters left behind!
goto End;
}
//
// Walk list of Site Counter Entries
//
pEntry = g_SiteCounterListHead.Flink;
while (pEntry != &g_SiteCounterListHead)
{
pCounterEntry = CONTAINING_RECORD(
pEntry,
UL_SITE_COUNTER_ENTRY,
ListEntry
);
ASSERT(IS_VALID_SITE_COUNTER_ENTRY(pCounterEntry));
UlTrace(PERF_COUNTERS,
("http!UlTerminateCounters: Error: pCounterEntry %p SiteId %d RefCount %d\n",
pCounterEntry,
pCounterEntry->Counters.SiteId,
pCounterEntry->RefCount
));
pEntry = pEntry->Flink;
}
End:
return;
#endif // DBG
}
///////////////////////////////////////////////////////////////////////////////
// Site Counter Entry
//
/***************************************************************************++
Routine Description:
Creates a new site counter entry for the given SiteId.
Arguments:
SiteId - the site id for the site counters.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlCreateSiteCounterEntry(
IN OUT PUL_CONFIG_GROUP_OBJECT pConfigGroup,
ULONG SiteId
)
{
NTSTATUS Status;
PUL_SITE_COUNTER_ENTRY pNewEntry;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pConfigGroup != NULL );
//
// Setup locals so we know how to cleanup on exit.
//
Status = STATUS_SUCCESS;
//
// [debug only] Check to see if the SiteId is already
// in the list of existing Site Counter Entries.
//
ASSERT(!UlpIsInSiteCounterList(SiteId));
// Alloc new struct w/space from Non Paged Pool
pNewEntry = UL_ALLOCATE_STRUCT(
NonPagedPool,
UL_SITE_COUNTER_ENTRY,
UL_SITE_COUNTER_ENTRY_POOL_TAG);
if (pNewEntry)
{
UlTrace( PERF_COUNTERS,
("http!UlCreateSiteCounterEntry: pNewEntry %p, pConfigGroup %p, SiteId %d\n",
pNewEntry,
pConfigGroup,
SiteId )
);
pNewEntry->Signature = UL_SITE_COUNTER_ENTRY_POOL_TAG;
pNewEntry->RefCount = 1;
// Zero out counters
RtlZeroMemory(&(pNewEntry->Counters), sizeof(HTTP_SITE_COUNTERS));
// Set Site ID
pNewEntry->Counters.SiteId = SiteId;
// Init Counter Mutex
ExInitializeFastMutex(&(pNewEntry->EntryMutex));
// Add to Site Counter List
ExAcquireFastMutex(&g_SiteCounterListMutex);
InsertTailList(
&g_SiteCounterListHead,
&(pNewEntry->ListEntry)
);
g_SiteCounterListCount++;
ExReleaseFastMutex(&g_SiteCounterListMutex);
// Check for wrap-around of Site List count.
ASSERT( 0 != g_SiteCounterListCount );
}
else
{
UlTrace( PERF_COUNTERS,
("http!UlCreateSiteCounterEntry: Error: NO_MEMORY pConfigGroup %p, SiteId %d\n",
pNewEntry,
pConfigGroup,
SiteId )
);
Status = STATUS_NO_MEMORY;
}
pConfigGroup->pSiteCounters = pNewEntry;
RETURN( Status );
}
#if REFERENCE_DEBUG
/***************************************************************************++
Routine Description:
increments the refcount.
Arguments:
pEntry - the object to increment.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
VOID
UlReferenceSiteCounterEntry(
IN PUL_SITE_COUNTER_ENTRY pEntry
REFERENCE_DEBUG_FORMAL_PARAMS
)
{
LONG refCount;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
refCount = InterlockedIncrement( &pEntry->RefCount );
//
// Tracing.
//
WRITE_REF_TRACE_LOG(
g_pSiteCounterTraceLog,
REF_ACTION_REFERENCE_SITE_COUNTER_ENTRY,
refCount,
pEntry,
pFileName,
LineNumber
);
UlTrace(
REFCOUNT,
("http!UlReferenceSiteCounterEntry pEntry=%p refcount=%d SiteId=%d\n",
pEntry,
refCount,
pEntry->Counters.SiteId)
);
} // UlReferenceAppPool
/***************************************************************************++
Routine Description:
decrements the refcount. if it hits 0, destruct's the site counter entry
block.
Arguments:
pEntry - the object to decrement.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
VOID
UlDereferenceSiteCounterEntry(
IN PUL_SITE_COUNTER_ENTRY pEntry
REFERENCE_DEBUG_FORMAL_PARAMS
)
{
LONG refCount;
NTSTATUS Status;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
refCount = InterlockedDecrement( &pEntry->RefCount );
//
// Tracing.
//
WRITE_REF_TRACE_LOG(
g_pSiteCounterTraceLog,
REF_ACTION_DEREFERENCE_SITE_COUNTER_ENTRY,
refCount,
pEntry,
pFileName,
LineNumber
);
UlTrace(
REFCOUNT,
("http!UlDereferenceSiteCounter pEntry=%p refcount=%d SiteId=%d\n",
pEntry,
refCount,
pEntry->Counters.SiteId)
);
//
// Remove from the list if we hit zero
//
if (refCount == 0)
{
ASSERT( 0 != g_SiteCounterListCount );
UlTrace(
PERF_COUNTERS,
("http!UlDereferenceSiteCounter: Removing pEntry=%p SiteId=%d\n",
pEntry,
pEntry->Counters.SiteId)
);
// Remove from list
ExAcquireFastMutex(&g_SiteCounterListMutex);
RemoveEntryList(&pEntry->ListEntry);
pEntry->ListEntry.Flink = pEntry->ListEntry.Blink = NULL;
g_SiteCounterListCount--;
ExReleaseFastMutex(&g_SiteCounterListMutex);
// Release memory
UL_FREE_POOL_WITH_SIG(pEntry, UL_SITE_COUNTER_ENTRY_POOL_TAG);
}
}
#endif
///////////////////////////////////////////////////////////////////////////////
// Collection
//
/***************************************************************************++
Routine Description:
Gets the Global (cache) counters.
Arguments:
pCounter - pointer to block of memory where the counter data should be
written.
BlockSize - Maximum size available at pCounter.
pBytesWritten - On success, count of bytes written into the block of
memory at pCounter. On failure, the required count of bytes for the
memory at pCounter.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlGetGlobalCounters(
PVOID IN OUT pCounter,
ULONG IN BlockSize,
PULONG OUT pBytesWritten
)
{
ULONG i;
PAGED_CODE();
ASSERT( pBytesWritten );
UlTraceVerbose(PERF_COUNTERS,
("http!UlGetGlobalCounters\n"));
if (BlockSize < sizeof(HTTP_GLOBAL_COUNTERS))
{
//
// Tell the caller how many bytes are required.
//
*pBytesWritten = sizeof(HTTP_GLOBAL_COUNTERS);
RETURN( STATUS_BUFFER_TOO_SMALL );
}
RtlCopyMemory(
pCounter,
&g_UlGlobalCounters,
sizeof(g_UlGlobalCounters)
);
//
// Zero out any counters that must be zeroed.
//
for ( i = 0; i < HttpGlobalCounterMaximum; i++ )
{
if (TRUE == aIISULGlobalDescription[i].WPZeros)
{
// Zero it out
UlResetCounter((HTTP_GLOBAL_COUNTER_ID) i);
}
}
*pBytesWritten = sizeof(HTTP_GLOBAL_COUNTERS);
RETURN( STATUS_SUCCESS );
} // UlpGetGlobalCounters
/***************************************************************************++
Routine Description:
Gets the Site (instance) counters for all sites
Arguments:
pCounter - pointer to block of memory where the counter data should be
written.
BlockSize - Maximum size available at pCounter.
pBytesWritten - On success, count of bytes written into the block of
memory at pCounter. On failure, the required count of bytes for the
memory at pCounter.
pBlocksWritten - (optional) On success, count of site counter blocks
written to pCounter.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlGetSiteCounters(
PVOID IN OUT pCounter,
ULONG IN BlockSize,
PULONG OUT pBytesWritten,
PULONG OUT pBlocksWritten OPTIONAL
)
{
NTSTATUS Status;
ULONG i;
ULONG BytesNeeded;
ULONG BytesToGo;
ULONG BlocksSeen;
PUCHAR pBlock;
PLIST_ENTRY pEntry;
PUL_SITE_COUNTER_ENTRY pCounterEntry;
PAGED_CODE();
ASSERT( pBytesWritten );
UlTraceVerbose(PERF_COUNTERS,
("http!UlGetSiteCounters\n"));
//
// Setup locals so we know how to cleanup on exit.
//
Status = STATUS_SUCCESS;
BytesToGo = BlockSize;
BlocksSeen = 0;
pBlock = (PUCHAR) pCounter;
BytesNeeded = g_SiteCounterListCount * sizeof(HTTP_SITE_COUNTERS);
if (BytesNeeded > BlockSize)
{
// Need more space
*pBytesWritten = BytesNeeded;
Status = STATUS_BUFFER_TOO_SMALL;
goto End;
}
if (IsListEmpty(&g_SiteCounterListHead))
{
// No counters to return.
goto End;
}
//
// NOTE: g_SiteCounterListHead is the only member of
// the list which isn't contained within a UL_SITE_COUNTER_ENTRY.
//
pEntry = g_SiteCounterListHead.Flink;
//
// Walk list of Site Counter Entries
//
while (pEntry != &g_SiteCounterListHead)
{
pCounterEntry = CONTAINING_RECORD(
pEntry,
UL_SITE_COUNTER_ENTRY,
ListEntry
);
if (BytesToGo < sizeof(HTTP_SITE_COUNTERS))
{
// NOTE: the only way this can happen is if someone
// added a site to the end of the site list before
// we finished walking the counter list.
*pBytesWritten = BlockSize + sizeof(HTTP_SITE_COUNTERS);
Status = STATUS_BUFFER_TOO_SMALL;
goto End;
}
RtlCopyMemory(pBlock,
&(pCounterEntry->Counters),
sizeof(HTTP_SITE_COUNTERS)
);
//
// Zero out any counters that must be zeroed.
//
for ( i = 0; i < HttpSiteCounterMaximum; i++ )
{
if (TRUE == aIISULSiteDescription[i].WPZeros)
{
// Zero it out
UlResetSiteCounter(pCounterEntry, (HTTP_SITE_COUNTER_ID) i);
}
}
//
// Continue to next block
//
pBlock += sizeof(HTTP_SITE_COUNTERS);
BytesToGo -= sizeof(HTTP_SITE_COUNTERS);
BlocksSeen++;
pEntry = pEntry->Flink;
}
End:
//
// Set callers values
//
if (STATUS_SUCCESS == Status)
{
// REVIEW: If we failed, *pBytesWritten already contains
// the bytes required value.
*pBytesWritten = DIFF(pBlock - ((PUCHAR)pCounter));
}
if (pBlocksWritten)
{
*pBlocksWritten = BlocksSeen;
}
RETURN( Status );
} // UlpGetSiteCounters
#if REFERENCE_DEBUG
///////////////////////////////////////////////////////////////////////////////
// Global Counter functions
//
/***************************************************************************++
Routine Description:
Increment a Global (cache) performance counter.
Arguments:
Ctr - ID of Counter to increment
--***************************************************************************/
VOID
UlIncCounter(
HTTP_GLOBAL_COUNTER_ID Ctr
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpGlobalCounterMaximum ); // REVIEW: signed/unsigned issues?
UlTraceVerbose( PERF_COUNTERS,
("http!UlIncCounter (Ctr == %d)\n", Ctr) );
//
// figure out offset of Ctr in g_UlGlobalCounters
//
pCtr = (PCHAR) &g_UlGlobalCounters;
pCtr += aIISULGlobalDescription[Ctr].Offset;
// figure out data size of Ctr and do
// apropriate thread-safe increment
if (sizeof(ULONG) == aIISULGlobalDescription[Ctr].Size)
{
// ULONG
InterlockedIncrement((PLONG) pCtr);
}
else
{
// ULONGLONG
UlInterlockedIncrement64((PLONGLONG) pCtr);
}
} // UlIncCounter
/***************************************************************************++
Routine Description:
Decrement a Global (cache) performance counter.
Arguments:
Ctr - ID of Counter to decrement
--***************************************************************************/
VOID
UlDecCounter(
HTTP_GLOBAL_COUNTER_ID Ctr
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpGlobalCounterMaximum ); // REVIEW: signed/unsigned issues?
UlTraceVerbose( PERF_COUNTERS,
("http!UlDecCounter (Ctr == %d)\n", Ctr));
//
// figure out offset of Ctr in g_UlGlobalCounters
//
pCtr = (PCHAR) &g_UlGlobalCounters;
pCtr += aIISULGlobalDescription[Ctr].Offset;
// figure out data size of Ctr and do
// apropriate thread-safe increment
if (sizeof(ULONG) == aIISULGlobalDescription[Ctr].Size)
{
// ULONG
InterlockedDecrement((PLONG) pCtr);
}
else
{
// ULONGLONG
UlInterlockedDecrement64((PLONGLONG) pCtr);
}
}
/***************************************************************************++
Routine Description:
Add a ULONG value to a Global (cache) performance counter.
Arguments:
Ctr - ID of counter to which the Value should be added
Value - The amount to add to the counter
--***************************************************************************/
VOID
UlAddCounter(
HTTP_GLOBAL_COUNTER_ID Ctr,
ULONG Value
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpGlobalCounterMaximum ); // REVIEW: signed/unsigned issues?
UlTraceVerbose( PERF_COUNTERS,
("http!UlAddCounter (Ctr == %d, Value == %d)\n", Ctr, Value));
//
// figure out offset of Ctr in g_UlGlobalCounters
//
pCtr = (PCHAR) &g_UlGlobalCounters;
pCtr += aIISULGlobalDescription[Ctr].Offset;
//
// figure out data size of Ctr and do
// apropriate thread-safe increment
//
if (sizeof(ULONG) == aIISULGlobalDescription[Ctr].Size)
{
// ULONG
InterlockedExchangeAdd((PLONG) pCtr, Value);
}
else
{
// ULONGLONG
UlInterlockedAdd64((PLONGLONG) pCtr, Value);
}
} // UlAddCounter
/***************************************************************************++
Routine Description:
Zero-out a Global (cache) performance counter.
Arguments:
Ctr - ID of Counter to be reset.
--***************************************************************************/
VOID
UlResetCounter(
HTTP_GLOBAL_COUNTER_ID Ctr
)
{
// Special Case
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpGlobalCounterMaximum ); // REVIEW: signed/unsigned issues?
UlTraceVerbose(PERF_COUNTERS,
("http!UlResetCounter (Ctr == %d)\n", Ctr));
//
// figure out offset of Ctr in g_UlGlobalCounters
//
pCtr = (PCHAR) &g_UlGlobalCounters;
pCtr += aIISULGlobalDescription[Ctr].Offset;
//
// do apropriate "set" for data size of Ctr
//
if (sizeof(ULONG) == aIISULGlobalDescription[Ctr].Size)
{
// ULONG
InterlockedExchange((PLONG) pCtr, 0);
}
else
{
// ULONGLONG
LONGLONG localCtr;
LONGLONG originalCtr;
LONGLONG localZero = 0;
do {
localCtr = *((volatile LONGLONG *) pCtr);
originalCtr = InterlockedCompareExchange64( (PLONGLONG) pCtr,
localZero,
localCtr );
} while (originalCtr != localCtr);
}
} // UlResetCounter
///////////////////////////////////////////////////////////////////////////////
// Site Counter functions
//
/***************************************************************************++
Routine Description:
Increment a NonCritical Site performance counter.
Arguments:
pEntry - pointer to Site Counter entry
CounterId - ID of Counter to increment
Returns:
Nothing
--***************************************************************************/
VOID
UlIncSiteNonCriticalCounterUlong(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID CounterId
)
{
PCHAR pCounter;
PLONG plValue;
pCounter = (PCHAR) &(pEntry->Counters);
pCounter += aIISULSiteDescription[CounterId].Offset;
plValue = (PLONG) pCounter;
++(*plValue);
}
/***************************************************************************++
Routine Description:
Increment a NonCritical Site performance counter.
Arguments:
pEntry - pointer to Site Counter entry
CounterId - ID of Counter to increment
Returns:
Nothing
--***************************************************************************/
VOID
UlIncSiteNonCriticalCounterUlonglong(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID CounterId
)
{
PCHAR pCounter;
PLONGLONG pllValue;
pCounter = (PCHAR) &(pEntry->Counters);
pCounter += aIISULSiteDescription[CounterId].Offset;
pllValue = (PLONGLONG) pCounter;
++(*pllValue);
}
/***************************************************************************++
Routine Description:
Increment a Site performance counter.
Arguments:
pEntry - pointer to Site Counter entry
Ctr - ID of Counter to increment
Returns:
Value of counter after incrementing
--***************************************************************************/
LONGLONG
UlIncSiteCounter(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID Ctr
)
{
PCHAR pCtr;
LONGLONG llValue;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues?
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
UlTraceVerbose( PERF_COUNTERS,
("http!UlIncSiteCounter Ctr=%d SiteId=%d\n",
Ctr,
pEntry->Counters.SiteId
));
//
// figure out offset of Ctr in HTTP_SITE_COUNTERS
//
pCtr = (PCHAR) &(pEntry->Counters);
pCtr += aIISULSiteDescription[Ctr].Offset;
// figure out data size of Ctr and do
// apropriate thread-safe increment
if (sizeof(ULONG) == aIISULSiteDescription[Ctr].Size)
{
// ULONG
llValue = (LONGLONG) InterlockedIncrement((PLONG) pCtr);
}
else
{
// ULONGLONG
llValue = UlInterlockedIncrement64((PLONGLONG) pCtr);
}
return llValue;
}
/***************************************************************************++
Routine Description:
Decrement a Site performance counter.
Arguments:
pEntry - pointer to Site Counter entry
Ctr - ID of Counter to decrement
--***************************************************************************/
VOID
UlDecSiteCounter(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID Ctr
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues?
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
UlTraceVerbose( PERF_COUNTERS,
("http!UlDecSiteCounter Ctr=%d SiteId=%d\n",
Ctr,
pEntry->Counters.SiteId
));
//
// figure out offset of Ctr in HTTP_SITE_COUNTERS
//
pCtr = (PCHAR) &(pEntry->Counters);
pCtr += aIISULSiteDescription[Ctr].Offset;
// figure out data size of Ctr and do
// apropriate thread-safe increment
if (sizeof(ULONG) == aIISULSiteDescription[Ctr].Size)
{
// ULONG
InterlockedDecrement((PLONG) pCtr);
}
else
{
// ULONGLONG
UlInterlockedDecrement64((PLONGLONG) pCtr);
}
}
/***************************************************************************++
Routine Description:
Add a ULONG value to a 32-bit site performance counter.
Arguments:
pEntry - pointer to Site Counter entry
Ctr - ID of counter to which the Value should be added
Value - The amount to add to the counter
--***************************************************************************/
VOID
UlAddSiteCounter(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID Ctr,
ULONG Value
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues?
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
UlTraceVerbose( PERF_COUNTERS,
("http!UlAddSiteCounter Ctr=%d SiteId=%d Value=%d\n",
Ctr,
pEntry->Counters.SiteId,
Value
));
//
// figure out offset of Ctr in HTTP_SITE_COUNTERS
//
pCtr = (PCHAR) &(pEntry->Counters);
pCtr += aIISULSiteDescription[Ctr].Offset;
// figure out data size of Ctr and do
// apropriate thread-safe increment
ASSERT(sizeof(ULONG) == aIISULSiteDescription[Ctr].Size);
InterlockedExchangeAdd((PLONG) pCtr, Value);
}
/***************************************************************************++
Routine Description:
Add a ULONGLONG value to a 64-bit site performance counter.
Arguments:
pEntry - pointer to Site Counter entry
Ctr - ID of counter to which the Value should be added
Value - The amount to add to the counter
--***************************************************************************/
VOID
UlAddSiteCounter64(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID Ctr,
ULONGLONG llValue
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues?
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
UlTraceVerbose( PERF_COUNTERS,
("http!UlAddSiteCounter64 Ctr=%d SiteId=%d Value=%I64d\n",
Ctr,
pEntry->Counters.SiteId,
llValue
));
//
// figure out offset of Ctr in HTTP_SITE_COUNTERS
//
pCtr = (PCHAR) &(pEntry->Counters);
pCtr += aIISULSiteDescription[Ctr].Offset;
ASSERT(sizeof(ULONGLONG) == aIISULSiteDescription[Ctr].Size);
UlInterlockedAdd64((PLONGLONG) pCtr, llValue);
}
/***************************************************************************++
Routine Description:
Reset a Site performance counter.
Arguments:
pEntry - pointer to Site Counter entry
Ctr - ID of counter to be reset
--***************************************************************************/
VOID
UlResetSiteCounter(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID Ctr
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues?
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
UlTraceVerbose( PERF_COUNTERS,
("http!UlResetSiteCounter Ctr=%d SiteId=%d\n",
Ctr,
pEntry->Counters.SiteId
));
//
// figure out offset of Ctr in HTTP_SITE_COUNTERS
//
pCtr = (PCHAR) &(pEntry->Counters);
pCtr += aIISULSiteDescription[Ctr].Offset;
//
// do apropriate "set" for data size of Ctr
//
if (sizeof(ULONG) == aIISULSiteDescription[Ctr].Size)
{
// ULONG
InterlockedExchange((PLONG) pCtr, 0);
}
else
{
// ULONGLONG
LONGLONG localCtr;
LONGLONG originalCtr;
LONGLONG localZero = 0;
do {
localCtr = *((volatile LONGLONG *) pCtr);
originalCtr = InterlockedCompareExchange64( (PLONGLONG) pCtr,
localZero,
localCtr );
} while (originalCtr != localCtr);
}
}
/***************************************************************************++
Routine Description:
Determine if a new maximum value of a Site performance counter has been
hit and set the counter to the new maximum if necessary. (ULONG version)
Arguments:
pEntry - pointer to Site Counter entry
Ctr - ID of counter
Value - possible new maximum (NOTE: Assumes that the counter Ctr is a
32-bit value)
--***************************************************************************/
VOID
UlMaxSiteCounter(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID Ctr,
ULONG Value
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues?
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
UlTraceVerbose( PERF_COUNTERS,
("http!UlMaxSiteCounter Ctr=%d SiteId=%d Value=%d\n",
Ctr,
pEntry->Counters.SiteId,
Value
));
//
// figure out offset of Ctr in HTTP_SITE_COUNTERS
//
pCtr = (PCHAR) &(pEntry->Counters);
pCtr += aIISULSiteDescription[Ctr].Offset;
// Grab counter block mutex
ExAcquireFastMutex(&pEntry->EntryMutex);
if (Value > (ULONG) *pCtr)
{
InterlockedExchange((PLONG) pCtr, Value);
}
// Release counter block mutex
ExReleaseFastMutex(&pEntry->EntryMutex);
}
/***************************************************************************++
Routine Description:
Determine if a new maximum value of a Site performance counter has been
hit and set the counter to the new maximum if necessary. (LONGLONG version)
Arguments:
pEntry - pointer to Site Counter entry
Ctr - ID of counter
Value - possible new maximum (NOTE: Assumes that the counter Ctr is a
64-bit value)
--***************************************************************************/
VOID
UlMaxSiteCounter64(
PUL_SITE_COUNTER_ENTRY pEntry,
HTTP_SITE_COUNTER_ID Ctr,
LONGLONG llValue
)
{
PCHAR pCtr;
ASSERT( g_InitCountersCalled );
ASSERT( Ctr < HttpSiteCounterMaximum ); // REVIEW: signed/unsigned issues?
ASSERT( IS_VALID_SITE_COUNTER_ENTRY(pEntry) );
UlTraceVerbose( PERF_COUNTERS,
("http!UlMaxSiteCounter64 Ctr=%d SiteId=%d Value=%I64d\n",
Ctr,
pEntry->Counters.SiteId,
llValue
));
//
// figure out offset of Ctr in HTTP_SITE_COUNTERS
//
pCtr = (PCHAR) &(pEntry->Counters);
pCtr += aIISULSiteDescription[Ctr].Offset;
// Grab counter block mutex
ExAcquireFastMutex(&pEntry->EntryMutex);
if (llValue > (LONGLONG) *pCtr)
{
*((PLONGLONG) pCtr) = llValue;
#if 0
// REVIEW: There *must* be a better way to do this...
// REVIEW: I want to do: (LONGLONG) *pCtr = llValue;
// REVIEW: But casting something seems to make it a constant.
// REVIEW: Also, there isn't an "InterlockedExchange64" for x86.
// REVIEW: Any suggestions? --EricSten
RtlCopyMemory(
pCtr,
&llValue,
sizeof(LONGLONG)
);
#endif // 0
}
// Release counter block mutex
ExReleaseFastMutex(&pEntry->EntryMutex);
}
#endif
/***************************************************************************++
Routine Description:
Predicate to test if a site counter entry already exists for the given
SiteId
Arguments:
SiteId - ID of site
Return Value:
TRUE if found
FALSE if not found
--***************************************************************************/
BOOLEAN
UlpIsInSiteCounterList(ULONG SiteId)
{
PLIST_ENTRY pEntry;
PUL_SITE_COUNTER_ENTRY pCounterEntry;
BOOLEAN IsFound = FALSE;
if (IsListEmpty(&g_SiteCounterListHead))
{
ASSERT(0 == g_SiteCounterListCount);
// Good! No counters left behind!
goto End;
}
//
// Walk list of Site Counter Entries
//
pEntry = g_SiteCounterListHead.Flink;
while (pEntry != &g_SiteCounterListHead)
{
pCounterEntry = CONTAINING_RECORD(
pEntry,
UL_SITE_COUNTER_ENTRY,
ListEntry
);
ASSERT(IS_VALID_SITE_COUNTER_ENTRY(pCounterEntry));
if (SiteId == pCounterEntry->Counters.SiteId)
{
IsFound = TRUE;
goto End;
}
pEntry = pEntry->Flink;
}
End:
return IsFound;
}