How to get the cpu usage per thread on windows (win32)
With the help of RRUZ's answer above I finally came up with this code for Borland Delphi:
const
THREAD_TERMINATE = $0001;
THREAD_SUSPEND_RESUME = $0002;
THREAD_GET_CONTEXT = $0008;
THREAD_SET_CONTEXT = $0010;
THREAD_SET_INFORMATION = $0020;
THREAD_QUERY_INFORMATION = $0040;
THREAD_SET_THREAD_TOKEN = $0080;
THREAD_IMPERSONATE = $0100;
THREAD_DIRECT_IMPERSONATION = $0200;
THREAD_SET_LIMITED_INFORMATION = $0400;
THREAD_QUERY_LIMITED_INFORMATION = $0800;
THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $03FF;
function OpenThread(dwDesiredAccess: DWord;
bInheritHandle: Bool;
dwThreadId: DWord): DWord; stdcall; external 'kernel32.dll';
procedure TForm1.Button1Click(Sender: TObject);
var iii:integer;
handle:thandle;
creationtime,exittime,kerneltime,usertime:filetime;
begin
Handle:=OpenThread(THREAD_SET_INFORMATION or THREAD_QUERY_INFORMATION, False, windows.GetCurrentThreadId);
if handle<>0 then
begin
getthreadtimes(Handle,creationtime,exittime,kerneltime,usertime);
label1.caption:='Total time for Thread #'+inttostr(windows.GetCurrentThreadId)+': '+inttostr( (int64(kerneltime)+int64(usertime)) div 1000 )+' msec';
CloseHandle(Handle);
end;
end;
Measuring CPU time per-thread on Windows
win32process.GetThreadTimes
You want the Python for Windows Extensions to do hairy windows things.
How to get thread state (e.g. suspended), memory + CPU usage, start time, priority, etc
I found the answer myself.
I wrote a class cProcInfo
that obtains a lot of information about processes and threads like:
- Process and Thread identifiers
- Process Parent Identifier
- Process Name
- Priority
- Context Switches
- Address
- State (running, waiting, suspended, etc..)
- Date and Time when process and thread were started
- Time spent in Kernel mode
- Time spent in User mode
- Memory usage
- Handle count
- Page Faults
My class works on Windows 2000, XP, Vista, 7, 8...
The following code shows how to determine if the thread 640
in the process 1948
is supended:
Main()
{
cProcInfo i_Proc;
DWORD u32_Error = i_Proc.Capture();
if (u32_Error)
{
printf("Error 0x%X capturing processes.\n", u32_Error);
return 0;
}
SYSTEM_PROCESS* pk_Proc = i_Proc.FindProcessByPid(1948);
if (!pk_Proc)
{
printf("The process does not exist.\n");
return 0;
}
SYSTEM_THREAD* pk_Thread = i_Proc.FindThreadByTid(pk_Proc, 640);
if (!pk_Thread)
{
printf("The thread does not exist.\n");
return 0;
}
BOOL b_Suspend;
i_Proc.IsThreadSuspended(pk_Thread, &b_Suspend);
if (b_Suspend) printf("The thread is suspended.\n");
else printf("The thread is not suspended.\n");
return 0;
}
My class first captures all currently running processes and threads with NtQuerySystemInformation()
and then searches the information of the requested thread.
You can easily add a function that searches a process by name. (pk_Proc->usName
)
Here comes my class. It is only one header file:
#pragma once
#include <winternl.h>
#include <winnt.h>
typedef LONG NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS) 0x00000000)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004)
enum KWAIT_REASON
{
Executive,
FreePage,
PageIn,
PoolAllocation,
DelayExecution,
Suspended,
UserRequest,
WrExecutive,
WrFreePage,
WrPageIn,
WrPoolAllocation,
WrDelayExecution,
WrSuspended,
WrUserRequest,
WrEventPair,
WrQueue,
WrLpcReceive,
WrLpcReply,
WrVirtualMemory,
WrPageOut,
WrRendezvous,
Spare2,
Spare3,
Spare4,
Spare5,
Spare6,
WrKernel,
MaximumWaitReason
};
enum THREAD_STATE
{
Running = 2,
Waiting = 5,
};
#pragma pack(push,8)
struct CLIENT_ID
{
HANDLE UniqueProcess; // Process ID
HANDLE UniqueThread; // Thread ID
};
// http://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/thread.htm
// Size = 0x40 for Win32
// Size = 0x50 for Win64
struct SYSTEM_THREAD
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientID; // process/thread ids
LONG Priority;
LONG BasePriority;
ULONG ContextSwitches;
THREAD_STATE ThreadState;
KWAIT_REASON WaitReason;
};
struct VM_COUNTERS // virtual memory of process
{
ULONG_PTR PeakVirtualSize;
ULONG_PTR VirtualSize;
ULONG PageFaultCount;
ULONG_PTR PeakWorkingSetSize;
ULONG_PTR WorkingSetSize;
ULONG_PTR QuotaPeakPagedPoolUsage;
ULONG_PTR QuotaPagedPoolUsage;
ULONG_PTR QuotaPeakNonPagedPoolUsage;
ULONG_PTR QuotaNonPagedPoolUsage;
ULONG_PTR PagefileUsage;
ULONG_PTR PeakPagefileUsage;
};
// http://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/process.htm
// See also SYSTEM_PROCESS_INROMATION in Winternl.h
// Size = 0x00B8 for Win32
// Size = 0x0100 for Win64
struct SYSTEM_PROCESS
{
ULONG NextEntryOffset; // relative offset
ULONG ThreadCount;
LARGE_INTEGER WorkingSetPrivateSize;
ULONG HardFaultCount;
ULONG NumberOfThreadsHighWatermark;
ULONGLONG CycleTime;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
LONG BasePriority;
PVOID UniqueProcessId;
PVOID InheritedFromUniqueProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG_PTR UniqueProcessKey;
VM_COUNTERS VmCounters;
ULONG_PTR PrivatePageCount;
IO_COUNTERS IoCounters; // defined in winnt.h
};
#pragma pack(pop)
typedef NTSTATUS (WINAPI* t_NtQueryInfo)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
class cProcInfo
{
public:
cProcInfo()
{
#ifdef WIN64
assert(sizeof(SYSTEM_THREAD) == 0x50 && sizeof(SYSTEM_PROCESS) == 0x100);
#else
assert(sizeof(SYSTEM_THREAD) == 0x40 && sizeof(SYSTEM_PROCESS) == 0xB8);
#endif
mu32_DataSize = 1000;
mp_Data = NULL;
mf_NtQueryInfo = NULL;
}
virtual ~cProcInfo()
{
if (mp_Data) LocalFree(mp_Data);
}
// Capture all running processes and all their threads.
// returns an API or NTSTATUS Error code or zero if successfull
DWORD Capture()
{
if (!mf_NtQueryInfo)
{
mf_NtQueryInfo = (t_NtQueryInfo)GetProcAddress(GetModuleHandleA("NtDll.dll"), "NtQuerySystemInformation");
if (!mf_NtQueryInfo)
return GetLastError();
}
// This must run in a loop because in the mean time a new process may have started
// and we need more buffer than u32_Needed !!
while (true)
{
if (!mp_Data)
{
mp_Data = (BYTE*)LocalAlloc(LMEM_FIXED, mu32_DataSize);
if (!mp_Data)
return GetLastError();
}
ULONG u32_Needed = 0;
NTSTATUS s32_Status = mf_NtQueryInfo(SystemProcessInformation, mp_Data, mu32_DataSize, &u32_Needed);
if (s32_Status == STATUS_INFO_LENGTH_MISMATCH) // The buffer was too small
{
mu32_DataSize = u32_Needed + 4000;
LocalFree(mp_Data);
mp_Data = NULL;
continue;
}
return s32_Status;
}
}
// Searches a process by a given Process Identifier
// Capture() must have been called before!
SYSTEM_PROCESS* FindProcessByPid(DWORD u32_PID)
{
if (!mp_Data)
{
assert(mp_Data);
return NULL;
}
SYSTEM_PROCESS* pk_Proc = (SYSTEM_PROCESS*)mp_Data;
while (TRUE)
{
if ((DWORD)(DWORD_PTR)pk_Proc->UniqueProcessId == u32_PID)
return pk_Proc;
if (!pk_Proc->NextEntryOffset)
return NULL;
pk_Proc = (SYSTEM_PROCESS*)((BYTE*)pk_Proc + pk_Proc->NextEntryOffset);
}
}
SYSTEM_THREAD* FindThreadByTid(SYSTEM_PROCESS* pk_Proc, DWORD u32_TID)
{
if (!pk_Proc)
{
assert(pk_Proc);
return NULL;
}
// The first SYSTEM_THREAD structure comes immediately after the SYSTEM_PROCESS structure
SYSTEM_THREAD* pk_Thread = (SYSTEM_THREAD*)((BYTE*)pk_Proc + sizeof(SYSTEM_PROCESS));
for (DWORD i=0; i<pk_Proc->ThreadCount; i++)
{
if (pk_Thread->ClientID.UniqueThread == (HANDLE)(DWORD_PTR)u32_TID)
return pk_Thread;
pk_Thread++;
}
return NULL;
}
DWORD IsThreadSuspended(SYSTEM_THREAD* pk_Thread, BOOL* pb_Suspended)
{
if (!pk_Thread)
return ERROR_INVALID_PARAMETER;
*pb_Suspended = (pk_Thread->ThreadState == Waiting &&
pk_Thread->WaitReason == Suspended);
return 0;
}
private:
BYTE* mp_Data;
DWORD mu32_DataSize;
t_NtQueryInfo mf_NtQueryInfo;
};
// Based on the 32 bit code of Sven B. Schreiber on:
// http://www.informit.com/articles/article.aspx?p=22442&seqNum=5
Retrieving CPU Load Percent total in Windows with C++
The reason it's popular to compute the load percentage over time is because CPUs don't really have variable speeds -- at any given instant, a CPU core is either processing instructions at its rated clock rate, or it's sitting idle, so an instantaneous measurement would only give you 0% or 100% (*), which isn't really what you want. So in order to calculate a meaningful load percentage, you have to examine what percentage of time the CPU was idle during a particular interval of time.
In any case, here's some code I use to get a CPU-usage value under Windows... just call GetCPULoad() at regular intervals (e.g. every 250mS or at whatever rate you like) and multiply by 100.0 to get a percentage:
#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;
}
(*) Okay, you might get a bit more resolution on a multicore system; e.g. if you measured instantaneous CPU usage on a quad-core CPU you might find that at that particular instant in time, three cores were idle and one core was active, and call that 25% load... and of course there are things like Intel's SpeedStep that actually varies the CPU's clock rate as a way to manage power consumption; but we'll ignore those complications for the time being :)
Related Topics
Sorting Two Corresponding Arrays
How to Call MAChine Code Stored in Char Array
Using Assignment as a Condition Expression
Why Can't I Write to a String Literal While I *Can* Write to a String Object
List of Standard Header Files in C and C++
Linking Different Libraries for Debug and Release Builds in Cmake on Windows
Lambda Implicit Capture Fails with Variable Declared from Structured Binding
Pointer to Array with Const Qualifier in C & C++
Standard Library Containers with Additional Optional Template Parameters
How to Get a List of Video Capture Devices (Web Cameras) on Linux ( Ubuntu )? (C/C++)
Linux Equivalent for Conio.H Getch()
How to Add 2 Arbitrarily Sized Integers in C++
Why Is Initializing an Integer in C++ to 010 Different from Initializing It to 10
When Should I Use C++14 Automatic Return Type Deduction
Waitpid Equivalent with Timeout
Why Is "Using Namespace X;" Not Allowed at Class/Struct Level