Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 7 additions & 16 deletions .github/workflows/cicd_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,16 +148,10 @@ jobs:
python -m pip list
BUILD_MONAI=0 python setup.py develop # no compile of extensions
shell: bash
- if: matrix.os == 'linux-gpu-runner'
name: Print GPU Info
run: |
nvidia-smi
python -c 'import torch; print(torch.rand(2,2).to("cuda:0"))'
shell: bash
- name: Run quick tests
run: |
python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
python -c "import monai; monai.config.print_config()"
nvidia-smi || true
python monai/config/check_env.py --env --monai
./runtests.sh --min
shell: bash
env:
Expand Down Expand Up @@ -229,19 +223,18 @@ jobs:
run: |
python -m pip uninstall -y monai
BUILD_MONAI=1 python -m pip install --no-build-isolation -e . # compile the cpp extensions

nvidia-smi || true
python monai/config/check_env.py --env --monai
shell: bash
- if: runner.os != 'macOS'
name: Run full tests
run: |
python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
python -c "import monai; monai.config.print_config()"
python -m unittest -v
shell: bash
- if: runner.os == 'macOS'
name: Run min tests
run: |
python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))'
python -c "import monai; monai.config.print_config()"
# TODO: enable large range of macOS tests which don't take a very long time
./runtests.sh --min
shell: bash
Expand Down Expand Up @@ -351,8 +344,7 @@ jobs:
run: |
# install from wheel
python -m pip install monai*.whl --extra-index-url https://download.pytorch.org/whl/cpu
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
python -c 'import monai; print(monai.__file__)'
python -m monai.config
python -m pip uninstall -y monai
rm monai*.whl
- name: Install source archive
Expand All @@ -361,5 +353,4 @@ jobs:
for name in *.tar.gz; do break; done
echo $name
python -m pip install ${name}[all] --extra-index-url https://download.pytorch.org/whl/cpu
python -c 'import monai; monai.config.print_config()' 2>&1 | grep -iv "unknown"
python -c 'import monai; print(monai.__file__)'
python -m monai.config
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include versioneer.py
include monai/_version.py
include monai/config/check_env.py

