XNSim/XNSimHtml/routes/ModelMonitor.js

220 lines
6.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const router = express.Router();
const { startMonitorModelInfo, stopMonitorModelInfo, getModelInfo } = require('../utils/systemMonitor');
// 存储监控服务的状态
let monitorStatus = {
isMonitoring: false,
lastError: null
};
// 存储模型频率历史数据
const modelFrequencyHistory = new Map(); // Map<modelId, number[]>
const MAX_HISTORY_SIZE = 100;
// 存储模型频率统计
const modelFrequencyStats = new Map(); // Map<modelId, {max: number, min: number, avg: number}>
// 频率转周期单位ms
function frequencyToPeriod(frequency) {
return frequency === 0 ? 0 : (1000 / frequency);
}
// 更新模型频率统计
function updateModelFrequencyStats(modelId, currentFrequency, setFrequency) {
// 初始化历史数据
if (!modelFrequencyHistory.has(modelId)) {
modelFrequencyHistory.set(modelId, []);
}
// 初始化统计数据
if (!modelFrequencyStats.has(modelId)) {
modelFrequencyStats.set(modelId, {
max: setFrequency,
min: setFrequency,
avg: setFrequency
});
}
const history = modelFrequencyHistory.get(modelId);
const stats = modelFrequencyStats.get(modelId);
// 更新最大最小值
stats.max = Math.max(stats.max, currentFrequency);
stats.min = Math.min(stats.min, currentFrequency);
// 更新历史数据
history.push(currentFrequency);
if (history.length > MAX_HISTORY_SIZE) {
history.shift(); // 移除最旧的数据
}
// 计算平均值
stats.avg = history.reduce((sum, freq) => sum + freq, 0) / history.length;
}
// 启动模型监控
router.post('/start', async (req, res) => {
try {
if (monitorStatus.isMonitoring) {
return res.status(400).json({ error: '模型监控已经在运行' });
}
const result = startMonitorModelInfo();
if (result && result.includes('失败')) {
monitorStatus.lastError = result;
return res.status(500).json({ error: result });
}
// 清空历史数据和统计数据
modelFrequencyHistory.clear();
modelFrequencyStats.clear();
monitorStatus.isMonitoring = true;
monitorStatus.lastError = null;
res.json({
message: '模型监控启动成功',
status: monitorStatus
});
} catch (error) {
console.error('启动模型监控失败:', error);
monitorStatus.lastError = error.message;
res.status(500).json({ error: '启动模型监控失败', message: error.message });
}
});
// 停止模型监控
router.post('/stop', async (req, res) => {
try {
if (!monitorStatus.isMonitoring) {
return res.status(400).json({ error: '模型监控未在运行' });
}
stopMonitorModelInfo();
monitorStatus.isMonitoring = false;
monitorStatus.lastError = null;
// 清空历史数据和统计数据
modelFrequencyHistory.clear();
modelFrequencyStats.clear();
res.json({
message: '模型监控停止成功',
status: monitorStatus
});
} catch (error) {
console.error('停止模型监控失败:', error);
monitorStatus.lastError = error.message;
res.status(500).json({ error: '停止模型监控失败', message: error.message });
}
});
// 获取模型信息
router.get('/model-info', async (req, res) => {
try {
if (!monitorStatus.isMonitoring) {
return res.status(400).json({ error: '模型监控未在运行' });
}
const result = getModelInfo();
if (result && result.includes('失败')) {
monitorStatus.lastError = result;
return res.status(500).json({ error: result });
}
// 解析JSON字符串
let data;
try {
data = JSON.parse(result);
} catch (error) {
console.error('解析模型信息JSON失败:', error);
return res.status(500).json({ error: '解析模型信息失败', message: error.message });
}
// 检查数据结构
if (!data || typeof data !== 'object') {
return res.status(500).json({ error: '模型信息数据格式错误' });
}
// 检查顶层modelStatus字段
if (!data.modelStatus || typeof data.modelStatus !== 'object') {
return res.status(500).json({ error: '模型状态数据缺失' });
}
// 构造响应数据
const responseData = Object.entries(data.modelStatus).map(([modelId, model]) => {
// 检查必要字段
const requiredFields = [
'modelName', 'modelID', 'modelStatus', 'modelThreadID',
'modelNode', 'modelPriority', 'modelRunCount',
'modelCurrentFrequency', 'modelSetFrequency'
];
const missingFields = requiredFields.filter(field =>
model[field] === undefined || model[field] === null
);
if (missingFields.length > 0) {
throw new Error(`模型数据不完整: 缺少 ${missingFields.join(', ')}`);
}
// 更新频率统计
updateModelFrequencyStats(
parseInt(modelId),
model.modelCurrentFrequency,
model.modelSetFrequency
);
const stats = modelFrequencyStats.get(parseInt(modelId));
if (!stats) {
throw new Error('模型频率统计数据缺失');
}
// 计算周期值
const currentPeriod = frequencyToPeriod(model.modelCurrentFrequency);
const setPeriod = frequencyToPeriod(model.modelSetFrequency);
const maxPeriod = frequencyToPeriod(stats.min);
const minPeriod = frequencyToPeriod(stats.max);
const avgPeriod = frequencyToPeriod(stats.avg);
return {
id: parseInt(modelId),
name: model.modelName,
status: model.modelStatus,
threadId: model.modelThreadID,
node: model.modelNode,
priority: model.modelPriority,
runCount: model.modelRunCount,
// 频率值
currentFrequency: model.modelCurrentFrequency,
setFrequency: model.modelSetFrequency,
maxFrequency: stats.max,
minFrequency: stats.min,
avgFrequency: stats.avg,
// 周期值单位ms
currentPeriod: currentPeriod,
setPeriod: setPeriod,
maxPeriod: maxPeriod,
minPeriod: minPeriod,
avgPeriod: avgPeriod
};
});
res.json({
data: responseData,
status: monitorStatus
});
} catch (error) {
console.error('获取模型信息失败:', error);
monitorStatus.lastError = error.message;
res.status(500).json({ error: '获取模型信息失败', message: error.message });
}
});
// 获取监控状态
router.get('/status', (req, res) => {
res.json(monitorStatus);
});
module.exports = router;