Skip to content

Commit 9e682fb

Browse files
committed
0.0.1
0 parents  commit 9e682fb

File tree

7 files changed

+223
-0
lines changed

7 files changed

+223
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
moni.build/
2+
moni.dist/
3+
moni.onefile-build/

MoniRuns.png

61.8 KB
Loading

README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<h1 style="text-align:center">Moni([aɪ])</h1>
2+
3+
## README [](README_zh.md) | [EN](README.md)
4+
5+
![Moni](MoniRuns.png)
6+
7+
### What is Moni?
8+
9+
Moni is a simple,easy to use and lightweight monitoring tool for Linux system.
10+
It provides a human readable GUI and rich texted information about the system.
11+
Whether acrros *CPU,RAM and NVIDIA CUDA GPUs* information(support multi GPU ***maybe*** because i have no budget for multi GPU system to test T_T ).
12+
13+
### Why Moni?
14+
15+
Moni has been written in Python,it's friendly for the developer using both NVIDIA CUDA GPU,Python and Linux to hands on.
16+
Also the core component and APIs of Moni is relys on your machine system libraries,that means Moni just a `API Caller` and `Data visualizer`.
17+
18+
### Setup for develop and contributing Moni
19+
I suggest you using env manager like `conda` and `virtualenv`.
20+
21+
Here is the below version of software SDKs version using for Moni development:
22+
- Python 3.10
23+
- CUDA Driver 11.8
24+
- Git
25+
- GCC111
26+
27+
Cloning the Moni repo and install the dependencies:
28+
```bash
29+
git clone https://github.com/ElinLiu0/Moni.git
30+
cd Moni
31+
pip install -r requirements.txt
32+
```
33+
> #### For Conda User
34+
> Don't forget to install `libpython-static` package for building,otherwise Nuitka will throw an error for that.
35+
> You can install it by:
36+
> ```bash
37+
> conda install libpython-static -y
38+
> ```
39+
40+
41+
### How to build Moni?
42+
43+
Once you clone the Moni repo,you will see a `build.sh` that using Nuitka compiler.
44+
I usggest you using GCC11 for building(because i'm using that).
45+
46+
Once you have setup the Python and GCC,then you can run `build.sh` to build the Moni binary file.
47+
Since this building script using some permision of `sudo`,you may need to type your password for these operations.
48+
49+
Once building done,Moni will automatically installed at `/usr/local/bin`,which means you no need to to specify the path for running Moni into system variables.
50+
51+
52+
53+
54+
55+

README_zh.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<h1 style="text-align:center">Moni([aɪ])</h1>
2+
3+
## README [](README_zh.md) | [EN](README.md)
4+
5+
![Moni](MoniRuns.png)
6+
7+
### 什么是Moni?
8+
9+
Moni是一个简单易用的轻量级Linux系统监控工具。
10+
它提供了一个人类可读的GUI,以及由富文本构建的终端信息系统。
11+
包含了CPU,RAM和NVIDIA CUDA GPU的信息(***可能***支持多GPU,因为穷,没钱买多卡T_T)
12+
13+
### 为什么用Moni?
14+
15+
Moni是用Python编写的,对于使用NVIDIA CUDA GPU,Python和Linux的开发人员来说非常友好。
16+
此外,Moni的核心组件和API依赖于您的系统库,这意味着Moni只是一个`API调用器``数据可视化器`
17+
18+
### 开始进行Moni软件环境搭建
19+
我建议您使用`conda``virtualenv`这样的环境管理器。
20+
21+
以下是用于Moni开发的软件SDKs及版本:
22+
- Python 3.10
23+
- CUDA Driver 11.8
24+
- Git
25+
- GCC111
26+
27+
克隆Moni Git仓库并下载Python依赖:
28+
```bash
29+
git clone https://github.com/ElinLiu0/Moni.git
30+
cd Moni
31+
pip install -r requirements.txt
32+
```
33+
> #### 针对Conda用户
34+
> 不要忘记安装`libpython-static`包,否则Nuitka会因为找不到这个包而在执行构建时报错!
35+
> 可通过:
36+
> ```bash
37+
> conda install libpython-static -y
38+
> ```
39+
> 进行安装。
40+
41+
### 如何构建你的Moni?
42+
在克隆了Moni仓库,您将看到一个使用Nuitka编译器的`build.sh`
43+
我建议您使用GCC11进行构建(别问,我就是我用,我跑,我没报错)。
44+
45+
设置好Python和GCC后,就可以运行`build.sh`来构建Moni二进制文件了。
46+
由于此构建脚本使用了`sudo`的某些权限,因此您可能在此期间需要输入一回`sudoer`的密码。
47+
48+
构建完成后,Moni将自动安装在`/usr/local/bin`中,这意味着您无需指定将Moni运行路径添加到系统变量中的路径。
49+
50+
51+
52+
53+

build.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
python -m nuitka --standalone --onefile --include-package=psutil --include-package=pynvml --include-package=rich --include-package=asciichartpy moni.py
2+
mv ./moni.bin ./moni
3+
sudo chmod -R 777 ./moni
4+
sudo mv ./moni /usr/local/bin

moni.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Author: Elin
2+
# Date: 2024-04-25 10:31:02
3+
# Last Modified by: Elin
4+
# Last Modified time: 2024-04-25 10:31:02
5+
6+
import psutil as pt
7+
from typing import List
8+
from pynvml import *
9+
import asciichartpy
10+
import time
11+
from rich.console import Console
12+
from rich.table import Table
13+
from datetime import datetime
14+
15+
class Moni:
16+
def __init__(self):
17+
nvmlInit()
18+
self.console = Console()
19+
self.cpu_name: str = open("/proc/cpuinfo").readlines()[4].split(":")[1].strip()
20+
self.threads: int = pt.cpu_count()
21+
self.mem_size: int = pt.virtual_memory().total // (1024 ** 3) + 1
22+
self.gpus: int = nvmlDeviceGetCount()
23+
self.gpus_names: List[str] = [nvmlDeviceGetName(nvmlDeviceGetHandleByIndex(i)) for i in range(self.gpus)]
24+
self.gpus_mem_size: List[int] = [
25+
nvmlDeviceGetMemoryInfo(nvmlDeviceGetHandleByIndex(i)).total // (1024 ** 3) for i in range(self.gpus)
26+
]
27+
28+
def __call__(self):
29+
while True:
30+
self._flush_data()
31+
self.console.clear()
32+
self._render()
33+
time.sleep(1)
34+
35+
def _render(self):
36+
self.console.print(f"Moni v{self.__version__()} by {self.__author__()}" + " " * 10 + datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
37+
self.console.print(f"CPU: {self.cpu_name}, {self.threads} THREADS")
38+
self.console.print(f"MEM: {self.mem_size} GB, {self.used_mem} GB has been used now")
39+
self.console.print("CPU Usage:")
40+
self.console.print(asciichartpy.plot(self.cpu_percent, {'height': 5}))
41+
for i in range(self.gpus):
42+
self.console.print(f"GPU {i}: {self.gpus_names[i]} ({self.gpus_mem_size[i]} GB), {self.gpus_mem_usage[i]} GB VRAM been used, CORE Temp {self.gpus_temperature[i]} °C")
43+
self.console.print(asciichartpy.plot(self.gpus_volatile_usage[i], {'height': 5}))
44+
self._plot_process_table()
45+
46+
def _plot_process_table(self):
47+
process_table = Table()
48+
fields = ["PID", "USER", "NAME", "STATUS", "CPU_USAGE", "MEM_USAGE", "COMMAND"]
49+
process_table.add_column("PID")
50+
process_table.add_column("USER")
51+
process_table.add_column("NAME")
52+
process_table.add_column("STATUS")
53+
process_table.add_column("CPU_USAGE")
54+
process_table.add_column("MEM_USAGE")
55+
process_table.add_column("COMMAND")
56+
running_process_count:int = 0
57+
sleeping_process_count:int = 0
58+
stopped_process_count:int = 0
59+
zombie_process_count:int = 0
60+
self.process_list = sorted(self.process_list, key=lambda x: (x.cpu_percent(),x.memory_percent()), reverse=True)
61+
for p in self.process_list:
62+
status = p.status()
63+
if status == "running":
64+
running_process_count += 1
65+
elif status == "sleeping":
66+
sleeping_process_count += 1
67+
elif status == "stopped":
68+
stopped_process_count += 1
69+
elif status == "zombie":
70+
zombie_process_count += 1
71+
for p in self.process_list[:10]:
72+
try:
73+
process_table.add_row(str(p.pid), p.username(), p.name(), p.status(), str(round(p.cpu_percent(), 2)) + "%", str(round(p.memory_percent(), 2)) + "%", p.cmdline()[0] if p.cmdline() else "")
74+
except pt.NoSuchProcess or pt.AccessDenied or pt.ZombieProcess:
75+
continue
76+
self.console.print(f"Total Process: {len(self.process_list)}, Running: {running_process_count}, Sleeping: {sleeping_process_count}, Stopped: {stopped_process_count}, Zombie: {zombie_process_count}")
77+
self.console.print(f"Shows TOP10 high utilized process:")
78+
self.console.print(process_table)
79+
80+
def _flush_data(self):
81+
self.used_mem: int = pt.virtual_memory().used // (1024 ** 3) + 1
82+
self.cpu_percent: List[float] = [pt.cpu_percent(interval=1e-1) for _ in range(self.threads)]
83+
self.gpus_mem_usage: List[float] = [
84+
round(nvmlDeviceGetMemoryInfo(nvmlDeviceGetHandleByIndex(i)).used // (1024 ** 3),2) for i in range(self.gpus)
85+
]
86+
self.gpus_temperature: List[int] = [
87+
nvmlDeviceGetTemperature(nvmlDeviceGetHandleByIndex(i), NVML_TEMPERATURE_GPU) for i in range(self.gpus)
88+
]
89+
self.gpus_volatile_usage: List[List[int]] = [
90+
[int(nvmlDeviceGetUtilizationRates(nvmlDeviceGetHandleByIndex(i)).gpu) for _ in range(50)] for i in range(self.gpus)
91+
]
92+
try:
93+
self.process_list: List[pt.Process] = list(pt.process_iter())
94+
except:
95+
self.process_list: List[pt.Process] = []
96+
97+
def __version__(self):
98+
return "0.0.1"
99+
def __author__(self):
100+
return "Elin"
101+
if __name__ == "__main__":
102+
moni = Moni()
103+
moni()

requirements.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
asciichartpy==1.5.25
2+
nvidia_ml_py==12.535.133
3+
psutil==5.9.8
4+
rich==13.7.1
5+
nuitka

0 commit comments

Comments
 (0)