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.

169 lines
3.7 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. callperf.c
  5. Abstract:
  6. This module implements the functions necessary to collect call data.
  7. Author:
  8. David N. Cutler (davec) 22-May-1994
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "exp.h"
  14. VOID
  15. ExInitializeCallData (
  16. IN PCALL_PERFORMANCE_DATA CallData
  17. )
  18. /*++
  19. Routine Description:
  20. This function initializes a call performance data structure.
  21. Arguments:
  22. CallData - Supplies a pointer to the call performance data structure
  23. that is initialized.
  24. Return Value:
  25. None.
  26. --*/
  27. {
  28. ULONG Index;
  29. //
  30. // Initialize the spinlock and listheads for the call performance
  31. // data structure.
  32. //
  33. KeInitializeSpinLock(&CallData->SpinLock);
  34. for (Index = 0; Index < CALL_HASH_TABLE_SIZE; Index += 1) {
  35. InitializeListHead(&CallData->HashTable[Index]);
  36. }
  37. }
  38. VOID
  39. ExRecordCallerInHashTable (
  40. IN PCALL_PERFORMANCE_DATA CallData,
  41. IN PVOID CallersAddress,
  42. IN PVOID CallersCaller
  43. )
  44. /*++
  45. Routine Description:
  46. This function records call data in the specified call performance
  47. data structure.
  48. Arguments:
  49. CallData - Supplies a pointer to the call performance data structure
  50. in which the call data is recorded.
  51. CallersAddress - Supplies the address of the caller of a fucntion.
  52. CallersCaller - Supplies the address of the caller of a caller of
  53. a function.
  54. Return Value:
  55. None.
  56. --*/
  57. {
  58. PCALL_HASH_ENTRY HashEntry;
  59. ULONG Hash;
  60. PCALL_HASH_ENTRY MatchEntry;
  61. PLIST_ENTRY NextEntry;
  62. KIRQL OldIrql;
  63. //
  64. // If the initialization phase is not zero, then collect call performance
  65. // data.
  66. //
  67. if (InitializationPhase != 0) {
  68. //
  69. // Acquire the call performance data structure spinlock.
  70. //
  71. ExAcquireSpinLock(&CallData->SpinLock, &OldIrql);
  72. //
  73. // Lookup the callers address in call performance data hash table. If
  74. // the address does not exist in the table, then create a new entry.
  75. //
  76. Hash = (ULONG)((ULONG_PTR)CallersAddress ^ (ULONG_PTR)CallersCaller);
  77. Hash = ((Hash >> 24) ^ (Hash >> 16) ^ (Hash >> 8) ^ (Hash)) & (CALL_HASH_TABLE_SIZE - 1);
  78. MatchEntry = NULL;
  79. NextEntry = CallData->HashTable[Hash].Flink;
  80. while (NextEntry != &CallData->HashTable[Hash]) {
  81. HashEntry = CONTAINING_RECORD(NextEntry,
  82. CALL_HASH_ENTRY,
  83. ListEntry);
  84. if ((HashEntry->CallersAddress == CallersAddress) &&
  85. (HashEntry->CallersCaller == CallersCaller)) {
  86. MatchEntry = HashEntry;
  87. break;
  88. }
  89. NextEntry = NextEntry->Flink;
  90. }
  91. //
  92. // If a matching caller address was found, then update the call site
  93. // statistics. Otherwise, allocate a new hash entry and initialize
  94. // call site statistics.
  95. //
  96. if (MatchEntry != NULL) {
  97. MatchEntry->CallCount += 1;
  98. } else {
  99. MatchEntry = ExAllocatePoolWithTag(NonPagedPool,
  100. sizeof(CALL_HASH_ENTRY),
  101. 'CdHe');
  102. if (MatchEntry != NULL) {
  103. MatchEntry->CallersAddress = CallersAddress;
  104. MatchEntry->CallersCaller = CallersCaller;
  105. MatchEntry->CallCount = 1;
  106. InsertTailList(&CallData->HashTable[Hash],
  107. &MatchEntry->ListEntry);
  108. }
  109. }
  110. //
  111. // Release the call performance data structure spinlock.
  112. //
  113. ExReleaseSpinLock(&CallData->SpinLock, OldIrql);
  114. }
  115. return;
  116. }