Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

NtQuerySystemInformation() for CPU usage on multi core/processor systems

1,071 views
Skip to first unread message

Waxhead

unread,
Dec 15, 2007, 9:04:18 PM12/15/07
to
I was hoping to get individual CPU usage information from the system
using the NtQuerySystemInformation() API. I have tried the following
code several times but it gives wrong results. E.g. the structure
returned are 48 bytes long e.g. 4 bytes longer than expected. Also on
a dual core system the 2nd processor is "dead" e.g. null - on a quad
core however CPU's 1 and 3 are "dead" (results are 0). I bet I screwed
up somewhere but I honestly can't see the error.
Thanks in advance for pointing out my errors ;)

PS! The following example code is not very clean. I know there are
several things that can be optimized but I think I call the
NtQuerySystemInformation() as I should.

CHAR cpuusage2()
{
#define SystemProcessorPerformanceInformation 0x8

static (_stdcall *ntquerysysteminformation) (int
SystemInformationClass, PVOID SystemInformation, ULONG
SystemInformationLength, PULONG ReturnLength) = 0;
SYSTEM_INFO sysinf;
unsigned long returnlength=0;
int status=0;

#pragma pack(push,8)

typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
{
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER Reserved1[2];
ULONG Reserved2;
} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;

#pragma pack(pop)

SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION spi[32];
memset(spi,0,sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*32);

if(!ntquerysysteminformation)
{
printf("*** Loading NtQuerySystemInformation\n");
ntquerysysteminformation =
GetProcAddress(LoadLibrary("ntdll.dll"),"NtQuerySystemInformation");
if(!ntquerysysteminformation)
{
printf("***ERROR: Can't link with NtQuerySystemInformation()
\n");
exit(5);
}
printf("*** Loading NtQuerySystemInformation success\n");
sleep(1500);
}

GetSystemInfo(&sysinf);

printf("Number of processors: %d\n",sysinf.dwNumberOfProcessors);


status=ntquerysysteminformation(SystemProcessorPerformanceInformation,spi,
(sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*sysinf.dwNumberOfProcessors),&returnlength);

printf("*** ntquerysysteminformation results = %d %s
\n",status,status?"FAILED":"OK");

if(0 != status)
printf("*** ntquerysysteminformation failed (%d)\n",status);

printf("ReturnLen = %d\n",returnlength);
printf("sizeli = %d\n",sizeof(LARGE_INTEGER));
printf("structsize = %d
\n",sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
printf("CPUs (rlen) = %d\n",returnlength /
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
if((returnlength %
sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) !=0)
printf("*** Returned unexpected size\n");

printf("----\n");

for(int c=0;c<sysinf.dwNumberOfProcessors;c++)
{
unsigned char usage=0;
ULARGE_INTEGER ul_sys_idle;
ULARGE_INTEGER ul_sys_kernel;
ULARGE_INTEGER ul_sys_user;
static ULARGE_INTEGER ul_sys_idle_old[32];
static ULARGE_INTEGER ul_sys_kernel_old[32];
static ULARGE_INTEGER ul_sys_user_old[32];

ul_sys_idle.QuadPart = spi[c].IdleTime.QuadPart;
ul_sys_kernel.QuadPart = spi[c].KernelTime.QuadPart;
ul_sys_user.QuadPart = spi[c].UserTime.QuadPart;

usage =
(
(
(
(
(ul_sys_kernel.QuadPart - ul_sys_kernel_old[c].QuadPart)
+
(ul_sys_user.QuadPart - ul_sys_user_old[c].QuadPart)
)
-
(ul_sys_idle.QuadPart - ul_sys_idle_old[c].QuadPart)
)
*
(100)
)
/ 1+
(
(ul_sys_kernel.QuadPart - ul_sys_kernel_old[c].QuadPart)
+
(ul_sys_user.QuadPart - ul_sys_user_old[c].QuadPart)
)
);

ul_sys_idle_old[c].QuadPart = ul_sys_idle.QuadPart;
ul_sys_user_old[c].QuadPart = ul_sys_user.QuadPart;
ul_sys_kernel_old[c].QuadPart = ul_sys_kernel.QuadPart;


printf("CPU : %u\n",c);
printf("Usage : %d%%\n",usage);
printf("-\n");
printf("IdleTime = %u\n",spi[c].IdleTime.QuadPart);
printf("KernelTime = %u\n",spi[c].KernelTime.QuadPart);
printf("UserTime = %u\n",spi[c].UserTime.QuadPart);
printf("\n");
}

return 0;
}

All help appreciated - thanks in advance ;)

Kellie Fitton

unread,
Dec 16, 2007, 3:57:58 AM12/16/07
to
> (sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)*sysinf.dwNumberOfProcesso-rs),&returnlength);


Hi,

I gather you want to determine the CPU load of each process,
in this case, try to use the API GetProcessTimes() in a loop, and
compare the user and the kernel times with the time passed by
using the API GetTickCount(), this approach should report the
time that your process is using on the machine.

http://msdn2.microsoft.com/en-us/library/ms683223.aspx

http://msdn2.microsoft.com/en-us/library/ms724408.aspx

Kellie.

Waxhead

unread,
Dec 16, 2007, 5:43:14 AM12/16/07
to

Thanks Kellie but this was actually not what I was looking for (might
be useful tough). What I'm trying to do is to get total CPU usage or
perhaps I should say the total CPU load for each CPU in the system.

Christian ASTOR

unread,
Dec 17, 2007, 6:48:13 AM12/17/07
to
On 16 déc, 03:04, Waxhead <zoi...@online.no> wrote:
> I was hoping to get individual CPU usage information from the system
> using the NtQuerySystemInformation() API. I have tried the following
> code several times but it gives wrong results. E.g. the structure
> returned are 48 bytes long e.g. 4 bytes longer than expected. Also on
> a dual core system the 2nd processor is "dead" e.g. null - on a quad
> core however CPU's 1 and 3 are "dead" (results are 0). I bet I screwed
> up somewhere but I honestly can't see the error.
> Thanks in advance for pointing out my errors ;)

Usage is wrong.
It must be something like this :

usage = (BYTE) (100 - (((ul_sys_idle.QuadPart -
ul_sys_idle_old[c].QuadPart) * 100) /
((ul_sys_kernel.QuadPart + ul_sys_user.QuadPart) -
(ul_sys_kernel_old[c].QuadPart + ul_sys_user_old[c].QuadPart))));

(and in your case, it will be wrong the first time as old variables
are null)

BTW, the structure definition is :

typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
{
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;

LARGE_INTEGER DpcTime;
LARGE_INTEGER InterruptTime;
ULONG InterruptCount;
} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION,
*PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;

(with a similar code in a timer, I get same results than Perf Meter or
Task Manager on 4 or 8 processors)

Waxhead

unread,
Dec 17, 2007, 11:14:59 AM12/17/07
to
On Dec 17, 12:48 pm, Christian ASTOR <casto...@club-internet.fr>
wrote:

Hi Christian and thanks for the new info (from where is this? MSDN
have another definition of the structure). However this does not solve
my problem. I still get a returnlength of 48 and the structure is
still 44 bytes. I expect to get 88 since I have two processors but so
far no luck :( Thanks anyway

Christian ASTOR

unread,
Dec 17, 2007, 12:30:34 PM12/17/07
to
On 17 déc, 17:14, Waxhead <zoi...@online.no> wrote:

> Hi Christian and thanks for the new info (from where is this? MSDN
> have another definition of the structure). However this does not solve
> my problem. I still get a returnlength of 48 and the structure is
> still 44 bytes. I expect to get 88 since I have two processors but so
> far no luck :(

It's from ntexapi.h, which is on many sites like :
https://forum.eviloctal.com/simple/index.php?t5087.html
and
int n = sizeof SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
=> I get n = 48...

Waxhead

unread,
Dec 17, 2007, 3:44:01 PM12/17/07
to

Well replacing the ULONG with a ULARGE_INTEGER in the structure did
the trick. A dirty trick by all means but it works ;) - Now the
interesting part will be to see how many systems it actually works
on ;)
Thanks for your help Christian!

0 new messages