Reputation: 11
I'm currently working on a kind of surveillance tool. It's basically like the taskmanager, and I'm just doing this because I want to get in touch with C++ and learn new stuff.
The core of the CPU-usage part is GetSystemTimes(). This function returns the pointers to 3 values, the time the CPU has been idle, the time the CPU has been in kernel mode, and the time the CPU has been in user mode. I call the function twice with 250ms sleep in between, and calculate the percentage with the differences of the values.
I have two problems, though. The function returns pointers to FILETIME structures, but I need the actual value as an integer, float, double, or similar, because I need to calculate (int would be enough for me, but I don't know how large the values are). I know that a pointer tells me where the data is saved, but I don't know how I can actually get that data. And how can I get from FILETIME to something else, once I've got it.
#include <iostream>
#define _WIN32_WINNT 0x0602
#include <windows.h>
#include <stdlib.h>
class Processor{};
class Usage: public Processor
{
public:
int now()
{
FILETIME a0, a1, a2, b0, b1, b2;
GetSystemTimes(&a0, &a1, &a2);
SleepEx(250, false);
GetSystemTimes(&b0, &b1, &b2);
// attempt to get the actual value instead of the pointer and convert it to float/double/int
float idle0 = a0;
float idle1 = b0;
float kernel0 = a1;
float kernel1 = b1;
float user0 = a2;
float user1 = b2;
float idl = idle1 - idle0;
float ker = kernel0 - kernel1;
float usr = user0 - user1;
float cpu = (ker - idl + usr) * 100 / (ker + usr);
return cpu;
}
};
int main()
{
using namespace std;
Usage Usage;
for(int i = 0; i < 10; i++)
{
cout << "CPU:\t" << Usage.now() << endl;
}
cout << "\nFinished!\nPress any key to exit!\n";
cin.clear();
cin.get();
return 0;
}
Thanks for the help! :)
Upvotes: 0
Views: 3880
Reputation: 19232
Two points, first you say "The function returns pointers to FILETIME structures" - the function returns a BOOL which you have not checked. Second, It takes pointers to FILETIME
structs as parameters. You have given it the address of local variables - which is fine.
If you have pointers e.g. FILETIME *pa0
you can deference them to find the members variables etc using ->
e.g. pa0->dwHighDateTime
For your variables a0
, a1
etc a simple .
will suffice.
Notice the type of the two members of a FILETIME
are actually DWORD
s so you can use DWORD instead of float to get what you want:
DWORD idle0 = a0.dwHighDateTime;
DWORD idle1 = b0.dwHighDateTime;
DWORD kernel0 = a1.dwHighDateTime;
DWORD kernel1 = b1.dwHighDateTime;
DWORD user0 = a2.dwHighDateTime;
DWORD user1 = b2.dwLowDateTime;
The API you have linked to has a suggestion of how to use a FILETIME time
to get milliseconds:
((ulong)time.dwHighDateTime << 32) + (uint)time.dwLowDateTime)
In essence, the two parts give you the whole number you are after. As people said in the comments, the FILETIME
docs suggest various ways of doing the sums you want.
BUT to spell it out in full, you need to be careful with a large integer. (See comment below). The simplest thing to do, is to use a ULARGE_INTEGER
(a 64-bit value) which has a LowPart
you can use for the dwLowDateTime
and HighPart
you can us for the dwHighDateTime
then use the QuadPart.
For example see
manipulating LARGE_INTEGERS
Upvotes: 0
Reputation: 51355
Your question can be composed into two easy problems:
FILETIME
object to an integer value.A FILETIME structure...
[c]ontains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
A suitable integer type to store a FILETIME
's timestamp is a uint64_t. The following code performs the conversion:
#include <cstdint>
uint64_t FromFileTime( const FILETIME& ft ) {
ULARGE_INTEGER uli = { 0 };
uli.LowPart = ft.dwLowDateTime;
uli.HighPart = ft.dwHighDateTime;
return uli.QuadPart;
}
With this utility function you can change the remaining code to produce the percentage you are looking for:
int now() {
FILETIME a0, a1, a2, b0, b1, b2;
GetSystemTimes(&a0, &a1, &a2);
SleepEx(250, false);
GetSystemTimes(&b0, &b1, &b2);
uint64_t idle0 = FromFileTime( a0 );
uint64_t idle1 = FromFileTime( b0 );
uint64_t kernel0 = FromFileTime( a1 );
uint64_t kernel1 = FromFileTime( b1 );
uint64_t user0 = FromFileTime( a2 );
uint64_t user1 = FromFileTime( b2 );
uint64_t idl = idle1 - idle0;
uint64_t ker = kernel1 - kernel0;
uint64_t usr = user1 - user0;
uint64_t cpu = (ker + usr) * 100 / (ker + usr + idl);
return static_cast<int>( cpu );
}
In theory, the multiplication and addition (ker + usr
or ker + usr + idl
) can overflow. Technically, those errors should be handled. In reality, however, the values should be very small compared to the maximum value the integer types can store.
Upvotes: 4