|
@@ -0,0 +1,369 @@
|
|
|
|
+package com.ruoyi.framework.web.domain;
|
|
|
|
+
|
|
|
|
+import java.io.BufferedReader;
|
|
|
|
+import java.io.File;
|
|
|
|
+import java.io.FileReader;
|
|
|
|
+import java.io.InputStreamReader;
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.HashMap;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Map;
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
+import java.util.regex.Matcher;
|
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
+
|
|
|
|
+public class AdvancedSystemMonitor {
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * CPU插槽 0 温度: 48.5°C
|
|
|
|
+ * CPU插槽 1 温度: 47.2°C
|
|
|
|
+ * CPU核心 Socket0-Core0 频率: 3.20 GHz
|
|
|
|
+ * CPU核心 Socket0-Core1 频率: 3.18 GHz
|
|
|
|
+ * CPU核心 Socket1-Core24 频率: 2.95 GHz
|
|
|
|
+ * CPU核心 Socket1-Core25 频率: 2.97 GHz
|
|
|
|
+ * <p>
|
|
|
|
+ * GPU #0 信息:
|
|
|
|
+ * 索引: 0
|
|
|
|
+ * 名称: NVIDIA GeForce RTX 3090
|
|
|
|
+ * 温度: 62°C
|
|
|
|
+ * 使用率: 24%
|
|
|
|
+ * 显存使用: 3456 MB
|
|
|
|
+ * 总显存: 24564 MB
|
|
|
|
+ * 功耗: 350.0 W
|
|
|
|
+ * 功耗限制: 400.0 W
|
|
|
|
+ * 图形时钟: 1860 MHz
|
|
|
|
+ * 显存时钟: 1219 MHz
|
|
|
|
+ * <p>
|
|
|
|
+ * GPU #1 信息:
|
|
|
|
+ * 索引: 1
|
|
|
|
+ * 名称: NVIDIA Tesla V100
|
|
|
|
+ * 温度: 58°C
|
|
|
|
+ * 使用率: 45%
|
|
|
|
+ * 显存使用: 16384 MB
|
|
|
|
+ * 总显存: 32768 MB
|
|
|
|
+ * 功耗: 250.0 W
|
|
|
|
+ * 功耗限制: 300.0 W
|
|
|
|
+ * 图形时钟: 1380 MHz
|
|
|
|
+ * 显存时钟: 877 MHz
|
|
|
|
+ * <p>
|
|
|
|
+ * 网络速率 (eth0):
|
|
|
|
+ * 下行: 1.23 Gbps
|
|
|
|
+ * 上行: 345.67 Mbps
|
|
|
|
+ */
|
|
|
|
+ public static String advancedSystem() {
|
|
|
|
+ try {
|
|
|
|
+ // 1. 获取所有CPU插槽的温度
|
|
|
|
+ Map<Integer, Double> cpuTemps = getCpuTemperatures();
|
|
|
|
+ cpuTemps.forEach((socket, temp) ->
|
|
|
|
+ System.out.printf("CPU插槽 %d 温度: %.1f°C\n", socket, temp)
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // 2. 获取所有CPU核心的实时频率
|
|
|
|
+ Map<String, Double> cpuFrequencies = getCpuFrequencies();
|
|
|
|
+ cpuFrequencies.forEach((core, freq) ->
|
|
|
|
+ System.out.printf("CPU核心 %s 频率: %.2f GHz\n", core, freq)
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // 3. 获取所有GPU信息
|
|
|
|
+ List<Map<String, String>> gpuInfoList = getMultiGpuInfo();
|
|
|
|
+ for (int i = 0; i < gpuInfoList.size(); i++) {
|
|
|
|
+ System.out.println("\nGPU #" + i + " 信息:");
|
|
|
|
+ gpuInfoList.get(i).forEach((key, value) ->
|
|
|
|
+ System.out.println(" " + key + ": " + value)
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 4. 获取网络速率
|
|
|
|
+ String interfaceName = "eth0"; // 替换为你的网卡名称
|
|
|
|
+ NetworkStats stats1 = getNetworkStats(interfaceName);
|
|
|
|
+ TimeUnit.SECONDS.sleep(1);
|
|
|
|
+ NetworkStats stats2 = getNetworkStats(interfaceName);
|
|
|
|
+
|
|
|
|
+ long rxRate = (stats2.rxBytes - stats1.rxBytes) * 8; // 比特/秒
|
|
|
|
+ long txRate = (stats2.txBytes - stats1.txBytes) * 8; // 比特/秒
|
|
|
|
+
|
|
|
|
+ System.out.printf("\n网络速率 (%s):\n 下行: %s\n 上行: %s\n",
|
|
|
|
+ interfaceName,
|
|
|
|
+ formatRate(rxRate),
|
|
|
|
+ formatRate(txRate)
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 获取多CPU插槽的温度
|
|
|
|
+ private static Map<Integer, Double> getCpuTemperatures() throws Exception {
|
|
|
|
+ Map<Integer, Double> temps = new HashMap<>();
|
|
|
|
+
|
|
|
|
+ // 方法1: 通过hwmon获取物理CPU温度
|
|
|
|
+ File hwmonDir = new File("/sys/class/hwmon/");
|
|
|
|
+ for (File hwmon : hwmonDir.listFiles()) {
|
|
|
|
+ try {
|
|
|
|
+ // 检测是否为CPU温度传感器
|
|
|
|
+ File nameFile = new File(hwmon, "name");
|
|
|
|
+ if (!nameFile.exists()) continue;
|
|
|
|
+
|
|
|
|
+ try (BufferedReader nameReader = new BufferedReader(new FileReader(nameFile))) {
|
|
|
|
+ String name = nameReader.readLine();
|
|
|
|
+ if (name == null || !(name.contains("coretemp") || name.contains("k10temp"))) continue;
|
|
|
|
+
|
|
|
|
+ // 查找所有物理CPU的温度
|
|
|
|
+ for (int i = 1; i <= 16; i++) {
|
|
|
|
+ File tempFile = new File(hwmon, "temp" + i + "_input");
|
|
|
|
+ File labelFile = new File(hwmon, "temp" + i + "_label");
|
|
|
|
+
|
|
|
|
+ if (tempFile.exists()) {
|
|
|
|
+ // 读取温度标签确定是物理CPU
|
|
|
|
+ String label = "Unknown";
|
|
|
|
+ if (labelFile.exists()) {
|
|
|
|
+ try (BufferedReader labelReader = new BufferedReader(new FileReader(labelFile))) {
|
|
|
|
+ label = labelReader.readLine();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 只获取物理CPU温度(Package或Tdie)
|
|
|
|
+ if (label.contains("Package") || label.contains("Tdie")) {
|
|
|
|
+ try (BufferedReader tempReader = new BufferedReader(new FileReader(tempFile))) {
|
|
|
|
+ double temp = Double.parseDouble(tempReader.readLine().trim()) / 1000.0;
|
|
|
|
+ // 提取CPU插槽ID
|
|
|
|
+ int socketId = 0;
|
|
|
|
+ Pattern p = Pattern.compile("(\\d+)");
|
|
|
|
+ Matcher m = p.matcher(label);
|
|
|
|
+ if (m.find()) socketId = Integer.parseInt(m.group());
|
|
|
|
+
|
|
|
|
+ temps.put(socketId, temp);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ // 继续下一个hwmon
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 方法2: 回退到thermal_zone方法
|
|
|
|
+ if (temps.isEmpty()) {
|
|
|
|
+ File thermalDir = new File("/sys/class/thermal/");
|
|
|
|
+ for (File zone : thermalDir.listFiles()) {
|
|
|
|
+ if (zone.getName().startsWith("thermal_zone")) {
|
|
|
|
+ try {
|
|
|
|
+ // 检查类型
|
|
|
|
+ File typeFile = new File(zone, "type");
|
|
|
|
+ if (!typeFile.exists()) continue;
|
|
|
|
+
|
|
|
|
+ try (BufferedReader typeReader = new BufferedReader(new FileReader(typeFile))) {
|
|
|
|
+ String type = typeReader.readLine();
|
|
|
|
+ if (type == null || !type.contains("x86_pkg_temp")) continue;
|
|
|
|
+
|
|
|
|
+ // 读取温度
|
|
|
|
+ File tempFile = new File(zone, "temp");
|
|
|
|
+ if (tempFile.exists()) {
|
|
|
|
+ try (BufferedReader tempReader = new BufferedReader(new FileReader(tempFile))) {
|
|
|
|
+ double temp = Double.parseDouble(tempReader.readLine().trim()) / 1000.0;
|
|
|
|
+ // 尝试从目录名获取zone ID
|
|
|
|
+ String zoneId = zone.getName().replace("thermal_zone", "");
|
|
|
|
+ temps.put(Integer.parseInt(zoneId), temp);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ // 忽略错误
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (temps.isEmpty()) throw new Exception("无法检测到CPU温度传感器");
|
|
|
|
+ return temps;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 获取所有CPU核心频率
|
|
|
|
+ private static Map<String, Double> getCpuFrequencies() throws Exception {
|
|
|
|
+ Map<String, Double> frequencies = new HashMap<>();
|
|
|
|
+ int socketCount = 0;
|
|
|
|
+ int coreCount = 0;
|
|
|
|
+
|
|
|
|
+ // 检测CPU核心
|
|
|
|
+ File cpuDir = new File("/sys/devices/system/cpu/");
|
|
|
|
+ for (File file : cpuDir.listFiles()) {
|
|
|
|
+ if (file.getName().matches("cpu\\d+")) {
|
|
|
|
+ String coreId = file.getName().replace("cpu", "");
|
|
|
|
+
|
|
|
|
+ // 读取实时频率
|
|
|
|
+ String freqPath = "/sys/devices/system/cpu/cpu" + coreId + "/cpufreq/scaling_cur_freq";
|
|
|
|
+ File freqFile = new File(freqPath);
|
|
|
|
+
|
|
|
|
+ if (freqFile.exists()) {
|
|
|
|
+ try (BufferedReader br = new BufferedReader(new FileReader(freqFile))) {
|
|
|
|
+ String line = br.readLine();
|
|
|
|
+ if (line != null) {
|
|
|
|
+ double freq = Double.parseDouble(line.trim()) / 1_000_000.0;
|
|
|
|
+ frequencies.put("Socket0-Core" + coreId, freq);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ coreCount++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 如果通过sysfs获取失败,尝试从/proc/cpuinfo获取
|
|
|
|
+ if (frequencies.isEmpty()) {
|
|
|
|
+ try (BufferedReader br = new BufferedReader(new FileReader("/proc/cpuinfo"))) {
|
|
|
|
+ String line;
|
|
|
|
+ int processor = -1;
|
|
|
|
+ while ((line = br.readLine()) != null) {
|
|
|
|
+ if (line.startsWith("processor")) {
|
|
|
|
+ String[] parts = line.split(":");
|
|
|
|
+ processor = Integer.parseInt(parts[1].trim());
|
|
|
|
+ } else if (line.startsWith("cpu MHz")) {
|
|
|
|
+ String[] parts = line.split(":");
|
|
|
|
+ double freq = Double.parseDouble(parts[1].trim()) / 1000.0;
|
|
|
|
+ frequencies.put("Core" + processor, freq);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return frequencies;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 获取多GPU信息
|
|
|
|
+ private static List<Map<String, String>> getMultiGpuInfo() {
|
|
|
|
+ List<Map<String, String>> gpuList = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ // 使用nvidia-smi获取多GPU信息
|
|
|
|
+ try {
|
|
|
|
+ Process process = Runtime.getRuntime().exec(
|
|
|
|
+ "nvidia-smi --query-gpu=index,name,temperature.gpu,utilization.gpu,memory.used,memory.total,power.draw,power.limit,clocks.current.graphics,clocks.current.memory --format=csv,noheader,nounits"
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
|
|
+ String line;
|
|
|
|
+ int gpuIndex = 0;
|
|
|
|
+
|
|
|
|
+ while ((line = reader.readLine()) != null) {
|
|
|
|
+ String[] parts = line.split(", ");
|
|
|
|
+ if (parts.length >= 10) {
|
|
|
|
+ Map<String, String> gpuInfo = new HashMap<>();
|
|
|
|
+ gpuInfo.put("索引", parts[0].trim());
|
|
|
|
+ gpuInfo.put("名称", parts[1].trim());
|
|
|
|
+ gpuInfo.put("温度", parts[2].trim() + "°C");
|
|
|
|
+ gpuInfo.put("使用率", parts[3].trim() + "%");
|
|
|
|
+ gpuInfo.put("显存使用", parts[4].trim() + " MB");
|
|
|
|
+ gpuInfo.put("总显存", parts[5].trim() + " MB");
|
|
|
|
+ gpuInfo.put("功耗", parts[6].trim() + " W");
|
|
|
|
+ gpuInfo.put("功耗限制", parts[7].trim() + " W");
|
|
|
|
+ gpuInfo.put("图形时钟", parts[8].trim() + " MHz");
|
|
|
|
+ gpuInfo.put("显存时钟", parts[9].trim() + " MHz");
|
|
|
|
+
|
|
|
|
+ gpuList.add(gpuInfo);
|
|
|
|
+ gpuIndex++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 检查是否有GPU被检测到
|
|
|
|
+ if (gpuIndex > 0) return gpuList;
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ System.err.println("nvidia-smi执行错误: " + e.getMessage());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 备用方法:尝试从sysfs读取AMD/集成GPU信息
|
|
|
|
+ try {
|
|
|
|
+ File hwmonDir = new File("/sys/class/hwmon/");
|
|
|
|
+ for (File hwmon : hwmonDir.listFiles()) {
|
|
|
|
+ try {
|
|
|
|
+ // 检测是否为GPU
|
|
|
|
+ File nameFile = new File(hwmon, "name");
|
|
|
|
+ if (!nameFile.exists()) continue;
|
|
|
|
+
|
|
|
|
+ try (BufferedReader nameReader = new BufferedReader(new FileReader(nameFile))) {
|
|
|
|
+ String name = nameReader.readLine();
|
|
|
|
+ if (name == null || !(name.contains("amdgpu") || name.contains("radeon"))) continue;
|
|
|
|
+
|
|
|
|
+ Map<String, String> gpuInfo = new HashMap<>();
|
|
|
|
+ gpuInfo.put("类型", name);
|
|
|
|
+
|
|
|
|
+ // 读取温度
|
|
|
|
+ for (int i = 1; i <= 5; i++) {
|
|
|
|
+ File tempFile = new File(hwmon, "temp" + i + "_input");
|
|
|
|
+ if (tempFile.exists()) {
|
|
|
|
+ try (BufferedReader tempReader = new BufferedReader(new FileReader(tempFile))) {
|
|
|
|
+ double temp = Double.parseDouble(tempReader.readLine().trim()) / 1000.0;
|
|
|
|
+ gpuInfo.put("温度", String.format("%.1f°C", temp));
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 读取功耗(如果可用)
|
|
|
|
+ File powerFile = new File(hwmon, "power1_average");
|
|
|
|
+ if (powerFile.exists()) {
|
|
|
|
+ try (BufferedReader powerReader = new BufferedReader(new FileReader(powerFile))) {
|
|
|
|
+ double power = Double.parseDouble(powerReader.readLine().trim()) / 1_000_000.0;
|
|
|
|
+ gpuInfo.put("功耗", String.format("%.1f W", power));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ gpuList.add(gpuInfo);
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ // 继续下一个hwmon
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ System.err.println("sysfs读取错误: " + e.getMessage());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 如果没有检测到GPU,添加一个错误信息
|
|
|
|
+ if (gpuList.isEmpty()) {
|
|
|
|
+ Map<String, String> errorInfo = new HashMap<>();
|
|
|
|
+ errorInfo.put("错误", "未检测到GPU或需要安装驱动");
|
|
|
|
+ gpuList.add(errorInfo);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return gpuList;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 网络统计数据结构
|
|
|
|
+ private static class NetworkStats {
|
|
|
|
+ long rxBytes;
|
|
|
|
+ long txBytes;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 获取网络统计信息
|
|
|
|
+ private static NetworkStats getNetworkStats(String interfaceName) throws Exception {
|
|
|
|
+ NetworkStats stats = new NetworkStats();
|
|
|
|
+ File file = new File("/proc/net/dev");
|
|
|
|
+
|
|
|
|
+ try (BufferedReader br = new BufferedReader(new FileReader(file))) {
|
|
|
|
+ String line;
|
|
|
|
+ while ((line = br.readLine()) != null) {
|
|
|
|
+ line = line.trim();
|
|
|
|
+ if (line.startsWith(interfaceName + ":")) {
|
|
|
|
+ String[] parts = line.split("\\s+");
|
|
|
|
+ stats.rxBytes = Long.parseLong(parts[1]);
|
|
|
|
+ stats.txBytes = Long.parseLong(parts[9]);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return stats;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 格式化网络速率
|
|
|
|
+ private static String formatRate(long rateBitsPerSec) {
|
|
|
|
+ if (rateBitsPerSec < 1000) {
|
|
|
|
+ return rateBitsPerSec + " bps";
|
|
|
|
+ } else if (rateBitsPerSec < 1_000_000) {
|
|
|
|
+ return String.format("%.2f Kbps", rateBitsPerSec / 1000.0);
|
|
|
|
+ } else if (rateBitsPerSec < 1_000_000_000) {
|
|
|
|
+ return String.format("%.2f Mbps", rateBitsPerSec / 1_000_000.0);
|
|
|
|
+ } else {
|
|
|
|
+ return String.format("%.2f Gbps", rateBitsPerSec / 1_000_000_000.0);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|