Я работал над этим инструментом, чтобы быстро регистрировать некоторые системные статистические данные, такие как информация о памяти и процент загрузки процессора (как то, что показано в диспетчере задач). Я, кажется, позаботился о части памяти и журналирования, но вычислить процент загрузки процессора было очень сложно 🙁 Я нашел много информации о методах для проверки информации о процессоре, но за исключением абстрактов, практически ни одного из примеров кода Я нашел компиляцию или хорошо прокомментирован, поэтому мне было сложно найти способ сделать это.Я уже прочитал много вопросов о стековом потоке о получении времени ЦП и тому подобном, но я не был в состоянии собрать кусочки вместе.
Может быть, я упускаю суть, но кажется, что популярный способ выяснить это, опрашивая ЦП два раза, по крайней мере, 200 мс между каждой проверкой, чтобы помочь избежать проблем с так называемым … разрешением? Так что да! Как, черт возьми, я это делаю? 🙁 Я синтаксически оспаривается D:
Я собираюсь поделиться своим исходным кодом, чтобы вы могли видеть, чем конкретно я занимался до сих пор. Это все в одном .cpp, я использую VS2013 Express для C ++, и это только для 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);
Кажется, что он получает то, что мне нужно, но я не знаю, как на самом деле использовать его или даже сделать из него модульный тест, который я бы предпочел, прежде чем выбросить в остальную часть моего Source.cpp.
Я полностью потерян. За последние несколько часов я перепробовал все что угодно, но даже не смог собрать простой модульный тест.
Я чувствую, что этот комментарий направил меня по правильному пути, но я не знаю, что с ним делать: Как рассчитывается загрузка процессора?
редактировать № 3:
Я показываю юнит-тест для кода Джереми Фриснера, а также законченный инструмент ведения журнала, над которым я работал.
Тест для мониторинга загрузки процессора
#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/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;
}
Причина, по которой популярно вычислять процент загрузки с течением времени, заключается в том, что процессоры на самом деле не имеют переменных скоростей — в любой данный момент ядро процессора либо обрабатывает инструкции с его номинальной тактовой частотой, либо оно бездействует, поэтому мгновенное измерение только даст вам 0% или 100% (*), что не совсем то, что вы хотите. Таким образом, чтобы рассчитать значимым процент загрузки, вы должны проверить, какой процент времени процессор простаивал в течение определенного промежутка времени.
В любом случае, вот некоторый код, который я использую, чтобы получить значение загрузки ЦП под 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, который фактически изменяет тактовую частоту процессора как способ управления энергопотреблением; но мы пока проигнорируем эти осложнения 🙂
Наиболее популярное предлагаемое решение не работает для меня на 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. Я подумал, что это был разумный период, в течение которого можно оценить загрузку процессора.
Этот код взять для использования процессора
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;
}