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)
9 /* INCLUDES *****************************************************************/
15 /* GLOBALS *******************************************************************/
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) */
23 /* FUNCTIONS *****************************************************************/
27 KeInitializeProfile(PKPROFILE Profile
,
32 KPROFILE_SOURCE ProfileSource
,
35 /* Initialize the Header */
36 Profile
->Type
= ProfileObject
;
37 Profile
->Size
= sizeof(KPROFILE
);
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
;
51 KeStartProfile(PKPROFILE Profile
,
55 PKPROFILE_SOURCE_OBJECT SourceBuffer
;
56 PKPROFILE_SOURCE_OBJECT CurrentSource
;
57 BOOLEAN FreeBuffer
= TRUE
, SourceFound
= FALSE
;
58 PKPROCESS ProfileProcess
;
59 PLIST_ENTRY NextEntry
;
61 /* Allocate a buffer first, before we raise IRQL */
62 SourceBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
63 sizeof(KPROFILE_SOURCE_OBJECT
),
65 if (!SourceBuffer
) return;
66 RtlZeroMemory(SourceBuffer
, sizeof(KPROFILE_SOURCE_OBJECT
));
68 /* Raise to PROFILE_LEVEL */
69 KeRaiseIrql(PROFILE_LEVEL
, &OldIrql
);
70 KeAcquireSpinLockAtDpcLevel(&KiProfileLock
);
72 /* Make sure it's not running */
73 if (!Profile
->Started
)
75 /* Set it as Started */
76 Profile
->Buffer
= Buffer
;
77 Profile
->Started
= TRUE
;
79 /* Get the process, if any */
80 ProfileProcess
= Profile
->Process
;
82 /* Check where we should insert it */
85 /* Insert it into the Process List */
86 InsertTailList(&ProfileProcess
->ProfileListHead
, &Profile
->ProfileListEntry
);
90 /* Insert it into the Global List */
91 InsertTailList(&KiProfileListHead
, &Profile
->ProfileListEntry
);
95 for (NextEntry
= KiProfileSourceListHead
.Flink
;
96 NextEntry
!= &KiProfileSourceListHead
;
97 NextEntry
= NextEntry
->Flink
)
100 CurrentSource
= CONTAINING_RECORD(NextEntry
,
101 KPROFILE_SOURCE_OBJECT
,
104 /* Check if it's the same as the one being requested now */
105 if (CurrentSource
->Source
== Profile
->Source
)
107 /* It is, break out */
113 /* See if the loop found something */
116 /* Nothing found, use our allocated buffer */
117 CurrentSource
= SourceBuffer
;
119 /* Set up the Source Object */
120 CurrentSource
->Source
= Profile
->Source
;
121 InsertHeadList(&KiProfileSourceListHead
, &CurrentSource
->ListEntry
);
123 /* Don't free the pool later on */
129 KeReleaseSpinLockFromDpcLevel(&KiProfileLock
);
130 KeLowerIrql(OldIrql
);
132 /* FIXME: Tell HAL to Start the Profile Interrupt */
133 //HalStartProfileInterrupt(Profile->Source);
136 if (FreeBuffer
) ExFreePool(SourceBuffer
);
141 KeStopProfile(PKPROFILE Profile
)
144 PKPROFILE_SOURCE_OBJECT CurrentSource
= NULL
;
145 PLIST_ENTRY NextEntry
;
146 BOOLEAN SourceFound
= FALSE
;
148 /* Raise to PROFILE_LEVEL and acquire spinlock */
149 KeRaiseIrql(PROFILE_LEVEL
, &OldIrql
);
150 KeAcquireSpinLockAtDpcLevel(&KiProfileLock
);
152 /* Make sure it's running */
153 if (Profile
->Started
)
155 /* Remove it from the list and disable */
156 RemoveEntryList(&Profile
->ProfileListEntry
);
157 Profile
->Started
= FALSE
;
160 for (NextEntry
= KiProfileSourceListHead
.Flink
;
161 NextEntry
!= &KiProfileSourceListHead
;
162 NextEntry
= NextEntry
->Flink
)
165 CurrentSource
= CONTAINING_RECORD(NextEntry
,
166 KPROFILE_SOURCE_OBJECT
,
169 /* Check if this is the Source Object */
170 if (CurrentSource
->Source
== Profile
->Source
)
172 /* Remember we found one */
175 /* Remove it and break out */
176 RemoveEntryList(&CurrentSource
->ListEntry
);
184 KeReleaseSpinLockFromDpcLevel(&KiProfileLock
);
185 KeLowerIrql(OldIrql
);
187 /* Stop Profiling. FIXME: Implement in HAL */
188 //HalStopProfileInterrupt(Profile->Source);
190 /* Free the Source Object */
191 if (SourceFound
) ExFreePool(CurrentSource
);
199 KeQueryIntervalProfile(KPROFILE_SOURCE ProfileSource
)
201 /* Check if this is the timer profile */
202 if (ProfileSource
== ProfileTime
)
204 /* Return the good old 100ns sampling interval */
205 return KiProfileTimeInterval
;
209 /* Request it from HAL. FIXME: What structure is used? */
210 HalQuerySystemInformation(HalProfileSourceInformation
,
221 KeSetIntervalProfile(KPROFILE_SOURCE ProfileSource
,
224 /* Check if this is the timer profile */
225 if (ProfileSource
== ProfileTime
)
227 /* Set the good old 100ns sampling interval */
228 KiProfileTimeInterval
= Interval
;
232 /* Set it with HAL. FIXME: What structure is used? */
233 HalSetSystemInformation(HalProfileSourceInformation
,
244 KeProfileInterrupt(PKTRAP_FRAME TrapFrame
)
246 /* Called from HAL for Timer Profiling */
247 KeProfileInterruptWithSource(TrapFrame
, ProfileTime
);
252 KiParseProfileList(IN PKTRAP_FRAME TrapFrame
,
253 IN KPROFILE_SOURCE Source
,
254 IN PLIST_ENTRY ListHead
)
258 PLIST_ENTRY NextEntry
;
261 for (NextEntry
= ListHead
->Flink
;
262 NextEntry
!= ListHead
;
263 NextEntry
= NextEntry
->Flink
)
266 Profile
= CONTAINING_RECORD(NextEntry
, KPROFILE
, ProfileListEntry
);
268 /* Check if the source is good, and if it's within the range */
270 if ((Profile
->Source
!= Source
) ||
271 (TrapFrame
->Eip
< (ULONG_PTR
)Profile
->RangeBase
) ||
272 (TrapFrame
->Eip
> (ULONG_PTR
)Profile
->RangeLimit
))
277 /* Get the Pointer to the Bucket Value representing this EIP */
278 BucketValue
= (PULONG
)((((ULONG_PTR
)Profile
->Buffer
+
279 (TrapFrame
->Eip
- (ULONG_PTR
)Profile
->RangeBase
))
280 >> Profile
->BucketShift
) &~ 0x3);
281 #elif defined(_M_PPC)
285 /* Increment the value */
294 * Called from HAL, this function looks up the process
295 * entries, finds the proper source object, verifies the
296 * ranges with the trapframe data, and inserts the information
297 * from the trap frame into the buffer, while using buckets and
298 * shifting like we specified. -- Alex
302 KeProfileInterruptWithSource(IN PKTRAP_FRAME TrapFrame
,
303 IN KPROFILE_SOURCE Source
)
305 PKPROCESS Process
= KeGetCurrentThread()->ApcState
.Process
;
307 /* We have to parse 2 lists. Per-Process and System-Wide */
308 KiParseProfileList(TrapFrame
, Source
, &Process
->ProfileListHead
);
309 KiParseProfileList(TrapFrame
, Source
, &KiProfileListHead
);
317 KeSetProfileIrql(IN KIRQL ProfileIrql
)
319 /* Set the IRQL at which Profiling will run */
320 KiProfileIrql
= ProfileIrql
;