summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2019-04-11 12:00:41 +0200
committerGiampaolo Rodola <g.rodola@gmail.com>2019-04-11 12:00:41 +0200
commit8ac80188472e8cf6889a6e4aeac2d09cdd19d630 (patch)
treeae825c60d301b913852353bef60af07f784fcf1b
parent97f0c7adf18ac02fa7e610fca19bf2a91455a06f (diff)
parent921870d54091f399cd2b129db19530cc486b5700 (diff)
downloadpsutil-8ac80188472e8cf6889a6e4aeac2d09cdd19d630.tar.gz
Merge branch 'master' of github.com:giampaolo/psutil
-rwxr-xr-x.ci/travis/install.sh4
-rw-r--r--.gitignore1
-rw-r--r--CREDITS5
-rw-r--r--HISTORY.rst2
-rw-r--r--docs/DEVNOTES2
-rw-r--r--docs/index.rst30
-rw-r--r--psutil/__init__.py11
-rw-r--r--psutil/_pslinux.py26
-rw-r--r--psutil/_psutil_windows.c7
-rw-r--r--psutil/_pswindows.py18
-rw-r--r--psutil/arch/windows/wmi.c115
-rw-r--r--psutil/arch/windows/wmi.h12
-rw-r--r--psutil/tests/__init__.py1
-rwxr-xr-xpsutil/tests/test_linux.py96
-rwxr-xr-xpsutil/tests/test_memory_leaks.py5
-rwxr-xr-xpsutil/tests/test_system.py10
-rwxr-xr-xsetup.py4
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
diff --git a/.gitignore b/.gitignore
index 99d0d545..3d22b0b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ syntax: glob
*.rej
*.so
*.swp
+.failed-tests.txt
.cache/
.idea/
.tox/
diff --git a/CREDITS b/CREDITS
index 36ab49be..626a79a8 100644
--- a/CREDITS
+++ b/CREDITS
@@ -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"]
diff --git a/setup.py b/setup.py
index 465a9b9e..2c3d9b36 100755
--- a/setup.py
+++ b/setup.py
@@ -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"]