diff --git a/psutil/__init__.py b/psutil/__init__.py index 4fed9fea1..a8aa84e20 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -181,7 +181,7 @@ "pid_exists", "pids", "process_iter", "wait_procs", # proc "virtual_memory", "swap_memory", # memory "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu - "cpu_stats", "cpu_freq", + "cpu_stats", # "cpu_freq", "net_io_counters", "net_connections", "net_if_addrs", # network "net_if_stats", "disk_io_counters", "disk_partitions", "disk_usage", # disk @@ -1869,6 +1869,8 @@ def cpu_freq(): """ return _psplatform.cpu_freq() + __all__.append("cpu_freq") + # ===================================================================== # --- system memory related functions diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c index 4d939aff6..4caace7d4 100644 --- a/psutil/_psutil_windows.c +++ b/psutil/_psutil_windows.c @@ -24,6 +24,7 @@ #include #include #include +#include // Link with Iphlpapi.lib #pragma comment(lib, "IPHLPAPI.lib") @@ -145,6 +146,16 @@ typedef struct _MIB_UDP6TABLE_OWNER_PID { } MIB_UDP6TABLE_OWNER_PID, *PMIB_UDP6TABLE_OWNER_PID; #endif +typedef struct _PROCESSOR_POWER_INFORMATION { + ULONG Number; + ULONG MaxMhz; + ULONG CurrentMhz; + ULONG MhzLimit; + ULONG MaxIdleState; + ULONG CurrentIdleState; +} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION; + + PIP_ADAPTER_ADDRESSES psutil_get_nic_addresses() { // allocate a 15 KB buffer to start with @@ -3391,6 +3402,60 @@ psutil_cpu_stats(PyObject *self, PyObject *args) { } +/* + * Return CPU frequency. + */ +static PyObject * +psutil_cpu_freq(PyObject *self, PyObject *args) { + PROCESSOR_POWER_INFORMATION *ppi; + NTSTATUS ret; + size_t size; + LPBYTE pBuffer = NULL; + ULONG current; + ULONG max; + unsigned int num_cpus; + SYSTEM_INFO system_info; + system_info.dwNumberOfProcessors = 0; + + // Get the number of CPUs. + GetSystemInfo(&system_info); + if (system_info.dwNumberOfProcessors == 0) + num_cpus = 1; + else + num_cpus = system_info.dwNumberOfProcessors; + + // Allocate size. + size = num_cpus * sizeof(PROCESSOR_POWER_INFORMATION); + pBuffer = (BYTE*)LocalAlloc(LPTR, size); + if (! pBuffer) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + + // Syscall. + ret = CallNtPowerInformation( + ProcessorInformation, NULL, 0, pBuffer, size); + if (ret != 0) { + PyErr_SetString(PyExc_RuntimeError, + "CallNtPowerInformation syscall failed"); + goto error; + } + + // Results. + ppi = (PROCESSOR_POWER_INFORMATION *)pBuffer; + max = ppi->MaxMhz; + current = ppi->CurrentMhz; + LocalFree(pBuffer); + + return Py_BuildValue("kk", current, max); + +error: + if (pBuffer != NULL) + LocalFree(pBuffer); + return NULL; +} + + // ------------------------ Python init --------------------------- static PyMethodDef @@ -3495,6 +3560,8 @@ PsutilMethods[] = { "Return NICs stats."}, {"cpu_stats", psutil_cpu_stats, METH_VARARGS, "Return NICs stats."}, + {"cpu_freq", psutil_cpu_freq, METH_VARARGS, + "Return CPU frequency."}, // --- windows services {"winservice_enumerate", psutil_winservice_enumerate, METH_VARARGS, diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index cb816f73a..8c9625352 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -299,6 +299,12 @@ def cpu_stats(): syscalls) +def cpu_freq(): + curr, max_ = cext.cpu_freq() + min_ = 0 + return [_common.scpufreq(curr, min_, max_)] + + # ===================================================================== # --- network # ===================================================================== diff --git a/psutil/tests/test_memory_leaks.py b/psutil/tests/test_memory_leaks.py index 46186e411..f1a951f01 100755 --- a/psutil/tests/test_memory_leaks.py +++ b/psutil/tests/test_memory_leaks.py @@ -458,6 +458,11 @@ def test_per_cpu_times(self): def test_cpu_stats(self): self.execute(psutil.cpu_stats) + @skip_if_linux() + @unittest.skipUnless(hasattr(psutil, "cpu_freq"), "platform not supported") + def test_cpu_freq(self): + self.execute(psutil.cpu_freq) + # --- mem def test_virtual_memory(self): diff --git a/setup.py b/setup.py index 80521a487..01543bee8 100755 --- a/setup.py +++ b/setup.py @@ -122,7 +122,7 @@ def get_winver(): define_macros=macros, libraries=[ "psapi", "kernel32", "advapi32", "shell32", "netapi32", - "iphlpapi", "wtsapi32", "ws2_32", + "iphlpapi", "wtsapi32", "ws2_32", "PowrProf", ], # extra_compile_args=["/Z7"], # extra_link_args=["/DEBUG"]