|
@@ -5,7 +5,6 @@ import com.ruoyi.common.utils.ip.IpUtils;
|
|
|
import com.ruoyi.framework.web.domain.server.*;
|
|
|
import oshi.SystemInfo;
|
|
|
import oshi.hardware.CentralProcessor;
|
|
|
-import oshi.hardware.CentralProcessor.TickType;
|
|
|
import oshi.hardware.GlobalMemory;
|
|
|
import oshi.hardware.HardwareAbstractionLayer;
|
|
|
import oshi.software.os.FileSystem;
|
|
@@ -13,26 +12,37 @@ import oshi.software.os.OSFileStore;
|
|
|
import oshi.software.os.OperatingSystem;
|
|
|
import oshi.util.Util;
|
|
|
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileReader;
|
|
|
+import java.io.InputStreamReader;
|
|
|
import java.net.UnknownHostException;
|
|
|
-import java.util.LinkedList;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Properties;
|
|
|
-
|
|
|
-import static com.ruoyi.framework.web.domain.AdvancedSystemMonitor.advancedSystem;
|
|
|
+import java.util.*;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
|
/**
|
|
|
* 服务器相关信息
|
|
|
- *
|
|
|
+ *
|
|
|
* @author ruoyi
|
|
|
*/
|
|
|
-public class Server
|
|
|
-{
|
|
|
+public class Server {
|
|
|
private static final int OSHI_WAIT_SECOND = 1000;
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* CPU相关信息
|
|
|
*/
|
|
|
private Cpu cpu = new Cpu();
|
|
|
+ private List<Cpu> cpuList = new ArrayList<>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * GPU
|
|
|
+ */
|
|
|
+ private List<Gpu> gpuList = new ArrayList<>();
|
|
|
+ /**
|
|
|
+ * 网络
|
|
|
+ */
|
|
|
+ private List<Network> netWorkList = new ArrayList<>();
|
|
|
|
|
|
/**
|
|
|
* 內存相关信息
|
|
@@ -54,58 +64,71 @@ public class Server
|
|
|
*/
|
|
|
private List<SysFile> sysFiles = new LinkedList<SysFile>();
|
|
|
|
|
|
- public Cpu getCpu()
|
|
|
- {
|
|
|
+ public List<Network> getNetWorkList() {
|
|
|
+ return netWorkList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setNetWorkList(List<Network> netWorkList) {
|
|
|
+ this.netWorkList = netWorkList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<Gpu> getGpuList() {
|
|
|
+ return gpuList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setGpuList(List<Gpu> gpuList) {
|
|
|
+ this.gpuList = gpuList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<Cpu> getCpuList() {
|
|
|
+ return cpuList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setCpuList(List<Cpu> cpuList) {
|
|
|
+ this.cpuList = cpuList;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Cpu getCpu() {
|
|
|
return cpu;
|
|
|
}
|
|
|
|
|
|
- public void setCpu(Cpu cpu)
|
|
|
- {
|
|
|
+ public void setCpu(Cpu cpu) {
|
|
|
this.cpu = cpu;
|
|
|
}
|
|
|
|
|
|
- public Mem getMem()
|
|
|
- {
|
|
|
+ public Mem getMem() {
|
|
|
return mem;
|
|
|
}
|
|
|
|
|
|
- public void setMem(Mem mem)
|
|
|
- {
|
|
|
+ public void setMem(Mem mem) {
|
|
|
this.mem = mem;
|
|
|
}
|
|
|
|
|
|
- public Jvm getJvm()
|
|
|
- {
|
|
|
+ public Jvm getJvm() {
|
|
|
return jvm;
|
|
|
}
|
|
|
|
|
|
- public void setJvm(Jvm jvm)
|
|
|
- {
|
|
|
+ public void setJvm(Jvm jvm) {
|
|
|
this.jvm = jvm;
|
|
|
}
|
|
|
|
|
|
- public Sys getSys()
|
|
|
- {
|
|
|
+ public Sys getSys() {
|
|
|
return sys;
|
|
|
}
|
|
|
|
|
|
- public void setSys(Sys sys)
|
|
|
- {
|
|
|
+ public void setSys(Sys sys) {
|
|
|
this.sys = sys;
|
|
|
}
|
|
|
|
|
|
- public List<SysFile> getSysFiles()
|
|
|
- {
|
|
|
+ public List<SysFile> getSysFiles() {
|
|
|
return sysFiles;
|
|
|
}
|
|
|
|
|
|
- public void setSysFiles(List<SysFile> sysFiles)
|
|
|
- {
|
|
|
+ public void setSysFiles(List<SysFile> sysFiles) {
|
|
|
this.sysFiles = sysFiles;
|
|
|
}
|
|
|
|
|
|
- public void copyTo() throws Exception
|
|
|
- {
|
|
|
+ public void copyTo() throws Exception {
|
|
|
SystemInfo si = new SystemInfo();
|
|
|
HardwareAbstractionLayer hal = si.getHardware();
|
|
|
|
|
@@ -119,40 +142,653 @@ public class Server
|
|
|
|
|
|
setSysFiles(si.getOperatingSystem());
|
|
|
|
|
|
- advancedSystem();
|
|
|
+ setGpuInfo();
|
|
|
+
|
|
|
+ List<String> interfaceNameList = new ArrayList<>();
|
|
|
+ interfaceNameList.add("eno1np0");// 替换为你的网卡名称
|
|
|
+ interfaceNameList.add("eno2np1");// 替换为你的网卡名称
|
|
|
+ for (String interfaceName : interfaceNameList) {
|
|
|
+ Network netWork = new Network();
|
|
|
+ NetworkStats stats1 = getNetworkStats(interfaceName);
|
|
|
+ if (stats1 != null) {
|
|
|
+ Util.sleep(OSHI_WAIT_SECOND);
|
|
|
+ NetworkStats stats2 = getNetworkStats(interfaceName);
|
|
|
+ long rxRate = (stats2.rxBytes - stats1.rxBytes) * 8; // 比特/秒
|
|
|
+ long txRate = (stats2.txBytes - stats1.txBytes) * 8; // 比特/秒
|
|
|
+ netWork.setNetworkName(interfaceName);
|
|
|
+ netWork.setNetworkUp(txRate);
|
|
|
+ netWork.setNetworkDown(rxRate);
|
|
|
+ netWorkList.add(netWork);
|
|
|
+ System.out.printf("\n网络速率 (%s):\n 下行: %s\n 上行: %s\n",
|
|
|
+ interfaceName,
|
|
|
+ formatRate(rxRate),
|
|
|
+ formatRate(txRate)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 网络统计数据结构
|
|
|
+ private static class NetworkStats {
|
|
|
+ long rxBytes;
|
|
|
+ long txBytes;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取网络统计信息
|
|
|
+ private static NetworkStats getNetworkStats(String interfaceName) throws Exception {
|
|
|
+ File file = new File("/proc/net/dev");
|
|
|
+ if (file == null || !file.exists()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ NetworkStats stats = new NetworkStats();
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setGpuInfo() {
|
|
|
+ // 3. 获取所有GPU信息
|
|
|
+ List<Map<String, String>> gpuInfoList = getMultiGpuInfo();
|
|
|
+ for (int i = 0; i < gpuInfoList.size(); i++) {
|
|
|
+ Gpu gpu = new Gpu();
|
|
|
+ System.out.println("\nGPU #" + i + " 信息:");
|
|
|
+ for (Map<String, String> stringStringMap : gpuInfoList) {
|
|
|
+ gpu.setName(stringStringMap.get("名称"));
|
|
|
+ gpu.setGpuMemory(stringStringMap.get("总显存"));
|
|
|
+ gpu.setUseMemory(stringStringMap.get("显存使用"));
|
|
|
+ gpu.setUsed(stringStringMap.get("使用率"));
|
|
|
+ gpu.setTemperature(stringStringMap.get("温度"));
|
|
|
+ gpu.setPower(stringStringMap.get("功耗"));
|
|
|
+ gpuList.add(gpu);
|
|
|
+ }
|
|
|
+ gpuInfoList.get(i).forEach((key, value) ->
|
|
|
+ System.out.println(" " + key + ": " + value)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取多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;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 设置CPU信息
|
|
|
*/
|
|
|
- private void setCpuInfo(CentralProcessor processor)
|
|
|
- {
|
|
|
- // CPU信息
|
|
|
- long[] prevTicks = processor.getSystemCpuLoadTicks();
|
|
|
+ private void setCpuInfo(CentralProcessor processor) {
|
|
|
+ // 1. 获取物理CPU数量
|
|
|
+ int physicalPackageCount = processor.getPhysicalPackageCount();
|
|
|
+ // 2分组方法:使用物理处理器编号分组
|
|
|
+ Map<Integer, List<CentralProcessor.LogicalProcessor>> cpuGroups = new HashMap<>();
|
|
|
+ for (CentralProcessor.LogicalProcessor lp : processor.getLogicalProcessors()) {
|
|
|
+ int packageId = lp.getPhysicalProcessorNumber() % physicalPackageCount;
|
|
|
+ cpuGroups.computeIfAbsent(packageId, k -> new ArrayList<>()).add(lp);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 获取初始CPU滴答计数(按逻辑处理器)
|
|
|
+ long[][] initialTicks = processor.getProcessorCpuLoadTicks();
|
|
|
+
|
|
|
+ // 4. 等待1秒获取新数据
|
|
|
Util.sleep(OSHI_WAIT_SECOND);
|
|
|
- long[] ticks = processor.getSystemCpuLoadTicks();
|
|
|
- long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
|
|
|
- long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
|
|
|
- long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
|
|
|
- long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
|
|
|
- long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
|
|
|
- long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
|
|
|
- long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
|
|
|
- long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
|
|
|
- long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
|
|
|
- cpu.setCpuNum(processor.getLogicalProcessorCount());
|
|
|
- cpu.setTotal(totalCpu);
|
|
|
- cpu.setSys(cSys);
|
|
|
- cpu.setUsed(user);
|
|
|
- cpu.setWait(iowait);
|
|
|
- cpu.setFree(idle);
|
|
|
+
|
|
|
+ // 5. 获取新的CPU滴答计数
|
|
|
+ long[][] newTicks = processor.getProcessorCpuLoadTicks();
|
|
|
+
|
|
|
+ // 6. 计算并显示每个物理CPU的数据
|
|
|
+ for (int pkgId = 0; pkgId < physicalPackageCount; pkgId++) {
|
|
|
+ Cpu cpuOne = new Cpu();
|
|
|
+ if (!cpuGroups.containsKey(pkgId)) continue;
|
|
|
+ System.out.println("\n===== 物理CPU " + (pkgId + 1) + " 数据 =====");
|
|
|
+ List<CentralProcessor.LogicalProcessor> group = cpuGroups.get(pkgId);
|
|
|
+ System.out.println("包含的逻辑处理器数量: " + cpuGroups.get(pkgId).size());
|
|
|
+ cpuOne.setCpuNum(cpuGroups.get(pkgId).size());
|
|
|
+ // 计算该物理CPU的总负载百分比
|
|
|
+ double totalLoad = calculatePackageLoad(initialTicks, newTicks, group);
|
|
|
+ System.out.printf("总负载: %.2f%%\n", totalLoad * 100);
|
|
|
+ cpuOne.setTotal(Arith.round(totalLoad * 100, 2));
|
|
|
+ // 计算并显示各个详细负载的百分比
|
|
|
+ printPackageLoadDetails(initialTicks, newTicks, group, cpuOne);
|
|
|
+ cpuList.add(cpuOne);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 获取所有CPU插槽的温度
|
|
|
+ Map<Integer, Double> cpuTemps = getCpuTemperatures();
|
|
|
+ if (cpuTemps != null) {
|
|
|
+ for (Integer socket : cpuTemps.keySet()) {
|
|
|
+ Double temp = cpuTemps.get(socket);
|
|
|
+ cpuList.get(socket).setTemperature(temp);
|
|
|
+ System.out.printf("CPU插槽 %d 温度: %.1f°C\n", socket, temp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 2. 获取双CPU的整体速度
|
|
|
+ Map<Integer, Double> cpuSpeeds = getCpuSpeeds();
|
|
|
+ if (!cpuSpeeds.isEmpty()) {
|
|
|
+ for (Integer socket : cpuSpeeds.keySet()) {
|
|
|
+ cpuList.get(socket).setSpeed(cpuSpeeds.get(socket));
|
|
|
+ System.out.printf("CPU插槽 %d 整体速度: %.2f GHz\n", socket, cpuSpeeds.get(socket));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取双CPU整体速度
|
|
|
+ private static Map<Integer, Double> getCpuSpeeds() {
|
|
|
+ Map<Integer, Double> speeds = new HashMap<>();
|
|
|
+
|
|
|
+ // 方法1: 从/proc/cpuinfo获取每个物理CPU的平均速度
|
|
|
+ try (BufferedReader br = new BufferedReader(new FileReader("/proc/cpuinfo"))) {
|
|
|
+ String line;
|
|
|
+ int currentSocket = -1;
|
|
|
+ Map<Integer, Double> socketTotalSpeed = new HashMap<>();
|
|
|
+ Map<Integer, Integer> socketCoreCount = new HashMap<>();
|
|
|
+
|
|
|
+ while ((line = br.readLine()) != null) {
|
|
|
+ if (line.startsWith("physical id")) {
|
|
|
+ // 提取物理CPU ID
|
|
|
+ String[] parts = line.split(":");
|
|
|
+ currentSocket = Integer.parseInt(parts[1].trim());
|
|
|
+
|
|
|
+ // 初始化计数器
|
|
|
+ if (!socketTotalSpeed.containsKey(currentSocket)) {
|
|
|
+ socketTotalSpeed.put(currentSocket, 0.0);
|
|
|
+ socketCoreCount.put(currentSocket, 0);
|
|
|
+ }
|
|
|
+ } else if (line.startsWith("cpu MHz") && currentSocket >= 0) {
|
|
|
+ // 提取核心速度
|
|
|
+ String[] parts = line.split(":");
|
|
|
+ double coreSpeed = Double.parseDouble(parts[1].trim()) / 1000.0; // MHz转GHz
|
|
|
+
|
|
|
+ // 累加到所属物理CPU
|
|
|
+ socketTotalSpeed.put(currentSocket, socketTotalSpeed.get(currentSocket) + coreSpeed);
|
|
|
+ socketCoreCount.put(currentSocket, socketCoreCount.get(currentSocket) + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算每个物理CPU的平均速度
|
|
|
+ for (Integer socket : socketTotalSpeed.keySet()) {
|
|
|
+ double totalSpeed = socketTotalSpeed.get(socket);
|
|
|
+ int coreCount = socketCoreCount.get(socket);
|
|
|
+ speeds.put(socket, totalSpeed / coreCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!speeds.isEmpty()) return speeds;
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("/proc/cpuinfo读取错误: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 方法2: 使用lscpu命令获取物理CPU速度
|
|
|
+ try {
|
|
|
+ Process process = Runtime.getRuntime().exec("lscpu -p=socket,core,CPU,MHz");
|
|
|
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
|
+ String line;
|
|
|
+ Map<Integer, Double> socketTotalSpeed = new HashMap<>();
|
|
|
+ Map<Integer, Integer> socketCoreCount = new HashMap<>();
|
|
|
+
|
|
|
+ while ((line = reader.readLine()) != null) {
|
|
|
+ // 跳过注释行
|
|
|
+ if (line.startsWith("#")) continue;
|
|
|
+
|
|
|
+ String[] parts = line.split(",");
|
|
|
+ if (parts.length >= 4) {
|
|
|
+ try {
|
|
|
+ int socket = Integer.parseInt(parts[0]);
|
|
|
+ double speed = Double.parseDouble(parts[3]) / 1000.0; // MHz转GHz
|
|
|
+
|
|
|
+ socketTotalSpeed.putIfAbsent(socket, 0.0);
|
|
|
+ socketCoreCount.putIfAbsent(socket, 0);
|
|
|
+
|
|
|
+ socketTotalSpeed.put(socket, socketTotalSpeed.get(socket) + speed);
|
|
|
+ socketCoreCount.put(socket, socketCoreCount.get(socket) + 1);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ // 忽略格式错误行
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算每个物理CPU的平均速度
|
|
|
+ for (Integer socket : socketTotalSpeed.keySet()) {
|
|
|
+ double totalSpeed = socketTotalSpeed.get(socket);
|
|
|
+ int coreCount = socketCoreCount.get(socket);
|
|
|
+ speeds.put(socket, totalSpeed / coreCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!speeds.isEmpty()) return speeds;
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("lscpu命令执行错误: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 方法3: 使用sysfs接口(回退方案)
|
|
|
+ try {
|
|
|
+ File cpuDir = new File("/sys/devices/system/cpu/");
|
|
|
+ Map<Integer, Double> socketTotalSpeed = new HashMap<>();
|
|
|
+ Map<Integer, Integer> socketCoreCount = new HashMap<>();
|
|
|
+
|
|
|
+ for (File file : cpuDir.listFiles()) {
|
|
|
+ if (file.getName().matches("cpu\\d+")) {
|
|
|
+ String coreId = file.getName().replace("cpu", "");
|
|
|
+
|
|
|
+ // 获取物理CPU ID
|
|
|
+ File topologyDir = new File(file, "topology");
|
|
|
+ File physicalPackageIdFile = new File(topologyDir, "physical_package_id");
|
|
|
+ int socket = 0;
|
|
|
+
|
|
|
+ if (physicalPackageIdFile.exists()) {
|
|
|
+ try (BufferedReader br = new BufferedReader(new FileReader(physicalPackageIdFile))) {
|
|
|
+ socket = Integer.parseInt(br.readLine().trim());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取核心速度
|
|
|
+ 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; // 转换为GHz
|
|
|
+
|
|
|
+ socketTotalSpeed.putIfAbsent(socket, 0.0);
|
|
|
+ socketCoreCount.putIfAbsent(socket, 0);
|
|
|
+
|
|
|
+ socketTotalSpeed.put(socket, socketTotalSpeed.get(socket) + freq);
|
|
|
+ socketCoreCount.put(socket, socketCoreCount.get(socket) + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算每个物理CPU的平均速度
|
|
|
+ for (Integer socket : socketTotalSpeed.keySet()) {
|
|
|
+ double totalSpeed = socketTotalSpeed.get(socket);
|
|
|
+ int coreCount = socketCoreCount.get(socket);
|
|
|
+ speeds.put(socket, totalSpeed / coreCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!speeds.isEmpty()) return speeds;
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("sysfs接口访问错误: " + e.getMessage());
|
|
|
+ }
|
|
|
+ System.out.println("无法检测到CPU速度");
|
|
|
+ return speeds;
|
|
|
+ }
|
|
|
+ // 获取双CPU温度
|
|
|
+
|
|
|
+ private static Map<Integer, Double> getCpuTemperatures() {
|
|
|
+ Map<Integer, Double> temps = new HashMap<>();
|
|
|
+ int cpuCount = 0;
|
|
|
+
|
|
|
+ // 方法1: 使用sensors命令并解析文本输出
|
|
|
+ try {
|
|
|
+ Process process = Runtime.getRuntime().exec("sensors");
|
|
|
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
|
+ String line;
|
|
|
+ boolean inCpuSection = false;
|
|
|
+ boolean foundTctl = false;
|
|
|
+
|
|
|
+ while ((line = reader.readLine()) != null) {
|
|
|
+ line = line.trim();
|
|
|
+
|
|
|
+ // 1. 检测适配器部分开始
|
|
|
+ if (line.endsWith(":") || (line.contains("Adapter:") && !line.contains(":"))) {
|
|
|
+ // 检查是否是CPU适配器
|
|
|
+ inCpuSection = isCpuAdapterSection(line);
|
|
|
+ foundTctl = false;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 在CPU部分处理温度行
|
|
|
+ if (inCpuSection) {
|
|
|
+ // 3. 检测CPU温度行 (Tctl, Tdie, Package)
|
|
|
+ if (isCpuTemperatureLine(line)) {
|
|
|
+ // 提取温度值
|
|
|
+ Double temp = extractTemperatureValue(line);
|
|
|
+ if (temp != null) {
|
|
|
+ temps.put(cpuCount, temp);
|
|
|
+ System.out.println("检测到CPU " + cpuCount + " 温度: " + temp + "°C");
|
|
|
+ foundTctl = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 4. 当检测到非温度行且已有温度值时,结束当前CPU部分
|
|
|
+ else if (foundTctl && !line.isEmpty()) {
|
|
|
+ inCpuSection = false;
|
|
|
+ cpuCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理最后一个CPU部分
|
|
|
+ if (foundTctl) {
|
|
|
+ cpuCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!temps.isEmpty()) return temps;
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("sensors命令执行错误: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 方法2: 备用方案 - 直接搜索所有温度行
|
|
|
+ if (temps.isEmpty()) {
|
|
|
+ try {
|
|
|
+ Process process = Runtime.getRuntime().exec("sensors");
|
|
|
+ BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
|
|
+ String line;
|
|
|
+ int cpuIndex = 0;
|
|
|
+
|
|
|
+ while ((line = reader.readLine()) != null) {
|
|
|
+ if (isCpuTemperatureLine(line)) {
|
|
|
+ Double temp = extractTemperatureValue(line);
|
|
|
+ if (temp != null) {
|
|
|
+ temps.put(cpuIndex++, temp);
|
|
|
+ System.out.println("通过备用方法检测到CPU " + (cpuIndex-1) + " 温度: " + temp + "°C");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!temps.isEmpty()) return temps;
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("备用sensors解析错误: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 方法3: 使用hwmon接口(不依赖固定名称)
|
|
|
+ try {
|
|
|
+ File hwmonDir = new File("/sys/class/hwmon/");
|
|
|
+ File[] hwmonDirs = hwmonDir.listFiles();
|
|
|
+ if (hwmonDirs == null) return temps;
|
|
|
+
|
|
|
+ for (File hwmon : hwmonDirs) {
|
|
|
+ try {
|
|
|
+ // 读取设备名(但不依赖特定名称)
|
|
|
+ File nameFile = new File(hwmon, "name");
|
|
|
+ if (!nameFile.exists()) continue;
|
|
|
+
|
|
|
+ // 查找标签包含CPU特征的文件
|
|
|
+ File[] labelFiles = hwmon.listFiles((dir, filename) ->
|
|
|
+ filename.startsWith("temp") && filename.endsWith("_label"));
|
|
|
+
|
|
|
+ for (File labelFile : labelFiles) {
|
|
|
+ String baseName = labelFile.getName().replace("_label", "");
|
|
|
+ File tempFile = new File(hwmon, baseName + "_input");
|
|
|
+
|
|
|
+ if (!tempFile.exists()) continue;
|
|
|
+
|
|
|
+ // 读取温度标签
|
|
|
+ String label;
|
|
|
+ try (BufferedReader labelReader = new BufferedReader(new FileReader(labelFile))) {
|
|
|
+ label = labelReader.readLine();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检测物理CPU温度特征
|
|
|
+ if (isCpuTemperatureLabel(label)) {
|
|
|
+ // 读取温度值
|
|
|
+ double temp;
|
|
|
+ try (BufferedReader tempReader = new BufferedReader(new FileReader(tempFile))) {
|
|
|
+ temp = Double.parseDouble(tempReader.readLine().trim()) / 1000.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加到结果
|
|
|
+ temps.put(cpuCount, temp);
|
|
|
+ System.out.println("通过hwmon检测到CPU " + cpuCount + " 温度: " + temp + "°C");
|
|
|
+ cpuCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("hwmon处理错误: " + hwmon.getName() + " - " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("hwmon接口访问错误: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (temps.isEmpty()) {
|
|
|
+ System.out.println("无法检测到CPU温度传感器");
|
|
|
+ }
|
|
|
+ return temps;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断是否CPU适配器部分
|
|
|
+ private static boolean isCpuAdapterSection(String line) {
|
|
|
+ // 空行或包含非CPU设备特征
|
|
|
+ if (line.isEmpty() || line.contains("nvme") || line.contains("bnxt") ||
|
|
|
+ line.contains("Composite") || line.contains("Sensor")) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 包含CPU特征
|
|
|
+ return line.contains("temp") || line.contains("Adapter") ||
|
|
|
+ line.contains("k10") || line.contains("core");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断是否CPU温度行
|
|
|
+ private static boolean isCpuTemperatureLine(String line) {
|
|
|
+ if (line.isEmpty()) return false;
|
|
|
+
|
|
|
+ // 匹配CPU温度特征
|
|
|
+ return line.startsWith("Tctl:") ||
|
|
|
+ line.startsWith("Tdie:") ||
|
|
|
+ line.startsWith("Package id") ||
|
|
|
+ line.startsWith("CPU Package") ||
|
|
|
+ line.contains("Core") ||
|
|
|
+ (line.contains("°C") && (line.contains("Package") || line.contains("Core")));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提取温度值
|
|
|
+ private static Double extractTemperatureValue(String line) {
|
|
|
+ // 匹配温度模式:+34.6°C 或 34.6
|
|
|
+ Pattern pattern = Pattern.compile("([+-]?[\\d\\.]+)\\s*°?C");
|
|
|
+ Matcher matcher = pattern.matcher(line);
|
|
|
+ if (matcher.find()) {
|
|
|
+ try {
|
|
|
+ return Double.parseDouble(matcher.group(1));
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断是否CPU温度标签
|
|
|
+ private static boolean isCpuTemperatureLabel(String label) {
|
|
|
+ if (label == null) return false;
|
|
|
+
|
|
|
+ // 匹配CPU温度特征
|
|
|
+ return label.contains("Tctl") ||
|
|
|
+ label.contains("Tdie") ||
|
|
|
+ label.contains("Package") ||
|
|
|
+ label.contains("Core") ||
|
|
|
+ label.contains("CPU");
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void printPackageLoadDetails(long[][] initialTicks, long[][] newTicks,List<CentralProcessor.LogicalProcessor> group,Cpu cpuOne) {
|
|
|
+ // 初始化各类型总增量
|
|
|
+ long totalUser = 0, totalNice = 0, totalSystem = 0, totalIdle = 0;
|
|
|
+ long totalIowait = 0, totalIrq = 0, totalSoftirq = 0, totalSteal = 0;
|
|
|
+ long totalAll = 0;
|
|
|
+
|
|
|
+ // 计算该物理CPU组内所有逻辑处理器的增量总和
|
|
|
+ for (CentralProcessor.LogicalProcessor lp : group) {
|
|
|
+ int processorNumber = lp.getProcessorNumber();
|
|
|
+ long[] initial = initialTicks[processorNumber];
|
|
|
+ long[] current = newTicks[processorNumber];
|
|
|
+
|
|
|
+ totalUser += current[CentralProcessor.TickType.USER.getIndex()] - initial[CentralProcessor.TickType.USER.getIndex()];
|
|
|
+ totalNice += current[CentralProcessor.TickType.NICE.getIndex()] - initial[CentralProcessor.TickType.NICE.getIndex()];
|
|
|
+ totalSystem += current[CentralProcessor.TickType.SYSTEM.getIndex()] - initial[CentralProcessor.TickType.SYSTEM.getIndex()];
|
|
|
+ totalIdle += current[CentralProcessor.TickType.IDLE.getIndex()] - initial[CentralProcessor.TickType.IDLE.getIndex()];
|
|
|
+ totalIowait += current[CentralProcessor.TickType.IOWAIT.getIndex()] - initial[CentralProcessor.TickType.IOWAIT.getIndex()];
|
|
|
+ totalIrq += current[CentralProcessor.TickType.IRQ.getIndex()] - initial[CentralProcessor.TickType.IRQ.getIndex()];
|
|
|
+ totalSoftirq += current[CentralProcessor.TickType.SOFTIRQ.getIndex()] - initial[CentralProcessor.TickType.SOFTIRQ.getIndex()];
|
|
|
+ totalSteal += current[CentralProcessor.TickType.STEAL.getIndex()] - initial[CentralProcessor.TickType.STEAL.getIndex()];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算总时间
|
|
|
+ totalAll = totalUser + totalNice + totalSystem + totalIdle +
|
|
|
+ totalIowait + totalIrq + totalSoftirq + totalSteal;
|
|
|
+
|
|
|
+ System.out.println("详细负载百分比:");
|
|
|
+
|
|
|
+ // 计算并显示每个负载类型的百分比(保留两位小数)
|
|
|
+ if (totalAll > 0) {
|
|
|
+ System.out.printf(" User: %.2f%%\n", 100.0 * totalUser / totalAll);
|
|
|
+ System.out.printf(" Nice: %.2f%%\n", 100.0 * totalNice / totalAll);
|
|
|
+ System.out.printf(" System: %.2f%%\n", 100.0 * totalSystem / totalAll);
|
|
|
+ System.out.printf(" Idle: %.2f%%\n", 100.0 * totalIdle / totalAll);
|
|
|
+ System.out.printf(" IOWait: %.2f%%\n", 100.0 * totalIowait / totalAll);
|
|
|
+ System.out.printf(" IRQ: %.2f%%\n", 100.0 * totalIrq / totalAll);
|
|
|
+ System.out.printf(" SoftIRQ:%.2f%%\n", 100.0 * totalSoftirq / totalAll);
|
|
|
+ System.out.printf(" Steal: %.2f%%\n", 100.0 * totalSteal / totalAll);
|
|
|
+ cpuOne.setSys(Arith.round(100.0 * totalSystem / totalAll, 2));
|
|
|
+ cpuOne.setFree(Arith.round(100.0 * totalIdle / totalAll, 2));
|
|
|
+ cpuOne.setUsed(Arith.round(100.0 * totalUser / totalAll, 2));
|
|
|
+ } else {
|
|
|
+ System.out.println(" 无有效负载数据");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static double calculatePackageLoad(long[][] initialTicks, long[][] newTicks, List<CentralProcessor.LogicalProcessor> group) {
|
|
|
+ long totalUsed = 0;
|
|
|
+ long total = 0;
|
|
|
+
|
|
|
+ for (CentralProcessor.LogicalProcessor lp : group) {
|
|
|
+ int processorNumber = lp.getProcessorNumber();
|
|
|
+ long[] initial = initialTicks[processorNumber];
|
|
|
+ long[] current = newTicks[processorNumber];
|
|
|
+
|
|
|
+ // 计算该逻辑处理器的负载增量
|
|
|
+ long user = current[CentralProcessor.TickType.USER.getIndex()] - initial[CentralProcessor.TickType.USER.getIndex()];
|
|
|
+ long nice = current[CentralProcessor.TickType.NICE.getIndex()] - initial[CentralProcessor.TickType.NICE.getIndex()];
|
|
|
+ long system = current[CentralProcessor.TickType.SYSTEM.getIndex()] - initial[CentralProcessor.TickType.SYSTEM.getIndex()];
|
|
|
+ long idle = current[CentralProcessor.TickType.IDLE.getIndex()] - initial[CentralProcessor.TickType.IDLE.getIndex()];
|
|
|
+ long iowait = current[CentralProcessor.TickType.IOWAIT.getIndex()] - initial[CentralProcessor.TickType.IOWAIT.getIndex()];
|
|
|
+ long irq = current[CentralProcessor.TickType.IRQ.getIndex()] - initial[CentralProcessor.TickType.IRQ.getIndex()];
|
|
|
+ long softirq = current[CentralProcessor.TickType.SOFTIRQ.getIndex()] - initial[CentralProcessor.TickType.SOFTIRQ.getIndex()];
|
|
|
+ long steal = current[CentralProcessor.TickType.STEAL.getIndex()] - initial[CentralProcessor.TickType.STEAL.getIndex()];
|
|
|
+
|
|
|
+ totalUsed += user + nice + system + irq + softirq + steal;
|
|
|
+ total += totalUsed + idle + iowait;
|
|
|
+ }
|
|
|
+ return total > 0 ? (double) totalUsed / total : 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 设置内存信息
|
|
|
*/
|
|
|
- private void setMemInfo(GlobalMemory memory)
|
|
|
- {
|
|
|
+ private void setMemInfo(GlobalMemory memory) {
|
|
|
mem.setTotal(memory.getTotal());
|
|
|
mem.setUsed(memory.getTotal() - memory.getAvailable());
|
|
|
mem.setFree(memory.getAvailable());
|
|
@@ -161,8 +797,7 @@ public class Server
|
|
|
/**
|
|
|
* 设置服务器信息
|
|
|
*/
|
|
|
- private void setSysInfo()
|
|
|
- {
|
|
|
+ private void setSysInfo() {
|
|
|
Properties props = System.getProperties();
|
|
|
sys.setComputerName(IpUtils.getHostName());
|
|
|
sys.setComputerIp(IpUtils.getHostIp());
|
|
@@ -174,8 +809,7 @@ public class Server
|
|
|
/**
|
|
|
* 设置Java虚拟机
|
|
|
*/
|
|
|
- private void setJvmInfo() throws UnknownHostException
|
|
|
- {
|
|
|
+ private void setJvmInfo() throws UnknownHostException {
|
|
|
Properties props = System.getProperties();
|
|
|
jvm.setTotal(Runtime.getRuntime().totalMemory());
|
|
|
jvm.setMax(Runtime.getRuntime().maxMemory());
|
|
@@ -187,12 +821,10 @@ public class Server
|
|
|
/**
|
|
|
* 设置磁盘信息
|
|
|
*/
|
|
|
- private void setSysFiles(OperatingSystem os)
|
|
|
- {
|
|
|
+ private void setSysFiles(OperatingSystem os) {
|
|
|
FileSystem fileSystem = os.getFileSystem();
|
|
|
List<OSFileStore> fsArray = fileSystem.getFileStores();
|
|
|
- for (OSFileStore fs : fsArray)
|
|
|
- {
|
|
|
+ for (OSFileStore fs : fsArray) {
|
|
|
long free = fs.getUsableSpace();
|
|
|
long total = fs.getTotalSpace();
|
|
|
long used = total - free;
|
|
@@ -210,31 +842,23 @@ public class Server
|
|
|
|
|
|
/**
|
|
|
* 字节转换
|
|
|
- *
|
|
|
+ *
|
|
|
* @param size 字节大小
|
|
|
* @return 转换后值
|
|
|
*/
|
|
|
- public String convertFileSize(long size)
|
|
|
- {
|
|
|
+ public String convertFileSize(long size) {
|
|
|
long kb = 1024;
|
|
|
long mb = kb * 1024;
|
|
|
long gb = mb * 1024;
|
|
|
- if (size >= gb)
|
|
|
- {
|
|
|
+ if (size >= gb) {
|
|
|
return String.format("%.1f GB", (float) size / gb);
|
|
|
- }
|
|
|
- else if (size >= mb)
|
|
|
- {
|
|
|
+ } else if (size >= mb) {
|
|
|
float f = (float) size / mb;
|
|
|
return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
|
|
|
- }
|
|
|
- else if (size >= kb)
|
|
|
- {
|
|
|
+ } else if (size >= kb) {
|
|
|
float f = (float) size / kb;
|
|
|
return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
+ } else {
|
|
|
return String.format("%d B", size);
|
|
|
}
|
|
|
}
|