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
),
64 TAG('P', 'r', 'o', 'f'));
65 RtlZeroMemory(SourceBuffer
, sizeof(KPROFILE_SOURCE_OBJECT
));
67 /* Raise to PROFILE_LEVEL */
68 KeRaiseIrql(PROFILE_LEVEL
, &OldIrql
);
69 KeAcquireSpinLockAtDpcLevel(&KiProfileLock
);
71 /* Make sure it's not running */
72 if (!Profile
->Started
)
74 /* Set it as Started */
75 Profile
->Buffer
= Buffer
;
76 Profile
->Started
= TRUE
;
78 /* Get the process, if any */
79 ProfileProcess
= Profile
->Process
;
81 /* Check where we should insert it */
84 /* Insert it into the Process List */
85 InsertTailList(&ProfileProcess
->ProfileListHead
, &Profile
->ProfileListEntry
);
89 /* Insert it into the Global List */
90 InsertTailList(&KiProfileListHead
, &Profile
->ProfileListEntry
);
94 for (NextEntry
= KiProfileSourceListHead
.Flink
;
95 NextEntry
!= &KiProfileSourceListHead
;
96 NextEntry
= NextEntry
->Flink
)
99 CurrentSource
= CONTAINING_RECORD(NextEntry
,
100 KPROFILE_SOURCE_OBJECT
,
103 /* Check if it's the same as the one being requested now */
104 if (CurrentSource
->Source
== Profile
->Source
)
106 /* It is, break out */
112 /* See if the loop found something */
115 /* Nothing found, use our allocated buffer */
116 CurrentSource
= SourceBuffer
;
118 /* Set up the Source Object */
119 CurrentSource
->Source
= Profile
->Source
;
120 InsertHeadList(&KiProfileSourceListHead
, &CurrentSource
->ListEntry
);
122 /* Don't free the pool later on */
128 KeReleaseSpinLockFromDpcLevel(&KiProfileLock
);
129 KeLowerIrql(OldIrql
);
131 /* FIXME: Tell HAL to Start the Profile Interrupt */
132 //HalStartProfileInterrupt(Profile->Source);
135 if (FreeBuffer
) ExFreePool(SourceBuffer
);
140 KeStopProfile(PKPROFILE Profile
)
143 PKPROFILE_SOURCE_OBJECT CurrentSource
= NULL
;
144 PLIST_ENTRY NextEntry
;
145 BOOLEAN SourceFound
= FALSE
;
147 /* Raise to PROFILE_LEVEL and acquire spinlock */
148 KeRaiseIrql(PROFILE_LEVEL
, &OldIrql
);
149 KeAcquireSpinLockAtDpcLevel(&KiProfileLock
);
151 /* Make sure it's running */
152 if (Profile
->Started
)
154 /* Remove it from the list and disable */
155 RemoveEntryList(&Profile
->ProfileListEntry
);
156 Profile
->Started
= FALSE
;
159 for (NextEntry
= KiProfileSourceListHead
.Flink
;
160 NextEntry
!= &KiProfileSourceListHead
;
161 NextEntry
= NextEntry
->Flink
)
164 CurrentSource
= CONTAINING_RECORD(NextEntry
,
165 KPROFILE_SOURCE_OBJECT
,
168 /* Check if this is the Source Object */
169 if (CurrentSource
->Source
== Profile
->Source
)
171 /* Remember we found one */
174 /* Remove it and break out */
175 RemoveEntryList(&CurrentSource
->ListEntry
);
183 KeReleaseSpinLockFromDpcLevel(&KiProfileLock
);
184 KeLowerIrql(OldIrql
);
186 /* Stop Profiling. FIXME: Implement in HAL */
187 //HalStopProfileInterrupt(Profile->Source);
189 /* Free the Source Object */
190 if (SourceFound
) ExFreePool(CurrentSource
);
198 KeQueryIntervalProfile(KPROFILE_SOURCE ProfileSource
)
200 /* Check if this is the timer profile */
201 if (ProfileSource
== ProfileTime
)
203 /* Return the good old 100ns sampling interval */
204 return KiProfileTimeInterval
;
208 /* Request it from HAL. FIXME: What structure is used? */
209 HalQuerySystemInformation(HalProfileSourceInformation
,
220 KeSetIntervalProfile(KPROFILE_SOURCE ProfileSource
,
223 /* Check if this is the timer profile */
224 if (ProfileSource
== ProfileTime
)
226 /* Set the good old 100ns sampling interval */
227 KiProfileTimeInterval
= Interval
;
231 /* Set it with HAL. FIXME: What structure is used? */
232 HalSetSystemInformation(HalProfileSourceInformation
,
243 KeProfileInterrupt(PKTRAP_FRAME TrapFrame
)
245 /* Called from HAL for Timer Profiling */
246 KeProfileInterruptWithSource(TrapFrame
, ProfileTime
);
251 KiParseProfileList(IN PKTRAP_FRAME TrapFrame
,
252 IN KPROFILE_SOURCE Source
,
253 IN PLIST_ENTRY ListHead
)
257 PLIST_ENTRY NextEntry
;
260 for (NextEntry
= ListHead
->Flink
;
261 NextEntry
!= ListHead
;
262 NextEntry
= NextEntry
->Flink
)
265 Profile
= CONTAINING_RECORD(NextEntry
, KPROFILE
, ProfileListEntry
);
267 /* Check if the source is good, and if it's within the range */
269 if ((Profile
->Source
!= Source
) ||
270 (TrapFrame
->Eip
< (ULONG_PTR
)Profile
->RangeBase
) ||
271 (TrapFrame
->Eip
> (ULONG_PTR
)Profile
->RangeLimit
))
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)
284 /* Increment the value */
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
301 KeProfileInterruptWithSource(IN PKTRAP_FRAME TrapFrame
,
302 IN KPROFILE_SOURCE Source
)
304 PKPROCESS Process
= KeGetCurrentThread()->ApcState
.Process
;
306 /* We have to parse 2 lists. Per-Process and System-Wide */
307 KiParseProfileList(TrapFrame
, Source
, &Process
->ProfileListHead
);
308 KiParseProfileList(TrapFrame
, Source
, &KiProfileListHead
);
316 KeSetProfileIrql(IN KIRQL ProfileIrql
)
318 /* Set the IRQL at which Profiling will run */
319 KiProfileIrql
= ProfileIrql
;