简体   繁体   English

如何获取Windows上每个线程的CPU使用率(win32)

[英]How to get the cpu usage per thread on windows (win32)

Looking for Win32 API functions, C++ or Delphi sample code that tells me the CPU usage (percent and/or total CPU time) of a thread (not the total for a process). 寻找Win32 API函数,C ++或Delphi示例代码,它告诉我线程的CPU使用率(百分比和/或总CPU时间)(而不是进程的总和)。 I have the thread ID. 我有线程ID。

I know that Sysinternals Process Explorer can display this information, but I need this information inside my program. 我知道Sysinternals Process Explorer可以显示这些信息,但我在程序中需要这些信息。

You must use these functions to get the cpu usage per thread and process. 您必须使用这些函数来获取每个线程和进程的cpu使用情况。

GetThreadTimes (Retrieves timing information for the specified thread.) GetThreadTimes (检索指定线程的计时信息。)

GetProcessTimes (Retrieves timing information for the specified process.) GetProcessTimes (检索指定进程的计时信息。)

GetSystemTime (Retrieves the current system date and time. The system time is expressed in Coordinated Universal Time UTC) GetSystemTime (检索当前系统日期和时间。系统时间以协调世界时UTC表示)

Here a excellent article from Dr. Dobb's Win32 Performance Measurement Options 这是Dobb博士的Win32性能测量选项的优秀文章

Bye. 再见。

The data you are refering to is available using specific WMI calls. 您使用特定的WMI调用可以获得您要引用的数据。 You can query Win32_Process to get all sorts of process specific information, and query Win32_PerfFormattedData_PerfProc_Process to get the thread count, and given a handle to a thread (what I believe your looking for) you can query Win32_PerfRawData_PerfProc_Thread to get the percent of processor time used. 您可以查询Win32_Process以获取各种特定于进程的信息,并查询Win32_PerfFormattedData_PerfProc_Process以获取线程计数,并给出线程的句柄(我相信您正在寻找),您可以查询Win32_PerfRawData_PerfProc_Thread以获得所用处理器时间的百分比。

There is a library available for Delphi which provides wrappers for most of the WMI queries, however it will take some experimentation to get the exact query your looking for. 有一个可用于Delphi库,它为大多数WMI查询提供包装器,但是需要一些实验才能获得您想要的确切查询。 The query syntax is very sql like, for example on my system to return the percent of processor time for threadid 8, for process id 4 is: 查询语法非常像sql,例如在我的系统上返回threadid 8的处理器时间百分比,因为进程id 4是:

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

Most of the programs which present statistical information about running processes now use WMI to query for this information. 现在,大多数提供有关正在运行的进程的统计信息的程序都使用WMI来查询此信息。

Is important to know that in certain situations, the execution time of a thread may be worthless. 重要的是要知道在某些情况下,线程的执行时间可能毫无价值。 The execution times of each thread are updated every 15 milliseconds usually for multi-core systems, so if a thread completes its task before this time, the runtime will be reset. 对于多核系统,每个线程的执行时间通常每15毫秒更新一次,因此如果线程在此时间之前完成其任务,则将重置运行时。 More details can be obtained on the link: GetThreadTimes function and I was surprised by the result! 更多细节可以在链接上获得: GetThreadTimes函数,我对结果感到惊讶!
and Why GetThreadTimes is wrong 以及为什么GetThreadTimes是错误的

With the help of RRUZ's answer above I finally came up with this code for Borland Delphi: 在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;

Using "GetThreadTimes"? 使用“GetThreadTimes”? If you measure the time between calls to "GetThreadTimes" and store the previous user and/or kernel times then you know how much time the thread has had since you last checked. 如果您测量调用“GetThreadTimes”并存储前一个用户和/或内核时间之间的时间,那么您就知道自上次检查以来该线程已经有多长时间了。 You also know how much time has elapsed in the mean time and thus you can work out how much CPU time was used. 您还知道平均时间已经过了多少时间,因此您可以计算出使用了多少CPU时间。 It would be best (for timer resolution reasons) to make this check every second or so and work out its average CPU usage over that second. 最好(出于计时器分辨率的原因)每隔一秒左右进行一次检查,并计算出其平均CPU使用率。

Here is a simple WMI query wrapper. 是一个简单的WMI查询包装器。 With help of it you can call this to get data: 借助它,您可以调用它来获取数据:

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

Also you might want to look at the Win32_PerfRawData_PerfProc_Thread documentation to see what other properties you can fetch. 您还可以查看Win32_PerfRawData_PerfProc_Thread文档,了解您可以获取的其他属性。

This example uses GetProcessTimes() but can easily be modified to use GetThreadTimes() . 此示例使用GetProcessTimes()但可以轻松修改为使用GetThreadTimes()

ISO C's clock() is SUPPOSED to give you elapsed CPU-seconds when divided by CLOCKS_PER_SEC . 支持ISO C的clock() ,以便在除以CLOCKS_PER_SEC时为您提供经过的CPU秒数。 However the Visual Studio 2019 web page says: 但是,Visual Studio 2019网页说:

The clock function tells how much wall-clock time has passed since the CRT initialization during process start. 时钟功能表示自进程启动期间CRT初始化以来已经过了多少挂钟时间。 Note that this function does not strictly conform to ISO C, which specifies net CPU time as the return value. 请注意,此函数不严格符合ISO C,后者指定净CPU时间作为返回值。

So, here is a stand-in I made. 所以,这是我制作的替身。 On Windows 7/Visual Studio 2017, CLOCKS_PER_SEC is 1000 and GetProcessTimes() only has millisecond accuracy, so no accuracy is lost returning clock_t instead of double , say. 在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
}

And for completeness, here's AKGetLastError(): 为了完整起见,这里是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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM