如何从 Delphi 读取 PerfMon PhysicalDisk\Average Disk sec/Read 计数器?
Posted
技术标签:
【中文标题】如何从 Delphi 读取 PerfMon PhysicalDisk\\Average Disk sec/Read 计数器?【英文标题】:How can I read PerfMon PhysicalDisk\Average Disk sec/Read counter from Delphi?如何从 Delphi 读取 PerfMon PhysicalDisk\Average Disk sec/Read 计数器? 【发布时间】:2015-11-20 14:48:29 【问题描述】:如何从 Delphi 读取 PhysicalDisk\Average Disk sec/Read
和其他类似的性能计数器?
我怀疑我应该使用 RRUZ 的 WMI 类生成器,但我不知道我需要哪个类,或者如何使用它。
【问题讨论】:
【参考方案1】:这应该让你开始:
$APPTYPE CONSOLE
uses
SysUtils,
ActiveX,
ComObj,
Variants;
procedure Main;
var
objWMIService: OleVariant;
colItems: OleVariant;
colItem: OleVariant;
oEnum: IEnumvariant;
iValue: LongWord;
function GetWMIObject(const objectName: String): IDispatch;
var
chEaten: Integer;
BindCtx: IBindCtx;
Moniker: IMoniker;
begin
OleCheck(CreateBindCtx(0, BindCtx));
OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten,
Moniker));
OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
end;
begin
objWMIService := GetWMIObject('winmgmts:\\localhost\root\CIMV2');
colItems := objWMIService.ExecQuery
('Select * from Win32_perfformatteddata_perfdisk_LogicalDisk', 'WQL', 0);
oEnum := IUnknown(colItems._NewEnum) as IEnumvariant;
while oEnum.Next(1, colItem, iValue) = 0 do
begin
Writeln(colItem.Name + ', ' + IntToStr(colItem.AvgDiskSecPerRead));
end;
end;
begin
try
CoInitialize(nil);
try
Main;
Readln;
finally
CoUninitialize;
end;
except
on E: Exception do
begin
Writeln(E.Classname, ': ', E.Message);
Readln;
end;
end;
end.
我假设您对 WMI 有足够的了解,可以完成剩下的工作。这个 WMI 类的文档在这里:Win32_PerfFormattedData_PerfDisk_LogicalDisk。
如果您想在 Rodrigo 的库之上构建它,那么我在这里推荐您:https://github.com/RRUZ/delphi-wmi-class-generator/blob/master/root_CIMV2/uWin32_PerfFormattedData_PerfDisk_LogicalDisk.pas
【讨论】:
【参考方案2】:如果有帮助,您也可以直接读取性能数据。这是一个使用我的PerfUtils
和从JEDI API Library 翻译的winperf.h 的快速示例:
program test;
$APPTYPE CONSOLE
$R *.res
uses
System.SysUtils,
JwaWinPerf,
PerfUtils in 'PerfUtils.pas';
const
CtrAvgDiskSecPerRead = 208;
procedure GetCounterAverageTimer(Obj: PPerfObjectType; NameIndex, InstanceIndex: Cardinal;
out TimerValue, BaseValue: Cardinal);
var
CounterTimer, CounterBase: PPerfCounterDefinition;
Instance: PPerfInstanceDefinition;
begin
TimerValue := 0;
BaseValue := 0;
// average timer counter
CounterTimer := GetCounterByNameIndex(Obj, NameIndex);
if not Assigned(CounterTimer) or (CounterTimer^.CounterType <> PERF_AVERAGE_TIMER) then
Exit;
// average base counter
CounterBase := GetNextCounter(CounterTimer);
if not Assigned(CounterBase) or (CounterBase^.CounterNameTitleIndex <> NameIndex) or
(CounterBase^.CounterType <> PERF_AVERAGE_BASE) then
Exit;
Instance := GetInstance(Obj, InstanceIndex);
if not Assigned(Instance) then
Exit;
TimerValue := GetCounterValue32(Obj, CounterTimer, Instance);
BaseValue := GetCounterValue32(Obj, CounterBase, Instance);
end;
function GetPhysicalDiskAvgSecPerRead(DiskInstance: Integer; Data1, Data2: PPerfDataBlock): Double;
var
Obj1, Obj2: PPerfObjectType;
TimerValue1, TimerValue2, BaseValue1, BaseValue2: Cardinal;
begin
Result := 0;
Obj1 := GetObjectByNameIndex(Data1, ObjPhysicalDisk);
Obj2 := GetObjectByNameIndex(Data2, ObjPhysicalDisk);
if not Assigned(Obj1) or not Assigned(Obj2) then
Exit;
GetCounterAverageTimer(Obj1, CtrAvgDiskSecPerRead, DiskInstance, TimerValue1, BaseValue1);
GetCounterAverageTimer(Obj2, CtrAvgDiskSecPerRead, DiskInstance, TimerValue2, BaseValue2);
if (TimerValue2 = TimerValue1) or (BaseValue2 = BaseValue1) then
Exit;
Result := (Int64(TimerValue2 - TimerValue1) / Data1^.PerfFreq.QuadPart) / Int64(BaseValue2 - BaseValue1);
end;
function GetDiskInstanceName(DiskInstance: Integer; Data: PPerfDataBlock): WideString;
var
Obj: PPerfObjectType;
Instance: PPerfInstanceDefinition;
begin
Result := '';
Obj := GetObjectByNameIndex(Data, ObjPhysicalDisk);
if not Assigned(Obj) then
Exit;
Instance := GetInstance(Obj, DiskInstance);
if not Assigned(Instance) then
Exit;
SetString(Result, PWideChar(NativeUInt(Instance) + Instance^.NameOffset), Instance^.NameLength div SizeOf(WideChar));
end;
procedure Main;
var
DiskInstance: Integer;
Data1, Data2: PPerfDataBlock;
begin
DiskInstance := 0; // first physical disk by default
if ParamCount > 0 then
DiskInstance := StrToInt(ParamStr(1));
Data1 := GetPerformanceData(IntToStr(ObjPhysicalDisk));
Writeln(Format('Disk instance %s', [GetDiskInstanceName(DiskInstance, Data1)]));
repeat
Sleep(1000);
Data2 := GetPerformanceData(IntToStr(ObjPhysicalDisk));
Writeln(Format('%.6f', [GetPhysicalDiskAvgSecPerRead(DiskInstance, Data1, Data2)]));
Data1 := Data2;
until False;
end;
begin
try
Main;
except
on E: Exception do
begin
ExitCode := 1;
Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
end;
end;
end.
【讨论】:
以上是关于如何从 Delphi 读取 PerfMon PhysicalDisk\Average Disk sec/Read 计数器?的主要内容,如果未能解决你的问题,请参考以下文章
SQLite - 如何从 XML 文件插入 JPG 图像(使用 Delphi 2009)