690 lines
26 KiB
Python
690 lines
26 KiB
Python
|
import json
|
||
|
import locale
|
||
|
import multiprocessing
|
||
|
import os
|
||
|
import platform
|
||
|
import textwrap
|
||
|
import sys
|
||
|
from contextlib import redirect_stdout
|
||
|
from datetime import datetime
|
||
|
from io import StringIO
|
||
|
from subprocess import check_output, PIPE, CalledProcessError
|
||
|
import numpy as np
|
||
|
import llvmlite.binding as llvmbind
|
||
|
from llvmlite import __version__ as llvmlite_version
|
||
|
from numba import cuda as cu, __version__ as version_number
|
||
|
from numba.cuda import cudadrv
|
||
|
from numba.cuda.cudadrv.driver import driver as cudriver
|
||
|
from numba.cuda.cudadrv.runtime import runtime as curuntime
|
||
|
from numba.core import config
|
||
|
|
||
|
_psutil_import = False
|
||
|
try:
|
||
|
import psutil
|
||
|
except ImportError:
|
||
|
pass
|
||
|
else:
|
||
|
_psutil_import = True
|
||
|
|
||
|
__all__ = ['get_sysinfo', 'display_sysinfo']
|
||
|
|
||
|
# Keys of a `sysinfo` dictionary
|
||
|
|
||
|
# Time info
|
||
|
_start, _start_utc, _runtime = 'Start', 'Start UTC', 'Runtime'
|
||
|
_numba_version = 'Numba Version'
|
||
|
# Hardware info
|
||
|
_machine = 'Machine'
|
||
|
_cpu_name, _cpu_count = 'CPU Name', 'CPU Count'
|
||
|
_cpus_allowed, _cpus_list = 'CPUs Allowed', 'List CPUs Allowed'
|
||
|
_cpu_features = 'CPU Features'
|
||
|
_cfs_quota, _cfs_period = 'CFS Quota', 'CFS Period',
|
||
|
_cfs_restrict = 'CFS Restriction'
|
||
|
_mem_total, _mem_available = 'Mem Total', 'Mem Available'
|
||
|
# OS info
|
||
|
_platform_name, _platform_release = 'Platform Name', 'Platform Release'
|
||
|
_os_name, _os_version = 'OS Name', 'OS Version'
|
||
|
_os_spec_version = 'OS Specific Version'
|
||
|
_libc_version = 'Libc Version'
|
||
|
# Python info
|
||
|
_python_comp = 'Python Compiler'
|
||
|
_python_impl = 'Python Implementation'
|
||
|
_python_version = 'Python Version'
|
||
|
_python_locale = 'Python Locale'
|
||
|
# LLVM info
|
||
|
_llvmlite_version = 'llvmlite Version'
|
||
|
_llvm_version = 'LLVM Version'
|
||
|
# CUDA info
|
||
|
_cu_dev_init = 'CUDA Device Init'
|
||
|
_cu_drv_ver = 'CUDA Driver Version'
|
||
|
_cu_rt_ver = 'CUDA Runtime Version'
|
||
|
_cu_nvidia_bindings = 'NVIDIA CUDA Bindings'
|
||
|
_cu_nvidia_bindings_used = 'NVIDIA CUDA Bindings In Use'
|
||
|
_cu_detect_out, _cu_lib_test = 'CUDA Detect Output', 'CUDA Lib Test'
|
||
|
_cu_mvc_available = 'NVIDIA CUDA Minor Version Compatibility Available'
|
||
|
_cu_mvc_needed = 'NVIDIA CUDA Minor Version Compatibility Needed'
|
||
|
_cu_mvc_in_use = 'NVIDIA CUDA Minor Version Compatibility In Use'
|
||
|
# NumPy info
|
||
|
_numpy_version = 'NumPy Version'
|
||
|
_numpy_supported_simd_features = 'NumPy Supported SIMD features'
|
||
|
_numpy_supported_simd_dispatch = 'NumPy Supported SIMD dispatch'
|
||
|
_numpy_supported_simd_baseline = 'NumPy Supported SIMD baseline'
|
||
|
_numpy_AVX512_SKX_detected = 'NumPy AVX512_SKX detected'
|
||
|
# SVML info
|
||
|
_svml_state, _svml_loaded = 'SVML State', 'SVML Lib Loaded'
|
||
|
_llvm_svml_patched = 'LLVM SVML Patched'
|
||
|
_svml_operational = 'SVML Operational'
|
||
|
# Threading layer info
|
||
|
_tbb_thread, _tbb_error = 'TBB Threading', 'TBB Threading Error'
|
||
|
_openmp_thread, _openmp_error = 'OpenMP Threading', 'OpenMP Threading Error'
|
||
|
_openmp_vendor = 'OpenMP vendor'
|
||
|
_wkq_thread, _wkq_error = 'Workqueue Threading', 'Workqueue Threading Error'
|
||
|
# Numba info
|
||
|
_numba_env_vars = 'Numba Env Vars'
|
||
|
# Conda info
|
||
|
_conda_build_ver, _conda_env_ver = 'Conda Build', 'Conda Env'
|
||
|
_conda_platform, _conda_python_ver = 'Conda Platform', 'Conda Python Version'
|
||
|
_conda_root_writable = 'Conda Root Writable'
|
||
|
# Packages info
|
||
|
_inst_pkg = 'Installed Packages'
|
||
|
# Psutil info
|
||
|
_psutil = 'Psutil Available'
|
||
|
# Errors and warnings
|
||
|
_errors = 'Errors'
|
||
|
_warnings = 'Warnings'
|
||
|
|
||
|
# Error and warning log
|
||
|
_error_log = []
|
||
|
_warning_log = []
|
||
|
|
||
|
|
||
|
def get_os_spec_info(os_name):
|
||
|
# Linux man page for `/proc`:
|
||
|
# http://man7.org/linux/man-pages/man5/proc.5.html
|
||
|
|
||
|
# Windows documentation for `wmic OS`:
|
||
|
# https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/cim-operatingsystem
|
||
|
|
||
|
# MacOS man page for `sysctl`:
|
||
|
# https://www.unix.com/man-page/osx/3/sysctl/
|
||
|
# MacOS man page for `vm_stat`:
|
||
|
# https://www.unix.com/man-page/osx/1/vm_stat/
|
||
|
|
||
|
class CmdBufferOut(tuple):
|
||
|
buffer_output_flag = True
|
||
|
|
||
|
class CmdReadFile(tuple):
|
||
|
read_file_flag = True
|
||
|
|
||
|
shell_params = {
|
||
|
'Linux': {
|
||
|
'cmd': (
|
||
|
CmdReadFile(('/sys/fs/cgroup/cpuacct/cpu.cfs_quota_us',)),
|
||
|
CmdReadFile(('/sys/fs/cgroup/cpuacct/cpu.cfs_period_us',)),
|
||
|
),
|
||
|
'cmd_optional': (
|
||
|
CmdReadFile(('/proc/meminfo',)),
|
||
|
CmdReadFile(('/proc/self/status',)),
|
||
|
),
|
||
|
'kwds': {
|
||
|
# output string fragment -> result dict key
|
||
|
'MemTotal:': _mem_total,
|
||
|
'MemAvailable:': _mem_available,
|
||
|
'Cpus_allowed:': _cpus_allowed,
|
||
|
'Cpus_allowed_list:': _cpus_list,
|
||
|
'/sys/fs/cgroup/cpuacct/cpu.cfs_quota_us': _cfs_quota,
|
||
|
'/sys/fs/cgroup/cpuacct/cpu.cfs_period_us': _cfs_period,
|
||
|
},
|
||
|
},
|
||
|
'Windows': {
|
||
|
'cmd': (),
|
||
|
'cmd_optional': (
|
||
|
CmdBufferOut(('wmic', 'OS', 'get', 'TotalVirtualMemorySize')),
|
||
|
CmdBufferOut(('wmic', 'OS', 'get', 'FreeVirtualMemory')),
|
||
|
),
|
||
|
'kwds': {
|
||
|
# output string fragment -> result dict key
|
||
|
'TotalVirtualMemorySize': _mem_total,
|
||
|
'FreeVirtualMemory': _mem_available,
|
||
|
},
|
||
|
},
|
||
|
'Darwin': {
|
||
|
'cmd': (),
|
||
|
'cmd_optional': (
|
||
|
('sysctl', 'hw.memsize'),
|
||
|
('vm_stat'),
|
||
|
),
|
||
|
'kwds': {
|
||
|
# output string fragment -> result dict key
|
||
|
'hw.memsize:': _mem_total,
|
||
|
'free:': _mem_available,
|
||
|
},
|
||
|
'units': {
|
||
|
_mem_total: 1, # Size is given in bytes.
|
||
|
_mem_available: 4096, # Size is given in 4kB pages.
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
os_spec_info = {}
|
||
|
params = shell_params.get(os_name, {})
|
||
|
cmd_selected = params.get('cmd', ())
|
||
|
|
||
|
if _psutil_import:
|
||
|
vm = psutil.virtual_memory()
|
||
|
os_spec_info.update({
|
||
|
_mem_total: vm.total,
|
||
|
_mem_available: vm.available,
|
||
|
})
|
||
|
p = psutil.Process()
|
||
|
cpus_allowed = p.cpu_affinity() if hasattr(p, 'cpu_affinity') else []
|
||
|
if cpus_allowed:
|
||
|
os_spec_info[_cpus_allowed] = len(cpus_allowed)
|
||
|
os_spec_info[_cpus_list] = ' '.join(str(n) for n in cpus_allowed)
|
||
|
|
||
|
else:
|
||
|
_warning_log.append(
|
||
|
"Warning (psutil): psutil cannot be imported. "
|
||
|
"For more accuracy, consider installing it.")
|
||
|
# Fallback to internal heuristics
|
||
|
cmd_selected += params.get('cmd_optional', ())
|
||
|
|
||
|
# Assuming the shell cmd returns a unique (k, v) pair per line
|
||
|
# or a unique (k, v) pair spread over several lines:
|
||
|
# Gather output in a list of strings containing a keyword and some value.
|
||
|
output = []
|
||
|
for cmd in cmd_selected:
|
||
|
if hasattr(cmd, 'read_file_flag'):
|
||
|
# Open file within Python
|
||
|
if os.path.exists(cmd[0]):
|
||
|
try:
|
||
|
with open(cmd[0], 'r') as f:
|
||
|
out = f.readlines()
|
||
|
if out:
|
||
|
out[0] = ' '.join((cmd[0], out[0]))
|
||
|
output.extend(out)
|
||
|
except OSError as e:
|
||
|
_error_log.append(f'Error (file read): {e}')
|
||
|
continue
|
||
|
else:
|
||
|
_warning_log.append('Warning (no file): {}'.format(cmd[0]))
|
||
|
continue
|
||
|
else:
|
||
|
# Spawn a subprocess
|
||
|
try:
|
||
|
out = check_output(cmd, stderr=PIPE)
|
||
|
except (OSError, CalledProcessError) as e:
|
||
|
_error_log.append(f'Error (subprocess): {e}')
|
||
|
continue
|
||
|
if hasattr(cmd, 'buffer_output_flag'):
|
||
|
out = b' '.join(line for line in out.splitlines()) + b'\n'
|
||
|
output.extend(out.decode().splitlines())
|
||
|
|
||
|
# Extract (k, output) pairs by searching for keywords in output
|
||
|
kwds = params.get('kwds', {})
|
||
|
for line in output:
|
||
|
match = kwds.keys() & line.split()
|
||
|
if match and len(match) == 1:
|
||
|
k = kwds[match.pop()]
|
||
|
os_spec_info[k] = line
|
||
|
elif len(match) > 1:
|
||
|
print(f'Ambiguous output: {line}')
|
||
|
|
||
|
# Try to extract something meaningful from output string
|
||
|
def format():
|
||
|
# CFS restrictions
|
||
|
split = os_spec_info.get(_cfs_quota, '').split()
|
||
|
if split:
|
||
|
os_spec_info[_cfs_quota] = float(split[-1])
|
||
|
split = os_spec_info.get(_cfs_period, '').split()
|
||
|
if split:
|
||
|
os_spec_info[_cfs_period] = float(split[-1])
|
||
|
if os_spec_info.get(_cfs_quota, -1) != -1:
|
||
|
cfs_quota = os_spec_info.get(_cfs_quota, '')
|
||
|
cfs_period = os_spec_info.get(_cfs_period, '')
|
||
|
runtime_amount = cfs_quota / cfs_period
|
||
|
os_spec_info[_cfs_restrict] = runtime_amount
|
||
|
|
||
|
def format_optional():
|
||
|
# Memory
|
||
|
units = {_mem_total: 1024, _mem_available: 1024}
|
||
|
units.update(params.get('units', {}))
|
||
|
for k in (_mem_total, _mem_available):
|
||
|
digits = ''.join(d for d in os_spec_info.get(k, '') if d.isdigit())
|
||
|
os_spec_info[k] = int(digits or 0) * units[k]
|
||
|
# Accessible CPUs
|
||
|
split = os_spec_info.get(_cpus_allowed, '').split()
|
||
|
if split:
|
||
|
n = split[-1]
|
||
|
n = n.split(',')[-1]
|
||
|
os_spec_info[_cpus_allowed] = str(bin(int(n or 0, 16))).count('1')
|
||
|
split = os_spec_info.get(_cpus_list, '').split()
|
||
|
if split:
|
||
|
os_spec_info[_cpus_list] = split[-1]
|
||
|
|
||
|
try:
|
||
|
format()
|
||
|
if not _psutil_import:
|
||
|
format_optional()
|
||
|
except Exception as e:
|
||
|
_error_log.append(f'Error (format shell output): {e}')
|
||
|
|
||
|
# Call OS specific functions
|
||
|
os_specific_funcs = {
|
||
|
'Linux': {
|
||
|
_libc_version: lambda: ' '.join(platform.libc_ver())
|
||
|
},
|
||
|
'Windows': {
|
||
|
_os_spec_version: lambda: ' '.join(
|
||
|
s for s in platform.win32_ver()),
|
||
|
},
|
||
|
'Darwin': {
|
||
|
_os_spec_version: lambda: ''.join(
|
||
|
i or ' ' for s in tuple(platform.mac_ver()) for i in s),
|
||
|
},
|
||
|
}
|
||
|
key_func = os_specific_funcs.get(os_name, {})
|
||
|
os_spec_info.update({k: f() for k, f in key_func.items()})
|
||
|
return os_spec_info
|
||
|
|
||
|
|
||
|
def get_sysinfo():
|
||
|
|
||
|
# Gather the information that shouldn't raise exceptions
|
||
|
sys_info = {
|
||
|
_start: datetime.now(),
|
||
|
_start_utc: datetime.utcnow(),
|
||
|
_machine: platform.machine(),
|
||
|
_cpu_name: llvmbind.get_host_cpu_name(),
|
||
|
_cpu_count: multiprocessing.cpu_count(),
|
||
|
_platform_name: platform.platform(aliased=True),
|
||
|
_platform_release: platform.release(),
|
||
|
_os_name: platform.system(),
|
||
|
_os_version: platform.version(),
|
||
|
_python_comp: platform.python_compiler(),
|
||
|
_python_impl: platform.python_implementation(),
|
||
|
_python_version: platform.python_version(),
|
||
|
_numba_env_vars: {k: v for (k, v) in os.environ.items()
|
||
|
if k.startswith('NUMBA_')},
|
||
|
_numba_version: version_number,
|
||
|
_llvm_version: '.'.join(str(i) for i in llvmbind.llvm_version_info),
|
||
|
_llvmlite_version: llvmlite_version,
|
||
|
_psutil: _psutil_import,
|
||
|
}
|
||
|
|
||
|
# CPU features
|
||
|
try:
|
||
|
feature_map = llvmbind.get_host_cpu_features()
|
||
|
except RuntimeError as e:
|
||
|
_error_log.append(f'Error (CPU features): {e}')
|
||
|
else:
|
||
|
features = sorted([key for key, value in feature_map.items() if value])
|
||
|
sys_info[_cpu_features] = ' '.join(features)
|
||
|
|
||
|
# Python locale
|
||
|
# On MacOSX, getdefaultlocale can raise. Check again if Py > 3.7.5
|
||
|
try:
|
||
|
# If $LANG is unset, getdefaultlocale() can return (None, None), make
|
||
|
# sure we can encode this as strings by casting explicitly.
|
||
|
sys_info[_python_locale] = '.'.join([str(i) for i in
|
||
|
locale.getdefaultlocale()])
|
||
|
except Exception as e:
|
||
|
_error_log.append(f'Error (locale): {e}')
|
||
|
|
||
|
# CUDA information
|
||
|
try:
|
||
|
cu.list_devices()[0] # will a device initialise?
|
||
|
except Exception as e:
|
||
|
sys_info[_cu_dev_init] = False
|
||
|
msg_not_found = "CUDA driver library cannot be found"
|
||
|
msg_disabled_by_user = "CUDA is disabled"
|
||
|
msg_end = " or no CUDA enabled devices are present."
|
||
|
msg_generic_problem = "CUDA device initialisation problem."
|
||
|
msg = getattr(e, 'msg', None)
|
||
|
if msg is not None:
|
||
|
if msg_not_found in msg:
|
||
|
err_msg = msg_not_found + msg_end
|
||
|
elif msg_disabled_by_user in msg:
|
||
|
err_msg = msg_disabled_by_user + msg_end
|
||
|
else:
|
||
|
err_msg = msg_generic_problem + " Message:" + msg
|
||
|
else:
|
||
|
err_msg = msg_generic_problem + " " + str(e)
|
||
|
# Best effort error report
|
||
|
_warning_log.append("Warning (cuda): %s\nException class: %s" %
|
||
|
(err_msg, str(type(e))))
|
||
|
else:
|
||
|
try:
|
||
|
sys_info[_cu_dev_init] = True
|
||
|
|
||
|
output = StringIO()
|
||
|
with redirect_stdout(output):
|
||
|
cu.detect()
|
||
|
sys_info[_cu_detect_out] = output.getvalue()
|
||
|
output.close()
|
||
|
|
||
|
cu_drv_ver = cudriver.get_version()
|
||
|
cu_rt_ver = curuntime.get_version()
|
||
|
sys_info[_cu_drv_ver] = '%s.%s' % cu_drv_ver
|
||
|
sys_info[_cu_rt_ver] = '%s.%s' % cu_rt_ver
|
||
|
|
||
|
output = StringIO()
|
||
|
with redirect_stdout(output):
|
||
|
cudadrv.libs.test()
|
||
|
sys_info[_cu_lib_test] = output.getvalue()
|
||
|
output.close()
|
||
|
|
||
|
try:
|
||
|
from cuda import cuda # noqa: F401
|
||
|
nvidia_bindings_available = True
|
||
|
except ImportError:
|
||
|
nvidia_bindings_available = False
|
||
|
sys_info[_cu_nvidia_bindings] = nvidia_bindings_available
|
||
|
|
||
|
nv_binding_used = bool(cudadrv.driver.USE_NV_BINDING)
|
||
|
sys_info[_cu_nvidia_bindings_used] = nv_binding_used
|
||
|
|
||
|
try:
|
||
|
from ptxcompiler import compile_ptx # noqa: F401
|
||
|
from cubinlinker import CubinLinker # noqa: F401
|
||
|
sys_info[_cu_mvc_available] = True
|
||
|
except ImportError:
|
||
|
sys_info[_cu_mvc_available] = False
|
||
|
|
||
|
sys_info[_cu_mvc_needed] = cu_rt_ver > cu_drv_ver
|
||
|
sys_info[_cu_mvc_in_use] = bool(
|
||
|
config.CUDA_ENABLE_MINOR_VERSION_COMPATIBILITY)
|
||
|
except Exception as e:
|
||
|
_warning_log.append(
|
||
|
"Warning (cuda): Probing CUDA failed "
|
||
|
"(device and driver present, runtime problem?)\n"
|
||
|
f"(cuda) {type(e)}: {e}")
|
||
|
|
||
|
# NumPy information
|
||
|
sys_info[_numpy_version] = np.version.full_version
|
||
|
try:
|
||
|
# NOTE: These consts were added in NumPy 1.20
|
||
|
from numpy.core._multiarray_umath import (__cpu_features__,
|
||
|
__cpu_dispatch__,
|
||
|
__cpu_baseline__,)
|
||
|
except ImportError:
|
||
|
sys_info[_numpy_AVX512_SKX_detected] = False
|
||
|
else:
|
||
|
feat_filtered = [k for k, v in __cpu_features__.items() if v]
|
||
|
sys_info[_numpy_supported_simd_features] = feat_filtered
|
||
|
sys_info[_numpy_supported_simd_dispatch] = __cpu_dispatch__
|
||
|
sys_info[_numpy_supported_simd_baseline] = __cpu_baseline__
|
||
|
sys_info[_numpy_AVX512_SKX_detected] = \
|
||
|
__cpu_features__.get("AVX512_SKX", False)
|
||
|
|
||
|
# SVML information
|
||
|
# Replicate some SVML detection logic from numba.__init__ here.
|
||
|
# If SVML load fails in numba.__init__ the splitting of the logic
|
||
|
# here will help diagnosing the underlying issue.
|
||
|
svml_lib_loaded = True
|
||
|
try:
|
||
|
if sys.platform.startswith('linux'):
|
||
|
llvmbind.load_library_permanently("libsvml.so")
|
||
|
elif sys.platform.startswith('darwin'):
|
||
|
llvmbind.load_library_permanently("libsvml.dylib")
|
||
|
elif sys.platform.startswith('win'):
|
||
|
llvmbind.load_library_permanently("svml_dispmd")
|
||
|
else:
|
||
|
svml_lib_loaded = False
|
||
|
except Exception:
|
||
|
svml_lib_loaded = False
|
||
|
func = getattr(llvmbind.targets, "has_svml", None)
|
||
|
sys_info[_llvm_svml_patched] = func() if func else False
|
||
|
sys_info[_svml_state] = config.USING_SVML
|
||
|
sys_info[_svml_loaded] = svml_lib_loaded
|
||
|
sys_info[_svml_operational] = all((
|
||
|
sys_info[_svml_state],
|
||
|
sys_info[_svml_loaded],
|
||
|
sys_info[_llvm_svml_patched],
|
||
|
))
|
||
|
|
||
|
# Check which threading backends are available.
|
||
|
def parse_error(e, backend):
|
||
|
# parses a linux based error message, this is to provide feedback
|
||
|
# and hide user paths etc
|
||
|
try:
|
||
|
path, problem, symbol = [x.strip() for x in e.msg.split(':')]
|
||
|
extn_dso = os.path.split(path)[1]
|
||
|
if backend in extn_dso:
|
||
|
return "%s: %s" % (problem, symbol)
|
||
|
except Exception:
|
||
|
pass
|
||
|
return "Unknown import problem."
|
||
|
|
||
|
try:
|
||
|
# check import is ok, this means the DSO linkage is working
|
||
|
from numba.np.ufunc import tbbpool # NOQA
|
||
|
# check that the version is compatible, this is a check performed at
|
||
|
# runtime (well, compile time), it will also ImportError if there's
|
||
|
# a problem.
|
||
|
from numba.np.ufunc.parallel import _check_tbb_version_compatible
|
||
|
_check_tbb_version_compatible()
|
||
|
sys_info[_tbb_thread] = True
|
||
|
except ImportError as e:
|
||
|
# might be a missing symbol due to e.g. tbb libraries missing
|
||
|
sys_info[_tbb_thread] = False
|
||
|
sys_info[_tbb_error] = parse_error(e, 'tbbpool')
|
||
|
|
||
|
try:
|
||
|
from numba.np.ufunc import omppool
|
||
|
sys_info[_openmp_thread] = True
|
||
|
sys_info[_openmp_vendor] = omppool.openmp_vendor
|
||
|
except ImportError as e:
|
||
|
sys_info[_openmp_thread] = False
|
||
|
sys_info[_openmp_error] = parse_error(e, 'omppool')
|
||
|
|
||
|
try:
|
||
|
from numba.np.ufunc import workqueue # NOQA
|
||
|
sys_info[_wkq_thread] = True
|
||
|
except ImportError as e:
|
||
|
sys_info[_wkq_thread] = True
|
||
|
sys_info[_wkq_error] = parse_error(e, 'workqueue')
|
||
|
|
||
|
# Look for conda and installed packages information
|
||
|
cmd = ('conda', 'info', '--json')
|
||
|
try:
|
||
|
conda_out = check_output(cmd)
|
||
|
except Exception as e:
|
||
|
_warning_log.append(f'Warning: Conda not available.\n Error was {e}\n')
|
||
|
# Conda is not available, try pip list to list installed packages
|
||
|
cmd = (sys.executable, '-m', 'pip', 'list')
|
||
|
try:
|
||
|
reqs = check_output(cmd)
|
||
|
except Exception as e:
|
||
|
_error_log.append(f'Error (pip): {e}')
|
||
|
else:
|
||
|
sys_info[_inst_pkg] = reqs.decode().splitlines()
|
||
|
|
||
|
else:
|
||
|
jsond = json.loads(conda_out.decode())
|
||
|
keys = {
|
||
|
'conda_build_version': _conda_build_ver,
|
||
|
'conda_env_version': _conda_env_ver,
|
||
|
'platform': _conda_platform,
|
||
|
'python_version': _conda_python_ver,
|
||
|
'root_writable': _conda_root_writable,
|
||
|
}
|
||
|
for conda_k, sysinfo_k in keys.items():
|
||
|
sys_info[sysinfo_k] = jsond.get(conda_k, 'N/A')
|
||
|
|
||
|
# Get info about packages in current environment
|
||
|
cmd = ('conda', 'list')
|
||
|
try:
|
||
|
conda_out = check_output(cmd)
|
||
|
except CalledProcessError as e:
|
||
|
_error_log.append(f'Error (conda): {e}')
|
||
|
else:
|
||
|
data = conda_out.decode().splitlines()
|
||
|
sys_info[_inst_pkg] = [l for l in data if not l.startswith('#')]
|
||
|
|
||
|
sys_info.update(get_os_spec_info(sys_info[_os_name]))
|
||
|
sys_info[_errors] = _error_log
|
||
|
sys_info[_warnings] = _warning_log
|
||
|
sys_info[_runtime] = (datetime.now() - sys_info[_start]).total_seconds()
|
||
|
return sys_info
|
||
|
|
||
|
|
||
|
def display_sysinfo(info=None, sep_pos=45):
|
||
|
class DisplayMap(dict):
|
||
|
display_map_flag = True
|
||
|
|
||
|
class DisplaySeq(tuple):
|
||
|
display_seq_flag = True
|
||
|
|
||
|
class DisplaySeqMaps(tuple):
|
||
|
display_seqmaps_flag = True
|
||
|
|
||
|
if info is None:
|
||
|
info = get_sysinfo()
|
||
|
|
||
|
fmt = f'%-{sep_pos}s : %-s'
|
||
|
MB = 1024**2
|
||
|
template = (
|
||
|
("-" * 80,),
|
||
|
("__Time Stamp__",),
|
||
|
("Report started (local time)", info.get(_start, '?')),
|
||
|
("UTC start time", info.get(_start_utc, '?')),
|
||
|
("Running time (s)", info.get(_runtime, '?')),
|
||
|
("",),
|
||
|
("__Hardware Information__",),
|
||
|
("Machine", info.get(_machine, '?')),
|
||
|
("CPU Name", info.get(_cpu_name, '?')),
|
||
|
("CPU Count", info.get(_cpu_count, '?')),
|
||
|
("Number of accessible CPUs", info.get(_cpus_allowed, '?')),
|
||
|
("List of accessible CPUs cores", info.get(_cpus_list, '?')),
|
||
|
("CFS Restrictions (CPUs worth of runtime)",
|
||
|
info.get(_cfs_restrict, 'None')),
|
||
|
("",),
|
||
|
("CPU Features", '\n'.join(
|
||
|
' ' * (sep_pos + 3) + l if i else l
|
||
|
for i, l in enumerate(
|
||
|
textwrap.wrap(
|
||
|
info.get(_cpu_features, '?'),
|
||
|
width=79 - sep_pos
|
||
|
)
|
||
|
)
|
||
|
)),
|
||
|
("",),
|
||
|
("Memory Total (MB)", info.get(_mem_total, 0) // MB or '?'),
|
||
|
("Memory Available (MB)"
|
||
|
if info.get(_os_name, '') != 'Darwin' or info.get(_psutil, False)
|
||
|
else "Free Memory (MB)", info.get(_mem_available, 0) // MB or '?'),
|
||
|
("",),
|
||
|
("__OS Information__",),
|
||
|
("Platform Name", info.get(_platform_name, '?')),
|
||
|
("Platform Release", info.get(_platform_release, '?')),
|
||
|
("OS Name", info.get(_os_name, '?')),
|
||
|
("OS Version", info.get(_os_version, '?')),
|
||
|
("OS Specific Version", info.get(_os_spec_version, '?')),
|
||
|
("Libc Version", info.get(_libc_version, '?')),
|
||
|
("",),
|
||
|
("__Python Information__",),
|
||
|
DisplayMap({k: v for k, v in info.items() if k.startswith('Python')}),
|
||
|
("",),
|
||
|
("__Numba Toolchain Versions__",),
|
||
|
("Numba Version", info.get(_numba_version, '?')),
|
||
|
("llvmlite Version", info.get(_llvmlite_version, '?')),
|
||
|
("",),
|
||
|
("__LLVM Information__",),
|
||
|
("LLVM Version", info.get(_llvm_version, '?')),
|
||
|
("",),
|
||
|
("__CUDA Information__",),
|
||
|
("CUDA Device Initialized", info.get(_cu_dev_init, '?')),
|
||
|
("CUDA Driver Version", info.get(_cu_drv_ver, '?')),
|
||
|
("CUDA Runtime Version", info.get(_cu_rt_ver, '?')),
|
||
|
("CUDA NVIDIA Bindings Available", info.get(_cu_nvidia_bindings, '?')),
|
||
|
("CUDA NVIDIA Bindings In Use",
|
||
|
info.get(_cu_nvidia_bindings_used, '?')),
|
||
|
("CUDA Minor Version Compatibility Available",
|
||
|
info.get(_cu_mvc_available, '?')),
|
||
|
("CUDA Minor Version Compatibility Needed",
|
||
|
info.get(_cu_mvc_needed, '?')),
|
||
|
("CUDA Minor Version Compatibility In Use",
|
||
|
info.get(_cu_mvc_in_use, '?')),
|
||
|
("CUDA Detect Output:",),
|
||
|
(info.get(_cu_detect_out, "None"),),
|
||
|
("CUDA Libraries Test Output:",),
|
||
|
(info.get(_cu_lib_test, "None"),),
|
||
|
("",),
|
||
|
("__NumPy Information__",),
|
||
|
("NumPy Version", info.get(_numpy_version, '?')),
|
||
|
("NumPy Supported SIMD features",
|
||
|
DisplaySeq(info.get(_numpy_supported_simd_features, [])
|
||
|
or ('None found.',))),
|
||
|
("NumPy Supported SIMD dispatch",
|
||
|
DisplaySeq(info.get(_numpy_supported_simd_dispatch, [])
|
||
|
or ('None found.',))),
|
||
|
("NumPy Supported SIMD baseline",
|
||
|
DisplaySeq(info.get(_numpy_supported_simd_baseline, [])
|
||
|
or ('None found.',))),
|
||
|
("NumPy AVX512_SKX support detected",
|
||
|
info.get(_numpy_AVX512_SKX_detected, '?')),
|
||
|
("",),
|
||
|
("__SVML Information__",),
|
||
|
("SVML State, config.USING_SVML", info.get(_svml_state, '?')),
|
||
|
("SVML Library Loaded", info.get(_svml_loaded, '?')),
|
||
|
("llvmlite Using SVML Patched LLVM", info.get(_llvm_svml_patched, '?')),
|
||
|
("SVML Operational", info.get(_svml_operational, '?')),
|
||
|
("",),
|
||
|
("__Threading Layer Information__",),
|
||
|
("TBB Threading Layer Available", info.get(_tbb_thread, '?')),
|
||
|
("+-->TBB imported successfully." if info.get(_tbb_thread, '?')
|
||
|
else f"+--> Disabled due to {info.get(_tbb_error, '?')}",),
|
||
|
("OpenMP Threading Layer Available", info.get(_openmp_thread, '?')),
|
||
|
(f"+-->Vendor: {info.get(_openmp_vendor, '?')}"
|
||
|
if info.get(_openmp_thread, False)
|
||
|
else f"+--> Disabled due to {info.get(_openmp_error, '?')}",),
|
||
|
("Workqueue Threading Layer Available", info.get(_wkq_thread, '?')),
|
||
|
("+-->Workqueue imported successfully." if info.get(_wkq_thread, False)
|
||
|
else f"+--> Disabled due to {info.get(_wkq_error, '?')}",),
|
||
|
("",),
|
||
|
("__Numba Environment Variable Information__",),
|
||
|
(DisplayMap(info.get(_numba_env_vars, {})) or ('None found.',)),
|
||
|
("",),
|
||
|
("__Conda Information__",),
|
||
|
(DisplayMap({k: v for k, v in info.items()
|
||
|
if k.startswith('Conda')}) or ("Conda not available.",)),
|
||
|
("",),
|
||
|
("__Installed Packages__",),
|
||
|
DisplaySeq(info.get(_inst_pkg, ("Couldn't retrieve packages info.",))),
|
||
|
("",),
|
||
|
("__Error log__" if info.get(_errors, [])
|
||
|
else "No errors reported.",),
|
||
|
DisplaySeq(info.get(_errors, [])),
|
||
|
("",),
|
||
|
("__Warning log__" if info.get(_warnings, [])
|
||
|
else "No warnings reported.",),
|
||
|
DisplaySeq(info.get(_warnings, [])),
|
||
|
("-" * 80,),
|
||
|
("If requested, please copy and paste the information between\n"
|
||
|
"the dashed (----) lines, or from a given specific section as\n"
|
||
|
"appropriate.\n\n"
|
||
|
"=============================================================\n"
|
||
|
"IMPORTANT: Please ensure that you are happy with sharing the\n"
|
||
|
"contents of the information present, any information that you\n"
|
||
|
"wish to keep private you should remove before sharing.\n"
|
||
|
"=============================================================\n",),
|
||
|
)
|
||
|
for t in template:
|
||
|
if hasattr(t, 'display_seq_flag'):
|
||
|
print(*t, sep='\n')
|
||
|
elif hasattr(t, 'display_map_flag'):
|
||
|
print(*tuple(fmt % (k, v) for (k, v) in t.items()), sep='\n')
|
||
|
elif hasattr(t, 'display_seqmaps_flag'):
|
||
|
for d in t:
|
||
|
print(*tuple(fmt % ('\t' + k, v) for (k, v) in d.items()),
|
||
|
sep='\n', end='\n')
|
||
|
elif len(t) == 2:
|
||
|
print(fmt % t)
|
||
|
else:
|
||
|
print(*t)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
display_sysinfo()
|