ReactOS  0.4.14-dev-52-g6116262
profobj.c
Go to the documentation of this file.
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 
21 ULONG KiProfileTimeInterval = 78125; /* Default resolution 7.8ms (sysinternals) */
23 
24 /* FUNCTIONS *****************************************************************/
25 
26 VOID
27 NTAPI
30  PVOID ImageBase,
31  SIZE_T ImageSize,
32  ULONG BucketSize,
33  KPROFILE_SOURCE ProfileSource,
35 {
36  /* Initialize the Header */
37  Profile->Type = ProfileObject;
38  Profile->Size = sizeof(KPROFILE);
39 
40  /* Copy all the settings we were given */
41  Profile->Process = Process;
42  Profile->RangeBase = ImageBase;
43  Profile->BucketShift = BucketSize - 2; /* See ntinternals.net -- Alex */
44  Profile->RangeLimit = (PVOID)((ULONG_PTR)ImageBase + ImageSize);
45  Profile->Started = FALSE;
46  Profile->Source = ProfileSource;
47  Profile->Affinity = Affinity;
48 }
49 
50 BOOLEAN
51 NTAPI
53  IN PVOID Buffer)
54 {
55  KIRQL OldIrql;
56  PKPROFILE_SOURCE_OBJECT SourceBuffer;
57  PKPROFILE_SOURCE_OBJECT CurrentSource;
58  BOOLEAN FreeBuffer = TRUE, SourceFound = FALSE, StartedProfile;
59  PKPROCESS ProfileProcess;
60  PLIST_ENTRY NextEntry;
61 
62  /* Allocate a buffer first, before we raise IRQL */
63  SourceBuffer = ExAllocatePoolWithTag(NonPagedPool,
64  sizeof(KPROFILE_SOURCE_OBJECT),
65  'forP');
66  if (!SourceBuffer) return FALSE;
67  RtlZeroMemory(SourceBuffer, sizeof(KPROFILE_SOURCE_OBJECT));
68 
69  /* Raise to profile IRQL and acquire the profile lock */
72 
73  /* Make sure it's not running */
74  if (!Profile->Started)
75  {
76  /* Set it as Started */
77  Profile->Buffer = Buffer;
78  Profile->Started = TRUE;
79  StartedProfile = TRUE;
80 
81  /* Get the process, if any */
82  ProfileProcess = Profile->Process;
83 
84  /* Check where we should insert it */
85  if (ProfileProcess)
86  {
87  /* Insert it into the Process List */
88  InsertTailList(&ProfileProcess->ProfileListHead, &Profile->ProfileListEntry);
89  }
90  else
91  {
92  /* Insert it into the Global List */
93  InsertTailList(&KiProfileListHead, &Profile->ProfileListEntry);
94  }
95 
96  /* Start looping */
97  for (NextEntry = KiProfileSourceListHead.Flink;
98  NextEntry != &KiProfileSourceListHead;
99  NextEntry = NextEntry->Flink)
100  {
101  /* Get the entry */
102  CurrentSource = CONTAINING_RECORD(NextEntry,
104  ListEntry);
105 
106  /* Check if it's the same as the one being requested now */
107  if (CurrentSource->Source == Profile->Source)
108  {
109  /* It is, break out */
110  SourceFound = TRUE;
111  break;
112  }
113  }
114 
115  /* See if the loop found something */
116  if (!SourceFound)
117  {
118  /* Nothing found, use our allocated buffer */
119  CurrentSource = SourceBuffer;
120 
121  /* Set up the Source Object */
122  CurrentSource->Source = Profile->Source;
124 
125  /* Don't free the pool later on */
126  FreeBuffer = FALSE;
127  }
128  }
129  else
130  {
131  /* Already running so nothing to start */
132  StartedProfile = FALSE;
133  }
134 
135  /* Release the profile lock */
137 
138  /* Tell HAL to start the profile interrupt */
139  HalStartProfileInterrupt(Profile->Source);
140 
141  /* Lower back to original IRQL */
143 
144  /* Free the pool */
145  if (FreeBuffer) ExFreePoolWithTag(SourceBuffer, 'forP');
146 
147  /* Return whether we could start the profile */
148  return StartedProfile;
149 }
150 
151 BOOLEAN
152 NTAPI
154 {
155  KIRQL OldIrql;
156  PKPROFILE_SOURCE_OBJECT CurrentSource = NULL;
157  PLIST_ENTRY NextEntry;
158  BOOLEAN SourceFound = FALSE, StoppedProfile;
159 
160  /* Raise to profile IRQL and acquire the profile lock */
163 
164  /* Make sure it's running */
165  if (Profile->Started)
166  {
167  /* Remove it from the list and disable */
168  RemoveEntryList(&Profile->ProfileListEntry);
169  Profile->Started = FALSE;
170  StoppedProfile = TRUE;
171 
172  /* Start looping */
173  for (NextEntry = KiProfileSourceListHead.Flink;
174  NextEntry != &KiProfileSourceListHead;
175  NextEntry = NextEntry->Flink)
176  {
177  /* Get the entry */
178  CurrentSource = CONTAINING_RECORD(NextEntry,
180  ListEntry);
181 
182  /* Check if this is the Source Object */
183  if (CurrentSource->Source == Profile->Source)
184  {
185  /* Remember we found one */
186  SourceFound = TRUE;
187 
188  /* Remove it and break out */
189  RemoveEntryList(&CurrentSource->ListEntry);
190  break;
191  }
192  }
193 
194  }
195  else
196  {
197  /* It wasn't! */
198  StoppedProfile = FALSE;
199  }
200 
201  /* Release the profile lock */
203 
204  /* Stop the profile interrupt */
205  HalStopProfileInterrupt(Profile->Source);
206 
207  /* Lower back to original IRQL */
209 
210  /* Free the Source Object */
211  if (SourceFound) ExFreePool(CurrentSource);
212 
213  /* Return whether we could stop the profile */
214  return StoppedProfile;
215 }
216 
217 ULONG
218 NTAPI
220 {
221  HAL_PROFILE_SOURCE_INFORMATION ProfileSourceInformation;
224 
225  /* Check what profile this is */
226  if (ProfileSource == ProfileTime)
227  {
228  /* Return the time interval */
230  }
231  else if (ProfileSource == ProfileAlignmentFixup)
232  {
233  /* Return the alignment interval */
235  }
236  else
237  {
238  /* Request it from HAL */
239  ProfileSourceInformation.Source = ProfileSource;
242  &ProfileSourceInformation,
243  &ReturnLength);
244 
245  /* Check if HAL handled it and supports this profile */
246  if (NT_SUCCESS(Status) && (ProfileSourceInformation.Supported))
247  {
248  /* Get the interval */
249  Interval = ProfileSourceInformation.Interval;
250  }
251  else
252  {
253  /* Unsupported or invalid source, fail */
254  Interval = 0;
255  }
256  }
257 
258  /* Return the interval we got */
259  return Interval;
260 }
261 
262 VOID
263 NTAPI
265  IN KPROFILE_SOURCE ProfileSource)
266 {
267  HAL_PROFILE_SOURCE_INTERVAL ProfileSourceInterval;
268 
269  /* Check what profile this is */
270  if (ProfileSource == ProfileTime)
271  {
272  /* Set the interval through HAL */
274  }
275  else if (ProfileSource == ProfileAlignmentFixup)
276  {
277  /* Set the alignment interval */
279  }
280  else
281  {
282  /* HAL handles any other interval */
283  ProfileSourceInterval.Source = ProfileSource;
284  ProfileSourceInterval.Interval = Interval;
287  &ProfileSourceInterval);
288  }
289 }
290 
291 /*
292  * @implemented
293  */
294 VOID
295 NTAPI
297 {
298  /* Called from HAL for Timer Profiling */
300 }
301 
302 VOID
303 NTAPI
306  IN PLIST_ENTRY ListHead)
307 {
308  PULONG BucketValue;
309  PKPROFILE Profile;
310  PLIST_ENTRY NextEntry;
311  ULONG_PTR ProgramCounter;
312 
313  /* Get the Program Counter */
314  ProgramCounter = KeGetTrapFramePc(TrapFrame);
315 
316  /* Loop the List */
317  for (NextEntry = ListHead->Flink;
318  NextEntry != ListHead;
319  NextEntry = NextEntry->Flink)
320  {
321  /* Get the entry */
322  Profile = CONTAINING_RECORD(NextEntry, KPROFILE, ProfileListEntry);
323 
324  /* Check if the source is good, and if it's within the range */
325  if ((Profile->Source != Source) ||
326  (ProgramCounter < (ULONG_PTR)Profile->RangeBase) ||
327  (ProgramCounter > (ULONG_PTR)Profile->RangeLimit))
328  {
329  continue;
330  }
331 
332  /* Get the Pointer to the Bucket Value representing this Program Counter */
333  BucketValue = (PULONG)((ULONG_PTR)Profile->Buffer +
334  (((ProgramCounter - (ULONG_PTR)Profile->RangeBase)
335  >> Profile->BucketShift) &~ 0x3));
336 
337  /* Increment the value */
338  (*BucketValue)++;
339  }
340 }
341 
342 /*
343  * @implemented
344  *
345  * Remarks:
346  * Called from HAL, this function looks up the process
347  * entries, finds the proper source object, verifies the
348  * ranges with the trapframe data, and inserts the information
349  * from the trap frame into the buffer, while using buckets and
350  * shifting like we specified. -- Alex
351  */
352 VOID
353 NTAPI
356 {
357  PKPROCESS Process = KeGetCurrentThread()->ApcState.Process;
358 
359  /* We have to parse 2 lists. Per-Process and System-Wide */
360  KiParseProfileList(TrapFrame, Source, &Process->ProfileListHead);
362 }
363 
364 /*
365  * @implemented
366  */
367 VOID
368 NTAPI
370 {
371  /* Set the IRQL at which Profiling will run */
372  KiProfileIrql = ProfileIrql;
373 }
BOOLEAN Started
Definition: ketypes.h:817
CSHORT Type
Definition: ketypes.h:806
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
PVOID Buffer
Definition: ketypes.h:813
#define IN
Definition: typedefs.h:38
ULONG_PTR NTAPI HalSetProfileInterval(IN ULONG_PTR Interval)
Definition: profil.c:44
enum _KPROFILE_SOURCE KPROFILE_SOURCE
KAFFINITY Affinity
Definition: ketypes.h:815
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define TRUE
Definition: types.h:120
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
PVOID RangeBase
Definition: ketypes.h:810
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:192
LONG NTSTATUS
Definition: precomp.h:26
VOID NTAPI HalStartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource)
Definition: profil.c:33
KIRQL KiProfileIrql
Definition: profobj.c:17
VOID NTAPI KeProfileInterrupt(IN PKTRAP_FRAME TrapFrame)
Definition: profobj.c:296
#define HalQuerySystemInformation
Definition: haltypes.h:283
#define InsertTailList(ListHead, Entry)
#define HalSetSystemInformation
Definition: haltypes.h:284
uint32_t ULONG_PTR
Definition: typedefs.h:63
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
UCHAR KIRQL
Definition: env_spec_w32.h:591
struct _KPROCESS * Process
Definition: ketypes.h:809
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
KPROFILE_SOURCE Source
Definition: ketypes.h:816
KPROFILE_SOURCE Source
Definition: ke.h:16
unsigned char BOOLEAN
PVOID RangeLimit
Definition: ketypes.h:811
smooth NULL
Definition: ftsmooth.c:416
KSPIN_LOCK KiProfileLock
Definition: profobj.c:20
ULONG KiProfileTimeInterval
Definition: profobj.c:21
BOOLEAN NTAPI KeStartProfile(IN PKPROFILE Profile, IN PVOID Buffer)
Definition: profobj.c:52
Definition: bufpool.h:45
void * PVOID
Definition: retypes.h:9
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
LIST_ENTRY ListEntry
Definition: ke.h:17
DWORD Interval
Definition: netstat.c:33
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
BOOLEAN NTAPI KeStopProfile(IN PKPROFILE Profile)
Definition: profobj.c:153
LIST_ENTRY KiProfileListHead
Definition: profobj.c:18
VOID NTAPI KeInitializeProfile(PKPROFILE Profile, PKPROCESS Process, PVOID ImageBase, SIZE_T ImageSize, ULONG BucketSize, KPROFILE_SOURCE ProfileSource, KAFFINITY Affinity)
Definition: profobj.c:28
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:215
_In_ ULONG _In_ ULONG _In_ ULONG _Out_ PKIRQL _Out_ PKAFFINITY Affinity
Definition: halfuncs.h:170
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
CSHORT Size
Definition: ketypes.h:807
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
KPROFILE_SOURCE Source
Definition: haltypes.h:328
#define KeGetTrapFramePc(TrapFrame)
Definition: ke.h:130
Definition: typedefs.h:117
Status
Definition: gdiplustypes.h:24
ULONG_PTR SIZE_T
Definition: typedefs.h:78
ULONG KiProfileAlignmentFixupInterval
Definition: profobj.c:22
VOID NTAPI KeSetIntervalProfile(IN ULONG Interval, IN KPROFILE_SOURCE ProfileSource)
Definition: profobj.c:264
#define PROFILE_LEVEL
Definition: env_spec_w32.h:698
ULONG_PTR KAFFINITY
Definition: compat.h:75
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
LIST_ENTRY ProfileListHead
Definition: ketypes.h:1975
unsigned int * PULONG
Definition: retypes.h:1
ULONG BucketShift
Definition: ketypes.h:812
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
ULONG NTAPI KeQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource)
Definition: profobj.c:219
unsigned int ULONG
Definition: retypes.h:1
VOID NTAPI KeProfileInterruptWithSource(IN PKTRAP_FRAME TrapFrame, IN KPROFILE_SOURCE Source)
Definition: profobj.c:354
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ULONG_PTR
Definition: config.h:101
VOID NTAPI KiParseProfileList(IN PKTRAP_FRAME TrapFrame, IN KPROFILE_SOURCE Source, IN PLIST_ENTRY ListHead)
Definition: profobj.c:304
VOID NTAPI HalStopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource)
Definition: profil.c:22
_In_ UINT _In_ UINT _In_ PNDIS_PACKET Source
Definition: ndis.h:3167
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define KeGetCurrentThread
Definition: hal.h:44
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
LIST_ENTRY KiProfileSourceListHead
Definition: profobj.c:19
struct _KPROFILE KPROFILE
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
VOID NTAPI KeSetProfileIrql(IN KIRQL ProfileIrql)
Definition: profobj.c:369