/*++ 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)CallersAddress ^ (ULONG)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; }