2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/profile.c
5 * PURPOSE: Kernel Profiling
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES *****************************************************************/
13 #include <internal/debug.h>
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
;
58 PKPROCESS ProfileProcess
;
60 /* Allocate a buffer first, before we raise IRQL */
61 SourceBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
62 sizeof(KPROFILE_SOURCE_OBJECT
),
63 TAG('P', 'r', 'o', 'f'));
64 RtlZeroMemory(SourceBuffer
, sizeof(KPROFILE_SOURCE_OBJECT
));
66 /* Raise to PROFILE_LEVEL */
67 KeRaiseIrql(PROFILE_LEVEL
, &OldIrql
);
68 KeAcquireSpinLockAtDpcLevel(&KiProfileLock
);
70 /* Make sure it's not running */
71 if (!Profile
->Started
) {
73 /* Set it as Started */
74 Profile
->Buffer
= Buffer
;
75 Profile
->Started
= TRUE
;
77 /* Get the process, if any */
78 ProfileProcess
= Profile
->Process
;
80 /* Insert it into the Process List or Global List */
83 InsertTailList(&ProfileProcess
->ProfileListHead
, &Profile
->ProfileListEntry
);
87 InsertTailList(&KiProfileListHead
, &Profile
->ProfileListEntry
);
90 /* Check if this type of profile (source) is already running */
91 LIST_FOR_EACH(CurrentSource
, &KiProfileSourceListHead
, KPROFILE_SOURCE_OBJECT
, ListEntry
)
93 /* Check if it's the same as the one being requested now */
94 if (CurrentSource
->Source
== Profile
->Source
) {
99 /* See if the loop found something */
100 if (!CurrentSource
) {
102 /* Nothing found, use our allocated buffer */
103 CurrentSource
= SourceBuffer
;
105 /* Set up the Source Object */
106 CurrentSource
->Source
= Profile
->Source
;
107 InsertHeadList(&KiProfileSourceListHead
, &CurrentSource
->ListEntry
);
109 /* Don't free the pool later on */
115 KeReleaseSpinLockFromDpcLevel(&KiProfileLock
);
116 KeLowerIrql(OldIrql
);
118 /* FIXME: Tell HAL to Start the Profile Interrupt */
119 //HalStartProfileInterrupt(Profile->Source);
122 if (!FreeBuffer
) ExFreePool(SourceBuffer
);
127 KeStopProfile(PKPROFILE Profile
)
130 PKPROFILE_SOURCE_OBJECT CurrentSource
= NULL
;
132 /* Raise to PROFILE_LEVEL and acquire spinlock */
133 KeRaiseIrql(PROFILE_LEVEL
, &OldIrql
);
134 KeAcquireSpinLockAtDpcLevel(&KiProfileLock
);
136 /* Make sure it's running */
137 if (Profile
->Started
) {
139 /* Remove it from the list and disable */
140 RemoveEntryList(&Profile
->ProfileListEntry
);
141 Profile
->Started
= FALSE
;
143 /* Find the Source Object */
144 LIST_FOR_EACH(CurrentSource
, &KiProfileSourceListHead
, KPROFILE_SOURCE_OBJECT
, ListEntry
)
146 if (CurrentSource
->Source
== Profile
->Source
) {
148 RemoveEntryList(&CurrentSource
->ListEntry
);
156 KeReleaseSpinLockFromDpcLevel(&KiProfileLock
);
157 KeLowerIrql(OldIrql
);
159 /* Stop Profiling. FIXME: Implement in HAL */
160 //HalStopProfileInterrupt(Profile->Source);
162 /* Free the Source Object */
163 if (CurrentSource
) ExFreePool(CurrentSource
);
168 KeQueryIntervalProfile(KPROFILE_SOURCE ProfileSource
)
170 /* Check if this is the timer profile */
171 if (ProfileSource
== ProfileTime
) {
173 /* Return the good old 100ns sampling interval */
174 return KiProfileTimeInterval
;
178 /* Request it from HAL. FIXME: What structure is used? */
179 HalQuerySystemInformation(HalProfileSourceInformation
,
190 KeSetIntervalProfile(KPROFILE_SOURCE ProfileSource
,
193 /* Check if this is the timer profile */
194 if (ProfileSource
== ProfileTime
) {
196 /* Set the good old 100ns sampling interval */
197 KiProfileTimeInterval
= Interval
;
201 /* Set it with HAL. FIXME: What structure is used? */
202 HalSetSystemInformation(HalProfileSourceInformation
,
214 KeProfileInterrupt(PKTRAP_FRAME TrapFrame
)
216 /* Called from HAL for Timer Profiling */
217 KeProfileInterruptWithSource(TrapFrame
, ProfileTime
);
222 KiParseProfileList(IN PKTRAP_FRAME TrapFrame
,
223 IN KPROFILE_SOURCE Source
,
224 IN PLIST_ENTRY ListHead
)
230 LIST_FOR_EACH(Profile
, ListHead
, KPROFILE
, ProfileListEntry
)
232 /* Check if the source is good, and if it's within the range */
233 if ((Profile
->Source
!= Source
) ||
234 (TrapFrame
->Eip
< (ULONG_PTR
)Profile
->RangeBase
) ||
235 (TrapFrame
->Eip
> (ULONG_PTR
)Profile
->RangeLimit
)) {
240 /* Get the Pointer to the Bucket Value representing this EIP */
241 BucketValue
= (PULONG
)((((ULONG_PTR
)Profile
->Buffer
+
242 (TrapFrame
->Eip
- (ULONG_PTR
)Profile
->RangeBase
))
243 >> Profile
->BucketShift
) &~ 0x3);
245 /* Increment the value */
254 * Called from HAL, this function looks up the process
255 * entries, finds the proper source object, verifies the
256 * ranges with the trapframe data, and inserts the information
257 * from the trap frame into the buffer, while using buckets and
258 * shifting like we specified. -- Alex
262 KeProfileInterruptWithSource(IN PKTRAP_FRAME TrapFrame
,
263 IN KPROFILE_SOURCE Source
)
265 PKPROCESS Process
= KeGetCurrentThread()->ApcState
.Process
;
267 /* We have to parse 2 lists. Per-Process and System-Wide */
268 KiParseProfileList(TrapFrame
, Source
, &Process
->ProfileListHead
);
269 KiParseProfileList(TrapFrame
, Source
, &KiProfileListHead
);
277 KeSetProfileIrql(IN KIRQL ProfileIrql
)
279 /* Set the IRQL at which Profiling will run */
280 KiProfileIrql
= ProfileIrql
;