Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1900 lines
52 KiB

//
// Systrack - System resource tracking
// Copyright (c) Microsoft Corporation, 1998
//
//
// module: systrack.cxx
// author: silviuc
// created: Mon Nov 09 12:20:41 1998
//
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
extern "C" {
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
}
#include <windows.h>
#include <common.ver>
#define VERSION_DEFINITION_MODULE
#include "version.hxx"
#define DEBUGINFO_DEFINITION_MODULE
#include "debug.hxx"
#include "pooltag.hxx"
#include "process.hxx"
#include "memory.hxx"
#include "systrack.hxx"
#define BUFFER_SIZE_STEP ( 128 * 1024 )
void PrintCurrentTime ();
void PrintSystemBasicInformation ();
void PrintSystemPerformanceInformation ();
void PrintSystemProcessInformation (BOOL ShortDump);
void PrintSystemPoolDetailedInformation ();
void PrintSystemPoolTagInformation ();
void PrintProcessStackInformation ();
VOID
GetProcessStackInfo (
PSYSTEM_PROCESS_INFORMATION Info,
PSIZE_T MaxSize,
PSIZE_T TotalSize,
PBOOL ErrorsFound
);
//
// Functions:
//
// Help
//
// Decription:
//
// Prints help information to the stdout. Exits with status code 1.
//
static void
Help ()
{
static char help_text [] =
" \n"
"systrack - System resource tracking --" BUILD_MACHINE_TAG "\n"
VER_LEGALCOPYRIGHT_STR "\n"
" \n"
" systrack [INFO-CLASS] \n"
" \n"
" <> : if no class specified, print process information. \n"
" /system : print system basic information. \n"
" /process : print process information. \n"
" /stack : print stack usage information for all processes. \n"
" /performance: print performance information. \n"
" /pool : print pool tag information (pool tags should be enabled). \n"
" /pooldetailed : print pool information (only checked builds). \n"
" /all : print everything. \n"
" \n"
" /trackpool PERIOD DELTA \n"
" /trackpooltag PERIOD PATTERN DELTA \n"
" /trackprocess PERIOD HANDLE THREAD WSET VSIZE PFILE \n"
" /trackprocessid PERIOD ID HANDLE THREAD WSET VSIZE PFILE \n"
" /trackavailablepages PERIOD DELTA \n"
" /trackcommittedpages PERIOD DELTA \n"
" /trackcommitlimit PERIOD DELTA \n"
" /trackpagefaultcount PERIOD DELTA \n"
" /tracksystemcalls PERIOD DELTA \n"
" /tracktotalsystemdriverpages PERIOD DELTA \n"
" /tracktotalsystemcodepages PERIOD DELTA \n"
" \n"
" /help TOPIC detailed help for the topic (e.g. process, trackpool, \n"
" trackprocessid, etc.). \n"
" ?, /? help \n"
" -version version information \n"
" \n"
"Examples: \n"
" \n"
" systrack /trackpool 1000 10000 \n"
" \n"
" Polls every 1000ms the kernel pools and will print every pool tag \n"
" whose pool usage increased by more than 10000 bytes. \n"
" \n"
" systrack /trackpooltag 1000 \"G*\" 10000 \n"
" \n"
" Polls every 1000ms the kernel pools and will print every pool tag \n"
" that matches the pattern if its pool usage increased by more \n"
" than 10000 bytes. \n"
" \n"
" systrack /trackprocess 1000 5 5 1000000 1000000 1000000 \n"
" \n"
" Polls every 1000ms the processes running and prints every process \n"
" whose handle count increased by more than 5 or thread count \n"
" increased by more than 5 or working set size increased by more \n"
" than 1000000 or virtual size increased by more than 1000000 or \n"
" pagefile usage increased by more than 1000000. \n"
" \n"
" systrack /trackprocessid 1000 136 5 5 1000000 1000000 1000000 \n"
" \n"
" Polls every 1000ms the process with id 136 and reports if the \n"
" handle count increased by more than 5 or thread count \n"
" increased by more than 5 or working set size increased by more \n"
" than 1000000 or virtual size increased by more than 1000000 or \n"
" pagefile usage increased by more than 1000000. \n"
" \n"
" \n";
printf (help_text);
exit (1);
}
//
// Functions:
//
// DetailedHelp
//
// Decription:
//
// Prints help information to the stdout for a specific topic.
// Exits with status code 1.
//
static void
DetailedHelp (
char * Topic)
{
char * help_text;
if (_stricmp (Topic, "system") == 0) {
help_text =
"systrack /system \n"
" \n"
" \n";
}
else if (_stricmp (Topic, "process") == 0) {
help_text =
"systrack /proces \n"
" \n"
" \n";
}
else if (_stricmp (Topic, "performance") == 0) {
help_text =
"systrack /performance \n"
" \n"
" \n";
}
else if (_stricmp (Topic, "trackprocess") == 0) {
help_text =
"systrack /trackprocess \n"
" \n"
" \n";
}
else if (_stricmp (Topic, "trackprocessid") == 0) {
help_text =
"systrack /system \n"
" \n"
" \n";
}
else if (_stricmp (Topic, "trackpool") == 0) {
help_text =
"systrack /trackpool \n"
" \n"
" \n";
}
else if (_stricmp (Topic, "trackpooltag") == 0) {
help_text =
"systrack /trackpooltag \n"
" \n"
" \n";
}
else {
printf ("Unknown help topic %s \n", Topic);
exit (1);
}
printf (help_text, VERSION_INFORMATION_VERSION);
exit (1);
}
//
// Function:
//
// main
//
// Description:
//
// ?, -?, /? - print help information.
// -version - print version information
//
// default (system, process, pool)
// /process
// /stack
// /system
// /performance
// /pool
// /pooldetailed
//
//
void _cdecl
main (int argc, char *argv[])
{
if (argc == 2 && _stricmp (argv[1], "?") == 0)
Help ();
else if (argc == 2 && _stricmp (argv[1], "/?") == 0)
Help ();
else if (argc == 2 && _stricmp (argv[1], "-?") == 0)
Help ();
else if (argc == 2 && _stricmp (argv[1], "-h") == 0)
Help ();
else if (argc == 2 && _stricmp (argv[1], "/h") == 0)
Help ();
// if (argc == 3 && _stricmp (argv[1], "/help") == 0)
// DetailedHelp (argv[2]);
if (argc == 2 && _stricmp (argv[1], "-version") == 0)
dump_version_information ();
try
{
//
// Here comes the code ...
//
PrintCurrentTime ();
if (argc == 1)
{
//
// <> default options
//
// PrintSystemBasicInformation ();
PrintSystemProcessInformation (TRUE);
// PrintSystemPoolTagInformation ();
}
else if (argc == 2 && _stricmp (argv[1], "/stack") == 0)
{
//
// /stack option
//
PrintProcessStackInformation ();
}
else if (argc == 2 && _stricmp (argv[1], "/all") == 0)
{
//
// /all option
//
PrintSystemBasicInformation ();
PrintSystemPerformanceInformation ();
PrintSystemProcessInformation (FALSE);
PrintSystemPoolTagInformation ();
PrintSystemPoolDetailedInformation ();
}
else if (argc == 4 && _stricmp (argv[1], "/trackpool") == 0)
{
//
// /trackpool PERIOD DELTA
//
ULONG Delta;
ULONG Period;
Period = atoi (argv[2]);
Delta = atoi (argv[3]);
if (Delta == 0)
Delta = 8192;
if (Period == 0)
Period = 1000;
SystemPoolTrack (Period, Delta);
}
else if (argc == 5 && _stricmp (argv[1], "/trackpooltag") == 0)
{
//
// /trackpooltag PERIOD PATTERN DELTA
//
ULONG Delta;
ULONG Period;
UCHAR * Pattern;
Period = atoi (argv[2]);
Pattern = (UCHAR *)(argv[3]);
Delta = atoi (argv[4]);
if (Delta == 0)
Delta = 8192;
if (Period == 0)
Period = 1000;
SystemPoolTagTrack (Period, Pattern, Delta);
}
else if (argc == 8 && _stricmp (argv[1], "/trackprocess") == 0)
{
//
// /trackprocess PERIOD HANDLES THREADS WSET VSIZE PFILE
//
ULONG DeltaHandles;
ULONG DeltaThreads;
ULONG DeltaWorkingSet;
SIZE_T DeltaVirtualSize;
SIZE_T DeltaPagefileUsage;
ULONG Period;
Period = atoi (argv[2]);
DeltaHandles = atoi (argv[3]);
DeltaThreads = atoi (argv[4]);
DeltaWorkingSet = atoi (argv[5]);
DeltaVirtualSize = atoi (argv[6]);
DeltaPagefileUsage = atoi (argv[7]);
if (Period == 0)
Period = 1000;
if (DeltaHandles == 0)
DeltaHandles = 32;
if (DeltaThreads == 0)
DeltaThreads = 8;
if (DeltaWorkingSet == 0)
DeltaWorkingSet = 0x100000;
if (DeltaVirtualSize == 0)
DeltaVirtualSize = 0x100000;
if (DeltaPagefileUsage == 0)
DeltaPagefileUsage = 0x100000;
SystemProcessTrack (Period,
DeltaHandles, DeltaThreads, DeltaWorkingSet,
DeltaVirtualSize, DeltaPagefileUsage);
}
else if (argc == 9 && _stricmp (argv[1], "/trackprocessid") == 0)
{
//
// /trackprocessid PERIOD ID HANDLES THREADS WSET VSIZE PFILE
//
ULONG ProcessId;
ULONG DeltaHandles;
ULONG DeltaThreads;
ULONG DeltaWorkingSet;
SIZE_T DeltaVirtualSize;
SIZE_T DeltaPagefileUsage;
ULONG Period;
Period = atoi (argv[2]);
ProcessId = atoi (argv[3]);
DeltaHandles = atoi (argv[4]);
DeltaThreads = atoi (argv[5]);
DeltaWorkingSet = atoi (argv[6]);
DeltaVirtualSize = atoi (argv[7]);
DeltaPagefileUsage = atoi (argv[8]);
if (Period == 0)
Period = 1000;
if (ProcessId == 0) {
printf ("Bad process id %s\n", argv[3]);
exit (1);
}
if (DeltaHandles == 0)
DeltaHandles = 32;
if (DeltaThreads == 0)
DeltaThreads = 8;
if (DeltaWorkingSet == 0)
DeltaWorkingSet = 0x100000;
if (DeltaVirtualSize == 0)
DeltaVirtualSize = 0x100000;
if (DeltaPagefileUsage == 0)
DeltaPagefileUsage = 0x100000;
SystemProcessIdTrack (Period, ProcessId,
DeltaHandles, DeltaThreads, DeltaWorkingSet,
DeltaVirtualSize, DeltaPagefileUsage);
}
else if (argc == 4 && _stricmp (argv[1], "/trackavailablepages") == 0)
{
//
// /trackavailablepages PERIOD DELTA
//
LONG Delta;
ULONG Period;
Period = atoi (argv[2]);
Delta = atoi (argv[3]);
if (Period == 0)
Period = 1000;
if (Delta == 0)
Delta = 100;
//
// We track decreasing values therefore delta should be negative.
//
TrackPerformanceCounter (argv[1], TRACK_AVAILABLE_PAGES, Period, -Delta);
}
else if (argc == 4 && _stricmp (argv[1], "/trackcommittedpages") == 0)
{
//
// /trackcommittedpages PERIOD DELTA
//
LONG Delta;
ULONG Period;
Period = atoi (argv[2]);
Delta = atoi (argv[3]);
if (Period == 0)
Period = 1000;
if (Delta == 0)
Delta = 100;
//
// We track increasing values therefore delta should be positive.
//
TrackPerformanceCounter (argv[1], TRACK_COMMITTED_PAGES, Period, Delta);
}
else if (argc == 4 && _stricmp (argv[1], "/trackcommitlimit") == 0)
{
//
// /trackcommitlimit PERIOD DELTA
//
LONG Delta;
ULONG Period;
Period = atoi (argv[2]);
Delta = atoi (argv[3]);
if (Period == 0)
Period = 1000;
if (Delta == 0)
Delta = 100;
//
// We track increasing values therefore delta should be positive.
//
TrackPerformanceCounter (argv[1], TRACK_COMMIT_LIMIT, Period, Delta);
}
else if (argc == 4 && _stricmp (argv[1], "/trackpagefaultcount") == 0)
{
//
// /trackpagefaultcount PERIOD DELTA
//
LONG Delta;
ULONG Period;
Period = atoi (argv[2]);
Delta = atoi (argv[3]);
if (Period == 0)
Period = 1000;
if (Delta == 0)
Delta = 100;
//
// We track increasing values therefore delta should be positive.
//
TrackPerformanceCounter (argv[1], TRACK_PAGE_FAULT_COUNT, Period, Delta);
}
else if (argc == 4 && _stricmp (argv[1], "/tracksystemcalls") == 0)
{
//
// /tracksystemcalls PERIOD DELTA
//
LONG Delta;
ULONG Period;
Period = atoi (argv[2]);
Delta = atoi (argv[3]);
if (Period == 0)
Period = 1000;
if (Delta == 0)
Delta = 100;
//
// We track increasing values therefore delta should be positive.
//
TrackPerformanceCounter (argv[1], TRACK_SYSTEM_CALLS, Period, Delta);
}
else if (argc == 4 && _stricmp (argv[1], "/tracktotalsystemdriverpages") == 0)
{
//
// /tracktotalsystemdriverpages PERIOD DELTA
//
LONG Delta;
ULONG Period;
Period = atoi (argv[2]);
Delta = atoi (argv[3]);
if (Period == 0)
Period = 1000;
if (Delta == 0)
Delta = 100;
//
// We track increasing values therefore delta should be positive.
//
TrackPerformanceCounter (argv[1], TRACK_TOTAL_SYSTEM_DRIVER_PAGES, Period, Delta);
}
else if (argc == 4 && _stricmp (argv[1], "/tracktotalsystemcodepages") == 0)
{
//
// /tracktotalsystemcodepages PERIOD DELTA
//
LONG Delta;
ULONG Period;
Period = atoi (argv[2]);
Delta = atoi (argv[3]);
if (Period == 0)
Period = 1000;
if (Delta == 0)
Delta = 100;
//
// We track increasing values therefore delta should be positive.
//
TrackPerformanceCounter (argv[1], TRACK_TOTAL_SYSTEM_CODE_PAGES, Period, Delta);
}
else
{
for (int Count = 1; Count < argc; Count++)
{
if (_stricmp (argv[Count], "/system") == 0)
PrintSystemBasicInformation ();
else if (_stricmp (argv[Count], "/performance") == 0)
PrintSystemPerformanceInformation ();
else if (_stricmp (argv[Count], "/process") == 0)
PrintSystemProcessInformation (TRUE);
else if (_stricmp (argv[Count], "/pool") == 0)
PrintSystemPoolTagInformation ();
else if (_stricmp (argv[Count], "/pooldetailed") == 0)
PrintSystemPoolDetailedInformation ();
else
Help ();
}
}
}
catch (...)
{
printf ("unexpected exception ...\n");
fflush (stdout);
exit (1);
}
exit (0);
}
//
// Function:
//
// PrintCurrentTime
//
// Description:
//
// Prints current time, machine name, etc.
//
//
void PrintCurrentTime ()
{
TCHAR MachineName [32];
LPCTSTR TimeString;
time_t Time;
DWORD Result;
if (GetEnvironmentVariable (TEXT("COMPUTERNAME"), MachineName, sizeof MachineName) == 0)
strcpy (MachineName, "unknown");
time (&Time);
TimeString = asctime (localtime (&Time));
printf ("Systrack - System resource tracking, %s\n", VERSION_INFORMATION_VERSION);
printf ("Machine: %s\n", MachineName);
printf ("Time: %s\n", TimeString);
fflush( stdout );
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//
// Macro:
//
// _dump_, _dump_quad_ (object, field)
//
// Description:
//
// Handy macros to dump the fields of a structure.
//
#define _dump_(object,field) printf ("%-30s %08X (%u)\n", #field, (ULONG)(object->field), (ULONG)(object->field))
#define _dump_quad_(object,field) printf ("%-30s %I64X (%I64u)\n", #field, (object->field.QuadPart), (object->field.QuadPart))
//
// Local:
//
// InfoBuffer
//
// Description:
//
// Large enough structure to hold theinformation returned by
// NtQuerySystemInformation. I've opted for this solution because
// systrack can run under heavy stress conditions and we do not
// to allocate big chunks of memory dynamically in such a situation.
//
// Note. If we decide to multithread the application we will need a
// critical section to protect the information buffer.
// CRITICAL_SECTION InfoBufferLock;
//
static TCHAR InfoBuffer [0x40000];
//
// Local:
//
// PoolTagInformationBuffer
//
// Description:
//
// Buffer for NtQuerySystemInformation( SystemPoolTagInformation ).
// Its size is grown by QueryPoolTagInformationIterative if necessary.
// The length of the buffer is held in PoolTagInformationBufferLength.
//
static TCHAR *PoolTagInformationBuffer = NULL;
//
// Local:
//
// PoolTagInformationBufferLength
//
// Description:
//
// The current length of PoolTagInformationBuffer.
//
size_t PoolTagInformationBufferLength = 0;
//
// Function:
//
// QueryPoolTagInformationIterative
//
// Description:
//
// ARGUMENTS:
//
// CurrentBuffer - a pointer to the buffer currently used for
// NtQuerySystemInformation( SystemPoolTagInformation ).
// It will be allocated if NULL or its size grown
// if necessary.
//
// CurrentBufferSize - a pointer to a variable that holds the current
// size of the buffer.
//
// RETURNS:
//
// NTSTATUS returned by NtQuerySystemInformation or
// STATUS_INSUFFICIENT_RESOURCES if the buffer must grow and the
// heap allocation for it fails.
//
NTSTATUS
QueryPoolTagInformationIterative(
TCHAR **CurrentBuffer,
size_t *CurrentBufferSize
)
{
size_t NewBufferSize;
NTSTATUS ReturnedStatus = STATUS_SUCCESS;
if( CurrentBuffer == NULL || CurrentBufferSize == NULL ) {
return STATUS_INVALID_PARAMETER;
}
if( *CurrentBufferSize == 0 || *CurrentBuffer == NULL ) {
//
// there is no buffer allocated yet
//
NewBufferSize = sizeof( TCHAR ) * BUFFER_SIZE_STEP;
*CurrentBuffer = (TCHAR *) malloc( NewBufferSize );
if( *CurrentBuffer != NULL ) {
*CurrentBufferSize = NewBufferSize;
} else {
//
// insufficient memory
//
ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
//
// iterate by buffer's size
//
while( *CurrentBuffer != NULL ) {
ReturnedStatus = NtQuerySystemInformation (
SystemPoolTagInformation,
*CurrentBuffer,
(ULONG)*CurrentBufferSize,
NULL );
if( ! NT_SUCCESS(ReturnedStatus) ) {
//
// free the current buffer
//
free( *CurrentBuffer );
*CurrentBuffer = NULL;
if (ReturnedStatus == STATUS_INFO_LENGTH_MISMATCH) {
//
// try with a greater buffer size
//
NewBufferSize = *CurrentBufferSize + BUFFER_SIZE_STEP;
*CurrentBuffer = (TCHAR *) malloc( NewBufferSize );
if( *CurrentBuffer != NULL ) {
//
// allocated new buffer
//
*CurrentBufferSize = NewBufferSize;
} else {
//
// insufficient memory
//
ReturnedStatus = STATUS_INSUFFICIENT_RESOURCES;
*CurrentBufferSize = 0;
}
} else {
*CurrentBufferSize = 0;
}
} else {
//
// NtQuerySystemInformation returned success
//
break;
}
}
return ReturnedStatus;
}
//
// Function:
//
// QuerySystemPoolTagInformation
//
// Description:
//
// Fills InfoBuffer with SystemPoolTagInformation and returns
// a pointer to it.
//
PVOID
QuerySystemPoolTagInformation ()
{
NTSTATUS Status;
ULONG RealLength;
//
// SystemPoolTagInformation
//
Status = QueryPoolTagInformationIterative(
&PoolTagInformationBuffer,
&PoolTagInformationBufferLength );
if (! NT_SUCCESS(Status))
printf ("NtQuerySystemInformation(pooltag): error %08X\n",
Status);
return NT_SUCCESS(Status) ? PoolTagInformationBuffer : NULL;
}
//
// Function:
//
// QuerySystemProcessInformation
//
// Description:
//
// Fills InfoBuffer with SystemProcessInformation and returns
// a pointer to it.
//
PVOID
QuerySystemProcessInformation ()
{
NTSTATUS Status;
ULONG RealLength;
//
// SystemProcessInformation
//
Status = NtQuerySystemInformation (
SystemProcessInformation,
InfoBuffer,
sizeof InfoBuffer,
&RealLength);
if (! NT_SUCCESS(Status))
printf ("NtQuerySystemInformation(process): error %08X\n",
Status);
return NT_SUCCESS(Status) ? InfoBuffer : NULL;
}
//
// Function:
//
// QuerySystemPerformanceInformation
//
// Description:
//
// Fills InfoBuffer with SystemPerformanceInformation and returns
// a pointer to it.
//
PVOID
QuerySystemPerformanceInformation ()
{
NTSTATUS Status;
ULONG RealLength;
//
// SystemPerformanceInformation
//
Status = NtQuerySystemInformation (
SystemPerformanceInformation,
InfoBuffer,
sizeof InfoBuffer,
&RealLength);
if (! NT_SUCCESS(Status))
printf ("NtQuerySystemInformation(performance): error %08X\n",
Status);
return NT_SUCCESS(Status) ? InfoBuffer : NULL;
}
//
// Function:
//
// PrintSystemBasicInformation
//
// Description:
//
// Prints SystemPerformanceInformation.
//
//
void PrintSystemBasicInformation ()
{
NTSTATUS Status;
ULONG RealLength;
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
printf ("System basic information \n");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
fflush( stdout );
//
// SystemBasicInformation
//
Status = NtQuerySystemInformation (
SystemBasicInformation,
InfoBuffer,
sizeof (SYSTEM_BASIC_INFORMATION),
&RealLength);
if (! NT_SUCCESS(Status))
{
printf ("NtQuerySystemInformation(Basic): error %08X\n", Status);
return;
}
{
PSYSTEM_BASIC_INFORMATION Info = (PSYSTEM_BASIC_INFORMATION)InfoBuffer;
_dump_(Info, PageSize);
_dump_(Info, NumberOfPhysicalPages);
_dump_(Info, LowestPhysicalPageNumber);
_dump_(Info, HighestPhysicalPageNumber);
_dump_(Info, AllocationGranularity);
_dump_(Info, MinimumUserModeAddress);
_dump_(Info, MaximumUserModeAddress);
_dump_(Info, ActiveProcessorsAffinityMask);
_dump_(Info, NumberOfProcessors);
}
}
//
// Function:
//
// PrintSystemPerformanceInformation
//
// Description:
//
// Prints systemPerformanceInformation.
//
void PrintSystemPerformanceInformation ()
{
NTSTATUS Status;
ULONG RealLength;
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
printf ("System performance information \n");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
fflush( stdout );
//
// SystemPerformanceInformation
//
Status = NtQuerySystemInformation (
SystemPerformanceInformation,
InfoBuffer,
sizeof (SYSTEM_PERFORMANCE_INFORMATION),
&RealLength);
if (! NT_SUCCESS(Status))
{
printf ("NtQuerySystemInformation(Performance): error %08X\n", Status);
return;
}
{
PSYSTEM_PERFORMANCE_INFORMATION Info = (PSYSTEM_PERFORMANCE_INFORMATION)InfoBuffer;
_dump_quad_ (Info, IdleProcessTime);
_dump_quad_ (Info, IoReadTransferCount);
_dump_quad_ (Info, IoWriteTransferCount);
_dump_quad_ (Info, IoOtherTransferCount);
_dump_ (Info, IoReadOperationCount);
_dump_ (Info, IoWriteOperationCount);
_dump_ (Info, IoOtherOperationCount);
_dump_ (Info, AvailablePages);
_dump_ (Info, CommittedPages);
_dump_ (Info, CommitLimit);
_dump_ (Info, PeakCommitment);
_dump_ (Info, PageFaultCount);
_dump_ (Info, CopyOnWriteCount);
_dump_ (Info, TransitionCount);
_dump_ (Info, CacheTransitionCount);
_dump_ (Info, DemandZeroCount);
_dump_ (Info, PageReadCount);
_dump_ (Info, PageReadIoCount);
_dump_ (Info, CacheReadCount);
_dump_ (Info, CacheIoCount);
_dump_ (Info, DirtyPagesWriteCount);
_dump_ (Info, DirtyWriteIoCount);
_dump_ (Info, MappedPagesWriteCount);
_dump_ (Info, MappedWriteIoCount);
_dump_ (Info, PagedPoolPages);
_dump_ (Info, NonPagedPoolPages);
_dump_ (Info, PagedPoolAllocs);
_dump_ (Info, PagedPoolFrees);
_dump_ (Info, NonPagedPoolAllocs);
_dump_ (Info, NonPagedPoolFrees);
_dump_ (Info, FreeSystemPtes);
_dump_ (Info, ResidentSystemCodePage);
_dump_ (Info, TotalSystemDriverPages);
_dump_ (Info, TotalSystemCodePages);
_dump_ (Info, NonPagedPoolLookasideHits);
_dump_ (Info, PagedPoolLookasideHits);
#if 0
_dump_ (Info, Spare3Count);
#endif
_dump_ (Info, ResidentSystemCachePage);
_dump_ (Info, ResidentPagedPoolPage);
_dump_ (Info, ResidentSystemDriverPage);
_dump_ (Info, CcFastReadNoWait);
_dump_ (Info, CcFastReadWait);
_dump_ (Info, CcFastReadResourceMiss);
_dump_ (Info, CcFastReadNotPossible);
_dump_ (Info, CcFastMdlReadNoWait);
_dump_ (Info, CcFastMdlReadWait);
_dump_ (Info, CcFastMdlReadResourceMiss);
_dump_ (Info, CcFastMdlReadNotPossible);
_dump_ (Info, CcMapDataNoWait);
_dump_ (Info, CcMapDataWait);
_dump_ (Info, CcMapDataNoWaitMiss);
_dump_ (Info, CcMapDataWaitMiss);
_dump_ (Info, CcPinMappedDataCount);
_dump_ (Info, CcPinReadNoWait);
_dump_ (Info, CcPinReadWait);
_dump_ (Info, CcPinReadNoWaitMiss);
_dump_ (Info, CcPinReadWaitMiss);
_dump_ (Info, CcCopyReadNoWait);
_dump_ (Info, CcCopyReadWait);
_dump_ (Info, CcCopyReadNoWaitMiss);
_dump_ (Info, CcCopyReadWaitMiss);
_dump_ (Info, CcMdlReadNoWait);
_dump_ (Info, CcMdlReadWait);
_dump_ (Info, CcMdlReadNoWaitMiss);
_dump_ (Info, CcMdlReadWaitMiss);
_dump_ (Info, CcReadAheadIos);
_dump_ (Info, CcLazyWriteIos);
_dump_ (Info, CcLazyWritePages);
_dump_ (Info, CcDataFlushes);
_dump_ (Info, CcDataPages);
_dump_ (Info, ContextSwitches);
_dump_ (Info, FirstLevelTbFills);
_dump_ (Info, SecondLevelTbFills);
_dump_ (Info, SystemCalls);
}
}
//
// Function:
//
// PrintSystemProcessInformation
//
// Description:
//
// Prints SystemProcessInformation.
//
// Details:
//
// These are the fields of a SYSTEM_PROCESS_INFORMATION structure:
//
// ULONG NextEntryOffset;
// ULONG NumberOfThreads;
// LARGE_INTEGER SpareLi1;
// LARGE_INTEGER SpareLi2;
// LARGE_INTEGER SpareLi3;
// LARGE_INTEGER CreateTime;
// LARGE_INTEGER UserTime;
// LARGE_INTEGER KernelTime;
// UNICODE_STRING ImageName;
// KPRIORITY BasePriority;
// HANDLE UniqueProcessId;
// HANDLE InheritedFromUniqueProcessId;
// ULONG HandleCount;
// ULONG SessionId;
// ULONG SpareUl3;
// SIZE_T PeakVirtualSize;
// SIZE_T VirtualSize;
// ULONG PageFaultCount;
// ULONG PeakWorkingSetSize;
// ULONG WorkingSetSize;
// SIZE_T QuotaPeakPagedPoolUsage;
// SIZE_T QuotaPagedPoolUsage;
// SIZE_T QuotaPeakNonPagedPoolUsage;
// SIZE_T QuotaNonPagedPoolUsage;
// SIZE_T PagefileUsage;
// SIZE_T PeakPagefileUsage;
// SIZE_T PrivatePageCount;
// LARGE_INTEGER ReadOperationCount;
// LARGE_INTEGER WriteOperationCount;
// LARGE_INTEGER OtherOperationCount;
// LARGE_INTEGER ReadTransferCount;
// LARGE_INTEGER WriteTransferCount;
// LARGE_INTEGER OtherTransferCount;
//
void PrintSystemProcessInformation (
BOOL ShortDump)
{
NTSTATUS Status;
ULONG RealLength;
SYSTEM_BASIC_INFORMATION SysInfo;
BOOL FinishNextTime = FALSE;
if (ShortDump)
{
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - -\n");
printf ("System process information \n");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - -\n");
}
else
{
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
printf ("System process information \n");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
}
fflush( stdout );
//
// SystemBasicInformation
//
Status = NtQuerySystemInformation (
SystemBasicInformation,
&SysInfo,
sizeof (SysInfo),
&RealLength);
if (! NT_SUCCESS(Status))
{
printf ("NtQuerySystemInformation(Basic): error %08X\n", Status);
return;
}
//
// SystemProcessInformation
//
Status = NtQuerySystemInformation (
SystemProcessInformation,
InfoBuffer,
sizeof InfoBuffer,
&RealLength);
if (! NT_SUCCESS(Status))
{
printf ("NtQuerySystemInformation(Process): error %08X\n", Status);
return;
}
{
PSYSTEM_PROCESS_INFORMATION Info = (PSYSTEM_PROCESS_INFORMATION)InfoBuffer;
if (ShortDump)
{
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-8s %-5s %-5s %-6s %-5s %-5s %-5s\n",
"Process",
"Id",
"Sess",
"Pri",
"Thrds",
"Faults",
"Handles",
"Utime",
"Ktime",
"Wset",
"Vsize",
"Pfile",
"I/O");
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-8s %-5s %-5s %-6s %-5s %-5s %-5s\n",
"",
"",
"",
"",
"",
"",
"",
"%",
"%",
"pages",
"Mb",
"Mb",
"x1000");
}
else
{
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-8s %-5s %-5s %-6s %-5s %-5s %-5s %-5s %-5s\n",
"Process",
"Id",
"Sess",
"Pri",
"Thrds",
"Faults",
"Handles",
"Utime",
"Ktime",
"Wset",
"Vsize",
"Pfile",
"I/O",
"Npool",
"Ppool");
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-8s %-5s %-5s %-6s %-5s %-5s %-5s %-5s %-5s\n",
"",
"",
"",
"",
"",
"",
"",
"%",
"%",
"pages",
"Mb",
"Mb",
"x1000",
"Mb",
"Mb");
}
if (ShortDump)
{
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - -\n");
}
else
{
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
}
fflush( stdout );
for (FinishNextTime = FALSE ;
FinishNextTime == FALSE;
Info = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)Info + Info->NextEntryOffset))
{
if (Info->NextEntryOffset == 0)
FinishNextTime = TRUE;
//
// User time vs Kernel time.
//
ULONG UserPercent, KernelPercent;
UserPercent = (ULONG)((Info->UserTime.QuadPart) * 100
/ (Info->UserTime.QuadPart + Info->KernelTime.QuadPart));
KernelPercent = 100 - UserPercent;
//
// I/O total count.
//
LARGE_INTEGER IoTotalCount;
IoTotalCount.QuadPart = Info->ReadOperationCount.QuadPart
+ Info->WriteOperationCount.QuadPart
+ Info->OtherOperationCount.QuadPart;
IoTotalCount.QuadPart /= 1000;
//
// Image name (special case the idle process).
//
if (Info->ImageName.Buffer == NULL)
printf ("%-15s ", "Idle");
else
printf ("%-15ws ", Info->ImageName.Buffer);
//
// Print the stuff.
//
if (ShortDump)
{
printf ("%-5I64u %-5u %-4u %-5u %-8u %-8u %-5u %-5u %-6u %-5u %-5u %-5I64u\n",
(ULONG64)((ULONG_PTR)(Info->UniqueProcessId)),
Info->SessionId,
Info->BasePriority,
Info->NumberOfThreads,
Info->PageFaultCount,
Info->HandleCount,
UserPercent,
KernelPercent,
Info->WorkingSetSize / SysInfo.PageSize,
Info->VirtualSize / 0x100000,
Info->PagefileUsage / 0x100000,
(IoTotalCount.QuadPart));
}
else
{
printf ("%-5I64u %-5u %-4u %-5u %-8u %-8u %-5u %-5u %-6u %-5u %-5u %-5I64u %-5u %-5u\n",
(ULONG64)((ULONG_PTR)(Info->UniqueProcessId)),
Info->SessionId,
Info->BasePriority,
Info->NumberOfThreads,
Info->PageFaultCount,
Info->HandleCount,
UserPercent,
KernelPercent,
Info->WorkingSetSize / SysInfo.PageSize,
Info->VirtualSize / 0x100000,
Info->PagefileUsage / 0x100000,
(IoTotalCount.QuadPart),
Info->QuotaNonPagedPoolUsage / 0x100000,
Info->QuotaPagedPoolUsage / 0x100000);
}
fflush( stdout );
}
}
}
//
// Function:
//
// PrintSystemPoolDetailedInformation
//
// Description:
//
// Prints systemNonPagedPoolInformation and systemPagedPoolInformation.
// The function returns something meaningful only on checked builds.
//
// typedef struct _SYSTEM_POOL_ENTRY {
// BOOLEAN Allocated;
// BOOLEAN Spare0;
// USHORT AllocatorBackTraceIndex;
// ULONG Size;
// union {
// UCHAR Tag[4];
// ULONG TagUlong;
// PVOID ProcessChargedQuota;
// };
// } SYSTEM_POOL_ENTRY, *PSYSTEM_POOL_ENTRY;
//
// typedef struct _SYSTEM_POOL_INFORMATION {
// SIZE_T TotalSize;
// PVOID FirstEntry;
// USHORT EntryOverhead;
// BOOLEAN PoolTagPresent;
// BOOLEAN Spare0;
// ULONG NumberOfEntries;
// SYSTEM_POOL_ENTRY Entries[1];
// } SYSTEM_POOL_INFORMATION, *PSYSTEM_POOL_INFORMATION;
//
void PrintSystemPoolDetailedInformation ()
{
NTSTATUS Status;
ULONG RealLength;
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
printf ("System pool detailed information \n");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
fflush( stdout );
//
// SystemPoolInformation
//
Status = NtQuerySystemInformation (
SystemNonPagedPoolInformation,
InfoBuffer,
sizeof InfoBuffer,
&RealLength);
if (! NT_SUCCESS(Status))
{
printf ("NtQuerySystemInformation(NonPagedPool): error %08X\n", Status);
return;
}
{
ULONG Index;
PSYSTEM_POOL_INFORMATION Info = (PSYSTEM_POOL_INFORMATION)InfoBuffer;
for (Index = 0; Index < Info->NumberOfEntries; Index++)
{
if (Index != 0 && Index%5 == 0)
printf ("\n");
printf ("%c%c%c%c %-5u ",
Info->Entries[Index].Tag[0],
Info->Entries[Index].Tag[1],
Info->Entries[Index].Tag[2],
Info->Entries[Index].Tag[3],
Info->Entries[Index].Size);
}
fflush( stdout );
}
}
//
// Function:
//
// PrintSystemPoolTagInformation
//
// Description:
//
// Prints SystemPoolTagInformation.
//
// typedef struct _SYSTEM_POOLTAG {
// union {
// UCHAR Tag[4];
// ULONG TagUlong;
// };
// ULONG PagedAllocs;
// ULONG PagedFrees;
// SIZE_T PagedUsed;
// ULONG NonPagedAllocs;
// ULONG NonPagedFrees;
// SIZE_T NonPagedUsed;
// } SYSTEM_POOLTAG, *PSYSTEM_POOLTAG;
//
// typedef struct _SYSTEM_POOLTAG_INFORMATION {
// ULONG Count;
// SYSTEM_POOLTAG TagInfo[1];
// } SYSTEM_POOLTAG_INFORMATION, *PSYSTEM_POOLTAG_INFORMATION;
//
void PrintSystemPoolTagInformation ()
{
NTSTATUS Status;
ULONG RealLength;
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
printf ("System pool tag information \n");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
printf ("%-4s %-8s %-8s %-8s %-8s %-8s %-8s\n",
"Tag",
"NP used", "P used",
"NP alloc", "NP free",
"P alloc", "P free");
printf ("%-4s %-8s %-8s %-8s %-8s %-8s %-8s\n",
"",
"x bytes", "x bytes",
"x ops", "x ops",
"x ops", "x ops");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - ");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
fflush( stdout );
//
// SystemPoolTagInformation
//
Status = NtQuerySystemInformation (
SystemPoolTagInformation,
InfoBuffer,
sizeof InfoBuffer,
&RealLength);
if (! NT_SUCCESS(Status))
{
printf ("NtQuerySystemInformation(PoolTag): error %08X\n", Status);
return;
}
{
ULONG Index;
PSYSTEM_POOLTAG_INFORMATION Info = (PSYSTEM_POOLTAG_INFORMATION)InfoBuffer;
for (Index = 0; Index < Info->Count; Index++)
{
printf ("%c%c%c%c %-8u %-8u %-8u %-8u %-8u %-8u\n",
Info->TagInfo[Index].Tag[0],
Info->TagInfo[Index].Tag[1],
Info->TagInfo[Index].Tag[2],
Info->TagInfo[Index].Tag[3],
Info->TagInfo[Index].NonPagedUsed,
Info->TagInfo[Index].PagedUsed,
Info->TagInfo[Index].NonPagedAllocs,
Info->TagInfo[Index].NonPagedFrees,
Info->TagInfo[Index].PagedAllocs,
Info->TagInfo[Index].PagedFrees);
}
fflush( stdout );
}
}
//
// Function:
//
// PrintProcessStackInformation
//
// Description:
//
// Prints stack usage information for each process.
//
BOOL
ComputeMaxStackInProcess (
DWORD Pid,
PSIZE_T MaxSize,
PSIZE_T TotalSize);
VOID
PrintProcessStackInformation (
VOID
)
{
NTSTATUS Status;
ULONG RealLength;
SYSTEM_BASIC_INFORMATION SysInfo;
BOOL FinishNextTime = FALSE;
BOOL ErrorsFound = FALSE;
SIZE_T MaxStack = 0;
SIZE_T TotalStack = 0;
BOOLEAN WasEnabled;
printf ("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
printf ("Process stack information \n");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
//
// SystemBasicInformation
//
Status = NtQuerySystemInformation (
SystemBasicInformation,
&SysInfo,
sizeof (SysInfo),
&RealLength);
if (! NT_SUCCESS(Status)) {
printf ("NtQuerySystemInformation(Basic): error %08X\n", Status);
return;
}
//
// SystemProcessInformation
//
Status = NtQuerySystemInformation (SystemProcessInformation,
InfoBuffer,
sizeof InfoBuffer,
&RealLength);
if (! NT_SUCCESS(Status)) {
printf ("NtQuerySystemInformation(Process): error %08X\n", Status);
return;
}
//
// Get debug privilege.
//
Status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,
TRUE,
FALSE,
&WasEnabled);
if (! NT_SUCCESS(Status)) {
printf("Failed to enable debug privilege (%X) \n", Status);
}
{
PSYSTEM_PROCESS_INFORMATION Info = (PSYSTEM_PROCESS_INFORMATION)InfoBuffer;
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-5s %-5s\n",
"",
"",
"",
"",
"",
"",
"Total",
"Max");
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-5s %-5s\n",
"Process",
"Id",
"Sess",
"Pri",
"Thrds",
"Handles",
"stack",
"stack");
printf ("%-15s %-5s %-5s %-4s %-5s %-8s %-5s %-5s\n",
"",
"",
"",
"",
"",
"",
"Kb",
"Kb");
printf ("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
for (FinishNextTime = FALSE ;
FinishNextTime == FALSE;
Info = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)Info + Info->NextEntryOffset)) {
if (Info->NextEntryOffset == 0)
FinishNextTime = TRUE;
//
// User time vs Kernel time.
//
ULONG UserPercent, KernelPercent;
UserPercent = (ULONG)((Info->UserTime.QuadPart) * 100
/ (Info->UserTime.QuadPart + Info->KernelTime.QuadPart));
KernelPercent = 100 - UserPercent;
//
// I/O total count.
//
LARGE_INTEGER IoTotalCount;
IoTotalCount.QuadPart = Info->ReadOperationCount.QuadPart
+ Info->WriteOperationCount.QuadPart
+ Info->OtherOperationCount.QuadPart;
IoTotalCount.QuadPart /= 1000;
//
// Image name (special case the idle process).
//
if (Info->ImageName.Buffer == NULL) {
printf ("%-15s ", "Idle");
}
else {
printf ("%-15ws ", Info->ImageName.Buffer);
}
//
// Compute stack info by iterating all threads in the process.
//
GetProcessStackInfo (Info, &MaxStack, &TotalStack, &ErrorsFound);
//
// Print the stuff.
//
printf ("%-5I64u %-5u %-4u %-5u %-8u %-5u %-5u\n",
(ULONG64)((ULONG_PTR)(Info->UniqueProcessId)),
Info->SessionId,
Info->BasePriority,
Info->NumberOfThreads,
Info->HandleCount,
(ULONG)(TotalStack/1024),
(ULONG)(MaxStack/1024));
}
}
printf(
" \n"
" * Total stack: total committed memory used for stacks by all threads \n"
" in the process. \n"
" * Max stack: the biggest committed stack in the process. \n"
" \n");
}
VOID
GetProcessStackInfo (
PSYSTEM_PROCESS_INFORMATION Info,
PSIZE_T MaxSize,
PSIZE_T TotalSize,
PBOOL ErrorsFound
)
{
ULONG Ti;
HANDLE Id;
HANDLE Thread;
HANDLE Process;
THREAD_BASIC_INFORMATION ThreadInfo;
TEB TebInfo;
SIZE_T BytesRead;
BOOL ReadResult;
NTSTATUS Status;
SIZE_T StackSize;
BOOLEAN WasEnabled;
*MaxSize = 0;
*TotalSize = 0;
*ErrorsFound = FALSE;
//
// Open the process.
//
Process = OpenProcess (PROCESS_VM_READ,
FALSE,
HandleToUlong(Info->UniqueProcessId));
if (Process == FALSE) {
//printf("Failed to open process %p (error %u) \n", Info->UniqueProcessId, GetLastError());
*ErrorsFound = TRUE;
return;
}
//
// Iterate all threads in the process and for each determine the
// thread ID, open the thread and query for TEB address. Finally
// read user mode stack sizes from the TEB.
//
for (Ti = 0; Ti < Info->NumberOfThreads; Ti += 1) {
Id = ((PSYSTEM_THREAD_INFORMATION)(Info + 1) + Ti)->ClientId.UniqueThread;
Thread = OpenThread (THREAD_QUERY_INFORMATION,
FALSE,
HandleToUlong(Id));
if (Thread == NULL) {
//printf("failed to open thread %u \n", GetLastError());
*ErrorsFound = TRUE;
continue;
}
Status = NtQueryInformationThread (Thread,
ThreadBasicInformation,
&ThreadInfo,
sizeof ThreadInfo,
NULL);
if (!NT_SUCCESS(Status)) {
//printf("query thread failed with %X \n", Status);
*ErrorsFound = TRUE;
CloseHandle (Thread);
continue;
}
ReadResult = ReadProcessMemory (Process,
ThreadInfo.TebBaseAddress,
&TebInfo,
sizeof TebInfo,
&BytesRead);
if (ReadResult == FALSE) {
//printf("failed to read teb with %u \n", GetLastError());
*ErrorsFound = TRUE;
CloseHandle (Thread);
continue;
}
StackSize = (SIZE_T)(TebInfo.NtTib.StackBase) - (SIZE_T)(TebInfo.NtTib.StackLimit);
*TotalSize += StackSize;
if (StackSize > *MaxSize) {
*MaxSize = StackSize;
}
CloseHandle (Thread);
}
CloseHandle (Process);
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//
// Function:
//
// DebugMessage
//
// Description:
//
// Printf like function that prints a message into debugger.
//
void __cdecl DebugMessage (char *fmt, ...)
{
va_list prms;
char Buffer [1024];
va_start (prms, fmt);
vsprintf (Buffer, fmt, prms);
OutputDebugString (Buffer);
va_end (prms);
}
//
// end of module: systrack.cxx
//