summaryrefslogtreecommitdiffstats
path: root/private/ntos/ex/callperf.c
blob: 7caad7b318c9ab220f141d7c1729ce5fbf50ddaf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*++

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;
}