Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenprofobj.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: GPL - See COPYING in the top level directory 00003 * PROJECT: ReactOS Kernel 00004 * FILE: ntoskrnl/ke/profobj.c 00005 * PURPOSE: Kernel Profiling 00006 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 00007 */ 00008 00009 /* INCLUDES *****************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* GLOBALS *******************************************************************/ 00016 00017 KIRQL KiProfileIrql = PROFILE_LEVEL; 00018 LIST_ENTRY KiProfileListHead; 00019 LIST_ENTRY KiProfileSourceListHead; 00020 KSPIN_LOCK KiProfileLock; 00021 ULONG KiProfileTimeInterval = 78125; /* Default resolution 7.8ms (sysinternals) */ 00022 ULONG KiProfileAlignmentFixupInterval; 00023 00024 /* FUNCTIONS *****************************************************************/ 00025 00026 VOID 00027 NTAPI 00028 KeInitializeProfile(PKPROFILE Profile, 00029 PKPROCESS Process, 00030 PVOID ImageBase, 00031 SIZE_T ImageSize, 00032 ULONG BucketSize, 00033 KPROFILE_SOURCE ProfileSource, 00034 KAFFINITY Affinity) 00035 { 00036 /* Initialize the Header */ 00037 Profile->Type = ProfileObject; 00038 Profile->Size = sizeof(KPROFILE); 00039 00040 /* Copy all the settings we were given */ 00041 Profile->Process = Process; 00042 Profile->RangeBase = ImageBase; 00043 Profile->BucketShift = BucketSize - 2; /* See ntinternals.net -- Alex */ 00044 Profile->RangeLimit = (PVOID)((ULONG_PTR)ImageBase + ImageSize); 00045 Profile->Started = FALSE; 00046 Profile->Source = ProfileSource; 00047 Profile->Affinity = Affinity; 00048 } 00049 00050 BOOLEAN 00051 NTAPI 00052 KeStartProfile(IN PKPROFILE Profile, 00053 IN PVOID Buffer) 00054 { 00055 KIRQL OldIrql; 00056 PKPROFILE_SOURCE_OBJECT SourceBuffer; 00057 PKPROFILE_SOURCE_OBJECT CurrentSource; 00058 BOOLEAN FreeBuffer = TRUE, SourceFound = FALSE, StartedProfile; 00059 PKPROCESS ProfileProcess; 00060 PLIST_ENTRY NextEntry; 00061 00062 /* Allocate a buffer first, before we raise IRQL */ 00063 SourceBuffer = ExAllocatePoolWithTag(NonPagedPool, 00064 sizeof(KPROFILE_SOURCE_OBJECT), 00065 'forP'); 00066 if (!SourceBuffer) return FALSE; 00067 RtlZeroMemory(SourceBuffer, sizeof(KPROFILE_SOURCE_OBJECT)); 00068 00069 /* Raise to profile IRQL and acquire the profile lock */ 00070 KeRaiseIrql(KiProfileIrql, &OldIrql); 00071 KeAcquireSpinLockAtDpcLevel(&KiProfileLock); 00072 00073 /* Make sure it's not running */ 00074 if (!Profile->Started) 00075 { 00076 /* Set it as Started */ 00077 Profile->Buffer = Buffer; 00078 Profile->Started = TRUE; 00079 StartedProfile = TRUE; 00080 00081 /* Get the process, if any */ 00082 ProfileProcess = Profile->Process; 00083 00084 /* Check where we should insert it */ 00085 if (ProfileProcess) 00086 { 00087 /* Insert it into the Process List */ 00088 InsertTailList(&ProfileProcess->ProfileListHead, &Profile->ProfileListEntry); 00089 } 00090 else 00091 { 00092 /* Insert it into the Global List */ 00093 InsertTailList(&KiProfileListHead, &Profile->ProfileListEntry); 00094 } 00095 00096 /* Start looping */ 00097 for (NextEntry = KiProfileSourceListHead.Flink; 00098 NextEntry != &KiProfileSourceListHead; 00099 NextEntry = NextEntry->Flink) 00100 { 00101 /* Get the entry */ 00102 CurrentSource = CONTAINING_RECORD(NextEntry, 00103 KPROFILE_SOURCE_OBJECT, 00104 ListEntry); 00105 00106 /* Check if it's the same as the one being requested now */ 00107 if (CurrentSource->Source == Profile->Source) 00108 { 00109 /* It is, break out */ 00110 SourceFound = TRUE; 00111 break; 00112 } 00113 } 00114 00115 /* See if the loop found something */ 00116 if (!SourceFound) 00117 { 00118 /* Nothing found, use our allocated buffer */ 00119 CurrentSource = SourceBuffer; 00120 00121 /* Set up the Source Object */ 00122 CurrentSource->Source = Profile->Source; 00123 InsertHeadList(&KiProfileSourceListHead, &CurrentSource->ListEntry); 00124 00125 /* Don't free the pool later on */ 00126 FreeBuffer = FALSE; 00127 } 00128 } 00129 else 00130 { 00131 /* Already running so nothing to start */ 00132 StartedProfile = FALSE; 00133 } 00134 00135 /* Release the profile lock */ 00136 KeReleaseSpinLockFromDpcLevel(&KiProfileLock); 00137 00138 /* Tell HAL to start the profile interrupt */ 00139 HalStartProfileInterrupt(Profile->Source); 00140 00141 /* Lower back to original IRQL */ 00142 KeLowerIrql(OldIrql); 00143 00144 /* Free the pool */ 00145 if (FreeBuffer) ExFreePool(SourceBuffer); 00146 00147 /* Return whether we could start the profile */ 00148 return StartedProfile; 00149 } 00150 00151 BOOLEAN 00152 NTAPI 00153 KeStopProfile(IN PKPROFILE Profile) 00154 { 00155 KIRQL OldIrql; 00156 PKPROFILE_SOURCE_OBJECT CurrentSource = NULL; 00157 PLIST_ENTRY NextEntry; 00158 BOOLEAN SourceFound = FALSE, StoppedProfile; 00159 00160 /* Raise to profile IRQL and acquire the profile lock */ 00161 KeRaiseIrql(KiProfileIrql, &OldIrql); 00162 KeAcquireSpinLockAtDpcLevel(&KiProfileLock); 00163 00164 /* Make sure it's running */ 00165 if (Profile->Started) 00166 { 00167 /* Remove it from the list and disable */ 00168 RemoveEntryList(&Profile->ProfileListEntry); 00169 Profile->Started = FALSE; 00170 StoppedProfile = TRUE; 00171 00172 /* Start looping */ 00173 for (NextEntry = KiProfileSourceListHead.Flink; 00174 NextEntry != &KiProfileSourceListHead; 00175 NextEntry = NextEntry->Flink) 00176 { 00177 /* Get the entry */ 00178 CurrentSource = CONTAINING_RECORD(NextEntry, 00179 KPROFILE_SOURCE_OBJECT, 00180 ListEntry); 00181 00182 /* Check if this is the Source Object */ 00183 if (CurrentSource->Source == Profile->Source) 00184 { 00185 /* Remember we found one */ 00186 SourceFound = TRUE; 00187 00188 /* Remove it and break out */ 00189 RemoveEntryList(&CurrentSource->ListEntry); 00190 break; 00191 } 00192 } 00193 00194 } 00195 else 00196 { 00197 /* It wasn't! */ 00198 StoppedProfile = FALSE; 00199 } 00200 00201 /* Release the profile lock */ 00202 KeReleaseSpinLockFromDpcLevel(&KiProfileLock); 00203 00204 /* Stop the profile interrupt */ 00205 HalStopProfileInterrupt(Profile->Source); 00206 00207 /* Lower back to original IRQL */ 00208 KeLowerIrql(OldIrql); 00209 00210 /* Free the Source Object */ 00211 if (SourceFound) ExFreePool(CurrentSource); 00212 00213 /* Return whether we could stop the profile */ 00214 return StoppedProfile; 00215 } 00216 00217 ULONG 00218 NTAPI 00219 KeQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource) 00220 { 00221 HAL_PROFILE_SOURCE_INFORMATION ProfileSourceInformation; 00222 ULONG ReturnLength, Interval; 00223 NTSTATUS Status; 00224 00225 /* Check what profile this is */ 00226 if (ProfileSource == ProfileTime) 00227 { 00228 /* Return the time interval */ 00229 Interval = KiProfileTimeInterval; 00230 } 00231 else if (ProfileSource == ProfileAlignmentFixup) 00232 { 00233 /* Return the alignment interval */ 00234 Interval = KiProfileAlignmentFixupInterval; 00235 } 00236 else 00237 { 00238 /* Request it from HAL */ 00239 ProfileSourceInformation.Source = ProfileSource; 00240 Status = HalQuerySystemInformation(HalProfileSourceInformation, 00241 sizeof(HAL_PROFILE_SOURCE_INFORMATION), 00242 &ProfileSourceInformation, 00243 &ReturnLength); 00244 00245 /* Check if HAL handled it and supports this profile */ 00246 if (NT_SUCCESS(Status) && (ProfileSourceInformation.Supported)) 00247 { 00248 /* Get the interval */ 00249 Interval = ProfileSourceInformation.Interval; 00250 } 00251 else 00252 { 00253 /* Unsupported or invalid source, fail */ 00254 Interval = 0; 00255 } 00256 } 00257 00258 /* Return the interval we got */ 00259 return Interval; 00260 } 00261 00262 VOID 00263 NTAPI 00264 KeSetIntervalProfile(IN KPROFILE_SOURCE ProfileSource, 00265 IN ULONG Interval) 00266 { 00267 HAL_PROFILE_SOURCE_INTERVAL ProfileSourceInterval; 00268 00269 /* Check what profile this is */ 00270 if (ProfileSource == ProfileTime) 00271 { 00272 /* Set the interval through HAL */ 00273 KiProfileTimeInterval = (ULONG)HalSetProfileInterval(Interval); 00274 } 00275 else if (ProfileSource == ProfileAlignmentFixup) 00276 { 00277 /* Set the alignment interval */ 00278 KiProfileAlignmentFixupInterval = Interval; 00279 } 00280 else 00281 { 00282 /* HAL handles any other interval */ 00283 ProfileSourceInterval.Source = ProfileSource; 00284 ProfileSourceInterval.Interval = Interval; 00285 HalSetSystemInformation(HalProfileSourceInterval, 00286 sizeof(HAL_PROFILE_SOURCE_INTERVAL), 00287 &ProfileSourceInterval); 00288 } 00289 } 00290 00291 /* 00292 * @implemented 00293 */ 00294 VOID 00295 NTAPI 00296 KeProfileInterrupt(IN PKTRAP_FRAME TrapFrame) 00297 { 00298 /* Called from HAL for Timer Profiling */ 00299 KeProfileInterruptWithSource(TrapFrame, ProfileTime); 00300 } 00301 00302 VOID 00303 NTAPI 00304 KiParseProfileList(IN PKTRAP_FRAME TrapFrame, 00305 IN KPROFILE_SOURCE Source, 00306 IN PLIST_ENTRY ListHead) 00307 { 00308 PULONG BucketValue; 00309 PKPROFILE Profile; 00310 PLIST_ENTRY NextEntry; 00311 ULONG_PTR ProgramCounter; 00312 00313 /* Get the Program Counter */ 00314 ProgramCounter = KeGetTrapFramePc(TrapFrame); 00315 00316 /* Loop the List */ 00317 for (NextEntry = ListHead->Flink; 00318 NextEntry != ListHead; 00319 NextEntry = NextEntry->Flink) 00320 { 00321 /* Get the entry */ 00322 Profile = CONTAINING_RECORD(NextEntry, KPROFILE, ProfileListEntry); 00323 00324 /* Check if the source is good, and if it's within the range */ 00325 if ((Profile->Source != Source) || 00326 (ProgramCounter < (ULONG_PTR)Profile->RangeBase) || 00327 (ProgramCounter > (ULONG_PTR)Profile->RangeLimit)) 00328 { 00329 continue; 00330 } 00331 00332 /* Get the Pointer to the Bucket Value representing this Program Counter */ 00333 BucketValue = (PULONG)((((ULONG_PTR)Profile->Buffer + 00334 (ProgramCounter - (ULONG_PTR)Profile->RangeBase)) 00335 >> Profile->BucketShift) &~ 0x3); 00336 00337 /* Increment the value */ 00338 ++BucketValue; 00339 } 00340 } 00341 00342 /* 00343 * @implemented 00344 * 00345 * Remarks: 00346 * Called from HAL, this function looks up the process 00347 * entries, finds the proper source object, verifies the 00348 * ranges with the trapframe data, and inserts the information 00349 * from the trap frame into the buffer, while using buckets and 00350 * shifting like we specified. -- Alex 00351 */ 00352 VOID 00353 NTAPI 00354 KeProfileInterruptWithSource(IN PKTRAP_FRAME TrapFrame, 00355 IN KPROFILE_SOURCE Source) 00356 { 00357 PKPROCESS Process = KeGetCurrentThread()->ApcState.Process; 00358 00359 /* We have to parse 2 lists. Per-Process and System-Wide */ 00360 KiParseProfileList(TrapFrame, Source, &Process->ProfileListHead); 00361 KiParseProfileList(TrapFrame, Source, &KiProfileListHead); 00362 } 00363 00364 /* 00365 * @implemented 00366 */ 00367 VOID 00368 NTAPI 00369 KeSetProfileIrql(IN KIRQL ProfileIrql) 00370 { 00371 /* Set the IRQL at which Profiling will run */ 00372 KiProfileIrql = ProfileIrql; 00373 } Generated on Sun May 27 2012 04:37:32 for ReactOS by
1.7.6.1
|