| |
|
| | |
| | |
| | |
| | import datetime |
| | import locale |
| | import re |
| | import subprocess |
| | import sys |
| | import os |
| | from collections import namedtuple |
| |
|
| |
|
| | try: |
| | import torch |
| | TORCH_AVAILABLE = True |
| | except (ImportError, NameError, AttributeError, OSError): |
| | TORCH_AVAILABLE = False |
| |
|
| | |
| | SystemEnv = namedtuple('SystemEnv', [ |
| | 'torch_version', |
| | 'is_debug_build', |
| | 'cuda_compiled_version', |
| | 'gcc_version', |
| | 'clang_version', |
| | 'cmake_version', |
| | 'os', |
| | 'libc_version', |
| | 'python_version', |
| | 'python_platform', |
| | 'is_cuda_available', |
| | 'cuda_runtime_version', |
| | 'cuda_module_loading', |
| | 'nvidia_driver_version', |
| | 'nvidia_gpu_models', |
| | 'cudnn_version', |
| | 'pip_version', |
| | 'pip_packages', |
| | 'conda_packages', |
| | 'hip_compiled_version', |
| | 'hip_runtime_version', |
| | 'miopen_runtime_version', |
| | 'caching_allocator_config', |
| | 'is_xnnpack_available', |
| | 'cpu_info', |
| | ]) |
| |
|
| |
|
| | def run(command): |
| | """Returns (return-code, stdout, stderr)""" |
| | shell = True if type(command) is str else False |
| | p = subprocess.Popen(command, stdout=subprocess.PIPE, |
| | stderr=subprocess.PIPE, shell=shell) |
| | raw_output, raw_err = p.communicate() |
| | rc = p.returncode |
| | if get_platform() == 'win32': |
| | enc = 'oem' |
| | else: |
| | enc = locale.getpreferredencoding() |
| | output = raw_output.decode(enc) |
| | err = raw_err.decode(enc) |
| | return rc, output.strip(), err.strip() |
| |
|
| |
|
| | def run_and_read_all(run_lambda, command): |
| | """Runs command using run_lambda; reads and returns entire output if rc is 0""" |
| | rc, out, _ = run_lambda(command) |
| | if rc != 0: |
| | return None |
| | return out |
| |
|
| |
|
| | def run_and_parse_first_match(run_lambda, command, regex): |
| | """Runs command using run_lambda, returns the first regex match if it exists""" |
| | rc, out, _ = run_lambda(command) |
| | if rc != 0: |
| | return None |
| | match = re.search(regex, out) |
| | if match is None: |
| | return None |
| | return match.group(1) |
| |
|
| | def run_and_return_first_line(run_lambda, command): |
| | """Runs command using run_lambda and returns first line if output is not empty""" |
| | rc, out, _ = run_lambda(command) |
| | if rc != 0: |
| | return None |
| | return out.split('\n')[0] |
| |
|
| |
|
| | def get_conda_packages(run_lambda): |
| | conda = os.environ.get('CONDA_EXE', 'conda') |
| | out = run_and_read_all(run_lambda, "{} list".format(conda)) |
| | if out is None: |
| | return out |
| |
|
| | return "\n".join( |
| | line |
| | for line in out.splitlines() |
| | if not line.startswith("#") |
| | and any( |
| | name in line |
| | for name in { |
| | "torch", |
| | "numpy", |
| | "cudatoolkit", |
| | "soumith", |
| | "mkl", |
| | "magma", |
| | "triton", |
| | } |
| | ) |
| | ) |
| |
|
| | def get_gcc_version(run_lambda): |
| | return run_and_parse_first_match(run_lambda, 'gcc --version', r'gcc (.*)') |
| |
|
| | def get_clang_version(run_lambda): |
| | return run_and_parse_first_match(run_lambda, 'clang --version', r'clang version (.*)') |
| |
|
| |
|
| | def get_cmake_version(run_lambda): |
| | return run_and_parse_first_match(run_lambda, 'cmake --version', r'cmake (.*)') |
| |
|
| |
|
| | def get_nvidia_driver_version(run_lambda): |
| | if get_platform() == 'darwin': |
| | cmd = 'kextstat | grep -i cuda' |
| | return run_and_parse_first_match(run_lambda, cmd, |
| | r'com[.]nvidia[.]CUDA [(](.*?)[)]') |
| | smi = get_nvidia_smi() |
| | return run_and_parse_first_match(run_lambda, smi, r'Driver Version: (.*?) ') |
| |
|
| |
|
| | def get_gpu_info(run_lambda): |
| | if get_platform() == 'darwin' or (TORCH_AVAILABLE and hasattr(torch.version, 'hip') and torch.version.hip is not None): |
| | if TORCH_AVAILABLE and torch.cuda.is_available(): |
| | return torch.cuda.get_device_name(None) |
| | return None |
| | smi = get_nvidia_smi() |
| | uuid_regex = re.compile(r' \(UUID: .+?\)') |
| | rc, out, _ = run_lambda(smi + ' -L') |
| | if rc != 0: |
| | return None |
| | |
| | return re.sub(uuid_regex, '', out) |
| |
|
| |
|
| | def get_running_cuda_version(run_lambda): |
| | return run_and_parse_first_match(run_lambda, 'nvcc --version', r'release .+ V(.*)') |
| |
|
| |
|
| | def get_cudnn_version(run_lambda): |
| | """This will return a list of libcudnn.so; it's hard to tell which one is being used""" |
| | if get_platform() == 'win32': |
| | system_root = os.environ.get('SYSTEMROOT', 'C:\\Windows') |
| | cuda_path = os.environ.get('CUDA_PATH', "%CUDA_PATH%") |
| | where_cmd = os.path.join(system_root, 'System32', 'where') |
| | cudnn_cmd = '{} /R "{}\\bin" cudnn*.dll'.format(where_cmd, cuda_path) |
| | elif get_platform() == 'darwin': |
| | |
| | |
| | |
| | |
| | cudnn_cmd = 'ls /usr/local/cuda/lib/libcudnn*' |
| | else: |
| | cudnn_cmd = 'ldconfig -p | grep libcudnn | rev | cut -d" " -f1 | rev' |
| | rc, out, _ = run_lambda(cudnn_cmd) |
| | |
| | if len(out) == 0 or (rc != 1 and rc != 0): |
| | l = os.environ.get('CUDNN_LIBRARY') |
| | if l is not None and os.path.isfile(l): |
| | return os.path.realpath(l) |
| | return None |
| | files_set = set() |
| | for fn in out.split('\n'): |
| | fn = os.path.realpath(fn) |
| | if os.path.isfile(fn): |
| | files_set.add(fn) |
| | if not files_set: |
| | return None |
| | |
| | files = sorted(files_set) |
| | if len(files) == 1: |
| | return files[0] |
| | result = '\n'.join(files) |
| | return 'Probably one of the following:\n{}'.format(result) |
| |
|
| |
|
| | def get_nvidia_smi(): |
| | |
| | smi = 'nvidia-smi' |
| | if get_platform() == 'win32': |
| | system_root = os.environ.get('SYSTEMROOT', 'C:\\Windows') |
| | program_files_root = os.environ.get('PROGRAMFILES', 'C:\\Program Files') |
| | legacy_path = os.path.join(program_files_root, 'NVIDIA Corporation', 'NVSMI', smi) |
| | new_path = os.path.join(system_root, 'System32', smi) |
| | smis = [new_path, legacy_path] |
| | for candidate_smi in smis: |
| | if os.path.exists(candidate_smi): |
| | smi = '"{}"'.format(candidate_smi) |
| | break |
| | return smi |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | def get_cpu_info(run_lambda): |
| | rc, out, err = 0, '', '' |
| | if get_platform() == 'linux': |
| | rc, out, err = run_lambda('lscpu') |
| | elif get_platform() == 'win32': |
| | rc, out, err = run_lambda('wmic cpu get Name,Manufacturer,Family,Architecture,ProcessorType,DeviceID,\ |
| | CurrentClockSpeed,MaxClockSpeed,L2CacheSize,L2CacheSpeed,Revision /VALUE') |
| | elif get_platform() == 'darwin': |
| | rc, out, err = run_lambda("sysctl -n machdep.cpu.brand_string") |
| | cpu_info = 'None' |
| | if rc == 0: |
| | cpu_info = out |
| | else: |
| | cpu_info = err |
| | return cpu_info |
| |
|
| |
|
| | def get_platform(): |
| | if sys.platform.startswith('linux'): |
| | return 'linux' |
| | elif sys.platform.startswith('win32'): |
| | return 'win32' |
| | elif sys.platform.startswith('cygwin'): |
| | return 'cygwin' |
| | elif sys.platform.startswith('darwin'): |
| | return 'darwin' |
| | else: |
| | return sys.platform |
| |
|
| |
|
| | def get_mac_version(run_lambda): |
| | return run_and_parse_first_match(run_lambda, 'sw_vers -productVersion', r'(.*)') |
| |
|
| |
|
| | def get_windows_version(run_lambda): |
| | system_root = os.environ.get('SYSTEMROOT', 'C:\\Windows') |
| | wmic_cmd = os.path.join(system_root, 'System32', 'Wbem', 'wmic') |
| | findstr_cmd = os.path.join(system_root, 'System32', 'findstr') |
| | return run_and_read_all(run_lambda, '{} os get Caption | {} /v Caption'.format(wmic_cmd, findstr_cmd)) |
| |
|
| |
|
| | def get_lsb_version(run_lambda): |
| | return run_and_parse_first_match(run_lambda, 'lsb_release -a', r'Description:\t(.*)') |
| |
|
| |
|
| | def check_release_file(run_lambda): |
| | return run_and_parse_first_match(run_lambda, 'cat /etc/*-release', |
| | r'PRETTY_NAME="(.*)"') |
| |
|
| |
|
| | def get_os(run_lambda): |
| | from platform import machine |
| | platform = get_platform() |
| |
|
| | if platform == 'win32' or platform == 'cygwin': |
| | return get_windows_version(run_lambda) |
| |
|
| | if platform == 'darwin': |
| | version = get_mac_version(run_lambda) |
| | if version is None: |
| | return None |
| | return 'macOS {} ({})'.format(version, machine()) |
| |
|
| | if platform == 'linux': |
| | |
| | desc = get_lsb_version(run_lambda) |
| | if desc is not None: |
| | return '{} ({})'.format(desc, machine()) |
| |
|
| | |
| | desc = check_release_file(run_lambda) |
| | if desc is not None: |
| | return '{} ({})'.format(desc, machine()) |
| |
|
| | return '{} ({})'.format(platform, machine()) |
| |
|
| | |
| | return platform |
| |
|
| |
|
| | def get_python_platform(): |
| | import platform |
| | return platform.platform() |
| |
|
| |
|
| | def get_libc_version(): |
| | import platform |
| | if get_platform() != 'linux': |
| | return 'N/A' |
| | return '-'.join(platform.libc_ver()) |
| |
|
| |
|
| | def get_pip_packages(run_lambda): |
| | """Returns `pip list` output. Note: will also find conda-installed pytorch |
| | and numpy packages.""" |
| | |
| | |
| | def run_with_pip(pip): |
| | out = run_and_read_all(run_lambda, pip + ["list", "--format=freeze"]) |
| | return "\n".join( |
| | line |
| | for line in out.splitlines() |
| | if any( |
| | name in line |
| | for name in { |
| | "torch", |
| | "numpy", |
| | "mypy", |
| | "flake8", |
| | "triton", |
| | } |
| | ) |
| | ) |
| |
|
| | pip_version = 'pip3' if sys.version[0] == '3' else 'pip' |
| | out = run_with_pip([sys.executable, '-mpip']) |
| |
|
| | return pip_version, out |
| |
|
| |
|
| | def get_cachingallocator_config(): |
| | ca_config = os.environ.get('PYTORCH_CUDA_ALLOC_CONF', '') |
| | return ca_config |
| |
|
| |
|
| | def get_cuda_module_loading_config(): |
| | if TORCH_AVAILABLE and torch.cuda.is_available(): |
| | torch.cuda.init() |
| | config = os.environ.get('CUDA_MODULE_LOADING', '') |
| | return config |
| | else: |
| | return "N/A" |
| |
|
| |
|
| | def is_xnnpack_available(): |
| | if TORCH_AVAILABLE: |
| | import torch.backends.xnnpack |
| | return str(torch.backends.xnnpack.enabled) |
| | else: |
| | return "N/A" |
| |
|
| | def get_env_info(): |
| | run_lambda = run |
| | pip_version, pip_list_output = get_pip_packages(run_lambda) |
| |
|
| | if TORCH_AVAILABLE: |
| | version_str = torch.__version__ |
| | debug_mode_str = str(torch.version.debug) |
| | cuda_available_str = str(torch.cuda.is_available()) |
| | cuda_version_str = torch.version.cuda |
| | if not hasattr(torch.version, 'hip') or torch.version.hip is None: |
| | hip_compiled_version = hip_runtime_version = miopen_runtime_version = 'N/A' |
| | else: |
| | def get_version_or_na(cfg, prefix): |
| | _lst = [s.rsplit(None, 1)[-1] for s in cfg if prefix in s] |
| | return _lst[0] if _lst else 'N/A' |
| |
|
| | cfg = torch._C._show_config().split('\n') |
| | hip_runtime_version = get_version_or_na(cfg, 'HIP Runtime') |
| | miopen_runtime_version = get_version_or_na(cfg, 'MIOpen') |
| | cuda_version_str = 'N/A' |
| | hip_compiled_version = torch.version.hip |
| | else: |
| | version_str = debug_mode_str = cuda_available_str = cuda_version_str = 'N/A' |
| | hip_compiled_version = hip_runtime_version = miopen_runtime_version = 'N/A' |
| |
|
| | sys_version = sys.version.replace("\n", " ") |
| |
|
| | return SystemEnv( |
| | torch_version=version_str, |
| | is_debug_build=debug_mode_str, |
| | python_version='{} ({}-bit runtime)'.format(sys_version, sys.maxsize.bit_length() + 1), |
| | python_platform=get_python_platform(), |
| | is_cuda_available=cuda_available_str, |
| | cuda_compiled_version=cuda_version_str, |
| | cuda_runtime_version=get_running_cuda_version(run_lambda), |
| | cuda_module_loading=get_cuda_module_loading_config(), |
| | nvidia_gpu_models=get_gpu_info(run_lambda), |
| | nvidia_driver_version=get_nvidia_driver_version(run_lambda), |
| | cudnn_version=get_cudnn_version(run_lambda), |
| | hip_compiled_version=hip_compiled_version, |
| | hip_runtime_version=hip_runtime_version, |
| | miopen_runtime_version=miopen_runtime_version, |
| | pip_version=pip_version, |
| | pip_packages=pip_list_output, |
| | conda_packages=get_conda_packages(run_lambda), |
| | os=get_os(run_lambda), |
| | libc_version=get_libc_version(), |
| | gcc_version=get_gcc_version(run_lambda), |
| | clang_version=get_clang_version(run_lambda), |
| | cmake_version=get_cmake_version(run_lambda), |
| | caching_allocator_config=get_cachingallocator_config(), |
| | is_xnnpack_available=is_xnnpack_available(), |
| | cpu_info=get_cpu_info(run_lambda), |
| | ) |
| |
|
| | env_info_fmt = """ |
| | PyTorch version: {torch_version} |
| | Is debug build: {is_debug_build} |
| | CUDA used to build PyTorch: {cuda_compiled_version} |
| | ROCM used to build PyTorch: {hip_compiled_version} |
| | |
| | OS: {os} |
| | GCC version: {gcc_version} |
| | Clang version: {clang_version} |
| | CMake version: {cmake_version} |
| | Libc version: {libc_version} |
| | |
| | Python version: {python_version} |
| | Python platform: {python_platform} |
| | Is CUDA available: {is_cuda_available} |
| | CUDA runtime version: {cuda_runtime_version} |
| | CUDA_MODULE_LOADING set to: {cuda_module_loading} |
| | GPU models and configuration: {nvidia_gpu_models} |
| | Nvidia driver version: {nvidia_driver_version} |
| | cuDNN version: {cudnn_version} |
| | HIP runtime version: {hip_runtime_version} |
| | MIOpen runtime version: {miopen_runtime_version} |
| | Is XNNPACK available: {is_xnnpack_available} |
| | |
| | CPU: |
| | {cpu_info} |
| | |
| | Versions of relevant libraries: |
| | {pip_packages} |
| | {conda_packages} |
| | """.strip() |
| |
|
| |
|
| | def pretty_str(envinfo): |
| | def replace_nones(dct, replacement='Could not collect'): |
| | for key in dct.keys(): |
| | if dct[key] is not None: |
| | continue |
| | dct[key] = replacement |
| | return dct |
| |
|
| | def replace_bools(dct, true='Yes', false='No'): |
| | for key in dct.keys(): |
| | if dct[key] is True: |
| | dct[key] = true |
| | elif dct[key] is False: |
| | dct[key] = false |
| | return dct |
| |
|
| | def prepend(text, tag='[prepend]'): |
| | lines = text.split('\n') |
| | updated_lines = [tag + line for line in lines] |
| | return '\n'.join(updated_lines) |
| |
|
| | def replace_if_empty(text, replacement='No relevant packages'): |
| | if text is not None and len(text) == 0: |
| | return replacement |
| | return text |
| |
|
| | def maybe_start_on_next_line(string): |
| | |
| | if string is not None and len(string.split('\n')) > 1: |
| | return '\n{}\n'.format(string) |
| | return string |
| |
|
| | mutable_dict = envinfo._asdict() |
| |
|
| | |
| | mutable_dict['nvidia_gpu_models'] = \ |
| | maybe_start_on_next_line(envinfo.nvidia_gpu_models) |
| |
|
| | |
| | dynamic_cuda_fields = [ |
| | 'cuda_runtime_version', |
| | 'nvidia_gpu_models', |
| | 'nvidia_driver_version', |
| | ] |
| | all_cuda_fields = dynamic_cuda_fields + ['cudnn_version'] |
| | all_dynamic_cuda_fields_missing = all( |
| | mutable_dict[field] is None for field in dynamic_cuda_fields) |
| | if TORCH_AVAILABLE and not torch.cuda.is_available() and all_dynamic_cuda_fields_missing: |
| | for field in all_cuda_fields: |
| | mutable_dict[field] = 'No CUDA' |
| | if envinfo.cuda_compiled_version is None: |
| | mutable_dict['cuda_compiled_version'] = 'None' |
| |
|
| | |
| | mutable_dict = replace_bools(mutable_dict) |
| |
|
| | |
| | mutable_dict = replace_nones(mutable_dict) |
| |
|
| | |
| | mutable_dict['pip_packages'] = replace_if_empty(mutable_dict['pip_packages']) |
| | mutable_dict['conda_packages'] = replace_if_empty(mutable_dict['conda_packages']) |
| |
|
| | |
| | |
| | if mutable_dict['pip_packages']: |
| | mutable_dict['pip_packages'] = prepend(mutable_dict['pip_packages'], |
| | '[{}] '.format(envinfo.pip_version)) |
| | if mutable_dict['conda_packages']: |
| | mutable_dict['conda_packages'] = prepend(mutable_dict['conda_packages'], |
| | '[conda] ') |
| | mutable_dict['cpu_info'] = envinfo.cpu_info |
| | return env_info_fmt.format(**mutable_dict) |
| |
|
| |
|
| | def get_pretty_env_info(): |
| | return pretty_str(get_env_info()) |
| |
|
| |
|
| | def main(): |
| | print("Collecting environment information...") |
| | output = get_pretty_env_info() |
| | print(output) |
| |
|
| | if TORCH_AVAILABLE and hasattr(torch, 'utils') and hasattr(torch.utils, '_crash_handler'): |
| | minidump_dir = torch.utils._crash_handler.DEFAULT_MINIDUMP_DIR |
| | if sys.platform == "linux" and os.path.exists(minidump_dir): |
| | dumps = [os.path.join(minidump_dir, dump) for dump in os.listdir(minidump_dir)] |
| | latest = max(dumps, key=os.path.getctime) |
| | ctime = os.path.getctime(latest) |
| | creation_time = datetime.datetime.fromtimestamp(ctime).strftime('%Y-%m-%d %H:%M:%S') |
| | msg = "\n*** Detected a minidump at {} created on {}, ".format(latest, creation_time) + \ |
| | "if this is related to your bug please include it when you file a report ***" |
| | print(msg, file=sys.stderr) |
| |
|
| |
|
| |
|
| | if __name__ == '__main__': |
| | main() |
| |
|