nvitop

XuehaiPanApache-2.0活跃维护

像 htop 一样在终端里实时查看 NVIDIA GPU 的进程占用、显存和利用率,还能导出指标接入 Grafana 做监控面板。

An interactive NVIDIA-GPU process viewer and beyond, the one-stop solution for GPU process management.

v1.7.2发布于 2026-10-26 04:38 UTC7,245star +3 / 7 天254fork同步于 2026-11-10 17:33 UTC

怎么上手

由 README 提炼,执行前请确认
pip3 install --upgrade nvitop
nvitop
硬件要求按 README 说明

README 未说明具体显存要求;需有 NVIDIA GPU 及驱动,通过 NVML 查询设备,支持 MIG 设备;README 称可在 Linux 和 Windows 上运行。

需要 CUDA有 Docker 镜像
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

交互式 NVIDIA GPU 进程查看器,比 nvidia-smi 更直观地监控和管理 GPU 进程

像 htop 一样在终端里实时查看 NVIDIA GPU 的进程占用、显存和利用率,还能导出指标接入 Grafana 做监控面板。

核心能力

  • 直接调用 NVML Python 绑定查询设备状态,不解析 nvidia-smi 输出
  • 监控模式提供条形图、历史曲线、进程排序与过滤
  • 支持树状视图查看 GPU 进程及其父进程关系
  • 按键即可向进程发送中断、终止或 kill 信号
  • 附带 nvisel 工具按 CUDA_VISIBLE_DEVICES 选择设备

容易踩的坑

