I wrote a simple function to retrieve system information using the WMI, passing as parameter the class and the property name. when I execute the function like this
These are some tips to improve the WMI performance
1.) Reutilize the call to CreateOleObject
2.) Reuse the WMI Connection
One of more expensive tasks is make a connection to the WMI services, so reutilize that conneciton instead of create one conneciton each time which call the function.
3.) Only retrieve the columns which you want to use
Every property which retrieve the WMI has different sources like the Windows registry, the WinAPi and so on, restricting the columns will improve the performance. read this article for more info How obtain the source of the WMI Data
4.) Use the WBEM_FLAG_FORWARD_ONLY flag when you execute the WQL sentence.
Following the above tips I rewrote your sample app
{$APPTYPE CONSOLE}
uses
Diagnostics,
SysUtils,
ActiveX,
ComObj,
Variants;
var
FSWbemLocator : OLEVariant;
FWMIService : OLEVariant;
function GetWMIInfo(const WMIClass, WMIProperty:string): string;
const
wbemFlagForwardOnly = $00000020;
var
FWbemObjectSet: OLEVariant;
FWbemObject : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
begin;
Result:='';
FWbemObjectSet:= FWMIService.ExecQuery(Format('Select %s from %s',[WMIProperty, WMIClass]),'WQL',wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
if oEnum.Next(1, FWbemObject, iValue) = 0 then
Result:=FWbemObject.Properties_.Item(WMIProperty).Value;
end;
var
SW : TStopwatch;
begin
try
CoInitialize(nil);
try
SW.Reset;
SW.Start;
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
Writeln('Procesor Id '+GetWMIInfo('Win32_Processor','Name'));
Writeln('Mother Board Serial '+GetWMIInfo('Win32_BaseBoard','SerialNumber'));
Writeln('BIOS Version '+GetWMIInfo('Win32_BIOS','Version'));
SW.Stop;
Writeln('Elapsed ms '+FormatFloat('#,0.000',SW.Elapsed.TotalMilliseconds));
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Readln;
end.
And the execution goes from 1245 to 180 ms (on my laptop).
This is a general rule of thumb.
When you say you want to retrieve a lot of additional information I assume that means you will be calling this function a lot, possibly in a loop. For performance tuning, you simply need to take those things that cost a lot of time and that you can reuse, out of the loop i.e. cache them.
In this case the CreateOleObject is likely to be costing you the bulk of the time, as a first pass I would put that outside the loop (or multiple calls) and pass your sWebLocator into the function, as a second pass you might like to take the ConnectServer call out of the function as well and pass the sWMIService object in as well.