Bug 1116194 - Catch errors calling psutil; r=ted

The build system / mach currently has a very hacky virtualenv setup.
Essentially, it resorts to sys.path munging instead of a proper,
isolated environment.

During initialization, mach installs python/psutil in sys.path. Later
on, some code does an |import psutil|. This fails iff the psutil C
extension can't be found.

If there is a psutil C extension installed outside of mach and
python/psutil, |import psutil| may load it. The version mismatch isn't
detected until an extension-using psutil API is called. This has
manifested inside |mach build| via the resource monitor as an
|AttributeError: 'module' object has no attribute 'linux_sysinfo'|
exception during psutil.virtual_memory().

The proper fix for this is for the Python environment to ensure the
psutil C extension is built before attempting to import and use psutil.
Arguably, psutil itself should perform some kind of version check when
it imports the C extension to ensure things are in sync and fail at
import time.

Fixing mach and the build system Python environment to build psutil
earlier/properly is a long outstanding bug. It needs to be addressed.
But it is considerable effort. This patch continues the long history of
wallpapering over psutil import/run failures because using a proper
virutalenv from mach/build system is a lot of work. Sad panda.
This commit is contained in:
Gregory Szorc
2014-12-29 12:06:21 -08:00
parent bea5ae84f9
commit 31fedb1702

View File

@@ -5,6 +5,7 @@
import multiprocessing
import sys
import time
import warnings
# psutil will raise NotImplementedError if the platform is not supported.
try:
@@ -178,15 +179,26 @@ class SystemResourceMonitor(object):
self._running = False
self._stopped = False
self._process = None
if psutil is None:
return
# This try..except should not be needed! However, some tools (like
# |mach build|) attempt to load psutil before properly creating a
# virtualenv by building psutil. As a result, python/psutil may be in
# sys.path and its .py files may pick up the psutil C extension from
# the system install. If the versions don't match, we typically see
# failures invoking one of these functions.
try:
cpu_percent = psutil.cpu_percent(0.0, True)
cpu_times = psutil.cpu_times(False)
io = get_disk_io_counters()
virt = psutil.virtual_memory()
swap = psutil.swap_memory()
except Exception as e:
warnings.warn('psutil failed to run: %s' % e)
return
self._cpu_cores = len(cpu_percent)
self._cpu_times_type = type(cpu_times)
@@ -215,7 +227,7 @@ class SystemResourceMonitor(object):
You should only call this once per instance.
"""
if psutil is None:
if not self._process:
return
self._running = True
@@ -229,7 +241,7 @@ class SystemResourceMonitor(object):
Currently, data is not available until you call stop().
"""
if psutil is None:
if not self._process:
self._stopped = True
return