// // Systrack - System resource tracking // Copyright (c) Microsoft Corporation, 1998 // // // module: systrack.cxx // author: silviuc // created: Mon Nov 09 12:20:41 1998 // #include #include #include #include extern "C" { #include #include #include } #include #include #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 //