Skip to content

Commit

Permalink
#792 / cpu_stats: win impl
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Mar 5, 2016
1 parent 77386f1 commit 2255b12
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 6 deletions.
24 changes: 18 additions & 6 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,16 @@ CPU
Return various CPU statistics as a namedtuple whose fields change depending
on the platform.

ctx_switches, interrupts, soft_interrupts, syscalls, traps

+-----------------+-----------------+--------------+-----------------+-----------------+-----------------+--------------+
| Linux | OSX | Windows | FreeBSD | OpenBSD | NetBSD | SunOS |
+=================+=================+==============+=================+=================+=================+==============+
| ctx_switches | ctx_switches | | ctx_switches | ctx_switches | ctx_switches | ctx_switches |
| ctx_switches | ctx_switches | ctx_switches | ctx_switches | ctx_switches | ctx_switches | ctx_switches |
+-----------------+-----------------+--------------+-----------------+-----------------+-----------------+--------------+
| interrupts | interrupts | | interrupts | interrupts | interrupts | interrupts |
| interrupts | interrupts | interrupts | interrupts | interrupts | interrupts | interrupts |
+-----------------+-----------------+--------------+-----------------+-----------------+-----------------+--------------+
| soft_interrupts | soft_interrupts | | soft_interrupts | soft_interrupts | soft_interrupts | syscalls |
| soft_interrupts | soft_interrupts | dpcs | soft_interrupts | soft_interrupts | soft_interrupts | syscalls |
+-----------------+-----------------+--------------+-----------------+-----------------+-----------------+--------------+
| procs_running | syscalls | | syscalls | syscalls | syscalls | traps |
| procs_running | syscalls | syscalls | syscalls | syscalls | syscalls | traps |
+-----------------+-----------------+--------------+-----------------+-----------------+-----------------+--------------+
| procs_blocked | traps | | traps | traps | traps | |
+-----------------+-----------------+--------------+-----------------+-----------------+-----------------+--------------+
Expand All @@ -177,6 +175,20 @@ CPU
| | | | | | | |
+-----------------+-----------------+--------------+-----------------+-----------------+-----------------+--------------+

- **ctx_switches**:
number of context switches (voluntary + involuntary) since boot.
- **interrupts**:
number of interrupts since boot.
- **interrupts**:
number of software interrupts since boot.
- **syscalls**: number of system calls since boot.
- **traps**: number of kernel traps since boot.
- **dpcs** *(Windows)*: number of
`delayed procedure calls <https://technet.microsoft.com/en-us/library/cc938646.aspx>`__
since boot.
- **procs_running** *(Linux)*: current number of actively running processes.
- **procs_blocked** *(Linux)*: current number of processes waiting for I/O.

Example (Linux):

.. code-block:: python
Expand Down
125 changes: 125 additions & 0 deletions psutil/_psutil_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -3119,6 +3119,129 @@ psutil_net_if_stats(PyObject *self, PyObject *args) {
}


/*
* Return CPU statistics.
*/
static PyObject *
psutil_cpu_stats(PyObject *self, PyObject *args) {
// NtQuerySystemInformation stuff
typedef DWORD (_stdcall * NTQSI_PROC) (int, PVOID, ULONG, PULONG);
NTQSI_PROC NtQuerySystemInformation;
HINSTANCE hNtDll;

NTSTATUS status;
_SYSTEM_PERFORMANCE_INFORMATION *spi = NULL;
_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
_SYSTEM_INTERRUPT_INFORMATION *InterruptInformation = NULL;
SYSTEM_INFO si;
UINT i;
ULONG64 dpcs = 0;
ULONG interrupts = 0;

// obtain NtQuerySystemInformation
hNtDll = LoadLibrary(TEXT("ntdll.dll"));
if (hNtDll == NULL) {
PyErr_SetFromWindowsErr(0);
goto error;
}
NtQuerySystemInformation = (NTQSI_PROC)GetProcAddress(
hNtDll, "NtQuerySystemInformation");
if (NtQuerySystemInformation == NULL) {
PyErr_SetFromWindowsErr(0);
goto error;
}

// retrives number of processors
GetSystemInfo(&si);

// get syscalls / ctx switches
spi = (_SYSTEM_PERFORMANCE_INFORMATION *) \
malloc(si.dwNumberOfProcessors * \
sizeof(_SYSTEM_PERFORMANCE_INFORMATION));
if (spi == NULL) {
PyErr_NoMemory();
goto error;
}
status = NtQuerySystemInformation(
SystemPerformanceInformation,
spi,
si.dwNumberOfProcessors * sizeof(_SYSTEM_PERFORMANCE_INFORMATION),
NULL);
if (status != 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}

// get DPCs
InterruptInformation = \
malloc(sizeof(_SYSTEM_INTERRUPT_INFORMATION) *
si.dwNumberOfProcessors);
if (InterruptInformation == NULL) {
PyErr_NoMemory();
goto error;
}
status = NtQuerySystemInformation(
SystemInterruptInformation,
InterruptInformation,
si.dwNumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION),
NULL);
if (status != 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}
for (i = 0; i < si.dwNumberOfProcessors; i++) {
dpcs += InterruptInformation[i].DpcCount;
}

