diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2019-04-11 12:00:41 +0200 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2019-04-11 12:00:41 +0200 |
commit | 8ac80188472e8cf6889a6e4aeac2d09cdd19d630 (patch) | |
tree | ae825c60d301b913852353bef60af07f784fcf1b | |
parent | 97f0c7adf18ac02fa7e610fca19bf2a91455a06f (diff) | |
parent | 921870d54091f399cd2b129db19530cc486b5700 (diff) | |
download | psutil-8ac80188472e8cf6889a6e4aeac2d09cdd19d630.tar.gz |
Merge branch 'master' of github.com:giampaolo/psutil
-rwxr-xr-x | .ci/travis/install.sh | 4 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CREDITS | 5 | ||||
-rw-r--r-- | HISTORY.rst | 2 | ||||
-rw-r--r-- | docs/DEVNOTES | 2 | ||||
-rw-r--r-- | docs/index.rst | 30 | ||||
-rw-r--r-- | psutil/__init__.py | 11 | ||||
-rw-r--r-- | psutil/_pslinux.py | 26 | ||||
-rw-r--r-- | psutil/_psutil_windows.c | 7 | ||||
-rw-r--r-- | psutil/_pswindows.py | 18 | ||||
-rw-r--r-- | psutil/arch/windows/wmi.c | 115 | ||||
-rw-r--r-- | psutil/arch/windows/wmi.h | 12 | ||||
-rw-r--r-- | psutil/tests/__init__.py | 1 | ||||
-rwxr-xr-x | psutil/tests/test_linux.py | 96 | ||||
-rwxr-xr-x | psutil/tests/test_memory_leaks.py | 5 | ||||
-rwxr-xr-x | psutil/tests/test_system.py | 10 | ||||
-rwxr-xr-x | setup.py | 4 |
17 files changed, 288 insertions, 61 deletions
diff --git a/.ci/travis/install.sh b/.ci/travis/install.sh index b0f28c66..1e37c39b 100755 --- a/.ci/travis/install.sh +++ b/.ci/travis/install.sh @@ -21,8 +21,8 @@ if [[ "$(uname -s)" == 'Darwin' ]]; then # pyenv virtualenv 2.6.9 psutil # ;; py27) - pyenv install 2.7.10 - pyenv virtualenv 2.7.10 psutil + pyenv install 2.7.16 + pyenv virtualenv 2.7.16 psutil ;; py36) pyenv install 3.6.6 @@ -11,6 +11,7 @@ syntax: glob *.rej *.so *.swp +.failed-tests.txt .cache/ .idea/ .tox/ @@ -607,3 +607,8 @@ I: 1471 N: Samer Masterson W: https://github.com/samertm I: 1480 + +N: Ammar Askar +E: ammar@ammaraskar.com +W: http://ammaraskar.com/ +I: 604, 1484
\ No newline at end of file diff --git a/HISTORY.rst b/HISTORY.rst index afd63f01..2d24ef95 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -14,6 +14,8 @@ new constants: IOPRIO_VERYLOW, IOPRIO_LOW, IOPRIO_NORMAL, IOPRIO_HIGH. Also it was not possible to set high I/O priority (not it is). - 1478_: add make command to re-run tests failed on last run. +- 604: [UNIX, Windows] add new psutil.getloadavg() returning system load + average calculation. (patch by Ammar Askar) **Bug fixes** diff --git a/docs/DEVNOTES b/docs/DEVNOTES index c54fa938..abd2e368 100644 --- a/docs/DEVNOTES +++ b/docs/DEVNOTES @@ -69,8 +69,6 @@ FEATURES - #613: thread names. -- #604: emulate os.getloadavg() on Windows - - scripts/taskmgr-gui.py (using tk). - system-wide number of open file descriptors: diff --git a/docs/index.rst b/docs/index.rst index 85429eb6..1469e61b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -238,6 +238,30 @@ CPU .. versionchanged:: 5.5.1 added FreeBSD support. +.. function:: getloadavg() + + Returns the average load on the system over the last 1, 5 and 15 minutes + respectively as a tuple. The load represents how many processes are waiting + to be run by the operating system. + + On UNIX systems this relies on `os.getloadavg`_. On Windows, this is + emulated by using a Windows API call that spawns a thread which updates the + average every 5 seconds mimicking the UNIX behavior. Thus, the first time + this is called and up until 5 seconds it returns a meaningless + ``(0.0, 0.0, 0.0)`` tuple. + + Example: + + .. code-block:: python + + >>> import psutil + >>> psutil.getloadavg() + (3.14, 3.89, 4.67) + + Availability: Unix, Windows + + .. versionadded:: 5.6.2 + Memory ------ @@ -2556,12 +2580,6 @@ FAQs the Python script as a Windows service (this is the trick used by tools such as ProcessHacker). ----- - -* Q: What about load average? -* A: psutil does not expose any load average function as it's already available - in python as `os.getloadavg`_. - Running tests ============= diff --git a/psutil/__init__.py b/psutil/__init__.py index 5d2b8d3c..07f1104b 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -2017,6 +2017,17 @@ if hasattr(_psplatform, "cpu_freq"): __all__.append("cpu_freq") +if hasattr(os, "getloadavg") or hasattr(_psplatform, "getloadavg"): + # Perform this hasattr check once on import time to either use the + # platform based code or proxy straight from the os module. + if hasattr(os, "getloadavg"): + getloadavg = os.getloadavg + else: + getloadavg = _psplatform.getloadavg + + __all__.append("getloadavg") + + # ===================================================================== # --- system memory related functions # ===================================================================== diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index bf815e87..1f8ddb93 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -688,23 +688,19 @@ if os.path.exists("/sys/devices/system/cpu/cpufreq") or \ Contrarily to other OSes, Linux updates these values in real-time. """ - # scaling_* files seem preferable to cpuinfo_*, see: - # http://unix.stackexchange.com/a/87537/168884 + def get_path(num): + for p in ("/sys/devices/system/cpu/cpufreq/policy%s" % num, + "/sys/devices/system/cpu/cpu%s/cpufreq" % num): + if os.path.exists(p): + return p + ret = [] - ls = glob.glob("/sys/devices/system/cpu/cpufreq/policy*") - if ls: - # Sort the list so that '10' comes after '2'. This should - # ensure the CPU order is consistent with other CPU functions - # having a 'percpu' argument and returning results for multiple - # CPUs (cpu_times(), cpu_percent(), cpu_times_percent()). - ls.sort(key=lambda x: int(os.path.basename(x)[6:])) - else: - # https://github.com/giampaolo/psutil/issues/981 - ls = glob.glob("/sys/devices/system/cpu/cpu[0-9]*/cpufreq") - ls.sort(key=lambda x: int(re.search('[0-9]+', x).group(0))) + for n in range(cpu_count_logical()): + path = get_path(n) + if not path: + continue - pjoin = os.path.join - for path in ls: + pjoin = os.path.join curr = cat(pjoin(path, "scaling_cur_freq"), fallback=None) if curr is None: # Likely an old RedHat, see: diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c index 53617c58..f071648f 100644 --- a/psutil/_psutil_windows.c +++ b/psutil/_psutil_windows.c @@ -40,6 +40,7 @@ #include "arch/windows/process_handles.h" #include "arch/windows/inet_ntop.h" #include "arch/windows/services.h" +#include "arch/windows/wmi.h" #include "_psutil_common.h" @@ -3508,6 +3509,12 @@ PsutilMethods[] = { "Return NICs stats."}, {"cpu_freq", psutil_cpu_freq, METH_VARARGS, "Return CPU frequency."}, +#if (_WIN32_WINNT >= 0x0600) // Windows Vista + {"init_loadavg_counter", psutil_init_loadavg_counter, METH_VARARGS, + "Initializes the emulated load average calculator."}, + {"getloadavg", psutil_get_loadavg, METH_VARARGS, + "Returns the emulated POSIX-like load average."}, +#endif {"sensors_battery", psutil_sensors_battery, METH_VARARGS, "Return battery metrics usage."}, {"getpagesize", psutil_getpagesize, METH_VARARGS, diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 929e27d7..3f131980 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -80,6 +80,7 @@ __extra__all__ = [ CONN_DELETE_TCB = "DELETE_TCB" HAS_PROC_IO_PRIORITY = hasattr(cext, "proc_io_priority_get") +HAS_GETLOADAVG = hasattr(cext, "getloadavg") if enum is None: @@ -353,6 +354,23 @@ def cpu_freq(): return [_common.scpufreq(float(curr), min_, float(max_))] +if HAS_GETLOADAVG: + _loadavg_inititialized = False + + def getloadavg(): + """Return the number of processes in the system run queue averaged + over the last 1, 5, and 15 minutes respectively as a tuple""" + global _loadavg_inititialized + + if not _loadavg_inititialized: + cext.init_loadavg_counter() + _loadavg_inititialized = True + + # Drop to 2 decimal points which is what Linux does + raw_loads = cext.getloadavg() + return tuple([round(load, 2) for load in raw_loads]) + + # ===================================================================== # --- network # ===================================================================== diff --git a/psutil/arch/windows/wmi.c b/psutil/arch/windows/wmi.c new file mode 100644 index 00000000..5858a9e0 --- /dev/null +++ b/psutil/arch/windows/wmi.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Functions related to the Windows Management Instrumentation API. + */ + +#include <Python.h> +#include <windows.h> +#include <pdh.h> + +#include "../../_psutil_common.h" + + +// We use an exponentially weighted moving average, just like Unix systems do +// https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation +// +// These constants serve as the damping factor and are calculated with +// 1 / exp(sampling interval in seconds / window size in seconds) +// +// This formula comes from linux's include/linux/sched/loadavg.h +// https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L20-L23 +#define LOADAVG_FACTOR_1F 0.9200444146293232478931553241 +#define LOADAVG_FACTOR_5F 0.6592406302004437462547604110 +#define LOADAVG_FACTOR_15F 0.2865047968601901003248854266 +// The time interval in seconds between taking load counts, same as Linux +#define SAMPLING_INTERVAL 5 + +double load_avg_1m = 0; +double load_avg_5m = 0; +double load_avg_15m = 0; + + +VOID CALLBACK LoadAvgCallback(PVOID hCounter) { + PDH_FMT_COUNTERVALUE displayValue; + double currentLoad; + PDH_STATUS err; + + err = PdhGetFormattedCounterValue( + (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &displayValue); + // Skip updating the load if we can't get the value successfully + if (err != ERROR_SUCCESS) { + return; + } + currentLoad = displayValue.doubleValue; + + load_avg_1m = load_avg_1m * LOADAVG_FACTOR_1F + currentLoad * \ + (1.0 - LOADAVG_FACTOR_1F); + load_avg_5m = load_avg_5m * LOADAVG_FACTOR_5F + currentLoad * \ + (1.0 - LOADAVG_FACTOR_5F); + load_avg_15m = load_avg_15m * LOADAVG_FACTOR_15F + currentLoad * \ + (1.0 - LOADAVG_FACTOR_15F); +} + + +PyObject * +psutil_init_loadavg_counter(PyObject *self, PyObject *args) { + WCHAR *szCounterPath = L"\\System\\Processor Queue Length"; + PDH_STATUS s; + BOOL ret; + HQUERY hQuery; + HCOUNTER hCounter; + HANDLE event; + HANDLE waitHandle; + + if ((PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS) + goto error; + + s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter); + if (s != ERROR_SUCCESS) + goto error; + + event = CreateEventW(NULL, FALSE, FALSE, L"LoadUpdateEvent"); + if (event == NULL) { + PyErr_SetFromWindowsErr(GetLastError()); + return NULL; + } + + s = PdhCollectQueryDataEx(hQuery, SAMPLING_INTERVAL, event); + if (s != ERROR_SUCCESS) + goto error; + + ret = RegisterWaitForSingleObject( + &waitHandle, + event, + (WAITORTIMERCALLBACK)LoadAvgCallback, + (PVOID) + hCounter, + INFINITE, + WT_EXECUTEDEFAULT); + + if (ret == 0) { + PyErr_SetFromWindowsErr(GetLastError()); + return NULL; + } + + Py_RETURN_NONE; + +error: + PyErr_SetExcFromWindowsErr(PyExc_OSError, 0); + return NULL; +} + + +/* + * Gets the emulated 1 minute, 5 minute and 15 minute load averages + * (processor queue length) for the system. + * `init_loadavg_counter` must be called before this function to engage the + * mechanism that records load values. + */ +PyObject * +psutil_get_loadavg(PyObject *self, PyObject *args) { + return Py_BuildValue("(ddd)", load_avg_1m, load_avg_5m, load_avg_15m); +}
\ No newline at end of file diff --git a/psutil/arch/windows/wmi.h b/psutil/arch/windows/wmi.h new file mode 100644 index 00000000..0210f2d6 --- /dev/null +++ b/psutil/arch/windows/wmi.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#include <Python.h> + +PyObject* psutil_init_loadavg_counter(); +PyObject* psutil_get_loadavg(); diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py index 3aebbcbd..79681719 100644 --- a/psutil/tests/__init__.py +++ b/psutil/tests/__init__.py @@ -159,6 +159,7 @@ HERE = os.path.abspath(os.path.dirname(__file__)) HAS_CONNECTIONS_UNIX = POSIX and not SUNOS HAS_CPU_AFFINITY = hasattr(psutil.Process, "cpu_affinity") HAS_CPU_FREQ = hasattr(psutil, "cpu_freq") +HAS_GETLOADAVG = hasattr(psutil, "getloadavg") HAS_ENVIRON = hasattr(psutil.Process, "environ") HAS_IONICE = hasattr(psutil.Process, "ionice") HAS_MEMORY_MAPS = hasattr(psutil.Process, "memory_maps") diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py index 66c50aa6..e8745a75 100755 --- a/psutil/tests/test_linux.py +++ b/psutil/tests/test_linux.py @@ -10,7 +10,6 @@ from __future__ import division import collections import contextlib import errno -import glob import io import os import re @@ -30,6 +29,7 @@ from psutil._compat import u from psutil.tests import call_until from psutil.tests import HAS_BATTERY from psutil.tests import HAS_CPU_FREQ +from psutil.tests import HAS_GETLOADAVG from psutil.tests import HAS_RLIMIT from psutil.tests import MEMORY_TOLERANCE from psutil.tests import mock @@ -698,27 +698,26 @@ class TestSystemCPUFrequency(unittest.TestCase): @unittest.skipIf(not HAS_CPU_FREQ, "not supported") def test_emulate_no_files(self): - with mock.patch("psutil._pslinux.glob.glob", return_value=[]): + with mock.patch("os.path.exists", return_value=False): self.assertIsNone(psutil.cpu_freq()) @unittest.skipIf(TRAVIS, "fails on Travis") @unittest.skipIf(not HAS_CPU_FREQ, "not supported") def test_emulate_use_second_file(self): # https://github.com/giampaolo/psutil/issues/981 - def glob_mock(pattern): - if pattern.startswith("/sys/devices/system/cpu/cpufreq/policy"): - flags.append(None) - return [] + def path_exists_mock(path): + if path.startswith("/sys/devices/system/cpu/cpufreq/policy"): + return False else: flags.append(None) - return orig_glob(pattern) + return orig_exists(path) flags = [] - orig_glob = glob.glob - with mock.patch("psutil._pslinux.glob.glob", side_effect=glob_mock, + orig_exists = os.path.exists + with mock.patch("os.path.exists", side_effect=path_exists_mock, create=True): assert psutil.cpu_freq() - self.assertEqual(len(flags), 2) + self.assertEqual(len(flags), psutil.cpu_count(logical=True)) @unittest.skipIf(not HAS_CPU_FREQ, "not supported") def test_emulate_use_cpuinfo(self): @@ -752,11 +751,14 @@ class TestSystemCPUFrequency(unittest.TestCase): @unittest.skipIf(not HAS_CPU_FREQ, "not supported") def test_emulate_data(self): def open_mock(name, *args, **kwargs): - if name.endswith('/scaling_cur_freq'): + if (name.endswith('/scaling_cur_freq') and + name.startswith("/sys/devices/system/cpu/cpufreq/policy")): return io.BytesIO(b"500000") - elif name.endswith('/scaling_min_freq'): + elif (name.endswith('/scaling_min_freq') and + name.startswith("/sys/devices/system/cpu/cpufreq/policy")): return io.BytesIO(b"600000") - elif name.endswith('/scaling_max_freq'): + elif (name.endswith('/scaling_max_freq') and + name.startswith("/sys/devices/system/cpu/cpufreq/policy")): return io.BytesIO(b"700000") else: return orig_open(name, *args, **kwargs) @@ -765,8 +767,7 @@ class TestSystemCPUFrequency(unittest.TestCase): patch_point = 'builtins.open' if PY3 else '__builtin__.open' with mock.patch(patch_point, side_effect=open_mock): with mock.patch( - 'glob.glob', - return_value=['/sys/devices/system/cpu/cpufreq/policy0']): + 'os.path.exists', return_value=True): freq = psutil.cpu_freq() self.assertEqual(freq.current, 500.0) self.assertEqual(freq.min, 600.0) @@ -775,26 +776,41 @@ class TestSystemCPUFrequency(unittest.TestCase): @unittest.skipIf(not HAS_CPU_FREQ, "not supported") def test_emulate_multi_cpu(self): def open_mock(name, *args, **kwargs): - if name.endswith('/scaling_cur_freq'): + n = name + if (n.endswith('/scaling_cur_freq') and + n.startswith("/sys/devices/system/cpu/cpufreq/policy0")): return io.BytesIO(b"100000") - elif name.endswith('/scaling_min_freq'): + elif (n.endswith('/scaling_min_freq') and + n.startswith("/sys/devices/system/cpu/cpufreq/policy0")): return io.BytesIO(b"200000") - elif name.endswith('/scaling_max_freq'): + elif (n.endswith('/scaling_max_freq') and + n.startswith("/sys/devices/system/cpu/cpufreq/policy0")): return io.BytesIO(b"300000") + elif (n.endswith('/scaling_cur_freq') and + n.startswith("/sys/devices/system/cpu/cpufreq/policy1")): + return io.BytesIO(b"400000") + elif (n.endswith('/scaling_min_freq') and + n.startswith("/sys/devices/system/cpu/cpufreq/policy1")): + return io.BytesIO(b"500000") + elif (n.endswith('/scaling_max_freq') and + n.startswith("/sys/devices/system/cpu/cpufreq/policy1")): + return io.BytesIO(b"600000") else: return orig_open(name, *args, **kwargs) orig_open = open patch_point = 'builtins.open' if PY3 else '__builtin__.open' - policies = ['/sys/devices/system/cpu/cpufreq/policy0', - '/sys/devices/system/cpu/cpufreq/policy1', - '/sys/devices/system/cpu/cpufreq/policy2'] with mock.patch(patch_point, side_effect=open_mock): - with mock.patch('glob.glob', return_value=policies): - freq = psutil.cpu_freq() - self.assertEqual(freq.current, 100.0) - self.assertEqual(freq.min, 200.0) - self.assertEqual(freq.max, 300.0) + with mock.patch('os.path.exists', return_value=True): + with mock.patch('psutil._pslinux.cpu_count_logical', + return_value=2): + freq = psutil.cpu_freq(percpu=True) + self.assertEqual(freq[0].current, 100.0) + self.assertEqual(freq[0].min, 200.0) + self.assertEqual(freq[0].max, 300.0) + self.assertEqual(freq[1].current, 400.0) + self.assertEqual(freq[1].min, 500.0) + self.assertEqual(freq[1].max, 600.0) @unittest.skipIf(TRAVIS, "fails on Travis") @unittest.skipIf(not HAS_CPU_FREQ, "not supported") @@ -810,14 +826,12 @@ class TestSystemCPUFrequency(unittest.TestCase): orig_open = open patch_point = 'builtins.open' if PY3 else '__builtin__.open' - policies = ['/sys/devices/system/cpu/cpufreq/policy0', - '/sys/devices/system/cpu/cpufreq/policy1', - '/sys/devices/system/cpu/cpufreq/policy2'] - with mock.patch(patch_point, side_effect=open_mock): - with mock.patch('glob.glob', return_value=policies): - freq = psutil.cpu_freq() - self.assertEqual(freq.current, 200) + with mock.patch('os.path.exists', return_value=True): + with mock.patch('psutil._pslinux.cpu_count_logical', + return_value=1): + freq = psutil.cpu_freq() + self.assertEqual(freq.current, 200) # Also test that NotImplementedError is raised in case no # current freq file is present. @@ -833,7 +847,7 @@ class TestSystemCPUFrequency(unittest.TestCase): orig_open = open patch_point = 'builtins.open' if PY3 else '__builtin__.open' with mock.patch(patch_point, side_effect=open_mock): - with mock.patch('glob.glob', return_value=policies): + with mock.patch('os.path.exists', return_value=True): self.assertRaises(NotImplementedError, psutil.cpu_freq) @@ -853,6 +867,20 @@ class TestSystemCPUStats(unittest.TestCase): self.assertAlmostEqual(vmstat_value, psutil_value, delta=500) +@unittest.skipIf(not LINUX, "LINUX only") +class TestLoadAvg(unittest.TestCase): + + @unittest.skipIf(not HAS_GETLOADAVG, "not supported") + def test_getloadavg(self): + psutil_value = psutil.getloadavg() + with open("/proc/loadavg", "r") as f: + proc_value = f.read().split() + + self.assertAlmostEqual(float(proc_value[0]), psutil_value[0], delta=1) + self.assertAlmostEqual(float(proc_value[1]), psutil_value[1], delta=1) + self.assertAlmostEqual(float(proc_value[2]), psutil_value[2], delta=1) + + # ===================================================================== # --- system network # ===================================================================== diff --git a/psutil/tests/test_memory_leaks.py b/psutil/tests/test_memory_leaks.py index 170a1d0c..dde50a57 100755 --- a/psutil/tests/test_memory_leaks.py +++ b/psutil/tests/test_memory_leaks.py @@ -36,6 +36,7 @@ from psutil.tests import create_sockets from psutil.tests import get_test_subprocess from psutil.tests import HAS_CPU_AFFINITY from psutil.tests import HAS_CPU_FREQ +from psutil.tests import HAS_GETLOADAVG from psutil.tests import HAS_ENVIRON from psutil.tests import HAS_IONICE from psutil.tests import HAS_MEMORY_MAPS @@ -474,6 +475,10 @@ class TestModuleFunctionsLeaks(TestMemLeak): def test_cpu_freq(self): self.execute(psutil.cpu_freq) + @unittest.skipIf(not HAS_GETLOADAVG, "not supported") + def test_getloadavg(self): + self.execute(psutil.getloadavg) + # --- mem def test_virtual_memory(self): diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index 75e65b0f..c4c503a2 100755 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -38,6 +38,7 @@ from psutil.tests import enum from psutil.tests import get_test_subprocess from psutil.tests import HAS_BATTERY from psutil.tests import HAS_CPU_FREQ +from psutil.tests import HAS_GETLOADAVG from psutil.tests import HAS_NET_IO_COUNTERS from psutil.tests import HAS_SENSORS_BATTERY from psutil.tests import HAS_SENSORS_FANS @@ -778,6 +779,15 @@ class TestSystemAPIs(unittest.TestCase): if LINUX: self.assertEqual(len(ls), psutil.cpu_count()) + @unittest.skipIf(not HAS_GETLOADAVG, "not supported") + def test_getloadavg(self): + loadavg = psutil.getloadavg() + assert len(loadavg) == 3 + + for load in loadavg: + self.assertIsInstance(load, float) + self.assertGreaterEqual(load, 0.0) + def test_os_constants(self): names = ["POSIX", "WINDOWS", "LINUX", "MACOS", "FREEBSD", "OPENBSD", "NETBSD", "BSD", "SUNOS"] @@ -135,12 +135,12 @@ if WINDOWS: 'psutil/arch/windows/inet_ntop.c', 'psutil/arch/windows/services.c', 'psutil/arch/windows/global.c', - # 'psutil/arch/windows/connections.c', + 'psutil/arch/windows/wmi.c', ], define_macros=macros, libraries=[ "psapi", "kernel32", "advapi32", "shell32", "netapi32", - "wtsapi32", "ws2_32", "PowrProf", + "wtsapi32", "ws2_32", "PowrProf", "pdh", ], # extra_compile_args=["/Z7"], # extra_link_args=["/DEBUG"] |