You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
12 KiB
309 lines
12 KiB
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Server and GPU Information</title>
|
|
<style>
|
|
.card {
|
|
margin: 10px;
|
|
padding: 10px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 5px;
|
|
width: 300px;
|
|
display: inline-block;
|
|
vertical-align: top;
|
|
}
|
|
.server-name {
|
|
font-weight: bold;
|
|
margin-bottom: 5px;
|
|
font-size: 24px; /* 调整字体大小 */
|
|
background-color: black; /* 背景色设为黑色 */
|
|
color: white; /* 文字颜色设为白色 */
|
|
padding: 10px; /* 增加内边距使其更美观 */
|
|
border-radius: 5px; /* 可选:增加圆角效果 */
|
|
}
|
|
.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; /* 加粗 */
|
|
}
|
|
|
|
/* 头部样式 */
|
|
.head_contrainer{
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
height: 90px;
|
|
align-items: center;
|
|
}
|
|
.head_contrainer .checkboxes{
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="head_contrainer">
|
|
<div>
|
|
<h1>Server and GPU Information</h1>
|
|
<p id="time"></p>
|
|
</div>
|
|
|
|
<div class="checkboxes">
|
|
<div class="sample">
|
|
<label for="toggle_network">网络</label>
|
|
<input type="checkbox" id="toggle_network" checked onchange="updateDisplay()">
|
|
</div>
|
|
<div class="sample">
|
|
<label for="toggle_memory">内存</label>
|
|
<input type="checkbox" id="toggle_memory" checked onchange="updateDisplay()">
|
|
</div>
|
|
<div class="sample">
|
|
<label for="toggle_storage">存储</label>
|
|
<input type="checkbox" id="toggle_storage" checked onchange="updateDisplay()">
|
|
</div>
|
|
<div class="sample">
|
|
<label for="toggle_gpus">显卡</label>
|
|
<input type="checkbox" id="toggle_gpus" checked onchange="updateDisplay()">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="server-data"></div>
|
|
|
|
<script>
|
|
let lastData = null;
|
|
|
|
// 请求服务器获取GPus数据
|
|
function fetchData() {
|
|
fetch('http://127.0.0.1:15002/all_data')
|
|
// 获取服务器和显卡数据
|
|
.then(response => response.json()) // 解析 JSON 响应
|
|
.then(data => {
|
|
// 处理 JSON 数据
|
|
// console.log(data);
|
|
displayServerData(data); // 调用显示数据的函数
|
|
})
|
|
.catch(error => {
|
|
// console.error('Error fetching data:', error);
|
|
displayError(error + " (多半是没有正确连接服务器端,可能是没开、网络错误)");
|
|
});
|
|
}
|
|
|
|
function displayError(err_info){
|
|
let serverDataContainer = document.getElementById('server-data');
|
|
serverDataContainer.innerHTML = ''; // 清空容器
|
|
|
|
let errDiv = document.createElement('div');
|
|
errDiv.classList.add('error-info');
|
|
errDiv.innerHTML = err_info;
|
|
serverDataContainer.appendChild(errDiv);
|
|
}
|
|
|
|
function parse_data_unit(num, fixedLen=2){
|
|
if (num < 1024){
|
|
return num.toFixed(fixedLen) + " KB";
|
|
}
|
|
|
|
num /= 1024;
|
|
if (num < 1024){
|
|
return num.toFixed(fixedLen) + " MB";
|
|
}
|
|
|
|
num /= 1024;
|
|
if (num < 1024){
|
|
return num.toFixed(fixedLen) + " GB";
|
|
}
|
|
|
|
num /= 1024;
|
|
if (num < 1024){
|
|
return num.toFixed(fixedLen) + " TB";
|
|
}
|
|
}
|
|
|
|
function add_bar(serverCard){
|
|
let bar = document.createElement('hr');
|
|
serverCard.appendChild(bar);
|
|
}
|
|
|
|
function updateDisplay(){
|
|
if (lastData != null){
|
|
displayServerData(lastData);
|
|
}
|
|
}
|
|
|
|
// 页面绑定数据
|
|
function displayServerData(data) {
|
|
lastData = data;
|
|
// 绘制 -------------------
|
|
let serverDataContainer = document.getElementById('server-data');
|
|
serverDataContainer.innerHTML = ''; // 清空容器
|
|
|
|
let timeStr = data['time']
|
|
let serverData = data['server_data']
|
|
|
|
let timeDiv = document.getElementById('time')
|
|
timeDiv.textContent = "更新时间为:" + timeStr
|
|
|
|
let greenDot = '<span style="color: green;"> 空闲</span>';
|
|
let yellowDot = '<span style="color: orange;"> 占用</span>';
|
|
let redDot = '<span style="color: red;"> 占用</span>';
|
|
|
|
for (let key in serverData){
|
|
let serverCard = document.createElement('div');
|
|
serverCard.classList.add('card');
|
|
|
|
// 标题
|
|
let serverName = document.createElement('div');
|
|
serverName.classList.add('server-name');
|
|
let updateFlag = serverData[key].updated ? '' : ' - Not updated -';
|
|
serverName.textContent = key + updateFlag;
|
|
serverCard.appendChild(serverName);
|
|
|
|
// 网速
|
|
if (document.getElementById('toggle_network').checked && 'network_info' in serverData[key]){
|
|
let networkInfo = document.createElement('div');
|
|
networkInfo.classList.add('network-info');
|
|
|
|
let inNum = serverData[key].network_info.in;
|
|
let outNum = serverData[key].network_info.out;
|
|
inNum = parse_data_unit(inNum)
|
|
outNum = parse_data_unit(outNum)
|
|
|
|
networkInfo.innerHTML += "<strong> 网络 : </strong> in: " + inNum + "/s, out: " + outNum + "/s";
|
|
|
|
serverCard.appendChild(networkInfo);
|
|
// 分割线
|
|
add_bar(serverCard);
|
|
}
|
|
|
|
// 内存
|
|
if (document.getElementById('toggle_memory').checked && 'memory_info' in serverData[key]){
|
|
let memoryInfo = document.createElement('div');
|
|
memoryInfo.classList.add('memory-info');
|
|
|
|
let totalNum = serverData[key].memory_info.total
|
|
let usedNum = serverData[key].memory_info.used
|
|
let totalMem = parse_data_unit(totalNum);
|
|
let usedMem = parse_data_unit(usedNum);
|
|
let tmpColor = "green";
|
|
if (usedNum / totalNum > 0.8)
|
|
tmpColor = "red";
|
|
else if (usedNum / totalNum > 0.6)
|
|
tmpColor = "orange";
|
|
|
|
memoryInfo.innerHTML += "<strong> 内存 : </strong> <span style=\"color: " + tmpColor + ";\">" + usedMem + " / " + totalMem + "</span><br>";
|
|
|
|
serverCard.appendChild(memoryInfo);
|
|
// 分割线
|
|
add_bar(serverCard);
|
|
}
|
|
|
|
// 存储空间
|
|
if (document.getElementById('toggle_storage').checked && 'storage_info_list' in serverData[key]){
|
|
let storageInfo = document.createElement('div');
|
|
storageInfo.classList.add('storage-info');
|
|
|
|
for (let i = 0; i < serverData[key].storage_info_list.length; i++) {
|
|
let targetPath = serverData[key].storage_info_list[i].path;
|
|
let totalNum = serverData[key].storage_info_list[i].total
|
|
let availableNum = serverData[key].storage_info_list[i].available
|
|
let totalStorage = parse_data_unit(totalNum);
|
|
let availableStorage = parse_data_unit(totalNum - availableNum);
|
|
let tmpColor = "green";
|
|
if (availableNum / totalNum < 0.1)
|
|
tmpColor = "red";
|
|
else if (availableNum / totalNum < 0.3)
|
|
tmpColor = "orange";
|
|
storageInfo.innerHTML += '<strong>' + targetPath + " :</strong> <span style=\"color: " + tmpColor
|
|
+ ";\">" + availableStorage + " / " + totalStorage + "</span><br>";
|
|
}
|
|
|
|
serverCard.appendChild(storageInfo);
|
|
// 分割线
|
|
add_bar(serverCard);
|
|
}
|
|
|
|
// gpu
|
|
if (document.getElementById('toggle_gpus').checked && 'gpu_info_list' in serverData[key]){
|
|
serverData[key].gpu_info_list.forEach(function(gpu){
|
|
let gpuInfo = document.createElement('div');
|
|
gpuInfo.classList.add('gpu-info');
|
|
let colorDot = greenDot;
|
|
if (gpu.used_mem < 1000 && gpu.util_gpu < 20){
|
|
colorDot = greenDot;
|
|
}
|
|
else if (gpu.util_mem < 50){
|
|
colorDot = yellowDot;
|
|
}else{
|
|
colorDot = redDot;
|
|
}
|
|
gpuInfo.innerHTML = '<strong>' + gpu.idx + ' - ' + gpu.gpu_name + colorDot + '</strong><br>'
|
|
+ '温度: ' + 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);
|
|
});
|
|
// 分割线
|
|
add_bar(serverCard);
|
|
}
|
|
|
|
// 错误信息
|
|
if ('err_info' in serverData[key])
|
|
{
|
|
let errInfo = document.createElement('div');
|
|
errInfo.classList.add('error-info');
|
|
errInfo.innerHTML = '<strong>error info</strong><br>' + serverData[key].err_info;
|
|
serverCard.appendChild(errInfo);
|
|
// 分割线
|
|
add_bar(serverCard);
|
|
}
|
|
|
|
// 删除最后的分割线
|
|
if (serverCard.lastElementChild && serverCard.lastElementChild.tagName === 'HR') {
|
|
serverCard.removeChild(serverCard.lastElementChild);
|
|
}
|
|
|
|
serverDataContainer.appendChild(serverCard);
|
|
}
|
|
}
|
|
|
|
// 页面加载时获取数据并定时刷新
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
fetchData();
|
|
setInterval(fetchData, 3000); // 每3秒刷新一次数据
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|