23

寻找 Win32 API 函数、C++ 或 Delphi 示例代码,告诉我线程的 CPU 使用率(百分比和/或总 CPU 时间)(而不是进程的总数)。我有线程 ID。

我知道 Sysinternals Process Explorer 可以显示此信息,但我需要在我的程序中使用此信息。

4

7 回答 7

27

您必须使用这些函数来获取每个线程和进程的 cpu 使用率。

GetThreadTimes(检索指定线程的计时信息。)

GetProcessTimes(检索指定进程的计时信息。)

GetSystemTime(检索当前系统日期和时间。系统时间以协调世界时 UTC 表示)

这是 Dobb 博士的Win32 性能测量选项中的一篇优秀文章

再见。

于 2009-09-08T10:07:38.237 回答
11

您所引用的数据可通过特定的WMI调用获得。您可以查询 Win32_Process 以获取各种进程特定信息,并查询 Win32_PerfFormattedData_PerfProc_Process 以获取线程计数,并给出线程句柄(我相信您正在寻找)您可以查询Win32_PerfRawData_PerfProc_Thread以获取使用的处理器时间百分比。

有一个可供 Delphi 使用的库,它为大多数 WMI 查询提供包装器,但是需要一些实验才能获得您正在寻找的确切查询。查询语法非常类似于 sql,例如在我的系统上返回 threadid 8 的处理器时间百分比,进程 id 4 是:

SELECT PercentProcessorTime FROM Win32_PerfRawData_PerfProc_Thread 
  WHERE IdProcess=4 and IdThread=8

大多数提供有关正在运行的进程的统计信息的程序现在都使用 WMI 来查询这些信息。

于 2009-09-08T18:21:40.017 回答
8

重要的是要知道在某些情况下,线程的执行时间可能毫无价值。对于多核系统,每个线程的执行时间通常每 15 毫秒更新一次,因此如果线程在此时间之前完成其任务,则运行时将被重置。可以在链接上获得更多详细信息: GetThreadTimes 函数,我对结果感到惊讶!
以及 为什么 GetThreadTimes 是错误的

于 2009-11-19T12:49:10.233 回答
6

在上面 RRUZ 的回答的帮助下,我终于想出了 Borland Delphi 的这段代码:

const
  THREAD_TERMINATE                 = $0001;
  THREAD_SUSPEND_RESUME            = $0002;
  THREAD_GET_CONTEXT               = $0008;
  THREAD_SET_CONTEXT               = $0010;
  THREAD_SET_INFORMATION           = $0020;
  THREAD_QUERY_INFORMATION         = $0040;
  THREAD_SET_THREAD_TOKEN          = $0080;
  THREAD_IMPERSONATE               = $0100;
  THREAD_DIRECT_IMPERSONATION      = $0200;
  THREAD_SET_LIMITED_INFORMATION   = $0400;
  THREAD_QUERY_LIMITED_INFORMATION = $0800;
  THREAD_ALL_ACCESS                = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $03FF;

function OpenThread(dwDesiredAccess: DWord;
                    bInheritHandle: Bool;
                    dwThreadId: DWord): DWord; stdcall; external 'kernel32.dll';


procedure TForm1.Button1Click(Sender: TObject);
var iii:integer;
    handle:thandle;
    creationtime,exittime,kerneltime,usertime:filetime;
begin
  Handle:=OpenThread(THREAD_SET_INFORMATION or THREAD_QUERY_INFORMATION, False, windows.GetCurrentThreadId);
  if handle<>0 then
  begin
    getthreadtimes(Handle,creationtime,exittime,kerneltime,usertime);
    label1.caption:='Total time for Thread #'+inttostr(windows.GetCurrentThreadId)+': '+inttostr( (int64(kerneltime)+int64(usertime)) div 1000 )+' msec';
    CloseHandle(Handle);
  end;
end;
于 2009-09-08T22:16:04.863 回答
4