// get interrupts
sppi = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *) \
malloc(si.dwNumberOfProcessors * \
sizeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
if (sppi == NULL) {
PyErr_NoMemory();
goto error;
}

status = NtQuerySystemInformation(
SystemProcessorPerformanceInformation,
sppi,
si.dwNumberOfProcessors * sizeof
(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
NULL);
if (status != 0) {
PyErr_SetFromWindowsErr(0);
goto error;
}

for (i = 0; i < si.dwNumberOfProcessors; i++) {
interrupts += sppi[i].InterruptCount;
}


// done
free(spi);
free(InterruptInformation);
FreeLibrary(hNtDll);
return Py_BuildValue(
"kkkk",
spi->ContextSwitches,
interrupts,
(unsigned long)dpcs,
spi->SystemCalls
);

error:
if (spi)
free(spi);
if (InterruptInformation)
free(InterruptInformation);
if (hNtDll)
FreeLibrary(hNtDll);
return NULL;
}



// ------------------------ Python init ---------------------------

static PyMethodDef
Expand Down Expand Up @@ -3223,6 +3346,8 @@ PsutilMethods[] = {
"Return NICs addresses."},
{"net_if_stats", psutil_net_if_stats, METH_VARARGS,
"Return NICs stats."},
{"cpu_stats", psutil_cpu_stats, METH_VARARGS,
"Return NICs stats."},

// --- windows API bindings
{"win32_QueryDosDevice", psutil_win32_QueryDosDevice, METH_VARARGS,
Expand Down
9 changes: 9 additions & 0 deletions psutil/_pswindows.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ class Priority(enum.IntEnum):
'ntpinfo', ['num_handles', 'ctx_switches', 'user_time', 'kernel_time',
'create_time', 'num_threads', 'io_rcount', 'io_wcount',
'io_rbytes', 'io_wbytes'])
ssysinfo = namedtuple(
'ssysinfo', ['ctx_switches', 'interrupts', 'dpcs', 'syscalls'])


# set later from __init__.py
NoSuchProcess = None
Expand Down Expand Up @@ -209,6 +212,12 @@ def cpu_count_physical():
return cext.cpu_count_phys()


def cpu_stats():
"""Return CPU statistics."""
ctx_switches, interrupts, dpcs, syscalls = cext.cpu_stats()
return ssysinfo(ctx_switches, interrupts, dpcs, syscalls)


def boot_time():
"""The system boot time expressed in seconds since the epoch."""
return cext.boot_time()
Expand Down
89 changes: 89 additions & 0 deletions psutil/arch/windows/ntextapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,95 @@ typedef struct {
} _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;


typedef struct {
LARGE_INTEGER IdleProcessTime;
LARGE_INTEGER IoReadTransferCount;
LARGE_INTEGER IoWriteTransferCount;
LARGE_INTEGER IoOtherTransferCount;
ULONG IoReadOperationCount;
ULONG IoWriteOperationCount;
ULONG IoOtherOperationCount;
ULONG AvailablePages;
ULONG CommittedPages;
ULONG CommitLimit;
ULONG PeakCommitment;
ULONG PageFaultCount;
ULONG CopyOnWriteCount;
ULONG TransitionCount;
ULONG CacheTransitionCount;
ULONG DemandZeroCount;
ULONG PageReadCount;
ULONG PageReadIoCount;
ULONG CacheReadCount;
ULONG CacheIoCount;
ULONG DirtyPagesWriteCount;
ULONG DirtyWriteIoCount;
ULONG MappedPagesWriteCount;
ULONG MappedWriteIoCount;
ULONG PagedPoolPages;
ULONG NonPagedPoolPages;
ULONG PagedPoolAllocs;
ULONG PagedPoolFrees;
ULONG NonPagedPoolAllocs;
ULONG NonPagedPoolFrees;
ULONG FreeSystemPtes;
ULONG ResidentSystemCodePage;
ULONG TotalSystemDriverPages;
ULONG TotalSystemCodePages;
ULONG NonPagedPoolLookasideHits;
ULONG PagedPoolLookasideHits;
ULONG AvailablePagedPoolPages;
ULONG ResidentSystemCachePage;
ULONG ResidentPagedPoolPage;
ULONG ResidentSystemDriverPage;
ULONG CcFastReadNoWait;
ULONG CcFastReadWait;
ULONG CcFastReadResourceMiss;
ULONG CcFastReadNotPossible;
ULONG CcFastMdlReadNoWait;
ULONG CcFastMdlReadWait;
ULONG CcFastMdlReadResourceMiss;
ULONG CcFastMdlReadNotPossible;
ULONG CcMapDataNoWait;
ULONG CcMapDataWait;
ULONG CcMapDataNoWaitMiss;
ULONG CcMapDataWaitMiss;
ULONG CcPinMappedDataCount;
ULONG CcPinReadNoWait;
ULONG CcPinReadWait;
ULONG CcPinReadNoWaitMiss;
ULONG CcPinReadWaitMiss;
ULONG CcCopyReadNoWait;
ULONG CcCopyReadWait;
ULONG CcCopyReadNoWaitMiss;
ULONG CcCopyReadWaitMiss;
ULONG CcMdlReadNoWait;
ULONG CcMdlReadWait;
ULONG CcMdlReadNoWaitMiss;
ULONG CcMdlReadWaitMiss;
ULONG CcReadAheadIos;
ULONG CcLazyWriteIos;
ULONG CcLazyWritePages;
ULONG CcDataFlushes;
ULONG CcDataPages;
ULONG ContextSwitches;
ULONG FirstLevelTbFills;
ULONG SecondLevelTbFills;
ULONG SystemCalls;

} _SYSTEM_PERFORMANCE_INFORMATION;


typedef struct {
ULONG ContextSwitches;
ULONG DpcCount;
ULONG DpcRate;
ULONG TimeIncrement;
ULONG DpcBypassCount;
ULONG ApcBypassCount;
} _SYSTEM_INTERRUPT_INFORMATION;


typedef enum _KTHREAD_STATE {
Initialized,
Ready,
Expand Down

0 comments on commit 2255b12

Please sign in to comment.