- Get rid of TAG() from the kernel
[reactos.git] / reactos / ntoskrnl / ke / profobj.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/profobj.c
5 * PURPOSE: Kernel Profiling
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 KIRQL KiProfileIrql = PROFILE_LEVEL;
18 LIST_ENTRY KiProfileListHead;
19 LIST_ENTRY KiProfileSourceListHead;
20 KSPIN_LOCK KiProfileLock;
21 ULONG KiProfileTimeInterval = 78125; /* Default resolution 7.8ms (sysinternals) */
22
23 /* FUNCTIONS *****************************************************************/
24
25 VOID
26 NTAPI
27 KeInitializeProfile(PKPROFILE Profile,
28 PKPROCESS Process,
29 PVOID ImageBase,
30 ULONG ImageSize,
31 ULONG BucketSize,
32 KPROFILE_SOURCE ProfileSource,
33 KAFFINITY Affinity)
34 {
35 /* Initialize the Header */
36 Profile->Type = ProfileObject;
37 Profile->Size = sizeof(KPROFILE);
38
39 /* Copy all the settings we were given */
40 Profile->Process = Process;
41 Profile->RangeBase = ImageBase;
42 Profile->BucketShift = BucketSize - 2; /* See ntinternals.net -- Alex */
43 Profile->RangeLimit = (PVOID)((ULONG_PTR)ImageBase + ImageSize);
44 Profile->Started = FALSE;
45 Profile->Source = ProfileSource;
46 Profile->Affinity = Affinity;
47 }
48
49 VOID
50 NTAPI
51 KeStartProfile(PKPROFILE Profile,
52 PVOID Buffer)
53 {
54 KIRQL OldIrql;
55 PKPROFILE_SOURCE_OBJECT SourceBuffer;
56 PKPROFILE_SOURCE_OBJECT CurrentSource;
57 BOOLEAN FreeBuffer = TRUE, SourceFound = FALSE;
58 PKPROCESS ProfileProcess;
59 PLIST_ENTRY NextEntry;
60
61 /* Allocate a buffer first, before we raise IRQL */
62 SourceBuffer = ExAllocatePoolWithTag(NonPagedPool,
63 sizeof(KPROFILE_SOURCE_OBJECT),
64 'forP');
65 RtlZeroMemory(SourceBuffer, sizeof(KPROFILE_SOURCE_OBJECT));
66
67 /* Raise to PROFILE_LEVEL */
68 KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
69 KeAcquireSpinLockAtDpcLevel(&KiProfileLock);
70
71 /* Make sure it's not running */
72 if (!Profile->Started)
73 {
74 /* Set it as Started */
75 Profile->Buffer = Buffer;
76 Profile->Started = TRUE;
77
78 /* Get the process, if any */
79 ProfileProcess = Profile->Process;
80
81 /* Check where we should insert it */
82 if (ProfileProcess)
83 {
84 /* Insert it into the Process List */
85 InsertTailList(&ProfileProcess->ProfileListHead, &Profile->ProfileListEntry);
86 }
87 else
88 {
89 /* Insert it into the Global List */
90 InsertTailList(&KiProfileListHead, &Profile->ProfileListEntry);
91 }
92
93 /* Start looping */
94 for (NextEntry = KiProfileSourceListHead.Flink;
95 NextEntry != &KiProfileSourceListHead;
96 NextEntry = NextEntry->Flink)
97 {
98 /* Get the entry */
99 CurrentSource = CONTAINING_RECORD(NextEntry,
100 KPROFILE_SOURCE_OBJECT,
101 ListEntry);
102
103 /* Check if it's the same as the one being requested now */
104 if (CurrentSource->Source == Profile->Source)
105 {
106 /* It is, break out */
107 SourceFound = TRUE;
108 break;
109 }
110 }
111
112 /* See if the loop found something */
113 if (!SourceFound)
114 {
115 /* Nothing found, use our allocated buffer */
116 CurrentSource = SourceBuffer;
117
118 /* Set up the Source Object */
119 CurrentSource->Source = Profile->Source;
120 InsertHeadList(&KiProfileSourceListHead, &CurrentSource->ListEntry);
121
122 /* Don't free the pool later on */
123 FreeBuffer = FALSE;
124 }
125 }
126
127 /* Lower the IRQL */
128 KeReleaseSpinLockFromDpcLevel(&KiProfileLock);
129 KeLowerIrql(OldIrql);
130
131 /* FIXME: Tell HAL to Start the Profile Interrupt */
132 //HalStartProfileInterrupt(Profile->Source);
133
134 /* Free the pool */
135 if (FreeBuffer) ExFreePool(SourceBuffer);
136 }
137
138 BOOLEAN
139 NTAPI
140 KeStopProfile(PKPROFILE Profile)
141 {
142 KIRQL OldIrql;
143 PKPROFILE_SOURCE_OBJECT CurrentSource = NULL;
144 PLIST_ENTRY NextEntry;
145 BOOLEAN SourceFound = FALSE;
146
147 /* Raise to PROFILE_LEVEL and acquire spinlock */
148 KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
149 KeAcquireSpinLockAtDpcLevel(&KiProfileLock);
150
151 /* Make sure it's running */
152 if (Profile->Started)
153 {
154 /* Remove it from the list and disable */
155 RemoveEntryList(&Profile->ProfileListEntry);
156 Profile->Started = FALSE;
157
158 /* Start looping */
159 for (NextEntry = KiProfileSourceListHead.Flink;
160 NextEntry != &KiProfileSourceListHead;
161 NextEntry = NextEntry->Flink)
162 {
163 /* Get the entry */
164 CurrentSource = CONTAINING_RECORD(NextEntry,
165 KPROFILE_SOURCE_OBJECT,
166 ListEntry);
167
168 /* Check if this is the Source Object */
169 if (CurrentSource->Source == Profile->Source)
170 {
171 /* Remember we found one */
172 SourceFound = TRUE;
173
174 /* Remove it and break out */
175 RemoveEntryList(&CurrentSource->ListEntry);
176 break;
177 }
178 }
179
180 }
181
182 /* Lower IRQL */
183 KeReleaseSpinLockFromDpcLevel(&KiProfileLock);
184 KeLowerIrql(OldIrql);
185
186 /* Stop Profiling. FIXME: Implement in HAL */
187 //HalStopProfileInterrupt(Profile->Source);
188
189 /* Free the Source Object */
190 if (SourceFound) ExFreePool(CurrentSource);
191
192 /* FIXME */
193 return FALSE;
194 }
195
196 ULONG
197 NTAPI
198 KeQueryIntervalProfile(KPROFILE_SOURCE ProfileSource)
199 {
200 /* Check if this is the timer profile */
201 if (ProfileSource == ProfileTime)
202 {
203 /* Return the good old 100ns sampling interval */
204 return KiProfileTimeInterval;
205 }
206 else
207 {
208 /* Request it from HAL. FIXME: What structure is used? */
209 HalQuerySystemInformation(HalProfileSourceInformation,
210 sizeof(NULL),
211 NULL,
212 NULL);
213
214 return 0;
215 }
216 }
217
218 VOID
219 NTAPI
220 KeSetIntervalProfile(KPROFILE_SOURCE ProfileSource,
221 ULONG Interval)
222 {
223 /* Check if this is the timer profile */
224 if (ProfileSource == ProfileTime)
225 {
226 /* Set the good old 100ns sampling interval */
227 KiProfileTimeInterval = Interval;
228 }
229 else
230 {
231 /* Set it with HAL. FIXME: What structure is used? */
232 HalSetSystemInformation(HalProfileSourceInformation,
233 sizeof(NULL),
234 NULL);
235 }
236 }
237
238 /*
239 * @implemented
240 */
241 VOID
242 NTAPI
243 KeProfileInterrupt(PKTRAP_FRAME TrapFrame)
244 {
245 /* Called from HAL for Timer Profiling */
246 KeProfileInterruptWithSource(TrapFrame, ProfileTime);
247 }
248
249 VOID
250 NTAPI
251 KiParseProfileList(IN PKTRAP_FRAME TrapFrame,
252 IN KPROFILE_SOURCE Source,
253 IN PLIST_ENTRY ListHead)
254 {
255 PULONG BucketValue;
256 PKPROFILE Profile;
257 PLIST_ENTRY NextEntry;
258
259 /* Loop the List */
260 for (NextEntry = ListHead->Flink;
261 NextEntry != ListHead;
262 NextEntry = NextEntry->Flink)
263 {
264 /* Get the entry */
265 Profile = CONTAINING_RECORD(NextEntry, KPROFILE, ProfileListEntry);
266
267 /* Check if the source is good, and if it's within the range */
268 #ifdef _M_IX86
269 if ((Profile->Source != Source) ||
270 (TrapFrame->Eip < (ULONG_PTR)Profile->RangeBase) ||
271 (TrapFrame->Eip > (ULONG_PTR)Profile->RangeLimit))
272 {
273 continue;
274 }
275
276 /* Get the Pointer to the Bucket Value representing this EIP */
277 BucketValue = (PULONG)((((ULONG_PTR)Profile->Buffer +
278 (TrapFrame->Eip - (ULONG_PTR)Profile->RangeBase))
279 >> Profile->BucketShift) &~ 0x3);
280 #elif defined(_M_PPC)
281 // XXX arty
282 #endif
283
284 /* Increment the value */
285 ++BucketValue;
286 }
287 }
288
289 /*
290 * @implemented
291 *
292 * Remarks:
293 * Called from HAL, this function looks up the process
294 * entries, finds the proper source object, verifies the
295 * ranges with the trapframe data, and inserts the information
296 * from the trap frame into the buffer, while using buckets and
297 * shifting like we specified. -- Alex
298 */
299 VOID
300 NTAPI
301 KeProfileInterruptWithSource(IN PKTRAP_FRAME TrapFrame,
302 IN KPROFILE_SOURCE Source)
303 {
304 PKPROCESS Process = KeGetCurrentThread()->ApcState.Process;
305
306 /* We have to parse 2 lists. Per-Process and System-Wide */
307 KiParseProfileList(TrapFrame, Source, &Process->ProfileListHead);
308 KiParseProfileList(TrapFrame, Source, &KiProfileListHead);
309 }
310
311 /*
312 * @implemented
313 */
314 VOID
315 NTAPI
316 KeSetProfileIrql(IN KIRQL ProfileIrql)
317 {
318 /* Set the IRQL at which Profiling will run */
319 KiProfileIrql = ProfileIrql;
320 }