使用“GetThreadTimes”?如果您测量调用“GetThreadTimes”之间的时间并存储以前的用户和/或内核时间,那么您就知道自上次检查以来线程已经有多少时间了。您还知道平均时间已经过去了多少时间,因此您可以计算出使用了多少 CPU 时间。最好(出于计时器分辨率的原因)每隔一秒左右进行一次检查,并计算出其在那一秒内的平均 CPU 使用率。

于 2009-09-08T09:45:18.530 回答
1

是一个简单的 WMI 查询包装器。在它的帮助下,您可以调用它来获取数据:

getWmiQueryResult(L"SELECT PercentProcessorTime FROM Win32_PerfRawData_PerfProc_Thread WHERE IdProcess=4 and IdThread=8", L"PercentProcessorTime ");

此外,您可能还想查看Win32_PerfRawData_PerfProc_Thread文档以了解您可以获取哪些其他属性。

于 2018-02-13T13:18:05.997 回答
1

此示例使用GetProcessTimes()但可以很容易地修改为使用GetThreadTimes().

ISO Cclock()应该在除以CLOCKS_PER_SEC. 但是 Visual Studio 2019 网页显示:

时钟函数告诉进程启动期间自 CRT 初始化以来已经过去了多少挂钟时间。请注意,此函数并不严格遵守 ISO C,后者将净 CPU 时间指定为返回值。

所以,这是我做的一个替身。在 Windows 7/Visual Studio 2017 上,CLOCKS_PER_SEC是 1000 并且GetProcessTimes()只有毫秒精度,所以没有精度丢失clock_t而不是返回double,比如说。

clock_t AKClock() {
#ifdef WIN32
  FILETIME  ftimeCreate, ftimeExit, ftimeKernel, ftimeUser;
  SYSTEMTIME stimeKernel, stimeUser;

  if ( ! GetProcessTimes( GetCurrentProcess(), &ftimeCreate, &ftimeExit,
                          &ftimeKernel, &ftimeUser )        ||
       ! FileTimeToSystemTime( &ftimeKernel, &stimeKernel ) ||
       ! FileTimeToSystemTime( &ftimeUser,   &stimeUser   )     ) {
      char szError[ 1024 ];
      MyLoggingFunction( "AKClock() failed; returning -1: %s",
                         AKGetLastError( szError, sizeof( szError ) ) );
      return (clock_t) -1.0;
  }

  return (clock_t)
         ( ( stimeKernel.wHour         * 3600.0 +
             stimeKernel.wMinute       *   60.0 +
             stimeKernel.wSecond                +
             stimeKernel.wMilliseconds / 1000.0 +
             stimeUser.wHour           * 3600.0 +
             stimeUser.wMinute         *   60.0 +
             stimeUser.wSecond                  +
             stimeUser.wMilliseconds   / 1000.0   ) * CLOCKS_PER_SEC );
#else
    return clock();
#endif
}

为了完整起见,这里是 AKGetLastError():

void AKstrncpy( char *pszDest, const char *pszSrc, const size_t sDest ) {

  strncpy( pszDest, pszSrc, sDest );
  pszDest[ sDest - 1 ] = '\0';
}

char* AKGetLastError( char* szBuf, int iBufSize ) {

  DWORD  errorMessageID = GetLastError();
  char*  pszError = NULL;
  size_t sizeBuf;

  if( errorMessageID == 0 ) {
      AKstrncpy( szBuf, "(no error)", iBufSize );
      return szBuf;
  }

  sizeBuf = FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, errorMessageID, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
            (LPSTR) &pszError, 0, NULL );

  AKstrncpy( szBuf, pszError, iBufSize );

  LocalFree( pszError );

  int iLen = strlen( szBuf );
  if ( strcmp( szBuf + iLen - 2, "\r\n" ) == 0 )
      szBuf[ iLen - 2 ] = '\0';

  return szBuf;
}
于 2019-05-14T05:28:38.423 回答