2025-04-27 07:49:33 -04:00

463 lines
12 KiB
C

/*++
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 <errno.h>
//#include <malloc.h>
#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; i<MAX_EVENTS; i++) {
//
// if the short perfname is not set, set to
// "instruction executed" instead
//
if (ShortPerfName[i] != NULL)
CounterType = FindShortName(ShortPerfName[i]);
else {
//
// if there is no short name at all, hardcode
// "instruction executed".
//
ShortPerfName[i] = _strdup("iexec");
CounterType = FindShortName("iexec");
}
if (CounterType == -1) {
MessageBox(hWndMain,
"Counter dtlbmiss not found",
"Failed to find CPU counters",
MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
CounterSet |= SetCounter (CounterType, i);
}
if (!CounterSet) {
MessageBox(hWndMain,
"Failed to set CPU counters!",
"Failed to set CPU counters",
MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
return TRUE;
}
//
// The template for monitoring an API
// Snap begining & ending counts
//
VOID
BeginCPUDump()
{
//
// Call driver and perform the setting
//
if (gfCPUEventMonitor) {
SetCounterEncodings ();
GetInternalStats (BufferStart); // snap current values
}
}
// snap ending values
VOID
EndCPUDump(ULONG Iter)
{
if (gfCPUEventMonitor) {
GetInternalStats (BufferEnd);
NumberIter = Iter;
}
}
// return the counter name
PUCHAR
Get_CPUDumpName(ULONG EventNo)
{
return Counters[CounterEvent[EventNo].AppReserved].PerfName;
}
VOID
Get_CPUDump(ULONG eventno, ULONGLONG *NewETime, ULONGLONG *NewECount)
{
ULONG j,len;
pPSTATS ProcStart, ProcEnd;
ULONGLONG ETime, ECount;
BOOLEAN ProcessorBreakout, ProcessorTotal;
// Hardcoded for single CPU
ProcessorBreakout=FALSE;
ProcessorTotal=TRUE;
//
// Calculate each counter and print it
//
if (!CounterEvent[eventno].Active) {
(*NewETime) = 0;
(*NewECount) = 0;
return;
}
len = *((PULONG) BufferStart);
/*
if (ProcessorBreakout) {
//
// Print stat for each processor
// This part is hardcoded out 11/20/96 a-ifkao
// Modify later
//
ProcStart = (pPSTATS) ((PUCHAR) BufferStart + sizeof(ULONG));
ProcEnd = (pPSTATS) ((PUCHAR) BufferEnd + sizeof(ULONG));
for (j=0; j < NumberOfProcessors; j++) {
ETime = ProcEnd->TSC - 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;
}