|
CX Framework
Cross-platform C utility framework
|
Two sets of readings live here: how busy the whole machine is, and how busy one process is. Both are plain structures filled in by a single call, so nothing needs to be initialized or destroyed – declare one, pass its address, read the fields.
Operating systems do not all count the same things. FreeBSD keeps no record of committed memory, Windows does not report how much of a process has been paged out, and only Linux separates time spent waiting for a disk from time spent idle.
Every structure therefore carries a valid field: a set of flags naming the fields the operating system actually reported. A field it did not report is also left at zero, so code that only wants a rough number can ignore valid entirely and print the zero. Code that needs to tell "nothing is being used" apart from "nobody is counting" checks the flag.
Each field's own documentation says where it is unavailable.
A call that could report nothing at all on this platform – sysLoadAvg() on Windows is the only one – returns false and sets cxerr to CX_NotSupported instead of returning an empty structure. A call that can report something always returns true, with valid saying how much.
sysCPUTimes() and procCPUTimes() report how much processor time has been used since the machine, or the process, started. A single reading cannot tell you how busy anything is right now; two readings and the time between them can.
sysCPUUsage() and procCPUUsage() do that arithmetic. Both return a percentage of the whole machine's capacity, from 0 to 100, so the two are directly comparable: a process reading of 25 means the process is using a quarter of everything the machine can do. Multiply by osLogicalCPUs() for the per-core figure that tools like top print, where a process using four cores fully reads 400.
For code that polls in a loop, a sampler keeps the previous reading so only one call is needed each time round. It has no answer to give until it has been called twice, and says so by returning false.
Samplers hold nothing but a previous reading, so they need no cleanup, and a process sampler does not hold the process either – it is passed in on each call.
The per-process calls come in two forms: one taking a Process handle, and one taking a process id directly. Both ask the operating system for the least access that will answer the question, and neither ever asks for more rights than it was started with. A reading that needs privileges the caller does not have comes back as a cleared flag, or as false with cxerr set to CX_AccessDenied, never as an attempt to acquire those privileges.
In practice processor and memory figures can be read for any process on the machine, while I/O counters on Linux can only be read for processes belonging to the same user.
The numbers describe the moment the call was made. Memory in particular moves constantly, so two fields read by two separate calls will not agree exactly, and a process can exit between one call and the next.
A handle whose process has already finished reports no statistics: the calls return false with cxerr set to CX_FileNotFound rather than reporting whatever now holds that process id.