获得当前进程/线程 CPU 使用率

有时候,我们需要排除其它进程的影响,单看自己的进程的CPU占用率,而不是整个系统的CPU占用率,那么我们该如何看呢?Windows 提供了一个 API GetProcessTimes 来获得进程的使用时间信息,我们简单封装了下提供给大家:

type
  TProcessCpuUsage = record
  private
    FLastUsed, FLastTime: Int64;
    FCpuCount:Integer;
  public
    class function Create: TProcessCpuUsage; static;
    function Current: Single;
  end;

var
  ProcessCpuUsage: TProcessCpuUsage = (FLastUsed: 0; FLastTime: 0;FCpuCount:0);

{ TProcessCpuUsage }

class function TProcessCpuUsage.Create: TProcessCpuUsage;
begin
  Result.FLastTime := 0;
  Result.FLastUsed := 0;
  Result.FCpuCount := 0;
end;

function TProcessCpuUsage.Current: Single;
var
  Usage, ACurTime: UInt64;
  CreateTime, ExitTime, IdleTime, UserTime, KernelTime: TFileTime;
  function FileTimeToI64(const ATime: TFileTime): Int64;
  begin
    Result := (Int64(ATime.dwHighDateTime) shl 32) + ATime.dwLowDateTime;
  end;
  function GetCPUCount: Integer;
  var
    SysInfo: TSystemInfo;
  begin
    GetSystemInfo(SysInfo);
    Result := SysInfo.dwNumberOfProcessors;
  end;

begin
  Result := 0;
  if GetProcessTimes(GetCurrentProcess, CreateTime, ExitTime, KernelTime,
    UserTime) then
  begin
    ACurTime := GetTickCount;
    Usage := FileTimeToI64(UserTime) + FileTimeToI64(KernelTime);
    if FLastTime <> 0 then
      Result := (Usage - FLastUsed) / (ACurTime - FLastTime) /
        FCpuCount / 100
    else
      FCpuCount:=GetCpuCount;
    FLastUsed := Usage;
    FLastTime := ACurTime;
  end;
end;

具体用法就很简单了,设置一个每秒触发一次的Timer,然后取全局变量ProcessCpuUsage.Current 的值就是进程自身的 CPU  使用率了,简单示例代码如下:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Caption := 'CPU:' + FormatFloat('0.##', ProcessCpuUsage.Current) + '%';
end;

这个代码是从 QWorker  的演示程序中抠出来重写的,移除了与 QDAC 相关的代码,理论上能够用于任意版本的 Delphi 里。

如果要获取线程的 CPU 使用情况,只需要将其中的 GetProcessTimes 替换为 GetThreadTimes 即可,剩下的代码保持不变。

下面是线程版本(和上面实际就差了一个函数,并在Create函数中默认调用了一次Current函数以初始化末次的CPU使用时间,以便下一次统计)

TThreadCpuUsage = record
  private
    FLastUsed, FLastTime: Int64;
    FCpuCount: Integer;
  public
    class function Create: TThreadCpuUsage; static;
    function Current: Single;
  end;
{ TThreadCpuUsage }

class function TThreadCpuUsage.Create: TThreadCpuUsage;
begin
  Result.FLastTime := 0;
  Result.FLastUsed := 0;
  Result.FCpuCount := 0;
  Result.Current;
end;

function TThreadCpuUsage.Current: Single;
var
  Usage, ACurTime: UInt64;
  CreateTime, ExitTime, IdleTime, UserTime, KernelTime: TFileTime;
  function FileTimeToI64(const ATime: TFileTime): Int64;
  begin
    Result := (Int64(ATime.dwHighDateTime) shl 32) + ATime.dwLowDateTime;
  end;
  function GetCPUCount: Integer;
  var
    SysInfo: TSystemInfo;
  begin
    GetSystemInfo(SysInfo);
    Result := SysInfo.dwNumberOfProcessors;
  end;

begin
  Result := 0;
  if GetThreadTimes(GetCurrentThread, CreateTime, ExitTime, KernelTime,
    UserTime) then
  begin
    ACurTime := GetTickCount;
    Usage := FileTimeToI64(UserTime) + FileTimeToI64(KernelTime);
    if FLastTime <> 0 then
      Result := (Usage - FLastUsed) / (ACurTime - FLastTime) / FCpuCount / 100
    else
      FCpuCount := GetCPUCount;
    FLastUsed := Usage;
    FLastTime := ACurTime;
  end;
end;

 

分享到: