/*++ Copyright (c) 1996 Microsoft Corporation Module Name: CPUdump.c Abstract: Modified from PDump.c, a Win32 application to display performance statictics. Author: Ken Reneris Environment: User Mode Revision History: --*/ #include "precomp.h" #include "resource.h" //#include //#include #include "CPUdump.h" #include "gdibench.h" #define INFSIZE 1024 extern HWND hWndMain; extern UCHAR Buffer[]; extern PUCHAR ShortPerfName[MAX_EVENTS]; extern BOOL gfCPUEventMonitor; extern HANDLE hLibrary; // the handle to the NTDLL.DLL loaded in the init GDIBench extern PFNNTAPI pfnNtQuerySystemInformation; // loaded in the init of GDIBench typedef NTSTATUS (NTAPI *PFNNTDEVICEIOCONTROLFILE)(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, PVOID, ULONG); PFNNTDEVICEIOCONTROLFILE pfnNtDeviceIoControlFile; typedef VOID (NTAPI *PFNRTLINITUNICODESTRING)(PUNICODE_STRING, PCWSTR); PFNRTLINITUNICODESTRING pfnRtlInitUnicodeString; typedef NTSTATUS (NTAPI *PFNNTOPENFILE)(PHANDLE, ACCESS_MASK,POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG); PFNNTOPENFILE pfnNtOpenFile; // Global variables ULONGLONG NumberIter; UCHAR NumberOfProcessors; HANDLE DriverHandle; ULONG BufferStart [INFSIZE/4]; ULONG BufferEnd [INFSIZE/4]; // // Selected Display Mode (read from wp2.ini), default set here. // struct { ULONG EventId; PUCHAR ShortName; PUCHAR PerfName; } *Counters; SETEVENT CounterEvent[MAX_EVENTS]; int CPUDumpInit() { if (WINNT_PLATFORM) { pfnNtDeviceIoControlFile = (PFNNTDEVICEIOCONTROLFILE) GetProcAddress(hLibrary,"NtDeviceIoControlFile"); if(pfnNtDeviceIoControlFile==NULL)MessageBox(NULL,"ptr1 NULL","DeviceIOControlFile",MB_OK); pfnRtlInitUnicodeString = (PFNRTLINITUNICODESTRING) GetProcAddress(hLibrary,"RtlInitUnicodeString"); if(pfnRtlInitUnicodeString==NULL)MessageBox(NULL,"ptr2 NULL","InitUnicodeString",MB_OK); pfnNtOpenFile = (PFNNTOPENFILE) GetProcAddress(hLibrary,"NtOpenFile"); if(pfnNtOpenFile==NULL)MessageBox(NULL,"ptr3 NULL","NtOpenFile",MB_OK); } // // Locate pentium perf driver // if (!InitDriver ()) { MessageBox(hWndMain, "pstat.sys is not installed!", "Cannot load PSTAT.SYS", MB_ICONSTOP | MB_OK); return FALSE; // exit the application } // // Initialize supported event list // InitPossibleEventList(); if (!Counters) { MessageBox(hWndMain, "No events to monitor!", "No events to monitor!", MB_ICONSTOP | MB_OK); return FALSE; // exit the application } if (NumberOfProcessors > 1) { MessageBox(hWndMain, "The count will not be correct for more than one CPU", "Warning: More than one CPU detected", MB_ICONWARNING | MB_OK); } /* if (WINNT_PLATFORM) { pfnNtDeviceIoControlFile = (PFNNTDEVICEIOCONTROLFILE) GetProcAddress(hLibrary,"NtDeviceIoControlFile"); if(pfnNtDeviceIoControlFile==NULL)MessageBox(NULL,"ptr1 NULL","DeviceIOControlFile",MB_OK); pfnRtlInitUnicodeString = (PFNRTLINITUNICODESTRING) GetProcAddress(hLibrary,"RtlInitUnicodeString"); if(pfnRtlInitUnicodeString==NULL)MessageBox(NULL,"ptr2 NULL","InitUnicodeString",MB_OK); pfnNtOpenFile = (PFNNTOPENFILE) GetProcAddress(hLibrary,"NtOpenFile"); if(pfnNtOpenFile==NULL)MessageBox(NULL,"ptr3 NULL","NtOpenFile",MB_OK); } */ return TRUE; } // End of CPUDumpInit BOOLEAN InitCPUDump() { BOOLEAN CounterSet; LONG CounterType; ULONG i; CounterSet = 0; for (i=0; iTSC - ProcStart->TSC; ECount = ProcEnd->Counters[eventno] - ProcStart->Counters[eventno]; ProcStart = (pPSTATS) (((PUCHAR) ProcStart) + len); ProcEnd = (pPSTATS) (((PUCHAR) ProcEnd) + len); // for each processor, stsatistics must be printed once // need to solve this later. //(Dump->PerfName)[eventno] = Counters[CounterEvent[eventno].AppReserved].PerfName; //(Dump->ETime)[eventno] = ETime; //(Dump->ECount)[eventno] = ECount; } // for } // if */ if (!ProcessorBreakout || ProcessorTotal) { // // Sum processor's and print it // ProcStart = (pPSTATS) ((PUCHAR) BufferStart + sizeof(ULONG)); ProcEnd = (pPSTATS) ((PUCHAR) BufferEnd + sizeof(ULONG)); ETime = 0; ECount = 0; for (j=0; j < NumberOfProcessors; j++) { ETime = ETime + ProcEnd->TSC; ETime = ETime - ProcStart->TSC; ECount = ECount + ProcEnd->Counters[eventno]; ECount = ECount - ProcStart->Counters[eventno]; ProcStart = (pPSTATS) (((PUCHAR) ProcStart) + len); ProcEnd = (pPSTATS) (((PUCHAR) ProcEnd) + len); } // for (*NewETime) = ETime / NumberIter; (*NewECount) = ECount / NumberIter; } // if } // End BOOLEAN InitDriver () { UNICODE_STRING DriverName; NTSTATUS status; OBJECT_ATTRIBUTES ObjA; IO_STATUS_BLOCK IOSB; SYSTEM_BASIC_INFORMATION BasicInfo; // PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PPerfInfo; // // Init Nt performance interface // pfnNtQuerySystemInformation( SystemBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL ); NumberOfProcessors = BasicInfo.NumberOfProcessors; if (NumberOfProcessors > MAX_PROCESSORS) { return FALSE; } // Also if NumberofProcessors>1 prompt a dialog box, but not stop // the program, since the count will not be accurate. // // Open PStat driver // pfnRtlInitUnicodeString(&DriverName, L"\\Device\\PStat"); InitializeObjectAttributes( &ObjA, &DriverName, OBJ_CASE_INSENSITIVE, 0, 0 ); status = pfnNtOpenFile ( &DriverHandle, // return handle SYNCHRONIZE | FILE_READ_DATA, // desired access &ObjA, // Object &IOSB, // io status block FILE_SHARE_READ | FILE_SHARE_WRITE, // share access FILE_SYNCHRONOUS_IO_ALERT // open options ); return NT_SUCCESS(status) ? TRUE : FALSE; return TRUE; } VOID InitPossibleEventList() { UCHAR buffer[400]; ULONG i, Count; NTSTATUS status; PEVENTID Event; IO_STATUS_BLOCK IOSB; // // Initialize possible counters // // determine how many events there are Event = (PEVENTID) buffer; Count = 0; do { *((PULONG) buffer) = Count; Count += 1; status = pfnNtDeviceIoControlFile( DriverHandle, (HANDLE) NULL, // event (PIO_APC_ROUTINE) NULL, (PVOID) NULL, &IOSB, PSTAT_QUERY_EVENTS, buffer, // input buffer sizeof (buffer), NULL, // output buffer 0 ); } while (NT_SUCCESS(status)); Counters = malloc(sizeof(*Counters) * Count); Count -= 1; for (i=0; i < Count; i++) { *((PULONG) buffer) = i; pfnNtDeviceIoControlFile( DriverHandle, (HANDLE) NULL, // event (PIO_APC_ROUTINE) NULL, (PVOID) NULL, &IOSB, PSTAT_QUERY_EVENTS, buffer, // input buffer sizeof (buffer), NULL, // output buffer 0 ); Counters[i].EventId = Event->EventId; Counters[i].ShortName = _strdup (Event->Buffer); Counters[i].PerfName = _strdup (Event->Buffer + Event->DescriptionOffset); } Counters[i].EventId = 0; Counters[i].ShortName = NULL; Counters[i].PerfName = NULL; } VOID GetInternalStats (PVOID Buffer) { IO_STATUS_BLOCK IOSB; pfnNtDeviceIoControlFile( DriverHandle, (HANDLE) NULL, // event (PIO_APC_ROUTINE) NULL, (PVOID) NULL, &IOSB, PSTAT_READ_STATS, Buffer, // input buffer INFSIZE, NULL, // output buffer 0 ); } VOID SetCounterEncodings (VOID) { IO_STATUS_BLOCK IOSB; pfnNtDeviceIoControlFile( DriverHandle, (HANDLE) NULL, // event (PIO_APC_ROUTINE) NULL, (PVOID) NULL, &IOSB, PSTAT_SET_CESR, CounterEvent, // input buffer sizeof (CounterEvent), NULL, // output buffer 0 ); } BOOLEAN SetCounter (LONG CounterId, ULONG counter) { if (CounterId == -1) { CounterEvent[counter].Active = FALSE; return FALSE; } CounterEvent[counter].EventId = Counters[CounterId].EventId; CounterEvent[counter].AppReserved = (ULONG) CounterId; CounterEvent[counter].Active = TRUE; CounterEvent[counter].UserMode = TRUE; CounterEvent[counter].KernelMode = TRUE; return TRUE; } LONG FindShortName (PSZ name) { LONG i; for (i=0; Counters[i].ShortName; i++) { if (strcmp (Counters[i].ShortName, name) == 0) { return i; } } return -1; }