How can I improve the WMI performance using delphi?

前端 未结 2 948
别那么骄傲
别那么骄傲 2020-12-30 05:54

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

相关标签:
2条回答
  • 2020-12-30 06:27

    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).

    0 讨论(0)
  • 2020-12-30 06:39

    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.

    0 讨论(0)
提交回复
热议问题