Получение процента загрузки процессора в Windows с помощью С++
Я работаю над этим инструментом, чтобы быстро регистрировать статистику системы, такую как информация о памяти, и процент загрузки процессора (например, то, что показано в диспетчере задач). У меня, похоже, есть память и часть регистрации, о которой идет речь, но выяснение процентного соотношения CPU было очень жестким: (я нашел много информации о методах проверки информации о процессоре, но за пределами абстрактных статей почти ничего из примеров кода Я нашел компиляцию или хорошо прокомментировал, поэтому мне было сложно сделать хэширование этого способа. Я уже прочитал много вопросов о stackoverflow о получении таймингов процессора и тому подобное, но я не был способный объединить куски.
Возможно, мне не хватает смысла, но кажется, что популярный способ понять это - это запросить CPU два раза с по меньшей мере 200 мс между каждой проверкой, чтобы избежать проблем с чем-то, называемым... разрешением? Так что да! Как я это делаю?:( Я синтаксически оспаривается D:
Я собираюсь поделиться своим исходным кодом, чтобы вы могли видеть, что именно я делал до сих пор. Это всего лишь один .cpp, я использую VS2013 Express для С++, и он предназначен только для Windows для многоядерных процессоров.
Предупреждение заранее: мне очень жаль всех комментариев в коде: x Кроме того, если вы скопируете этот код и запустите его, он собирается создать файл .CSV с именем log.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
}
изменить # 2:
Я столкнулся с этим
BOOL WINAPI GetSystemTimes(_Out_opt_ LPFILETIME lpIdleTime,_Out_opt_ LPFILETIME lpKernelTime,_Out_opt_ LPFILETIME lpUserTime);
Кажется, что он получает материал, который мне нужен, но я не знаю, как его использовать или даже сделать из него unit test, который я бы предпочел, прежде чем выбросить его в остальную часть моего источника .cpp
Я полностью потерян. Я пробовал всевозможные вещи за последние несколько часов, но я даже не могу получить простой компилятор unit test.
Мне кажется, что этот комментарий имеет меня на правильном пути, но я на самом деле не знаю, что с ним делать: Как рассчитано использование процессора?
edit # 3:
Я показываю код unit test для кода Джереми Фризнера, а также завершенный инструмент ведения журнала, над которым я работал.
Тест для контроля загрузки процессора
#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;
}
Завершенный инструмент (все идет в ваш 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/info/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;
}
Ответы
Ответ 1
Причина, по которой популярно вычислять процент нагрузки во времени, состоит в том, что CPU не имеют переменной скорости - в любой момент времени ядро процессора является либо инструкцией по обработке с номинальной тактовой частотой, либо сидит без дела, поэтому мгновенное измерение даст вам только 0% или 100% (*), чего вы не хотите. Поэтому, чтобы рассчитать значимый процент нагрузки, вам нужно выяснить, какой процент времени простоя CPU в течение определенного периода времени.
В любом случае, здесь некоторый код, который я использую для получения значения использования ЦП под Windows... просто вызывайте 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;
}
(*) Хорошо, вы можете получить немного большее разрешение в многоядерной системе; например если бы вы измерили мгновенное использование ЦП на четырехъядерном ЦП, вы могли бы обнаружить, что в тот момент времени три ядра были бездействующими, а одно ядро было активным и называет 25% нагрузку... и, конечно, есть такие вещи, как Intel SpeedStep, который фактически изменяет тактовую частоту процессора как способ управления энергопотреблением; но мы будем игнорировать эти осложнения на данный момент:)
Ответ 2
Самое популярное предлагаемое решение для меня не работает на Win10/Visual Studio 2010; значения, полученные с помощью этого метода, по-видимому, не коррелируют ни с чем. Возможно, это связано с тем, что, как отмечается в комментариях Белогорцева, функция GetSystemTimes возвращает для времени ядра время простоя.
См. https://msdn.microsoft.com/en-us/library/windows/desktop/ms724400(v=vs.85).aspx для описания функции GetSystemTimes.
Кроме того, я не уверен, что произойдет, когда вы назначаете вычитание двух чисел без знака, на другое беззнаковое число. Похоже, что это должно быть неподписанным, но предлагаемое решение делает тест на это значение меньше нуля.
Я вычислил "запас" таким образом:
Headroom = time spent in idle
/
(Kernel time + User time)
а затем "загрузить" как:
Load = 1 - Headroom
Вот пример кода, который вы можете разрезать и вставлять в проект 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;
}
У меня UITimerHandler вызывается один раз в секунду с помощью TimerQueue. Я полагал, что это был разумный период, в течение которого можно было бы оценить использование процессора.
Ответ 3
Этот код берет для использования Cpu
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;
}