C++ 如何在 Windows (win32) 上获取每个线程的 CPU 使用率
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1393006/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get the cpu usage per thread on windows (win32)
提问by Dirk Paessler
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). I have the thread ID.
寻找 Win32 API 函数、C++ 或 Delphi 示例代码,这些代码告诉我线程(而不是进程的总数)的 CPU 使用率(百分比和/或总 CPU 时间)。我有线程 ID。
I know that Sysinternals Process Explorer can display this information, but I need this information inside my program.
我知道 Sysinternals Process Explorer 可以显示此信息,但我的程序中需要此信息。
采纳答案by Dirk Paessler
With the help of RRUZ's answer above I finally came up with this code for Borland Delphi:
在上面 RRUZ 的回答的帮助下,我终于为 Borland Delphi 想出了这个代码:
const
THREAD_TERMINATE = SELECT PercentProcessorTime FROM Win32_PerfRawData_PerfProc_Thread
WHERE IdProcess=4 and IdThread=8
01;
THREAD_SUSPEND_RESUME = getWmiQueryResult(L"SELECT PercentProcessorTime FROM Win32_PerfRawData_PerfProc_Thread WHERE IdProcess=4 and IdThread=8", L"PercentProcessorTime ");
02;
THREAD_GET_CONTEXT = 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
}
08;
THREAD_SET_CONTEXT = void AKstrncpy( char *pszDest, const char *pszSrc, const size_t sDest ) {
strncpy( pszDest, pszSrc, sDest );
pszDest[ sDest - 1 ] = '##代码##';
}
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 ] = '##代码##';
return szBuf;
}
10;
THREAD_SET_INFORMATION = ##代码##20;
THREAD_QUERY_INFORMATION = ##代码##40;
THREAD_SET_THREAD_TOKEN = ##代码##80;
THREAD_IMPERSONATE = 00;
THREAD_DIRECT_IMPERSONATION = 00;
THREAD_SET_LIMITED_INFORMATION = 00;
THREAD_QUERY_LIMITED_INFORMATION = 00;
THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or FF;
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;
回答by RRUZ
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.
再见。
回答by skamradt
The data you are refering to is available using specific WMIcalls. 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_Threadto get the percent of processor time used.
您所引用的数据可使用特定的WMI调用获得。您可以查询 Win32_Process 以获取各种特定于进程的信息,并查询 Win32_PerfFormattedData_PerfProc_Process 以获取线程数,并提供线程的句柄(我相信您正在寻找),您可以查询Win32_PerfRawData_PerfProc_Thread以获取使用的处理器时间百分比。
There is a library available for Delphiwhich provides wrappers for most of the WMI queries, however it will take some experimentation to get the exact query your looking for. 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:
有一个可用于 Delphi的库,它为大多数 WMI 查询提供包装器,但是需要进行一些实验才能获得您要查找的确切查询。查询语法非常像 sql,例如在我的系统上返回线程 ID 8 的处理器时间百分比,进程 ID 4 是:
##代码##Most of the programs which present statistical information about running processes now use WMI to query for this information.
大多数提供有关正在运行的进程的统计信息的程序现在都使用 WMI 来查询这些信息。
回答by lsalamon
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.
More details can be obtained on the link:
GetThreadTimes function and I was surprised by the result!
and
Why GetThreadTimes is wrong
重要的是要知道在某些情况下,线程的执行时间可能毫无价值。对于多核系统,每个线程的执行时间通常每 15 毫秒更新一次,因此如果线程在此时间之前完成其任务,则运行时将被重置。可以在链接上获得更多详细信息:
GetThreadTimes 函数,我对结果感到惊讶!
以及
为什么 GetThreadTimes 是错误的
回答by Goz
Using "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. You also know how much time has elapsed in the mean time and thus you can work out how much CPU time was used. 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.
使用“GetThreadTimes”?如果您测量对“GetThreadTimes”的调用之间的时间并存储先前的用户和/或内核时间,那么您就知道自上次检查以来该线程已拥有多长时间。您还知道平均时间过去了多少时间,因此您可以计算出使用了多少 CPU 时间。最好(出于计时器分辨率的原因)每隔一秒左右进行一次检查,并计算出该秒内的平均 CPU 使用率。
回答by Just Shadow
Hereis a simple WMI query wrapper. With help of it you can call this to get data:
这是一个简单的 WMI 查询包装器。在它的帮助下,您可以调用它来获取数据:
##代码##Also you might want to look at the Win32_PerfRawData_PerfProc_Threaddocumentation to see what other properties you can fetch.
此外,您可能还想查看Win32_PerfRawData_PerfProc_Thread文档以了解您可以获取哪些其他属性。
回答by Swiss Frank
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
. However the Visual Studio 2019 web page says:
ISO Cclock()
应该为您提供除以CLOCKS_PER_SEC
. 但是 Visual Studio 2019 网页说:
The clock function tells how much wall-clock time has passed since the CRT initialization during process start. Note that this function does not strictly conform to ISO C, which specifies net CPU time as the return value.
时钟函数告诉在进程启动期间自 CRT 初始化以来已经过去了多少挂钟时间。请注意,此函数并不严格遵守 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
,比如说。
And for completeness, here's AKGetLastError():
为了完整起见,这里是 AKGetLastError():
##代码##