include README.md
include LICENSE
Expand Down
1 change: 0 additions & 1 deletion monai/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from .deviceconfig import (
USE_COMPILED,
USE_META_DICT,
IgniteInfo,
get_config_values,
get_gpu_info,
get_optional_config_values,
Expand Down
15 changes: 15 additions & 0 deletions monai/config/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

if __name__ == "__main__":
import monai

monai.config.print_debug_info() # type: ignore
181 changes: 181 additions & 0 deletions monai/config/check_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#! /usr/bin/env python

# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Script for checking various elements of the runtime environment and printing a large amount of diagnostic information.

This is meant to be used for debugging environments used with MONAI, but doesn't directly need MONAI itself. It will
print information about the environment, including trying to get installed packages, test PyTorch with CUDA, and then
have MONAI print its debugging information if no errors encountered. If MONAI is not installed this script should still
work and produce useful information. Only standard libraries are needed in case a bare environment is being used.

This can be run as a program with the following options to see all outputs:

python check_env.py --env --envvars --monai

With no options at all this can be used to test that PyTorch is installed and can move a tensor to a device. This is
useful when creating a fresh test environment and MONAI isn't present yet but it's good practice to valid PyTorch.

This can also be used remotely with only Python installed to get current environment diagnostic info:

curl https://raw.githubusercontent.com/Project-MONAI/MONAI/refs/heads/dev/monai/config/check_env.py | python
"""

from __future__ import annotations

import argparse
import getpass
import multiprocessing
import os
import platform
import shutil
import subprocess
import sys
from functools import partial

DESC = """
Script for checking various elements of the runtime environment and printing a large amount of diagnostic information.
This is used for debugging your environment by printing out various system statistics and diagnostic information. It
checks PyTorch and MONAI are installed and functioning. A typical use case is with the `--env` and `--monai` options.
"""

USER = getpass.getuser()
HOST = platform.node()
efprint = partial(print, flush=True, file=sys.stderr)


def fprint(*args, **kwargs):
"""
Print with flushing, replacing the username and hostname values with placeholders for better anonymization.
"""
kwargs["flush"] = True
content = " ".join(map(str, args))
content = content.replace(USER, "<user>").replace(HOST, "<host>")
print(content, **kwargs)


def print_platform():
"""
Print basic platform information.
"""
fprint(platform.platform())
fprint("uname:", list(platform.uname()))
fprint("CPU:", platform.processor(), "Count:", multiprocessing.cpu_count())
fprint("Python:", sys.executable, platform.python_implementation(), platform.python_version())


def print_environment_vars():
"""
Print all environment variables other than a few known pointless ones.
"""
fprint("Environment:")
for k, v in os.environ.items():
if k not in ("LS_COLORS", "PS1", "PS2"):
fprint(f" {k}:", v)


def print_environment():
"""
Print the installed environment using `conda` or `pip`, fail if neither are present.
"""
try:
cmd = ("conda", "env", "export") if shutil.which("conda") else ("pip", "list")

result = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
fprint(result.decode())
return True
except Exception as e:
efprint(f"Exception encountered getting environment with conda/pip: {e}")
return False


def check_torch():
"""
Check PyTorch is installed and a tensor can be created.
"""
try:
import torch

t = torch.rand(2, 3) * 5
fprint("PyTorch:", torch.__version__, torch.__path__)
fprint("Test tensor:", t.flatten())
return True
except ImportError:
efprint("PyTorch not installed")
return False


def check_torch_cuda():
"""
Check CUDA capability in PyTorch by moving a tensor to each available device.
"""
import torch

dcount = torch.cuda.device_count()
fprint("CUDA version:", torch.version.cuda)
fprint("PyTorch GPU Count:", dcount)

try:
for d in range(dcount):
fprint(f" {torch.cuda.get_device_properties(d)}")
t = torch.rand(2, 3).to(torch.device(f"cuda:{d}")) * 5
fprint("Test tensor:", t.flatten())
return True
except Exception as e:
efprint(f"PyTorch encountered exception creating GPU tensor on device {d}: {e}")
return False


def check_monai():
"""
Check MONAI by importing it then printing its debug info.
"""
try:
import monai

monai.config.print_debug_info() # type: ignore
return True
except ImportError:
efprint("MONAI not installed")
return False
Comment thread
coderabbitai[bot] marked this conversation as resolved.


if __name__ == "__main__":
parser = argparse.ArgumentParser(prog="check_env.py", description=DESC.strip())
parser.add_argument("--env", default=False, action="store_true", help="Print environment info")
parser.add_argument("--envvars", default=False, action="store_true", help="Include environment variables")
parser.add_argument("--monai", default=False, action="store_true", help="Print MONAI info")
args = parser.parse_args()

fprint("=" * 10, "Platform Info", "=" * 10)
print_platform()

if args.env:
fprint("=" * 10, "Checking Environment", "=" * 10)
if args.envvars:
print_environment_vars()
print_environment()
Comment thread
ericspod marked this conversation as resolved.

fprint("=" * 10, "Checking PyTorch", "=" * 10)

if not check_torch():
efprint("Exiting early, no valid PyTorch install found.")
sys.exit(1)

if not check_torch_cuda():
efprint("Exiting early, PyTorch encountered CUDA error.")
sys.exit(1)

if args.monai:
fprint("=" * 10, "Checking MONAI", "=" * 10)
check_monai()
65 changes: 33 additions & 32 deletions monai/config/deviceconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
import torch

import monai
from monai.utils.deprecate_utils import deprecated
from monai.utils.enums import IgniteInfo as _IgniteInfo
from monai.utils.module import OptionalImportError, get_package_version, optional_import

try:
Expand All @@ -47,9 +45,21 @@
"print_debug_info",
"USE_COMPILED",
"USE_META_DICT",
"IgniteInfo",
]

USER = getpass.getuser()
HOST = platform.node()


def fprint(*args, **kwargs):
"""
Print with flushing, replacing the username and hostname values with placeholders for better anonymization.
"""
kwargs["flush"] = True
content = " ".join(map(str, args))
content = content.replace(USER, "<user>").replace(HOST, "<host>")
print(content, **kwargs)


def get_config_values():
"""
Expand Down Expand Up @@ -100,17 +110,15 @@ def print_config(file=sys.stdout):
file: `print()` text stream file. Defaults to `sys.stdout`.
"""
for k, v in get_config_values().items():
print(f"{k} version: {v}", file=file, flush=True)
print(f"MONAI flags: HAS_EXT = {HAS_EXT}, USE_COMPILED = {USE_COMPILED}, USE_META_DICT = {USE_META_DICT}")
print(f"MONAI rev id: {monai.__revision_id__}")
username = getpass.getuser()
masked_file_path = re.sub(username, "<username>", monai.__file__)
print(f"MONAI __file__: {masked_file_path}", file=file, flush=True)
print("\nOptional dependencies:", file=file, flush=True)
fprint(f"{k} version: {v}", file=file)
fprint(f"MONAI flags: {HAS_EXT=}, {USE_COMPILED=}, {USE_META_DICT=}", file=file)
fprint(f"MONAI rev id: {monai.__revision_id__}", file=file)
fprint(f"MONAI __file__: {monai.__file__}", file=file)
fprint("\nOptional dependencies:", file=file)
for k, v in get_optional_config_values().items():
print(f"{k} version: {v}", file=file, flush=True)
print("\nFor details about installing the optional dependencies, please visit:", file=file, flush=True)
print(
fprint(f"{k} version: {v}", file=file)
fprint("\nFor details about installing the optional dependencies, please visit:", file=file)
fprint(
" https://monai.readthedocs.io/en/latest/installation.html#installing-the-recommended-dependencies\n",
file=file,
flush=True,
Expand Down Expand Up @@ -191,10 +199,10 @@ def print_system_info(file: TextIO = sys.stdout) -> None:
file: `print()` text stream file. Defaults to `sys.stdout`.
"""
if not has_psutil:
print("`psutil` required for `print_system_info`", file=file, flush=True)
fprint("`psutil` required for `print_system_info`", file=file)
else:
for k, v in get_system_info().items():
print(f"{k}: {v}", file=file, flush=True)
fprint(f"{k}: {v}", file=file)


def get_gpu_info() -> OrderedDict:
Expand Down Expand Up @@ -239,7 +247,7 @@ def print_gpu_info(file: TextIO = sys.stdout) -> None:
file: `print()` text stream file. Defaults to `sys.stdout`.
"""
for k, v in get_gpu_info().items():
print(f"{k}: {v}", file=file, flush=True)
fprint(f"{k}: {v}", file=file)


def print_debug_info(file: TextIO = sys.stdout) -> None:
Expand All @@ -249,26 +257,19 @@ def print_debug_info(file: TextIO = sys.stdout) -> None:
Args:
file: `print()` text stream file. Defaults to `sys.stdout`.
"""
print("================================", file=file, flush=True)
print("Printing MONAI config...", file=file, flush=True)
print("================================", file=file, flush=True)
fprint("================================", file=file)
fprint("Printing MONAI config...", file=file)
fprint("================================", file=file)
print_config(file)
print("\n================================", file=file, flush=True)
print("Printing system config...")
print("================================", file=file, flush=True)
fprint("\n================================", file=file)
fprint("Printing system config...", file=file)
fprint("================================", file=file)
print_system_info(file)
print("\n================================", file=file, flush=True)
print("Printing GPU config...")
print("================================", file=file, flush=True)
fprint("\n================================", file=file)
fprint("Printing GPU config...", file=file)
fprint("================================", file=file)
print_gpu_info(file)


@deprecated(since="1.4.0", removed="1.6.0", msg_suffix="Please use `monai.utils.enums.IgniteInfo` instead.")
class IgniteInfo:
"""Deprecated Import of IgniteInfo enum, which was moved to `monai.utils.enums.IgniteInfo`."""

OPT_IMPORT_VERSION = _IgniteInfo.OPT_IMPORT_VERSION


if __name__ == "__main__":
print_debug_info()
Loading
Loading