mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1361 lines
29 KiB
1361 lines
29 KiB
/*++
|
|
|
|
Copyright (c© 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
preftchp.h
|
|
|
|
Abstract:
|
|
|
|
This module contains the private definitions for the kernel mode
|
|
prefetcher for optimizing demand paging. Page faults for a
|
|
scenario are logged and the next time scenario starts, these pages
|
|
are prefetched efficiently via asynchronous paging I/O.
|
|
|
|
Author:
|
|
|
|
Stuart Sechrest (stuartse)
|
|
Chuck Lenzmeier (chuckl)
|
|
Cenk Ergan (cenke)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#ifndef _PREFTCHP_H
|
|
#define _PREFTCHP_H
|
|
|
|
//
|
|
// Define tags used in prefetcher routines.
|
|
//
|
|
|
|
#define CCPF_PREFETCHER_TAG 'fPcC'
|
|
|
|
#define CCPF_ALLOC_SCENARIO_TAG 'SPcC'
|
|
#define CCPF_ALLOC_TRACE_TAG 'TPcC'
|
|
#define CCPF_ALLOC_TRCBUF_TAG 'BPcC'
|
|
#define CCPF_ALLOC_SECTTBL_TAG 'sPcC'
|
|
#define CCPF_ALLOC_TRCDMP_TAG 'DPcC'
|
|
#define CCPF_ALLOC_QUERY_TAG 'qPcC'
|
|
#define CCPF_ALLOC_FILENAME_TAG 'FPcC'
|
|
#define CCPF_ALLOC_CONTEXT_TAG 'CPcC'
|
|
#define CCPF_ALLOC_INTRTABL_TAG 'IPcC'
|
|
#define CCPF_ALLOC_PREFSCEN_TAG 'pPcC'
|
|
#define CCPF_ALLOC_BOOTWRKR_TAG 'wPcC'
|
|
#define CCPF_ALLOC_VOLUME_TAG 'vPcC'
|
|
#define CCPF_ALLOC_READLIST_TAG 'LPcC'
|
|
#define CCPF_ALLOC_METADATA_TAG 'MPcC'
|
|
|
|
//
|
|
// Whether the scenario type is for a system-wide scenario, meaning that
|
|
// only it can be active while running.
|
|
//
|
|
|
|
#define CCPF_IS_SYSTEM_WIDE_SCENARIO_TYPE(ScenarioType) \
|
|
((ScenarioType) == PfSystemBootScenarioType)
|
|
|
|
//
|
|
// In the kernel, we have to look for named objects under this
|
|
// directory for them to visible to Win32 prefetcher service.
|
|
//
|
|
|
|
#define CCPF_BASE_NAMED_OBJ_ROOT_DIR L"\\BaseNamedObjects"
|
|
|
|
//
|
|
// This is the invalid index value used with section tables.
|
|
//
|
|
|
|
#define CCPF_INVALID_TABLE_INDEX (-1)
|
|
|
|
//
|
|
// This is the max number of file metadata that NTFS can prefetch
|
|
// at a time.
|
|
//
|
|
|
|
#define CCPF_MAX_FILE_METADATA_PREFETCH_COUNT 0x300
|
|
|
|
//
|
|
// Define structure to hold prefetcher parameters state.
|
|
//
|
|
|
|
typedef struct _CCPF_PREFETCHER_PARAMETERS {
|
|
|
|
//
|
|
// This is the named event that is used to signal the service that
|
|
// parameters have been updated.
|
|
//
|
|
|
|
HANDLE ParametersChangedEvent;
|
|
|
|
//
|
|
// This is the registry key containing prefetch parameters.
|
|
//
|
|
|
|
HANDLE ParametersKey;
|
|
|
|
//
|
|
// Fields used in registering for change notify on parameters
|
|
// registry key.
|
|
//
|
|
|
|
IO_STATUS_BLOCK RegistryWatchIosb;
|
|
WORK_QUEUE_ITEM RegistryWatchWorkItem;
|
|
ULONG RegistryWatchBuffer;
|
|
|
|
//
|
|
// System wide prefetching parameters. When using any parameters
|
|
// whose update may cause problems [e.g. strings], get the
|
|
// ParametersLock shared. When you need to update Parameters,
|
|
// after getting the ParametersLock exclusive, bump
|
|
// ParametersVersion before updating parameters.
|
|
//
|
|
|
|
PF_SYSTEM_PREFETCH_PARAMETERS Parameters;
|
|
ERESOURCE ParametersLock;
|
|
LONG ParametersVersion;
|
|
|
|
//
|
|
// Prefixes to registry values for different scenario types.
|
|
//
|
|
|
|
WCHAR *ScenarioTypePrefixes[PfMaxScenarioType];
|
|
|
|
//
|
|
// This is set to InitSafeBootMode during initialization.
|
|
//
|
|
|
|
ULONG SafeBootMode;
|
|
|
|
} CCPF_PREFETCHER_PARAMETERS, *PCCPF_PREFETCHER_PARAMETERS;
|
|
|
|
//
|
|
// Define structure to hold prefetcher's global state.
|
|
//
|
|
|
|
typedef struct _CCPF_PREFETCHER_GLOBALS {
|
|
|
|
//
|
|
// List of active traces and the lock to protect it. The number
|
|
// of items on this list is a global, since it is used by other
|
|
// kernel components to make a fast check.
|
|
//
|
|
|
|
LIST_ENTRY ActiveTraces;
|
|
KSPIN_LOCK ActiveTracesLock;
|
|
|
|
//
|
|
// Pointer to the global trace if one is active. While there is a
|
|
// global trace active we don't trace & prefetch other scenarios.
|
|
// Boot tracing is an example of global trace.
|
|
//
|
|
|
|
struct _CCPF_TRACE_HEADER *SystemWideTrace;
|
|
|
|
//
|
|
// List and number of saved completed prefetch traces and lock to
|
|
// protect it.
|
|
//
|
|
|
|
LIST_ENTRY CompletedTraces;
|
|
FAST_MUTEX CompletedTracesLock;
|
|
LONG NumCompletedTraces;
|
|
|
|
//
|
|
// This is the named event that is used to signal the service that
|
|
// there are traces ready for it to get.
|
|
//
|
|
|
|
HANDLE CompletedTracesEvent;
|
|
|
|
//
|
|
// Prefetcher parameters.
|
|
//
|
|
|
|
CCPF_PREFETCHER_PARAMETERS Parameters;
|
|
|
|
} CCPF_PREFETCHER_GLOBALS, *PCCPF_PREFETCHER_GLOBALS;
|
|
|
|
//
|
|
// Reference count structure.
|
|
//
|
|
|
|
typedef struct _CCPF_REFCOUNT {
|
|
|
|
//
|
|
// When initialized or reset, this reference count starts from
|
|
// 1. When exclusive access is granted it stays at 0: even if it
|
|
// may get bumped by an AddRef by mistake, it will return to 0.
|
|
//
|
|
|
|
LONG RefCount;
|
|
|
|
//
|
|
// This is set when somebody wants to gain exclusive access to the
|
|
// protected structure.
|
|
//
|
|
|
|
LONG Exclusive;
|
|
|
|
} CCPF_REFCOUNT, *PCCPF_REFCOUNT;
|
|
|
|
//
|
|
// Define structures used for logging pagefaults:
|
|
//
|
|
|
|
//
|
|
// One of these is logged for every page fault.
|
|
//
|
|
|
|
typedef struct _CCPF_LOG_ENTRY {
|
|
|
|
//
|
|
// File offset of the page that was faulted.
|
|
//
|
|
|
|
ULONG FileOffset;
|
|
|
|
//
|
|
// Index into the section table in the trace header that helps us
|
|
// identify the file.
|
|
//
|
|
|
|
USHORT SectionId;
|
|
|
|
//
|
|
// Whether this page was faulted as an image page or data page.
|
|
//
|
|
|
|
BOOLEAN IsImage;
|
|
|
|
//
|
|
// Whether this is a fault that happened in the process in which
|
|
// the scenario is associated with.
|
|
//
|
|
|
|
BOOLEAN InProcess;
|
|
|
|
} CCPF_LOG_ENTRY, *PCCPF_LOG_ENTRY;
|
|
|
|
//
|
|
// CCPF_LOG_ENTRIES is a buffer of log entries with a small header containing
|
|
// an index to the highest used entry. This is used so that a trace can consist
|
|
// of several smaller trace buffers instead of one large, fixed-size buffer.
|
|
// The current index must be contained in the buffer in order to allow entries
|
|
// to be added without acquiring a spin lock.
|
|
//
|
|
|
|
typedef struct _CCPF_LOG_ENTRIES {
|
|
|
|
//
|
|
// Link used to put this buffer in the traces's buffer list.
|
|
//
|
|
|
|
LIST_ENTRY TraceBuffersLink;
|
|
|
|
//
|
|
// NumEntries is the current number of entries in the buffer. MaxEntries
|
|
// is the maximum number of entries that can be placed in the buffer.
|
|
// (Currently MaxEntries always equals CCPF_TRACE_BUFFER_MAX_ENTRIES.)
|
|
//
|
|
|
|
LONG NumEntries;
|
|
LONG MaxEntries;
|
|
|
|
//
|
|
// The logged entries start here.
|
|
//
|
|
|
|
CCPF_LOG_ENTRY Entries[1];
|
|
|
|
} CCPF_LOG_ENTRIES, *PCCPF_LOG_ENTRIES;
|
|
|
|
//
|
|
// CCPF_TRACE_BUFFER_SIZE is the size of an allocated CCPF_LOG_ENTRIES structure
|
|
// (including the header). This should be a multiple of the page size.
|
|
//
|
|
|
|
#define CCPF_TRACE_BUFFER_SIZE 8192
|
|
|
|
//
|
|
// CCPF_TRACE_BUFFER_MAX_ENTRIES is the number of log entries that will fit in
|
|
// a trace buffer of size CCPF_TRACE_BUFFER_SIZE.
|
|
//
|
|
|
|
#define CCPF_TRACE_BUFFER_MAX_ENTRIES (((CCPF_TRACE_BUFFER_SIZE - sizeof(CCPF_LOG_ENTRIES)) / sizeof(CCPF_LOG_ENTRY)) + 1)
|
|
|
|
//
|
|
// This structure associates a SectionObjectPointer with a file name
|
|
// in the runtime trace buffer. There is a table of these in the trace
|
|
// header and every page fault has an index into this table denoting
|
|
// which file it is to.
|
|
//
|
|
|
|
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _CCPF_SECTION_INFO {
|
|
|
|
//
|
|
// Section info entries are kept in a hash. This field is
|
|
// InterlockedCompareExchange'd to denote that it is in use.
|
|
//
|
|
|
|
LONG EntryValid;
|
|
|
|
//
|
|
// Whether this section is used for file systems to map metafile.
|
|
//
|
|
|
|
ULONG Metafile:1;
|
|
ULONG Unused:31;
|
|
|
|
//
|
|
// SectionObjectPointer used as a unique identifier to a file
|
|
// mapping. The same file may be mapped using a number of file
|
|
// objects, but the SectionObjectPointer fields of all those file
|
|
// objects will be the same.
|
|
//
|
|
|
|
PSECTION_OBJECT_POINTERS SectionObjectPointer;
|
|
|
|
//
|
|
// All references to all file objects for a file may be released,
|
|
// and a new file may be opened using the same memory block for
|
|
// its FCB at which point the SectionObjectPointer would no longer
|
|
// be unique. This would result in pagefaults getting logged under
|
|
// the entry for the file that was closed. The consequences would
|
|
// be misprefetching wrong pages from a couple of sections until
|
|
// the scenario corrects itself by looking at new traces. By
|
|
// keeping track of these two fields of the SectionObjectPointers
|
|
// to check for uniqueness we make this case very unlikely to
|
|
// happen. The other solutions we thought of to solve this issue
|
|
// 100% were too costly in terms of complication or efficiency.
|
|
//
|
|
|
|
//
|
|
// In order to avoid adding two entries to the table for the
|
|
// section when it is used as data first then image (or vice
|
|
// versa) it is assumed that it is still the same section if the
|
|
// current entry's Data/ImageSectionObject is NULL but the
|
|
// Data/ImageSectionObject of the section we are logging a new
|
|
// pagefault to is not. Then we try to update the NULL pointer
|
|
// with the new value using InterlockedCompareExchangePointer.
|
|
//
|
|
|
|
PVOID DataSectionObject;
|
|
PVOID ImageSectionObject;
|
|
|
|
//
|
|
// This may point to a file object that we have referenced to
|
|
// ensure the section object stays around until we can get a name.
|
|
//
|
|
|
|
PFILE_OBJECT ReferencedFileObject;
|
|
|
|
//
|
|
// The name is set as soon as we can get a file name. We cannot
|
|
// access the file name while running at a high IRQL.
|
|
//
|
|
|
|
WCHAR *FileName;
|
|
|
|
//
|
|
// We queue a section to the get-file-name list using this field.
|
|
//
|
|
|
|
SINGLE_LIST_ENTRY GetNameLink;
|
|
|
|
} CCPF_SECTION_INFO, *PCCPF_SECTION_INFO;
|
|
|
|
//
|
|
// This structure contains information on a volume on which sections
|
|
// in the trace are located on.
|
|
//
|
|
|
|
typedef struct _CCPF_VOLUME_INFO {
|
|
|
|
//
|
|
// Link in the trace's volume list.
|
|
//
|
|
|
|
LIST_ENTRY VolumeLink;
|
|
|
|
//
|
|
// Volume creation time and serial number used to identify the
|
|
// volume in case its NT/device path e.g. \Device\HarddiskVolume1
|
|
// changes.
|
|
//
|
|
|
|
LARGE_INTEGER CreationTime;
|
|
ULONG SerialNumber;
|
|
|
|
//
|
|
// Current NT/device path for the volume and its length in
|
|
// characters excluding terminating NUL.
|
|
//
|
|
|
|
ULONG VolumePathLength;
|
|
WCHAR VolumePath[1];
|
|
|
|
} CCPF_VOLUME_INFO, *PCCPF_VOLUME_INFO;
|
|
|
|
//
|
|
// This is the runtime trace header for a scenario.
|
|
//
|
|
|
|
typedef struct _CCPF_TRACE_HEADER {
|
|
|
|
//
|
|
// Magic number identifying this structure as a trace.
|
|
//
|
|
|
|
ULONG Magic;
|
|
|
|
//
|
|
// Link in the active traces list.
|
|
//
|
|
|
|
LIST_ENTRY ActiveTracesLink;
|
|
|
|
//
|
|
// Scenario id for which we are acquiring this trace.
|
|
//
|
|
|
|
PF_SCENARIO_ID ScenarioId;
|
|
|
|
//
|
|
// Type of this scenario.
|
|
//
|
|
|
|
PF_SCENARIO_TYPE ScenarioType;
|
|
|
|
//
|
|
// CurrentTraceBuffer is the active trace buffer.
|
|
//
|
|
|
|
PCCPF_LOG_ENTRIES CurrentTraceBuffer;
|
|
|
|
//
|
|
// This is the list of trace buffers for this trace.
|
|
// CurrentTraceBuffer is the last element. Both this list and
|
|
// CurrentTraceBuffer are protected by TraceBufferSpinLock.
|
|
//
|
|
|
|
LIST_ENTRY TraceBuffersList;
|
|
ULONG NumTraceBuffers;
|
|
KSPIN_LOCK TraceBufferSpinLock;
|
|
|
|
//
|
|
// This is the table for section info.
|
|
//
|
|
|
|
PCCPF_SECTION_INFO SectionInfoTable;
|
|
LONG NumSections;
|
|
LONG MaxSections;
|
|
ULONG SectionTableSize;
|
|
|
|
//
|
|
// We don't log timestamps with page faults but it helps to know
|
|
// how many we are logging per given time. This information can be
|
|
// used to mark the end of a scenario.
|
|
//
|
|
|
|
KTIMER TraceTimer;
|
|
LARGE_INTEGER TraceTimerPeriod;
|
|
KDPC TraceTimerDpc;
|
|
KSPIN_LOCK TraceTimerSpinLock;
|
|
|
|
//
|
|
// This array contains the number of page faults logged per trace
|
|
// period.
|
|
//
|
|
|
|
ULONG FaultsPerPeriod[PF_MAX_NUM_TRACE_PERIODS];
|
|
LONG LastNumFaults;
|
|
LONG CurPeriod;
|
|
|
|
//
|
|
// NumFaults is the number of faults that have been logged so far, in all
|
|
// trace buffers. MaxFaults is the maximum number of page faults we will
|
|
// log, in all trace buffers.
|
|
//
|
|
|
|
LONG NumFaults;
|
|
LONG MaxFaults;
|
|
|
|
//
|
|
// This workitem is queued to get names for file objects we are
|
|
// logging page faults to. First GetFileNameWorkItemQueued should
|
|
// be InterlockedCompareExchange'd from 0 to 1 and a reference
|
|
// should be acquired on the scenario. The workitem will free this
|
|
// reference just before it completes.
|
|
//
|
|
|
|
WORK_QUEUE_ITEM GetFileNameWorkItem;
|
|
LONG GetFileNameWorkItemQueued;
|
|
|
|
//
|
|
// Sections for which we have to get names are pushed and popped
|
|
// to/from this slist.
|
|
//
|
|
|
|
SLIST_HEADER SectionsWithoutNamesList;
|
|
|
|
//
|
|
// Because we don't want to incur the cost of queuing a work item
|
|
// to get file names for every one or two sections, the worker we
|
|
// queue will wait on this event before returning. The event can
|
|
// be signaled when a new section comes, or when the scenario is
|
|
// ending.
|
|
//
|
|
|
|
KEVENT GetFileNameWorkerEvent;
|
|
|
|
//
|
|
// This is the process we are associated with.
|
|
//
|
|
|
|
PEPROCESS Process;
|
|
|
|
//
|
|
// This is the removal reference count protecting us.
|
|
//
|
|
|
|
CCPF_REFCOUNT RefCount;
|
|
|
|
//
|
|
// This work item can be queued to call the end trace function if
|
|
// the trace times out or we log to many entries etc. First
|
|
// EndTraceCalled should be InterlockedCompareExchange'd from 0 to
|
|
// 1.
|
|
//
|
|
|
|
WORK_QUEUE_ITEM EndTraceWorkItem;
|
|
|
|
//
|
|
// Before anybody calls end trace function, they have to
|
|
// InterlockedCompareExchange this from 0 to 1 to ensure this
|
|
// function gets called only once.
|
|
//
|
|
|
|
LONG EndTraceCalled;
|
|
|
|
//
|
|
// This is the list of volumes the sections we are tracing are
|
|
// located on. It is sorted lexically by the volume NT/device path.
|
|
//
|
|
|
|
LIST_ENTRY VolumeList;
|
|
ULONG NumVolumes;
|
|
|
|
//
|
|
// This is the pointer to the built trace dump from this runtime
|
|
// trace structure and the status with which dumping failed if it
|
|
// did.
|
|
//
|
|
|
|
struct _CCPF_TRACE_DUMP *TraceDump;
|
|
NTSTATUS TraceDumpStatus;
|
|
|
|
//
|
|
// System time when we started tracing.
|
|
//
|
|
|
|
LARGE_INTEGER LaunchTime;
|
|
|
|
} CCPF_TRACE_HEADER, *PCCPF_TRACE_HEADER;
|
|
|
|
//
|
|
// This structure is used to save completed traces in a list. The
|
|
// trace extends beyond this structure as necessary.
|
|
//
|
|
|
|
typedef struct _CCPF_TRACE_DUMP {
|
|
|
|
//
|
|
// Link in the completed traces list.
|
|
//
|
|
|
|
LIST_ENTRY CompletedTracesLink;
|
|
|
|
//
|
|
// Completed trace.
|
|
//
|
|
|
|
PF_TRACE_HEADER Trace;
|
|
|
|
} CCPF_TRACE_DUMP, *PCCPF_TRACE_DUMP;
|
|
|
|
//
|
|
// This structure contains information for a volume used during prefetching.
|
|
//
|
|
|
|
typedef struct _CCPF_PREFETCH_VOLUME_INFO {
|
|
|
|
//
|
|
// Link in the lists this volume gets put on.
|
|
//
|
|
|
|
LIST_ENTRY VolumeLink;
|
|
|
|
//
|
|
// Volume path.
|
|
//
|
|
|
|
WCHAR *VolumePath;
|
|
ULONG VolumePathLength;
|
|
|
|
//
|
|
// Handle to the opened volume.
|
|
//
|
|
|
|
HANDLE VolumeHandle;
|
|
|
|
} CCPF_PREFETCH_VOLUME_INFO, *PCCPF_PREFETCH_VOLUME_INFO;
|
|
|
|
//
|
|
// This structure is used to keep track of prefetched pages & context.
|
|
//
|
|
|
|
//
|
|
// Note: This structure is used as a stack variable. Don't add events
|
|
// etc, without changing that.
|
|
//
|
|
|
|
typedef struct _CCPF_PREFETCH_HEADER {
|
|
|
|
//
|
|
// Pointer to prefetch instructions. The instructions should not
|
|
// be removed / freed until the prefetch header is cleaned up.
|
|
// E.g. VolumeNodes may point to volume paths in the scenario.
|
|
//
|
|
|
|
PPF_SCENARIO_HEADER Scenario;
|
|
|
|
//
|
|
// Nodes for the volumes we are going to prefetch from.
|
|
//
|
|
|
|
PCCPF_PREFETCH_VOLUME_INFO VolumeNodes;
|
|
|
|
//
|
|
// List of volumes we won't prefetch on.
|
|
//
|
|
|
|
LIST_ENTRY BadVolumeList;
|
|
|
|
//
|
|
// List of volumes we have opened. They are opened with the following
|
|
// flags: FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE
|
|
//
|
|
|
|
LIST_ENTRY OpenedVolumeList;
|
|
|
|
} CCPF_PREFETCH_HEADER, *PCCPF_PREFETCH_HEADER;
|
|
|
|
//
|
|
// Define types of prefetching CcPfPrefetchSections can be called to
|
|
// perform.
|
|
//
|
|
|
|
typedef enum _CCPF_PREFETCH_TYPE {
|
|
CcPfPrefetchAllDataPages,
|
|
CcPfPrefetchAllImagePages,
|
|
CcPfPrefetchPartOfDataPages,
|
|
CcPfPrefetchPartOfImagePages,
|
|
CcPfMaxPrefetchType
|
|
} CCPF_PREFETCH_TYPE, *PCCPF_PREFETCH_TYPE;
|
|
|
|
//
|
|
// This structure stands for the position in the prefetch
|
|
// instructions. It is used and updated by CcPfPrefetchSections when
|
|
// prefetching parts of a scenario at a time.
|
|
//
|
|
|
|
typedef struct _CCPF_PREFETCH_CURSOR {
|
|
|
|
//
|
|
// Index of the current section and the page in that section.
|
|
//
|
|
|
|
ULONG SectionIdx;
|
|
ULONG PageIdx;
|
|
|
|
} CCPF_PREFETCH_CURSOR, *PCCPF_PREFETCH_CURSOR;
|
|
|
|
//
|
|
// This type is used in CcPfPrefetchSections.
|
|
//
|
|
|
|
typedef struct _SECTION *PSECTION;
|
|
|
|
//
|
|
// Define types of information CcPfQueryScenarioInformation can be
|
|
// asked to return.
|
|
//
|
|
|
|
typedef enum _CCPF_SCENARIO_INFORMATION_TYPE {
|
|
CcPfBasicScenarioInformation,
|
|
CcPfBootScenarioInformation,
|
|
CcPfMaxScenarioInformationType
|
|
} CCPF_SCENARIO_INFORMATION_TYPE, *PCCPF_SCENARIO_INFORMATION_TYPE;
|
|
|
|
//
|
|
// This structure contains basic scenario information.
|
|
//
|
|
|
|
typedef struct _CCPF_BASIC_SCENARIO_INFORMATION {
|
|
|
|
//
|
|
// Number of pages that will be prefetched as data pages.
|
|
//
|
|
|
|
ULONG NumDataPages;
|
|
|
|
//
|
|
// Number of pages that will be prefetched as image pages.
|
|
//
|
|
|
|
ULONG NumImagePages;
|
|
|
|
//
|
|
// Number of sections for which only data pages will be
|
|
// prefetched.
|
|
//
|
|
|
|
ULONG NumDataOnlySections;
|
|
|
|
//
|
|
// Number of sections for which only image pages will be
|
|
// prefetched excluding the header page.
|
|
//
|
|
|
|
ULONG NumImageOnlySections;
|
|
|
|
//
|
|
// Number of ignored pages.
|
|
//
|
|
|
|
ULONG NumIgnoredPages;
|
|
|
|
//
|
|
// Number of ignored sections.
|
|
//
|
|
|
|
ULONG NumIgnoredSections;
|
|
|
|
} CCPF_BASIC_SCENARIO_INFORMATION, *PCCPF_BASIC_SCENARIO_INFORMATION;
|
|
|
|
//
|
|
// Routines used in the core prefetcher.
|
|
//
|
|
|
|
//
|
|
// Routines used in prefetch tracing.
|
|
//
|
|
|
|
NTSTATUS
|
|
CcPfBeginTrace(
|
|
IN PF_SCENARIO_ID *ScenarioId,
|
|
IN PF_SCENARIO_TYPE ScenarioType,
|
|
IN HANDLE ProcessHandle
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfActivateTrace(
|
|
IN PCCPF_TRACE_HEADER Scenario
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfDeactivateTrace(
|
|
IN PCCPF_TRACE_HEADER Scenario
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfEndTrace(
|
|
IN PCCPF_TRACE_HEADER Trace
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfBuildDumpFromTrace(
|
|
OUT PCCPF_TRACE_DUMP *TraceDump,
|
|
IN PCCPF_TRACE_HEADER RuntimeTrace
|
|
);
|
|
|
|
VOID
|
|
CcPfCleanupTrace(
|
|
IN PCCPF_TRACE_HEADER Trace
|
|
);
|
|
|
|
VOID
|
|
CcPfTraceTimerRoutine(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfCancelTraceTimer(
|
|
IN PCCPF_TRACE_HEADER Trace
|
|
);
|
|
|
|
VOID
|
|
CcPfEndTraceWorkerThreadRoutine(
|
|
PVOID Parameter
|
|
);
|
|
|
|
VOID
|
|
CcPfGetFileNamesWorkerRoutine(
|
|
PVOID Parameter
|
|
);
|
|
|
|
LONG
|
|
CcPfLookUpSection(
|
|
PCCPF_SECTION_INFO Table,
|
|
ULONG TableSize,
|
|
PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
PLONG AvailablePosition
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfGetCompletedTrace (
|
|
PVOID Buffer,
|
|
ULONG BufferSize,
|
|
PULONG ReturnSize
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfUpdateVolumeList(
|
|
PCCPF_TRACE_HEADER Trace,
|
|
WCHAR *VolumePath,
|
|
ULONG VolumePathLength
|
|
);
|
|
|
|
//
|
|
// Routines used for prefetching and dealing with prefetch instructions.
|
|
//
|
|
|
|
NTSTATUS
|
|
CcPfPrefetchScenario (
|
|
PPF_SCENARIO_HEADER Scenario
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfPrefetchSections(
|
|
IN PCCPF_PREFETCH_HEADER PrefetchHeader,
|
|
IN CCPF_PREFETCH_TYPE PrefetchType,
|
|
OPTIONAL IN PCCPF_PREFETCH_CURSOR StartCursor,
|
|
OPTIONAL ULONG TotalPagesToPrefetch,
|
|
OPTIONAL OUT PULONG NumPagesPrefetched,
|
|
OPTIONAL OUT PCCPF_PREFETCH_CURSOR EndCursor
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfPrefetchMetadata(
|
|
IN PCCPF_PREFETCH_HEADER PrefetchHeader
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfPrefetchDirectoryContents(
|
|
WCHAR *DirectoryPath,
|
|
WCHAR DirectoryPathlength
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfPrefetchFileMetadata(
|
|
HANDLE VolumeHandle,
|
|
PFILE_PREFETCH FilePrefetch
|
|
);
|
|
|
|
VOID
|
|
CcPfInitializePrefetchHeader (
|
|
OUT PCCPF_PREFETCH_HEADER PrefetchHeader
|
|
);
|
|
|
|
VOID
|
|
CcPfCleanupPrefetchHeader (
|
|
IN PCCPF_PREFETCH_HEADER PrefetchHeader
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfGetPrefetchInstructions(
|
|
IN PPF_SCENARIO_ID ScenarioId,
|
|
IN PF_SCENARIO_TYPE ScenarioType,
|
|
OUT PPF_SCENARIO_HEADER *Scenario
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfQueryScenarioInformation(
|
|
IN PPF_SCENARIO_HEADER Scenario,
|
|
IN CCPF_SCENARIO_INFORMATION_TYPE InformationType,
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferSize,
|
|
OUT PULONG RequiredSize
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfOpenVolumesForPrefetch (
|
|
IN PCCPF_PREFETCH_HEADER PrefetchHeader
|
|
);
|
|
|
|
PCCPF_PREFETCH_VOLUME_INFO
|
|
CcPfFindPrefetchVolumeInfoInList(
|
|
WCHAR *Path,
|
|
PLIST_ENTRY List
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfGetSectionObject(
|
|
IN PUNICODE_STRING FileName,
|
|
IN LOGICAL ImageSection,
|
|
OUT PVOID* SectionObject,
|
|
OUT PFILE_OBJECT* FileObject,
|
|
OUT HANDLE* FileHandle
|
|
);
|
|
|
|
//
|
|
// Routines used for application launch prefetching.
|
|
//
|
|
|
|
BOOLEAN
|
|
CcPfIsHostingApplication(
|
|
IN PWCHAR ExecutableName
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfScanCommandLine(
|
|
OUT PULONG PrefetchHint,
|
|
OPTIONAL OUT PULONG HashId
|
|
);
|
|
|
|
//
|
|
// Reference count functions:
|
|
//
|
|
|
|
VOID
|
|
CcPfInitializeRefCount(
|
|
PCCPF_REFCOUNT RefCount
|
|
);
|
|
|
|
NTSTATUS
|
|
FASTCALL
|
|
CcPfAddRef(
|
|
PCCPF_REFCOUNT RefCount
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
CcPfDecRef(
|
|
PCCPF_REFCOUNT RefCount
|
|
);
|
|
|
|
NTSTATUS
|
|
FASTCALL
|
|
CcPfAddRefEx(
|
|
PCCPF_REFCOUNT RefCount,
|
|
ULONG Count
|
|
);
|
|
|
|
VOID
|
|
FASTCALL
|
|
CcPfDecRefEx(
|
|
PCCPF_REFCOUNT RefCount,
|
|
ULONG Count
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfAcquireExclusiveRef(
|
|
PCCPF_REFCOUNT RefCount
|
|
);
|
|
|
|
PCCPF_TRACE_HEADER
|
|
CcPfReferenceProcessTrace(
|
|
PEPROCESS Process
|
|
);
|
|
|
|
PCCPF_TRACE_HEADER
|
|
CcPfRemoveProcessTrace(
|
|
PEPROCESS Process
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfAddProcessTrace(
|
|
PEPROCESS Process,
|
|
PCCPF_TRACE_HEADER Trace
|
|
);
|
|
|
|
//
|
|
// Utility routines.
|
|
//
|
|
|
|
PWCHAR
|
|
CcPfFindString (
|
|
PUNICODE_STRING SearchIn,
|
|
PUNICODE_STRING SearchFor
|
|
);
|
|
|
|
ULONG
|
|
CcPfHashValue(
|
|
PVOID Key,
|
|
ULONG Len
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfIsVolumeMounted (
|
|
IN WCHAR *VolumePath,
|
|
OUT BOOLEAN *VolumeMounted
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfQueryVolumeInfo (
|
|
IN WCHAR *VolumePath,
|
|
OPTIONAL OUT HANDLE *VolumeHandleOut,
|
|
OUT PLARGE_INTEGER CreationTime,
|
|
OUT PULONG SerialNumber
|
|
);
|
|
|
|
//
|
|
// Declarations and definitions for prefetcher parameters.
|
|
//
|
|
|
|
//
|
|
// Define location of registry key for prefetch parameters.
|
|
//
|
|
|
|
#define CCPF_PARAMETERS_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters"
|
|
|
|
//
|
|
// Maximum characters in registry value names for prefetch parameters.
|
|
//
|
|
|
|
#define CCPF_MAX_PARAMETER_NAME_LENGTH 80
|
|
|
|
//
|
|
// Maximum bytes needed to query a prefetch parameter from the
|
|
// registry. Currently our largest parameter would be the hosting
|
|
// application list.
|
|
//
|
|
|
|
#define CCPF_MAX_PARAMETER_VALUE_BUFFER ((PF_HOSTING_APP_LIST_MAX_CHARS * sizeof(WCHAR)) + sizeof(KEY_VALUE_PARTIAL_INFORMATION))
|
|
|
|
NTSTATUS
|
|
CcPfParametersInitialize (
|
|
PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
|
|
);
|
|
|
|
VOID
|
|
CcPfParametersSetDefaults (
|
|
PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfParametersRead (
|
|
PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfParametersSave (
|
|
PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfParametersVerify (
|
|
PPF_SYSTEM_PREFETCH_PARAMETERS Parameters
|
|
);
|
|
|
|
VOID
|
|
CcPfParametersWatcher (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfParametersSetChangedEvent (
|
|
PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfGetParameter (
|
|
HANDLE ParametersKey,
|
|
WCHAR *ValueNameBuffer,
|
|
ULONG ValueType,
|
|
PVOID Value,
|
|
ULONG *ValueSize
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfSetParameter (
|
|
HANDLE ParametersKey,
|
|
WCHAR *ValueNameBuffer,
|
|
ULONG ValueType,
|
|
PVOID Value,
|
|
ULONG ValueSize
|
|
);
|
|
|
|
LOGICAL
|
|
CcPfDetermineEnablePrefetcher(
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Declarations and definitions for boot prefetching.
|
|
//
|
|
|
|
//
|
|
// Value name under prefetcher parameters key where we store how long
|
|
// video initialization took during boot.
|
|
//
|
|
|
|
#define CCPF_VIDEO_INIT_TIME_VALUE_NAME L"VideoInitTime"
|
|
|
|
//
|
|
// How long (in milliseconds) video initialization could take max. This value
|
|
// is used to sanity check the value read from the registry.
|
|
//
|
|
|
|
#define CCPF_MAX_VIDEO_INIT_TIME (10 * 1000) // 10 seconds
|
|
|
|
//
|
|
// Value name under prefetcher parameters key where we store how many
|
|
// pages we should try to prefetch per second of video initialization.
|
|
//
|
|
|
|
#define CCPF_VIDEO_INIT_PAGES_PER_SECOND_VALUE_NAME L"VideoInitPagesPerSecond"
|
|
|
|
//
|
|
// Sanity check maximum value for video init pages per second.
|
|
//
|
|
|
|
#define CCPF_VIDEO_INIT_MAX_PAGES_PER_SECOND 128000
|
|
|
|
//
|
|
// How many pages will we try to prefetch in parallel to video initialization
|
|
// per second of it.
|
|
//
|
|
|
|
#define CCPF_VIDEO_INIT_DEFAULT_PAGES_PER_SECOND 1500
|
|
|
|
//
|
|
// Maximum number of chunks in which we will prefetch for boot.
|
|
//
|
|
|
|
#define CCPF_MAX_BOOT_PREFETCH_PHASES 16
|
|
|
|
//
|
|
// Different phases of boot we return page counts for in
|
|
// CCPF_BOOT_SCENARIO_INFORMATION.
|
|
//
|
|
|
|
typedef enum _CCPF_BOOT_SCENARIO_PHASE {
|
|
|
|
CcPfBootScenDriverInitPhase,
|
|
CcPfBootScenSubsystemInitPhase,
|
|
CcPfBootScenSystemProcInitPhase,
|
|
CcPfBootScenServicesInitPhase,
|
|
CcPfBootScenUserInitPhase,
|
|
CcPfBootScenMaxPhase
|
|
|
|
} CCPF_BOOT_SCENARIO_PHASE, *PCCPF_BOOT_SCENARIO_PHASE;
|
|
|
|
//
|
|
// Define structure to hold boot prefetching state.
|
|
//
|
|
|
|
typedef struct _CCPF_BOOT_PREFETCHER {
|
|
|
|
//
|
|
// These events are signaled by the boot prefetch worker when
|
|
// it has completed prefetching for the specified phase.
|
|
//
|
|
|
|
KEVENT SystemDriversPrefetchingDone;
|
|
KEVENT PreSmssPrefetchingDone;
|
|
KEVENT VideoInitPrefetchingDone;
|
|
|
|
//
|
|
// This event will be signaled when we start initializing video
|
|
// on the console. Boot prefetcher waits on this event to perform
|
|
// prefetching parallel to video initialization.
|
|
//
|
|
|
|
KEVENT VideoInitStarted;
|
|
|
|
} CCPF_BOOT_PREFETCHER, *PCCPF_BOOT_PREFETCHER;
|
|
|
|
//
|
|
// This structure contains boot scenario information.
|
|
//
|
|
|
|
typedef struct _CCPF_BOOT_SCENARIO_INFORMATION {
|
|
|
|
//
|
|
// These are the number of data/image pages to prefetch for the
|
|
// different phase of boot.
|
|
//
|
|
|
|
ULONG NumDataPages[CcPfBootScenMaxPhase];
|
|
ULONG NumImagePages[CcPfBootScenMaxPhase];
|
|
|
|
} CCPF_BOOT_SCENARIO_INFORMATION, *PCCPF_BOOT_SCENARIO_INFORMATION;
|
|
|
|
//
|
|
// We will be prefetching data and image pages for boot in parts. Since the
|
|
// code is mostly same to prefetch the data and image pages, we keep track
|
|
// of where we left off and what to prefetch next in a common boot prefetch
|
|
// cursor structure and make two passes (first for data, then for image).
|
|
//
|
|
|
|
typedef struct _CCPF_BOOT_PREFETCH_CURSOR {
|
|
|
|
//
|
|
// Start & end cursors passed to prefetch sections function.
|
|
//
|
|
|
|
CCPF_PREFETCH_CURSOR StartCursor;
|
|
CCPF_PREFETCH_CURSOR EndCursor;
|
|
|
|
//
|
|
// How to prefetch (e.g. part of data pages or part of image pages).
|
|
//
|
|
|
|
CCPF_PREFETCH_TYPE PrefetchType;
|
|
|
|
//
|
|
// How many pages to prefetch per phase.
|
|
//
|
|
|
|
ULONG NumPagesForPhase[CCPF_MAX_BOOT_PREFETCH_PHASES];
|
|
|
|
} CCPF_BOOT_PREFETCH_CURSOR, *PCCPF_BOOT_PREFETCH_CURSOR;
|
|
|
|
//
|
|
// Boot prefetching routines.
|
|
//
|
|
|
|
VOID
|
|
CcPfBootWorker(
|
|
PCCPF_BOOT_PREFETCHER BootPrefetcher
|
|
);
|
|
|
|
NTSTATUS
|
|
CcPfBootQueueEndTraceTimer (
|
|
PLARGE_INTEGER Timeout
|
|
);
|
|
|
|
VOID
|
|
CcPfEndBootTimerRoutine(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
);
|
|
|
|
//
|
|
// Debug routines.
|
|
//
|
|
|
|
#if CCPF_DBG
|
|
|
|
NTSTATUS
|
|
CcPfWriteToFile(
|
|
IN PVOID pData,
|
|
IN ULONG Size,
|
|
IN WCHAR *pFileName
|
|
);
|
|
|
|
#endif // CCPF_DBG
|
|
|
|
//
|
|
// Define useful macros. As with all macros, must be careful of
|
|
// parameter reevalation. Don't use expressions as macro parameters.
|
|
//
|
|
|
|
#define CCPF_MAX(A,B) (((A) >= (B)) ? (A) : (B))
|
|
#define CCPF_MIN(A,B) (((A) <= (B)) ? (A) : (B))
|
|
|
|
//
|
|
// Define debugging macros:
|
|
//
|
|
|
|
//
|
|
// Define the component ID we use.
|
|
//
|
|
|
|
#define CCPFID DPFLTR_PREFETCHER_ID
|
|
|
|
//
|
|
// Define DbgPrintEx levels.
|
|
//
|
|
|
|
#define PFERR DPFLTR_ERROR_LEVEL
|
|
#define PFWARN DPFLTR_WARNING_LEVEL
|
|
#define PFTRC DPFLTR_TRACE_LEVEL
|
|
#define PFINFO DPFLTR_INFO_LEVEL
|
|
#define PFPREF 4
|
|
#define PFPRFD 5
|
|
#define PFPRFF 6
|
|
#define PFPRFZ 7
|
|
#define PFTRAC 8
|
|
#define PFTMR 9
|
|
#define PFNAME 10
|
|
#define PFNAMS 11
|
|
#define PFLKUP 12
|
|
#define PFBOOT 13
|
|
|
|
//
|
|
// DbgPrintEx levels 20 - 31 are reserved for the service.
|
|
//
|
|
|
|
//
|
|
// This may help you determine what to set the DbgPrintEx mask.
|
|
//
|
|
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
|
|
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
|
// _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
|
//
|
|
|
|
//
|
|
// CCPF_DBG can be defined if you want to turn on asserts and debug
|
|
// prints in prefetcher code but you do not want to have a checked
|
|
// kernel. Defining CCPF_DBG overrides defining DBG.
|
|
//
|
|
|
|
#if CCPF_DBG
|
|
|
|
NTSYSAPI
|
|
VOID
|
|
NTAPI
|
|
RtlAssert(
|
|
PVOID FailedAssertion,
|
|
PVOID FileName,
|
|
ULONG LineNumber,
|
|
PCHAR Message
|
|
);
|
|
|
|
#define DBGPR(x) DbgPrintEx x
|
|
#define CCPF_ASSERT(x) if (!(x)) RtlAssert(#x, __FILE__, __LINE__, NULL )
|
|
|
|
#else // CCPF_DBG
|
|
|
|
//
|
|
// If CCPF_DBG is not defined, build with debug prints and asserts
|
|
// only on checked build.
|
|
//
|
|
|
|
#if DBG
|
|
|
|
#define DBGPR(x) DbgPrintEx x
|
|
#define CCPF_ASSERT(x) ASSERT(x)
|
|
|
|
#else // DBG
|
|
|
|
//
|
|
// On a free build we don't compile with debug prints or asserts.
|
|
//
|
|
|
|
#define DBGPR(x)
|
|
#define CCPF_ASSERT(x)
|
|
|
|
#endif // DBG
|
|
|
|
#endif // CCPF_DBG
|
|
|
|
#endif // _PREFTCHP_H
|