使用 C++ 在 Windows 中检索 CPU 总负载百分比
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23143693/
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
Retrieving CPU Load Percent total in Windows with C++
提问by kayleeFrye_onDeck
I've been working on this tool to quickly log some system stats, like memory info, and cpu load percentage(like what's shown in the Task Manager). I seem to have the memory and logging part taken care of, but figuring out the CPU percentage has been very tough :( I've found a lot info on methods to check CPU info, but outside of abstracts pretty much none of the code samples I've found compile, or are well commented, so it's been hard for me to hash out a way to do this. I've already read through a lot of stackoverflow questions about getting CPU timings and such, but I haven't been able to put the pieces together.
我一直在研究这个工具来快速记录一些系统统计信息,比如内存信息和CPU 负载百分比(比如任务管理器中显示的内容)。我似乎处理了内存和日志记录部分,但是计算 CPU 百分比非常困难:( 我找到了很多关于检查 CPU 信息的方法的信息,但在摘要之外几乎没有任何代码示例我找到了编译,或者评论很好,所以我很难找到一种方法来做到这一点。我已经阅读了很多关于获取 CPU 计时等的计算器问题,但我还没有能够将碎片拼凑在一起。
Maybe I'm missing the point, but it seems like a popular way to figure this out is by querying the CPU two times with at least 200ms between each check to help avoid problems with something called... resolution? So yeah! How the heck do I do that? :( I'm syntactically challenged D:
也许我没有抓住重点,但似乎一种流行的解决方法是通过两次查询 CPU 两次,每次检查之间至少间隔 200 毫秒,以帮助避免出现称为...分辨率的问题?是的!我他妈的怎么做?:( 我在语法上受到挑战 D:
I'm going to share my source code so you can see what exactly I've been up to, up until now. It's all in just one .cpp, I'm using VS2013 Express for C++, and it's only for Windowsfor multicore CPUs.
我将分享我的源代码,这样你就可以看到我一直在做什么,直到现在。这一切都在一个 .cpp 中,我使用VS2013 Express for C++,它仅适用于多核 CPU 的Windows。
Warning in advance: I'm so sorry for all the comments in the code :x Also, if you copy this code and run it, it's going to generate a .CSV file called log.CSV
提前警告:我对代码中的所有注释感到抱歉 :x 另外,如果您复制此代码并运行它,它将生成一个名为 log.CSV 的 .CSV 文件
//included libraries/functionality for input/output
#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;
//creates a static variable to convert Bytes to Megabytes
#define MB 1048576
//main program code loop
int main()
{
//Code block intiialization for the memory referenced in the Kernell
MEMORYSTATUSEX memStat;
memStat.dwLength = sizeof (memStat);
GlobalMemoryStatusEx(&memStat);
//loads the SYSTEMTIME
SYSTEMTIME sysTime;
//Retrieves data so that we have a way to Get it to output when using the pointers
GetSystemTime(&sysTime);
//setting the I/O for our log file to be "myfile"
ofstream myfile;
// ios::out means that we're outputting data to the file
// ios::app means that all the data we're outputting goes to the end of that log file instead of the start
myfile.open("log.csv", ios::out | ios::app);
//a while loop that gathers and logs data every quarter of a second to gather 4 data points in one second
int counter = 0;
while (counter < 4)
{
//Timestamp + Memory Info, and eventually CPU Load percentage
myfile << sysTime.wHour << ":" << sysTime.wMinute << ":" << sysTime.wMilliseconds << ", " << memStat.dwMemoryLoad << "%, " << memStat.ullTotalPhys / MB << ", " << memStat.ullAvailPhys / MB << ", " << memStat.ullTotalPageFile / MB << ", " << memStat.ullAvailPageFile / MB << ", " << memStat.ullTotalVirtual / MB << ", " << memStat.ullAvailVirtual / MB << ", " << memStat.ullAvailExtendedVirtual / MB << "\n";
//250 millisecond sleep delay
Sleep(250);
counter = counter + 1;
}
//close the log file before terminating the program
myfile.close();
return 0; //standard main() end of program terminator
}
edit#2:
编辑#2:
I ran across this
我遇到了这个
BOOL WINAPI GetSystemTimes(_Out_opt_ LPFILETIME lpIdleTime,_Out_opt_ LPFILETIME lpKernelTime,_Out_opt_ LPFILETIME lpUserTime);
It seems like it is getting the stuff I need, but I don't know how to actually use it or even make a unit test out of it, which I'd prefer before throwing it in the rest of my Source.cpp
似乎它正在获取我需要的东西,但我不知道如何实际使用它,甚至不知道如何使用它进行单元测试,我更喜欢在将其放入 Source.cpp 的其余部分之前
I am completely lost. I've tried all sorts of things for the last few hours, but I can't even get a simple unit test compiling.
我完全迷失了。在过去的几个小时里,我尝试了各种方法,但我什至无法进行简单的单元测试编译。
I feel like this comment has me on the right path, but I don't actually know what to do with it: How is CPU usage calculated?
我觉得这条评论让我走上了正确的道路,但我实际上不知道该怎么做:CPU 使用率是如何计算的?
edit #3:
编辑#3:
I'm showing a Unit Test for Jeremy Friesner's code, as well as the completed logging tool that I was working on.
我正在展示 Jeremy Friesner 代码的单元测试,以及我正在开发的完整日志工具。
Test to monitor CPU Load
测试以监控 CPU 负载
#include <Windows.h>
#include <iostream>
using namespace std;
static float CalculateCPULoad();
static unsigned long long FileTimeToInt64();
float GetCPULoad();
int main()
{
int _c = 0;
while (_c == 0)
{
cout << GetCPULoad() * 100 << "\n";
Sleep(1000);
}
return 0;
}
static float CalculateCPULoad(unsigned long long idleTicks, unsigned long long totalTicks)
{
static unsigned long long _previousTotalTicks = 0;
static unsigned long long _previousIdleTicks = 0;
unsigned long long totalTicksSinceLastTime = totalTicks - _previousTotalTicks;
unsigned long long idleTicksSinceLastTime = idleTicks - _previousIdleTicks;
float ret = 1.0f - ((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime) / totalTicksSinceLastTime : 0);
_previousTotalTicks = totalTicks;
_previousIdleTicks = idleTicks;
return ret;
}
static unsigned long long FileTimeToInt64(const FILETIME & ft)
{
return (((unsigned long long)(ft.dwHighDateTime)) << 32) | ((unsigned long long)ft.dwLowDateTime);
}
// Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
// You'll need to call this at regular intervals, since it measures the load between
// the previous call and the current one. Returns -1.0 on error.
float GetCPULoad()
{
FILETIME idleTime, kernelTime, userTime;
return GetSystemTimes(&idleTime, &kernelTime, &userTime) ? CalculateCPULoad(FileTimeToInt64(idleTime), FileTimeToInt64(kernelTime) + FileTimeToInt64(userTime)) : -1.0f;
}
Completed Tool (all goes into your Source.cpp, then compile and run):
完成的工具(全部进入你的 Source.cpp,然后编译并运行):
/*
Resource Links:
Calling memory info in c++: http://msdn.microsoft.com/en-us/library/aa366589%28VS.85%29.aspx
I/O file handling in c++: http://www.cplusplus.com/doc/tutorial/files/
Date and Time in c++: http://www.tutorialspoint.com/cplusplus/cpp_date_time.htm
CPU Load Percent (Credit to Jeremy Friesner): https://stackoverflow.com/questions/23143693/retrieving-cpu-load-percent-total-in-windows-with-c
Everything else (too many to list): https://stackoverflow.com/
*/
/*
Performance Snapshot Tool
Grabs CPU load percent and basic Memory info from the system,
and or the Windows Task manager
Designed to work with specifically Windows 7 and beyond
Ideology: Create a small executable program to retrieve and
write to a log file a data sample from system performance
in a single snapshot -- robust enough to be called multiple
times per boot
The compiled .exe will be called by another program to run at
an exact, specified time relative to the program that is
calling it
Does 5 checks per second, every 200 milliseconds for a "Snapshot"
of performance
Initial Code Author: Anonymous
Current Author: Anonymous
Revision: 0.01
Date: 18/4/2014
*/
//included libraries/functionality for input/output
#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;
//creates a static variable to convert Bytes to Megabytes
#define MB 1048576
//functions to calculate and retrieve CPU Load information
static float CalculateCPULoad();
static unsigned long long FileTimeToInt64();
float GetCPULoad();
//main program code loop
int main()
{
//Code block initialization for the memory referenced in the Kernel
MEMORYSTATUSEX memStat;
memStat.dwLength = sizeof (memStat);
GlobalMemoryStatusEx(&memStat);
//loads the SYSTEMTIME
SYSTEMTIME sysTime;
//Retrieves data so that we have a way to Get it to output when using the pointers
GetSystemTime(&sysTime);
//setting the I/O for our log file to be "myfile"
ofstream myfile;
// ios::out means that we're outputting data to the file
// ios::app means that all the data we're outputting goes to the end of that log file instead of the start
myfile.open("log.csv", ios::out | ios::app);
//a while loop that gathers and logs data every quarter of a second to gather 4 data points in one second
int counter = 0;
while (counter < 5)
{
//Timestamp + Memory Info, and eventually CPU Load percentage
myfile << sysTime.wHour << "." << sysTime.wMinute << "." << sysTime.wSecond << ", " << GetCPULoad() * 100 << "%, " << memStat.dwMemoryLoad << "%, " << memStat.ullTotalPhys / MB << ", " << memStat.ullAvailPhys / MB << ", " << memStat.ullTotalPageFile / MB << ", " << memStat.ullAvailPageFile / MB << ", " << memStat.ullTotalVirtual / MB << ", " << memStat.ullAvailVirtual / MB << ", " << memStat.ullAvailExtendedVirtual / MB << "\n";
//250 millisecond sleep delay
Sleep(200);
counter = counter + 1;
}
//close the log file before terminating the program
myfile.close();
return 0; //standard main() end of program terminator
}
static float CalculateCPULoad(unsigned long long idleTicks, unsigned long long totalTicks)
{
static unsigned long long _previousTotalTicks = 0;
static unsigned long long _previousIdleTicks = 0;
unsigned long long totalTicksSinceLastTime = totalTicks - _previousTotalTicks;
unsigned long long idleTicksSinceLastTime = idleTicks - _previousIdleTicks;
float ret = 1.0f - ((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime) / totalTicksSinceLastTime : 0);
_previousTotalTicks = totalTicks;
_previousIdleTicks = idleTicks;
return ret;
}
static unsigned long long FileTimeToInt64(const FILETIME & ft)
{
return (((unsigned long long)(ft.dwHighDateTime)) << 32) | ((unsigned long long)ft.dwLowDateTime);
}
// Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
// You'll need to call this at regular intervals, since it measures the load between
// the previous call and the current one. Returns -1.0 on error.
float GetCPULoad()
{
FILETIME idleTime, kernelTime, userTime;
return GetSystemTimes(&idleTime, &kernelTime, &userTime) ? CalculateCPULoad(FileTimeToInt64(idleTime), FileTimeToInt64(kernelTime) + FileTimeToInt64(userTime)) : -1.0f;
}
采纳答案by Jeremy Friesner
The reason it's popular to compute the load percentage over time is because CPUs don't really have variable speeds -- at any given instant, a CPU core is either processing instructions at its rated clock rate, or it's sitting idle, so an instantaneous measurement would only give you 0% or 100% (*), which isn't really what you want. So in order to calculate a meaningfulload percentage, you have to examine what percentage of time the CPU was idle during a particular interval of time.
随着时间的推移计算负载百分比很流行的原因是因为 CPU 并没有真正的可变速度——在任何给定的时刻,CPU 内核要么以其额定时钟速率处理指令,要么处于空闲状态,因此是即时测量只会给你 0% 或 100% (*),这不是你真正想要的。因此,为了计算有意义的负载百分比,您必须检查 CPU在特定时间间隔内空闲的时间百分比。
In any case, here's some code I use to get a CPU-usage value under Windows... just call GetCPULoad() at regular intervals (e.g. every 250mS or at whatever rate you like) and multiply by 100.0 to get a percentage:
无论如何,这是我用来在 Windows 下获取 CPU 使用率值的一些代码……只需定期调用 GetCPULoad()(例如每 250 毫秒或以您喜欢的任何速率)并乘以 100.0 即可获得百分比:
#include <Windows.h>
static float CalculateCPULoad(unsigned long long idleTicks, unsigned long long totalTicks)
{
static unsigned long long _previousTotalTicks = 0;
static unsigned long long _previousIdleTicks = 0;
unsigned long long totalTicksSinceLastTime = totalTicks-_previousTotalTicks;
unsigned long long idleTicksSinceLastTime = idleTicks-_previousIdleTicks;
float ret = 1.0f-((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime)/totalTicksSinceLastTime : 0);
_previousTotalTicks = totalTicks;
_previousIdleTicks = idleTicks;
return ret;
}
static unsigned long long FileTimeToInt64(const FILETIME & ft) {return (((unsigned long long)(ft.dwHighDateTime))<<32)|((unsigned long long)ft.dwLowDateTime);}
// Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
// You'll need to call this at regular intervals, since it measures the load between
// the previous call and the current one. Returns -1.0 on error.
float GetCPULoad()
{
FILETIME idleTime, kernelTime, userTime;
return GetSystemTimes(&idleTime, &kernelTime, &userTime) ? CalculateCPULoad(FileTimeToInt64(idleTime), FileTimeToInt64(kernelTime)+FileTimeToInt64(userTime)) : -1.0f;
}
(*) Okay, you might get a bit more resolution on a multicore system; e.g. if you measured instantaneous CPU usage on a quad-core CPU you might find that at that particular instant in time, three cores were idle and one core was active, and call that 25% load... and of course there are things like Intel's SpeedStep that actually varies the CPU's clock rate as a way to manage power consumption; but we'll ignore those complications for the time being :)
(*) 好的,您可能会在多核系统上获得更高的分辨率;例如,如果您测量四核 CPU 上的瞬时 CPU 使用率,您可能会发现在那个特定时刻,三个内核空闲,一个内核处于活动状态,并称其为 25% 负载……当然还有诸如英特尔的 SpeedStep 实际上改变了 CPU 的时钟频率,作为管理功耗的一种方式;但我们暂时忽略这些并发症:)
回答by El Ronaldo
The most popular proposed solution does not work for me on Win10 / Visual Studio 2010; the values obtained with that method do not seem to correlate with anything. Perhaps this is because, as noted in comments by Belogortseff, the GetSystemTimes function return for kernel time includes idle time.
最流行的建议解决方案在 Win10 / Visual Studio 2010 上对我不起作用;用该方法获得的值似乎与任何东西都没有关联。也许这是因为,正如 Belogartseff 在评论中指出的那样,内核时间的 GetSystemTimes 函数返回包括空闲时间。
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724400(v=vs.85).aspxfor a description of the GetSystemTimes function.
有关 GetSystemTimes 函数的说明,请参阅https://msdn.microsoft.com/en-us/library/windows/desktop/ms724400(v=vs.85).aspx。
Furthermore, I'm not sure what happens when you assign the subtraction of two unsigned numbers, to another unsigned number. Seems like that should still be unsigned, but the proposed solution does a test on that value being less than zero.
此外,我不确定当您将两个无符号数的减法分配给另一个无符号数时会发生什么。看起来应该仍然是无符号的,但建议的解决方案对该值进行了测试,该值小于零。
I computed "headroom" this way:
我这样计算“净空”:
Headroom = time spent in idle
/
(Kernel time + User time)
and then "load" as:
然后“加载”为:
Load = 1 - Headroom
Here is example code that you should be able to cut and paste into a VS project. If run under the VS debugger, it will display the results in the Output Window of the debugger via the OutputDebugString() call.
这是您应该能够剪切并粘贴到 VS 项目中的示例代码。如果在 VS 调试器下运行,它将通过 OutputDebugString() 调用在调试器的输出窗口中显示结果。
// DOSHeadroom.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <atlstr.h>
#include <iostream>
__int64 FileTimeToInt64 ( FILETIME & ft )
{
ULARGE_INTEGER foo;
foo.LowPart = ft.dwLowDateTime;
foo.HighPart = ft.dwHighDateTime;
return ( foo.QuadPart );
}
// UI Timer callback
VOID CALLBACK UITimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
#define NUMBER_OF_PROCESSORS (8)
#define PROCESSOR_BUFFER_SIZE (NUMBER_OF_PROCESSORS * 8)
static ULONG64 ProcessorIdleTimeBuffer [ PROCESSOR_BUFFER_SIZE ];
CString ProcessorHeadroomPercentage;
FILETIME IdleTime, KernelTime, UserTime;
static unsigned long long PrevTotal = 0;
static unsigned long long PrevIdle = 0;
static unsigned long long PrevUser = 0;
unsigned long long ThisTotal;
unsigned long long ThisIdle, ThisKernel, ThisUser;
unsigned long long TotalSinceLast, IdleSinceLast, UserSinceLast;
// GET THE KERNEL / USER / IDLE times.
// And oh, BTW, kernel time includes idle time
GetSystemTimes( & IdleTime, & KernelTime, & UserTime);
ThisIdle = FileTimeToInt64(IdleTime);
ThisKernel = FileTimeToInt64 (KernelTime);
ThisUser = FileTimeToInt64 (UserTime);
ThisTotal = ThisKernel + ThisUser;
TotalSinceLast = ThisTotal - PrevTotal;
IdleSinceLast = ThisIdle - PrevIdle;
UserSinceLast = ThisUser - PrevUser;
double Headroom;
Headroom = (double)IdleSinceLast / (double)TotalSinceLast ;
double Load;
Load = 1.0 - Headroom;
Headroom *= 100.0; // to make it percent
Load *= 100.0; // percent
PrevTotal = ThisTotal;
PrevIdle = ThisIdle;
PrevUser = ThisUser;
// print results to output window of VS when run in Debug
ProcessorHeadroomPercentage.Format(_T(" Headroom: %2.0lf%% Load: %2.0lf%%\n"), Headroom, Load);
OutputDebugString(ProcessorHeadroomPercentage);
}
void SetupMyTimer (void)
{
// set up a timer to periodically update UI, specifically to support headroom display
// I'll use a timerQueue for this application
// Create the timer queue.
HANDLE hTimerQueue;
HANDLE hUITimer;
enum { UI_TIMER_RATE = 1000 }; // should happen every 1000 ms or 1Hz. That should be fast enough
hTimerQueue = NULL;
hUITimer = NULL;
hTimerQueue = CreateTimerQueue();
CreateTimerQueueTimer( &hUITimer, hTimerQueue,
(WAITORTIMERCALLBACK)UITimerRoutine, NULL, 0, UI_TIMER_RATE, 0); //the 1000 means wait 1000ms for first call
}
int _tmain(int argc, _TCHAR* argv[])
{
SetupMyTimer();
Sleep(10000);
return 0;
}
I have the UITimerHandler called once a second by a TimerQueue. I figured that was a reasonable period over which processor utilization could be estimated.
我有一个 TimerQueue 每秒调用一次 UITimerHandler。我认为这是可以估计处理器利用率的合理时期。
回答by KimBoGyu
This code is take for Cpu Usage
此代码用于 Cpu Usage
FILETIME prevSysIdle, prevSysKernel, prevSysUser;
int getUsage(double &val)
{
FILETIME sysIdle, sysKernel, sysUser;
// sysKernel include IdleTime
if (GetSystemTimes(&sysIdle, &sysKernel, &sysUser) == 0) // GetSystemTimes func FAILED return value is zero;
return 0;
if (prevSysIdle.dwLowDateTime != 0 && prevSysIdle.dwHighDateTime != 0)
{
ULONGLONG sysIdleDiff, sysKernelDiff, sysUserDiff;
sysIdleDiff = SubtractTimes(sysIdle, prevSysIdle);
sysKernelDiff = SubtractTimes(sysKernel, prevSysKernel);
sysUserDiff = SubtractTimes(sysUser, prevSysUser);
ULONGLONG sysTotal = sysKernelDiff + sysUserDiff;
ULONGLONG kernelTotal = sysKernelDiff - sysIdleDiff; // kernelTime - IdleTime = kernelTime, because sysKernel include IdleTime
if (sysTotal > 0) // sometimes kernelTime > idleTime
val = (double)(((kernelTotal + sysUserDiff) * 100.0) / sysTotal);
}
prevSysIdle = sysIdle;
prevSysKernel = sysKernel;
prevSysUser = sysUser;
return 1;
}
// TIME DIFF FUNC
ULONGLONG SubtractTimes(const FILETIME one, const FILETIME two)
{
LARGE_INTEGER a, b;
a.LowPart = one.dwLowDateTime;
a.HighPart = one.dwHighDateTime;
b.LowPart = two.dwLowDateTime;
b.HighPart = two.dwHighDateTime;
return a.QuadPart - b.QuadPart;
}