I was thinking of making an improved version of Windows resource monitor, which not only included resource usage, but also hardware status, such as temperatures and fan speeds.
I've started programming it yesterday using c++, and I've managed to make it list and refresh memory and CPU utilization of every process on my computer.
However, here comes the issue: it's terribly slow. It uses 5% of my i5 2500k@4.3 GHz when polling the usage once every second. Which is unacceptable, because I want not only CPU and memory usage, but also disk usage for every hard drive, internet usage, GPU usage (all of those for every process), then I also want to monitor all the temperatures too.
Here's my code:
const double MB = 1024*1024;
const double KB = 1024;
struct WinProcess
{
wstring Name;
unsigned int ID;
wstring UserName;
double cpuUsage;
long long int ramUsage;
WinProcess(wstring name, unsigned int id) : Name(name), ID(id), UserName(L"Not set"), cpuUsage(0), ramUsage(0) {}
};
class ResourceMonitor
{
private:
void** hquery;
void** hcountercpu;
void** hcountermem;
int cpuCores;
vector<WinProcess> Processes;
public:
ResourceMonitor();
~ResourceMonitor();
void StartResourceMonitor();
void MeasureResourceUsage();
void PrintUsage();
};
ResourceMonitor::ResourceMonitor() :
Processes(GetProcessList()) // Function GetProcessList() returns vector with all processes, their IDs and username, from which it was launched
{
hquery = new void*[Processes.size()];
hcountercpu = new void*[Processes.size()];
hcountermem = new void*[Processes.size()];
for (unsigned int i = 2; i < Processes.size(); i++)
{
Processes[i].Name = Processes[i].Name.substr(0, Processes[i].Name.size() - 4);
}
for (unsigned int i = 2; i < Processes.size(); i++)
{
wstring CounterPathCPU = L"\\Process(" + Processes[i].Name + L")\\% Processor Time";
wstring CounterPathMEM = L"\\Process(" + Processes[i].Name + L")\\Private Bytes";
if ((PdhOpenQuery(NULL, 0, &hquery[i])) != ERROR_SUCCESS
|| PdhAddCounter(hquery[i], CounterPathCPU.c_str(), 0, &hcountercpu[i]) != ERROR_SUCCESS
|| PdhAddCounter(hquery[i], CounterPathMEM.c_str(), 0, &hcountermem[i]) != ERROR_SUCCESS
|| PdhCollectQueryData(hquery[i]) != ERROR_SUCCESS)
{
continue;
}
}
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
cpuCores = sysinfo.dwNumberOfProcessors;
wcout.setf(ios::fixed);
}
ResourceMonitor::~ResourceMonitor()
{
for (unsigned int i = 2; i < Processes.size(); i++)
{
PdhCloseQuery(hquery[i]);
PdhRemoveCounter(hcountercpu[i]);
PdhRemoveCounter(hcountermem[i]);
}
delete[] hquery;
delete[] hcountercpu;
}
void ResourceMonitor::StartResourceMonitor()
{
system("mode CON: COLS=150");
while (1)
{
MeasureResourceUsage();
PrintUsage();
Sleep(1000);
}
}
void ResourceMonitor::MeasureResourceUsage()
{
PDH_FMT_COUNTERVALUE countervalcpu;
PDH_FMT_COUNTERVALUE countervalmem;
for (unsigned int i = 2; i < Processes.size(); i++)
{
if ((PdhCollectQueryData(hquery[i])) != ERROR_SUCCESS)
{
printError(L"Error on collecting query data: ");
continue;
}
if ((PdhGetFormattedCounterValue(hcountercpu[i], PDH_FMT_LONG | PDH_FMT_NOCAP100, 0, &countervalcpu)) != ERROR_SUCCESS)
{
printError(L"Error on CPU usage retrieval: ");
continue;
}
if ((PdhGetFormattedCounterValue(hcountermem[i], PDH_FMT_LONG, 0, &countervalmem)) != ERROR_SUCCESS)
{
printError(L"Error on Memory usage retrieval: ");
continue;
}
Processes[i].cpuUsage = countervalcpu.longValue / (double)cpuCores;
Processes[i].ramUsage = countervalmem.longValue;
}
}
void ResourceMonitor::PrintUsage()
{
system("cls");
long long int RAMSUM = 0;
for (unsigned int i = 2; i < Processes.size(); i++)
{
wcout << left << setw(40) << Processes[i].Name + L".exe: ";
wcout << setw(6) << left << L" | ID " << setw(4) << right << Processes[i].ID;
wcout << setw(8) << left << L" | User " << setw(15) << Processes[i].UserName;
wcout << setw(8) << left << L" | CPU usage " << setw(10) << right << setprecision(2) << Processes[i].cpuUsage << setw(1) << L"%";
wcout << setw(8) << left << L" | RAM usage " << setw(15) << right << setprecision(3) << Processes[i].ramUsage / MB << setw(3) << left << L" MB" << endl;
RAMSUM += Processes[i].ramUsage;
}
wcout << L"Total RAM usage: " << setw(7) << right << RAMSUM / MB
<< setw(3) << left << L" MB" << endl;
}
I'm well aware issues surrounding this code: the process list never gets updated, and there's no GUI, but those are fixable, as getting process list function is pretty fast.
Is there a way to check CPU and memory usage task, as windows task manager does? I can use c++ or c#, as I know both of the languages. Lastly, I have no idea how to monitor network traffic, disk usage and GPU usage for each process. Any ideas? Thanks for the help!