Browse Source

增加用户使用情况

master
lxbhahaha 9 months ago
parent
commit
c6570b007b
  1. 4
      README.md
  2. 39
      app.py
  3. 42
      index.html

4
README.md

@ -15,6 +15,7 @@ pip install flask flask-cors paramiko -i https://pypi.tuna.tsinghua.edu.cn/simpl
因为本质上是通过ssh连接服务器,然后通过命令来获取相应的信息,有的命令可能服务器系统上不自带需要另外安装,否则无法获取到对应的数据。
- **ifstat**,用于获取网络数据的工具,可通过apt安装(如果不需要显示网络数据则不用安装)。并且需要在服务器上运行一下命令,查看哪个网卡才是主要的,写到配置文件里去(如果不需要查看网络信息可以不写)。
- **gpustat**,用于获取显卡上用户的使用情况,也可通过apt安装。
- **nvidia驱动**,需要需要安装N卡的驱动,能够通过`nvidia-smi`来获取显卡信息即可(AMD的应该就没办法了)。
其中这个ifstat查看网卡的步骤如下:通过apt安装完成之后,在终端输入`ifstat`,可以看到类似下面的输出(ctrl+c停止),因为一般会不只一个网卡,而且名称也会不一样。此时可以看一下哪个名称的网卡有数据变化,比如下方的就是`eno2`,可以写到配置文件里。
@ -89,4 +90,5 @@ document.addEventListener('DOMContentLoaded', function() {
有域名的话也可以搞一个反向代理,可参考 [服务器上使用Nginx部署网页+反向代理](http://blog.lxblxb.top/archives/1723257245091)。
# 3. 其他
- 永辉帮忙搞了一下顶部checkbox布局的问题
- `永辉`帮忙搞了一下顶部checkbox布局的问题。
- 参考`治鹏`的方法加了每张显卡的用户使用的情况。

39
app.py

@ -76,14 +76,48 @@ def get_gpus_info(client, timeout, info_list:list=None):
'free_mem': free_mem,
'util_gpu': util_gpu,
'util_mem': util_mem,
'temperature': temperature
'temperature': temperature,
'users': {}
})
# 读取用户使用信息
try:
gpustat_cmd = 'gpustat --json'
stdin, stdout, stderr = client.exec_command(gpustat_cmd, timeout=timeout)
gpustat_output = stdout.read().decode()
# 确保 gpustat 输出不是空的
if not gpustat_output:
raise ValueError("gpustat did not return any output.")
gpustat_info = json.loads(gpustat_output)
# 确保解析的 gpustat 信息格式正确
if 'gpus' not in gpustat_info:
raise ValueError("Parsed gpustat info does not contain 'gpus' key.")
# 解析进程信息 -----------------------------
for gpu in gpustat_info['gpus']:
idx = gpu['index']
processes = gpu.get('processes', []) # 使用 get() 方法避免 KeyError
for process in processes:
username = process['username']
gpu_memory_usage = process['gpu_memory_usage'] # 占用的显存
# 找到对应的 GPU,将用户及其显存使用情况记录下来
for gpu_result in result:
if gpu_result['idx'] == idx:
if username not in gpu_result['users']:
gpu_result['users'][username] = 0
gpu_result['users'][username] += gpu_memory_usage
except Exception as e:
if info_list is not None:
info_list.append(f'gpu user: {e}')
return result
except Exception as e:
if info_list is not None:
info_list.append(f'gpus: {e}')
None
return None
def get_storage_info(client, timeout, path_list, info_list:list=None):
try:
@ -157,7 +191,6 @@ def keep_check_one(server: dict, shared_data_list: dict, server_title: str, inte
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(server['ip'], port=server['port'], username=server['username'], password=server.get('password', None), key_filename=server.get('key_filename', None), timeout=interval*3)
cmd = 'nvidia-smi --query-gpu=index,name,memory.total,memory.used,memory.free,utilization.gpu,utilization.memory,temperature.gpu --format=csv'
shared_data_list[server_title]['err_info'] = None
re_try_count = 0

42
index.html

@ -25,6 +25,23 @@
}
.gpu-info {
margin-top: 10px;
border: 1px solid #ccc; /* 边框 */
border-radius: 8px; /* 圆角 */
padding: 10px; /* 内边距 */
margin-bottom: 15px; /* 下边距 */
background-color: #f9f9f9; /* 背景颜色 */
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 阴影 */
}
.user-info {
margin-top: 10px; /* 上边距 */
font-size: 14px; /* 字体大小 */
color: #555; /* 字体颜色 */
}
.user-item {
color: #007bff; /* 用户名颜色 */
font-weight: bold; /* 加粗 */
}
/* 头部样式 */
@ -76,7 +93,7 @@
// 请求服务器获取GPus数据
function fetchData() {
fetch('http://lxblxb.top:15002/all_data')
fetch('http://127.0.0.1:15002/all_data')
// 获取服务器和显卡数据
.then(response => response.json()) // 解析 JSON 响应
.then(data => {
@ -239,9 +256,23 @@
colorDot = redDot;
}
gpuInfo.innerHTML = '<strong>' + gpu.idx + ' - ' + gpu.gpu_name + colorDot + '</strong><br>'
+ 'Temperature: ' + gpu.temperature + '°C<br>'
+ 'Memory: ' + gpu.used_mem + ' / ' + gpu.total_mem + " MB" + '<br>'
+ 'Utilization: ' + gpu.util_gpu + '%';
+ '温度: ' + gpu.temperature + '°C<br>'
+ '显存: ' + gpu.used_mem + ' / ' + gpu.total_mem + " MB" + '<br>'
+ '利用率: ' + gpu.util_gpu + '%';
// 添加用户使用信息
if ('users' in gpu) { // 检查是否有用户信息
let userInfo = document.createElement('div');
userInfo.classList.add('user-info');
userInfo.innerHTML = "<strong>使用情况:</strong>";
for (const [username, pid] of Object.entries(gpu.users)) {
userInfo.innerHTML += `<span class="user-item">${username} (${pid}) </span>`;
}
gpuInfo.appendChild(userInfo); // 将用户信息添加到GPU信息中
}
serverCard.appendChild(gpuInfo);
});
// 分割线
@ -251,9 +282,6 @@
// 错误信息
if ('err_info' in serverData[key])
{
// 分割线
add_bar(serverCard);
let errInfo = document.createElement('div');
errInfo.classList.add('error-info');
errInfo.innerHTML = '<strong>error info</strong><br>' + serverData[key].err_info;

Loading…
Cancel
Save