Merge 13159:13510 from trunk
[reactos.git] / reactos / ntoskrnl / ke / profile.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/profile.c
6 * PURPOSE: Kernel Profiling
7 *
8 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 */
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <internal/debug.h>
14
15 extern LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
16 extern LIST_ENTRY SystemProfileList;
17 extern KSPIN_LOCK ProfileListLock;
18 extern BOOLEAN ProfileInitDone;
19
20 /* FUNCTIONS *****************************************************************/
21
22 VOID
23 KiAddProfileEventToProcess(PLIST_ENTRY ListHead, PVOID Eip)
24 /*
25 * Add a profile event to the profile objects for a particular process
26 * or the system
27 */
28 {
29 PKPROFILE current;
30 PLIST_ENTRY current_entry;
31
32 current_entry = ListHead->Flink;
33 while (current_entry != ListHead)
34 {
35 current = CONTAINING_RECORD(current_entry, KPROFILE, ListEntry);
36
37 if (current->Base > Eip)
38 {
39 return;
40 }
41
42 if (current->Base <= Eip && ((char*)current->Base + current->Size) > (char*)Eip &&
43 current->Started)
44 {
45 ULONG Bucket;
46
47 Bucket = ((ULONG)((char*)Eip - (char*)current->Base)) >> current->BucketShift;
48
49 if ((Bucket*4) < current->BufferSize)
50 {
51 current->Buffer[Bucket]++;
52 }
53 }
54
55 current_entry = current_entry->Flink;
56 }
57 }
58
59 VOID
60 KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Eip)
61 /*
62 * Add a profile event
63 */
64 {
65 HANDLE Pid;
66 PKPROCESS_PROFILE current;
67 PLIST_ENTRY current_entry;
68 PLIST_ENTRY ListHead;
69
70 if (!ProfileInitDone)
71 {
72 return;
73 }
74
75 Pid = PsGetCurrentProcessId();
76 ListHead =
77 ProcessProfileListHashTable[(ULONG)Pid % PROFILE_HASH_TABLE_SIZE].Flink;
78
79 KeAcquireSpinLockAtDpcLevel(&ProfileListLock);
80
81 current_entry = ListHead;
82 while (current_entry != ListHead)
83 {
84 current = CONTAINING_RECORD(current_entry, KPROCESS_PROFILE, ListEntry);
85
86 if (current->Pid == Pid)
87 {
88 KiAddProfileEventToProcess(&current->ProfileListHead, (PVOID)Eip);
89 break;
90 }
91
92 current_entry = current_entry->Flink;
93 }
94
95 KiAddProfileEventToProcess(&SystemProfileList, (PVOID)Eip);
96
97 KeReleaseSpinLockFromDpcLevel(&ProfileListLock);
98 }
99
100 VOID
101 KiInsertProfileIntoProcess(PLIST_ENTRY ListHead, PKPROFILE Profile)
102 /*
103 * Insert a profile object into the list for a process or the system
104 */
105 {
106 PKPROFILE current;
107 PLIST_ENTRY current_entry;
108
109 current_entry = ListHead;
110 while (current_entry != ListHead)
111 {
112 current = CONTAINING_RECORD(current_entry, KPROFILE, ListEntry);
113
114 if (current->Base > Profile->Base)
115 {
116 Profile->ListEntry.Flink = current_entry;
117 Profile->ListEntry.Blink = current_entry->Blink;
118 current_entry->Blink->Flink = &Profile->ListEntry;
119 current_entry->Blink = &Profile->ListEntry;
120 return;
121 }
122
123 current_entry = current_entry->Flink;
124 }
125 InsertTailList(ListHead, &Profile->ListEntry);
126 }
127
128 VOID
129 KiInsertProfile(PKPROFILE Profile)
130 /*
131 * Insert a profile into the relevant data structures
132 */
133 {
134 KIRQL oldIrql;
135
136 KeAcquireSpinLock(&ProfileListLock, &oldIrql);
137
138 if (Profile->Process == NULL)
139 {
140 KiInsertProfileIntoProcess(&SystemProfileList, Profile);
141 }
142 else
143 {
144 HANDLE Pid;
145 PKPROCESS_PROFILE current;
146 PLIST_ENTRY current_entry;
147 PLIST_ENTRY ListHead;
148
149 Pid = Profile->Process->UniqueProcessId;
150 ListHead = &ProcessProfileListHashTable[(ULONG_PTR)Pid % PROFILE_HASH_TABLE_SIZE];
151
152 current_entry = ListHead;
153 while(current_entry != ListHead)
154 {
155 current = CONTAINING_RECORD(current_entry, KPROCESS_PROFILE,
156 ListEntry);
157
158 if (current->Pid == Pid)
159 {
160 KiInsertProfileIntoProcess(&current->ProfileListHead, Profile);
161 KeReleaseSpinLock(&ProfileListLock, oldIrql);
162 return;
163 }
164
165 current_entry = current_entry->Flink;
166 }
167
168 current = ExAllocatePool(NonPagedPool, sizeof(KPROCESS_PROFILE));
169
170 current->Pid = Pid;
171 InitializeListHead(&current->ProfileListHead);
172 InsertTailList(ListHead, &current->ListEntry);
173
174 KiInsertProfileIntoProcess(&current->ProfileListHead, Profile);
175 }
176
177 KeReleaseSpinLock(&ProfileListLock, oldIrql);
178 }
179
180 VOID KiRemoveProfile(PKPROFILE Profile)
181 {
182 KIRQL oldIrql;
183
184 KeAcquireSpinLock(&ProfileListLock, &oldIrql);
185
186 if (Profile->Process == NULL)
187 {
188 RemoveEntryList(&Profile->ListEntry);
189 }
190 else
191 {
192 HANDLE Pid;
193 PLIST_ENTRY ListHead;
194 PKPROCESS_PROFILE current;
195 PLIST_ENTRY current_entry;
196
197 RemoveEntryList(&Profile->ListEntry);
198
199 Pid = Profile->Process->UniqueProcessId;
200 ListHead = &ProcessProfileListHashTable[(ULONG_PTR)Pid % PROFILE_HASH_TABLE_SIZE];
201
202 current_entry = ListHead;
203 while(current_entry != ListHead)
204 {
205 current = CONTAINING_RECORD(current_entry, KPROCESS_PROFILE,
206 ListEntry);
207
208 if (current->Pid == Pid)
209 {
210 if (IsListEmpty(&current->ProfileListHead))
211 {
212 RemoveEntryList(&current->ListEntry);
213 ExFreePool(current);
214 }
215 KeReleaseSpinLock(&ProfileListLock, oldIrql);
216 return;
217 }
218
219 current_entry = current_entry->Flink;
220 }
221 KEBUGCHECK(0);
222 }
223
224 KeReleaseSpinLock(&ProfileListLock, oldIrql);
225 }
226
227 VOID STDCALL
228 KiDeleteProfile(PVOID ObjectBody)
229 {
230 PKPROFILE Profile;
231
232 Profile = (PKPROFILE)ObjectBody;
233
234 KiRemoveProfile(Profile);
235 if (Profile->Process != NULL)
236 {
237 ObDereferenceObject(Profile->Process);
238 Profile->Process = NULL;
239 }
240
241 if (Profile->BufferMdl->MappedSystemVa != NULL)
242 {
243 MmUnmapLockedPages(Profile->BufferMdl->MappedSystemVa,
244 Profile->BufferMdl);
245 }
246 MmUnlockPages(Profile->BufferMdl);
247 ExFreePool(Profile->BufferMdl);
248 Profile->BufferMdl = NULL;
249 }
250
251 /*
252 * @unimplemented
253 */
254 STDCALL
255 VOID
256 KeProfileInterrupt(
257 PKTRAP_FRAME TrapFrame
258 )
259 {
260 UNIMPLEMENTED;
261 }
262
263 /*
264 * @unimplemented
265 */
266 STDCALL
267 VOID
268 KeProfileInterruptWithSource(
269 IN PKTRAP_FRAME TrapFrame,
270 IN KPROFILE_SOURCE Source
271 )
272 {
273 UNIMPLEMENTED;
274 }
275
276 /*
277 * @unimplemented
278 */
279 STDCALL
280 VOID
281 KeSetProfileIrql(
282 IN KIRQL ProfileIrql
283 )
284 {
285 UNIMPLEMENTED;
286 }