170 lines
3.7 KiB
C
170 lines
3.7 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
callperf.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the functions necessary to collect call data.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 22-May-1994
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "exp.h"
|
||
|
||
VOID
|
||
ExInitializeCallData (
|
||
IN PCALL_PERFORMANCE_DATA CallData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes a call performance data structure.
|
||
|
||
Arguments:
|
||
|
||
CallData - Supplies a pointer to the call performance data structure
|
||
that is initialized.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG Index;
|
||
|
||
//
|
||
// Initialize the spinlock and listheads for the call performance
|
||
// data structure.
|
||
//
|
||
|
||
KeInitializeSpinLock(&CallData->SpinLock);
|
||
for (Index = 0; Index < CALL_HASH_TABLE_SIZE; Index += 1) {
|
||
InitializeListHead(&CallData->HashTable[Index]);
|
||
}
|
||
}
|
||
|
||
VOID
|
||
ExRecordCallerInHashTable (
|
||
IN PCALL_PERFORMANCE_DATA CallData,
|
||
IN PVOID CallersAddress,
|
||
IN PVOID CallersCaller
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function records call data in the specified call performance
|
||
data structure.
|
||
|
||
Arguments:
|
||
|
||
CallData - Supplies a pointer to the call performance data structure
|
||
in which the call data is recorded.
|
||
|
||
CallersAddress - Supplies the address of the caller of a fucntion.
|
||
|
||
CallersCaller - Supplies the address of the caller of a caller of
|
||
a function.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PCALL_HASH_ENTRY HashEntry;
|
||
ULONG Hash;
|
||
PCALL_HASH_ENTRY MatchEntry;
|
||
PLIST_ENTRY NextEntry;
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// If the initialization phase is not zero, then collect call performance
|
||
// data.
|
||
//
|
||
|
||
if (InitializationPhase != 0) {
|
||
|
||
//
|
||
// Acquire the call performance data structure spinlock.
|
||
//
|
||
|
||
ExAcquireSpinLock(&CallData->SpinLock, &OldIrql);
|
||
|
||
//
|
||
// Lookup the callers address in call performance data hash table. If
|
||
// the address does not exist in the table, then create a new entry.
|
||
//
|
||
|
||
Hash = (ULONG)((ULONG_PTR)CallersAddress ^ (ULONG_PTR)CallersCaller);
|
||
Hash = ((Hash >> 24) ^ (Hash >> 16) ^ (Hash >> 8) ^ (Hash)) & (CALL_HASH_TABLE_SIZE - 1);
|
||
MatchEntry = NULL;
|
||
NextEntry = CallData->HashTable[Hash].Flink;
|
||
while (NextEntry != &CallData->HashTable[Hash]) {
|
||
HashEntry = CONTAINING_RECORD(NextEntry,
|
||
CALL_HASH_ENTRY,
|
||
ListEntry);
|
||
|
||
if ((HashEntry->CallersAddress == CallersAddress) &&
|
||
(HashEntry->CallersCaller == CallersCaller)) {
|
||
MatchEntry = HashEntry;
|
||
break;
|
||
}
|
||
|
||
NextEntry = NextEntry->Flink;
|
||
}
|
||
|
||
//
|
||
// If a matching caller address was found, then update the call site
|
||
// statistics. Otherwise, allocate a new hash entry and initialize
|
||
// call site statistics.
|
||
//
|
||
|
||
if (MatchEntry != NULL) {
|
||
MatchEntry->CallCount += 1;
|
||
|
||
} else {
|
||
MatchEntry = ExAllocatePoolWithTag(NonPagedPool,
|
||
sizeof(CALL_HASH_ENTRY),
|
||
'CdHe');
|
||
|
||
if (MatchEntry != NULL) {
|
||
MatchEntry->CallersAddress = CallersAddress;
|
||
MatchEntry->CallersCaller = CallersCaller;
|
||
MatchEntry->CallCount = 1;
|
||
InsertTailList(&CallData->HashTable[Hash],
|
||
&MatchEntry->ListEntry);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Release the call performance data structure spinlock.
|
||
//
|
||
|
||
ExReleaseSpinLock(&CallData->SpinLock, OldIrql);
|
||
}
|
||
|
||
return;
|
||
}
|