844 lines
20 KiB
C
844 lines
20 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
profobj.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the kernel Profile Object. Functions are
|
|||
|
provided to initialize, start, and stop profile objects and to set
|
|||
|
and query the profile interval.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bryan M. Willman (bryanwi) 19-Sep-1990
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ki.h"
|
|||
|
|
|||
|
#pragma alloc_text (PAGE, KeQueryIntervalProfile)
|
|||
|
|
|||
|
//
|
|||
|
// The following assert macro is used to check that an input profile object is
|
|||
|
// really a kprofile and not something else, like deallocated pool.
|
|||
|
//
|
|||
|
|
|||
|
#define ASSERT_PROFILE(E) { \
|
|||
|
ASSERT((E)->Type == ProfileObject); \
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Structure representing an active profile source
|
|||
|
//
|
|||
|
typedef struct _KACTIVE_PROFILE_SOURCE {
|
|||
|
LIST_ENTRY ListEntry;
|
|||
|
KPROFILE_SOURCE Source;
|
|||
|
KAFFINITY Affinity;
|
|||
|
ULONG ProcessorCount[1]; // variable-sized, one per processor
|
|||
|
} KACTIVE_PROFILE_SOURCE, *PKACTIVE_PROFILE_SOURCE;
|
|||
|
|
|||
|
//
|
|||
|
// Prototypes for IPI target functions
|
|||
|
//
|
|||
|
VOID
|
|||
|
KiStartProfileInterrupt (
|
|||
|
IN PKIPI_CONTEXT SignalDone,
|
|||
|
IN PVOID Parameter1,
|
|||
|
IN PVOID Parameter2,
|
|||
|
IN PVOID Parameter3
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
KiStopProfileInterrupt (
|
|||
|
IN PKIPI_CONTEXT SignalDone,
|
|||
|
IN PVOID Parameter1,
|
|||
|
IN PVOID Parameter2,
|
|||
|
IN PVOID Parameter3
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KeInitializeProfile (
|
|||
|
IN PKPROFILE Profile,
|
|||
|
IN PKPROCESS Process OPTIONAL,
|
|||
|
IN PVOID RangeBase,
|
|||
|
IN SIZE_T RangeSize,
|
|||
|
IN ULONG BucketSize,
|
|||
|
IN ULONG Segment,
|
|||
|
IN KPROFILE_SOURCE ProfileSource,
|
|||
|
IN KAFFINITY ProfileAffinity
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function initializes a kernel profile object. The process,
|
|||
|
address range, bucket size, and buffer are set. The profile is
|
|||
|
set to the stopped state.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Profile - Supplies a pointer to control object of type profile.
|
|||
|
|
|||
|
Process - Supplies an optional pointer to a process object that
|
|||
|
describes the address space to profile. If not specified,
|
|||
|
then all address spaces are included in the profile.
|
|||
|
|
|||
|
RangeBase - Supplies the address of the first byte of the address
|
|||
|
range for which profiling information is to be collected.
|
|||
|
|
|||
|
RangeSize - Supplies the size of the address range for which profiling
|
|||
|
information is to be collected. The RangeBase and RangeSize
|
|||
|
parameters are interpreted such that RangeBase <= address <
|
|||
|
RangeBase + RangeSize generates a profile hit.
|
|||
|
|
|||
|
BucketSize - Supplies the log base 2 of the size of a profiling bucket.
|
|||
|
Thus, BucketSize = 2 yields 4-byte buckets, BucketSize = 7 yields
|
|||
|
128-byte buckets.
|
|||
|
|
|||
|
Segment - Supplies the non-Flat code segment to profile. If this
|
|||
|
is zero, then the flat profiling is done. This will only
|
|||
|
be non-zero on an x86 machine.
|
|||
|
|
|||
|
ProfileSource - Supplies the profile interrupt source.
|
|||
|
|
|||
|
ProfileAffinity - Supplies the set of processor to count hits for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
#if !defined(i386)
|
|||
|
|
|||
|
ASSERT(Segment == 0);
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the standard control object header.
|
|||
|
//
|
|||
|
|
|||
|
Profile->Type = ProfileObject;
|
|||
|
Profile->Size = sizeof(KPROFILE);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the process address space, range base, range limit,
|
|||
|
// bucket shift count, and set started FALSE.
|
|||
|
//
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(Process)) {
|
|||
|
Profile->Process = Process;
|
|||
|
|
|||
|
} else {
|
|||
|
Profile->Process = NULL;
|
|||
|
}
|
|||
|
|
|||
|
Profile->RangeBase = RangeBase;
|
|||
|
Profile->RangeLimit = (PUCHAR)RangeBase + RangeSize;
|
|||
|
Profile->BucketShift = BucketSize - 2;
|
|||
|
Profile->Started = FALSE;
|
|||
|
Profile->Segment = Segment;
|
|||
|
Profile->Source = (CSHORT)ProfileSource;
|
|||
|
Profile->Affinity = ProfileAffinity & KeActiveProcessors;
|
|||
|
if (Profile->Affinity == 0) {
|
|||
|
Profile->Affinity = KeActiveProcessors;
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
KeQueryIntervalProfile (
|
|||
|
IN KPROFILE_SOURCE ProfileSource
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function returns the profile sample interval the system is
|
|||
|
currently using.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ProfileSource - Supplies the profile source to be queried.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Sample interval in units of 100ns.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
HAL_PROFILE_SOURCE_INFORMATION ProfileSourceInfo;
|
|||
|
ULONG ReturnedLength;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
#if !defined(_IA64_)
|
|||
|
if (ProfileSource == ProfileTime) {
|
|||
|
|
|||
|
//
|
|||
|
// Return the current sampling interval in 100ns units.
|
|||
|
//
|
|||
|
|
|||
|
return KiProfileInterval;
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
#endif // !_IA64_
|
|||
|
if (ProfileSource == ProfileAlignmentFixup) {
|
|||
|
return KiProfileAlignmentFixupInterval;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The HAL is responsible for tracking this profile interval.
|
|||
|
//
|
|||
|
|
|||
|
ProfileSourceInfo.Source = ProfileSource;
|
|||
|
Status = HalQuerySystemInformation(HalProfileSourceInformation,
|
|||
|
sizeof(HAL_PROFILE_SOURCE_INFORMATION),
|
|||
|
&ProfileSourceInfo,
|
|||
|
&ReturnedLength);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) && ProfileSourceInfo.Supported) {
|
|||
|
return ProfileSourceInfo.Interval;
|
|||
|
|
|||
|
} else {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KeSetIntervalProfile (
|
|||
|
IN ULONG Interval,
|
|||
|
IN KPROFILE_SOURCE Source
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function sets the profile sampling interval. The interval is in
|
|||
|
100ns units. The interval will actually be set to some value in a set
|
|||
|
of preset values (at least on pc based hardware), using the one closest
|
|||
|
to what the user asked for.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Interval - Supplies the length of the sampling interval in 100ns units.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
HAL_PROFILE_SOURCE_INTERVAL ProfileSourceInterval;
|
|||
|
|
|||
|
#if !defined(_IA64_)
|
|||
|
if (Source == ProfileTime) {
|
|||
|
|
|||
|
//
|
|||
|
// If the specified sampling interval is less than the minimum
|
|||
|
// sampling interval, then set the sampling interval to the minimum
|
|||
|
// sampling interval.
|
|||
|
//
|
|||
|
|
|||
|
if (Interval < MINIMUM_PROFILE_INTERVAL) {
|
|||
|
Interval = MINIMUM_PROFILE_INTERVAL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set the sampling interval.
|
|||
|
//
|
|||
|
|
|||
|
KiProfileInterval = (ULONG)KiIpiGenericCall(HalSetProfileInterval, Interval);
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
#endif // !_IA64_
|
|||
|
if (Source == ProfileAlignmentFixup) {
|
|||
|
KiProfileAlignmentFixupInterval = Interval;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The HAL is responsible for setting this profile interval.
|
|||
|
//
|
|||
|
|
|||
|
ProfileSourceInterval.Source = Source;
|
|||
|
ProfileSourceInterval.Interval = Interval;
|
|||
|
HalSetSystemInformation(HalProfileSourceInterval,
|
|||
|
sizeof(HAL_PROFILE_SOURCE_INTERVAL),
|
|||
|
&ProfileSourceInterval);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
KeStartProfile (
|
|||
|
IN PKPROFILE Profile,
|
|||
|
IN PULONG Buffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function starts profile data gathering on the specified profile
|
|||
|
object. The profile object is marked started, and is registered with
|
|||
|
the profile interrupt procedure.
|
|||
|
|
|||
|
If the number of active profile objects was previously zero, then the
|
|||
|
profile interrupt is enabled.
|
|||
|
|
|||
|
N.B. For the current implementation, an arbitrary number of profile
|
|||
|
objects may be active at once. This can present a large system
|
|||
|
overhead. It is assumed that the caller appropriately limits the
|
|||
|
the number of active profiles.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Profile - Supplies a pointer to a control object of type profile.
|
|||
|
|
|||
|
Buffer - Supplies a pointer to an array of counters, which record
|
|||
|
the number of hits in the corresponding bucket.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A value of TRUE is returned if profiling was previously stopped for
|
|||
|
the specified profile object. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KIRQL OldIrql, OldIrql2;
|
|||
|
PKPROCESS Process;
|
|||
|
BOOLEAN Started;
|
|||
|
KAFFINITY TargetProcessors;
|
|||
|
PKPRCB Prcb;
|
|||
|
PKACTIVE_PROFILE_SOURCE ActiveSource = NULL;
|
|||
|
PKACTIVE_PROFILE_SOURCE CurrentActiveSource;
|
|||
|
PKACTIVE_PROFILE_SOURCE AllocatedPool;
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
ULONG SourceSize;
|
|||
|
KAFFINITY AffinitySet;
|
|||
|
PULONG Reference;
|
|||
|
|
|||
|
ASSERT_PROFILE(Profile);
|
|||
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|||
|
|
|||
|
//
|
|||
|
// Allocate pool that may be required before raising to PROFILE_LEVEL.
|
|||
|
//
|
|||
|
|
|||
|
SourceSize = sizeof(KACTIVE_PROFILE_SOURCE) + sizeof(ULONG) *
|
|||
|
(KeNumberProcessors - 1);
|
|||
|
AllocatedPool = ExAllocatePoolWithTag(NonPagedPool, SourceSize, 'forP');
|
|||
|
if (AllocatedPool == NULL) {
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Raise to dispatch level
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
|
|||
|
Prcb = KeGetCurrentPrcb();
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to PROFILE_LEVEL and acquire the profile lock.
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(KiProfileIrql, &OldIrql2);
|
|||
|
KiAcquireSpinLock(&KiProfileLock);
|
|||
|
|
|||
|
//
|
|||
|
// Assume object already started
|
|||
|
//
|
|||
|
|
|||
|
Started = FALSE;
|
|||
|
AffinitySet = 0L;
|
|||
|
TargetProcessors = 0L;
|
|||
|
|
|||
|
//
|
|||
|
// If the specified profile object is not started, set started to TRUE,
|
|||
|
// set the address of the profile buffer, set the profile object to started,
|
|||
|
// insert the profile object in the appropriate profile list, and start
|
|||
|
// profile interrupts if the number of active profile objects was previously zero.
|
|||
|
//
|
|||
|
|
|||
|
if (Profile->Started == FALSE) {
|
|||
|
|
|||
|
Started = TRUE;
|
|||
|
Profile->Buffer = Buffer;
|
|||
|
Profile->Started = TRUE;
|
|||
|
Process = Profile->Process;
|
|||
|
|
|||
|
if (Profile->Buffer) {
|
|||
|
|
|||
|
if (Process != NULL) {
|
|||
|
InsertTailList(&Process->ProfileListHead, &Profile->ProfileListEntry);
|
|||
|
|
|||
|
} else {
|
|||
|
InsertTailList(&KiProfileListHead, &Profile->ProfileListEntry);
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// If we don't have a buffer passed, we'll use only the
|
|||
|
// event profiling
|
|||
|
//
|
|||
|
|
|||
|
InitializeListHead(&Profile->ProfileListEntry);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check the profile source list to see if this profile source is
|
|||
|
// already started. If so, update the reference counts. If not,
|
|||
|
// allocate a profile source object, initialize the reference
|
|||
|
// counts, and add it to the list.
|
|||
|
//
|
|||
|
|
|||
|
ListEntry = KiProfileSourceListHead.Flink;
|
|||
|
while (ListEntry != &KiProfileSourceListHead) {
|
|||
|
CurrentActiveSource = CONTAINING_RECORD(ListEntry,
|
|||
|
KACTIVE_PROFILE_SOURCE,
|
|||
|
ListEntry);
|
|||
|
|
|||
|
if (CurrentActiveSource->Source == Profile->Source) {
|
|||
|
ActiveSource = CurrentActiveSource;
|
|||
|
break;
|
|||
|
}
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
}
|
|||
|
|
|||
|
if (ActiveSource == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// This source was not found, allocate and initialize a new entry and add
|
|||
|
// it to the head of the list.
|
|||
|
//
|
|||
|
|
|||
|
ActiveSource = AllocatedPool;
|
|||
|
AllocatedPool = NULL;
|
|||
|
RtlZeroMemory(ActiveSource, SourceSize);
|
|||
|
ActiveSource->Source = Profile->Source;
|
|||
|
InsertHeadList(&KiProfileSourceListHead, &ActiveSource->ListEntry);
|
|||
|
if (Profile->Source == ProfileAlignmentFixup) {
|
|||
|
KiProfileAlignmentFixup = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Increment the reference counts for each processor in the
|
|||
|
// affinity set.
|
|||
|
//
|
|||
|
|
|||
|
AffinitySet = Profile->Affinity;
|
|||
|
Reference = &ActiveSource->ProcessorCount[0];
|
|||
|
while (AffinitySet != 0) {
|
|||
|
if (AffinitySet & 1) {
|
|||
|
*Reference = *Reference + 1;
|
|||
|
}
|
|||
|
|
|||
|
AffinitySet = AffinitySet >> 1;
|
|||
|
Reference = Reference + 1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Compute the processors which the profile interrupt is
|
|||
|
// required and not already started
|
|||
|
//
|
|||
|
|
|||
|
AffinitySet = Profile->Affinity & ~ActiveSource->Affinity;
|
|||
|
TargetProcessors = AffinitySet & ~Prcb->SetMember;
|
|||
|
|
|||
|
//
|
|||
|
// Update set of processors on which this source is active.
|
|||
|
//
|
|||
|
|
|||
|
ActiveSource->Affinity |= Profile->Affinity;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release the profile lock, lower IRQL to its previous value, and
|
|||
|
// return whether profiling was started.
|
|||
|
//
|
|||
|
|
|||
|
KiReleaseSpinLock(&KiProfileLock);
|
|||
|
KeLowerIrql(OldIrql2);
|
|||
|
|
|||
|
//
|
|||
|
// Start profile interrupt on pending processors
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
if (TargetProcessors != 0) {
|
|||
|
KiIpiSendPacket(TargetProcessors,
|
|||
|
KiStartProfileInterrupt,
|
|||
|
(PVOID)Profile->Source,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
if (AffinitySet & Prcb->SetMember) {
|
|||
|
if (Profile->Source == ProfileAlignmentFixup) {
|
|||
|
KiEnableAlignmentExceptions();
|
|||
|
}
|
|||
|
HalStartProfileInterrupt(Profile->Source);
|
|||
|
}
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
if (TargetProcessors != 0) {
|
|||
|
KiIpiStallOnPacketTargets(TargetProcessors);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Lower to original IRQL
|
|||
|
//
|
|||
|
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// If the allocated pool was not used, free it now.
|
|||
|
//
|
|||
|
|
|||
|
if (AllocatedPool != NULL) {
|
|||
|
ExFreePool(AllocatedPool);
|
|||
|
}
|
|||
|
|
|||
|
return Started;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
KeStopProfile (
|
|||
|
IN PKPROFILE Profile
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function stops profile data gathering on the specified profile
|
|||
|
object. The object is marked stopped, and is removed from the active
|
|||
|
profile list.
|
|||
|
|
|||
|
If the number of active profile objects goes to zero, then the profile
|
|||
|
interrupt is disabled.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Profile - Supplies a pointer to a control object of type profile.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A value of TRUE is returned if profiling was previously started for
|
|||
|
the specified profile object. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KIRQL OldIrql, OldIrql2;
|
|||
|
BOOLEAN Stopped;
|
|||
|
KAFFINITY TargetProcessors;
|
|||
|
PKPRCB Prcb;
|
|||
|
BOOLEAN StopInterrupt = TRUE;
|
|||
|
PLIST_ENTRY ListEntry;
|
|||
|
PKACTIVE_PROFILE_SOURCE ActiveSource;
|
|||
|
PKACTIVE_PROFILE_SOURCE PoolToFree=NULL;
|
|||
|
KAFFINITY AffinitySet = 0;
|
|||
|
KAFFINITY CurrentProcessor;
|
|||
|
PULONG Reference;
|
|||
|
|
|||
|
ASSERT_PROFILE(Profile);
|
|||
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|||
|
|
|||
|
//
|
|||
|
// Raise to disaptch level
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
|
|||
|
Prcb = KeGetCurrentPrcb();
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to PROFILE_LEVEL and acquire the profile lock.
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(KiProfileIrql, &OldIrql2);
|
|||
|
KiAcquireSpinLock(&KiProfileLock);
|
|||
|
|
|||
|
//
|
|||
|
// Assume object already stopped
|
|||
|
//
|
|||
|
|
|||
|
Stopped = FALSE;
|
|||
|
AffinitySet = 0L;
|
|||
|
TargetProcessors = 0L;
|
|||
|
|
|||
|
//
|
|||
|
// If the specified profile object is not stopped, set stopped to TRUE, set
|
|||
|
// the profile object to stopped, remove the profile object object from the
|
|||
|
// appropriate profilelist, and stop profile interrupts if the number of
|
|||
|
// active profile objects is zero.
|
|||
|
//
|
|||
|
|
|||
|
if (Profile->Started != FALSE) {
|
|||
|
|
|||
|
Stopped = TRUE;
|
|||
|
Profile->Started = FALSE;
|
|||
|
|
|||
|
if (!IsListEmpty(&Profile->ProfileListEntry)) {
|
|||
|
|
|||
|
RemoveEntryList(&Profile->ProfileListEntry);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Search the profile source list to find the entry for this
|
|||
|
// profile source.
|
|||
|
//
|
|||
|
|
|||
|
ListEntry = KiProfileSourceListHead.Flink;
|
|||
|
do {
|
|||
|
ASSERT(ListEntry != &KiProfileSourceListHead);
|
|||
|
ActiveSource = CONTAINING_RECORD(ListEntry,
|
|||
|
KACTIVE_PROFILE_SOURCE,
|
|||
|
ListEntry);
|
|||
|
ListEntry = ListEntry->Flink;
|
|||
|
} while ( ActiveSource->Source != Profile->Source );
|
|||
|
|
|||
|
//
|
|||
|
// Decrement the reference counts for each processor in the
|
|||
|
// affinity set and build up a mask of the processors that
|
|||
|
// now have a reference count of zero.
|
|||
|
//
|
|||
|
|
|||
|
CurrentProcessor = 1;
|
|||
|
TargetProcessors = 0;
|
|||
|
AffinitySet = Profile->Affinity;
|
|||
|
Reference = &ActiveSource->ProcessorCount[0];
|
|||
|
while (AffinitySet != 0) {
|
|||
|
if (AffinitySet & 1) {
|
|||
|
*Reference = *Reference - 1;
|
|||
|
if (*Reference == 0) {
|
|||
|
TargetProcessors = TargetProcessors | CurrentProcessor;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
AffinitySet = AffinitySet >> 1;
|
|||
|
Reference = Reference + 1;
|
|||
|
CurrentProcessor = CurrentProcessor << 1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Compute the processors whose profile interrupt reference
|
|||
|
// count has dropped to zero.
|
|||
|
//
|
|||
|
|
|||
|
AffinitySet = TargetProcessors;
|
|||
|
TargetProcessors = AffinitySet & ~Prcb->SetMember;
|
|||
|
|
|||
|
//
|
|||
|
// Update set of processors on which this source is active.
|
|||
|
//
|
|||
|
|
|||
|
ActiveSource->Affinity &= ~AffinitySet;
|
|||
|
|
|||
|
//
|
|||
|
// Determine whether this profile source is stopped on all
|
|||
|
// processors. If so, remove it from the list and free it.
|
|||
|
//
|
|||
|
|
|||
|
if (ActiveSource->Affinity == 0) {
|
|||
|
RemoveEntryList(&ActiveSource->ListEntry);
|
|||
|
PoolToFree = ActiveSource;
|
|||
|
if (Profile->Source == ProfileAlignmentFixup) {
|
|||
|
KiProfileAlignmentFixup = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release the profile lock, lower IRQL to its previous value, and
|
|||
|
// return whether profiling was stopped.
|
|||
|
//
|
|||
|
|
|||
|
KiReleaseSpinLock(&KiProfileLock);
|
|||
|
KeLowerIrql(OldIrql2);
|
|||
|
|
|||
|
//
|
|||
|
// Stop profile interrupt on pending processors
|
|||
|
//
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
if (TargetProcessors != 0) {
|
|||
|
KiIpiSendPacket(TargetProcessors,
|
|||
|
KiStopProfileInterrupt,
|
|||
|
(PVOID)Profile->Source,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
if (AffinitySet & Prcb->SetMember) {
|
|||
|
if (Profile->Source == ProfileAlignmentFixup) {
|
|||
|
KiDisableAlignmentExceptions();
|
|||
|
}
|
|||
|
HalStopProfileInterrupt(Profile->Source);
|
|||
|
}
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
if (TargetProcessors != 0) {
|
|||
|
KiIpiStallOnPacketTargets(TargetProcessors);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Lower to original IRQL
|
|||
|
//
|
|||
|
|
|||
|
KeLowerIrql (OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Now that IRQL has been lowered, free the profile source if
|
|||
|
// necessary.
|
|||
|
//
|
|||
|
|
|||
|
if (PoolToFree != NULL) {
|
|||
|
ExFreePool(PoolToFree);
|
|||
|
}
|
|||
|
|
|||
|
return Stopped;
|
|||
|
}
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
KiStopProfileInterrupt (
|
|||
|
IN PKIPI_CONTEXT SignalDone,
|
|||
|
IN PVOID Parameter1,
|
|||
|
IN PVOID Parameter2,
|
|||
|
IN PVOID Parameter3
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the target function for stopping the profile interrupt on target
|
|||
|
processors.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SignalDone - Supplies a pointer to a variable that is cleared when the
|
|||
|
requested operation has been performed
|
|||
|
|
|||
|
Parameter1 - Supplies the profile source
|
|||
|
|
|||
|
Parameter2 - Parameter3 - not used
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KPROFILE_SOURCE ProfileSource;
|
|||
|
|
|||
|
//
|
|||
|
// Stop the profile interrupt on the current processor and clear the
|
|||
|
// data cache packet address to signal the source to continue.
|
|||
|
//
|
|||
|
|
|||
|
ProfileSource = (KPROFILE_SOURCE) PtrToUlong(Parameter1);
|
|||
|
if (ProfileSource == ProfileAlignmentFixup) {
|
|||
|
KiDisableAlignmentExceptions();
|
|||
|
}
|
|||
|
HalStopProfileInterrupt(ProfileSource);
|
|||
|
KiIpiSignalPacketDone(SignalDone);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
KiStartProfileInterrupt (
|
|||
|
IN PKIPI_CONTEXT SignalDone,
|
|||
|
IN PVOID Parameter1,
|
|||
|
IN PVOID Parameter2,
|
|||
|
IN PVOID Parameter3
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the target function for stopping the profile interrupt on target
|
|||
|
processors.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SignalDone - Supplies a pointer to a variable that is cleared when the
|
|||
|
requested operation has been performed
|
|||
|
|
|||
|
Parameter1 - Supplies the profile source
|
|||
|
|
|||
|
Parameter2 - Parameter3 - not used
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KPROFILE_SOURCE ProfileSource;
|
|||
|
|
|||
|
//
|
|||
|
// Start the profile interrupt on the current processor and clear the
|
|||
|
// data cache packet address to signal the source to continue.
|
|||
|
//
|
|||
|
|
|||
|
ProfileSource = (KPROFILE_SOURCE)PtrToUlong(Parameter1);
|
|||
|
if (ProfileSource == ProfileAlignmentFixup) {
|
|||
|
KiEnableAlignmentExceptions();
|
|||
|
}
|
|||
|
HalStartProfileInterrupt(ProfileSource);
|
|||
|
KiIpiSignalPacketDone(SignalDone);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|