windows-nt/Source/XPSP1/NT/base/ntos/ex/callperf.c
2020-09-26 16:20:57 +08:00

170 lines
3.7 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}