安装后若提示 nvitop: command not found,需把 Python 脚本目录(如 ~/.local/bin)加入 PATH,或改用 python3 -m nvitop;README 建议在隔离虚拟环境中安装;终端不支持 Unicode 时需加 -U 使用 ASCII 字符。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v1.7.2
  1. v1.7.2nvitop v1.7.2最新正式版2026-10-26 · 2026-10-26 04:38 UTC

    What's Changed

    Added

    • Add nvidia-ml-py 13.610.43 to support list by @XuehaiPan.
    • Add nvidia-ml-py 13.615.71 to support list by @XuehaiPan.
    • Add a responsive Rich GPU dashboard example with host metrics, MIG support, and GPU process snapshots by @XuehaiPan in #231.

    Fixed

    • Guard NVML field queries against a buffer overrun in NVIDIA driver 595.91.07 that can crash nvitop-exporter while collecting NVLink throughput by @XuehaiPan in #232.
    • Fix shared-memory accounting on unified-memory devices (e.g., NVIDIA DGX Spark and RTX Spark N1X) to include reclaimable cache in free memory and calculate used memory from available capacity by @johnnynunez in #234.

    Full Changelog: https://github.com/XuehaiPan/nvitop/compare/v1.7.1...v1.7.2

  2. v1.7.1nvitop v1.7.12026-07-10 · 2026-07-10 11:24 UTC
    查看更新说明

    What's Changed

    Added

    • Add a minimal stdlib HTTP(S) GPU dashboard built on nvitop.collect_in_background by @XuehaiPan in #218.
    • Add inline script metadata (PEP 723) to the runnable examples/ scripts so each runs directly from its URL with uv run without cloning the repository by @XuehaiPan in #224.

    Fixed

    • Fix an intermittent SIGSEGV at interpreter exit where the atexit nvmlShutdown() raced in-flight NVML queries from background threads by @XuehaiPan in #223. Issued by @zengchang233 in #222.

    Full Changelog: https://github.com/XuehaiPan/nvitop/compare/v1.7.0...v1.7.1

  3. v1.7.0nvitop v1.7.02026-05-16 · 2026-05-16 07:48 UTC
    查看更新说明

    What's Changed

    Added

    • Add nvidia-ml-py 13.595.45 to support list by @XuehaiPan.
    • Add support for open kernel-module driver packages (e.g., nvidia-driver-595-open) in install-nvidia-driver.sh with new --proprietary and --open flags by @XuehaiPan.
    • Add TLS and mutual TLS (mTLS) support for nvitop-exporter via new --certfile, --keyfile, --client-cafile, --client-capath, and --client-auth-required CLI flags by @XuehaiPan in #213. Issued by @StefanSander3 in #131.
    • Add --readonly CLI flag (and equivalent NVITOP_MONITOR_MODE="readonly" env token) for monitor mode that disables all process-mutating shortcuts (Ctrl-c / T / K / I / k) by @XuehaiPan in #214.
    • Add examples/ directory with self-contained runnable scripts by @XuehaiPan in #216.

    Changed

    • Bump minimum prometheus-client version to 0.19.0 for nvitop-exporter (required for TLS support) by @XuehaiPan in #213.

    Fixed

    • Propagate need_redraw=True to parent if self.need_redraw has been already updated to True to avoid missing redraws by @XuehaiPan.

    Removed

    • Relocate the nvitop.callbacks subpackage (Keras / Lightning / TensorBoard GpuStatsLogger and add_scalar_dict) to examples/ml-framework-callbacks/ by @XuehaiPan in #216.

    Full Changelog: https://github.com/XuehaiPan/nvitop/compare/v1.6.2...v1.7.0

  4. v1.6.2nvitop v1.6.22026-01-27 · 2026-01-27 17:06 UTC
    查看更新说明

    What's Changed

    Added

    • Add nvidia-ml-py 13.580.126 and 13.590.44 and 13.590.48 to support list by @XuehaiPan.

    Fixed

    • Fix TUI column alignment for device with power limit >= 1000W by @XuehaiPan.
    • Fix grammar and typos in documentation by @XuehaiPan.

    Full Changelog: https://github.com/XuehaiPan/nvitop/compare/v1.6.1...v1.6.2

  5. v1.6.1nvitop v1.6.12025-12-08 · 2025-12-08 03:46 UTC
    查看更新说明

    What's Changed

    • Support devices with unified memory (e.g., NVIDIA Spark) by @XuehaiPan in #195. Issued by @FlorinAndrei.

    Full Changelog: https://github.com/XuehaiPan/nvitop/compare/v1.6.0...v1.6.1

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    nvitop

    Python 3.8+ PyPI conda-forge Documentation Status Downloads GitHub Repo Stars License

    An interactive NVIDIA-GPU process viewer and beyond, the one-stop solution for GPU process management. The full API references host at https://nvitop.readthedocs.io.

    Table of Contents


    nvitop is an interactive NVIDIA device and process monitoring tool. It has a colorful and informative interface that continuously updates the status of the devices and processes. As a resource monitor, it includes many features and options, such as tree-view, environment variable viewing, process filtering, process metrics monitoring, etc. Beyond that, the package also ships a CUDA device selection tool nvisel for deep learning researchers. It also provides handy APIs that allow developers to write their own monitoring tools. Please refer to section More than a Monitor and the full API references at https://nvitop.readthedocs.io for more information.


    Features

    • Informative and fancy output: show more information than nvidia-smi with colorized fancy box drawing.
    • Monitor mode: can run as a resource monitor, rather than print the results only once.
      • bar charts and history graphs
      • process sorting
      • process filtering
      • send signals to processes with a keystroke
      • tree-view screen for GPU processes and their parent processes
      • environment variable screen
      • help screen
      • mouse support
    • Interactive: responsive for user input (from keyboard and/or mouse) in monitor mode. (vs. gpustat & py3nvml)
    • Efficient:
      • query device status using NVML Python bindings directly, instead of parsing the output of nvidia-smi. (vs. nvidia-htop)
      • support sparse query and cache results with TTLCache from cachetools. (vs. gpustat)
      • display information using the curses library rather than print with ANSI escape codes. (vs. py3nvml)
      • asynchronously gather information using multi-threading and correspond to user input much faster. (vs. nvtop)
    • Portable: work on both Linux and Windows.
      • get host process information using the cross-platform library psutil instead of calling ps -p <pid> in a subprocess. (vs. nvidia-htop & py3nvml)
      • written in pure Python, easy to install with pip. (vs. nvtop)
    • Integrable: easy to integrate into other applications, more than monitoring. (vs. nvidia-htop & nvtop)

    Requirements

    • Python 3.8+
    • NVIDIA Management Library (NVML)
    • nvidia-ml-py
    • psutil
    • curses* (with libncursesw)

    NOTE: The NVIDIA Management Library (NVML) is a C-based programmatic interface for monitoring and managing various states. The runtime version of the NVML library ships with the NVIDIA display driver (available at Download Drivers | NVIDIA), or can be downloaded as part of the NVIDIA CUDA Toolkit (available at CUDA Toolkit | NVIDIA Developer). The lists of OS platforms and NVIDIA-GPUs supported by the NVML library can be found in the NVML API Reference.

    This repository contains a Bash script to install/upgrade the NVIDIA drivers for Ubuntu Linux. For example:

    git clone --depth=1 https://github.com/XuehaiPan/nvitop.git && cd nvitop
    
    # Change to tty3 console (required for desktop users with GUI (tty2))
    # Optional for SSH users
    sudo chvt 3  # or use keyboard shortcut: Ctrl-LeftAlt-F3
    
    bash install-nvidia-driver.sh --package=nvidia-driver-595  # install the R595 driver from ppa:graphics-drivers
    bash install-nvidia-driver.sh --latest                     # install the latest driver from ppa:graphics-drivers
    bash install-nvidia-driver.sh --latest --open              # install the latest open-kernel-module driver
    bash install-nvidia-driver.sh --latest --server            # install the latest server driver
    bash install-nvidia-driver.sh --latest --server --open     # install the latest server open-kernel-module driver
    

    Run bash install-nvidia-driver.sh --help for more information.

    The installer preserves the installed driver's standard/server family and proprietary/open kernel-module flavor by default. Use --server to select server packages; without --latest, it selects the server counterpart of the installed major version. With --package=PKG, the family is detected from the package name, so this option can also switch back to a standard driver. --upgrade-only keeps the installed package and rejects family or flavor changes.

    The installer stops active nvidia-dcgm, nvidia-fabricmanager, and nvidia-persistenced services alongside display manager services before unloading the driver. Services stopped by the installer are restarted on completion, failure, or interruption; missing or inactive services are skipped.

    * The curses library is a built-in module of Python on Unix-like systems, and it is supported by a third-party package called windows-curses on Windows using PDCurses. Inconsistent behavior of nvitop may occur on different terminal emulators on Windows, such as missing mouse support.


    Installation

    It is highly recommended to install nvitop in an isolated virtual environment. Simple installation and run via uvx (a.k.a. uv tool run) or pipx:

    uvx nvitop
    # or
    pipx run nvitop
    

    You can also set this command as an alias in your shell startup file, e.g.:

    # For Bash
    echo 'alias nvitop="uvx nvitop"' >> ~/.bashrc
    
    # For Zsh
    echo 'alias nvitop="uvx nvitop"' >> ~/.zshrc
    
    # For Fish
    mkdir -p ~/.config/fish
    echo 'alias nvitop="uvx nvitop"' >> ~/.config/fish/config.fish
    
    # For PowerShell
    New-Item -Path (Split-Path -Parent -Path $PROFILE.CurrentUserAllHosts) -ItemType Directory -Force
    'Function nvitop { uvx nvitop @Args }' >> $PROFILE.CurrentUserAllHosts
    

    or

    # For Bash
    echo 'alias nvitop="pipx run nvitop"' >> ~/.bashrc
    
    # For Zsh
    echo 'alias nvitop="pipx run nvitop"' >> ~/.zshrc
    
    # For Fish
    mkdir -p ~/.config/fish
    echo 'alias nvitop="pipx run nvitop"' >> ~/.config/fish/config.fish
    
    # For PowerShell
    New-Item -Path (Split-Path -Parent -Path $PROFILE.CurrentUserAllHosts) -ItemType Directory -Force
    'Function nvitop { pipx run nvitop @Args }' >> $PROFILE.CurrentUserAllHosts
    

    Install from PyPI (PyPI):

    pip3 install --upgrade nvitop
    

    Install from conda-forge (conda-forge):

    conda install -c conda-forge nvitop
    

    Install the latest version from GitHub (Commit Count):

    pip3 install --upgrade pip setuptools
    pip3 install git+https://github.com/XuehaiPan/nvitop.git
    

    Or, clone this repo and install manually:

    git clone --depth=1 https://github.com/XuehaiPan/nvitop.git && cd nvitop
    pip3 install .
    

    NOTE: If you encounter the "nvitop: command not found" error after installation, please check whether you have added the Python console script path (e.g., "${HOME}/.local/bin") to your PATH environment variable. Alternatively, you can use python3 -m nvitop.


    Usage

    Device and Process Status

    Query the device and process status. The output is similar to nvidia-smi, but has been enriched and colorized.

    # Query the status of all devices
    $ nvitop -1  # or use `python3 -m nvitop -1`
    
    # Specify query devices (by integer indices)
    $ nvitop -1 -o 0 1  # only show <GPU 0> and <GPU 1>
    
    # Only show devices in `CUDA_VISIBLE_DEVICES` (by integer indices or UUID strings)
    $ nvitop -1 -ov
    
    # Only show GPU processes with the compute context (type: 'C' or 'C+G')
    $ nvitop -1 -c
    

    When the -1 switch is on, the result will be displayed ONLY ONCE (same as the default behavior of nvidia-smi). This is much faster and has lower resource usage. See Command Line Options for more command options.

    There is also a CLI tool called nvisel that ships with the nvitop PyPI package. See CUDA Visible Devices Selection Tool for more information.

    Resource Monitor

    Run as a resource monitor:

    # Monitor mode (when the display mode is omitted, `NVITOP_MONITOR_MODE` will be used)
    $ nvitop  # or use `python3 -m nvitop`
    
    # Automatically configure the display mode according to the terminal size
    $ nvitop -m auto     # shortcut: `a` key
    
    # Arbitrarily display as `full` mode
    $ nvitop -m full     # shortcut: `f` key
    
    # Arbitrarily display as `compact` mode
    $ nvitop -m compact  # shortcut: `c` key
    
    # Specify query devices (by integer indices)
    $ nvitop -o 0 1  # only show <GPU 0> and <GPU 1>
    
    # Only show devices in `CUDA_VISIBLE_DEVICES` (by integer indices or UUID strings)
    $ nvitop -ov
    
    # Only show GPU processes with the compute context (type: 'C' or 'C+G')
    $ nvitop -c
    
    # Use ASCII characters only
    $ nvitop -U  # useful for terminals without Unicode support
    
    # For light terminals
    $ nvitop --light
    
    # For spectrum-like bar charts (requires the terminal supports 256-color)
    $ nvitop --colorful
    

    You can configure the default monitor mode with the NVITOP_MONITOR_MODE environment variable (default auto if not set). See Command Line Options and Environment Variables for more command options.

    In monitor mode, you can use Ctrl-c / T / K keys to interrupt / terminate / kill a process. And it's recommended to terminate or kill a process in the tree-view screen (shortcut: t). For normal users, nvitop will shallow other users' processes (in low-intensity colors). For system administrators, you can use sudo nvitop to terminate other users' processes.

    To run nvitop as a viewer only and disable all process-mutating shortcuts, pass --readonly (or set NVITOP_MONITOR_MODE="readonly"). The signal keys above become no-ops, the on-screen "Press ^C(INT)/T(TERM)/K(KILL) to send signals" hint is hidden, and the corresponding rows in the help screen are dimmed. Use this when sharing a session over SSH, demoing on a multi-tenant box, or wrapping nvitop in a non-admin alias.

    Also, to enter the process metrics screen, select a process and then press the Enter / Return key . nvitop dynamically displays the process metrics with live graphs.

    Press h for help or q to return to the terminal. See Keybindings for Monitor Mode for more shortcuts.

    For Docker Users

    Build and run the Docker image with nvidia-container-toolkit:

    docker run -it --rm --runtime=nvidia --gpus=all --pid=host ghcr.io/xuehaipan/nvitop:latest
    

    NOTE: Don't forget to add the --pid=host option when running the container.

    If you only need to set up the Grafana dashboard, you can start a dashboard at http://localhost:3000 with the following command:

    docker compose --project-directory=nvitop-exporter/grafana up --build --detach
    

    See nvitop-exporter for more details.

    For SSH Users

    Run nvitop directly on the SSH session instead of a login shell:

    ssh user@host -t nvitop                 # installed by `sudo pip3 install ...`
    ssh user@host -t '~/.local/bin/nvitop'  # installed by `pip3 install --user ...`
    

    NOTE: Users need to add the -t option to allocate a pseudo-terminal over the SSH session for monitor mode.

    Command Line Options and Environment Variables

    Type nvitop --help for more command options:

    usage: nvitop [--help] [--version] [--once | --monitor [{auto,full,compact}]]
                  [--interval SEC] [--no-unicode] [--readonly] [--colorful]
                  [--force-color] [--light] [--gpu-util-thresh th1 th2]
                  [--mem-util-thresh th1 th2] [--only INDEX [INDEX ...]]
                  [--only-visible] [--compute] [--only-compute] [--graphics]
                  [--only-graphics] [--user [USERNAME ...]] [--pid PID [PID ...]]
    
    An interactive NVIDIA-GPU process viewer.
    
    options:
      --help, -h            Show this help message and exit.
      --version, -V         Show nvitop's version number and exit.
      --once, -1            Report query data only once.
      --monitor, -m [{auto,full,compact}]
                            Run as a resource monitor. Continuously report query data and handle user inputs.
                            If the argument is omitted, the value from `NVITOP_MONITOR_MODE` will be used.
                            (default fallback mode: auto)
      --interval SEC        Process status update interval in seconds. (default: 2)
      --no-unicode, --ascii, -U
                            Use ASCII characters only, which is useful for terminals without Unicode support.
      --readonly            Disable all system and process changing features (e.g., terminating processes).
                            Set variable `NVITOP_MONITOR_MODE="readonly"` for convenience.
    
    coloring:
      --colorful            Use gradient colors to get spectrum-like bar charts.
                            Set variable `NVITOP_MONITOR_MODE="colorful"` for convenience.
                            This option is only available when the terminal supports 256 colors.
                            You may need to set environment variable `TERM="xterm-256color"`. Note that the
                            terminal multiplexer, such as `tmux`, may override the `TERM` variable.
      --force-color         Force colorize even when `stdout` is not a TTY terminal.
      --light               Tweak visual results for light theme terminals in monitor mode.
                            Set variable `NVITOP_MONITOR_MODE="light"` on light terminals for convenience.
      --gpu-util-thresh th1 th2
                            Thresholds of GPU utilization to determine the load intensity.
                            Coloring rules: light < th1 % <= moderate < th2 % <= heavy.
                            ( 1 <= th1 < th2 <= 99, defaults: 10 75 )
      --mem-util-thresh th1 th2
                            Thresholds of GPU memory percent to determine the load intensity.
                            Coloring rules: light < th1 % <= moderate < th2 % <= heavy.
                            ( 1 <= th1 < th2 <= 99, defaults: 10 80 )
    
    device filtering:
      --only, -o INDEX [INDEX ...]
                            Only show the specified devices, suppress option `--only-visible`.
      --only-visible, -ov   Only show devices in the `CUDA_VISIBLE_DEVICES` environment variable.
    
    process filtering:
      --compute, -c         Only show GPU processes with the compute context. (type: 'C' or 'C+G')
      --only-compute, -C    Only show GPU processes exactly with the compute context. (type: 'C' only)
      --graphics, -g        Only show GPU processes with the graphics context. (type: 'G' or 'C+G')
      --only-graphics, -G   Only show GPU processes exactly with the graphics context. (type: 'G' only)
      --user, -u [USERNAME ...]
                            Only show processes of the given users (or `$USER` for no argument).
      --pid, -p PID [PID ...]
                            Only show processes of the given PIDs.
    

    nvitop can accept the following environment variables for monitor mode:

    NameDescriptionValid ValuesDefault Value
    NVITOP_MONITOR_MODEThe default display mode (a comma-separated string)auto / full / compactplain / colorfuldark / lightreadonly (disables process-mutating shortcuts)auto,plain,dark
    NVITOP_GPU_UTILIZATION_THRESHOLDSThresholds of GPU utilization10,75 , 1,99, ...10,75
    NVITOP_MEMORY_UTILIZATION_THRESHOLDSThresholds of GPU memory percent10,80 , 1,99, ...10,80
    LOGLEVELLog level for log messagesDEBUG , INFO, WARNING, ...WARNING

    For example:

    # Replace the following export statements if you are not using Bash / Zsh
    export NVITOP_MONITOR_MODE="full,light"
    
    # Full monitor mode with light terminal tweaks
    nvitop
    

    For convenience, you can add these environment variables to your shell startup file, e.g.:

    # For Bash
    echo 'export NVITOP_MONITOR_MODE="full"' >> ~/.bashrc
    
    # For Zsh
    echo 'export NVITOP_MONITOR_MODE="full"' >> ~/.zshrc
    
    # For Fish
    echo 'set -gx NVITOP_MONITOR_MODE "full"' >> ~/.config/fish/config.fish
    
    # For PowerShell
    '$Env:NVITOP_MONITOR_MODE = "full"' >> $PROFILE.CurrentUserAllHosts
    
    Keybindings for Monitor Mode
    KeyBinding
    qQuit and return to the terminal.
    h / ?Go to the help screen.
    a / f / cChange the display mode to auto / full / compact.
    r / <C-r> / <F5>Force refresh the window.
    <Up> / <Down><A-k> / <A-j><Tab> / <S-Tab><Wheel>Select and highlight a process.
    <Left> / <Right><A-h> / <A-l><S-Wheel>Scroll the host information of processes.
    <Home>Select the first process.
    <End>Select the last process.
    <C-a>^Scroll left to the beginning of the process entry (i.e. beginning of line).
    <C-e>$Scroll right to the end of the process entry (i.e. end of line).
    <PageUp> / <PageDown> <A-K> / <A-J>[ / ]scroll entire screen (for large amounts of processes).
    <Space>Tag/untag current process.
    <Esc>Clear process selection.
    <C-c>ISend signal.SIGINT to the selected process (interrupt). (disabled under --readonly)
    TSend signal.SIGTERM to the selected process (terminate). (disabled under --readonly)
    KSend signal.SIGKILL to the selected process (kill). (disabled under --readonly)
    eShow process environment.
    tToggle tree-view screen.
    <Enter>Show process metrics.
    , / .Select the sort column.
    /Reverse the sort order.
    on (oN)Sort processes in the natural order, i.e., in ascending (descending) order of GPU.
    ou (oU)Sort processes by USER in ascending (descending) order.
    op (oP)Sort processes by PID in descending (ascending) order.
    og (oG)Sort processes by GPU-MEM in descending (ascending) order.
    os (oS)Sort processes by SM% in descending (ascending) order.
    oc (oC)Sort processes by CPU% in descending (ascending) order.
    om (oM)Sort processes by MEM% in descending (ascending) order.
    ot (oT)Sort processes by TIME in descending (ascending) order.

    HINT: It's recommended to terminate or kill a process in the tree-view screen (shortcut: t).


    CUDA Visible Devices Selection Tool

    Automatically select CUDA_VISIBLE_DEVICES from the given criteria. Example usage of the CLI tool:

    # All devices but sorted
    $ nvisel       # or use `python3 -m nvitop.select`
    6,5,4,3,2,1,0,7,8
    
    # A simple example to select 4 devices
    $ nvisel -n 4  # or use `python3 -m nvitop.select -n 4`
    6,5,4,3
    
    # Select available devices that satisfy the given constraints
    $ nvisel --min-count 2 --max-count 3 --min-free-memory 5GiB --max-gpu-utilization 60
    6,5,4
    
    # Set `CUDA_VISIBLE_DEVICES` environment variable using `nvisel`
    $ export CUDA_DEVICE_ORDER="PCI_BUS_ID" CUDA_VISIBLE_DEVICES="$(nvisel -c 1 -f 10GiB)"
    CUDA_VISIBLE_DEVICES="6,5,4,3,2,1,0"
    
    # Use UUID strings in `CUDA_VISIBLE_DEVICES` environment variable
    $ export CUDA_VISIBLE_DEVICES="$(nvisel -O uuid -c 2 -f 5000M)"
    CUDA_VISIBLE_DEVICES="GPU-849d5a8d-610e-eeea-1fd4-81ff44a23794,GPU-18ef14e9-dec6-1d7e-1284-3010c6ce98b1,GPU-96de99c9-d68f-84c8-424c-7c75e59cc0a0,GPU-2428d171-8684-5b64-830c-435cd972ec4a,GPU-6d2a57c9-7783-44bb-9f53-13f36282830a,GPU-f8e5a624-2c7e-417c-e647-b764d26d4733,GPU-f9ca790e-683e-3d56-00ba-8f654e977e02"
    
    # Pipe output to other shell utilities
    $ nvisel --newline -O uuid -C 6 -f 8GiB
    GPU-849d5a8d-610e-eeea-1fd4-81ff44a23794
    GPU-18ef14e9-dec6-1d7e-1284-3010c6ce98b1
    GPU-96de99c9-d68f-84c8-424c-7c75e59cc0a0
    GPU-2428d171-8684-5b64-830c-435cd972ec4a
    GPU-6d2a57c9-7783-44bb-9f53-13f36282830a
    GPU-f8e5a624-2c7e-417c-e647-b764d26d4733
    $ nvisel -0 -O uuid -c 2 -f 4GiB | xargs -0 -I {} nvidia-smi --id={} --query-gpu=index,memory.free --format=csv
    CUDA_VISIBLE_DEVICES="GPU-849d5a8d-610e-eeea-1fd4-81ff44a23794,GPU-18ef14e9-dec6-1d7e-1284-3010c6ce98b1,GPU-96de99c9-d68f-84c8-424c-7c75e59cc0a0,GPU-2428d171-8684-5b64-830c-435cd972ec4a,GPU-6d2a57c9-7783-44bb-9f53-13f36282830a,GPU-f8e5a624-2c7e-417c-e647-b764d26d4733,GPU-f9ca790e-683e-3d56-00ba-8f654e977e02"
    index, memory.free [MiB]
    6, 11018 MiB
    index, memory.free [MiB]
    5, 11018 MiB
    index, memory.free [MiB]
    4, 11018 MiB
    index, memory.free [MiB]
    3, 11018 MiB
    index, memory.free [MiB]
    2, 11018 MiB
    index, memory.free [MiB]
    1, 11018 MiB
    index, memory.free [MiB]
    0, 11018 MiB
    
    # Normalize the `CUDA_VISIBLE_DEVICES` environment variable (e.g. convert UUIDs to indices or get full UUIDs for an abbreviated form)
    $ nvisel -i "GPU-18ef14e9,GPU-849d5a8d" -S
    5,6
    $ nvisel -i "GPU-18ef14e9,GPU-849d5a8d" -S -O uuid --newline
    GPU-18ef14e9-dec6-1d7e-1284-3010c6ce98b1
    GPU-849d5a8d-610e-eeea-1fd4-81ff44a23794
    

    You can also integrate nvisel into your training script like this:

    # Put this at the top of the Python script
    import os
    from nvitop import select_devices
    
    os.environ['CUDA_VISIBLE_DEVICES'] = ','.join(
        select_devices(format='uuid', min_count=4, min_free_memory='8GiB')
    )
    

    Type nvisel --help for more command options:

    usage: nvisel [--help] [--version]
                  [--inherit [CUDA_VISIBLE_DEVICES]] [--account-as-free [USERNAME ...]]
                  [--min-count N] [--max-count N] [--count N]
                  [--min-free-memory SIZE] [--min-total-memory SIZE]
                  [--max-gpu-utilization RATE] [--max-memory-utilization RATE]
                  [--tolerance TOL]
                  [--format FORMAT] [--sep SEP | --newline | --null] [--no-sort]
    
    CUDA visible devices selection tool.
    
    options:
      --help, -h            Show this help message and exit.
      --version, -V         Show nvisel's version number and exit.
    
    constraints:
      --inherit [CUDA_VISIBLE_DEVICES], -i [CUDA_VISIBLE_DEVICES]
                            Inherit the given `CUDA_VISIBLE_DEVICES`. If the argument is omitted, use the
                            value from the environment. This means selecting a subset of the currently
                            CUDA-visible devices.
      --account-as-free [USERNAME ...]
                            Account the used GPU memory of the given users as free memory.
                            If this option is specified but without argument, `$USER` will be used.
      --min-count N, -c N   Minimum number of devices to select. (default: 0)
                            The tool will fail (exit non-zero) if the requested resource is not available.
      --max-count N, -C N   Maximum number of devices to select. (default: all devices)
      --count N, -n N       Overriding both `--min-count N` and `--max-count N`.
      --min-free-memory SIZE, -f SIZE
                            Minimum free memory of devices to select. (example value: 4GiB)
                            If this constraint is given, check against all devices.
      --min-total-memory SIZE, -t SIZE
                            Minimum total memory of devices to select. (example value: 10GiB)
                            If this constraint is given, check against all devices.
      --max-gpu-utilization RATE, -G RATE
                            Maximum GPU utilization rate of devices to select. (example value: 30)
                            If this constraint is given, check against all devices.
      --max-memory-utilization RATE, -M RATE
                            Maximum memory bandwidth utilization rate of devices to select. (example value: 50)
                            If this constraint is given, check against all devices.
      --tolerance TOL, --tol TOL
                            The constraints tolerance (in percentage). (default: 0, i.e., strict)
                            This option can loose the constraints if the requested resource is not available.
                            For example, set `--tolerance=20` will accept a device with only 4GiB of free
                            memory when set `--min-free-memory=5GiB`.
    
    formatting:
      --format FORMAT, -O FORMAT
                            The output format of the selected device identifiers. (default: index)
                            If any MIG device found, the output format will be fallback to `uuid`.
      --sep SEP, --separator SEP, -s SEP
                            Separator for the output. (default: ',')
      --newline             Use newline character as separator for the output, equivalent to `--sep=$'\n'`.
      --null, -0            Use null character ('\x00') as separator for the output. This option corresponds
                            to the `-0` option of `xargs`.
      --no-sort, -S         Do not sort the device by memory usage and GPU utilization.
    

    More than a Monitor

    nvitop can be easily integrated into other applications. You can use nvitop to make your own monitoring tools. The full API references host at https://nvitop.readthedocs.io. Runnable reference scripts live in examples/.

    Quick Start

    A minimal script to monitor the GPU devices based on APIs from nvitop:

    from nvitop import Device
    
    devices = Device.all()  # or `Device.cuda.all()` to use CUDA ordinal instead
    for device in devices:
        processes = device.processes()  # type: Dict[int, GpuProcess]
        sorted_pids = sorted(processes.keys())
    
        print(device)
        print(f'  - Fan speed:       {device.fan_speed()}%')
        print(f'  - Temperature:     {device.temperature()}C')
        print(f'  - GPU utilization: {device.gpu_utilization()}%')
        print(f'  - Total memory:    {device.memory_total_human()}')
        print(f'  - Used memory:     {device.memory_used_human()}')
        print(f'  - Free memory:     {device.memory_free_human()}')
        print(f'  - Processes ({len(processes)}): {sorted_pids}')
        for pid in sorted_pids:
            print(f'    - {processes[pid]}')
        print('-' * 120)
    

    Another more advanced approach with coloring:

    import time
    
    from nvitop import Device, GpuProcess, NA, colored
    
    print(colored(time.strftime('%a %b %d %H:%M:%S %Y'), color='red', attrs=('bold',)))
    
    devices = Device.cuda.all()  # or `Device.all()` to use NVML ordinal instead
    separator = False
    for device in devices:
        processes = device.processes()  # type: Dict[int, GpuProcess]
    
        print(colored(str(device), color='green', attrs=('bold',)))
        print(colored('  - Fan speed:       ', color='blue', attrs=('bold',)) + f'{device.fan_speed()}%')
        print(colored('  - Temperature:     ', color='blue', attrs=('bold',)) + f'{device.temperature()}C')
        print(colored('  - GPU utilization: ', color='blue', attrs=('bold',)) + f'{device.gpu_utilization()}%')
        print(colored('  - Total memory:    ', color='blue', attrs=('bold',)) + f'{device.memory_total_human()}')
        print(colored('  - Used memory:     ', color='blue', attrs=('bold',)) + f'{device.memory_used_human()}')
        print(colored('  - Free memory:     ', color='blue', attrs=('bold',)) + f'{device.memory_free_human()}')
        if len(processes) > 0:
            processes = GpuProcess.take_snapshots(processes.values(), failsafe=True)
            processes.sort(key=lambda process: (process.username, process.pid))
    
            print(colored(f'  - Processes ({len(processes)}):', color='blue', attrs=('bold',)))
            fmt = '    {pid:<5}  {username:<8} {cpu:>5}  {host_memory:>8} {time:>8}  {gpu_memory:>8}  {sm:>3}  {command:<}'.format
            print(colored(fmt(pid='PID', username='USERNAME',
                              cpu='CPU%', host_memory='HOST-MEM', time='TIME',
                              gpu_memory='GPU-MEM', sm='SM%',
                              command='COMMAND'),
                          attrs=('bold',)))
            for snapshot in processes:
                print(fmt(pid=snapshot.pid,
                          username=snapshot.username[:7] + ('+' if len(snapshot.username) > 8 else snapshot.username[7:8]),
                          cpu=snapshot.cpu_percent, host_memory=snapshot.host_memory_human,
                          time=snapshot.running_time_human,
                          gpu_memory=(snapshot.gpu_memory_human if snapshot.gpu_memory_human is not NA else 'WDDM:N/A'),
                          sm=snapshot.gpu_sm_utilization,
                          command=snapshot.command))
        else:
            print(colored('  - No Running Processes', attrs=('bold',)))
    
        if separator:
            print('-' * 120)
        separator = True
    

    Status Snapshot

    nvitop provides a helper function take_snapshots to retrieve the status of both GPU devices and GPU processes at once. You can type help(nvitop.take_snapshots) in Python REPL for detailed documentation.

    In [1]: from nvitop import take_snapshots, Device
       ...: import os
       ...: os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID'
       ...: os.environ['CUDA_VISIBLE_DEVICES'] = '1,0'  # comma-separated integers or UUID strings
    
    In [2]: take_snapshots()  # equivalent to `take_snapshots(Device.all())`
    Out[2]:
    SnapshotResult(
        devices=[
            DeviceSnapshot(
                real=Device(index=0, ...),
                ...
            ),
            ...
        ],
        gpu_processes=[
            GpuProcessSnapshot(
                real=GpuProcess(pid=xxxxxx, device=Device(index=0, ...), ...),
                ...
            ),
            ...
        ]
    )
    
    In [3]: device_snapshots, gpu_process_snapshots = take_snapshots(Device.all())  # type: Tuple[List[DeviceSnapshot], List[GpuProcessSnapshot]]
    
    In [4]: device_snapshots, _ = take_snapshots(gpu_processes=False)  # ignore process snapshots
    
    In [5]: take_snapshots(Device.cuda.all())  # use CUDA device enumeration
    Out[5]:
    SnapshotResult(
        devices=[
            CudaDeviceSnapshot(
                real=CudaDevice(cuda_index=0, nvml_index=1, ...),
                ...
            ),
            CudaDeviceSnapshot(
                real=CudaDevice(cuda_index=1, nvml_index=0, ...),
                ...
            ),
        ],
        gpu_processes=[
            GpuProcessSnapshot(
                real=GpuProcess(pid=xxxxxx, device=CudaDevice(cuda_index=0, ...), ...),
                ...
            ),
            ...
        ]
    )
    
    In [6]: take_snapshots(Device.cuda(1))  # <CUDA 1> only
    Out[6]:
    SnapshotResult(
        devices=[
            CudaDeviceSnapshot(
                real=CudaDevice(cuda_index=1, nvml_index=0, ...),
                ...
            )
        ],
        gpu_processes=[
            GpuProcessSnapshot(
                real=GpuProcess(pid=xxxxxx, device=CudaDevice(cuda_index=1, ...), ...),
                ...
            ),
            ...
        ]
    )
    

    Please refer to section Low-level APIs for more information.


    Resource Metric Collector

    ResourceMetricCollector is a class that collects resource metrics for host, GPUs and processes running on the GPUs. All metrics will be collected in an asynchronous manner. You can type help(nvitop.ResourceMetricCollector) in Python REPL for detailed documentation.

    In [1]: from nvitop import ResourceMetricCollector, Device
       ...: import os
       ...: os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID'
       ...: os.environ['CUDA_VISIBLE_DEVICES'] = '3,2,1,0'  # comma-separated integers or UUID strings
    
    In [2]: collector = ResourceMetricCollector()                                   # log all devices and descendant processes of the current process on the GPUs
    In [3]: collector = ResourceMetricCollector(root_pids={1})                      # log all devices and all GPU processes
    In [4]: collector = ResourceMetricCollector(devices=Device(0), root_pids={1})   # log <GPU 0> and all GPU processes on <GPU 0>
    In [5]: collector = ResourceMetricCollector(devices=Device.cuda.all())          # use the CUDA ordinal
    
    In [6]: with collector(tag='<tag>'):
       ...:     # Do something
       ...:     collector.collect()  # -> Dict[str, float]
    # key -> '<tag>/<scope>/<metric (unit)>/<mean/min/max>'
    {
        '<tag>/host/cpu_percent (%)/mean': 8.967849777683456,
        '<tag>/host/cpu_percent (%)/min': 6.1,
        '<tag>/host/cpu_percent (%)/max': 28.1,
        ...,
        '<tag>/host/memory_percent (%)/mean': 21.5,
        '<tag>/host/swap_percent (%)/mean': 0.3,
        '<tag>/host/memory_used (GiB)/mean': 91.0136418208109,
        '<tag>/host/load_average (%) (1 min)/mean': 10.251427386878328,
        '<tag>/host/load_average (%) (5 min)/mean': 10.072539414569503,
        '<tag>/host/load_average (%) (15 min)/mean': 11.91126970422139,
        ...,
        '<tag>/cuda:0 (gpu:3)/memory_used (MiB)/mean': 3.875,
        '<tag>/cuda:0 (gpu:3)/memory_free (MiB)/mean': 11015.562499999998,
        '<tag>/cuda:0 (gpu:3)/memory_total (MiB)/mean': 11019.437500000002,
        '<tag>/cuda:0 (gpu:3)/memory_percent (%)/mean': 0.0,
        '<tag>/cuda:0 (gpu:3)/gpu_utilization (%)/mean': 0.0,
        '<tag>/cuda:0 (gpu:3)/memory_utilization (%)/mean': 0.0,
        '<tag>/cuda:0 (gpu:3)/fan_speed (%)/mean': 22.0,
        '<tag>/cuda:0 (gpu:3)/temperature (C)/mean': 25.0,
        '<tag>/cuda:0 (gpu:3)/power_usage (W)/mean': 19.11166264116916,
        ...,
        '<tag>/cuda:1 (gpu:2)/memory_used (MiB)/mean': 8878.875,
        ...,
        '<tag>/cuda:2 (gpu:1)/memory_used (MiB)/mean': 8182.875,
        ...,
        '<tag>/cuda:3 (gpu:0)/memory_used (MiB)/mean': 9286.875,
        ...,
        '<tag>/pid:12345/host/cpu_percent (%)/mean': 151.34342772112265,
        '<tag>/pid:12345/host/host_memory (MiB)/mean': 44749.72373447514,
        '<tag>/pid:12345/host/host_memory_percent (%)/mean': 8.675082352111717,
        '<tag>/pid:12345/host/running_time (min)': 336.23803206741576,
        '<tag>/pid:12345/cuda:1 (gpu:4)/gpu_memory (MiB)/mean': 8861.0,
        '<tag>/pid:12345/cuda:1 (gpu:4)/gpu_memory_percent (%)/mean': 80.4,
        '<tag>/pid:12345/cuda:1 (gpu:4)/gpu_memory_utilization (%)/mean': 6.711118172407917,
        '<tag>/pid:12345/cuda:1 (gpu:4)/gpu_sm_utilization (%)/mean': 48.23283397736476,
        ...,
        '<tag>/duration (s)': 7.247399162035435,
        '<tag>/timestamp': 1655909466.9981883
    }
    

    The results can be easily logged into TensorBoard or a CSV file. For example:

    import os
    
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    from torch.utils.tensorboard import SummaryWriter
    
    from nvitop import CudaDevice, ResourceMetricCollector
    
    
    def add_scalar_dict(writer, main_tag, tag_scalar_dict, global_step=None, walltime=None):
        for tag, scalar in tag_scalar_dict.items():
            writer.add_scalar(f'{main_tag}/{tag}', scalar, global_step=global_step, walltime=walltime)
    
    
    # Build networks and prepare datasets
    ...
    
    # Logger and status collector
    writer = SummaryWriter()
    collector = ResourceMetricCollector(
        devices=CudaDevice.all(),  # log all visible CUDA devices and use the CUDA ordinal
        root_pids={os.getpid()},  # only log the descendant processes of the current process
        interval=1.0,  # snapshot interval for background daemon thread
    )
    
    # Start training
    global_step = 0
    for epoch in range(num_epoch):
        with collector(tag='train'):
            for batch in train_dataset:
                with collector(tag='batch'):
                    metrics = train(net, batch)
                    global_step += 1
                    add_scalar_dict(writer, 'train', metrics, global_step=global_step)
                    add_scalar_dict(
                        writer,
                        'resources',  # tag='resources/train/batch/...'
                        collector.collect(),
                        global_step=global_step,
                    )
    
            add_scalar_dict(
                writer,
                'resources',  # tag='resources/train/...'
                collector.collect(),
                global_step=epoch,
            )
    
        with collector(tag='validate'):
            metrics = validate(net, validation_dataset)
            add_scalar_dict(writer, 'validate', metrics, global_step=epoch)
            add_scalar_dict(
                writer,
                'resources',  # tag='resources/validate/...'
                collector.collect(),
                global_step=epoch,
            )
    

    Another example for logging into a CSV file:

    import datetime
    import time
    
    import pandas as pd
    
    from nvitop import ResourceMetricCollector
    
    # Log all devices and all GPU processes
    collector = ResourceMetricCollector(root_pids={1}, interval=2.0)
    df = pd.DataFrame()
    
    with collector(tag='resources'):
        for _ in range(60):
            # Do something
            time.sleep(60)
    
            metrics = collector.collect()
            df_metrics = pd.DataFrame.from_records(metrics, index=[len(df)])
            df = pd.concat([df, df_metrics], ignore_index=True)
            # Flush to CSV file ...
    
    df.insert(0, 'time', df['resources/timestamp'].map(datetime.datetime.fromtimestamp))
    df.to_csv('results.csv', index=False)
    

    You can also daemonize the collector in the background using collect_in_background or ResourceMetricCollector.daemonize with callback functions.

    from nvitop import Device, ResourceMetricCollector, collect_in_background
    
    logger = ...
    
    
    def on_collect(metrics):  # will be called periodically
        if logger.is_closed():  # closed manually by user
            return False
        logger.log(metrics)
        return True
    
    
    def on_stop(collector):  # will be called only once at stop
        if not logger.is_closed():
            logger.close()  # cleanup
    
    
    # Record metrics to the logger in the background every 5 seconds.
    # It will collect 5-second mean/min/max for each metric.
    collect_in_background(
        on_collect,
        ResourceMetricCollector(Device.cuda.all()),
        interval=5.0,
        on_stop=on_stop,
    )
    

    or simply:

    ResourceMetricCollector(Device.cuda.all()).daemonize(
        on_collect,
        interval=5.0,
        on_stop=on_stop,
    )
    

    Low-level APIs

    The full API references can be found at https://nvitop.readthedocs.io.

    Device

    The device module provides:

    In [1]: from nvitop import (
       ...:     host,
       ...:     Device, PhysicalDevice, CudaDevice,
       ...:     parse_cuda_visible_devices, normalize_cuda_visible_devices
       ...:     HostProcess, GpuProcess,
       ...:     NA,
       ...: )
       ...: import os
       ...: os.environ['CUDA_DEVICE_ORDER'] = 'PCI_BUS_ID'
       ...: os.environ['CUDA_VISIBLE_DEVICES'] = '9,8,7,6'  # comma-separated integers or UUID strings
    
    In [2]: Device.driver_version()
    Out[2]: '525.60.11'
    
    In [3]: Device.cuda_driver_version()  # the maximum CUDA version supported by the driver (can be different from the CUDA Runtime version)
    Out[3]: '12.0'
    
    In [4]: Device.cuda_runtime_version()  # the CUDA Runtime version
    Out[4]: '11.8'
    
    In [5]: Device.count()
    Out[5]: 10
    
    In [6]: CudaDevice.count()  # or `Device.cuda.count()`
    Out[6]: 4
    
    In [7]: all_devices      = Device.all()                 # all devices on board (physical device)
       ...: nvidia0, nvidia1 = Device.from_indices([0, 1])  # from physical device indices
       ...: all_devices
    Out[7]: [
        PhysicalDevice(index=0, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=1, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=2, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=3, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=4, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=5, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=6, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=7, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=8, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        PhysicalDevice(index=9, name="GeForce RTX 2080 Ti", total_memory=11019MiB)
    ]
    
    In [8]: # NOTE: The function results might be different between calls when the `CUDA_VISIBLE_DEVICES` environment variable has been modified
       ...: cuda_visible_devices = Device.from_cuda_visible_devices()  # from the `CUDA_VISIBLE_DEVICES` environment variable
       ...: cuda0, cuda1         = Device.from_cuda_indices([0, 1])    # from CUDA device indices (might be different from physical device indices if `CUDA_VISIBLE_DEVICES` is set)
       ...: cuda_visible_devices = CudaDevice.all()                    # shortcut to `Device.from_cuda_visible_devices()`
       ...: cuda_visible_devices = Device.cuda.all()                   # `Device.cuda` is aliased to `CudaDevice`
       ...: cuda_visible_devices
    Out[8]: [
        CudaDevice(cuda_index=0, nvml_index=9, name="NVIDIA GeForce RTX 2080 Ti", total_memory=11019MiB),
        CudaDevice(cuda_index=1, nvml_index=8, name="NVIDIA GeForce RTX 2080 Ti", total_memory=11019MiB),
        CudaDevice(cuda_index=2, nvml_index=7, name="NVIDIA GeForce RTX 2080 Ti", total_memory=11019MiB),
        CudaDevice(cuda_index=3, nvml_index=6, name="NVIDIA GeForce RTX 2080 Ti", total_memory=11019MiB)
    ]
    
    In [9]: nvidia0 = Device(0)  # from device index (or `Device(index=0)`)
       ...: nvidia0
    Out[9]: PhysicalDevice(index=0, name="GeForce RTX 2080 Ti", total_memory=11019MiB)
    
    In [10]: nvidia1 = Device(uuid='GPU-01234567-89ab-cdef-0123-456789abcdef')  # from UUID string (or just `Device('GPU-xxxxxxxx-...')`)
        ...: nvidia2 = Device(bus_id='00000000:06:00.0')                        # from PCI bus ID
        ...: nvidia1
    Out[10]: PhysicalDevice(index=1, name="GeForce RTX 2080 Ti", total_memory=11019MiB)
    
    In [11]: cuda0 = CudaDevice(0)                        # from CUDA device index (equivalent to `CudaDevice(cuda_index=0)`)
        ...: cuda1 = CudaDevice(nvml_index=8)             # from physical device index
        ...: cuda3 = CudaDevice(uuid='GPU-xxxxxxxx-...')  # from UUID string
        ...: cuda4 = Device.cuda(4)                       # `Device.cuda` is aliased to `CudaDevice`
        ...: cuda0
    Out[11]:
    CudaDevice(cuda_index=0, nvml_index=9, name="NVIDIA GeForce RTX 2080 Ti", total_memory=11019MiB)
    
    In [12]: nvidia0.memory_used()  # in bytes
    Out[12]: 9293398016
    
    In [13]: nvidia0.memory_used_human()
    Out[13]: '8862MiB'
    
    In [14]: nvidia0.gpu_utilization()  # in percentage
    Out[14]: 5
    
    In [15]: nvidia0.processes()  # type: Dict[int, GpuProcess]
    Out[15]: {
        52059: GpuProcess(pid=52059, gpu_memory=7885MiB, type=C, device=PhysicalDevice(index=0, name="GeForce RTX 2080 Ti", total_memory=11019MiB), host=HostProcess(pid=52059, name='ipython3', status='sleeping', started='14:31:22')),
        53002: GpuProcess(pid=53002, gpu_memory=967MiB, type=C, device=PhysicalDevice(index=0, name="GeForce RTX 2080 Ti", total_memory=11019MiB), host=HostProcess(pid=53002, name='python', status='running', started='14:31:59'))
    }
    
    In [16]: nvidia1_snapshot = nvidia1.as_snapshot()
        ...: nvidia1_snapshot
    Out[16]: PhysicalDeviceSnapshot(
        real=PhysicalDevice(index=1, name="GeForce RTX 2080 Ti", total_memory=11019MiB),
        bus_id='00000000:05:00.0',
        compute_mode='Default',
        clock_infos=ClockInfos(graphics=1815, sm=1815, memory=6800, video=1680),  # in MHz
        clock_speed_infos=ClockSpeedInfos(current=ClockInfos(graphics=1815, sm=1815, memory=6800, video=1680), max=ClockInfos(graphics=2100, sm=2100, memory=7000, video=1950)),  # in MHz
        cuda_compute_capability=(7, 5),
        current_driver_model='N/A',
        decoder_utilization=0,              # in percentage
        display_active='Disabled',
        display_mode='Disabled',
        encoder_utilization=0,              # in percentage
        fan_speed=22,                       # in percentage
        gpu_utilization=17,                 # in percentage (NOTE: this is the utilization rate of SMs, i.e. GPU percent)
        index=1,
        max_clock_infos=ClockInfos(graphics=2100, sm=2100, memory=7000, video=1950),  # in MHz
        memory_clock=6800,                  # in MHz
        memory_free=10462232576,            # in bytes
        memory_free_human='9977MiB',
        memory_info=MemoryInfo(total=11554717696, free=10462232576, used=1092485120)  # in bytes
        memory_percent=9.5,                 # in percentage (NOTE: this is the percentage of used GPU memory)
        memory_total=11554717696,           # in bytes
        memory_total_human='11019MiB',
        memory_usage='1041MiB / 11019MiB',
        memory_used=1092485120,             # in bytes
        memory_used_human='1041MiB',
        memory_utilization=7,               # in percentage (NOTE: this is the utilization rate of GPU memory bandwidth)
        mig_mode='N/A',
        name='GeForce RTX 2080 Ti',
        pcie_rx_throughput=1000,            # in KiB/s
        pcie_rx_throughput_human='1000KiB/s',
        pcie_throughput=ThroughputInfo(tx=1000, rx=1000),  # in KiB/s
        pcie_t