寻找 Win32 API 函数、C++ 或 Delphi 示例代码,告诉我线程的 CPU 使用率(百分比和/或总 CPU 时间)(而不是进程的总数)。我有线程 ID。
我知道 Sysinternals Process Explorer 可以显示此信息,但我需要在我的程序中使用此信息。
寻找 Win32 API 函数、C++ 或 Delphi 示例代码,告诉我线程的 CPU 使用率(百分比和/或总 CPU 时间)(而不是进程的总数)。我有线程 ID。
我知道 Sysinternals Process Explorer 可以显示此信息,但我需要在我的程序中使用此信息。
您必须使用这些函数来获取每个线程和进程的 cpu 使用率。
GetThreadTimes(检索指定线程的计时信息。)
GetProcessTimes(检索指定进程的计时信息。)
GetSystemTime(检索当前系统日期和时间。系统时间以协调世界时 UTC 表示)
这是 Dobb 博士的Win32 性能测量选项中的一篇优秀文章
再见。
您所引用的数据可通过特定的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 来查询这些信息。
重要的是要知道在某些情况下,线程的执行时间可能毫无价值。对于多核系统,每个线程的执行时间通常每 15 毫秒更新一次,因此如果线程在此时间之前完成其任务,则运行时将被重置。可以在链接上获得更多详细信息:
GetThreadTimes 函数,我对结果感到惊讶!
以及
为什么 GetThreadTimes 是错误的
在上面 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;
使用“GetThreadTimes”?如果您测量调用“GetThreadTimes”之间的时间并存储以前的用户和/或内核时间,那么您就知道自上次检查以来线程已经有多少时间了。您还知道平均时间已经过去了多少时间,因此您可以计算出使用了多少 CPU 时间。最好(出于计时器分辨率的原因)每隔一秒左右进行一次检查,并计算出其在那一秒内的平均 CPU 使用率。
这是一个简单的 WMI 查询包装器。在它的帮助下,您可以调用它来获取数据:
getWmiQueryResult(L"SELECT PercentProcessorTime FROM Win32_PerfRawData_PerfProc_Thread WHERE IdProcess=4 and IdThread=8", L"PercentProcessorTime ");
此外,您可能还想查看Win32_PerfRawData_PerfProc_Thread文档以了解您可以获取哪些其他属性。
此示例使用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;
}