home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 September
/
Chip_2001-09_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d2345
/
MSYSINFO.ZIP
/
Source
/
MiTeC_PerfLibNT.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
2001-06-26
|
40KB
|
1,136 lines
{*******************************************************}
{ }
{ MiTeC System Information Component }
{ Performance Library for WinNT }
{ version 5.6 for Delphi 3,4,5 }
{ }
{ Copyright ⌐ 1997,2001 Michal Mutl }
{ }
{*******************************************************}
{$INCLUDE MITEC_DEF.INC}
unit MiTeC_PerfLibNT;
interface
uses Windows, Classes, SysUtils;
//resourcestring
const
SPERFNUMHEX_BadSize = 'Bad Size (PERF_NUMBER_HEX)';
SPERFNUMDEC_BadSize = 'Bad Size (PERF_NUMBER_DEC)';
SPERFNUMDEC1K_BadSize = 'Bad Size (PERF_NUMBER_DEC1000)';
SPERFCNTR_BadSize = 'Bad Size (PERF_COUNTER)';
SPERFCNTRRATE_BadSize = 'Bad Size (PERF_COUNTER_RATE)';
SPERFCNTRBASE_BadSize = 'Bad Size (PERF_COUNTER_BASE)';
SPERFCNTRELAPS_BadSize = 'Bad Size (PERF_COUNTER_ELAPSED)';
SUnknownType = 'Cannot display data';
SPERFTYPETEXT_BadData = 'Bad Data (PERF_TYPE_TEXT)';
SPerSec = '/sec';
SPercent = ' %';
SSecs = ' secs';
SFrac = 'Frac';
SElapsed = 'Elapsed';
SNoname = '<noname>';
const
Timer100N = 10000000;
Timer1S = 1000;
PERF_DETAIL_NOVICE = $00000000;
PERF_DETAIL_ADVANCED = $00000100;
PERF_DETAIL_EXPERT = $00000200;
PERF_DETAIL_WIZARD = $00000300;
// PERF_COUNTER_DEFINITION
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// PERF_COUNTER_DEFINITION.CounterType field values
//
//
// Counter ID Field Definition:
//
// 3 2 2 2 2 1 1 1
// 1 8 4 2 0 6 2 0 8 0
// +--------+--------+----+----+--------+--------+----+----+----------------+
// |Display |Calculation |Time|Counter | |Ctr |Size| |
// |Flags |Modifiers |Base|SubType |Reserved|Type|Fld | Reserved |
// +--------+--------+----+----+--------+--------+----+----+----------------+
//
//
PERF_SIZE_DWORD = $00000000;
PERF_SIZE_LARGE = $00000100;
PERF_SIZE_ZERO = $00000200; // for Zero Length fields
PERF_SIZE_VARIABLE_LEN = $00000300; // length is in CounterLength field of Counter Definition struct
//
// select one of the following values to indicate the counter field usage
//
PERF_TYPE_NUMBER = $00000000; // a number (not a counter)
PERF_TYPE_COUNTER = $00000400; // an increasing numeric value
PERF_TYPE_TEXT = $00000800; // a text field
PERF_TYPE_ZERO = $00000C00; // displays a zero
//
// If the PERF_TYPE_NUMBER field was selected, then select one of the
// following to describe the Number
//
PERF_NUMBER_HEX = $00000000; // display as HEX value
PERF_NUMBER_DECIMAL = $00010000; // display as a decimal integer
PERF_NUMBER_DEC_1000 = $00020000; // display as a decimal/1000
//
// If the PERF_TYPE_COUNTER value was selected then select one of the
// following to indicate the type of counter
//
PERF_COUNTER_VALUE = $00000000; // display counter value
PERF_COUNTER_RATE = $00010000; // divide ctr / delta time
PERF_COUNTER_FRACTION = $00020000; // divide ctr / base
PERF_COUNTER_BASE = $00030000; // base value used in fractions
PERF_COUNTER_ELAPSED = $00040000; // subtract counter from current time
PERF_COUNTER_QUEUELEN = $00050000; // Use Queuelen processing func.
PERF_COUNTER_HISTOGRAM = $00060000; // Counter begins or ends a histogram
//
// If the PERF_TYPE_TEXT value was selected, then select one of the
// following to indicate the type of TEXT data.
//
PERF_TEXT_UNICODE = $00000000; // type of text in text field
PERF_TEXT_ASCII = $00010000; // ASCII using the CodePage field
//
// Timer SubTypes
//
PERF_TIMER_TICK = $00000000; // use system perf. freq for base
PERF_TIMER_100NS = $00100000; // use 100 NS timer time base units
PERF_OBJECT_TIMER = $00200000; // use the object timer freq
//
// Any types that have calculations performed can use one or more of
// the following calculation modification flags listed here
//
PERF_DELTA_COUNTER = $00400000; // compute difference first
PERF_DELTA_BASE = $00800000; // compute base diff as well
PERF_INVERSE_COUNTER = $01000000; // show as 1.00-value (assumes:
PERF_MULTI_COUNTER = $02000000; // sum of multiple instances
//
// Select one of the following values to indicate the display suffix (if any)
//
PERF_DISPLAY_NO_SUFFIX = $00000000; // no suffix
PERF_DISPLAY_PER_SEC = $10000000; // "/sec"
PERF_DISPLAY_PERCENT = $20000000; // "%"
PERF_DISPLAY_SECONDS = $30000000; // "secs"
PERF_DISPLAY_NOSHOW = $40000000; // value is not displayed
//
// Predefined counter types
//
// 32-bit Counter. Divide delta by delta time. Display suffix: "/sec"
PERF_COUNTER_COUNTER =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_TIMER_TICK or PERF_DELTA_COUNTER or PERF_DISPLAY_PER_SEC;
// 64-bit Timer. Divide delta by delta time. Display suffix: "%"
PERF_COUNTER_TIMER =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_TIMER_TICK or PERF_DELTA_COUNTER or PERF_DISPLAY_PERCENT;
// Queue Length Space-Time Product. Divide delta by delta time. No Display Suffix.
PERF_COUNTER_QUEUELEN_TYPE =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_QUEUELEN or
PERF_TIMER_TICK or PERF_DELTA_COUNTER or PERF_DISPLAY_NO_SUFFIX;
// Queue Length Space-Time Product. Divide delta by delta time. No Display Suffix.
PERF_COUNTER_LARGE_QUEUELEN_TYPE =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_QUEUELEN or
PERF_TIMER_TICK or PERF_DELTA_COUNTER or PERF_DISPLAY_NO_SUFFIX;
// 64-bit Counter. Divide delta by delta time. Display Suffix: "/sec"
PERF_COUNTER_BULK_COUNT =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_TIMER_TICK or PERF_DELTA_COUNTER or PERF_DISPLAY_PER_SEC;
// Indicates the counter is not a counter but rather Unicode text Display as text.
PERF_COUNTER_TEXT =
PERF_SIZE_VARIABLE_LEN or PERF_TYPE_TEXT or PERF_TEXT_UNICODE or
PERF_DISPLAY_NO_SUFFIX;
// Indicates the data is a counter which should not be
// time averaged on display (such as an error counter on a serial line)
// Display as is. No Display Suffix.
PERF_COUNTER_RAWCOUNT =
PERF_SIZE_DWORD or PERF_TYPE_NUMBER or PERF_NUMBER_DECIMAL or
PERF_DISPLAY_NO_SUFFIX;
// Same as PERF_COUNTER_RAWCOUNT except its size is a large integer
PERF_COUNTER_LARGE_RAWCOUNT =
PERF_SIZE_LARGE or PERF_TYPE_NUMBER or PERF_NUMBER_DECIMAL or
PERF_DISPLAY_NO_SUFFIX;
// Special case for RAWCOUNT that want to be displayed in hex
// Indicates the data is a counter which should not be
// time averaged on display (such as an error counter on a serial line)
// Display as is. No Display Suffix.
PERF_COUNTER_RAWCOUNT_HEX =
PERF_SIZE_DWORD or PERF_TYPE_NUMBER or PERF_NUMBER_HEX or
PERF_DISPLAY_NO_SUFFIX;
// Same as PERF_COUNTER_RAWCOUNT_HEX except its size is a large integer
PERF_COUNTER_LARGE_RAWCOUNT_HEX =
PERF_SIZE_LARGE or PERF_TYPE_NUMBER or PERF_NUMBER_HEX or
PERF_DISPLAY_NO_SUFFIX;
// A count which is either 1 or 0 on each sampling interrupt (% busy)
// Divide delta by delta base. Display Suffix: "%"
PERF_SAMPLE_FRACTION =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_FRACTION or
PERF_DELTA_COUNTER or PERF_DELTA_BASE or PERF_DISPLAY_PERCENT;
// A count which is sampled on each sampling interrupt (queue length)
// Divide delta by delta time. No Display Suffix.
PERF_SAMPLE_COUNTER =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_TIMER_TICK or PERF_DELTA_COUNTER or PERF_DISPLAY_NO_SUFFIX;
// A label: no data is associated with this counter (it has 0 length)
// Do not display.
PERF_COUNTER_NODATA =
PERF_SIZE_ZERO or PERF_DISPLAY_NOSHOW;
// 64-bit Timer inverse (e.g., idle is measured, but display busy %)
// Display 100 - delta divided by delta time. Display suffix: "%"
PERF_COUNTER_TIMER_INV =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_TIMER_TICK or PERF_DELTA_COUNTER or PERF_INVERSE_COUNTER or
PERF_DISPLAY_PERCENT;
// The divisor for a sample, used with the previous counter to form a
// sampled %. You must check for >0 before dividing by this! This
// counter will directly follow the numerator counter. It should not
// be displayed to the user.
PERF_SAMPLE_BASE =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_BASE or
PERF_DISPLAY_NOSHOW or
$00000001; // for compatibility with pre-beta versions
// A timer which, when divided by an average base, produces a time
// in seconds which is the average time of some operation. This
// timer times total operations, and the base is the number of opera-
// tions. Display Suffix: "sec"
PERF_AVERAGE_TIMER =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_FRACTION or
PERF_DISPLAY_SECONDS;
// Used as the denominator in the computation of time or count
// averages. Must directly follow the numerator counter. Not dis-
// played to the user.
PERF_AVERAGE_BASE =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_BASE or
PERF_DISPLAY_NOSHOW or
$00000002; // for compatibility with pre-beta versions
// A bulk count which, when divided (typically) by the number of
// operations, gives (typically) the number of bytes per operation.
// No Display Suffix.
PERF_AVERAGE_BULK =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_FRACTION or
PERF_DISPLAY_NOSHOW;
// 64-bit Timer in 100 nsec units. Display delta divided by
// delta time. Display suffix: "%"
PERF_100NSEC_TIMER =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_TIMER_100NS or PERF_DELTA_COUNTER or PERF_DISPLAY_PERCENT;
// 64-bit Timer inverse (e.g., idle is measured, but display busy %)
// Display 100 - delta divided by delta time. Display suffix: "%"
PERF_100NSEC_TIMER_INV =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_TIMER_100NS or PERF_DELTA_COUNTER or PERF_INVERSE_COUNTER or
PERF_DISPLAY_PERCENT;
// 64-bit Timer. Divide delta by delta time. Display suffix: "%"
// Timer for multiple instances, so result can exceed 100%.
PERF_COUNTER_MULTI_TIMER =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_DELTA_COUNTER or PERF_TIMER_TICK or PERF_MULTI_COUNTER or
PERF_DISPLAY_PERCENT;
// 64-bit Timer inverse (e.g., idle is measured, but display busy %)
// Display 100 * _MULTI_BASE - delta divided by delta time.
// Display suffix: "%" Timer for multiple instances, so result
// can exceed 100%. Followed by a counter of type _MULTI_BASE.
PERF_COUNTER_MULTI_TIMER_INV =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_RATE or
PERF_DELTA_COUNTER or PERF_MULTI_COUNTER or PERF_TIMER_TICK or
PERF_INVERSE_COUNTER or PERF_DISPLAY_PERCENT;
// Number of instances to which the preceding _MULTI_..._INV counter
// applies. Used as a factor to get the percentage.
PERF_COUNTER_MULTI_BASE =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_BASE or
PERF_MULTI_COUNTER or PERF_DISPLAY_NOSHOW;
// 64-bit Timer in 100 nsec units. Display delta divided by delta time.
// Display suffix: "%" Timer for multiple instances, so result can exceed 100%.
PERF_100NSEC_MULTI_TIMER =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_DELTA_COUNTER or
PERF_COUNTER_RATE or PERF_TIMER_100NS or PERF_MULTI_COUNTER or
PERF_DISPLAY_PERCENT;
// 64-bit Timer inverse (e.g., idle is measured, but display busy %)
// Display 100 * _MULTI_BASE - delta divided by delta time.
// Display suffix: "%" Timer for multiple instances, so result
// can exceed 100%. Followed by a counter of type _MULTI_BASE.
PERF_100NSEC_MULTI_TIMER_INV =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_DELTA_COUNTER or
PERF_COUNTER_RATE or PERF_TIMER_100NS or PERF_MULTI_COUNTER or
PERF_INVERSE_COUNTER or PERF_DISPLAY_PERCENT;
// Indicates the data is a fraction of the following counter which
// should not be time averaged on display (such as free space over
// total space.) Display as is. Display the quotient as "%".
PERF_RAW_FRACTION =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_FRACTION or
PERF_DISPLAY_PERCENT;
// Indicates the data is a base for the preceding counter which should
// not be time averaged on display (such as free space over total space.)
PERF_RAW_BASE =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_BASE or
PERF_DISPLAY_NOSHOW or
$00000003; // for compatibility with pre-beta versions
// The data collected in this counter is actually the start time of the
// item being measured. For display, this data is subtracted from the
// sample time to yield the elapsed time as the difference between the two.
// In the definition below, the PerfTime field of the Object contains
// the sample time as indicated by the PERF_OBJECT_TIMER bit and the
// difference is scaled by the PerfFreq of the Object to convert the time
// units into seconds.
PERF_ELAPSED_TIME =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_ELAPSED or
PERF_OBJECT_TIMER or PERF_DISPLAY_SECONDS;
//
// The following counter type can be used with the preceding types to
// define a range of values to be displayed in a histogram.
//
PERF_COUNTER_HISTOGRAM_TYPE = $80000000;
// Counter begins or ends a histogram
//
// This counter is used to display the difference from one sample
// to the next. The counter value is a constantly increasing number
// and the value displayed is the difference between the current
// value and the previous value. Negative numbers are not allowed
// which shouldn't be a problem as long as the counter value is
// increasing or unchanged.
//
PERF_COUNTER_DELTA =
PERF_SIZE_DWORD or PERF_TYPE_COUNTER or PERF_COUNTER_VALUE or
PERF_DELTA_COUNTER or PERF_DISPLAY_NO_SUFFIX;
PERF_COUNTER_LARGE_DELTA =
PERF_SIZE_LARGE or PERF_TYPE_COUNTER or PERF_COUNTER_VALUE or
PERF_DELTA_COUNTER or PERF_DISPLAY_NO_SUFFIX;
type
PLARGE_INTEGER = ^LARGE_INTEGER;
PPERF_OBJECT_TYPE = ^TPERF_OBJECT_TYPE;
TPERF_OBJECT_TYPE = packed record
TotalByteLength,
DefinitionLength,
HeaderLength,
ObjectNameTitleIndex: DWORD;
ObjectNameTitle: LPWSTR;
ObjectHelpTitleIndex: DWORD;
ObjectHelpTitle: LPWSTR;
DetailLevel,
NumCounters,
DefaultCounter,
NumInstances,
CodePage: DWORD;
PerfTime,
PerfFreq: LARGE_INTEGER;
end;
PPERF_COUNTER_DEFINITION = ^TPERF_COUNTER_DEFINITION;
TPERF_COUNTER_DEFINITION = packed record
ByteLength,
CounterNameTitleIndex: DWORD;
CounterNameTitle: LPWSTR;
CounterHelpTitleIndex: DWORD;
CounterHelpTitle: LPWSTR;
DefaultScale,
DetailLevel,
CounterType,
CounterSize,
CounterOffset: DWORD;
end;
PPERF_INSTANCE_DEFINITION = ^TPERF_INSTANCE_DEFINITION;
TPERF_INSTANCE_DEFINITION = packed record
ByteLength,
ParentObjectTitleIndex,
ParentObjectInstance,
UniqueID,
NameOffset,
NameLength: DWORD;
end;
PPERF_COUNTER_BLOCK = ^TPERF_COUNTER_BLOCK;
TPERF_COUNTER_BLOCK = packed record
ByteLength: DWORD;
end;
PPERF_DATA_BLOCK = ^TPERF_DATA_BLOCK;
TPERF_DATA_BLOCK = packed record
Signature: array [0..3] of WCHAR;
LittleEndian,
Version,
Revision,
TotalByteLength,
HeaderLength,
NumObjectTypes,
DefaultObject: DWORD;
SystemTime: SYSTEMTIME;
PerfTime,
PerfFreq,
PerfTime100nSec: LARGE_INTEGER;
SystemNameLength,
SystemNameOffset: DWORD;
end;
TPerfLibNT = class;
TPerfObject = class;
TDetailLevel = (Novice,Advanced,Expert,Wizard);
TPerfCounter = class(TObject)
private
FPerfObject: TPerfObject;
FName: string;
FDescription: string;
FCounterOffset: DWORD;
FDefaultScale: DWORD;
FCounterSize: DWORD;
FDetailLevel: TDetailLevel;
FCounterType: DWORD;
FIndex: DWORD;
function GetData(InstanceIndex: DWORD): PChar;
function GetDataStr(InstanceIndex: DWORD): string;
function GetDataStrEx(InstanceIndex: DWORD): string;
protected
property CounterOffset: DWORD read FCounterOffset;
property Index: DWORD read FIndex;
public
constructor Create(AIndex: DWORD; APerfObject: TPerfObject; APerfCntr: PPERF_COUNTER_DEFINITION);
destructor Destroy; override;
property Name: string read FName;
property Description: string read FDescription;
property DefaultScale: DWORD read FDefaultScale;
property DetailLevel: TDetailLevel read FDetailLevel;
property CounterType: DWORD read FCounterType;
property CounterSize: DWORD read FCounterSize;
property ParentObject: TPerfObject read FPerfObject;
property Data[InstanceIndex: DWORD]: PChar read GetData;
property DataStr[InstanceIndex: DWORD]: string read GetDataStr;
property DataStrEx[InstanceIndex: DWORD]: string read GetDataStrEx;
end;
PPerfInstance = ^TPerfInstance;
TPerfInstance = record
Name: string;
ID,
Index: DWORD;
end;
TPerfObject = class(TObject)
private
FCounters: TStringList;
FPerfLib: TPerfLibNT;
FName: string;
FDescription: string;
FCodePage: DWORD;
FCounterCount: integer;
FDefaultCounter: integer;
FDetailLevel: TDetailLevel;
FPerfObj: PPERF_OBJECT_TYPE;
FPerfTime: LARGE_INTEGER;
FPerfFreq: LARGE_INTEGER;
FIndex: DWORD;
function GetCounter(Index: integer): TPerfCounter;
function GetInstance(Index: integer): TPerfInstance;
function GetInstanceCount: integer;
protected
property Index: DWORD read FIndex;
property PerfLib: TPerfLibNT read FPerfLib;
property PerfObj: PPERF_OBJECT_TYPE read FPerfObj;
public
constructor Create(AIndex: DWORD; APerfLib: TPerfLibNT; APerfObj: PPERF_OBJECT_TYPE);
destructor Destroy; override;
function GetCntrIndexByName(AName: string): integer;
{function GetInstIndexByName(AName: string): integer;
function GetInstIndexByID(AID: DWORD): integer;}
property Name: string read FName;
property Description: string read FDescription;
property DetailLevel: TDetailLevel read FDetailLevel;
property CounterCount: integer read FCounterCount;
property DefaultCounter: integer read FDefaultCounter;
property InstanceCount: integer read GetInstanceCount;
property CodePage: DWORD read FCodePage;
property PerfTime: LARGE_INTEGER read FPerfTime;
property PerfFreq: LARGE_INTEGER read FPerfFreq;
property Counters[Index: integer]: TPerfCounter read GetCounter;
property Instances[Index: integer]: TPerfInstance read GetInstance;
end;
TPerfLibNT = class(TPersistent)
private
FPerfData: PPERF_DATA_BLOCK;
FCounters,
FHelps,
FObjects: TStringList;
FPerfTime: LARGE_INTEGER;
FPerfFreq: LARGE_INTEGER;
FPerfTime100nsec: LARGE_INTEGER;
FRevision: DWORD;
FVersion: DWORD;
procedure GetNameStrings;
procedure ReadObjects;
function GetObject(Index: integer): TPerfObject;
function GetObjectCount: integer;
protected
function GetCounterData(ObjectIndex,InstanceIndex,CounterIndex: DWORD): PChar;
property Helps: TStringList read FHelps;
public
constructor Create;
destructor Destroy; override;
procedure TakeSnapshot;
procedure Refresh;
function GetIndexByName(AName: string): integer;
property Names: TStringList read FCounters;
property PerfTime: LARGE_INTEGER read FPerfTime;
property PerfFreq: LARGE_INTEGER read FPerfFreq;
property PerfTime100nsec: LARGE_INTEGER read FPerfTime100nsec;
property Version: DWORD read FVersion;
property Revision: DWORD read FRevision;
property ObjectCount: integer read GetObjectCount;
property Objects[Index: integer]: TPerfObject read GetObject;
end;
function FormatData(AType, ASize: Integer; AVerbose: Boolean; AData: PChar): string;
function GetCounterTypeStr(AType: DWORD): string;
function GetDetailLevelStr(ALevel: TDetailLevel): string;
implementation
const
rkPerfLib = {HKLM\}'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib';
rvLastCounter = 'LastCounter';
rkPerfLib009 = {HKLM\}'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009';
rvCounter = 'Counter';
rvHelp = 'Help';
rkGlobal = 'Global';
function FirstObject(APerfData: PPERF_DATA_BLOCK): PPERF_OBJECT_TYPE;
begin
Result:=PPERF_OBJECT_TYPE(PCHAR(APerfData)+APerfData^.HeaderLength);
end;
function NextObject(APerfObj: PPERF_OBJECT_TYPE): PPERF_OBJECT_TYPE;
begin
Result:=PPERF_OBJECT_TYPE(PCHAR(APerfObj)+APerfObj^.TotalByteLength);
end;
function FirstInstance(APerfObj: PPERF_OBJECT_TYPE): PPERF_INSTANCE_DEFINITION;
begin
Result:=PPERF_INSTANCE_DEFINITION(PCHAR(APerfObj)+APerfObj^.DefinitionLength);
end;
function NextInstance(APerfInst: PPERF_INSTANCE_DEFINITION): PPERF_INSTANCE_DEFINITION;
var
PerfCntrBlk: PPERF_COUNTER_BLOCK;
begin
PerfCntrBlk:=PPERF_COUNTER_BLOCK(PCHAR(APerfInst)+APerfInst^.ByteLength);
result:=PPERF_INSTANCE_DEFINITION(PCHAR(PerfCntrBlk)+PerfCntrBlk^.ByteLength);
end;
function FirstCounter(APerfObj: PPERF_OBJECT_TYPE): PPERF_COUNTER_DEFINITION;
begin
Result:=PPERF_COUNTER_DEFINITION(PCHAR(APerfObj)+APerfObj^.HeaderLength);
end;
function NextCounter(APerfCntr: PPERF_COUNTER_DEFINITION): PPERF_COUNTER_DEFINITION;
begin
Result:=PPERF_COUNTER_DEFINITION(PCHAR(APerfCntr)+APerfCntr^.ByteLength);
end;
// 3 2 2 2 2 1 1 1
// 1 8 4 2 0 6 2 0 8 0
// +--------+--------+----+----+--------+--------+----+----+----------------+
// |Display |Calculation |Time|Counter | |Ctr |Size| |
// |Flags |Modifiers |Base|SubType |Reserved|Type|Fld | Reserved |
// +--------+--------+----+----+--------+--------+----+----+----------------+
function FormatData;
var
SizeFld,
CtrType,
CounterSubType,
//TimeBase,
//CalculationModifiers,
DisplayFlags: Integer;
s: string;
time: int64;
n: extended;
const
DeltaTime: Integer = 1;
Base: extended = 1;
begin
SizeFld:=AType and $300;
CtrType:=AType and $c00;
CounterSubType:=AType and $f0000;
// TimeBase:=AType and $300000;
// CalculationModifiers:=AType and $fc00000;
DisplayFlags:=AType and $f0000000;
s:='';
case SizeFld of
PERF_SIZE_DWORD: ASize := 4;
PERF_SIZE_LARGE: ASize := 8;
PERF_SIZE_ZERO: ASize := 0;
PERF_SIZE_VARIABLE_LEN: ; // length is in CounterLength field
end;
case CtrType of
PERF_TYPE_NUMBER :
case CounterSubType of
PERF_NUMBER_HEX:
case ASize of
4: s:=IntToHex(PInteger(AData)^,8);
8: s:=IntToHex(PLARGE_INTEGER(AData)^.HighPart,8)+':'+IntToHex(PLARGE_INTEGER(AData)^.LowPart,8);
else s:=SPERFNUMHEX_BadSize;
end;
PERF_NUMBER_DECIMAL:
case ASize of
4: s:=IntToStr(PInteger(AData)^);
8: s:=Format('%d',[PLARGE_INTEGER(AData)^.QuadPart]);
else s:=SPERFNUMDEC_BadSize;
end;
PERF_NUMBER_DEC_1000:
case ASize of
4: s:=IntToStr(PInteger(AData)^ div 1000);
8: s:=Format('%n',[PLARGE_INTEGER(AData)^.QuadPart/1000]);
else s:=SPERFNUMDEC1K_BadSize;
end
end;
PERF_TYPE_COUNTER:
case CounterSubType of
PERF_COUNTER_VALUE :
case ASize of
4: s:=IntToStr(PInteger(AData)^);
8: s:=Format('%d',[PLARGE_INTEGER(AData)^.QuadPart]);
else s:=SPERFCNTR_BadSize;
end;
PERF_COUNTER_RATE :
case ASize of
4: s:=IntToStr(PInteger(AData)^ div deltaTime);
8: s:=Format('%n',[PLARGE_INTEGER(AData)^.QuadPart/deltatime]);
else s:=SPERFCNTRRATE_BadSize;
end;
PERF_COUNTER_FRACTION: begin
case ASize of
4: n:=PInteger(AData)^/base;
8: n:=PLARGE_INTEGER(AData)^.QuadPart/base;
else
n:=0;
end;
if (ASize=4) or (ASize=8) then begin
if DisplayFlags=PERF_DISPLAY_PERCENT then
n:=n*100;
s:=Format('%1.3n',[n]);
if AVerbose then
s:=SFrac+' '+s;
end
end;
PERF_COUNTER_BASE:
case ASize of
4 : base:=PInteger(AData)^;
8 : base:=PLARGE_INTEGER(AData)^.QuadPart;
else s:=SPERFCNTRBASE_BadSize;
end;
PERF_COUNTER_ELAPSED: begin
QueryPerformanceFrequency(time);
case ASize of
4 : s:=IntToStr(low(time)-PInteger(AData)^);
8 : s:=Format('%n',[PLARGE_INTEGER(AData)^.QuadPart/time]);
else s:=SPERFCNTRELAPS_BadSize;
end;
if AVerbose then
s:=SElapsed+' '+s;
end;
PERF_COUNTER_QUEUELEN:
s:='QUEUELEN';
PERF_COUNTER_HISTOGRAM:
s:='HISTOGRAM';
else s:=SUnknownType;
end;
PERF_TYPE_TEXT:
s:=SPERFTYPETEXT_BadData;
PERF_TYPE_ZERO:
s:='0';
end;
if AVerbose then
case DisplayFlags of
PERF_DISPLAY_PER_SEC: s:=s+SPerSec;
PERF_DISPLAY_PERCENT: s:=s+SPercent;
PERF_DISPLAY_SECONDS: s:=s+SSecs;
PERF_DISPLAY_NOSHOW: s:='';
end;
result:=s;
end;
function GetCounterTypeStr(AType: DWORD): string;
var
CtrType,
CtrSubType: integer;
begin
CtrType:=AType and $c00;
CtrSubType:=AType and $f0000;
Result:='';
case AType of
PERF_COUNTER_COUNTER: Result:='PERF_COUNTER_COUNTER';
PERF_COUNTER_TIMER: Result:='PERF_COUNTER_TIMER';
PERF_COUNTER_QUEUELEN_TYPE: Result:='PERF_COUNTER_QUEUELEN_TYPE';
PERF_COUNTER_LARGE_QUEUELEN_TYPE: Result:='PERF_COUNTER_LARGE_QUEUELEN_TYPE';
PERF_COUNTER_BULK_COUNT: Result:='PERF_COUNTER_BULK_COUNT';
PERF_COUNTER_TEXT: Result:='PERF_COUNTER_TEXT';
PERF_COUNTER_RAWCOUNT: Result:='PERF_COUNTER_RAWCOUNT';
PERF_COUNTER_LARGE_RAWCOUNT: Result:='PERF_COUNTER_LARGE_RAWCOUNT';
PERF_COUNTER_RAWCOUNT_HEX: Result:='PERF_COUNTER_RAWCOUNT_HEX';
PERF_COUNTER_LARGE_RAWCOUNT_HEX: Result:='PERF_COUNTER_LARGE_RAWCOUNT_HEX';
PERF_SAMPLE_FRACTION: Result:='PERF_SAMPLE_FRACTION';
PERF_SAMPLE_COUNTER: Result:='PERF_SAMPLE_COUNTER';
PERF_COUNTER_NODATA: Result:='PERF_COUNTER_NODATA';
PERF_COUNTER_TIMER_INV: Result:='PERF_COUNTER_TIMER_INV';
PERF_SAMPLE_BASE: Result:='PERF_SAMPLE_BASE';
PERF_AVERAGE_TIMER: Result:='PERF_AVERAGE_TIMER';
PERF_AVERAGE_BASE: Result:='PERF_AVERAGE_BASE';
PERF_AVERAGE_BULK: Result:='PERF_AVERAGE_BULK';
PERF_100NSEC_TIMER: Result:='PERF_100NSEC_TIMER';
PERF_100NSEC_TIMER_INV: Result:='PERF_100NSEC_TIMER_INV';
PERF_COUNTER_MULTI_TIMER: Result:='PERF_COUNTER_MULTI_TIMER';
PERF_COUNTER_MULTI_TIMER_INV: Result:='PERF_COUNTER_MULTI_TIMER_INV';
PERF_COUNTER_MULTI_BASE: Result:='PERF_COUNTER_MULTI_BASE';
PERF_100NSEC_MULTI_TIMER: Result:='PERF_100NSEC_MULTI_TIMER';
PERF_100NSEC_MULTI_TIMER_INV: Result:='PERF_100NSEC_MULTI_TIMER_INV';
PERF_RAW_FRACTION: Result:='PERF_RAW_FRACTION';
PERF_RAW_BASE: Result:='PERF_RAW_BASE';
PERF_ELAPSED_TIME: Result:='PERF_ELAPSED_TIME';
PERF_COUNTER_HISTOGRAM_TYPE: Result:='PERF_COUNTER_HISTOGRAM_TYPE';
PERF_COUNTER_DELTA: Result:='PERF_COUNTER_DELTA';
PERF_COUNTER_LARGE_DELTA: Result:='PERF_COUNTER_LARGE_DELTA';
end;
if Result='' then
case CtrType of
PERF_TYPE_NUMBER :
case CtrSubType of
PERF_NUMBER_HEX: Result:='PERF_NUMBER_HEX';
PERF_NUMBER_DECIMAL: Result:='PERF_NUMBER_DEC';
PERF_NUMBER_DEC_1000: Result:='PERF_NUMBER_DEC1000';
end;
PERF_TYPE_COUNTER:
case CtrSubType of
PERF_COUNTER_VALUE: Result:='PERF_COUNTER_VALUE';
PERF_COUNTER_RATE : Result:='PERF_COUNTER_RATE';
PERF_COUNTER_FRACTION: Result:='PERF_COUNTER_FRACTION';
PERF_COUNTER_BASE: Result:='PERF_COUNTER_BASE';
PERF_COUNTER_ELAPSED: Result:='PERF_COUNTER_ELAPSED';
PERF_COUNTER_QUEUELEN: Result:='PERF_COUNTER_QUEUELEN';
PERF_COUNTER_HISTOGRAM: Result:='PERF_COUNTER_HISTOGRAM';
end;
PERF_TYPE_TEXT:
case CtrSubType of
PERF_TEXT_UNICODE: Result:='PERF_TEXT_UNICODE';
PERF_TEXT_ASCII: Result:='PERF_TEXT_ASCII';
end;
PERF_TYPE_ZERO: Result:='PERF_TYPE_ZERO';
end;
if Result='' then
Result:='0x'+IntToHex(AType,8);
end;
function GetDetailLevelStr(ALevel: TDetailLevel): string;
begin
case ALevel of
Novice: Result:='Novice';
Advanced: Result:='Advanced';
Expert: Result:='Expert';
Wizard: Result:='Wizard';
end;
end;
{ TPerfLibNT }
constructor TPerfLibNT.Create;
begin
FCounters:=TStringList.Create;
FHelps:=TStringList.Create;
FObjects:=TStringList.Create;
FPerfData:=AllocMem(MaxWord);
end;
destructor TPerfLibNT.Destroy;
begin
while FCounters.Count>0 do begin
Freemem(PChar(FCounters.Objects[FCounters.Count-1]));
FCounters.Delete(FCounters.Count-1);
end;
while FHelps.Count>0 do begin
Freemem(PChar(FHelps.Objects[FHelps.Count-1]));
FHelps.Delete(FHelps.Count-1);
end;
while FObjects.Count>0 do begin
FObjects.Objects[FObjects.Count-1].Free;
FObjects.Delete(FObjects.Count-1);
end;
FCounters.Free;
FObjects.Free;
FHelps.Free;
FreeMem(FPerfData);
inherited;
end;
function TPerfLibNT.GetIndexByName(AName: string): integer;
begin
Result:=FObjects.IndexOf(AName);
end;
procedure TPerfLibNT.GetNameStrings;
var
hkPerfLib,
hkPerfLib009: HKEY;
dwBufferSize,
dwBuffer,
dwMaxValueLen: DWORD;
lpNameStrings: PChar;
p: integer;
szID,
szName: string;
begin
while FCounters.Count>0 do begin
Freemem(PChar(FCounters.Objects[FCounters.Count-1]));
FCounters.Delete(FCounters.Count-1);
end;
while FHelps.Count>0 do begin
Freemem(PChar(FHelps.Objects[FHelps.Count-1]));
FHelps.Delete(FHelps.Count-1);
end;
RegOpenKeyEx(HKEY_LOCAL_MACHINE,rkPerfLib,0,KEY_READ,hkPerflib);
dwBufferSize:=sizeof(dwBuffer);
RegQueryValueEx(hkPerflib,rvLastCounter,nil,nil,PBYTE(@dwBuffer),@dwBufferSize);
RegCloseKey(hkPerflib);
RegOpenKeyEx(HKEY_LOCAL_MACHINE,rkPerfLib009,0,KEY_READ,hkPerflib009);
RegQueryInfoKey(hkPerflib009,nil,nil,nil,nil,nil,nil,nil,nil,@dwMaxValueLen,nil,nil);
dwBuffer:=dwMaxValueLen+1;
lpNameStrings:=AllocMem(dwBuffer*sizeof(char));
RegQueryValueEx(hkPerflib009,rvCounter,nil,nil,PBYTE(lpNameStrings),@dwBuffer);
p:=0;
repeat
szID:=lpNameStrings+p;
Inc(p,Length(szID)+1);
szName:=lpNameStrings+p;
Inc(p,Length(szName)+1);
FCounters.AddObject(szName,TObject(StrToInt(szID)));
until lpNameStrings[p]=#0;
RegQueryInfoKey(hkPerflib009,nil,nil,nil,nil,nil,nil,nil,nil,@dwMaxValueLen,nil,nil);
dwBuffer:=dwMaxValueLen+1;
ReallocMem(lpNameStrings,dwBuffer*sizeof(char));
RegQueryValueEx(hkPerflib009,rvHelp,nil,nil,PBYTE(lpNameStrings),@dwBuffer);
p:=0;
repeat
szID:=lpNameStrings+p;
Inc(p,Length(szID)+1);
szName:=lpNameStrings+p;
Inc(p,Length(szName)+1);
FHelps.AddObject(szName,TObject(StrToInt(szID)));
until lpNameStrings[p]=#0;
FreeMem(lpNameStrings);
RegCloseKey(hkPerflib009);
end;
function TPerfLibNT.GetObject(Index: integer): TPerfObject;
begin
if Index<FObjects.Count then
Result:=TPerfObject(FObjects.Objects[Index])
else
Result:=nil;
end;
function TPerfLibNT.GetObjectCount: integer;
begin
Result:=FPerfData^.NumObjectTypes;
end;
function TPerfLibNT.GetCounterData(ObjectIndex,
InstanceIndex, CounterIndex: DWORD): PChar;
var
po: PPERF_OBJECT_TYPE;
pc: PPERF_COUNTER_DEFINITION;
pi: PPERF_INSTANCE_DEFINITION;
i: DWORD;
begin
po:=FirstObject(FPerfData);
if ObjectIndex>0 then
for i:=0 to ObjectIndex-1 do
po:=NextObject(po);
pc:=FirstCounter(po);
if CounterIndex>0 then
for i:=0 to CounterIndex-1 do
pc:=NextCounter(pc);
if Integer(po^.NumInstances)>0 then begin
pi:=FirstInstance(po);
if InstanceIndex>0 then
for i:=0 to InstanceIndex-1 do
pi:=NextInstance(pi);
Result:=PChar(pi)+pi^.ByteLength+pc^.CounterOffset;
end else begin
Result:=PChar(po)+po^.DefinitionLength+pc^.CounterOffset;
end;
end;
procedure TPerfLibNT.ReadObjects;
var
PerfObj: PPERF_OBJECT_TYPE;
PO: TPerfObject;
i: integer;
begin
while FObjects.Count>0 do begin
FObjects.Objects[FObjects.Count-1].Free;
FObjects.Delete(FObjects.Count-1);
end;
PerfObj:=FirstObject(FPerfData);
for i:=0 to FPerfData^.NumObjectTypes-1 do begin
PO:=TPerfObject.Create(FObjects.Count,Self,PerfObj);
FObjects.AddObject(PO.Name,PO);
PerfObj:=NextObject(PerfObj);
end;
end;
procedure TPerfLibNT.Refresh;
begin
GetNameStrings;
TakeSnapShot;
ReadObjects;
end;
procedure TPerfLibNT.TakeSnapshot;
var
BufferSize: DWORD;
const
BYTEINCREMENT = 4096;
begin
BufferSize:=MaxWord;
ReallocMem(FPerfData,BufferSize);
while RegQueryValueEx(HKEY_PERFORMANCE_DATA,rkGlobal,nil,nil,PBYTE(FPerfData),@BufferSize)=ERROR_MORE_DATA do begin
BufferSize:=BufferSize+BYTEINCREMENT;
ReallocMem(FPerfData,BufferSize);
end;
FPerfTime:=FPerfData^.PerfTime;
FPerfFreq:=FPerfData^.PerfFreq;
FPerfTime100nsec:=FPerfData^.PerfTime100nSec;
FVersion:=FPerfData^.Version;
FRevision:=FPerfData^.Revision;
end;
{ TPerfObject }
constructor TPerfObject.Create;
var
PerfCntr: PPERF_COUNTER_DEFINITION;
//PtrToCntr: PPERF_COUNTER_BLOCK;
i :DWORD;
PC: TPerfCounter;
begin
FPerfLib:=APerfLib;
FPerfObj:=APerfObj;
FIndex:=AIndex;
FName:=FPerfLib.Names[FPerfLib.Names.IndexOfObject(TObject(APerfObj^.ObjectNameTitleIndex))];
FDescription:=FPerfLib.Helps[FPerfLib.Helps.IndexOfObject(TObject(APerfObj^.ObjectHelpTitleIndex))];
FCodePage:=APerfObj^.CodePage;
FCounterCount:=APerfObj^.NumCounters;
FDefaultCounter:=APerfObj^.DefaultCounter;
FPerfTime:=APerfObj^.PerfTime;
FPerfFreq:=APerfObj^.PerfFreq;
case APerfObj^.DetailLevel of
PERF_DETAIL_NOVICE: FDetailLevel:=Novice;
PERF_DETAIL_ADVANCED: FDetailLevel:=Advanced;
PERF_DETAIL_EXPERT: FDetailLevel:=Expert;
PERF_DETAIL_WIZARD: FDetailLevel:=Wizard;
end;
FCounters:=TStringList.Create;
PerfCntr:=FirstCounter(APerfObj);
//PtrToCntr:=PPERF_COUNTER_BLOCK(PChar(APerfObj)+APerfObj^.DefinitionLength);
for i:=0 to CounterCount-1 do begin
PC:=TPerfCounter.Create(FCounters.Count,Self,PerfCntr);
FCounters.AddObject(PC.Name,PC);
PerfCntr:=NextCounter(PerfCntr);
end;
end;
destructor TPerfObject.Destroy;
begin
while FCounters.Count>0 do begin
FCounters.Objects[FCounters.Count-1].Free;
FCounters.Delete(FCounters.Count-1);
end;
FCounters.Free;
inherited;
end;
function TPerfObject.GetCounter(Index: integer): TPerfCounter;
begin
if Index<FCounters.Count then
Result:=TPerfCounter(FCounters.Objects[Index])
else
Result:=nil;
end;
function TPerfObject.GetCntrIndexByName(AName: string): integer;
begin
Result:=FCounters.IndexOf(AName);
end;
function TPerfObject.GetInstance(Index: integer): TPerfInstance;
var
pi: PPERF_INSTANCE_DEFINITION;
i: integer;
begin
if Index<InstanceCount then begin
pi:=FirstInstance(FPerfObj);
if Index>0 then
for i:=0 to Index-1 do
pi:=NextInstance(pi);
Result.Name:='';
Result.Index:=Index;
for i:=0 to pi^.NameLength-1 do
if PChar(pi)[pi^.NameOffset+i]<>#0 then
Result.Name:=Result.Name+PChar(pi)[pi^.NameOffset+i];
Result.ID:=pi^.UniqueID;
end;
end;
{function TPerfObject.GetInstIndexByID(AID: DWORD): integer;
var
i: integer;
begin
Result:=-1;
end;
function TPerfObject.GetInstIndexByName(AName: string): integer;
begin
Result:=-1;
end;}
function TPerfObject.GetInstanceCount: integer;
var
po: PPERF_OBJECT_TYPE;
i: integer;
begin
po:=FirstObject(FPerfLib.FPerfData);
if Index>0 then
for i:=0 to Index-1 do
po:=NextObject(po);
Result:=po^.NumInstances;
end;
{ TPerfCounter }
constructor TPerfCounter.Create;
var
idx: integer;
begin
FPerfObject:=APerfObject;
FIndex:=AIndex;
idx:=FPerfObject.PerfLib.Names.IndexOfObject(TObject(APerfCntr^.CounterNameTitleIndex));
if idx>-1 then
FName:=FPerfObject.PerfLib.Names[idx]
else
FName:=SNoname;
idx:=FPerfObject.PerfLib.Helps.IndexOfObject(TObject(APerfCntr^.CounterHelpTitleIndex));
if idx>-1 then
FDescription:=FPerfObject.PerfLib.Helps[idx]
else
FDescription:='';
FCounterOffset:=APerfCntr^.CounterOffset;
FDefaultScale:=APerfCntr^.DefaultScale;
FCounterSize:=APerfCntr^.CounterSize;
FCounterType:=APerfCntr^.CounterType;
case APerfCntr^.DetailLevel of
PERF_DETAIL_NOVICE: FDetailLevel:=Novice;
PERF_DETAIL_ADVANCED: FDetailLevel:=Advanced;
PERF_DETAIL_EXPERT: FDetailLevel:=Expert;
PERF_DETAIL_WIZARD: FDetailLevel:=Wizard;
end;
end;
destructor TPerfCounter.Destroy;
begin
inherited;
end;
function TPerfCounter.GetData;
begin
result:=FPerfObject.PerfLib.GetCounterData(FPerfObject.Index,InstanceIndex,Self.Index);
end;
function TPerfCounter.GetDataStr;
begin
Result:=FormatData(CounterType,CounterSize,False,Data[InstanceIndex]);
end;
function TPerfCounter.GetDataStrEx;
begin
Result:=FormatData(CounterType,CounterSize,True,Data[InstanceIndex]);
end;
end.