summaryrefslogtreecommitdiff
path: root/psutil
diff options
context:
space:
mode:
Diffstat (limited to 'psutil')
-rw-r--r--psutil/__init__.py87
-rw-r--r--psutil/_psbsd.py50
-rw-r--r--psutil/_pslinux.py17
-rw-r--r--psutil/_psosx.py5
-rw-r--r--psutil/_psutil_common.c15
-rw-r--r--psutil/_psutil_common.h1
-rw-r--r--psutil/_psutil_osx.c2
-rw-r--r--psutil/_psutil_windows.c5
-rw-r--r--psutil/_pswindows.py12
-rw-r--r--psutil/arch/osx/cpu.c13
-rw-r--r--psutil/arch/osx/cpu.h1
-rw-r--r--psutil/arch/windows/cpu.c45
-rw-r--r--psutil/arch/windows/cpu.h2
-rwxr-xr-xpsutil/tests/test_aix.py2
-rwxr-xr-xpsutil/tests/test_bsd.py4
-rwxr-xr-xpsutil/tests/test_contracts.py7
-rwxr-xr-xpsutil/tests/test_linux.py96
-rwxr-xr-xpsutil/tests/test_memleaks.py18
-rwxr-xr-xpsutil/tests/test_osx.py28
-rwxr-xr-xpsutil/tests/test_system.py98
-rwxr-xr-xpsutil/tests/test_windows.py15
21 files changed, 377 insertions, 146 deletions
diff --git a/psutil/__init__.py b/psutil/__init__.py
index 44efb7ff..7e6afada 100644
--- a/psutil/__init__.py
+++ b/psutil/__init__.py
@@ -31,6 +31,7 @@ import subprocess
import sys
import threading
import time
+import warnings
try:
import pwd
except ImportError:
@@ -1558,27 +1559,81 @@ def wait_procs(procs, timeout=None, callback=None):
# =====================================================================
-def cpu_count(logical=True):
- """Return the number of logical CPUs in the system (same as
- os.cpu_count() in Python 3.4).
+def cpu_count(kind="logical", **_kwargs):
+ """Return the number of CPUs in the system (various kinds).
- If *logical* is False return the number of physical cores only
- (e.g. hyper thread CPUs are excluded).
+ DEPRECATION WARNING: before, the signature of this function was
+ cpu_count(logical=True), then it was replaced with:
+ cpu_count(kind="logical").
- Return None if undetermined.
+ The old argument is still supported, even if it's not part of the
+ signature anymore (it's hidden in the private **_kwargs).
+ The followings statements are equivalent and should be replaced in
+ new code:
- The return value is cached after first call.
- If desired cache can be cleared like this:
-
- >>> psutil.cpu_count.cache_clear()
+ cpu_count(logical=True) == cpu_count(kind="logical")
+ cpu_count(logical=False) == cpu_count(kind="cores")
+ cpu_count(True) == cpu_count("logical")
+ cpu_count(False) == cpu_count("cores")
"""
- if logical:
- ret = _psplatform.cpu_count_logical()
+ if isinstance(kind, bool):
+ msg = "cpu_count(%s) function invocation is deprecated; use " \
+ "cpu_count(%r) instead" % (kind, "logical" if kind else "cores")
+ warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
+ kind = "logical" if kind else "cores"
+ if _kwargs:
+ if list(_kwargs.keys()) == ["logical"]:
+ msg = "cpu_count(logical=%s) function invocation is deprecated; " \
+ "use cpu_count(kind=%r) instead"
+ msg = msg % (_kwargs["logical"], "logical" if _kwargs["logical"]
+ else "cores")
+ kind = "logical" if _kwargs["logical"] else "cores"
+ warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
+ else:
+ raise TypeError("cpu_count() got an unexpected keyword argument "
+ "'%s'" % (list(_kwargs.keys()).pop()))
+
+ if kind == "logical":
+ # Availability: all
+ count = _psplatform.cpu_count_logical()
+ elif kind == "cores":
+ # Availability: all except OpenBSD and NetBSD
+ if not hasattr(_psplatform, "cpu_count_cores"):
+ return None
+ count = _psplatform.cpu_count_cores()
+ elif kind == "sockets":
+ # Availability: Linux, Windows, macOS, FreeBSD
+ if not hasattr(_psplatform, "cpu_count_sockets"):
+ return None
+ count = _psplatform.cpu_count_sockets()
+ elif kind == "numa":
+ # Availability: Linux, Windows
+ if not hasattr(_psplatform, "cpu_count_numa"):
+ return None
+ count = _psplatform.cpu_count_numa()
+ # XXX: this is more complicated than this, see:
+ # https://github.com/giampaolo/psutil/issues/1122
+ # https://bugs.python.org/issue36054
+ # elif kind == "usable":
+ # if hasattr(os, "sched_getaffinity"):
+ # # Availability: some UNIXes (definitively Linux), Python >= 3.3
+ # count = len(os.sched_getaffinity(0))
+ # elif hasattr(Process, "cpu_affinity"):
+ # # Availability: Linux, Windows, FreeBSD
+ # count = len(Process().cpu_affinity())
+ # else:
+ # # Note that this may not necessarily be correct in case:
+ # # * the process CPU affinity has been changed
+ # # * Linux cgroups are in use with CPU affinity configured
+ # # * Windows systems using processor groups or having more
+ # # than 64 CPUs
+ # count = _psplatform.cpu_count_logical()
else:
- ret = _psplatform.cpu_count_cores()
- if ret is not None and ret < 1:
- ret = None
- return ret
+ valid = ("logical", "cores", "sockets", "numa")
+ raise ValueError("invalid kind %r; choose between %s" % (kind, valid))
+ if count is not None and count < 1:
+ count = None
+ return count
def cpu_times(percpu=False):
diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py
index bdcfc1e6..19e636fd 100644
--- a/psutil/_psbsd.py
+++ b/psutil/_psbsd.py
@@ -248,36 +248,28 @@ def cpu_count_logical():
return cext.cpu_count_logical()
-if OPENBSD or NETBSD:
- def cpu_count_cores():
- # OpenBSD and NetBSD do not implement this.
- return 1 if cpu_count_logical() == 1 else None
-else:
+if FREEBSD:
+
def cpu_count_cores():
- """Return the number of CPU cores in the system."""
- # From the C module we'll get an XML string similar to this:
- # http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
- # We may get None in case "sysctl kern.sched.topology_spec"
- # is not supported on this BSD version, in which case we'll mimic
- # os.cpu_count() and return None.
- ret = None
- s = cext.cpu_topology()
- if s is not None:
- # get rid of padding chars appended at the end of the string
- index = s.rfind("</groups>")
- if index != -1:
- s = s[:index + 9]
- root = ET.fromstring(s)
- try:
- ret = len(root.findall('group/children/group/cpu')) or None
- finally:
- # needed otherwise it will memleak
- root.clear()
- if not ret:
- # If logical CPUs == 1 it's obvious we' have only 1 core.
- if cpu_count_logical() == 1:
- return 1
- return ret
+ # https://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
+ xmlstr = cext.cpu_topology()
+ if xmlstr is not None:
+ root = ET.fromstring(xmlstr)
+ try:
+ count = len(root.findall('group/children/group/cpu'))
+ return count if count != 0 else None
+ finally:
+ root.clear()
+
+ def cpu_count_sockets():
+ xmlstr = cext.cpu_topology()
+ if xmlstr is not None:
+ root = ET.fromstring(xmlstr)
+ try:
+ count = len(root.findall('group'))
+ return count if count != 0 else None
+ finally:
+ root.clear()
def cpu_stats():
diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py
index 640a0f3d..69b175c5 100644
--- a/psutil/_pslinux.py
+++ b/psutil/_pslinux.py
@@ -698,6 +698,23 @@ def cpu_count_cores():
return result or None # mimic os.cpu_count()
+def cpu_count_sockets():
+ """Return the number of physical CPU sockets on the motherboard."""
+ found = set()
+ with open_binary('%s/cpuinfo' % get_procfs_path()) as f:
+ for line in f:
+ line = line.strip().lower()
+ if line.startswith(b'physical id'):
+ key, value = line.split(b'\t:', 1)
+ found.add(int(value))
+ return len(found) or None
+
+
+def cpu_count_numa():
+ """Return the number of CPU NUMA nodes."""
+ return len(glob.glob("/sys/devices/system/node/node[0-9]*"))
+
+
def cpu_stats():
"""Return various CPU stats as a named tuple."""
with open_binary('%s/stat' % get_procfs_path()) as f:
diff --git a/psutil/_psosx.py b/psutil/_psosx.py
index d948cc15..9cfb2d15 100644
--- a/psutil/_psosx.py
+++ b/psutil/_psosx.py
@@ -164,6 +164,11 @@ def cpu_count_cores():
return cext.cpu_count_cores()
+def cpu_count_sockets():
+ """Return the number of physical sockets on the motherboard."""
+ return cext.cpu_count_sockets()
+
+
def cpu_stats():
ctx_switches, interrupts, soft_interrupts, syscalls, traps = \
cext.cpu_stats()
diff --git a/psutil/_psutil_common.c b/psutil/_psutil_common.c
index ff060a51..b82d5e89 100644
--- a/psutil/_psutil_common.c
+++ b/psutil/_psutil_common.c
@@ -178,6 +178,21 @@ psutil_setup(void) {
}
+int
+psutil_add_to_dict(PyObject *py_dict, char *keyname, PyObject *py_obj) {
+ // Add a new python object to an existing dict, DECREFing that object
+ // and setting it to NULL both in case of success or failure.
+ if (!py_obj)
+ return 1;
+ if (PyDict_SetItemString(py_dict, keyname, py_obj)) {
+ Py_CLEAR(py_obj);
+ return 1;
+ }
+ Py_CLEAR(py_obj);
+ return 0;
+}
+
+
// ============================================================================
// Utility functions (BSD)
// ============================================================================
diff --git a/psutil/_psutil_common.h b/psutil/_psutil_common.h
index cb0b399d..636f783c 100644
--- a/psutil/_psutil_common.h
+++ b/psutil/_psutil_common.h
@@ -103,6 +103,7 @@ PyObject* PyErr_SetFromOSErrnoWithSyscall(const char *syscall);
PyObject* psutil_set_testing(PyObject *self, PyObject *args);
void psutil_debug(const char* format, ...);
int psutil_setup(void);
+int psutil_add_to_dict(PyObject *py_dict, char *keyname, PyObject *py_obj);
// ====================================================================
// --- BSD
diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c
index 5a77de14..a12679ec 100644
--- a/psutil/_psutil_osx.c
+++ b/psutil/_psutil_osx.c
@@ -1650,6 +1650,8 @@ static PyMethodDef mod_methods[] = {
"Return number of logical CPUs on the system"},
{"cpu_count_cores", psutil_cpu_count_cores, METH_VARARGS,
"Return number of CPU cores on the system"},
+ {"cpu_count_sockets", psutil_cpu_count_sockets, METH_VARARGS,
+ "Return number of CPU sockets on the motherboard"},
{"virtual_mem", psutil_virtual_mem, METH_VARARGS,
"Return system virtual memory stats"},
{"swap_mem", psutil_swap_mem, METH_VARARGS,
diff --git a/psutil/_psutil_windows.c b/psutil/_psutil_windows.c
index 13cf58c4..1b813f99 100644
--- a/psutil/_psutil_windows.c
+++ b/psutil/_psutil_windows.c
@@ -1582,8 +1582,6 @@ PsutilMethods[] = {
"Determine if the process exists in the current process list."},
{"cpu_count_logical", psutil_cpu_count_logical, METH_VARARGS,
"Returns the number of logical CPUs on the system"},
- {"cpu_count_cores", psutil_cpu_count_cores, METH_VARARGS,
- "Returns the number of CPU cores on the system"},
{"boot_time", psutil_boot_time, METH_VARARGS,
"Return the system boot time expressed in seconds since the epoch."},
{"virtual_mem", psutil_virtual_mem, METH_VARARGS,
@@ -1639,6 +1637,9 @@ PsutilMethods[] = {
// --- windows API bindings
{"QueryDosDevice", psutil_QueryDosDevice, METH_VARARGS,
"QueryDosDevice binding"},
+ {"GetLogicalProcessorInformationEx",
+ psutil_GetLogicalProcessorInformationEx, METH_VARARGS,
+ "GetLogicalProcessorInformationEx win API call as a dict"},
// --- others
{"set_testing", psutil_set_testing, METH_NOARGS,
diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py
index 0ad60c4a..30902297 100644
--- a/psutil/_pswindows.py
+++ b/psutil/_pswindows.py
@@ -306,7 +306,17 @@ def cpu_count_logical():
def cpu_count_cores():
"""Return the number of CPU cores in the system."""
- return cext.cpu_count_cores()
+ return cext.GetLogicalProcessorInformationEx()['cores']
+
+
+def cpu_count_sockets():
+ """Return the number of CPU sockets on the motherboard."""
+ return cext.GetLogicalProcessorInformationEx()['sockets']
+
+
+def cpu_count_numa():
+ """Return the number of CPU NUMA nodes."""
+ return cext.GetLogicalProcessorInformationEx()['numa']
def cpu_stats():
diff --git a/psutil/arch/osx/cpu.c b/psutil/arch/osx/cpu.c
index 37141a2d..e6f72a8a 100644
--- a/psutil/arch/osx/cpu.c
+++ b/psutil/arch/osx/cpu.c
@@ -30,7 +30,6 @@ For reference, here's the git history with original implementations:
#include "../../_psutil_posix.h"
-
PyObject *
psutil_cpu_count_logical(PyObject *self, PyObject *args) {
int num;
@@ -56,6 +55,18 @@ psutil_cpu_count_cores(PyObject *self, PyObject *args) {
PyObject *
+psutil_cpu_count_sockets(PyObject *self, PyObject *args) {
+ int value;
+ size_t size = sizeof(value);
+
+ if (sysctlbyname("hw.packages", &value, &size, NULL, 2))
+ Py_RETURN_NONE; // mimic os.cpu_count()
+ else
+ return Py_BuildValue("i", value);
+}
+
+
+PyObject *
psutil_cpu_times(PyObject *self, PyObject *args) {
mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
kern_return_t error;
diff --git a/psutil/arch/osx/cpu.h b/psutil/arch/osx/cpu.h
index aac0f809..40be1117 100644
--- a/psutil/arch/osx/cpu.h
+++ b/psutil/arch/osx/cpu.h
@@ -8,6 +8,7 @@
PyObject *psutil_cpu_count_logical(PyObject *self, PyObject *args);
PyObject *psutil_cpu_count_cores(PyObject *self, PyObject *args);
+PyObject *psutil_cpu_count_sockets(PyObject *self, PyObject *args);
PyObject *psutil_cpu_times(PyObject *self, PyObject *args);
PyObject *psutil_cpu_freq(PyObject *self, PyObject *args);
PyObject *psutil_cpu_stats(PyObject *self, PyObject *args);
diff --git a/psutil/arch/windows/cpu.c b/psutil/arch/windows/cpu.c
index 355de6df..020a9727 100644
--- a/psutil/arch/windows/cpu.c
+++ b/psutil/arch/windows/cpu.c
@@ -177,17 +177,25 @@ psutil_cpu_count_logical(PyObject *self, PyObject *args) {
/*
- * Return the number of CPU cores (non hyper-threading).
+ * Re-adapted from:
+ * https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/
+ * nf-sysinfoapi-getlogicalprocessorinformation?redirectedfrom=MSDN
*/
PyObject *
-psutil_cpu_count_cores(PyObject *self, PyObject *args) {
+psutil_GetLogicalProcessorInformationEx(PyObject *self, PyObject *args) {
DWORD rc;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX buffer = NULL;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX ptr = NULL;
DWORD length = 0;
DWORD offset = 0;
- DWORD ncpus = 0;
- DWORD prev_processor_info_size = 0;
+ DWORD coresCount = 0;
+ DWORD socketsCount = 0;
+ DWORD numaNodesCount = 0;
+ DWORD prevProcInfoSize = 0;
+ PyObject *py_retdict = PyDict_New();
+
+ if (py_retdict == NULL)
+ return NULL;
// GetLogicalProcessorInformationEx() is available from Windows 7
// onward. Differently from GetLogicalProcessorInformation()
@@ -230,26 +238,39 @@ psutil_cpu_count_cores(PyObject *self, PyObject *args) {
// Advance ptr by the size of the previous
// SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX struct.
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*) \
- (((char*)ptr) + prev_processor_info_size);
+ (((char*)ptr) + prevProcInfoSize);
if (ptr->Relationship == RelationProcessorCore) {
- ncpus += 1;
+ coresCount += 1;
+ }
+ else if (ptr->Relationship == RelationNumaNode) {
+ numaNodesCount += 1;
+ }
+ else if (ptr->Relationship == RelationProcessorPackage) {
+ socketsCount += 1;
}
// When offset == length, we've reached the last processor
// info struct in the buffer.
offset += ptr->Size;
- prev_processor_info_size = ptr->Size;
+ prevProcInfoSize = ptr->Size;
}
free(buffer);
- if (ncpus != 0) {
- return Py_BuildValue("I", ncpus);
+
+ if (psutil_add_to_dict(py_retdict, "cores",
+ Py_BuildValue("I", coresCount)) == 1) {
+ return NULL;
}
- else {
- psutil_debug("GetLogicalProcessorInformationEx() count was 0");
- Py_RETURN_NONE; // mimick os.cpu_count()
+ if (psutil_add_to_dict(py_retdict, "sockets",
+ Py_BuildValue("I", socketsCount)) == 1) {
+ return NULL;
+ }
+ if (psutil_add_to_dict(py_retdict, "numa",
+ Py_BuildValue("I", numaNodesCount)) == 1) {
+ return NULL;
}
+ return py_retdict;
return_none:
if (buffer != NULL)
diff --git a/psutil/arch/windows/cpu.h b/psutil/arch/windows/cpu.h
index 1ef3ff1f..8ebcf80c 100644
--- a/psutil/arch/windows/cpu.h
+++ b/psutil/arch/windows/cpu.h
@@ -7,7 +7,7 @@
#include <Python.h>
PyObject *psutil_cpu_count_logical(PyObject *self, PyObject *args);
-PyObject *psutil_cpu_count_cores(PyObject *self, PyObject *args);
+PyObject *psutil_GetLogicalProcessorInformationEx(PyObject *self, PyObject *args);
PyObject *psutil_cpu_freq(PyObject *self, PyObject *args);
PyObject *psutil_cpu_stats(PyObject *self, PyObject *args);
PyObject *psutil_cpu_times(PyObject *self, PyObject *args);
diff --git a/psutil/tests/test_aix.py b/psutil/tests/test_aix.py
index a32c3f6a..b1133833 100755
--- a/psutil/tests/test_aix.py
+++ b/psutil/tests/test_aix.py
@@ -107,7 +107,7 @@ class AIXSpecificTestCase(PsutilTestCase):
def test_cpu_count_logical(self):
out = sh('/usr/bin/mpstat -a')
mpstat_lcpu = int(re.search(r"lcpu=(\d+)", out).group(1))
- psutil_lcpu = psutil.cpu_count(logical=True)
+ psutil_lcpu = psutil.cpu_count("logical")
self.assertEqual(mpstat_lcpu, psutil_lcpu)
def test_net_if_addrs_names(self):
diff --git a/psutil/tests/test_bsd.py b/psutil/tests/test_bsd.py
index b0bff87f..48b118ab 100755
--- a/psutil/tests/test_bsd.py
+++ b/psutil/tests/test_bsd.py
@@ -124,7 +124,7 @@ class BSDTestCase(PsutilTestCase):
@unittest.skipIf(not which('sysctl'), "sysctl cmd not available")
def test_cpu_count_logical(self):
syst = sysctl("hw.ncpu")
- self.assertEqual(psutil.cpu_count(logical=True), syst)
+ self.assertEqual(psutil.cpu_count("logical"), syst)
@unittest.skipIf(not which('sysctl'), "sysctl cmd not available")
def test_virtual_memory_total(self):
@@ -457,7 +457,7 @@ class FreeBSDSystemTestCase(PsutilTestCase):
# --- sensors_temperatures
def test_sensors_temperatures_against_sysctl(self):
- num_cpus = psutil.cpu_count(True)
+ num_cpus = psutil.cpu_count()
for cpu in range(num_cpus):
sensor = "dev.cpu.%s.temperature" % cpu
# sysctl returns a string in the format 46.0C
diff --git a/psutil/tests/test_contracts.py b/psutil/tests/test_contracts.py
index 32c75fd7..3cb2c97f 100755
--- a/psutil/tests/test_contracts.py
+++ b/psutil/tests/test_contracts.py
@@ -233,6 +233,13 @@ class TestSystemAPITypes(PsutilTestCase):
def test_cpu_count(self):
self.assertIsInstance(psutil.cpu_count(), int)
+ self.assertIsNotNone(psutil.cpu_count("logical"))
+ if not OPENBSD or NETBSD:
+ self.assertIsNotNone(psutil.cpu_count("cores"))
+ if LINUX or MACOS or WINDOWS or FREEBSD:
+ self.assertIsNotNone(psutil.cpu_count("sockets"))
+ if LINUX or WINDOWS:
+ self.assertIsNotNone(psutil.cpu_count("numa"))
@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
def test_cpu_freq(self):
diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py
index 0c6d498c..e03490b3 100755
--- a/psutil/tests/test_linux.py
+++ b/psutil/tests/test_linux.py
@@ -58,6 +58,7 @@ if LINUX:
SECTOR_SIZE = 512
EMPTY_TEMPERATURES = not glob.glob('/sys/class/hwmon/hwmon*')
+
# =====================================================================
# --- utils
# =====================================================================
@@ -182,6 +183,14 @@ def vmstat(stat):
raise ValueError("can't find %r in 'vmstat' output" % stat)
+def lscpu(field):
+ out = sh("lscpu")
+ for line in out.splitlines():
+ key, _, value = line.partition(':')
+ if field.lower() == key.lower():
+ return value.strip()
+
+
def get_free_version_info():
out = sh("free -V").strip()
if 'UNKNOWN' in out:
@@ -625,32 +634,11 @@ class TestSystemSwapMemory(PsutilTestCase):
# =====================================================================
-# --- system CPU
+# --- system CPU counts
# =====================================================================
@unittest.skipIf(not LINUX, "LINUX only")
-class TestSystemCPUTimes(PsutilTestCase):
-
- def test_fields(self):
- fields = psutil.cpu_times()._fields
- kernel_ver = re.findall(r'\d+\.\d+\.\d+', os.uname()[2])[0]
- kernel_ver_info = tuple(map(int, kernel_ver.split('.')))
- if kernel_ver_info >= (2, 6, 11):
- self.assertIn('steal', fields)
- else:
- self.assertNotIn('steal', fields)
- if kernel_ver_info >= (2, 6, 24):
- self.assertIn('guest', fields)
- else:
- self.assertNotIn('guest', fields)
- if kernel_ver_info >= (3, 2, 0):
- self.assertIn('guest_nice', fields)
- else:
- self.assertNotIn('guest_nice', fields)
-
-
-@unittest.skipIf(not LINUX, "LINUX only")
class TestSystemCPUCountLogical(PsutilTestCase):
@unittest.skipIf(not os.path.exists("/sys/devices/system/cpu/online"),
@@ -660,25 +648,24 @@ class TestSystemCPUCountLogical(PsutilTestCase):
value = f.read().strip()
if "-" in str(value):
value = int(value.split('-')[1]) + 1
- self.assertEqual(psutil.cpu_count(), value)
+ self.assertEqual(psutil.cpu_count("logical"), value)
@unittest.skipIf(not os.path.exists("/sys/devices/system/cpu"),
"/sys/devices/system/cpu does not exist")
def test_against_sysdev_cpu_num(self):
ls = os.listdir("/sys/devices/system/cpu")
count = len([x for x in ls if re.search(r"cpu\d+$", x) is not None])
- self.assertEqual(psutil.cpu_count(), count)
+ self.assertEqual(psutil.cpu_count("logical"), count)
@unittest.skipIf(not which("nproc"), "nproc utility not available")
def test_against_nproc(self):
num = int(sh("nproc --all"))
- self.assertEqual(psutil.cpu_count(logical=True), num)
+ self.assertEqual(psutil.cpu_count("logical"), num)
@unittest.skipIf(not which("lscpu"), "lscpu utility not available")
def test_against_lscpu(self):
- out = sh("lscpu -p")
- num = len([x for x in out.split('\n') if not x.startswith('#')])
- self.assertEqual(psutil.cpu_count(logical=True), num)
+ num = int(lscpu("cpu(s)"))
+ self.assertEqual(psutil.cpu_count("logical"), num)
def test_emulate_fallbacks(self):
import psutil._pslinux
@@ -719,13 +706,8 @@ class TestSystemCPUCountCores(PsutilTestCase):
@unittest.skipIf(not which("lscpu"), "lscpu utility not available")
def test_against_lscpu(self):
- out = sh("lscpu -p")
- core_ids = set()
- for line in out.split('\n'):
- if not line.startswith('#'):
- fields = line.split(',')
- core_ids.add(fields[1])
- self.assertEqual(psutil.cpu_count(logical=False), len(core_ids))
+ num = int(lscpu("core(s) per socket"))
+ self.assertEqual(psutil.cpu_count("cores"), num)
def test_method_2(self):
meth_1 = psutil._pslinux.cpu_count_cores()
@@ -744,6 +726,50 @@ class TestSystemCPUCountCores(PsutilTestCase):
@unittest.skipIf(not LINUX, "LINUX only")
+class TestSystemCPUCountSockets(PsutilTestCase):
+
+ @unittest.skipIf(not which("lscpu"), "lscpu utility not available")
+ def test_against_lscpu(self):
+ num = int(lscpu("socket(s)"))
+ self.assertEqual(psutil.cpu_count(kind="sockets"), num)
+
+
+@unittest.skipIf(not LINUX, "LINUX only")
+class TestSystemCPUCountNuma(PsutilTestCase):
+
+ @unittest.skipIf(not which("lscpu"), "lscpu utility not available")
+ def test_against_lscpu(self):
+ num = int(lscpu("numa node(s)"))
+ self.assertEqual(psutil.cpu_count(kind="numa"), num)
+
+
+# =====================================================================
+# --- system CPU (others)
+# =====================================================================
+
+
+@unittest.skipIf(not LINUX, "LINUX only")
+class TestSystemCPUTimes(PsutilTestCase):
+
+ def test_fields(self):
+ fields = psutil.cpu_times()._fields
+ kernel_ver = re.findall(r'\d+\.\d+\.\d+', os.uname()[2])[0]
+ kernel_ver_info = tuple(map(int, kernel_ver.split('.')))
+ if kernel_ver_info >= (2, 6, 11):
+ self.assertIn('steal', fields)
+ else:
+ self.assertNotIn('steal', fields)
+ if kernel_ver_info >= (2, 6, 24):
+ self.assertIn('guest', fields)
+ else:
+ self.assertNotIn('guest', fields)
+ if kernel_ver_info >= (3, 2, 0):
+ self.assertIn('guest_nice', fields)
+ else:
+ self.assertNotIn('guest_nice', fields)
+
+
+@unittest.skipIf(not LINUX, "LINUX only")
class TestSystemCPUFrequency(PsutilTestCase):
@unittest.skipIf(not HAS_CPU_FREQ, "not supported")
diff --git a/psutil/tests/test_memleaks.py b/psutil/tests/test_memleaks.py
index e6940a30..38628478 100755
--- a/psutil/tests/test_memleaks.py
+++ b/psutil/tests/test_memleaks.py
@@ -342,13 +342,25 @@ class TestModuleFunctionsLeaks(TestMemoryLeak):
# --- cpu
+ def test_cpu_count(self):
+ # here just to make ns.test_class_coverage happy
+ pass
+
@fewtimes_if_linux()
- def test_cpu_count(self): # logical
- self.execute(lambda: psutil.cpu_count(logical=True))
+ def test_cpu_count_logical(self):
+ self.execute(lambda: psutil.cpu_count("logical"))
@fewtimes_if_linux()
def test_cpu_count_cores(self):
- self.execute(lambda: psutil.cpu_count(logical=False))
+ self.execute(lambda: psutil.cpu_count("cores"))
+
+ @fewtimes_if_linux()
+ def test_cpu_count_sockets(self):
+ self.execute(lambda: psutil.cpu_count("sockets"))
+
+ @fewtimes_if_linux()
+ def test_cpu_count_numa(self):
+ self.execute(lambda: psutil.cpu_count("numa"))
@fewtimes_if_linux()
def test_cpu_times(self):
diff --git a/psutil/tests/test_osx.py b/psutil/tests/test_osx.py
index b7a0b088..a3d97c31 100755
--- a/psutil/tests/test_osx.py
+++ b/psutil/tests/test_osx.py
@@ -22,12 +22,10 @@ from psutil.tests import TOLERANCE_SYS_MEM
from psutil.tests import unittest
-def sysctl(cmdline):
- """Expects a sysctl command with an argument and parse the result
- returning only the value of interest.
- """
- out = sh(cmdline)
- result = out.split()[1]
+def sysctl(param):
+ """Expects a sysctl sub-command and return its stripped result."""
+ out = sh("sysctl " + param)
+ result = out.partition(' ')[2]
try:
return int(result)
except ValueError:
@@ -134,21 +132,25 @@ class TestSystemAPIs(PsutilTestCase):
# --- cpu
def test_cpu_count_logical(self):
- num = sysctl("sysctl hw.logicalcpu")
- self.assertEqual(num, psutil.cpu_count(logical=True))
+ num = sysctl("hw.logicalcpu")
+ self.assertEqual(num, psutil.cpu_count("logical"))
def test_cpu_count_cores(self):
- num = sysctl("sysctl hw.physicalcpu")
- self.assertEqual(num, psutil.cpu_count(logical=False))
+ num = sysctl("hw.physicalcpu")
+ self.assertEqual(num, psutil.cpu_count("cores"))
+
+ def test_cpu_count_sockets(self):
+ num = sysctl("hw.packages")
+ self.assertEqual(num, psutil.cpu_count("sockets"))
def test_cpu_freq(self):
freq = psutil.cpu_freq()
self.assertEqual(
- freq.current * 1000 * 1000, sysctl("sysctl hw.cpufrequency"))
+ freq.current * 1000 * 1000, sysctl("hw.cpufrequency"))
self.assertEqual(
- freq.min * 1000 * 1000, sysctl("sysctl hw.cpufrequency_min"))
+ freq.min * 1000 * 1000, sysctl("hw.cpufrequency_min"))
self.assertEqual(
- freq.max * 1000 * 1000, sysctl("sysctl hw.cpufrequency_max"))
+ freq.max * 1000 * 1000, sysctl("hw.cpufrequency_max"))
# --- virtual mem
diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py
index 4e3ac3e4..145d0ffe 100755
--- a/psutil/tests/test_system.py
+++ b/psutil/tests/test_system.py
@@ -16,6 +16,7 @@ import signal
import socket
import sys
import time
+import warnings
import psutil
from psutil import AIX
@@ -302,23 +303,69 @@ class TestMemoryAPIs(PsutilTestCase):
assert mem.sout >= 0, mem
-class TestCpuAPIs(PsutilTestCase):
-
- def test_cpu_count_logical(self):
- logical = psutil.cpu_count()
- self.assertIsNotNone(logical)
- self.assertEqual(logical, len(psutil.cpu_times(percpu=True)))
- self.assertGreaterEqual(logical, 1)
- #
- if os.path.exists("/proc/cpuinfo"):
- with open("/proc/cpuinfo") as fd:
- cpuinfo_data = fd.read()
- if "physical id" not in cpuinfo_data:
- raise unittest.SkipTest("cpuinfo doesn't include physical id")
-
- def test_cpu_count_cores(self):
+class TestCpuCount(PsutilTestCase):
+
+ def test_base(self):
+ kinds = ("logical", "cores", "sockets", "numa")
+ for kind in kinds:
+ n = psutil.cpu_count(kind=kind)
+ if n is not None:
+ self.assertIsInstance(n, int)
+ with self.subTest(kind):
+ self.assertGreaterEqual(n, 1)
+
+ self.assertEqual(psutil.cpu_count(), psutil.cpu_count("logical"))
+
+ with self.assertRaises(ValueError) as cm:
+ psutil.cpu_count(kind='xxx')
+ self.assertIn(str(kinds), str(cm.exception))
+
+ def test_consistency(self):
+ logical = psutil.cpu_count("logical")
+ cores = psutil.cpu_count("cores")
+ sockets = psutil.cpu_count("sockets")
+ numa = psutil.cpu_count(kind='numa')
+
+ # logical (always supposed to be the highest)
+ if logical is not None:
+ if cores is not None:
+ self.assertGreaterEqual(logical, cores)
+ if sockets is not None:
+ self.assertGreaterEqual(logical, sockets)
+
+ # cores (at least >= sockets)
+ if cores is not None:
+ if sockets is not None:
+ self.assertGreaterEqual(cores, sockets)
+
+ if numa is not None:
+ self.assertGreaterEqual(numa, 0)
+
+ def test_deprecation(self):
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ self.assertEqual(psutil.cpu_count(logical=True),
+ psutil.cpu_count(kind="logical"))
+ self.assertEqual(psutil.cpu_count(logical=False),
+ psutil.cpu_count(kind="cores"))
+ self.assertEqual(psutil.cpu_count(True),
+ psutil.cpu_count("logical"))
+ self.assertEqual(psutil.cpu_count(False),
+ psutil.cpu_count("cores"))
+
+ with warnings.catch_warnings(record=True) as ws:
+ warnings.simplefilter("always")
+ psutil.cpu_count(logical=True)
+ assert ws
+
+ with warnings.catch_warnings(record=True) as ws:
+ warnings.simplefilter("always")
+ psutil.cpu_count(True)
+ assert ws
+
+ def test_cores(self):
logical = psutil.cpu_count()
- cores = psutil.cpu_count(logical=False)
+ cores = psutil.cpu_count("cores")
if cores is None:
raise self.skipTest("cpu_count_cores() is None")
if WINDOWS and sys.getwindowsversion()[:2] <= (6, 1): # <= Vista
@@ -327,19 +374,18 @@ class TestCpuAPIs(PsutilTestCase):
self.assertGreaterEqual(cores, 1)
self.assertGreaterEqual(logical, cores)
- def test_cpu_count_none(self):
+ def test_return_none(self):
# https://github.com/giampaolo/psutil/issues/1085
for val in (-1, 0, None):
with mock.patch('psutil._psplatform.cpu_count_logical',
return_value=val) as m:
self.assertIsNone(psutil.cpu_count())
assert m.called
- with mock.patch('psutil._psplatform.cpu_count_cores',
- return_value=val) as m:
- self.assertIsNone(psutil.cpu_count(logical=False))
- assert m.called
- def test_cpu_times(self):
+
+class TestCpuTimes(PsutilTestCase):
+
+ def test_base(self):
# Check type, value >= 0, str().
total = 0
times = psutil.cpu_times()
@@ -368,7 +414,7 @@ class TestCpuAPIs(PsutilTestCase):
# msg="%s %s" % (new_t, last_t))
# last = new
- def test_cpu_times_time_increases(self):
+ def test_time_increases(self):
# Make sure time increases between calls.
t1 = sum(psutil.cpu_times())
stop_at = time.time() + GLOBAL_TIMEOUT
@@ -436,6 +482,9 @@ class TestCpuAPIs(PsutilTestCase):
self.assertAlmostEqual(
getattr(base, field), getattr(summed_values, field), delta=1)
+
+class TestCpuPercent(PsutilTestCase):
+
def _test_cpu_percent(self, percent, last_ret, new_ret):
try:
self.assertIsInstance(percent, float)
@@ -498,6 +547,9 @@ class TestCpuAPIs(PsutilTestCase):
for percent in cpu:
self._test_cpu_percent(percent, None, None)
+
+class TestOtherCPUFunctions(PsutilTestCase):
+
def test_cpu_stats(self):
# Tested more extensively in per-platform test modules.
infos = psutil.cpu_stats()
diff --git a/psutil/tests/test_windows.py b/psutil/tests/test_windows.py
index aeb282c8..815771bf 100755
--- a/psutil/tests/test_windows.py
+++ b/psutil/tests/test_windows.py
@@ -82,28 +82,29 @@ class TestCpuAPIs(WindowsTestCase):
@unittest.skipIf('NUMBER_OF_PROCESSORS' not in os.environ,
'NUMBER_OF_PROCESSORS env var is not available')
- def test_cpu_count_vs_NUMBER_OF_PROCESSORS(self):
+ def test_cpu_count_logical_vs_NUMBER_OF_PROCESSORS(self):
# Will likely fail on many-cores systems:
# https://stackoverflow.com/questions/31209256
num_cpus = int(os.environ['NUMBER_OF_PROCESSORS'])
- self.assertEqual(num_cpus, psutil.cpu_count())
+ self.assertEqual(num_cpus, psutil.cpu_count("logical"))
- def test_cpu_count_vs_GetSystemInfo(self):
+ def test_cpu_count_logical_vs_GetSystemInfo(self):
# Will likely fail on many-cores systems:
# https://stackoverflow.com/questions/31209256
sys_value = win32api.GetSystemInfo()[5]
- psutil_value = psutil.cpu_count()
+ psutil_value = psutil.cpu_count("logical")
self.assertEqual(sys_value, psutil_value)
def test_cpu_count_logical_vs_wmi(self):
w = wmi.WMI()
proc = w.Win32_Processor()[0]
- self.assertEqual(psutil.cpu_count(), proc.NumberOfLogicalProcessors)
+ self.assertEqual(psutil.cpu_count("logical"),
+ proc.NumberOfLogicalProcessors)
def test_cpu_count_cores_vs_wmi(self):
w = wmi.WMI()
proc = w.Win32_Processor()[0]
- self.assertEqual(psutil.cpu_count(logical=False), proc.NumberOfCores)
+ self.assertEqual(psutil.cpu_count("cores"), proc.NumberOfCores)
def test_cpu_count_vs_cpu_times(self):
self.assertEqual(psutil.cpu_count(),
@@ -725,7 +726,7 @@ class RemoteProcessTestCase(PsutilTestCase):
p = psutil.Process(self.proc32.pid)
e = p.environ()
self.assertIn("THINK_OF_A_NUMBER", e)
- self.assertEquals(e["THINK_OF_A_NUMBER"], str(os.getpid()))
+ self.assertEqual(e["THINK_OF_A_NUMBER"], str(os.getpid()))
def test_environ_64(self):
p = psutil.Process(self.proc64.pid)