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.
528 lines
13 KiB
528 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Wperf.c
|
|
|
|
Abstract:
|
|
|
|
Win32 application to display performance statictics.
|
|
|
|
Author:
|
|
|
|
Ken Reneris
|
|
|
|
Environment:
|
|
|
|
console
|
|
|
|
--*/
|
|
|
|
//
|
|
// set variable to define global variables
|
|
//
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <errno.h>
|
|
#include <malloc.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include "..\pstat.h"
|
|
|
|
|
|
//
|
|
// global handles
|
|
//
|
|
|
|
extern UCHAR Buffer[];
|
|
#define INFSIZE 1024
|
|
|
|
UCHAR Usage[] = "pdump: [-p] [-t] second-delay [counter] [counter]...\n";
|
|
|
|
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];
|
|
|
|
//
|
|
// Protos..
|
|
//
|
|
|
|
VOID GetInternalStats (PVOID Buffer);
|
|
VOID SetCounterEncodings (VOID);
|
|
LONG FindShortName (PSZ);
|
|
VOID LI2Str (PSZ, ULONG, ULONGLONG);
|
|
BOOLEAN SetCounter (LONG CounterID, ULONG counter);
|
|
BOOLEAN InitDriver ();
|
|
VOID InitPossibleEventList();
|
|
|
|
|
|
|
|
|
|
int
|
|
__cdecl
|
|
main(USHORT argc, CHAR **argv)
|
|
{
|
|
ULONG i, j, len, pos, Delay;
|
|
LONG cnttype;
|
|
BOOLEAN CounterSet;
|
|
pPSTATS ProcStart, ProcEnd;
|
|
ULONGLONG ETime, ECount;
|
|
UCHAR s1[40], s2[40];
|
|
BOOLEAN Fail, DumpAll, ProcessorBreakout, ProcessorTotal;
|
|
|
|
//
|
|
// Locate pentium perf driver
|
|
//
|
|
|
|
if (!InitDriver ()) {
|
|
printf ("pstat.sys is not installed\n");
|
|
exit (1);
|
|
}
|
|
|
|
//
|
|
// Make sure local buffers are NULL terminated
|
|
//
|
|
s1[sizeof(s1) - 1] = 0;
|
|
s2[sizeof(s2) - 1] = 0;
|
|
|
|
//
|
|
// Initialize supported event list
|
|
//
|
|
|
|
InitPossibleEventList();
|
|
if (!Counters) {
|
|
printf ("No events to monitor\n");
|
|
exit (1);
|
|
}
|
|
|
|
//
|
|
// Check args
|
|
//
|
|
|
|
if (argc < 2) {
|
|
printf (Usage);
|
|
for (i=0; Counters[i].ShortName; i++) {
|
|
printf (" %-20s\t%s\n", Counters[i].ShortName, Counters[i].PerfName);
|
|
}
|
|
exit (1);
|
|
}
|
|
|
|
pos = 1;
|
|
|
|
Fail = FALSE;
|
|
Delay = 0;
|
|
DumpAll = FALSE;
|
|
ProcessorBreakout = FALSE;
|
|
ProcessorTotal = FALSE;
|
|
|
|
while (pos < argc && argv[pos][0] == '-') {
|
|
switch (argv[pos][1]) {
|
|
case 't':
|
|
ProcessorTotal = TRUE;
|
|
break;
|
|
|
|
case 'p':
|
|
ProcessorBreakout = TRUE;
|
|
break;
|
|
|
|
default:
|
|
printf ("pdump: unkown switch '%c'\n", argv[pos][1]);
|
|
Fail = TRUE;
|
|
break;
|
|
}
|
|
pos += 1;
|
|
}
|
|
|
|
if (pos < argc) {
|
|
Delay = atoi (argv[pos]) * 1000;
|
|
pos += 1;
|
|
}
|
|
|
|
if (Fail /* || Delay == 0 */) {
|
|
printf (Usage);
|
|
exit (1);
|
|
}
|
|
|
|
//
|
|
// Raise to highest priority
|
|
//
|
|
|
|
if (!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS)) {
|
|
printf("Failed to raise to realtime priority\n");
|
|
}
|
|
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
|
|
|
|
|
|
//
|
|
// Loop for every pentium count desired
|
|
//
|
|
|
|
if (pos >= argc) {
|
|
pos = 0;
|
|
DumpAll = TRUE;
|
|
}
|
|
|
|
printf (" %-30s %17s %17s\n", "", "Cycles", "Count");
|
|
|
|
for (; ;) {
|
|
//
|
|
// Set MAX_EVENTS
|
|
//
|
|
|
|
CounterSet = FALSE;
|
|
i = 0;
|
|
while (i < MAX_EVENTS) {
|
|
cnttype = -1;
|
|
if (DumpAll) {
|
|
//
|
|
// Dump all - get next counter
|
|
//
|
|
|
|
if (Counters[pos].ShortName) {
|
|
cnttype = pos;
|
|
pos++;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// process command line args
|
|
//
|
|
|
|
if (pos < argc) {
|
|
cnttype = FindShortName (argv[pos]);
|
|
if (cnttype == -1) {
|
|
printf ("Counter '%s' not found\n", argv[pos]);
|
|
pos++;
|
|
continue;
|
|
}
|
|
pos++;
|
|
}
|
|
}
|
|
|
|
CounterSet |= SetCounter (cnttype, i);
|
|
i++;
|
|
}
|
|
|
|
if (!CounterSet) {
|
|
// done
|
|
exit (1);
|
|
}
|
|
|
|
//
|
|
// Call driver and perform the setting
|
|
//
|
|
|
|
SetCounterEncodings ();
|
|
if ( Delay == 0 ) {
|
|
printf( "Counters set\n" );
|
|
// done
|
|
exit(1);
|
|
}
|
|
|
|
//
|
|
// Snap begining & ending counts
|
|
//
|
|
|
|
Sleep (50); // slight settle
|
|
GetInternalStats (BufferStart); // snap current values
|
|
Sleep (Delay); // sleep desired time
|
|
GetInternalStats (BufferEnd); // snap ending values
|
|
|
|
//
|
|
// Calculate each counter and print it
|
|
//
|
|
|
|
for (i=0; i < MAX_EVENTS; i++) {
|
|
if (!CounterEvent[i].Active) {
|
|
continue;
|
|
}
|
|
|
|
len = *((PULONG) BufferStart);
|
|
|
|
if (ProcessorBreakout) {
|
|
//
|
|
// Print stat for each processor
|
|
//
|
|
|
|
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[i] - ProcStart->Counters[i];
|
|
|
|
ProcStart = (pPSTATS) (((PUCHAR) ProcStart) + len);
|
|
ProcEnd = (pPSTATS) (((PUCHAR) ProcEnd) + len);
|
|
|
|
LI2Str (s1, sizeof(s1) - 1, ETime);
|
|
LI2Str (s2, sizeof(s2) - 1, ECount);
|
|
printf (" P%d %-30s %s %s\n",
|
|
j,
|
|
Counters[CounterEvent[i].AppReserved].PerfName,
|
|
s1, s2
|
|
);
|
|
}
|
|
}
|
|
|
|
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[i];
|
|
ECount = ECount - ProcStart->Counters[i];
|
|
|
|
ProcStart = (pPSTATS) (((PUCHAR) ProcStart) + len);
|
|
ProcEnd = (pPSTATS) (((PUCHAR) ProcEnd) + len);
|
|
}
|
|
|
|
LI2Str (s1, sizeof(s1) - 1, ETime);
|
|
LI2Str (s2, sizeof(s2) - 1, ECount);
|
|
printf (" %-30s %s %s\n",
|
|
Counters[CounterEvent[i].AppReserved].PerfName,
|
|
s1, s2
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOLEAN
|
|
InitDriver ()
|
|
{
|
|
UNICODE_STRING DriverName;
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES ObjA;
|
|
IO_STATUS_BLOCK IOSB;
|
|
SYSTEM_BASIC_INFORMATION BasicInfo;
|
|
PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PPerfInfo;
|
|
int i;
|
|
|
|
//
|
|
// Init Nt performance interface
|
|
//
|
|
|
|
NtQuerySystemInformation(
|
|
SystemBasicInformation,
|
|
&BasicInfo,
|
|
sizeof(BasicInfo),
|
|
NULL
|
|
);
|
|
|
|
NumberOfProcessors = BasicInfo.NumberOfProcessors;
|
|
|
|
if (NumberOfProcessors > MAX_PROCESSORS) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Open PStat driver
|
|
//
|
|
|
|
RtlInitUnicodeString(&DriverName, L"\\Device\\PStat");
|
|
InitializeObjectAttributes(
|
|
&ObjA,
|
|
&DriverName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
0 );
|
|
|
|
status = NtOpenFile (
|
|
&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 = NtDeviceIoControlFile(
|
|
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);
|
|
if (Counters == NULL) {
|
|
printf ("Memory allocation failure initializing event list\n");
|
|
exit(1);
|
|
}
|
|
|
|
Count -= 1;
|
|
for (i=0; i < Count; i++) {
|
|
*((PULONG) buffer) = i;
|
|
NtDeviceIoControlFile(
|
|
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 LI2Str (PSZ s, ULONG Size, ULONGLONG li)
|
|
{
|
|
|
|
//
|
|
// BogdanA - 02/22/2002: added another parameter (the size of s) so we
|
|
// do not overflow s. s is guaranteed to be NULL terminated, so
|
|
// we will not worry about it.
|
|
//
|
|
if (li > 0xFFFFFFFF) {
|
|
_snprintf (s, Size, "%08x:%08x", (ULONG) (li >> 32), (ULONG) li);
|
|
} else {
|
|
_snprintf (s, Size, " %08x", (ULONG) li);
|
|
}
|
|
}
|
|
|
|
|
|
LONG FindShortName (PSZ name)
|
|
{
|
|
LONG i;
|
|
|
|
for (i=0; Counters[i].ShortName; i++) {
|
|
if (strcmp (Counters[i].ShortName, name) == 0) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
VOID GetInternalStats (PVOID Buffer)
|
|
{
|
|
IO_STATUS_BLOCK IOSB;
|
|
|
|
NtDeviceIoControlFile(
|
|
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;
|
|
|
|
NtDeviceIoControlFile(
|
|
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;
|
|
}
|