GPU检测修改
This commit is contained in:
@@ -6,3 +6,4 @@ cryptography==41.0.7
|
||||
requests==2.31.0
|
||||
psutil==5.9.8
|
||||
werkzeug==3.0.1
|
||||
pynvml==11.5.0
|
||||
|
||||
150
src/main.py
150
src/main.py
@@ -366,6 +366,156 @@ def health_check():
|
||||
return jsonify({'status': 'error', 'code': 1, 'message': str(e)})
|
||||
|
||||
|
||||
# ============ 详细系统监控 ============
|
||||
@app.route('/api/system-info', methods=['GET'])
|
||||
def system_info():
|
||||
"""获取详细系统监控信息"""
|
||||
import psutil
|
||||
import os
|
||||
try:
|
||||
# CPU 信息
|
||||
cpu_percent = psutil.cpu_percent(interval=None)
|
||||
cpu_counts = psutil.cpu_count()
|
||||
cpu_freq = psutil.cpu_freq()
|
||||
|
||||
# 内存信息
|
||||
memory = psutil.virtual_memory()
|
||||
|
||||
# 磁盘信息
|
||||
disk = psutil.disk_usage('/')
|
||||
disk_io = psutil.disk_io_counters()
|
||||
|
||||
# 网络信息
|
||||
net_io = psutil.net_io_counters()
|
||||
|
||||
# 系统启动时间
|
||||
boot_time = psutil.boot_time()
|
||||
uptime_seconds = time.time() - boot_time
|
||||
|
||||
# GPU 信息
|
||||
gpu_list = []
|
||||
try:
|
||||
import pynvml
|
||||
pynvml.nvmlInit()
|
||||
gpu_count = pynvml.nvmlDeviceGetCount()
|
||||
for i in range(gpu_count):
|
||||
try:
|
||||
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
|
||||
name = pynvml.nvmlDeviceGetName(handle)
|
||||
|
||||
# 获取显存信息
|
||||
try:
|
||||
mem_info = pynvml.nvmlDeviceGetMemoryInfo(handle)
|
||||
memory_used = mem_info.used
|
||||
memory_total = mem_info.total
|
||||
except:
|
||||
memory_used = 0
|
||||
memory_total = 0
|
||||
|
||||
# 获取利用率
|
||||
try:
|
||||
util = pynvml.nvmlDeviceGetUtilizationRates(handle)
|
||||
gpu_util = util.gpu
|
||||
mem_util = util.memory
|
||||
except:
|
||||
gpu_util = 0
|
||||
mem_util = 0
|
||||
|
||||
# 获取温度 - pynvml 11.x API: 只接受handle参数
|
||||
try:
|
||||
temp = pynvml.nvmlDeviceGetTemperature(handle)
|
||||
except:
|
||||
temp = 0
|
||||
|
||||
# 获取功耗
|
||||
try:
|
||||
power = pynvml.nvmlDeviceGetPowerUsage(handle)
|
||||
except:
|
||||
power = 0
|
||||
|
||||
# 获取风扇转速 (百分比)
|
||||
try:
|
||||
fan_speed = pynvml.nvmlDeviceGetFanSpeed(handle)
|
||||
except:
|
||||
fan_speed = 0
|
||||
|
||||
# 获取显卡时钟频率 (MHz)
|
||||
try:
|
||||
clock = pynvml.nvmlDeviceGetClockInfo(handle, pynvml.NVML_CLOCK_SM)
|
||||
except:
|
||||
clock = 0
|
||||
|
||||
# 获取显存时钟频率 (MHz)
|
||||
try:
|
||||
mem_clock = pynvml.nvmlDeviceGetClockInfo(handle, pynvml.NVML_CLOCK_MEM)
|
||||
except:
|
||||
mem_clock = 0
|
||||
|
||||
# 获取驱动版本信息
|
||||
try:
|
||||
version = pynvml.nvmlSystemGetDriverVersion()
|
||||
except:
|
||||
version = ''
|
||||
|
||||
gpu_list.append({
|
||||
'name': name.decode() if isinstance(name, bytes) else name,
|
||||
'memory_used_gb': round(memory_used / (1024**3), 1),
|
||||
'memory_total_gb': round(memory_total / (1024**3), 1),
|
||||
'gpu_percent': gpu_util,
|
||||
'memory_percent': mem_util,
|
||||
'temperature': temp,
|
||||
'power_w': round(power / 1000, 1) if power > 0 else 0,
|
||||
'fan_speed': fan_speed,
|
||||
'clock_mhz': clock,
|
||||
'memory_clock_mhz': mem_clock,
|
||||
'driver_version': version.decode() if isinstance(version, bytes) else version
|
||||
})
|
||||
except Exception as e:
|
||||
logger.debug(f"获取GPU {i} 信息失败: {e}")
|
||||
continue
|
||||
pynvml.nvmlShutdown()
|
||||
except Exception as e:
|
||||
logger.warning(f"获取GPU信息失败: {e}")
|
||||
gpu_list = []
|
||||
|
||||
return jsonify({
|
||||
'code': 0,
|
||||
'data': {
|
||||
'cpu': {
|
||||
'percent': cpu_percent,
|
||||
'cores': cpu_counts,
|
||||
'frequency_mhz': cpu_freq.current if cpu_freq else 0
|
||||
},
|
||||
'memory': {
|
||||
'percent': memory.percent,
|
||||
'used_gb': round(memory.used / (1024**3), 1),
|
||||
'total_gb': round(memory.total / (1024**3), 1),
|
||||
'available_gb': round(memory.available / (1024**3), 1),
|
||||
'cached_gb': round(memory.cached / (1024**3), 1) if hasattr(memory, 'cached') else 0
|
||||
},
|
||||
'disk': {
|
||||
'percent': disk.percent,
|
||||
'used_gb': round(disk.used / (1024**3), 0),
|
||||
'total_gb': round(disk.total / (1024**3), 0),
|
||||
'read_mb': round(disk_io.read_bytes / (1024**2), 0),
|
||||
'write_mb': round(disk_io.write_bytes / (1024**2), 0)
|
||||
},
|
||||
'network': {
|
||||
'upload_mb': round(net_io.bytes_sent / (1024**2), 1),
|
||||
'download_mb': round(net_io.bytes_recv / (1024**2), 1)
|
||||
},
|
||||
'system': {
|
||||
'uptime_seconds': uptime_seconds,
|
||||
'process_count': len(psutil.pids())
|
||||
},
|
||||
'gpu': gpu_list
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"获取系统信息失败: {e}")
|
||||
return jsonify({'code': 1, 'message': str(e)})
|
||||
|
||||
|
||||
# ============ 通用 CRUD 操作 ============
|
||||
def generic_get_all(table_name, order_by='create_time DESC'):
|
||||
"""通用查询所有"""
|
||||
|
||||
@@ -826,31 +826,64 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 获取GPU数据(模拟数据,实际可从API获取)
|
||||
// 获取GPU数据(从真实API获取)
|
||||
async function fetchGPUs() {
|
||||
// 实际项目中可以调用后端API获取GPU信息
|
||||
// const response = await fetch(`${API_BASE}/gpus`);
|
||||
// return await response.json();
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/system-info`);
|
||||
const result = await response.json();
|
||||
|
||||
// 模拟GPU数据
|
||||
if (result.code === 0 && result.data.gpu && result.data.gpu.length > 0) {
|
||||
// 将真实GPU数据转换为前端所需格式
|
||||
return result.data.gpu.map((gpu, index) => ({
|
||||
id: `gpu${index}`,
|
||||
name: gpu.name || `GPU ${index}`,
|
||||
memory: `${gpu.memory_total_gb}GB`,
|
||||
cuda_cores: 'N/A',
|
||||
available: gpu.power_w > 0 || gpu.gpu_percent >= 0, // 有数据即为可用
|
||||
real_data: gpu // 保存真实数据供显示
|
||||
}));
|
||||
}
|
||||
|
||||
// 如果没有真实数据,尝试获取驱动版本
|
||||
const driverVersion = result.data.gpu?.[0]?.driver_version || '';
|
||||
if (driverVersion) {
|
||||
return [{
|
||||
id: 'gpu0',
|
||||
name: 'NVIDIA GPU (Detected)',
|
||||
memory: 'Unknown',
|
||||
cuda_cores: 'N/A',
|
||||
available: true,
|
||||
real_data: result.data.gpu?.[0] || null
|
||||
}];
|
||||
}
|
||||
|
||||
throw new Error('未检测到GPU设备');
|
||||
} catch (error) {
|
||||
console.warn('获取GPU信息失败,使用模拟数据:', error);
|
||||
// 失败时返回模拟数据作为后备
|
||||
return [
|
||||
{ id: 'gpu0', name: 'NVIDIA A100 80GB', memory: '80GB', cuda_cores: 6912, available: true },
|
||||
{ id: 'gpu1', name: 'NVIDIA A100 80GB', memory: '80GB', cuda_cores: 6912, available: true },
|
||||
{ id: 'gpu2', name: 'NVIDIA A100 40GB', memory: '40GB', cuda_cores: 6912, available: true },
|
||||
{ id: 'gpu3', name: 'NVIDIA A100 40GB', memory: '40GB', cuda_cores: 6912, available: false },
|
||||
{ id: 'gpu4', name: 'NVIDIA V100 32GB', memory: '32GB', cuda_cores: 5120, available: true },
|
||||
{ id: 'gpu5', name: 'NVIDIA V100 16GB', memory: '16GB', cuda_cores: 5120, available: false },
|
||||
{ id: 'gpu6', name: 'NVIDIA RTX 3090', memory: '24GB', cuda_cores: 10496, available: true },
|
||||
{ id: 'gpu7', name: 'NVIDIA RTX 4090', memory: '24GB', cuda_cores: 16384, available: true }
|
||||
{ id: 'gpu0', name: 'NVIDIA GPU (未检测到)', memory: 'Unknown', cuda_cores: 'N/A', available: false }
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染GPU列表(点击卡片选中,无需复选框)
|
||||
function renderGPUList(gpus) {
|
||||
const container = document.getElementById('gpuSelectionArea');
|
||||
if (!container) return;
|
||||
|
||||
container.innerHTML = gpus.map(gpu => `
|
||||
container.innerHTML = gpus.map(gpu => {
|
||||
// 从真实数据中提取监控信息
|
||||
const realData = gpu.real_data || {};
|
||||
const memoryUsed = realData.memory_used_gb || 0;
|
||||
const memoryTotal = realData.memory_total_gb || 0;
|
||||
const temp = realData.temperature || 0;
|
||||
const power = realData.power_w || 0;
|
||||
const gpuPercent = realData.gpu_percent || 0;
|
||||
const fanSpeed = realData.fan_speed || 0;
|
||||
const clock = realData.clock_mhz || 0;
|
||||
|
||||
return `
|
||||
<div id="gpu_card_${gpu.id}"
|
||||
class="gpu-card ${!gpu.available ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:border-primary'} border rounded-lg p-3 transition-all"
|
||||
onclick="toggleGPUSelection('${gpu.id}')"
|
||||
@@ -865,14 +898,27 @@
|
||||
? '<i class="fa fa-check-circle text-green-600 text-xs"></i>'
|
||||
: '<i class="fa fa-times-circle text-red-500 text-xs"></i>'}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 mt-1">
|
||||
<span class="mr-2"><i class="fa fa-floppy-o mr-1"></i>${gpu.memory}</span>
|
||||
<span><i class="fa fa-cog mr-1"></i>${gpu.cuda_cores} CUDA</span>
|
||||
<div class="text-xs text-gray-500 mt-1 flex flex-wrap gap-2">
|
||||
<span class="mr-2"><i class="fa fa-floppy-o mr-1"></i>${memoryUsed}/${memoryTotal} GB</span>
|
||||
<span class="mr-2"><i class="fa fa-thermometer-half mr-1"></i>${temp}°C</span>
|
||||
<span class="mr-2"><i class="fa fa-bolt mr-1"></i>${power} W</span>
|
||||
<span><i class="fa fa-tachometer mr-1"></i>${clock} MHz</span>
|
||||
</div>
|
||||
<!-- GPU利用率进度条 -->
|
||||
<div class="mt-2">
|
||||
<div class="flex justify-between text-[10px] text-gray-400 mb-0.5">
|
||||
<span>GPU: ${gpuPercent}%</span>
|
||||
<span>Fan: ${fanSpeed}%</span>
|
||||
</div>
|
||||
<div class="h-1.5 bg-gray-200 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-gradient-to-r from-green-400 via-yellow-400 to-red-400 transition-all"
|
||||
style="width: ${gpuPercent}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
</div>
|
||||
`}).join('');
|
||||
}
|
||||
|
||||
// 切换GPU选择状态
|
||||
@@ -884,11 +930,16 @@
|
||||
if (card.classList.contains('border-primary')) {
|
||||
// 取消选中
|
||||
card.classList.remove('border-primary', 'bg-blue-50');
|
||||
card.querySelector('.fa-check-circle').classList.replace('text-primary', 'text-green-600');
|
||||
// 恢复图标为可选中状态(绿色勾选圈)
|
||||
const icon = card.querySelector('.fa-check, .fa-check-circle');
|
||||
if (icon) {
|
||||
icon.classList.remove('fa-check', 'text-primary');
|
||||
icon.classList.add('fa-check-circle', 'text-green-600');
|
||||
}
|
||||
} else {
|
||||
// 选中
|
||||
card.classList.add('border-primary', 'bg-blue-50');
|
||||
// 移除检查图标,添加选中标记
|
||||
// 切换图标为已选中状态(蓝色勾选)
|
||||
const icon = card.querySelector('.fa-check-circle');
|
||||
if (icon) {
|
||||
icon.classList.remove('fa-check-circle', 'text-green-600');
|
||||
@@ -900,7 +951,17 @@
|
||||
// 获取选中的GPU列表
|
||||
function getSelectedGPUs() {
|
||||
const cards = document.querySelectorAll('.gpu-card.border-primary');
|
||||
return Array.from(cards).map(card => card.dataset.gpuId);
|
||||
return Array.from(cards).map(card => {
|
||||
const gpuId = card.dataset.gpuId;
|
||||
// 获取GPU名称和显存信息用于显示
|
||||
const nameEl = card.querySelector('.text-gray-700');
|
||||
const name = nameEl ? nameEl.textContent : gpuId;
|
||||
// 返回GPU信息对象
|
||||
return {
|
||||
id: gpuId,
|
||||
name: name
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
|
||||
@@ -1721,8 +1721,69 @@
|
||||
let refreshTimer = null;
|
||||
let currentRefreshInterval = 5000;
|
||||
|
||||
// 刷新硬件信息
|
||||
function refreshHardwareInfo() {
|
||||
// 刷新硬件信息(使用真实API)
|
||||
async function refreshHardwareInfo() {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/system-info`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.code === 0 && result.data) {
|
||||
const data = result.data;
|
||||
|
||||
// 更新CPU
|
||||
const cpu = data.cpu || {};
|
||||
const cpuPercent = cpu.percent || 0;
|
||||
document.getElementById('cpuPercent').textContent = cpuPercent + '%';
|
||||
document.getElementById('cpuBar').style.width = cpuPercent + '%';
|
||||
document.getElementById('cpuCores').textContent = (cpu.cores || 0) + ' 核心';
|
||||
|
||||
// 更新内存
|
||||
const mem = data.memory || {};
|
||||
const memUsed = mem.used_gb || 0;
|
||||
const memTotal = mem.total_gb || 0;
|
||||
const memPercent = mem.percent || 0;
|
||||
document.getElementById('memoryPercent').textContent = memPercent + '%';
|
||||
document.getElementById('memoryBar').style.width = memPercent + '%';
|
||||
document.getElementById('memoryUsed').textContent = memUsed + ' GB';
|
||||
document.getElementById('memoryAvailable').textContent = (mem.available_gb || 0) + ' GB';
|
||||
document.getElementById('memoryCached').textContent = (mem.cached_gb || 0) + ' GB';
|
||||
|
||||
// 更新磁盘
|
||||
const disk = data.disk || {};
|
||||
const diskUsed = disk.used_gb || 0;
|
||||
const diskTotal = disk.total_gb || 0;
|
||||
const diskPercent = disk.percent || 0;
|
||||
document.getElementById('diskPercent').textContent = diskPercent + '%';
|
||||
document.getElementById('diskBar').style.width = diskPercent + '%';
|
||||
document.getElementById('diskUsed').textContent = diskUsed + ' GB';
|
||||
document.getElementById('diskAvailable').textContent = (diskTotal - diskUsed) + ' GB';
|
||||
|
||||
// 更新网络
|
||||
const net = data.network || {};
|
||||
document.getElementById('totalDownload').textContent = (net.download_mb || 0) + ' GB';
|
||||
document.getElementById('totalUpload').textContent = (net.upload_mb || 0) + ' GB';
|
||||
|
||||
// 更新系统信息
|
||||
const sys = data.system || {};
|
||||
const uptime = sys.uptime_seconds || 0;
|
||||
const days = Math.floor(uptime / 86400);
|
||||
const hours = Math.floor((uptime % 86400) / 3600);
|
||||
const mins = Math.floor((uptime % 3600) / 60);
|
||||
document.getElementById('uptime').textContent = days + ' 天 ' + hours + ' 时 ' + mins + ' 分';
|
||||
document.getElementById('processCount').textContent = sys.process_count || 0;
|
||||
|
||||
// 更新GPU信息(传入真实数据)
|
||||
updateGPUInfo(data.gpu || []);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取系统信息失败:', error);
|
||||
// 如果API调用失败,使用模拟数据作为后备
|
||||
useMockData();
|
||||
}
|
||||
}
|
||||
|
||||
// 使用模拟数据(当API不可用时)
|
||||
function useMockData() {
|
||||
// 更新CPU
|
||||
const cpuUsage = Math.floor(Math.random() * 30) + 20;
|
||||
document.getElementById('cpuPercent').textContent = cpuUsage + '%';
|
||||
@@ -1768,10 +1829,6 @@
|
||||
document.getElementById('uptime').textContent = days + ' 天 ' + hours + ' 时 ' + mins + ' 分';
|
||||
document.getElementById('processCount').textContent = Math.floor(Math.random() * 200 + 100);
|
||||
document.getElementById('loadAvg').textContent = (Math.random() * 2).toFixed(2) + ', ' + (Math.random() * 1.5).toFixed(2) + ', ' + (Math.random() * 1).toFixed(2);
|
||||
|
||||
// 更新时间
|
||||
// const now = new Date();
|
||||
// document.getElementById('updateTime').textContent = now.toLocaleTimeString('zh-CN');
|
||||
}
|
||||
|
||||
// GPU配置 - 支持模拟1-8块GPU
|
||||
@@ -1787,15 +1844,118 @@
|
||||
{ name: 'NVIDIA RTX 4080', memory: 16 }
|
||||
];
|
||||
|
||||
// 初始化GPU列表
|
||||
function initGPUList() {
|
||||
const gpuList = document.getElementById('gpuList');
|
||||
const gpuCount = Math.min(GPU_COUNT, 8);
|
||||
// 初始化GPU列表(获取真实数据)
|
||||
async function initGPUList() {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/system-info`);
|
||||
const result = await response.json();
|
||||
const gpuData = (result.data && result.data.gpu) || [];
|
||||
updateGPUInfo(gpuData);
|
||||
} catch (error) {
|
||||
console.error('初始化GPU列表失败:', error);
|
||||
useMockGPUData();
|
||||
}
|
||||
}
|
||||
|
||||
// 更新GPU信息
|
||||
function updateGPUInfo(gpuData) {
|
||||
// 如果有真实数据,使用真实数据
|
||||
if (gpuData && gpuData.length > 0) {
|
||||
const gpuCount = gpuData.length;
|
||||
document.getElementById('gpuCount').textContent = `检测到 ${gpuCount} 块 GPU`;
|
||||
|
||||
let totalUsedMemory = 0;
|
||||
let totalMemory = 0;
|
||||
|
||||
// 重新初始化GPU列表
|
||||
const gpuList = document.getElementById('gpuList');
|
||||
if (gpuList) {
|
||||
let gpuCardsHTML = '';
|
||||
for (let i = 0; i < gpuCount; i++) {
|
||||
const gpu = gpuData[i];
|
||||
totalUsedMemory += gpu.memory_used_gb;
|
||||
totalMemory += gpu.memory_total_gb;
|
||||
|
||||
gpuCardsHTML += `
|
||||
<div class="border border-gray-200 rounded-lg p-2 bg-gradient-to-br from-gray-50 to-gray-100" id="gpuCard${i}">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<div class="flex items-center min-w-0">
|
||||
<div class="w-6 h-6 rounded bg-red-100 flex items-center justify-center mr-2 flex-shrink-0">
|
||||
<i class="fa fa-microchip text-red-600 text-xs"></i>
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<div class="text-xs font-medium text-gray-800 truncate" id="gpuName${i}" title="${gpu.name}">${gpu.name}</div>
|
||||
<div class="text-[10px] text-gray-400">PCIe</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-gray-800" id="gpuPercent${i}">${gpu.gpu_percent}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative h-1.5 bg-gray-200 rounded-full overflow-hidden mb-2">
|
||||
<div id="gpuBar${i}" class="absolute left-0 top-0 h-full bg-gradient-to-r from-green-400 via-yellow-400 to-red-400 transition-all duration-500" style="width: ${gpu.gpu_percent}%"></div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-1 text-center text-[10px]">
|
||||
<div class="bg-white/80 rounded py-0.5">
|
||||
<div class="text-gray-400">显存</div>
|
||||
<div class="font-medium text-gray-700" id="gpuMem${i}">${gpu.memory_used_gb}/${gpu.memory_total_gb} GB</div>
|
||||
</div>
|
||||
<div class="bg-white/80 rounded py-0.5">
|
||||
<div class="text-gray-400">温度</div>
|
||||
<div class="font-medium ${gpu.temperature >= 80 ? 'text-red-600' : gpu.temperature >= 70 ? 'text-yellow-600' : 'text-gray-800'}" id="gpuTemp${i}">${gpu.temperature}°C</div>
|
||||
</div>
|
||||
<div class="bg-white/80 rounded py-0.5">
|
||||
<div class="text-gray-400">功耗</div>
|
||||
<div class="font-medium text-gray-700" id="gpuPower${i}">${gpu.power_w} W</div>
|
||||
</div>
|
||||
<div class="bg-white/80 rounded py-0.5">
|
||||
<div class="text-gray-400">Fan</div>
|
||||
<div class="font-medium text-gray-700" id="gpuFan${i}">${gpu.fan_speed || 0}%</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-1 grid grid-cols-2 gap-1 text-center text-[9px] text-gray-400">
|
||||
<div>Clock: <span id="gpuClock${i}">${gpu.clock_mhz || 0} MHz</span></div>
|
||||
<div>Driver: <span id="gpuDriver${i}">${gpu.driver_version || '-'}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
gpuList.innerHTML = gpuCardsHTML;
|
||||
}
|
||||
|
||||
// 更新总显存
|
||||
const gpuTotalMem = document.getElementById('gpuTotalMemory');
|
||||
if (gpuTotalMem) {
|
||||
gpuTotalMem.textContent = `${totalUsedMemory}/${totalMemory} GB`;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 没有真实数据,使用模拟数据
|
||||
useMockGPUData();
|
||||
}
|
||||
|
||||
// 使用模拟GPU数据
|
||||
function useMockGPUData() {
|
||||
const gpuCount = Math.min(GPU_COUNT, 8);
|
||||
let totalUsedMemory = 0;
|
||||
let totalMemory = 0;
|
||||
|
||||
// 重新初始化GPU列表
|
||||
const gpuList = document.getElementById('gpuList');
|
||||
if (gpuList) {
|
||||
let gpuCardsHTML = '';
|
||||
for (let i = 0; i < gpuCount; i++) {
|
||||
const config = gpuConfigs[i % gpuConfigs.length];
|
||||
const gpuUsage = Math.floor(Math.random() * 60 + 20);
|
||||
const memUsed = (Math.random() * config.memory * 0.7 + config.memory * 0.1).toFixed(1);
|
||||
const temp = Math.floor(Math.random() * 30 + 40);
|
||||
const power = Math.floor(Math.random() * 150 + 100);
|
||||
const fan = Math.floor(gpuUsage + Math.random() * 10);
|
||||
|
||||
totalUsedMemory += parseFloat(memUsed);
|
||||
totalMemory += config.memory;
|
||||
|
||||
gpuCardsHTML += `
|
||||
<div class="border border-gray-200 rounded-lg p-2 bg-gradient-to-br from-gray-50 to-gray-100" id="gpuCard${i}">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
@@ -1809,73 +1969,42 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-gray-800" id="gpuPercent${i}">0%</span>
|
||||
<span class="text-sm font-bold text-gray-800" id="gpuPercent${i}">${gpuUsage}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative h-1.5 bg-gray-200 rounded-full overflow-hidden mb-2">
|
||||
<div id="gpuBar${i}" class="absolute left-0 top-0 h-full bg-gradient-to-r from-green-400 via-yellow-400 to-red-400 transition-all duration-500" style="width: 0%"></div>
|
||||
<div id="gpuBar${i}" class="absolute left-0 top-0 h-full bg-gradient-to-r from-green-400 via-yellow-400 to-red-400 transition-all duration-500" style="width: ${gpuUsage}%"></div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 gap-1 text-center text-[10px]">
|
||||
<div class="bg-white/80 rounded py-0.5">
|
||||
<div class="text-gray-400">显存</div>
|
||||
<div class="font-medium text-gray-700 truncate" id="gpuMem${i}" title="0/${config.memory} GB">0/${config.memory}G</div>
|
||||
<div class="font-medium text-gray-700" id="gpuMem${i}">${parseFloat(memUsed).toFixed(1)}/${config.memory} GB</div>
|
||||
</div>
|
||||
<div class="bg-white/80 rounded py-0.5">
|
||||
<div class="text-gray-400">温度</div>
|
||||
<div class="font-medium text-gray-700" id="gpuTemp${i}">0°C</div>
|
||||
<div class="font-medium ${temp >= 80 ? 'text-red-600' : temp >= 70 ? 'text-yellow-600' : 'text-gray-800'}" id="gpuTemp${i}">${temp}°C</div>
|
||||
</div>
|
||||
<div class="bg-white/80 rounded py-0.5">
|
||||
<div class="text-gray-400">功耗</div>
|
||||
<div class="font-medium text-gray-700" id="gpuPower${i}">0W</div>
|
||||
<div class="font-medium text-gray-700" id="gpuPower${i}">${power} W</div>
|
||||
</div>
|
||||
<div class="bg-white/80 rounded py-0.5">
|
||||
<div class="text-gray-400">Fan</div>
|
||||
<div class="font-medium text-gray-700" id="gpuFan${i}">0%</div>
|
||||
<div class="font-medium text-gray-700" id="gpuFan${i}">${fan}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
gpuList.innerHTML = gpuCardsHTML;
|
||||
}
|
||||
|
||||
// 更新GPU信息
|
||||
function updateGPUInfo() {
|
||||
const gpuCount = Math.min(GPU_COUNT, 8);
|
||||
let totalUsedMemory = 0;
|
||||
let totalMemory = 0;
|
||||
|
||||
for (let i = 0; i < gpuCount; i++) {
|
||||
const config = gpuConfigs[i % gpuConfigs.length];
|
||||
const gpuUsage = Math.floor(Math.random() * 60 + 20);
|
||||
const memUsed = (Math.random() * config.memory * 0.7 + config.memory * 0.1).toFixed(1);
|
||||
const temp = Math.floor(Math.random() * 30 + 40);
|
||||
const power = Math.floor(Math.random() * 150 + 100);
|
||||
const fan = Math.floor(gpuUsage + Math.random() * 10);
|
||||
|
||||
totalUsedMemory += parseFloat(memUsed);
|
||||
totalMemory += config.memory;
|
||||
|
||||
document.getElementById(`gpuPercent${i}`).textContent = gpuUsage + '%';
|
||||
document.getElementById(`gpuBar${i}`).style.width = gpuUsage + '%';
|
||||
document.getElementById(`gpuMem${i}`).textContent = `${parseFloat(memUsed).toFixed(1)}/${config.memory} GB`;
|
||||
document.getElementById(`gpuTemp${i}`).textContent = temp + '°C';
|
||||
document.getElementById(`gpuPower${i}`).textContent = power + ' W';
|
||||
document.getElementById(`gpuFan${i}`).textContent = fan + '%';
|
||||
|
||||
// 根据温度改变颜色
|
||||
const tempEl = document.getElementById(`gpuTemp${i}`);
|
||||
if (temp >= 80) {
|
||||
tempEl.className = 'font-medium text-red-600';
|
||||
} else if (temp >= 70) {
|
||||
tempEl.className = 'font-medium text-yellow-600';
|
||||
} else {
|
||||
tempEl.className = 'font-medium text-gray-800';
|
||||
}
|
||||
document.getElementById('gpuCount').textContent = `检测到 ${gpuCount} 块 GPU`;
|
||||
}
|
||||
|
||||
// 更新总显存
|
||||
document.getElementById('gpuTotalMemory').textContent = `${totalUsedMemory.toFixed(1)}/${totalMemory} GB`;
|
||||
const gpuTotalMem = document.getElementById('gpuTotalMemory');
|
||||
if (gpuTotalMem) {
|
||||
gpuTotalMem.textContent = `${totalUsedMemory.toFixed(1)}/${totalMemory} GB`;
|
||||
}
|
||||
}
|
||||
|
||||
// 启动硬件监控自动刷新
|
||||
|
||||
Reference in New Issue
Block a user