diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2016-02-02 07:01:12 +0000 |
---|---|---|
committer | Giampaolo Rodola <g.rodola@gmail.com> | 2016-02-02 07:01:12 +0000 |
commit | 9c879e52948e1105e0a9a90854792198be636ebf (patch) | |
tree | 7a9991b0c2983563884303b89777bdb50d55e7d5 | |
parent | e5dd8b6817e344bf04b7b3e2333bbeb562fc7ac6 (diff) | |
parent | cbfe54481327639689587699bd23882cee0ca0f4 (diff) | |
download | psutil-9c879e52948e1105e0a9a90854792198be636ebf.tar.gz |
Merge branch 'master' of github.com:giampaolo/psutil
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | HISTORY.rst | 7 | ||||
-rw-r--r-- | IDEAS | 7 | ||||
-rw-r--r-- | INSTALL.rst | 15 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README.rst | 2 | ||||
-rw-r--r-- | docs/index.rst | 30 | ||||
-rw-r--r-- | psutil/__init__.py | 16 | ||||
-rw-r--r-- | psutil/_common.py | 3 | ||||
-rw-r--r-- | psutil/_psbsd.py | 14 | ||||
-rw-r--r-- | psutil/_pslinux.py | 15 | ||||
-rw-r--r-- | psutil/_psosx.py | 3 | ||||
-rw-r--r-- | psutil/_pssunos.py | 6 | ||||
-rw-r--r-- | psutil/_psutil_bsd.c | 11 | ||||
-rw-r--r-- | psutil/_psutil_osx.c | 13 | ||||
-rw-r--r-- | psutil/_psutil_sunos.c | 10 | ||||
-rw-r--r-- | psutil/_pswindows.py | 7 | ||||
-rw-r--r-- | psutil/tests/__init__.py | 9 | ||||
-rw-r--r-- | psutil/tests/test_bsd.py | 41 | ||||
-rw-r--r-- | psutil/tests/test_linux.py | 65 | ||||
-rw-r--r-- | psutil/tests/test_process.py | 16 | ||||
-rw-r--r-- | psutil/tests/test_system.py | 21 |
22 files changed, 246 insertions, 68 deletions
diff --git a/.travis.yml b/.travis.yml index 03f19132..17206c58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ matrix: - python: 3.3 - python: 3.4 - python: 3.5 + - "pypy" # XXX - commented because OSX builds are deadly slow # - language: generic # os: osx diff --git a/HISTORY.rst b/HISTORY.rst index 5ba233b8..b8bdec10 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,6 +7,8 @@ Bug tracker at https://github.com/giampaolo/psutil/issues - #777: [Linux] Process.open_files() on Linux return 3 new fields: position, mode and flags. +- #779: Process.cpu_times() returns two new fields, 'children_user' and + 'children_system' (always set to 0 on OSX and Windows). **Bug fixes** @@ -14,6 +16,9 @@ Bug tracker at https://github.com/giampaolo/psutil/issues provides it. - #776: [Linux] Process.cpu_affinity() may erroneously raise NoSuchProcess. (patch by wxwright) +- #780: [OSX] psutil does not compile with some gcc versions. +- #786: net_if_addrs() may report incomplete MAC addresses. +- #788: [NetBSD] virtual_memory()'s buffers and shared values were set to 0. 4.0.0 - 2016-02-17 @@ -36,6 +41,8 @@ Bug tracker at https://github.com/giampaolo/psutil/issues **Bug fixes** +- #685: [Linux] virtual_memory() provides wrong results on systems with a lot + of physical memory. - #704: [Solaris] psutil does not compile on Solaris sparc. - #734: on Python 3 invalid UTF-8 data is not correctly handled for process name(), cwd(), exe(), cmdline() and open_files() methods resulting in @@ -17,9 +17,9 @@ PLATFORMS FEATURES ======== -- #782: (UNIX) process num of signals received. +- (UNIX) process root (different from cwd) -- (UNIX) process root (different from xwd) +- #782: (UNIX) process num of signals received. - (Linux) locked files via /proc/locks: https://www.centos.org/docs/5/html/5.2/Deployment_Guide/s2-proc-locks.html @@ -144,5 +144,6 @@ FEATURES SIMILAR PROJECTS ================ -- https://github.com/hyperic/sigar (Java) +- sigar: https://github.com/hyperic/sigar (Java) - zabbix source code: https://zabbix.org/wiki/Get_Zabbix +- libstatgrab: http://www.i-scream.org/libstatgrab/ diff --git a/INSTALL.rst b/INSTALL.rst index fdbc4d6d..2a98e193 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -69,13 +69,16 @@ Once done, you can build/install psutil with:: $ python setup.py install -================== -Installing on OS X -================== +================= +Installing on OSX +================= -OS X installation from source will require gcc which you can obtain as part of -the 'XcodeTools' installer from Apple. Then you can run the standard distutils -commands. +OSX installation from source will require gcc which you can obtain as part of +the 'XcodeTools' installer from Apple: + +https://developer.apple.com/downloads/?name=Xcode + +Once you have installed XCode you can run the standard distutils commands. To build only:: $ python setup.py build @@ -82,7 +82,7 @@ test-by-name: install # Run specific platform tests only. test-platform: install - $(PYTHON) psutil/tests/test_`$(PYTHON) -c 'import psutil; print([x.lower() for x in ("FREEBSD", "LINUX", "NETBSD", "OPENBSD", "OSX", "SUNOS", "WINDOWS") if getattr(psutil, x)][0])'`.py + $(PYTHON) psutil/tests/test_`$(PYTHON) -c 'import psutil; print([x.lower() for x in ("LINUX", "BSD", "OSX", "SUNOS", "WINDOWS") if getattr(psutil, x)][0])'`.py # Same as above but for test_memory_leaks.py script. test-memleaks-by-name: install @@ -226,7 +226,7 @@ Process management pgids(real=1000, effective=1000, saved=1000) >>> >>> p.cpu_times() - pcputimes(user=1.02, system=0.31) + pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1) >>> p.cpu_percent(interval=1.0) 12.1 >>> p.cpu_affinity() diff --git a/docs/index.rst b/docs/index.rst index b6cf4d91..c9066493 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -266,16 +266,22 @@ Disks .. function:: disk_io_counters(perdisk=False) Return system-wide disk I/O statistics as a namedtuple including the - following fields. + following fields: + - **read_count**: number of reads - **write_count**: number of writes - **read_bytes**: number of bytes read - **write_bytes**: number of bytes written - - **read_time**: (all except NetBSD and OpenBSD) time spent reading from disk (in milliseconds) - - **write_time**: (all except NetBSD and OpenBSD) time spent writing to disk (in milliseconds) - - **busy_time**: (Linux, FreeBSD) time spent doing actual I/Os (in milliseconds) - - **read_merged_count** (Linux): number of merged reads (see `iostat doc <https://www.kernel.org/doc/Documentation/iostats.txt>`__) - - **write_merged_count** (Linux): number of merged writes (see `iostats doc <https://www.kernel.org/doc/Documentation/iostats.txt>`__) + - **read_time**: (all except NetBSD and OpenBSD) time spent reading from + disk (in milliseconds) + - **write_time**: (all except NetBSD and OpenBSD) time spent writing to disk + (in milliseconds) + - **busy_time**: (Linux, FreeBSD) time spent doing actual I/Os (in + milliseconds) + - **read_merged_count** (Linux): number of merged reads + (see `iostat doc <https://www.kernel.org/doc/Documentation/iostats.txt>`__) + - **write_merged_count** (Linux): number of merged writes + (see `iostats doc <https://www.kernel.org/doc/Documentation/iostats.txt>`__) If *perdisk* is ``True`` return the same information for every physical disk installed on the system as a dictionary with partition names as the keys and @@ -915,14 +921,18 @@ Process class .. method:: cpu_times() - Return a tuple whose values are process CPU **user** and **system** - times which means the amount of time expressed in seconds that a process - has spent in - `user / system mode <http://stackoverflow.com/questions/556405/what-do-real-user-and-sys-mean-in-the-output-of-time1>`__. + Return a `(user, system, children_user, children_system)` namedtuple + representing the accumulated process time, in seconds (see + `explanation <http://stackoverflow.com/questions/556405/>`__). + On Windows and OSX only *user* and *system* are filled, the others are + set to ``0``. This is similar to `os.times() <http://docs.python.org//library/os.html#os.times>`__ but can be used for any process PID. + .. versionchanged:: 4.1.0 return two extra fields: *children_user* and + *children_system*. + .. method:: cpu_percent(interval=None) Return a float representing the process CPU utilization as a percentage. diff --git a/psutil/__init__.py b/psutil/__init__.py index 8594e4b9..256783d9 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -960,9 +960,12 @@ class Process(object): return round(overall_percent, 1) def cpu_times(self): - """Return a (user, system) namedtuple representing the - accumulated process time, in seconds. - This is the same as os.times() but per-process. + """Return a (user, system, children_user, children_system) + namedtuple representing the accumulated process time, in + seconds. + This is similar to os.times() but per-process. + On OSX and Windows children_user and children_system are + always set to 0. """ return self._proc.cpu_times() @@ -1911,6 +1914,13 @@ def net_if_addrs(): # We re-set the family here so that repr(family) # will show AF_LINK rather than AF_PACKET fam = _psplatform.AF_LINK + if fam == _psplatform.AF_LINK: + # The underlying C function may return an incomplete MAC + # address in which case we fill it with null bytes, see: + # https://github.com/giampaolo/psutil/issues/786 + separator = ":" if POSIX else "-" + while addr.count(separator) < 5: + addr += "%s00" % separator ret[name].append(_common.snic(fam, addr, mask, broadcast, ptp)) return dict(ret) diff --git a/psutil/_common.py b/psutil/_common.py index 51cc1a2c..b146c736 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -311,7 +311,8 @@ snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu']) # --- namedtuples for psutil.Process methods # psutil.Process.cpu_times() -pcputimes = namedtuple('pcputimes', ['user', 'system']) +pcputimes = namedtuple('pcputimes', + ['user', 'system', 'children_user', 'children_system']) # psutil.Process.open_files() popenfile = namedtuple('popenfile', ['path', 'fd']) # psutil.Process.threads() diff --git a/psutil/_psbsd.py b/psutil/_psbsd.py index b43e052a..4af3bc8e 100644 --- a/psutil/_psbsd.py +++ b/psutil/_psbsd.py @@ -100,6 +100,8 @@ scputimes = namedtuple( 'scputimes', ['user', 'nice', 'system', 'idle', 'irq']) pmem = namedtuple('pmem', ['rss', 'vms', 'text', 'data', 'stack']) pfullmem = pmem +pcputimes = namedtuple('pcputimes', + ['user', 'system', 'children_user', 'children_system']) pmmap_grouped = namedtuple( 'pmmap_grouped', 'path rss, private, ref_count, shadow_count') pmmap_ext = namedtuple( @@ -124,6 +126,15 @@ def virtual_memory(): """System virtual memory as a namedtuple.""" mem = cext.virtual_mem() total, free, active, inactive, wired, cached, buffers, shared = mem + if NETBSD: + # On NetBSD buffers and shared mem is determined via /proc. + # The C ext set them to 0. + with open('/proc/meminfo', 'rb') as f: + for line in f: + if line.startswith("Buffers:"): + buffers = int(line.split()[1]) * 1024 + elif line.startswith("MemShared:"): + shared = int(line.split()[1]) * 1024 avail = inactive + cached + free used = active + wired + cached percent = usage_percent((total - avail), total, _round=1) @@ -436,8 +447,7 @@ class Process(object): @wrap_exceptions def cpu_times(self): - user, system = cext.proc_cpu_times(self.pid) - return _common.pcputimes(user, system) + return _common.pcputimes(*cext.proc_cpu_times(self.pid)) @wrap_exceptions def memory_info(self): diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index 324ff5cb..0b996e70 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -180,13 +180,13 @@ def readlink(path): def file_flags_to_mode(flags): - md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'} - m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)] + modes_map = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'} + mode = modes_map[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)] if flags & os.O_APPEND: - m = m.replace('w', 'a', 1) - m = m.replace('w+', 'r+') + mode = mode.replace('w', 'a', 1) + mode = mode.replace('w+', 'r+') # possible values: r, w, a, r+, a+ - return m + return mode def get_sector_size(): @@ -251,7 +251,6 @@ popenfile = namedtuple('popenfile', ['path', 'fd', 'position', 'mode', 'flags']) pmem = namedtuple('pmem', 'rss vms shared text lib data dirty') pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', 'pss', 'swap')) - pmmap_grouped = namedtuple( 'pmmap_grouped', ['path', 'rss', 'size', 'pss', 'shared_clean', 'shared_dirty', 'private_clean', 'private_dirty', @@ -989,7 +988,9 @@ class Process(object): values = st.split(b' ') utime = float(values[11]) / CLOCK_TICKS stime = float(values[12]) / CLOCK_TICKS - return _common.pcputimes(utime, stime) + children_utime = float(values[13]) / CLOCK_TICKS + children_stime = float(values[14]) / CLOCK_TICKS + return _common.pcputimes(utime, stime, children_utime, children_stime) @wrap_exceptions def wait(self, timeout=None): diff --git a/psutil/_psosx.py b/psutil/_psosx.py index 5f39589c..b8066775 100644 --- a/psutil/_psosx.py +++ b/psutil/_psosx.py @@ -282,7 +282,8 @@ class Process(object): @wrap_exceptions def cpu_times(self): user, system = cext.proc_cpu_times(self.pid) - return _common.pcputimes(user, system) + # Children user/system times are not retrievable (set to 0). + return _common.pcputimes(user, system, 0, 0) @wrap_exceptions def create_time(self): diff --git a/psutil/_pssunos.py b/psutil/_pssunos.py index c0d44b12..06da5aab 100644 --- a/psutil/_pssunos.py +++ b/psutil/_pssunos.py @@ -59,6 +59,8 @@ TCP_STATUSES = { } scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait']) +pcputimes = namedtuple('pcputimes', + ['user', 'system', 'children_user', 'children_system']) svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free']) pmem = namedtuple('pmem', ['rss', 'vms']) pfullmem = pmem @@ -364,8 +366,8 @@ class Process(object): @wrap_exceptions def cpu_times(self): - user, system = cext.proc_cpu_times(self.pid, self._procfs_path) - return _common.pcputimes(user, system) + times = cext.proc_cpu_times(self.pid, self._procfs_path) + return _common.pcputimes(*times) @wrap_exceptions def terminal(self): diff --git a/psutil/_psutil_bsd.c b/psutil/_psutil_bsd.c index db05dc8e..31511abb 100644 --- a/psutil/_psutil_bsd.c +++ b/psutil/_psutil_bsd.c @@ -368,7 +368,7 @@ psutil_proc_num_ctx_switches(PyObject *self, PyObject *args) { static PyObject * psutil_proc_cpu_times(PyObject *self, PyObject *args) { long pid; - double user_t, sys_t; + double user_t, sys_t, children_user_t, children_sys_t; kinfo_proc kp; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; @@ -378,11 +378,18 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) { #ifdef __FreeBSD__ user_t = PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_utime); sys_t = PSUTIL_TV2DOUBLE(kp.ki_rusage.ru_stime); + children_user_t = PSUTIL_TV2DOUBLE(kp.ki_rusage_ch.ru_utime); + children_sys_t = PSUTIL_TV2DOUBLE(kp.ki_rusage_ch.ru_stime); #elif defined(__OpenBSD__) || defined(__NetBSD__) user_t = PSUTIL_KPT2DOUBLE(kp.p_uutime); sys_t = PSUTIL_KPT2DOUBLE(kp.p_ustime); + // OpenBSD and NetBSD provide children user + system times summed + // together (no distinction). + children_user_t = kp.p_uctime_sec + kp.p_uctime_usec / 1000000.0; + children_sys_t = children_user_t; #endif - return Py_BuildValue("(dd)", user_t, sys_t); + return Py_BuildValue("(dddd)", + user_t, sys_t, children_user_t, children_sys_t); } diff --git a/psutil/_psutil_osx.c b/psutil/_psutil_osx.c index f76ca0e6..e9a898ac 100644 --- a/psutil/_psutil_osx.c +++ b/psutil/_psutil_osx.c @@ -581,11 +581,14 @@ psutil_proc_memory_uss(PyObject *self, PyObject *args) { mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT; kern_return_t kr; vm_size_t page_size; + mach_vm_address_t addr = MACH_VM_MIN_ADDRESS; + mach_port_t task = MACH_PORT_NULL; + vm_region_top_info_data_t info; + mach_port_t object_name; if (! PyArg_ParseTuple(args, "l", &pid)) return NULL; - mach_port_t task = MACH_PORT_NULL; err = task_for_pid(mach_task_self(), pid, &task); if (err != KERN_SUCCESS) { psutil_raise_ad_or_nsp(pid); @@ -600,10 +603,7 @@ psutil_proc_memory_uss(PyObject *self, PyObject *args) { // Roughly based on libtop_update_vm_regions in // http://www.opensource.apple.com/source/top/top-100.1.2/libtop.c - for (mach_vm_address_t addr = MACH_VM_MIN_ADDRESS; ; addr += size) { - vm_region_top_info_data_t info; - mach_port_t object_name; - + for (addr = 0; ; addr += size) { kr = mach_vm_region( task, &addr, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, &info_count, &object_name); @@ -612,7 +612,8 @@ psutil_proc_memory_uss(PyObject *self, PyObject *args) { break; } else if (kr != KERN_SUCCESS) { - return false; + PyErr_Format(PyExc_RuntimeError, "mach_vm_region() failed"); + return NULL; } if (psutil_in_shared_region(addr, cpu_type) && diff --git a/psutil/_psutil_sunos.c b/psutil/_psutil_sunos.c index 7ffee306..9a7067d3 100644 --- a/psutil/_psutil_sunos.c +++ b/psutil/_psutil_sunos.c @@ -159,9 +159,13 @@ psutil_proc_cpu_times(PyObject *self, PyObject *args) { if (! psutil_file_to_struct(path, (void *)&info, sizeof(info))) return NULL; // results are more precise than os.times() - return Py_BuildValue("dd", - PSUTIL_TV2DOUBLE(info.pr_utime), - PSUTIL_TV2DOUBLE(info.pr_stime)); + return Py_BuildValue( + "(dddd)", + PSUTIL_TV2DOUBLE(info.pr_utime), + PSUTIL_TV2DOUBLE(info.pr_stime), + PSUTIL_TV2DOUBLE(info.pr_cutime), + PSUTIL_TV2DOUBLE(info.pr_cstime) + ); } diff --git a/psutil/_pswindows.py b/psutil/_pswindows.py index 92472576..25ed2a59 100644 --- a/psutil/_pswindows.py +++ b/psutil/_pswindows.py @@ -448,14 +448,15 @@ class Process(object): @wrap_exceptions def cpu_times(self): try: - ret = cext.proc_cpu_times(self.pid) + user, system = cext.proc_cpu_times(self.pid) except OSError as err: if err.errno in ACCESS_DENIED_SET: nt = ntpinfo(*cext.proc_info(self.pid)) - ret = (nt.user_time, nt.kernel_time) + user, system = (nt.user_time, nt.kernel_time) else: raise - return _common.pcputimes(*ret) + # Children user/system times are not retrievable (set to 0). + return _common.pcputimes(user, system, 0, 0) @wrap_exceptions def suspend(self): diff --git a/psutil/tests/__init__.py b/psutil/tests/__init__.py index 7ff5133f..1db2369b 100644 --- a/psutil/tests/__init__.py +++ b/psutil/tests/__init__.py @@ -82,6 +82,7 @@ TESTFN = os.path.join(os.getcwd(), "$testfile") TESTFN_UNICODE = TESTFN + "ƒőő" TESTFILE_PREFIX = 'psutil-test-suite-' TOX = os.getenv('TOX') or '' in ('1', 'true') +PYPY = '__pypy__' in sys.builtin_module_names if not PY3: try: TESTFN_UNICODE = unicode(TESTFN_UNICODE, sys.getfilesystemencoding()) @@ -344,8 +345,10 @@ def reap_children(search_all=False): _subprocesses_started = set(alive) -def check_ip_address(addr, family): - """Attempts to check IP address's validity.""" +def check_net_address(addr, family): + """Check a net address validity. Supported families are IPv4, + IPv6 and MAC addresses. + """ if enum and PY3: assert isinstance(family, enum.IntEnum), family if family == AF_INET: @@ -392,7 +395,7 @@ def check_connection_ntuple(conn): ip, port = addr assert isinstance(port, int), port assert 0 <= port <= 65535, port - check_ip_address(ip, conn.family) + check_net_address(ip, conn.family) elif conn.family == AF_UNIX: assert isinstance(addr, (str, None)), addr else: diff --git a/psutil/tests/test_bsd.py b/psutil/tests/test_bsd.py index b77640cf..6d2749ae 100644 --- a/psutil/tests/test_bsd.py +++ b/psutil/tests/test_bsd.py @@ -286,7 +286,6 @@ class FreeBSDSpecificTestCase(unittest.TestCase): # --- OpenBSD # ===================================================================== - @unittest.skipUnless(OPENBSD, "not an OpenBSD system") class OpenBSDSpecificTestCase(unittest.TestCase): @@ -297,5 +296,45 @@ class OpenBSDSpecificTestCase(unittest.TestCase): self.assertEqual(sys_bt, psutil_bt) +# ===================================================================== +# --- NetBSD +# ===================================================================== + +@unittest.skipUnless(NETBSD, "not a NetBSD system") +class NetBSDSpecificTestCase(unittest.TestCase): + + def parse_meminfo(self, look_for): + with open('/proc/meminfo', 'rb') as f: + for line in f: + if line.startswith(look_for): + return int(line.split()[1]) * 1024 + raise ValueError("can't find %s" % look_for) + + # XXX - failing tests + + # def test_vmem_total(self): + # self.assertEqual( + # psutil.virtual_memory().total, self.parse_meminfo("MemTotal:")) + + # def test_vmem_free(self): + # self.assertEqual( + # psutil.virtual_memory().buffers, self.parse_meminfo("MemFree:")) + + def test_vmem_buffers(self): + self.assertEqual( + psutil.virtual_memory().buffers, self.parse_meminfo("Buffers:")) + + def test_vmem_shared(self): + self.assertEqual( + psutil.virtual_memory().shared, self.parse_meminfo("MemShared:")) + + def test_swapmem_total(self): + self.assertEqual( + psutil.swap_memory().total, self.parse_meminfo("SwapTotal:")) + + def test_swapmem_free(self): + self.assertEqual( + psutil.swap_memory().free, self.parse_meminfo("SwapFree:")) + if __name__ == '__main__': run_test_module_by_name(__file__) diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py index a9545991..baab1228 100644 --- a/psutil/tests/test_linux.py +++ b/psutil/tests/test_linux.py @@ -33,6 +33,7 @@ from psutil.tests import call_until from psutil.tests import get_kernel_version from psutil.tests import importlib from psutil.tests import MEMORY_TOLERANCE +from psutil.tests import PYPY from psutil.tests import pyrun from psutil.tests import reap_children from psutil.tests import retry_before_failing @@ -332,6 +333,53 @@ class TestSystemNetwork(unittest.TestCase): self.assertEqual(addr.address, get_ipv4_address(name)) # TODO: test for AF_INET6 family + def test_net_if_stats(self): + for name, stats in psutil.net_if_stats().items(): + try: + out = sh("ifconfig %s" % name) + except RuntimeError: + pass + else: + self.assertEqual(stats.isup, 'RUNNING' in out) + self.assertEqual(stats.mtu, + int(re.findall('MTU:(\d+)', out)[0])) + + def test_net_io_counters(self): + def ifconfig(nic): + ret = {} + out = sh("ifconfig %s" % name) + ret['packets_recv'] = int(re.findall('RX packets:(\d+)', out)[0]) + ret['packets_sent'] = int(re.findall('TX packets:(\d+)', out)[0]) + ret['errin'] = int(re.findall('errors:(\d+)', out)[0]) + ret['errout'] = int(re.findall('errors:(\d+)', out)[1]) + ret['dropin'] = int(re.findall('dropped:(\d+)', out)[0]) + ret['dropout'] = int(re.findall('dropped:(\d+)', out)[1]) + ret['bytes_recv'] = int(re.findall('RX bytes:(\d+)', out)[0]) + ret['bytes_sent'] = int(re.findall('TX bytes:(\d+)', out)[0]) + return ret + + for name, stats in psutil.net_io_counters(pernic=True).items(): + try: + ifconfig_ret = ifconfig(name) + except RuntimeError: + continue + self.assertAlmostEqual( + stats.bytes_recv, ifconfig_ret['bytes_recv'], delta=1024) + self.assertAlmostEqual( + stats.bytes_sent, ifconfig_ret['bytes_sent'], delta=1024) + self.assertAlmostEqual( + stats.packets_recv, ifconfig_ret['packets_recv'], delta=512) + self.assertAlmostEqual( + stats.packets_sent, ifconfig_ret['packets_sent'], delta=512) + self.assertAlmostEqual( + stats.errin, ifconfig_ret['errin'], delta=10) + self.assertAlmostEqual( + stats.errout, ifconfig_ret['errout'], delta=10) + self.assertAlmostEqual( + stats.dropin, ifconfig_ret['dropin'], delta=10) + self.assertAlmostEqual( + stats.dropout, ifconfig_ret['dropout'], delta=10) + @unittest.skipUnless(which('ip'), "'ip' utility not available") @unittest.skipIf(TRAVIS, "skipped on Travis") def test_net_if_names(self): @@ -764,13 +812,16 @@ class TestProcess(unittest.TestCase): time.sleep(.1) mem = p.memory_full_info() maps = p.memory_maps(grouped=False) - self.assertEqual( - mem.uss, sum([x.private_dirty + x.private_clean for x in maps])) - self.assertEqual( - mem.pss, sum([x.pss for x in maps])) - self.assertEqual( - mem.swap, sum([x.swap for x in maps])) - + self.assertAlmostEqual( + mem.uss, sum([x.private_dirty + x.private_clean for x in maps]), + delta=4096) + self.assertAlmostEqual( + mem.pss, sum([x.pss for x in maps]), delta=4096) + self.assertAlmostEqual( + mem.swap, sum([x.swap for x in maps]), delta=4096) + + # On PYPY file descriptors are not closed fast enough. + @unittest.skipIf(PYPY, "skipped on PYPY") def test_open_files_mode(self): def get_test_file(): p = psutil.Process() diff --git a/psutil/tests/test_process.py b/psutil/tests/test_process.py index c556caf0..79d28b19 100644 --- a/psutil/tests/test_process.py +++ b/psutil/tests/test_process.py @@ -65,6 +65,7 @@ from psutil.tests import get_test_subprocess from psutil.tests import get_winver from psutil.tests import GLOBAL_TIMEOUT from psutil.tests import pyrun +from psutil.tests import PYPY from psutil.tests import PYTHON from psutil.tests import reap_children from psutil.tests import retry_before_failing @@ -267,9 +268,11 @@ class TestProcess(unittest.TestCase): def test_cpu_times(self): times = psutil.Process().cpu_times() assert (times.user > 0.0) or (times.system > 0.0), times + assert (times.children_user >= 0.0), times + assert (times.children_system >= 0.0), times # make sure returned values can be pretty printed with strftime - time.strftime("%H:%M:%S", time.localtime(times.user)) - time.strftime("%H:%M:%S", time.localtime(times.system)) + for name in times._fields: + time.strftime("%H:%M:%S", time.localtime(getattr(times, name))) # Test Process.cpu_times() against os.times() # os.times() is broken on Python 2.6 @@ -279,8 +282,8 @@ class TestProcess(unittest.TestCase): @unittest.skipUnless(sys.version_info > (2, 6, 1) and not OSX, 'os.times() is not reliable on this Python version') - def test_cpu_times2(self): - user_time, kernel_time = psutil.Process().cpu_times() + def test_cpu_times_2(self): + user_time, kernel_time = psutil.Process().cpu_times()[:2] utime, ktime = os.times()[:2] # Use os.times()[:2] as base values to compare our results @@ -423,6 +426,11 @@ class TestProcess(unittest.TestCase): self.assertGreaterEqual(value, 0) if name in dir(resource): self.assertEqual(value, getattr(resource, name)) + # XXX - On PyPy RLIMIT_INFINITY returned by + # resource.getrlimit() is reported as a very big long + # number instead of -1. It looks like a bug with PyPy. + if PYPY: + continue self.assertEqual(p.rlimit(value), resource.getrlimit(value)) else: ret = p.rlimit(value) diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index 4f73e181..4cbba7f8 100644 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -31,7 +31,7 @@ from psutil import WINDOWS from psutil._compat import long from psutil.tests import AF_INET6 from psutil.tests import APPVEYOR -from psutil.tests import check_ip_address +from psutil.tests import check_net_address from psutil.tests import DEVNULL from psutil.tests import enum from psutil.tests import get_test_subprocess @@ -568,7 +568,7 @@ class TestSystemAPIs(unittest.TestCase): # AddressValueError: Only hex digits permitted in # u'c6f3%lxcbr0' in u'fe80::c8e0:fff:fe54:c6f3%lxcbr0' if addr.family != AF_INET6: - check_ip_address(ip, addr.family) + check_net_address(ip, addr.family) # broadcast and ptp addresses are mutually exclusive if addr.broadcast: self.assertIsNone(addr.ptp) @@ -583,6 +583,23 @@ class TestSystemAPIs(unittest.TestCase): elif WINDOWS: self.assertEqual(psutil.AF_LINK, -1) + def test_net_if_addrs_mac_null_bytes(self): + # Simulate that the underlying C function returns an incomplete + # MAC address. psutil is supposed to fill it with null bytes. + # https://github.com/giampaolo/psutil/issues/786 + if POSIX: + ret = [('em1', psutil.AF_LINK, '06:3d:29', None, None, None)] + else: + ret = [('em1', -1, '06-3d-29', None, None, None)] + with mock.patch('psutil._psplatform.net_if_addrs', + return_value=ret) as m: + addr = psutil.net_if_addrs()['em1'][0] + assert m.called + if POSIX: + self.assertEqual(addr.address, '06:3d:29:00:00:00') + else: + self.assertEqual(addr.address, '06-3d-29-00-00-00') + @unittest.skipIf(TRAVIS, "EPERM on travis") def test_net_if_stats(self): nics = psutil.net_if_stats() |