xpustat 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xpustat-0.1.0/LICENSE +21 -0
- xpustat-0.1.0/PKG-INFO +143 -0
- xpustat-0.1.0/README.md +109 -0
- xpustat-0.1.0/pyproject.toml +49 -0
- xpustat-0.1.0/setup.cfg +4 -0
- xpustat-0.1.0/tests/test_cli.py +44 -0
- xpustat-0.1.0/tests/test_process.py +49 -0
- xpustat-0.1.0/tests/test_vendors.py +110 -0
- xpustat-0.1.0/tests/test_xpu.py +78 -0
- xpustat-0.1.0/xpustat/__init__.py +77 -0
- xpustat-0.1.0/xpustat/_process.py +59 -0
- xpustat-0.1.0/xpustat/amd.py +359 -0
- xpustat-0.1.0/xpustat/cambricon.py +153 -0
- xpustat-0.1.0/xpustat/cli.py +443 -0
- xpustat-0.1.0/xpustat/gaudi.py +103 -0
- xpustat-0.1.0/xpustat/huawei.py +333 -0
- xpustat-0.1.0/xpustat/hygon.py +142 -0
- xpustat-0.1.0/xpustat/intel_gpu.py +150 -0
- xpustat-0.1.0/xpustat/moorethreads.py +120 -0
- xpustat-0.1.0/xpustat/nvidia.py +336 -0
- xpustat-0.1.0/xpustat/xpu.py +311 -0
- xpustat-0.1.0/xpustat.egg-info/PKG-INFO +143 -0
- xpustat-0.1.0/xpustat.egg-info/SOURCES.txt +25 -0
- xpustat-0.1.0/xpustat.egg-info/dependency_links.txt +1 -0
- xpustat-0.1.0/xpustat.egg-info/entry_points.txt +2 -0
- xpustat-0.1.0/xpustat.egg-info/requires.txt +11 -0
- xpustat-0.1.0/xpustat.egg-info/top_level.txt +1 -0
xpustat-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Salah Eddine Bekhouche, Hichem Telli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
xpustat-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xpustat
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A unified stat tool for NVIDIA, AMD, Intel, Huawei, Hygon, Cambricon and Moore Threads accelerators
|
|
5
|
+
Author: Salah Eddine Bekhouche, Hichem Telli
|
|
6
|
+
Author-email: bekhouchesalah@gmail.com
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/Bekhouche/xpustat
|
|
9
|
+
Keywords: gpu,npu,accelerator,monitoring,nvidia,amd,intel,huawei,ascend
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: System :: Monitoring
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: psutil>=5.9
|
|
26
|
+
Provides-Extra: nvidia
|
|
27
|
+
Requires-Dist: pynvml>=11.0; extra == "nvidia"
|
|
28
|
+
Provides-Extra: amd
|
|
29
|
+
Requires-Dist: amdsmi; extra == "amd"
|
|
30
|
+
Provides-Extra: fast
|
|
31
|
+
Requires-Dist: pynvml>=11.0; extra == "fast"
|
|
32
|
+
Requires-Dist: amdsmi; extra == "fast"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# xpustat
|
|
36
|
+
|
|
37
|
+
[](https://github.com/Bekhouche/xpustat)
|
|
38
|
+
**Authors:** Salah Eddine Bekhouche, Hichem Telli
|
|
39
|
+
|
|
40
|
+
A unified accelerator stat tool — think `gpustat`, but for every vendor.
|
|
41
|
+
|
|
42
|
+
## Supported backends
|
|
43
|
+
|
|
44
|
+
| Status | Vendor | Device | CLI tool | Filter key |
|
|
45
|
+
|:---:|---|---|---|---|
|
|
46
|
+
| ✅ Tested | AMD | Radeon RX 7900 XTX (gfx1100) | `amd-smi` | `amd` |
|
|
47
|
+
| ✅ Tested | NVIDIA | NVIDIA L4 (cc8.9), TITAN V (cc7.0) | `nvidia-smi` | `nvidia` |
|
|
48
|
+
| 🔲 Untested | Intel | Gaudi / Gaudi 2 / Gaudi 3 | `hl-smi` | `gaudi` |
|
|
49
|
+
| 🔲 Untested | Intel | Arc / Data Center GPU | `xpu-smi` | `intel` |
|
|
50
|
+
| ✅ Tested | Huawei | Ascend 910B2 | `ascend-dmi` / `npu-smi` | `huawei` |
|
|
51
|
+
| 🔲 Untested | Hygon | DCU | `hy-smi` | `hygon` |
|
|
52
|
+
| 🔲 Untested | Cambricon | MLU | `cnmon` | `cambricon` |
|
|
53
|
+
| 🔲 Untested | Moore Threads | MTT GPU | `mthreads-gmi` | `moorethreads` |
|
|
54
|
+
|
|
55
|
+
> **Legend:** ✅ Tested on real hardware — 🔲 Implemented, awaiting hardware test
|
|
56
|
+
>
|
|
57
|
+
> Backends whose management tool is not installed are silently skipped.
|
|
58
|
+
|
|
59
|
+
### Running Vendor Hardware Tests
|
|
60
|
+
|
|
61
|
+
If you have access to specific hardware, you can help us verify the implementation by running the standalone test scripts found in the `vendor_devices_tests/` directory:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Example: Testing the Huawei backend on a machine with Ascend NPUs
|
|
65
|
+
python vendor_devices_tests/test_huawei.py
|
|
66
|
+
|
|
67
|
+
# Example: Testing the NVIDIA backend
|
|
68
|
+
python vendor_devices_tests/test_nvidia.py
|
|
69
|
+
```
|
|
70
|
+
If the test successfully outputs your hardware metrics, please let us know so we can update the backend status to **✅ Tested**!
|
|
71
|
+
|
|
72
|
+
## Install
|
|
73
|
+
|
|
74
|
+
**pip**
|
|
75
|
+
```bash
|
|
76
|
+
pip install xpustat
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**conda**
|
|
80
|
+
```bash
|
|
81
|
+
conda install -c conda-forge xpustat
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## CLI usage
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
xpustat # coloured table of all detected devices
|
|
88
|
+
xpustat -pui # watch mode, showing processes (-p), users (-u), refreshing every 1.0s (-i)
|
|
89
|
+
xpustat -i 2 # watch mode, refresh every 2 seconds
|
|
90
|
+
xpustat -i 1 -n 10 # 10 refreshes then exit
|
|
91
|
+
xpustat -a # show everything (util, temp, power, arch, user, pid, cmd)
|
|
92
|
+
xpustat -f nvidia amd # show only NVIDIA and AMD
|
|
93
|
+
xpustat --no-color # plain text, no ANSI codes
|
|
94
|
+
xpustat --json # raw JSON output
|
|
95
|
+
xpustat --version
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Example output:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
xpustat 0.1.0 · myhost · Fri May 22 11:24:00 2026
|
|
102
|
+
──────────────────────────────────────────────────────────────────────────
|
|
103
|
+
[NVIDIA] #0 Tesla V100 │ 1,024 / 32,768 MB ███░░░░░░░░░░░░░ 3%
|
|
104
|
+
[AMD ] #0 Radeon RX 7900 XTX │ 26 / 24,560 MB ░░░░░░░░░░░░░░░░ 0%
|
|
105
|
+
[HUAWEI] #0:0 Ascend 310 │ 2,703 / 8,192 MB █████░░░░░░░░░░░ 33%
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Example output with processes, users, and watch mode (`xpustat -pui`):
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
xpustat 0.1.0 · salah-amd · Fri May 29 10:07:57 2026
|
|
112
|
+
──────────────────────────────────────────────────────────
|
|
113
|
+
[AMD ] #0 Radeon RX 7900 XTX │ 17,918 / 24,560 MB ████████████░░░░ 72%
|
|
114
|
+
└─ salah/348504(17480M)
|
|
115
|
+
refreshing every 1.0s · Ctrl+C to quit
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Python API
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
import xpustat
|
|
122
|
+
|
|
123
|
+
# Query everything at once (parallel by default)
|
|
124
|
+
stats = xpustat.query_all()
|
|
125
|
+
|
|
126
|
+
print(stats) # XPUStatCollection(nvidia=0, amd=1, ...)
|
|
127
|
+
print(stats.amd[0].name) # "Radeon RX 7900 XTX"
|
|
128
|
+
print(stats.amd[0].mem_used_mb) # 26
|
|
129
|
+
|
|
130
|
+
# As a dict (JSON-serialisable)
|
|
131
|
+
import json
|
|
132
|
+
print(json.dumps(stats.to_dict(), indent=2))
|
|
133
|
+
|
|
134
|
+
# Query a single vendor
|
|
135
|
+
from xpustat import NvidiaGPUStatCollection
|
|
136
|
+
gpus = NvidiaGPUStatCollection.new_query()
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Version history
|
|
140
|
+
|
|
141
|
+
### 0.1.0
|
|
142
|
+
- Initial release
|
|
143
|
+
- Support for NVIDIA, AMD, Intel Gaudi, Intel Arc/GPU, Huawei Ascend, Hygon DCU, Cambricon MLU, Moore Threads
|
xpustat-0.1.0/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# xpustat
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Bekhouche/xpustat)
|
|
4
|
+
**Authors:** Salah Eddine Bekhouche, Hichem Telli
|
|
5
|
+
|
|
6
|
+
A unified accelerator stat tool — think `gpustat`, but for every vendor.
|
|
7
|
+
|
|
8
|
+
## Supported backends
|
|
9
|
+
|
|
10
|
+
| Status | Vendor | Device | CLI tool | Filter key |
|
|
11
|
+
|:---:|---|---|---|---|
|
|
12
|
+
| ✅ Tested | AMD | Radeon RX 7900 XTX (gfx1100) | `amd-smi` | `amd` |
|
|
13
|
+
| ✅ Tested | NVIDIA | NVIDIA L4 (cc8.9), TITAN V (cc7.0) | `nvidia-smi` | `nvidia` |
|
|
14
|
+
| 🔲 Untested | Intel | Gaudi / Gaudi 2 / Gaudi 3 | `hl-smi` | `gaudi` |
|
|
15
|
+
| 🔲 Untested | Intel | Arc / Data Center GPU | `xpu-smi` | `intel` |
|
|
16
|
+
| ✅ Tested | Huawei | Ascend 910B2 | `ascend-dmi` / `npu-smi` | `huawei` |
|
|
17
|
+
| 🔲 Untested | Hygon | DCU | `hy-smi` | `hygon` |
|
|
18
|
+
| 🔲 Untested | Cambricon | MLU | `cnmon` | `cambricon` |
|
|
19
|
+
| 🔲 Untested | Moore Threads | MTT GPU | `mthreads-gmi` | `moorethreads` |
|
|
20
|
+
|
|
21
|
+
> **Legend:** ✅ Tested on real hardware — 🔲 Implemented, awaiting hardware test
|
|
22
|
+
>
|
|
23
|
+
> Backends whose management tool is not installed are silently skipped.
|
|
24
|
+
|
|
25
|
+
### Running Vendor Hardware Tests
|
|
26
|
+
|
|
27
|
+
If you have access to specific hardware, you can help us verify the implementation by running the standalone test scripts found in the `vendor_devices_tests/` directory:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Example: Testing the Huawei backend on a machine with Ascend NPUs
|
|
31
|
+
python vendor_devices_tests/test_huawei.py
|
|
32
|
+
|
|
33
|
+
# Example: Testing the NVIDIA backend
|
|
34
|
+
python vendor_devices_tests/test_nvidia.py
|
|
35
|
+
```
|
|
36
|
+
If the test successfully outputs your hardware metrics, please let us know so we can update the backend status to **✅ Tested**!
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
**pip**
|
|
41
|
+
```bash
|
|
42
|
+
pip install xpustat
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**conda**
|
|
46
|
+
```bash
|
|
47
|
+
conda install -c conda-forge xpustat
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## CLI usage
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
xpustat # coloured table of all detected devices
|
|
54
|
+
xpustat -pui # watch mode, showing processes (-p), users (-u), refreshing every 1.0s (-i)
|
|
55
|
+
xpustat -i 2 # watch mode, refresh every 2 seconds
|
|
56
|
+
xpustat -i 1 -n 10 # 10 refreshes then exit
|
|
57
|
+
xpustat -a # show everything (util, temp, power, arch, user, pid, cmd)
|
|
58
|
+
xpustat -f nvidia amd # show only NVIDIA and AMD
|
|
59
|
+
xpustat --no-color # plain text, no ANSI codes
|
|
60
|
+
xpustat --json # raw JSON output
|
|
61
|
+
xpustat --version
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Example output:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
xpustat 0.1.0 · myhost · Fri May 22 11:24:00 2026
|
|
68
|
+
──────────────────────────────────────────────────────────────────────────
|
|
69
|
+
[NVIDIA] #0 Tesla V100 │ 1,024 / 32,768 MB ███░░░░░░░░░░░░░ 3%
|
|
70
|
+
[AMD ] #0 Radeon RX 7900 XTX │ 26 / 24,560 MB ░░░░░░░░░░░░░░░░ 0%
|
|
71
|
+
[HUAWEI] #0:0 Ascend 310 │ 2,703 / 8,192 MB █████░░░░░░░░░░░ 33%
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Example output with processes, users, and watch mode (`xpustat -pui`):
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
xpustat 0.1.0 · salah-amd · Fri May 29 10:07:57 2026
|
|
78
|
+
──────────────────────────────────────────────────────────
|
|
79
|
+
[AMD ] #0 Radeon RX 7900 XTX │ 17,918 / 24,560 MB ████████████░░░░ 72%
|
|
80
|
+
└─ salah/348504(17480M)
|
|
81
|
+
refreshing every 1.0s · Ctrl+C to quit
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Python API
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
import xpustat
|
|
88
|
+
|
|
89
|
+
# Query everything at once (parallel by default)
|
|
90
|
+
stats = xpustat.query_all()
|
|
91
|
+
|
|
92
|
+
print(stats) # XPUStatCollection(nvidia=0, amd=1, ...)
|
|
93
|
+
print(stats.amd[0].name) # "Radeon RX 7900 XTX"
|
|
94
|
+
print(stats.amd[0].mem_used_mb) # 26
|
|
95
|
+
|
|
96
|
+
# As a dict (JSON-serialisable)
|
|
97
|
+
import json
|
|
98
|
+
print(json.dumps(stats.to_dict(), indent=2))
|
|
99
|
+
|
|
100
|
+
# Query a single vendor
|
|
101
|
+
from xpustat import NvidiaGPUStatCollection
|
|
102
|
+
gpus = NvidiaGPUStatCollection.new_query()
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Version history
|
|
106
|
+
|
|
107
|
+
### 0.1.0
|
|
108
|
+
- Initial release
|
|
109
|
+
- Support for NVIDIA, AMD, Intel Gaudi, Intel Arc/GPU, Huawei Ascend, Hygon DCU, Cambricon MLU, Moore Threads
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "xpustat"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A unified stat tool for NVIDIA, AMD, Intel, Huawei, Hygon, Cambricon and Moore Threads accelerators"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Salah Eddine Bekhouche" },
|
|
12
|
+
{ name = "Hichem Telli" },
|
|
13
|
+
{ email = "bekhouchesalah@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
license = { text = "MIT" }
|
|
16
|
+
requires-python = ">=3.9"
|
|
17
|
+
dependencies = ["psutil>=5.9"]
|
|
18
|
+
keywords = ["gpu", "npu", "accelerator", "monitoring", "nvidia", "amd", "intel", "huawei", "ascend"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Intended Audience :: Science/Research",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.9",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Topic :: System :: Monitoring",
|
|
31
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
# Native SDK backends — faster than subprocess, no extra build tools needed
|
|
36
|
+
nvidia = ["pynvml>=11.0"]
|
|
37
|
+
amd = ["amdsmi"]
|
|
38
|
+
# Install everything at once: pip install xpustat[fast]
|
|
39
|
+
fast = ["pynvml>=11.0", "amdsmi"]
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
xpustat = "xpustat.cli:main"
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/Bekhouche/xpustat"
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
where = ["."]
|
|
49
|
+
include = ["xpustat*"]
|
xpustat-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
from xpustat import cli
|
|
4
|
+
import argparse
|
|
5
|
+
|
|
6
|
+
@patch("xpustat.cli._render")
|
|
7
|
+
def test_print_xpustat_snapshot(mock_render):
|
|
8
|
+
cli.print_xpustat()
|
|
9
|
+
mock_render.assert_called_once()
|
|
10
|
+
args = mock_render.call_args[1]
|
|
11
|
+
assert args["filter_vendors"] is None
|
|
12
|
+
assert args["show_util"] is False
|
|
13
|
+
|
|
14
|
+
@patch("xpustat.cli._render")
|
|
15
|
+
@patch("time.sleep", return_value=None)
|
|
16
|
+
@patch("time.monotonic", side_effect=[0, 1, 2, 3])
|
|
17
|
+
def test_print_xpustat_watch_mode(mock_monotonic, mock_sleep, mock_render):
|
|
18
|
+
cli.print_xpustat(interval=1.0, count=2)
|
|
19
|
+
assert mock_render.call_count == 2
|
|
20
|
+
|
|
21
|
+
def test_fields_extract():
|
|
22
|
+
class DummyDev:
|
|
23
|
+
name = "TestDev"
|
|
24
|
+
processes = []
|
|
25
|
+
|
|
26
|
+
idx, name, arch, used, tot, util, temp, pwr, procs = cli._fields("unknown", DummyDev())
|
|
27
|
+
assert idx == "?"
|
|
28
|
+
assert name.startswith("<") or "TestDev" in name
|
|
29
|
+
assert used == 0
|
|
30
|
+
assert tot == 0
|
|
31
|
+
|
|
32
|
+
def test_mem_bar():
|
|
33
|
+
# used=500, total=1000 => 50%
|
|
34
|
+
bar = cli._mem_bar("32", 500, 1000)
|
|
35
|
+
assert "█" in bar
|
|
36
|
+
assert "░" in bar
|
|
37
|
+
|
|
38
|
+
def test_fmt_cc():
|
|
39
|
+
assert cli._fmt_cc("8.6") == "cc8.6"
|
|
40
|
+
assert cli._fmt_cc(None) is None
|
|
41
|
+
|
|
42
|
+
def test_fmt_gfx():
|
|
43
|
+
assert cli._fmt_gfx("gfx1100") == "gfx1100"
|
|
44
|
+
assert cli._fmt_gfx(None) is None
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import patch, MagicMock
|
|
3
|
+
from xpustat._process import ProcessInfo, enrich_process
|
|
4
|
+
import psutil
|
|
5
|
+
|
|
6
|
+
def test_process_info():
|
|
7
|
+
p = ProcessInfo(pid=1234, username="testuser", command="python script.py", gpu_mem_mb=500)
|
|
8
|
+
assert p.pid == 1234
|
|
9
|
+
assert p.username == "testuser"
|
|
10
|
+
assert p.command == "python script.py"
|
|
11
|
+
assert p.gpu_mem_mb == 500
|
|
12
|
+
|
|
13
|
+
d = p.to_dict()
|
|
14
|
+
assert d["pid"] == 1234
|
|
15
|
+
assert d["username"] == "testuser"
|
|
16
|
+
assert d["command"] == "python script.py"
|
|
17
|
+
assert d["gpu_mem_mb"] == 500
|
|
18
|
+
|
|
19
|
+
assert repr(p) == "testuser:python script.py/1234(500M)"
|
|
20
|
+
|
|
21
|
+
@patch("psutil.Process")
|
|
22
|
+
def test_enrich_process_success(mock_process_cls):
|
|
23
|
+
mock_proc = MagicMock()
|
|
24
|
+
mock_proc.username.return_value = "mockuser"
|
|
25
|
+
mock_proc.cmdline.return_value = ["/usr/bin/python", "app.py"]
|
|
26
|
+
mock_process_cls.return_value = mock_proc
|
|
27
|
+
|
|
28
|
+
username, command = enrich_process(9999, "fallback")
|
|
29
|
+
assert username == "mockuser"
|
|
30
|
+
assert command == "python"
|
|
31
|
+
|
|
32
|
+
@patch("psutil.Process")
|
|
33
|
+
def test_enrich_process_access_denied(mock_process_cls):
|
|
34
|
+
mock_proc = MagicMock()
|
|
35
|
+
mock_proc.username.return_value = "mockuser"
|
|
36
|
+
mock_proc.cmdline.side_effect = psutil.AccessDenied()
|
|
37
|
+
mock_process_cls.return_value = mock_proc
|
|
38
|
+
|
|
39
|
+
username, command = enrich_process(9999, "fallback")
|
|
40
|
+
assert username == "mockuser"
|
|
41
|
+
assert command == "fallback"
|
|
42
|
+
|
|
43
|
+
@patch("psutil.Process")
|
|
44
|
+
def test_enrich_process_no_process(mock_process_cls):
|
|
45
|
+
mock_process_cls.side_effect = psutil.NoSuchProcess(9999)
|
|
46
|
+
|
|
47
|
+
username, command = enrich_process(9999, "fallback")
|
|
48
|
+
assert username == "?"
|
|
49
|
+
assert command == "fallback"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from xpustat.nvidia import NvidiaGPUStat, NvidiaGPUStatCollection
|
|
3
|
+
from xpustat.amd import AMDGPUStat, AMDGPUStatCollection
|
|
4
|
+
from xpustat.gaudi import GaudiAIPStat, GaudiAIPStatCollection
|
|
5
|
+
from xpustat.intel_gpu import IntelGPUStat, IntelGPUStatCollection
|
|
6
|
+
from xpustat.huawei import HuaweiNPUStat, HuaweiNPUStatCollection
|
|
7
|
+
from xpustat.hygon import HygonDCUStat, HygonDCUStatCollection
|
|
8
|
+
from xpustat.cambricon import CambriconMLUStat, CambriconMLUStatCollection
|
|
9
|
+
from xpustat.moorethreads import MooreThreadsGPUStat, MooreThreadsGPUStatCollection
|
|
10
|
+
|
|
11
|
+
def test_nvidia_stat():
|
|
12
|
+
stat = NvidiaGPUStat(
|
|
13
|
+
gpu_index=0,
|
|
14
|
+
uuid="GPU-12345",
|
|
15
|
+
name="Mock Nvidia",
|
|
16
|
+
mem_used_mb=1000,
|
|
17
|
+
mem_total_mb=8000,
|
|
18
|
+
util_pct=50,
|
|
19
|
+
temp_c=45,
|
|
20
|
+
power_w=120.0,
|
|
21
|
+
cuda_cc="8.6",
|
|
22
|
+
processes=[]
|
|
23
|
+
)
|
|
24
|
+
col = NvidiaGPUStatCollection([stat])
|
|
25
|
+
assert len(col) == 1
|
|
26
|
+
d = col.to_dict()
|
|
27
|
+
assert len(d["gpus"]) == 1
|
|
28
|
+
assert d["gpus"][0]["name"] == "Mock Nvidia"
|
|
29
|
+
|
|
30
|
+
def test_amd_stat():
|
|
31
|
+
stat = AMDGPUStat(
|
|
32
|
+
gpu_index=0,
|
|
33
|
+
name="Mock AMD",
|
|
34
|
+
mem_used_mb=2000,
|
|
35
|
+
mem_total_mb=16000,
|
|
36
|
+
util_pct=80,
|
|
37
|
+
temp_c=65,
|
|
38
|
+
power_w=200.0,
|
|
39
|
+
gfx_target="gfx1100"
|
|
40
|
+
)
|
|
41
|
+
col = AMDGPUStatCollection([stat])
|
|
42
|
+
assert len(col) == 1
|
|
43
|
+
d = col.to_dict()
|
|
44
|
+
assert len(d["gpus"]) == 1
|
|
45
|
+
|
|
46
|
+
def test_gaudi_stat():
|
|
47
|
+
stat = GaudiAIPStat(
|
|
48
|
+
aip_index=0,
|
|
49
|
+
name="Gaudi2",
|
|
50
|
+
mem_used_mb=5000,
|
|
51
|
+
mem_total_mb=32000
|
|
52
|
+
)
|
|
53
|
+
col = GaudiAIPStatCollection([stat])
|
|
54
|
+
assert len(col) == 1
|
|
55
|
+
|
|
56
|
+
def test_intel_stat():
|
|
57
|
+
stat = IntelGPUStat(
|
|
58
|
+
device_id=0,
|
|
59
|
+
name="Intel Arc",
|
|
60
|
+
mem_used_mb=1000,
|
|
61
|
+
mem_total_mb=8000
|
|
62
|
+
)
|
|
63
|
+
col = IntelGPUStatCollection([stat])
|
|
64
|
+
assert len(col) == 1
|
|
65
|
+
|
|
66
|
+
def test_huawei_stat():
|
|
67
|
+
stat = HuaweiNPUStat(
|
|
68
|
+
npu_id=0,
|
|
69
|
+
chip_id=0,
|
|
70
|
+
name="Ascend 910B",
|
|
71
|
+
mem_used_mb=2000,
|
|
72
|
+
mem_total_mb=32000,
|
|
73
|
+
ai_core_pct=50,
|
|
74
|
+
temp_c=40,
|
|
75
|
+
power_w=150.0,
|
|
76
|
+
health="OK"
|
|
77
|
+
)
|
|
78
|
+
col = HuaweiNPUStatCollection([stat])
|
|
79
|
+
assert len(col) == 1
|
|
80
|
+
|
|
81
|
+
def test_hygon_stat():
|
|
82
|
+
stat = HygonDCUStat(
|
|
83
|
+
card_index=0,
|
|
84
|
+
name="Hygon DCU",
|
|
85
|
+
mem_used_mb=1000,
|
|
86
|
+
mem_total_mb=16000
|
|
87
|
+
)
|
|
88
|
+
col = HygonDCUStatCollection([stat])
|
|
89
|
+
assert len(col) == 1
|
|
90
|
+
|
|
91
|
+
def test_cambricon_stat():
|
|
92
|
+
stat = CambriconMLUStat(
|
|
93
|
+
card_id=0,
|
|
94
|
+
chip_id=0,
|
|
95
|
+
name="Cambricon MLU",
|
|
96
|
+
mem_used_mb=1000,
|
|
97
|
+
mem_total_mb=16000
|
|
98
|
+
)
|
|
99
|
+
col = CambriconMLUStatCollection([stat])
|
|
100
|
+
assert len(col) == 1
|
|
101
|
+
|
|
102
|
+
def test_moorethreads_stat():
|
|
103
|
+
stat = MooreThreadsGPUStat(
|
|
104
|
+
gpu_id=0,
|
|
105
|
+
name="MTT S80",
|
|
106
|
+
mem_used_mb=1000,
|
|
107
|
+
mem_total_mb=16000
|
|
108
|
+
)
|
|
109
|
+
col = MooreThreadsGPUStatCollection([stat])
|
|
110
|
+
assert len(col) == 1
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import datetime
|
|
3
|
+
import json
|
|
4
|
+
from xpustat import xpu
|
|
5
|
+
from xpustat.xpu import XPUStatCollection
|
|
6
|
+
from xpustat.nvidia import NvidiaGPUStatCollection
|
|
7
|
+
from xpustat.amd import AMDGPUStatCollection
|
|
8
|
+
from xpustat.gaudi import GaudiAIPStatCollection
|
|
9
|
+
from xpustat.intel_gpu import IntelGPUStatCollection
|
|
10
|
+
from xpustat.huawei import HuaweiNPUStatCollection
|
|
11
|
+
from xpustat.hygon import HygonDCUStatCollection
|
|
12
|
+
from xpustat.cambricon import CambriconMLUStatCollection
|
|
13
|
+
from xpustat.moorethreads import MooreThreadsGPUStatCollection
|
|
14
|
+
|
|
15
|
+
def create_mock_collection():
|
|
16
|
+
return XPUStatCollection(
|
|
17
|
+
nvidia=NvidiaGPUStatCollection([]),
|
|
18
|
+
amd=AMDGPUStatCollection([]),
|
|
19
|
+
gaudi=GaudiAIPStatCollection([]),
|
|
20
|
+
intel=IntelGPUStatCollection([]),
|
|
21
|
+
huawei=HuaweiNPUStatCollection([]),
|
|
22
|
+
hygon=HygonDCUStatCollection([]),
|
|
23
|
+
cambricon=CambriconMLUStatCollection([]),
|
|
24
|
+
moorethreads=MooreThreadsGPUStatCollection([]),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def test_xpustat_collection_empty():
|
|
28
|
+
col = create_mock_collection()
|
|
29
|
+
assert len(col) == 0
|
|
30
|
+
assert not bool(col)
|
|
31
|
+
assert len(list(col)) == 0
|
|
32
|
+
|
|
33
|
+
def test_xpustat_collection_get_item():
|
|
34
|
+
col = create_mock_collection()
|
|
35
|
+
assert isinstance(col["nvidia"], NvidiaGPUStatCollection)
|
|
36
|
+
assert isinstance(col["amd"], AMDGPUStatCollection)
|
|
37
|
+
with pytest.raises(KeyError):
|
|
38
|
+
_ = col["unknown"]
|
|
39
|
+
|
|
40
|
+
def test_xpustat_collection_to_dict():
|
|
41
|
+
col = create_mock_collection()
|
|
42
|
+
d = col.to_dict()
|
|
43
|
+
assert "nvidia" in d
|
|
44
|
+
assert "amd" in d
|
|
45
|
+
assert "moorethreads" in d
|
|
46
|
+
assert d["nvidia"] == []
|
|
47
|
+
|
|
48
|
+
def test_xpustat_collection_to_json():
|
|
49
|
+
col = create_mock_collection()
|
|
50
|
+
j = col.to_json()
|
|
51
|
+
assert "nvidia" in json.loads(j)
|
|
52
|
+
|
|
53
|
+
j_meta = col.to_json(metadata=True)
|
|
54
|
+
d_meta = json.loads(j_meta)
|
|
55
|
+
assert "hostname" in d_meta
|
|
56
|
+
assert "query_time" in d_meta
|
|
57
|
+
assert "xpustat_version" in d_meta
|
|
58
|
+
assert "devices" in d_meta
|
|
59
|
+
|
|
60
|
+
def test_query_all(monkeypatch):
|
|
61
|
+
# Mocking new_query on all collections to return empty for testing
|
|
62
|
+
for name, cls in xpu._BACKENDS:
|
|
63
|
+
monkeypatch.setattr(cls, "new_query", lambda: cls([]))
|
|
64
|
+
|
|
65
|
+
col = xpu.query_all(parallel=False)
|
|
66
|
+
assert isinstance(col, XPUStatCollection)
|
|
67
|
+
assert len(col) == 0
|
|
68
|
+
|
|
69
|
+
col_parallel = xpu.query_all(parallel=True)
|
|
70
|
+
assert isinstance(col_parallel, XPUStatCollection)
|
|
71
|
+
|
|
72
|
+
def test_query(monkeypatch):
|
|
73
|
+
monkeypatch.setattr(NvidiaGPUStatCollection, "new_query", lambda: NvidiaGPUStatCollection([]))
|
|
74
|
+
res = xpu.query("nvidia")
|
|
75
|
+
assert isinstance(res, NvidiaGPUStatCollection)
|
|
76
|
+
|
|
77
|
+
with pytest.raises(ValueError):
|
|
78
|
+
xpu.query("unknown")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
xpustat — unified accelerator stat tool.
|
|
3
|
+
|
|
4
|
+
Supports NVIDIA, AMD, Intel Gaudi, Intel Arc/GPU,
|
|
5
|
+
Huawei Ascend, Hygon DCU, Cambricon MLU, and Moore Threads.
|
|
6
|
+
|
|
7
|
+
Quick start::
|
|
8
|
+
|
|
9
|
+
import xpustat
|
|
10
|
+
|
|
11
|
+
# Query all vendors at once
|
|
12
|
+
stats = xpustat.query_all()
|
|
13
|
+
|
|
14
|
+
# Iterate every device across all vendors
|
|
15
|
+
for dev in stats:
|
|
16
|
+
print(dev.name, dev.mem_used_mb, "/", dev.mem_total_mb, "MB")
|
|
17
|
+
|
|
18
|
+
# Vendor-specific access
|
|
19
|
+
for gpu in stats.nvidia:
|
|
20
|
+
print(gpu.name, gpu.util_pct, "%", gpu.temp_c, "°C")
|
|
21
|
+
|
|
22
|
+
# Subscript by vendor key
|
|
23
|
+
for gpu in stats["amd"]:
|
|
24
|
+
print(gpu.power_w, "W")
|
|
25
|
+
|
|
26
|
+
# Query a single vendor
|
|
27
|
+
gpus = xpustat.query("nvidia")
|
|
28
|
+
|
|
29
|
+
# JSON string (for HTTP responses / files)
|
|
30
|
+
print(stats.to_json(indent=2))
|
|
31
|
+
|
|
32
|
+
# JSON with metadata wrapper
|
|
33
|
+
print(stats.to_json(metadata=True))
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
__version__ = "0.1.0"
|
|
37
|
+
__version_tuple__ = (0, 1, 0)
|
|
38
|
+
|
|
39
|
+
from ._process import ProcessInfo
|
|
40
|
+
from .xpu import AnyDeviceStat, XPUStatCollection, query, query_all
|
|
41
|
+
from .nvidia import NvidiaGPUStat, NvidiaGPUStatCollection
|
|
42
|
+
from .amd import AMDGPUStat, AMDGPUStatCollection
|
|
43
|
+
from .gaudi import GaudiAIPStat, GaudiAIPStatCollection
|
|
44
|
+
from .intel_gpu import IntelGPUStat, IntelGPUStatCollection
|
|
45
|
+
from .huawei import HuaweiNPUStat, HuaweiNPUStatCollection
|
|
46
|
+
from .hygon import HygonDCUStat, HygonDCUStatCollection
|
|
47
|
+
from .cambricon import CambriconMLUStat, CambriconMLUStatCollection
|
|
48
|
+
from .moorethreads import MooreThreadsGPUStat, MooreThreadsGPUStatCollection
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
"__version__",
|
|
52
|
+
"__version_tuple__",
|
|
53
|
+
# Core API
|
|
54
|
+
"query_all",
|
|
55
|
+
"query",
|
|
56
|
+
"XPUStatCollection",
|
|
57
|
+
"AnyDeviceStat",
|
|
58
|
+
# Process info
|
|
59
|
+
"ProcessInfo",
|
|
60
|
+
# Per-vendor stat objects
|
|
61
|
+
"NvidiaGPUStat",
|
|
62
|
+
"NvidiaGPUStatCollection",
|
|
63
|
+
"AMDGPUStat",
|
|
64
|
+
"AMDGPUStatCollection",
|
|
65
|
+
"GaudiAIPStat",
|
|
66
|
+
"GaudiAIPStatCollection",
|
|
67
|
+
"IntelGPUStat",
|
|
68
|
+
"IntelGPUStatCollection",
|
|
69
|
+
"HuaweiNPUStat",
|
|
70
|
+
"HuaweiNPUStatCollection",
|
|
71
|
+
"HygonDCUStat",
|
|
72
|
+
"HygonDCUStatCollection",
|
|
73
|
+
"CambriconMLUStat",
|
|
74
|
+
"CambriconMLUStatCollection",
|
|
75
|
+
"MooreThreadsGPUStat",
|
|
76
|
+
"MooreThreadsGPUStatCollection",
|
|
77
|
+
]
|